1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/x11/textctrl.cpp
3 // Purpose:
4 // Author:      Robert Roebling
5 // Copyright:   (c) 1998 Robert Roebling
6 // Licence:     wxWindows licence
7 /////////////////////////////////////////////////////////////////////////////
8 
9 // for compilers that support precompilation, includes "wx.h".
10 #include "wx/wxprec.h"
11 
12 #include "wx/textctrl.h"
13 
14 #ifndef WX_PRECOMP
15     #include "wx/intl.h"
16     #include "wx/log.h"
17     #include "wx/utils.h"
18     #include "wx/panel.h"
19     #include "wx/dcclient.h"
20     #include "wx/settings.h"
21 #endif
22 
23 #include "wx/clipbrd.h"
24 #include "wx/tokenzr.h"
25 
26 #include "wx/univ/inphand.h"
27 #include "wx/univ/renderer.h"
28 #include "wx/univ/colschem.h"
29 #include "wx/univ/theme.h"
30 
31 //-----------------------------------------------------------------------------
32 //  helpers
33 //-----------------------------------------------------------------------------
34 
wxSourceUndoStep(wxSourceUndo type,int y1,int y2,wxTextCtrl * owner)35 wxSourceUndoStep::wxSourceUndoStep( wxSourceUndo type, int y1, int y2, wxTextCtrl *owner )
36 {
37     m_type = type;
38     m_y1 = y1;
39     m_y2 = y2;
40     m_owner = owner;
41 
42     m_cursorX = m_owner->GetCursorX();
43     m_cursorY = m_owner->GetCursorY();
44 
45     if (m_type == wxSOURCE_UNDO_LINE)
46     {
47         m_text = m_owner->m_lines[m_y1].m_text;
48     } else
49     if (m_type == wxSOURCE_UNDO_ENTER)
50     {
51         m_text = m_owner->m_lines[m_y1].m_text;
52     } else
53     if (m_type == wxSOURCE_UNDO_BACK)
54     {
55         for (int i = m_y1; i < m_y2+2; i++)
56         {
57             if (i >= (int)m_owner->m_lines.GetCount())
58                 m_lines.Add( wxEmptyString );
59             else
60                 m_lines.Add( m_owner->m_lines[i].m_text );
61         }
62     } else
63     if (m_type == wxSOURCE_UNDO_DELETE)
64     {
65         for (int i = m_y1; i < m_y2+1; i++)
66         {
67             m_lines.Add( m_owner->m_lines[i].m_text );
68         }
69     } else
70     if (m_type == wxSOURCE_UNDO_PASTE)
71     {
72         m_text = m_owner->m_lines[m_y1].m_text;
73     }
74 }
75 
Undo()76 void wxSourceUndoStep::Undo()
77 {
78     if (m_type == wxSOURCE_UNDO_LINE)
79     {
80         m_owner->m_lines[m_y1].m_text = m_text;
81         m_owner->MoveCursor( m_cursorX, m_cursorY );
82         m_owner->RefreshLine( m_y1 );
83     } else
84     if (m_type == wxSOURCE_UNDO_ENTER)
85     {
86         m_owner->m_lines[m_y1].m_text = m_text;
87         m_owner->m_lines.RemoveAt( m_y1+1 );
88         m_owner->MoveCursor( m_cursorX, m_cursorY );
89         m_owner->RefreshDown( m_y1 );
90     } else
91     if (m_type == wxSOURCE_UNDO_BACK)
92     {
93         m_owner->m_lines[m_y1].m_text = m_lines[0];
94         m_owner->m_lines.Insert( new wxSourceLine( m_lines[1] ), m_y1+1 );
95         m_owner->MyAdjustScrollbars();
96         m_owner->MoveCursor( m_cursorX, m_cursorY );
97         m_owner->RefreshDown( m_y1 );
98     } else
99     if (m_type == wxSOURCE_UNDO_DELETE)
100     {
101         m_owner->m_lines[m_y1].m_text = m_lines[0];
102         for (int i = 1; i < (int)m_lines.GetCount(); i++)
103             m_owner->m_lines.Insert( new wxSourceLine( m_lines[i] ), m_y1+i );
104         m_owner->MyAdjustScrollbars();
105         m_owner->MoveCursor( m_cursorX, m_cursorY );
106         m_owner->RefreshDown( m_y1 );
107     } else
108     if (m_type == wxSOURCE_UNDO_PASTE)
109     {
110         m_owner->m_lines[m_y1].m_text = m_text;
111         for (int i = 0; i < m_y2-m_y1; i++)
112             m_owner->m_lines.RemoveAt( m_y1+1 );
113         m_owner->MyAdjustScrollbars();
114         m_owner->MoveCursor( m_cursorX, m_cursorY );
115         m_owner->RefreshDown( m_y1 );
116     } else
117     if (m_type == wxSOURCE_UNDO_INSERT_LINE)
118     {
119         m_owner->m_lines.RemoveAt( m_y1 );
120         m_owner->MyAdjustScrollbars();
121         m_owner->MoveCursor( 0, m_y1 );
122         m_owner->RefreshDown( m_y1 );
123     }
124 }
125 
126 #include "wx/arrimpl.cpp"
127 WX_DEFINE_OBJARRAY(wxSourceLineArray);
128 
129 //-----------------------------------------------------------------------------
130 //  wxTextCtrl
131 //-----------------------------------------------------------------------------
132 
BEGIN_EVENT_TABLE(wxTextCtrl,wxTextCtrlBase)133 BEGIN_EVENT_TABLE(wxTextCtrl, wxTextCtrlBase)
134     EVT_PAINT(wxTextCtrl::OnPaint)
135     EVT_ERASE_BACKGROUND(wxTextCtrl::OnEraseBackground)
136     EVT_CHAR(wxTextCtrl::OnChar)
137     EVT_MOUSE_EVENTS(wxTextCtrl::OnMouse)
138     EVT_KILL_FOCUS(wxTextCtrl::OnKillFocus)
139     EVT_SET_FOCUS(wxTextCtrl::OnSetFocus)
140 
141     EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
142     EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
143     EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
144     EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
145     EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
146 
147     EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
148     EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
149     EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
150     EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
151     EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
152 END_EVENT_TABLE()
153 
154 void wxTextCtrl::Init()
155 {
156     m_editable = true;
157     m_modified = false;
158 
159     m_lang = wxSOURCE_LANG_NONE;
160 
161     m_capturing = false;
162 
163     m_cursorX = 0;
164     m_cursorY = 0;
165 
166     m_longestLine = 0;
167 
168     m_bracketX = -1;
169     m_bracketY = -1;
170 
171     m_overwrite = false;
172     m_ignoreInput = false;
173 
174     ClearSelection();
175 
176     m_keywordColour = wxColour( 10, 140, 10 );
177 
178     m_defineColour = *wxRED;
179 
180     m_variableColour = wxColour( 50, 120, 150 );
181 
182     m_commentColour = wxColour( 130, 130, 130 );
183 
184     m_stringColour = wxColour( 10, 140, 10 );
185 }
186 
wxTextCtrl(wxWindow * parent,wxWindowID id,const wxString & value,const wxPoint & pos,const wxSize & size,long style,const wxValidator & validator,const wxString & name)187 wxTextCtrl::wxTextCtrl( wxWindow *parent,
188                         wxWindowID id,
189                         const wxString &value,
190                         const wxPoint &pos,
191                         const wxSize &size,
192                         long style,
193                         const wxValidator& validator,
194                         const wxString &name )
195     : wxScrollHelper(this)
196 {
197     Init();
198 
199     Create( parent, id, value, pos, size, style, validator, name );
200 }
201 
~wxTextCtrl()202 wxTextCtrl::~wxTextCtrl()
203 {
204     WX_CLEAR_LIST(wxList, m_undos);
205 }
206 
Create(wxWindow * parent,wxWindowID id,const wxString & value,const wxPoint & pos,const wxSize & size,long style,const wxValidator & validator,const wxString & name)207 bool wxTextCtrl::Create( wxWindow *parent,
208                          wxWindowID id,
209                          const wxString &value,
210                          const wxPoint &pos,
211                          const wxSize &size,
212                          long style,
213                          const wxValidator& validator,
214                          const wxString &name )
215 {
216     if ((style & wxBORDER_MASK) == 0)
217         style |= wxBORDER_SUNKEN;
218 
219     if ((style & wxTE_MULTILINE) != 0)
220         style |= wxALWAYS_SHOW_SB;
221 
222     wxTextCtrlBase::Create( parent, id, pos /* wxDefaultPosition */, size,
223                             style | wxVSCROLL | wxHSCROLL);
224 
225     SetBackgroundColour( *wxWHITE );
226 
227     SetCursor( wxCursor( wxCURSOR_IBEAM ) );
228 
229     m_editable = ((m_windowStyle & wxTE_READONLY) == 0);
230 
231     if (HasFlag(wxTE_PASSWORD))
232         m_sourceFont = wxFont( 12, wxMODERN, wxNORMAL, wxNORMAL );
233     else
234         m_sourceFont = GetFont();
235 
236     wxClientDC dc(this);
237     dc.SetFont( m_sourceFont );
238     m_lineHeight = dc.GetCharHeight();
239     m_charWidth = dc.GetCharWidth();
240 
241     SetValue( value );
242 
243     wxSize size_best( DoGetBestSize() );
244     wxSize new_size( size );
245     if (new_size.x == -1)
246         new_size.x = size_best.x;
247     if (new_size.y == -1)
248         new_size.y = size_best.y;
249     if ((new_size.x != size.x) || (new_size.y != size.y))
250         SetSize( new_size.x, new_size.y );
251 
252     // We create an input handler since it might be useful
253     CreateInputHandler(wxINP_HANDLER_TEXTCTRL);
254 
255     MyAdjustScrollbars();
256 
257     return true;
258 }
259 
260 //-----------------------------------------------------------------------------
261 //  public methods
262 //-----------------------------------------------------------------------------
263 
GetValue() const264 wxString wxTextCtrl::GetValue() const
265 {
266     wxString ret;
267     for (size_t i = 0; i < m_lines.GetCount(); i++)
268     {
269         ret += m_lines[i].m_text;
270         if (i+1 < m_lines.GetCount())
271             ret += wxT('\n');
272     }
273 
274     return ret;
275 }
276 
DoSetValue(const wxString & value,int flags)277 void wxTextCtrl::DoSetValue(const wxString& value, int flags)
278 {
279     m_modified = false;
280 
281     wxString oldValue = GetValue();
282 
283     m_cursorX = 0;
284     m_cursorY = 0;
285     ClearSelection();
286     m_lines.Clear();
287     m_longestLine = 0;
288 
289     if (value.empty())
290     {
291         m_lines.Add( new wxSourceLine( wxEmptyString ) );
292     }
293     else
294     {
295         int begin = 0;
296         int pos = 0;
297         for (;;)
298         {
299             pos = value.find( wxT('\n'), begin );
300             if (pos < 0)
301             {
302                 wxSourceLine *sl = new wxSourceLine( value.Mid( begin, value.Len()-begin ) );
303                 m_lines.Add( sl );
304 
305                 // if (sl->m_text.Len() > m_longestLine)
306                 //    m_longestLine = sl->m_text.Len();
307                 int ww = 0;
308                 GetTextExtent( sl->m_text, &ww, NULL, NULL, NULL );
309                 ww /= m_charWidth;
310                 if (ww > m_longestLine)
311                     m_longestLine = ww;
312 
313                 break;
314             }
315             else
316             {
317                 wxSourceLine *sl = new wxSourceLine( value.Mid( begin, pos-begin ) );
318                 m_lines.Add( sl );
319 
320                 // if (sl->m_text.Len() > m_longestLine)
321                 //      m_longestLine = sl->m_text.Len();
322                 int ww = 0;
323                 GetTextExtent( sl->m_text, &ww, NULL, NULL, NULL );
324                 ww /= m_charWidth;
325                 if (ww > m_longestLine)
326                     m_longestLine = ww;
327 
328                 begin = pos+1;
329             }
330         }
331     }
332 
333     // Don't need to refresh if the value hasn't changed
334     if ((GetWindowStyle() & wxTE_MULTILINE) == 0)
335     {
336         if (value == oldValue)
337             return;
338     }
339 
340     MyAdjustScrollbars();
341 
342     Refresh();
343 
344     if ( flags & SetValue_SendEvent )
345         SendTextUpdatedEvent();
346 }
347 
GetLineLength(long lineNo) const348 int wxTextCtrl::GetLineLength(long lineNo) const
349 {
350     if (lineNo >= (long)m_lines.GetCount())
351         return 0;
352 
353     return m_lines[lineNo].m_text.Len();
354 }
355 
GetLineText(long lineNo) const356 wxString wxTextCtrl::GetLineText(long lineNo) const
357 {
358     if (lineNo >= (long)m_lines.GetCount())
359         return wxEmptyString;
360 
361     return m_lines[lineNo].m_text;
362 }
363 
GetNumberOfLines() const364 int wxTextCtrl::GetNumberOfLines() const
365 {
366     return  m_lines.GetCount();
367 }
368 
IsModified() const369 bool wxTextCtrl::IsModified() const
370 {
371     return m_modified;
372 }
373 
IsEditable() const374 bool wxTextCtrl::IsEditable() const
375 {
376     return m_editable;
377 }
378 
GetSelection(long * from,long * to) const379 void wxTextCtrl::GetSelection(long* from, long* to) const
380 {
381     if (m_selStartX == -1 || m_selStartY == -1 ||
382         m_selEndX == -1 || m_selEndY == -1)
383     {
384         *from = GetInsertionPoint();
385         *to = GetInsertionPoint();
386     }
387     else
388     {
389         *from = XYToPosition(m_selStartX, m_selStartY);
390         *to = XYToPosition(m_selEndX, m_selEndY);
391     }
392 }
393 
Clear()394 void wxTextCtrl::Clear()
395 {
396     m_modified = true;
397     m_cursorX = 0;
398     m_cursorY = 0;
399     ClearSelection();
400 
401     m_lines.Clear();
402     m_lines.Add( new wxSourceLine( wxEmptyString ) );
403 
404     SetScrollbars( m_charWidth, m_lineHeight, 0, 0, 0, 0 );
405     Refresh();
406     WX_CLEAR_LIST(wxList, m_undos);
407 }
408 
Replace(long from,long to,const wxString & value)409 void wxTextCtrl::Replace(long from, long to, const wxString& value)
410 {
411 }
412 
Remove(long from,long to)413 void wxTextCtrl::Remove(long from, long to)
414 {
415 }
416 
DiscardEdits()417 void wxTextCtrl::DiscardEdits()
418 {
419     ClearSelection();
420     Refresh();
421 }
422 
SetMaxLength(unsigned long len)423 void wxTextCtrl::SetMaxLength(unsigned long len)
424 {
425 }
426 
PosToPixel(int line,int pos)427 int wxTextCtrl::PosToPixel( int line, int pos )
428 {
429     // TODO add support for Tabs
430 
431     if (line >= (int)m_lines.GetCount()) return 0;
432     if (pos < 0) return 0;
433 
434     wxString text = m_lines[line].m_text;
435 
436     if (text.empty()) return 0;
437 
438     if (pos < (int)text.Len())
439         text.Remove( pos, text.Len()-pos );
440 
441     int w = 0;
442 
443     GetTextExtent( text, &w, NULL, NULL, NULL );
444 
445     return w;
446 }
447 
PixelToPos(int line,int pixel)448 int wxTextCtrl::PixelToPos( int line, int pixel )
449 {
450     if (pixel < 2) return 0;
451 
452     if (line >= (int)m_lines.GetCount()) return 0;
453 
454     wxString text = m_lines[line].m_text;
455 
456     int w = 0;
457     int res = text.Len();
458     while (res > 0)
459     {
460         GetTextExtent( text, &w, NULL, NULL, NULL );
461 
462         if (w < pixel)
463             return res;
464 
465         res--;
466         text.Remove( res,1 );
467     }
468 
469     return 0;
470 }
471 
SetLanguage(wxSourceLanguage lang)472 void wxTextCtrl::SetLanguage( wxSourceLanguage lang )
473 {
474     m_lang = lang;
475 
476     m_keywords.Clear();
477 }
478 
WriteText(const wxString & text2)479 void wxTextCtrl::WriteText(const wxString& text2)
480 {
481     if (text2.empty()) return;
482 
483     m_modified = true;
484 
485     wxString text( text2 );
486     wxArrayString lines;
487     int pos;
488     while ( (pos = text.Find('\n')) != -1 )
489     {
490        lines.Add( text.Left( pos ) );
491        text.Remove( 0, pos+1 );
492     }
493     lines.Add( text );
494     int count = (int)lines.GetCount();
495 
496     wxString tmp1( m_lines[m_cursorY].m_text );
497     wxString tmp2( tmp1 );
498     int len = (int)tmp1.Len();
499 
500     if (len < m_cursorX)
501     {
502         wxString tmp;
503         for (int i = 0; i < m_cursorX-len; i++)
504             tmp.Append( ' ' );
505         m_lines[m_cursorY].m_text.Append( tmp );
506         tmp1.Append( tmp );
507         tmp2.Append( tmp );
508     }
509 
510     tmp1.Remove( m_cursorX );
511     tmp2.Remove( 0, m_cursorX );
512     tmp1.Append( lines[0] );
513 
514     if (count == 1)
515     {
516         m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, m_cursorY, m_cursorY, this ) );
517 
518         tmp1.Append( tmp2 );
519         m_lines[m_cursorY].m_text = tmp1;
520         RefreshLine( m_cursorY );
521     }
522     else
523     {
524         m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_PASTE, m_cursorY, m_cursorY+count-1, this ) );
525 
526         m_lines[m_cursorY].m_text = tmp1;
527         int i;
528         for (i = 1; i < count; i++)
529             m_lines.Insert( new wxSourceLine( lines[i] ), m_cursorY+i );
530         m_lines[m_cursorY+i-1].m_text.Append( tmp2 );
531 
532         MyAdjustScrollbars();
533         RefreshDown( m_cursorY );
534     }
535 }
536 
AppendText(const wxString & text2)537 void wxTextCtrl::AppendText(const wxString& text2)
538 {
539     if (text2.empty()) return;
540 
541     m_modified = true;
542 
543     wxString text( text2 );
544     wxArrayString lines;
545     int pos;
546     while ( (pos = text.Find('\n')) != -1 )
547     {
548        lines.Add( text.Left( pos ) );
549        text.Remove( 0, pos+1 );
550     }
551     lines.Add( text );
552     int count = (int)lines.GetCount();
553 
554     size_t y = m_lines.GetCount()-1;
555 
556     wxString tmp( m_lines[y].m_text );
557     tmp.Append( lines[0] );
558 
559     if (count == 1)
560     {
561         m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, y, y, this ) );
562 
563         m_lines[y].m_text = tmp;
564         RefreshLine( y );
565     }
566     else
567     {
568         m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_PASTE, y, y+count-1, this ) );
569 
570         m_lines[y].m_text = tmp;
571         int i;
572         for (i = 1; i < count; i++)
573             m_lines.Insert( new wxSourceLine( lines[i] ), y+i );
574 
575         MyAdjustScrollbars();
576         RefreshDown( y );
577     }
578 }
579 
SetStyle(long start,long end,const wxTextAttr & style)580 bool wxTextCtrl::SetStyle(long start, long end, const wxTextAttr& style)
581 {
582     return false;
583 }
584 
XYToPosition(long x,long y) const585 long wxTextCtrl::XYToPosition(long x, long y) const
586 {
587     long ret = 0;
588 
589     for (size_t i = 0; i < m_lines.GetCount(); i++)
590     {
591         if (i < (size_t)y)
592         {
593             // Add one for the end-of-line character
594             ret += m_lines[i].m_text.Len() + 1;
595             continue;
596         }
597 
598         if ((size_t)x < (m_lines[i].m_text.Len()+1))
599             return (ret + x);
600         else
601             return (ret + m_lines[i].m_text.Len() + 1);
602     }
603 
604     return ret;
605 }
606 
PositionToXY(long pos,long * x,long * y) const607 bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
608 {
609     if (m_lines.GetCount() == 0)
610     {
611         if (x) *x = 0;
612         if (y) *y = 0;
613 
614         return (pos == 0);
615     }
616 
617     long xx = 0;
618     long yy = 0;
619 
620     for (size_t i = 0; i < m_lines.GetCount(); i++)
621     {
622         //pos -= m_lines[i].m_text.Len();
623         //if (pos <= 0)
624 
625         // Add one for the end-of-line character. (In Windows,
626         // there are _two_ positions for each end of line.)
627         if (pos <= ((int)m_lines[i].m_text.Len()))
628         {
629             xx = pos;
630             if (x) *x = xx;
631             if (y) *y = yy;
632             return true;
633         }
634         pos -= (m_lines[i].m_text.Len() + 1);
635         yy++;
636     }
637 
638     // Last pos
639     //xx = m_lines[ m_lines.GetCount()-1 ].m_text.Len();
640     xx = pos;
641     if (x) *x = xx;
642     if (y) *y = yy;
643 
644     return false;
645 }
646 
ShowPosition(long pos)647 void wxTextCtrl::ShowPosition(long pos)
648 {
649 }
650 
Copy()651 void wxTextCtrl::Copy()
652 {
653     if (!HasSelection()) return;
654 
655     wxString sel;
656 
657     int selStartY = m_selStartY;
658     int selEndY = m_selEndY;
659     int selStartX = m_selStartX;
660     int selEndX = m_selEndX;
661 
662     if ((selStartY > selEndY) ||
663         ((selStartY == selEndY) && (selStartX > selEndX)))
664     {
665         int tmp = selStartX;
666         selStartX = selEndX;
667         selEndX = tmp;
668         tmp = selStartY;
669         selStartY = selEndY;
670         selEndY = tmp;
671     }
672 
673     if (selStartY == selEndY)
674     {
675         sel = m_lines[selStartY].m_text;
676 
677         if (selStartX >= (int)sel.Len()) return;
678         if (selEndX > (int)sel.Len())
679             selEndX = sel.Len();
680 
681         sel.Remove( selEndX, sel.Len()-selEndX );
682         sel.Remove( 0, selStartX );
683     }
684     else
685     {
686         wxString tmp( m_lines[selStartY].m_text );
687 
688         if (selStartX < (int)tmp.Len())
689         {
690             tmp.Remove( 0, selStartX );
691             sel = tmp;
692             sel.Append( wxT("\n") );
693         }
694         for (int i = selStartY+1; i < selEndY; i++)
695         {
696             sel.Append( m_lines[i].m_text );
697             sel.Append( wxT("\n") );
698         }
699         tmp = m_lines[selEndY].m_text;
700         if (selEndX > (int)tmp.Len())
701             selEndX = tmp.Len();
702         if (selEndX > 0)
703         {
704             tmp.Remove( selEndX, tmp.Len()-selEndX );
705             sel.Append( tmp );
706         }
707     }
708 
709     if (wxTheClipboard->Open())
710     {
711         wxTheClipboard->SetData( new wxTextDataObject( sel ) );
712         wxTheClipboard->Close();
713     }
714 }
715 
Cut()716 void wxTextCtrl::Cut()
717 {
718     Copy();
719 
720     Delete();
721 }
722 
Paste()723 void wxTextCtrl::Paste()
724 {
725     Delete();
726 
727     if (!wxTheClipboard->Open()) return;
728 
729     if (!wxTheClipboard->IsSupported( wxDF_TEXT ))
730     {
731         wxTheClipboard->Close();
732 
733         return;
734     }
735 
736     wxTextDataObject data;
737 
738     bool ret = wxTheClipboard->GetData( data );
739 
740     wxTheClipboard->Close();
741 
742     if (!ret) return;
743 
744     m_modified = true;
745 
746     wxString text( data.GetText() );
747     wxArrayString lines;
748     int pos;
749     while ( (pos = text.Find('\n')) != -1 )
750     {
751        lines.Add( text.Left( pos ) );
752        text.Remove( 0, pos+1 );
753     }
754     lines.Add( text );
755     int count = (int)lines.GetCount();
756 
757     wxString tmp1( m_lines[m_cursorY].m_text );
758     wxString tmp2( tmp1 );
759     int len = (int)tmp1.Len();
760 
761     if (len < m_cursorX)
762     {
763         wxString tmp;
764         for (int i = 0; i < m_cursorX-len; i++)
765             tmp.Append( ' ' );
766         m_lines[m_cursorY].m_text.Append( tmp );
767         tmp1.Append( tmp );
768         tmp2.Append( tmp );
769     }
770 
771     tmp1.Remove( m_cursorX );
772     tmp2.Remove( 0, m_cursorX );
773     tmp1.Append( lines[0] );
774 
775     if (count == 1)
776     {
777         m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, m_cursorY, m_cursorY, this ) );
778 
779         tmp1.Append( tmp2 );
780         m_lines[m_cursorY].m_text = tmp1;
781         RefreshLine( m_cursorY );
782     }
783     else
784     {
785         m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_PASTE, m_cursorY, m_cursorY+count-1, this ) );
786 
787         m_lines[m_cursorY].m_text = tmp1;
788         int i;
789         for (i = 1; i < count; i++)
790             m_lines.Insert( new wxSourceLine( lines[i] ), m_cursorY+i );
791         m_lines[m_cursorY+i-1].m_text.Append( tmp2 );
792 
793         MyAdjustScrollbars();
794         RefreshDown( m_cursorY );
795     }
796 }
797 
Undo()798 void wxTextCtrl::Undo()
799 {
800     if (m_undos.GetCount() == 0) return;
801 
802     wxList::compatibility_iterator node = m_undos.Item( m_undos.GetCount()-1 );
803     wxSourceUndoStep *undo = (wxSourceUndoStep*) node->GetData();
804 
805     undo->Undo();
806 
807     delete undo;
808     m_undos.Erase( node );
809 
810     m_modified = true;
811 }
812 
SetInsertionPoint(long pos)813 void wxTextCtrl::SetInsertionPoint(long pos)
814 {
815     ClearSelection();
816     long x, y;
817     PositionToXY(pos, & x, & y);
818     m_cursorX = x;
819     m_cursorY = y;
820     // TODO: scroll to this position if necessary
821     Refresh();
822 }
823 
SetInsertionPointEnd()824 void wxTextCtrl::SetInsertionPointEnd()
825 {
826     SetInsertionPoint(GetLastPosition());
827 }
828 
GetInsertionPoint() const829 long wxTextCtrl::GetInsertionPoint() const
830 {
831     return XYToPosition( m_cursorX, m_cursorY );
832 }
833 
GetLastPosition() const834 wxTextPos wxTextCtrl::GetLastPosition() const
835 {
836     size_t lineCount = m_lines.GetCount() - 1;
837     // It's the length of the line, not the length - 1,
838     // because there's a position after the last character.
839     return XYToPosition( m_lines[lineCount].m_text.Len(), lineCount );
840 }
841 
SetSelection(long from,long to)842 void wxTextCtrl::SetSelection(long from, long to)
843 {
844 }
845 
SetEditable(bool editable)846 void wxTextCtrl::SetEditable(bool editable)
847 {
848     m_editable = editable;
849 }
850 
Enable(bool enable)851 bool wxTextCtrl::Enable( bool enable )
852 {
853     return false;
854 }
855 
SetFont(const wxFont & font)856 bool wxTextCtrl::SetFont(const wxFont& font)
857 {
858     wxTextCtrlBase::SetFont( font );
859 
860     m_sourceFont = font;
861 
862     wxClientDC dc(this);
863     dc.SetFont( m_sourceFont );
864     m_lineHeight = dc.GetCharHeight();
865     m_charWidth = dc.GetCharWidth();
866 
867     // TODO: recalc longest lines
868 
869     MyAdjustScrollbars();
870 
871     return true;
872 }
873 
SetForegroundColour(const wxColour & colour)874 bool wxTextCtrl::SetForegroundColour(const wxColour& colour)
875 {
876     return wxWindow::SetForegroundColour( colour );
877 }
878 
SetBackgroundColour(const wxColour & colour)879 bool wxTextCtrl::SetBackgroundColour(const wxColour& colour)
880 {
881     return wxWindow::SetBackgroundColour( colour );
882 }
883 
884 //-----------------------------------------------------------------------------
885 //  private code and handlers
886 //-----------------------------------------------------------------------------
887 
SearchForBrackets()888 void wxTextCtrl::SearchForBrackets()
889 {
890     int oldBracketY = m_bracketY;
891     int oldBracketX = m_bracketX;
892 
893     if (m_cursorY < 0 || m_cursorY >= (int)m_lines.GetCount()) return;
894 
895     wxString current = m_lines[m_cursorY].m_text;
896 
897     // reverse search first
898 
899     char bracket = ' ';
900 
901     if (m_cursorX > 0)
902         bracket = current[(size_t) (m_cursorX-1)];
903 
904     if (bracket == ')' || bracket == ']' || bracket == '}')
905     {
906         char antibracket = '(';
907         if (bracket == ']') antibracket = '[';
908         if (bracket == '}') antibracket = '{';
909 
910         int count = 1;
911 
912         int endY = m_cursorY-60;
913         if (endY < 0) endY = 0;
914         for (int y = m_cursorY; y >= endY; y--)
915         {
916             current = m_lines[y].m_text;
917             if (y == m_cursorY)
918                 current.erase(m_cursorX-1,current.Len()-m_cursorX+1);
919 
920             for (int n = current.Len()-1; n >= 0; n--)
921             {
922                 // ignore chars
923                 if (current[(size_t) (n)] == '\'')
924                 {
925                     for (int m = n-1; m >= 0; m--)
926                     {
927                         if (current[(size_t) (m)] == '\'')
928                         {
929                             if (m == 0 || current[(size_t) (m-1)] != '\\')
930                                 break;
931                         }
932                         n = m-1;
933                     }
934                     continue;
935                 }
936 
937                 // ignore strings
938                 if (current[(size_t) (n)] == '\"')
939                 {
940                     for (int m = n-1; m >= 0; m--)
941                     {
942                         if (current[(size_t) (m)] == '\"')
943                         {
944                             if (m == 0 || current[(size_t) (m-1)] != '\\')
945                                 break;
946                         }
947                         n = m-1;
948                     }
949                     continue;
950                 }
951 
952                 if (current[(size_t) (n)] == antibracket)
953                 {
954                     count--;
955                     if (count == 0)
956                     {
957                         m_bracketY = y;
958                         m_bracketX = n;
959                         if (oldBracketY != m_bracketY && oldBracketY != -1)
960                             RefreshLine( oldBracketY );
961                         if (m_bracketY != oldBracketY || m_bracketX != oldBracketX)
962                             RefreshLine( m_bracketY );
963                         return;
964                     }
965                 }
966                 else if (current[(size_t) (n)] == bracket)
967                 {
968                     count++;
969                 }
970             }
971         }
972     }
973 
974     // then forward
975 
976     bracket = ' ';
977     if ((int)current.Len() > m_cursorX)
978         bracket = current[(size_t) (m_cursorX)];
979     if (bracket == '(' || bracket == '[' || bracket == '{')
980     {
981         char antibracket = ')';
982         if (bracket == '[') antibracket = ']';
983         if (bracket == '{') antibracket = '}';
984 
985         int count = 1;
986 
987         int endY = m_cursorY+60;
988         if (endY > (int)(m_lines.GetCount()-1)) endY = m_lines.GetCount()-1;
989         for (int y = m_cursorY; y <= endY; y++)
990         {
991             current = m_lines[y].m_text;
992             int start = 0;
993             if (y == m_cursorY)
994                 start = m_cursorX+1;
995 
996             for (int n = start; n < (int)current.Len(); n++)
997             {
998                 // ignore chars
999                 if (current[(size_t) (n)] == '\'')
1000                 {
1001                     for (int m = n+1; m < (int)current.Len(); m++)
1002                     {
1003                         if (current[(size_t) (m)] == '\'')
1004                         {
1005                             if (m == 0 || (current[(size_t) (m-1)] != '\\') || (m >= 2 && current[(size_t) (m-2)] == '\\'))
1006                                 break;
1007                         }
1008                         n = m+1;
1009                     }
1010                     continue;
1011                 }
1012 
1013                 // ignore strings
1014                 if (current[(size_t) (n)] == '\"')
1015                 {
1016                     for (int m = n+1; m < (int)current.Len(); m++)
1017                     {
1018                         if (current[(size_t) (m)] == '\"')
1019                         {
1020                             if (m == 0 || (current[(size_t) (m-1)] != '\\') || (m >= 2 && current[(size_t) (m-2)] == '\\'))
1021                                 break;
1022                         }
1023                         n = m+1;
1024                     }
1025                     continue;
1026                 }
1027 
1028                 if (current[(size_t) (n)] == antibracket)
1029                 {
1030                     count--;
1031                     if (count == 0)
1032                     {
1033                         m_bracketY = y;
1034                         m_bracketX = n;
1035                         if (oldBracketY != m_bracketY && oldBracketY != -1)
1036                             RefreshLine( oldBracketY );
1037                         if (m_bracketY != oldBracketY || m_bracketX != oldBracketX)
1038                             RefreshLine( m_bracketY );
1039                         return;
1040                     }
1041                 }
1042                 else if (current[(size_t) (n)] == bracket)
1043                 {
1044                     count++;
1045                 }
1046             }
1047         }
1048     }
1049 
1050     if (oldBracketY != -1)
1051     {
1052         m_bracketY = -1;
1053         RefreshLine( oldBracketY );
1054     }
1055 }
1056 
Delete()1057 void wxTextCtrl::Delete()
1058 {
1059     if (!HasSelection()) return;
1060 
1061     m_modified = true;
1062 
1063     int selStartY = m_selStartY;
1064     int selEndY = m_selEndY;
1065     int selStartX = m_selStartX;
1066     int selEndX = m_selEndX;
1067 
1068     if ((selStartY > selEndY) ||
1069         ((selStartY == selEndY) && (selStartX > selEndX)))
1070     {
1071         int tmp = selStartX;
1072         selStartX = selEndX;
1073         selEndX = tmp;
1074         tmp = selStartY;
1075         selStartY = selEndY;
1076         selEndY = tmp;
1077     }
1078 
1079     int len = (int)m_lines[selStartY].m_text.Len();
1080 
1081     if (selStartY == selEndY)
1082     {
1083         m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, selStartY, selStartY, this ) );
1084 
1085         wxString tmp( m_lines[selStartY].m_text );
1086         if (selStartX < len)
1087         {
1088             if (selEndX > len)
1089                 selEndX = len;
1090             tmp.Remove( selStartX, selEndX-selStartX );
1091             m_lines[selStartY].m_text = tmp;
1092         }
1093         ClearSelection();
1094         m_cursorX = selStartX;
1095         RefreshLine( selStartY );
1096     }
1097     else
1098     {
1099         m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_DELETE, selStartY, selEndY, this ) );
1100 
1101         if (selStartX < len)
1102             m_lines[selStartY].m_text.Remove( selStartX );
1103 
1104         for (int i = 0; i < selEndY-selStartY-1; i++)
1105             m_lines.RemoveAt( selStartY+1 );
1106 
1107         if (selEndX < (int)m_lines[selStartY+1].m_text.Len())
1108             m_lines[selStartY+1].m_text.Remove( 0, selEndX );
1109         else
1110             m_lines[selStartY+1].m_text.Remove( 0 );
1111 
1112         m_lines[selStartY].m_text.Append( m_lines[selStartY+1].m_text );
1113         m_lines.RemoveAt( selStartY+1 );
1114 
1115         ClearSelection();
1116         MoveCursor( selStartX, selStartY );
1117         MyAdjustScrollbars();
1118 
1119         RefreshDown( selStartY );
1120     }
1121 }
1122 
DeleteLine()1123 void wxTextCtrl::DeleteLine()
1124 {
1125     if (HasSelection()) return;
1126 
1127     if (m_cursorY < 0 || m_cursorY >= (int)m_lines.GetCount()-1) return;  // TODO
1128 
1129     m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_DELETE, m_cursorY, m_cursorY+1, this ) );
1130 
1131     m_lines.RemoveAt( m_cursorY );
1132     m_cursorX = 0;
1133     if (m_cursorY >= (int)m_lines.GetCount()) m_cursorY--;
1134 
1135     MyAdjustScrollbars();
1136     RefreshDown( m_cursorY );
1137 }
1138 
DoChar(char c)1139 void wxTextCtrl::DoChar( char c )
1140 {
1141     m_modified = true;
1142 
1143     m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, m_cursorY, m_cursorY, this ) );
1144 
1145     wxString tmp( m_lines[m_cursorY].m_text );
1146     tmp.Trim();
1147     if (m_cursorX >= (int)tmp.Len())
1148     {
1149         int len = tmp.Len();
1150         for (int i = 0; i < m_cursorX - len; i++)
1151             tmp.Append( ' ' );
1152         tmp.Append( c );
1153     }
1154     else
1155     {
1156         if (m_overwrite)
1157             tmp.SetChar( m_cursorX, c );
1158         else
1159             tmp.insert( m_cursorX, 1, c );
1160     }
1161 
1162     m_lines[m_cursorY].m_text = tmp;
1163 
1164 //    if (tmp.Len() > m_longestLine)
1165 //    {
1166 //        m_longestLine = tmp.Len();
1167 //        MyAdjustScrollbars();
1168 //    }
1169 
1170     int ww = 0;
1171     GetTextExtent( tmp, &ww, NULL, NULL, NULL );
1172     ww /= m_charWidth;
1173     if (ww > m_longestLine)
1174     {
1175         m_longestLine = ww;
1176         MyAdjustScrollbars();
1177     }
1178 
1179     m_cursorX++;
1180 
1181     int y = m_cursorY*m_lineHeight;
1182     // int x = (m_cursorX-1)*m_charWidth;
1183     int x = PosToPixel( m_cursorY, m_cursorX-1 );
1184     CalcScrolledPosition( x, y, &x, &y );
1185     wxRect rect( x+2, y+2, 10000, m_lineHeight );
1186     Refresh( true, &rect );
1187     // refresh whole line for syntax colour highlighting
1188     rect.x = 0;
1189     Refresh( false, &rect );
1190 
1191     int size_x = 0;
1192     int size_y = 0;
1193     GetClientSize( &size_x, &size_y );
1194     size_x /= m_charWidth;
1195 
1196     int view_x = 0;
1197     int view_y = 0;
1198     GetViewStart( &view_x, &view_y );
1199 
1200     //int xx = m_cursorX;
1201     int xx = PosToPixel( m_cursorY, m_cursorX ) / m_charWidth;
1202 
1203     if (xx < view_x)
1204         Scroll( xx, -1 );
1205     else if (xx > view_x+size_x-1)
1206         Scroll( xx-size_x+1, -1 );
1207 }
1208 
DoBack()1209 void wxTextCtrl::DoBack()
1210 {
1211     m_modified = true;
1212 
1213     if (m_cursorX == 0)
1214     {
1215         if (m_cursorY == 0) return;
1216 
1217         m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_BACK, m_cursorY-1, m_cursorY, this ) );
1218 
1219         wxString tmp1( m_lines[m_cursorY-1].m_text );
1220         tmp1.Trim();
1221         wxString tmp2( m_lines[m_cursorY].m_text );
1222         tmp2.Trim();
1223         m_cursorX = tmp1.Len();
1224         m_cursorY--;
1225         tmp1.Append( tmp2 );
1226         m_lines[m_cursorY].m_text = tmp1;
1227         m_lines.RemoveAt( m_cursorY+1 );
1228 
1229         MyAdjustScrollbars();
1230         RefreshDown( m_cursorY-1 );
1231     }
1232     else
1233     {
1234         m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, m_cursorY, m_cursorY, this ) );
1235 
1236         if (m_cursorX <= (int)m_lines[m_cursorY].m_text.Len())
1237             m_lines[m_cursorY].m_text.Remove( m_cursorX-1, 1 );
1238         m_cursorX--;
1239 
1240         int y = m_cursorY*m_lineHeight;
1241         // int x = m_cursorX*m_charWidth;
1242         int x = PosToPixel( m_cursorY, m_cursorX );
1243         CalcScrolledPosition( x, y, &x, &y );
1244         wxRect rect( x+2, y+2, 10000, m_lineHeight );
1245         Refresh( true, &rect );
1246         // refresh whole line for syntax colour highlighting
1247         rect.x = 0;
1248         Refresh( false, &rect );
1249     }
1250 }
1251 
DoDelete()1252 void wxTextCtrl::DoDelete()
1253 {
1254     m_modified = true;
1255 
1256     wxString tmp( m_lines[m_cursorY].m_text );
1257     tmp.Trim();
1258     int len = (int)tmp.Len();
1259     if (m_cursorX >= len)
1260     {
1261         if (m_cursorY == (int)m_lines.GetCount()-1) return;
1262 
1263         m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_DELETE, m_cursorY, m_cursorY+1, this ) );
1264 
1265         for (int i = 0; i < (m_cursorX-len); i++)
1266             tmp += ' ';
1267 
1268         tmp += m_lines[m_cursorY+1].m_text;
1269 
1270         m_lines[m_cursorY] = tmp;
1271         m_lines.RemoveAt( m_cursorY+1 );
1272 
1273         MyAdjustScrollbars();
1274         RefreshDown( m_cursorY );
1275     }
1276     else
1277     {
1278         m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, m_cursorY, m_cursorY, this ) );
1279 
1280         tmp.Remove( m_cursorX, 1 );
1281         m_lines[m_cursorY].m_text = tmp;
1282 
1283         int y = m_cursorY*m_lineHeight;
1284         // int x = m_cursorX*m_charWidth;
1285         int x = PosToPixel( m_cursorY, m_cursorX );
1286         CalcScrolledPosition( x, y, &x, &y );
1287         wxRect rect( x+2, y+2, 10000, m_lineHeight );
1288         Refresh( true, &rect );
1289         // refresh whole line for syntax colour highlighting
1290         rect.x = 0;
1291         Refresh( false, &rect );
1292     }
1293 }
1294 
DoReturn()1295 void wxTextCtrl::DoReturn()
1296 {
1297     m_modified = true;
1298 
1299     m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_ENTER, m_cursorY, m_cursorY, this ) );
1300 
1301     wxString tmp( m_lines[m_cursorY].m_text );
1302     size_t indent = tmp.find_first_not_of( ' ' );
1303     if (indent == wxSTRING_MAXLEN) indent = 0;
1304     tmp.Trim();
1305     if (m_cursorX >= (int)tmp.Len())
1306     {
1307         int cursorX = indent;
1308         int cursorY = m_cursorY + 1;
1309 
1310         wxString new_tmp;
1311         for (size_t i = 0; i < indent; i++) new_tmp.Append( ' ' );
1312         m_lines.Insert( new wxSourceLine( new_tmp ), cursorY );
1313 
1314         MyAdjustScrollbars();
1315         MoveCursor( cursorX, cursorY );
1316         RefreshDown( m_cursorY );
1317     }
1318     else
1319     {
1320         wxString tmp1( tmp );
1321         tmp1.Remove( m_cursorX, tmp.Len()-m_cursorX );
1322         m_lines[m_cursorY].m_text = tmp1;
1323 
1324         wxString tmp2( tmp );
1325         tmp2.Remove( 0, m_cursorX );
1326 
1327         int cursorX = indent;
1328         int cursorY = m_cursorY + 1;
1329 
1330         wxString new_tmp;
1331         for (size_t i = 0; i < indent; i++) new_tmp.Append( ' ' );
1332         new_tmp.Append( tmp2 );
1333         m_lines.Insert( new wxSourceLine( new_tmp ), cursorY );
1334 
1335         MyAdjustScrollbars();
1336         MoveCursor( cursorX, cursorY );
1337         RefreshDown( m_cursorY-1 );
1338     }
1339 }
1340 
DoDClick()1341 void wxTextCtrl::DoDClick()
1342 {
1343     wxString line( m_lines[ m_cursorY ].m_text );
1344     if (m_cursorX >= (int)line.Len()) return;
1345     int p = m_cursorX;
1346     char ch = line[(size_t) (p)];
1347     if (((ch >= 'a') && (ch <= 'z')) ||
1348         ((ch >= 'A') && (ch <= 'Z')) ||
1349         ((ch >= '0') && (ch <= '9')) ||
1350         (ch == '_'))
1351     {
1352         m_selStartY = m_cursorY;
1353         m_selEndY = m_cursorY;
1354         if (p > 0)
1355         {
1356             ch = line[(size_t) (p-1)];
1357             while (((ch >= 'a') && (ch <= 'z')) ||
1358                    ((ch >= 'A') && (ch <= 'Z')) ||
1359                    ((ch >= '0') && (ch <= '9')) ||
1360                    (ch == '_'))
1361             {
1362                 p--;
1363                 if (p == 0) break;
1364                 ch = line[(size_t) (p-1)];
1365             }
1366         }
1367         m_selStartX = p;
1368 
1369         p = m_cursorX;
1370         if (p < (int)line.Len())
1371         {
1372             ch = line[(size_t) (p)];
1373             while (((ch >= 'a') && (ch <= 'z')) ||
1374                    ((ch >= 'A') && (ch <= 'Z')) ||
1375                    ((ch >= '0') && (ch <= '9')) ||
1376                    (ch == '_'))
1377             {
1378                 if (p >= (int)line.Len()) break;
1379                 p++;
1380                 ch = line[(size_t) (p)];
1381             }
1382         }
1383         m_selEndX = p;
1384         RefreshLine( m_cursorY );
1385     }
1386 }
1387 
GetNextToken(wxString & line,size_t & pos)1388 wxString wxTextCtrl::GetNextToken( wxString &line, size_t &pos )
1389 {
1390     wxString ret;
1391     size_t len = line.Len();
1392     for (size_t p = pos; p < len; p++)
1393     {
1394         if ((m_lang == wxSOURCE_LANG_PYTHON) || (m_lang == wxSOURCE_LANG_PERL))
1395         {
1396             if (line[p] == '#')
1397             {
1398                 for (size_t q = p; q < len; q++)
1399                     ret.Append( line[q] );
1400                 pos = p;
1401                 return ret;
1402             }
1403         }
1404         else
1405         {
1406             if ((line[p] == '/') && (p+1 < len) && (line[(size_t) (p+1)] == '/'))
1407             {
1408                 for (size_t q = p; q < len; q++)
1409                     ret.Append( line[q] );
1410                 pos = p;
1411                 return ret;
1412             }
1413         }
1414 
1415         if (line[p] == '"')
1416         {
1417             ret.Append( line[p] );
1418             for (size_t q = p+1; q < len; q++)
1419             {
1420                 ret.Append( line[q] );
1421                 if ((line[q] == '"') && ((line[(size_t) (q-1)] != '\\') || (q >= 2 && line[(size_t) (q-2)] == '\\')))
1422                    break;
1423             }
1424             pos = p;
1425             return ret;
1426         }
1427 
1428         if (line[p] == '\'')
1429         {
1430             ret.Append( line[p] );
1431             for (size_t q = p+1; q < len; q++)
1432             {
1433                 ret.Append( line[q] );
1434                 if ((line[q] == '\'') && ((line[(size_t) (q-1)] != '\\') || (q >= 2 && line[(size_t) (q-2)] == '\\')))
1435                    break;
1436             }
1437             pos = p;
1438             return ret;
1439         }
1440 
1441         if (((line[p] >= 'a') && (line[p] <= 'z')) ||
1442             ((line[p] >= 'A') && (line[p] <= 'Z')) ||
1443             (line[p] == '_') ||
1444             (line[p] == '#'))
1445         {
1446            ret.Append( line[p] );
1447            for (size_t q = p+1; q < len; q++)
1448            {
1449                 if (((line[q] >= 'a') && (line[q] <= 'z')) ||
1450                    ((line[q] >= 'A') && (line[q] <= 'Z')) ||
1451                    ((line[q] >= '0') && (line[q] <= '9')) ||
1452                    (line[q] == '_'))
1453                 {
1454                     ret.Append( line[q] );
1455                     continue;
1456                 }
1457                 else
1458                 {
1459                     pos = p;
1460                     return ret;
1461                 }
1462            }
1463            pos = p;
1464            return ret;
1465         }
1466     }
1467 
1468     return ret;
1469 }
1470 
OnEraseBackground(wxEraseEvent & event)1471 void wxTextCtrl::OnEraseBackground( wxEraseEvent &event )
1472 {
1473     event.Skip();
1474 }
1475 
DrawLinePart(wxDC & dc,int x,int y,const wxString & toDraw,const wxString & origin,const wxColour & colour)1476 void wxTextCtrl::DrawLinePart( wxDC &dc, int x, int y, const wxString &toDraw, const wxString &origin, const wxColour &colour )
1477 {
1478     size_t pos = 0;
1479     size_t len = origin.Len();
1480     dc.SetTextForeground( colour );
1481     while (pos < len)
1482     {
1483         while (toDraw[pos] == wxT(' '))
1484         {
1485             pos++;
1486             if (pos == len) return;
1487         }
1488 
1489         size_t start = pos;
1490 
1491         wxString current;
1492         current += toDraw[pos];
1493         pos++;
1494         while ( (toDraw[pos] == origin[pos]) && (pos < len))
1495         {
1496             current += toDraw[pos];
1497             pos++;
1498         }
1499 
1500         int xx = 0;
1501         wxString tmp = origin.Left( start );
1502         GetTextExtent( tmp, &xx, NULL, NULL, NULL );
1503         xx += x;
1504         int yy = y;
1505         dc.DrawText( current, xx, yy );
1506     }
1507 }
1508 
DrawLine(wxDC & dc,int x,int y,const wxString & line2,int lineNum)1509 void wxTextCtrl::DrawLine( wxDC &dc, int x, int y, const wxString &line2, int lineNum )
1510 {
1511     int selStartY = m_selStartY;
1512     int selEndY = m_selEndY;
1513     int selStartX = m_selStartX;
1514     int selEndX = m_selEndX;
1515 
1516     if ((selStartY > selEndY) ||
1517         ((selStartY == selEndY) && (selStartX > selEndX)))
1518     {
1519         int tmp = selStartX;
1520         selStartX = selEndX;
1521         selEndX = tmp;
1522         tmp = selStartY;
1523         selStartY = selEndY;
1524         selEndY = tmp;
1525     }
1526 
1527     wxString line( line2 );
1528     if (HasFlag(wxTE_PASSWORD))
1529     {
1530         size_t len = line.Len();
1531         line = wxString( wxT('*'), len );
1532     }
1533 
1534     wxString keyword( ' ', line.Len() );
1535     wxString define( ' ', line.Len() );
1536     wxString variable( ' ', line.Len() );
1537     wxString comment( ' ', line.Len() );
1538     wxString my_string( ' ', line.Len() );
1539     wxString selection( ' ', line.Len() );
1540 
1541     if (m_lang != wxSOURCE_LANG_NONE)
1542     {
1543         if (lineNum == m_bracketY)
1544         {
1545             wxString red( ' ', line.Len() );
1546             if (m_bracketX < (int)line.Len())
1547             {
1548                 red.SetChar( m_bracketX, line[(size_t) (m_bracketX)] );
1549                 line.SetChar( m_bracketX, ' ' );
1550                 dc.SetTextForeground( *wxRED );
1551                 dc.DrawText( red, x, y );
1552                 dc.SetTextForeground( *wxBLACK );
1553             }
1554         }
1555 
1556         size_t pos = 0;
1557         wxString token( GetNextToken( line, pos ) );
1558         while ( !token.empty() )
1559         {
1560             if (m_keywords.Index( token ) != wxNOT_FOUND)
1561             {
1562                 size_t end_pos = pos + token.Len();
1563                 for (size_t i = pos; i < end_pos; i++)
1564                 {
1565                     keyword[i] = line[i];
1566                     line[i] = ' ';
1567                 }
1568             } else
1569             if (m_defines.Index( token ) != wxNOT_FOUND)
1570             {
1571                 size_t end_pos = pos + token.Len();
1572                 for (size_t i = pos; i < end_pos; i++)
1573                 {
1574                     define[i] = line[i];
1575                     line[i] = ' ';
1576                 }
1577             } else
1578             if ((m_variables.Index( token ) != wxNOT_FOUND) ||
1579                 ((token.Len() > 2) && (token[(size_t) (0)] == 'w') && (token[(size_t) (1)] == 'x')))
1580             {
1581                 size_t end_pos = pos + token.Len();
1582                 for (size_t i = pos; i < end_pos; i++)
1583                 {
1584                     variable[i] = line[i];
1585                     line[i] = ' ';
1586                 }
1587             } else
1588             if ((token.Len() >= 2) && (token[(size_t) (0)] == '/') && (token[(size_t) (1)] == '/') && (m_lang == wxSOURCE_LANG_CPP))
1589             {
1590                 size_t end_pos = pos + token.Len();
1591                 for (size_t i = pos; i < end_pos; i++)
1592                 {
1593                     comment[i] = line[i];
1594                     line[i] = ' ';
1595                 }
1596             } else
1597             if ((token[(size_t) (0)] == '#') &&
1598                 ((m_lang == wxSOURCE_LANG_PYTHON) || (m_lang == wxSOURCE_LANG_PERL)))
1599             {
1600                 size_t end_pos = pos + token.Len();
1601                 for (size_t i = pos; i < end_pos; i++)
1602                 {
1603                     comment[i] = line[i];
1604                     line[i] = ' ';
1605                 }
1606             } else
1607             if ((token[(size_t) (0)] == '"') || (token[(size_t) (0)] == '\''))
1608             {
1609                 size_t end_pos = pos + token.Len();
1610                 for (size_t i = pos; i < end_pos; i++)
1611                 {
1612                     my_string[i] = line[i];
1613                     line[i] = ' ';
1614                 }
1615             }
1616             pos += token.Len();
1617             token = GetNextToken( line, pos );
1618         }
1619     }
1620 
1621     if ((lineNum < selStartY) || (lineNum > selEndY))
1622     {
1623         DrawLinePart( dc, x, y, line, line2, *wxBLACK );
1624         DrawLinePart( dc, x, y, selection, line2, *wxWHITE );
1625         DrawLinePart( dc, x, y, keyword, line2, m_keywordColour );
1626         DrawLinePart( dc, x, y, define, line2, m_defineColour );
1627         DrawLinePart( dc, x, y, variable, line2, m_variableColour );
1628         DrawLinePart( dc, x, y, comment, line2, m_commentColour );
1629         DrawLinePart( dc, x, y, my_string, line2, m_stringColour );
1630         return;
1631     }
1632 
1633     if (selStartY == selEndY)
1634     {
1635         // int xx = selStartX*m_charWidth;
1636         int xx = PosToPixel( lineNum, selStartX );
1637         // int ww = (selEndX-selStartX)*m_charWidth;
1638         int ww = PosToPixel( lineNum, selEndX ) - xx;
1639         dc.DrawRectangle( xx+2, lineNum*m_lineHeight+2, ww, m_lineHeight );
1640 
1641         for (size_t i = (size_t)selStartX; i < (size_t)selEndX; i++)
1642         {
1643             selection[i] = line[i];
1644             line[i] = ' ';
1645         }
1646     } else
1647     if ((lineNum > selStartY) && (lineNum < selEndY))
1648     {
1649         dc.DrawRectangle( 0+2, lineNum*m_lineHeight+2, 10000, m_lineHeight );
1650 
1651         for (size_t i = 0; i < line.Len(); i++)
1652         {
1653             selection[i] = line[i];
1654             line[i] = ' ';
1655         }
1656     } else
1657     if (lineNum == selStartY)
1658     {
1659         // int xx = selStartX*m_charWidth;
1660         int xx = PosToPixel( lineNum, selStartX );
1661         dc.DrawRectangle( xx+2, lineNum*m_lineHeight+2, 10000, m_lineHeight );
1662 
1663         for (size_t i = (size_t)selStartX; i < line.Len(); i++)
1664         {
1665             selection[i] = line[i];
1666             line[i] = ' ';
1667         }
1668     } else
1669     if (lineNum == selEndY)
1670     {
1671         // int ww = selEndX*m_charWidth;
1672         int ww = PosToPixel( lineNum, selEndX );
1673         dc.DrawRectangle( 0+2, lineNum*m_lineHeight+2, ww, m_lineHeight );
1674 
1675         for (size_t i = 0; i < (size_t)selEndX; i++)
1676         {
1677             selection[i] = line[i];
1678             line[i] = ' ';
1679         }
1680     }
1681 
1682     DrawLinePart( dc, x, y, line, line2, *wxBLACK );
1683     DrawLinePart( dc, x, y, selection, line2, *wxWHITE );
1684     DrawLinePart( dc, x, y, keyword, line2, m_keywordColour );
1685     DrawLinePart( dc, x, y, define, line2, m_defineColour );
1686     DrawLinePart( dc, x, y, variable, line2, m_variableColour );
1687     DrawLinePart( dc, x, y, comment, line2, m_commentColour );
1688     DrawLinePart( dc, x, y, my_string, line2, m_stringColour );
1689 }
1690 
OnPaint(wxPaintEvent & event)1691 void wxTextCtrl::OnPaint( wxPaintEvent &event )
1692 {
1693     wxPaintDC dc(this);
1694 
1695     if (m_lines.GetCount() == 0) return;
1696 
1697     PrepareDC( dc );
1698 
1699     dc.SetFont( m_sourceFont );
1700 
1701     int scroll_y = 0;
1702     GetViewStart( NULL, &scroll_y );
1703 
1704     // We have a inner border of two pixels
1705     // around the text, so scroll units do
1706     // not correspond to lines.
1707     if (scroll_y > 0) scroll_y--;
1708 
1709     int size_x = 0;
1710     int size_y = 0;
1711     GetClientSize( &size_x, &size_y );
1712 
1713     dc.SetPen( *wxTRANSPARENT_PEN );
1714     dc.SetBrush( wxBrush( wxTHEME_COLOUR(HIGHLIGHT), wxSOLID ) );
1715     int upper = wxMin( (int)m_lines.GetCount(), scroll_y+(size_y/m_lineHeight)+2 );
1716     for (int i = scroll_y; i < upper; i++)
1717     {
1718         int x = 0+2;
1719         int y = i*m_lineHeight+2;
1720         int w = 10000;
1721         int h = m_lineHeight;
1722         CalcScrolledPosition( x,y,&x,&y );
1723         if (IsExposed(x,y,w,h))
1724             DrawLine( dc, 0+2, i*m_lineHeight+2, m_lines[i].m_text, i );
1725     }
1726 
1727     if (m_editable && (FindFocus() == this))
1728     {
1729         ///dc.SetBrush( *wxRED_BRUSH );
1730         dc.SetBrush( *wxBLACK_BRUSH );
1731         // int xx = m_cursorX*m_charWidth;
1732         int xx = PosToPixel( m_cursorY, m_cursorX );
1733         dc.DrawRectangle( xx+2, m_cursorY*m_lineHeight+2, 2, m_lineHeight );
1734     }
1735 }
1736 
OnMouse(wxMouseEvent & event)1737 void wxTextCtrl::OnMouse( wxMouseEvent &event )
1738 {
1739     if (m_lines.GetCount() == 0) return;
1740 
1741 
1742 #if 0  // there is no middle button on iPAQs
1743     if (event.MiddleDown())
1744     {
1745         Paste( true );
1746         return;
1747     }
1748 #endif
1749 
1750     if (event.LeftDClick())
1751     {
1752         DoDClick();
1753         return;
1754     }
1755 
1756     if (event.LeftDown())
1757     {
1758         m_capturing = true;
1759         CaptureMouse();
1760     }
1761 
1762     if (event.LeftUp())
1763     {
1764         m_capturing = false;
1765         ReleaseMouse();
1766     }
1767 
1768     if (event.LeftDown() ||
1769         (event.LeftIsDown() && m_capturing))
1770     {
1771         int x = event.GetX();
1772         int y = event.GetY();
1773         CalcUnscrolledPosition( x, y, &x, &y );
1774         y /= m_lineHeight;
1775         // x /= m_charWidth;
1776         x = PixelToPos( y, x );
1777         MoveCursor(
1778             wxMin( 1000, wxMax( 0, x ) ),
1779             wxMin( (int)m_lines.GetCount()-1, wxMax( 0, y ) ),
1780             event.ShiftDown() || !event.LeftDown() );
1781     }
1782 }
1783 
OnChar(wxKeyEvent & event)1784 void wxTextCtrl::OnChar( wxKeyEvent &event )
1785 {
1786     if (m_lines.GetCount() == 0) return;
1787 
1788     if (!m_editable) return;
1789 
1790     int size_x = 0;
1791     int size_y = 0;
1792     GetClientSize( &size_x, &size_y );
1793     size_x /= m_charWidth;
1794     size_y /= m_lineHeight;
1795     size_y--;
1796 
1797     if (event.ShiftDown())
1798     {
1799         switch (event.GetKeyCode())
1800         {
1801             case '4': event.m_keyCode = WXK_LEFT;     break;
1802             case '8': event.m_keyCode = WXK_UP;       break;
1803             case '6': event.m_keyCode = WXK_RIGHT;    break;
1804             case '2': event.m_keyCode = WXK_DOWN;     break;
1805             case '9': event.m_keyCode = WXK_PAGEUP;   break;
1806             case '3': event.m_keyCode = WXK_PAGEDOWN; break;
1807             case '7': event.m_keyCode = WXK_HOME;     break;
1808             case '1': event.m_keyCode = WXK_END;      break;
1809             case '0': event.m_keyCode = WXK_INSERT;   break;
1810         }
1811     }
1812 
1813     switch (event.GetKeyCode())
1814     {
1815         case WXK_UP:
1816         {
1817             if (m_ignoreInput) return;
1818             if (m_cursorY > 0)
1819                 MoveCursor( m_cursorX, m_cursorY-1, event.ShiftDown() );
1820             m_ignoreInput = true;
1821             return;
1822         }
1823         case WXK_DOWN:
1824         {
1825             if (m_ignoreInput) return;
1826             if (m_cursorY < (int)(m_lines.GetCount()-1))
1827                 MoveCursor( m_cursorX, m_cursorY+1, event.ShiftDown() );
1828             m_ignoreInput = true;
1829             return;
1830         }
1831         case WXK_LEFT:
1832         {
1833             if (m_ignoreInput) return;
1834             if (m_cursorX > 0)
1835             {
1836                 MoveCursor( m_cursorX-1, m_cursorY, event.ShiftDown() );
1837             }
1838             else
1839             {
1840                 if (m_cursorY > 0)
1841                     MoveCursor( m_lines[m_cursorY-1].m_text.Len(), m_cursorY-1, event.ShiftDown() );
1842             }
1843             m_ignoreInput = true;
1844             return;
1845         }
1846         case WXK_RIGHT:
1847         {
1848             if (m_ignoreInput) return;
1849             if (m_cursorX < 1000)
1850                 MoveCursor( m_cursorX+1, m_cursorY, event.ShiftDown() );
1851             m_ignoreInput = true;
1852             return;
1853         }
1854         case WXK_HOME:
1855         {
1856             if (event.ControlDown())
1857                 MoveCursor( 0, 0, event.ShiftDown() );
1858             else
1859                 MoveCursor( 0, m_cursorY, event.ShiftDown() );
1860             return;
1861         }
1862         case WXK_END:
1863         {
1864             if (event.ControlDown())
1865                 MoveCursor( 0, m_lines.GetCount()-1, event.ShiftDown() );
1866             else
1867                 MoveCursor( m_lines[m_cursorY].m_text.Len(), m_cursorY, event.ShiftDown() );
1868             return;
1869         }
1870         case WXK_NEXT:
1871         {
1872             if (m_ignoreInput) return;
1873             MoveCursor( m_cursorX, wxMin( (int)(m_lines.GetCount()-1), m_cursorY+size_y ), event.ShiftDown() );
1874             m_ignoreInput = true;
1875             return;
1876         }
1877         case WXK_PAGEUP:
1878         {
1879             if (m_ignoreInput) return;
1880             MoveCursor( m_cursorX, wxMax( 0, m_cursorY-size_y ), event.ShiftDown() );
1881             m_ignoreInput = true;
1882             return;
1883         }
1884         case WXK_INSERT:
1885         {
1886             if (event.ShiftDown())
1887                 Paste();
1888             else if (event.ControlDown())
1889                 Copy();
1890             else
1891                 m_overwrite = !m_overwrite;
1892             return;
1893         }
1894         case WXK_RETURN:
1895         {
1896             if (m_windowStyle & wxTE_PROCESS_ENTER)
1897             {
1898                 wxCommandEvent event(wxEVT_TEXT_ENTER, m_windowId);
1899                 event.SetEventObject(this);
1900                 event.SetString(GetValue());
1901                 if (HandleWindowEvent(event)) return;
1902             }
1903 
1904             if (IsSingleLine())
1905             {
1906                 event.Skip();
1907                 return;
1908             }
1909 
1910             if (HasSelection())
1911                 Delete();
1912             DoReturn();
1913             return;
1914         }
1915         case WXK_TAB:
1916         {
1917             if (HasSelection())
1918                 Delete();
1919             bool save_overwrite = m_overwrite;
1920             m_overwrite = false;
1921             int i = 4-(m_cursorX % 4);
1922             if (i == 0) i = 4;
1923             for (int c = 0; c < i; c++)
1924                  DoChar( ' ' );
1925             m_overwrite = save_overwrite;
1926             return;
1927         }
1928         case WXK_BACK:
1929         {
1930             if (HasSelection())
1931                 Delete();
1932             else
1933                 DoBack();
1934             return;
1935         }
1936         case WXK_DELETE:
1937         {
1938             if (HasSelection())
1939                 Delete();
1940             else
1941                 DoDelete();
1942             return;
1943         }
1944         default:
1945         {
1946             if (  (event.GetKeyCode() >= 'a') &&
1947                   (event.GetKeyCode() <= 'z') &&
1948                   (event.AltDown()) )
1949             {
1950                 // Alt-F etc.
1951                 event.Skip();
1952                 return;
1953             }
1954 
1955             if (  (event.GetKeyCode() >= 32) &&
1956                   (event.GetKeyCode() <= 255) &&
1957                  !(event.ControlDown() && !event.AltDown()) ) // filters out Ctrl-X but leaves Alt-Gr
1958             {
1959                 if (HasSelection())
1960                     Delete();
1961                 DoChar( (char) event.GetKeyCode() );
1962                 return;
1963             }
1964         }
1965     }
1966 
1967     event.Skip();
1968 }
1969 
OnInternalIdle()1970 void wxTextCtrl::OnInternalIdle()
1971 {
1972     wxControl::OnInternalIdle();
1973 
1974     m_ignoreInput = false;
1975 
1976     if (m_lang != wxSOURCE_LANG_NONE)
1977         SearchForBrackets();
1978 }
1979 
Indent()1980 void wxTextCtrl::Indent()
1981 {
1982     int startY = m_cursorY;
1983     int endY = m_cursorY;
1984     if (HasSelection())
1985     {
1986         startY = m_selStartY;
1987         endY = m_selEndY;
1988         if (endY < startY)
1989         {
1990             int tmp = startY;
1991             startY = endY;
1992             endY = tmp;
1993         }
1994     }
1995 
1996     m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, startY, endY, this ) );
1997 
1998     for (int i = startY; i <= endY; i++)
1999     {
2000         m_lines[i].m_text.insert( 0u, wxT("    ") );
2001         RefreshLine( i );
2002     }
2003 }
2004 
Unindent()2005 void wxTextCtrl::Unindent()
2006 {
2007     int startY = m_cursorY;
2008     int endY = m_cursorY;
2009     if (HasSelection())
2010     {
2011         startY = m_selStartY;
2012         endY = m_selEndY;
2013         if (endY < startY)
2014         {
2015             int tmp = startY;
2016             startY = endY;
2017             endY = tmp;
2018         }
2019     }
2020 
2021     m_undos.Append( new wxSourceUndoStep( wxSOURCE_UNDO_LINE, startY, endY, this ) );
2022 
2023     for (int i = startY; i <= endY; i++)
2024     {
2025         for (int n = 0; n < 4; n++)
2026         {
2027             if (m_lines[i].m_text[0u] == wxT(' '))
2028                 m_lines[i].m_text.erase(0u,1u);
2029         }
2030         RefreshLine( i );
2031     }
2032 }
HasSelection()2033 bool wxTextCtrl::HasSelection()
2034 {
2035     return ((m_selStartY != m_selEndY) || (m_selStartX != m_selEndX));
2036 }
2037 
ClearSelection()2038 void wxTextCtrl::ClearSelection()
2039 {
2040     m_selStartX = -1;
2041     m_selStartY = -1;
2042     m_selEndX = -1;
2043     m_selEndY = -1;
2044 }
2045 
RefreshLine(int n)2046 void wxTextCtrl::RefreshLine( int n )
2047 {
2048     int y = n*m_lineHeight;
2049     int x = 0;
2050     CalcScrolledPosition( x, y, &x, &y );
2051     wxRect rect( 0+2, y+2, 10000, m_lineHeight );
2052     Refresh( true, &rect );
2053 }
2054 
RefreshDown(int n)2055 void wxTextCtrl::RefreshDown( int n )
2056 {
2057     int size_x = 0;
2058     int size_y = 0;
2059     GetClientSize( &size_x, &size_y );
2060 
2061     int view_x = 0;
2062     int view_y = 0;
2063     GetViewStart( &view_x, &view_y );
2064 
2065     if (n < view_y)
2066     {
2067         Refresh();
2068     }
2069     else
2070     {
2071         int y = n*m_lineHeight;
2072         int x = 0;
2073         CalcScrolledPosition( x, y, &x, &y );
2074 
2075         wxRect rect( 0+2, y+2, 10000, size_y );
2076         Refresh( true, &rect );
2077     }
2078 }
2079 
MoveCursor(int new_x,int new_y,bool shift,bool centre)2080 void wxTextCtrl::MoveCursor( int new_x, int new_y, bool shift, bool centre )
2081 {
2082     if (!m_editable) return;
2083 
2084     // if (IsSingleLine() || (m_lang == wxSOURCE_LANG_NONE))
2085     {
2086         if (new_x > (int) (m_lines[new_y].m_text.Len()))
2087             new_x = m_lines[new_y].m_text.Len();
2088     }
2089 
2090     if ((new_x == m_cursorX) && (new_y == m_cursorY)) return;
2091 
2092     bool no_cursor_refresh = false;
2093     bool has_selection = HasSelection();
2094 
2095     if (shift)
2096     {
2097         int x,y,w,h;
2098         bool erase_background = true;
2099 
2100         if (!has_selection)
2101         {
2102             m_selStartX = m_cursorX;
2103             m_selStartY = m_cursorY;
2104 
2105             x = 0;
2106             w = 10000;
2107             if (new_y > m_selStartY)
2108             {
2109                 y = m_selStartY*m_lineHeight;
2110                 h = (new_y-m_selStartY+1)*m_lineHeight;
2111             }
2112             else if (new_y == m_selStartY)
2113             {
2114                 x = PosToPixel( new_y, m_selStartX );
2115                 w = PosToPixel( new_y, new_x ) - x;
2116                 if (w < 0)
2117                 {
2118                     x += w;
2119                     w = -w + 2; // +2 for the cursor
2120                 }
2121                 y = m_selStartY*m_lineHeight;
2122                 h = m_lineHeight;
2123             }
2124             else
2125             {
2126                 y = new_y*m_lineHeight;
2127                 h = (-new_y+m_selStartY+1)*m_lineHeight;
2128             }
2129 
2130             no_cursor_refresh = true;
2131             m_cursorX = new_x;
2132             m_cursorY = new_y;
2133         }
2134         else
2135         {
2136             if (new_y == m_selEndY)
2137             {
2138                 y = new_y *m_lineHeight;
2139                 h = m_lineHeight;
2140                 if (m_selEndX > new_x)
2141                 {
2142                     // x = new_x*m_charWidth;
2143                     x = PosToPixel( new_y, new_x );
2144                     // w = (m_selEndX-new_x)*m_charWidth;
2145                     w = PosToPixel( new_y, m_selEndX ) - x;
2146                 }
2147                 else
2148                 {
2149                     // x = m_selEndX*m_charWidth;
2150                     x = PosToPixel( new_y, m_selEndX );
2151                     // w = (-m_selEndX+new_x)*m_charWidth;
2152                     w = PosToPixel( new_y, new_x ) - x;
2153                 }
2154             }
2155             else
2156             {
2157                 x = 0;
2158                 w = 10000;
2159                 if (new_y > m_selEndY)
2160                 {
2161                     y = m_selEndY*m_lineHeight;
2162                     h = (new_y-m_selEndY+1) * m_lineHeight;
2163 
2164                     erase_background = ((m_selEndY < m_selStartY) ||
2165                                         ((m_selEndY == m_selStartY) && (m_selEndX < m_selStartX)));
2166                 }
2167                 else
2168                 {
2169                     y = new_y*m_lineHeight;
2170                     h = (-new_y+m_selEndY+1) * m_lineHeight;
2171 
2172                     erase_background = ((m_selEndY > m_selStartY) ||
2173                                         ((m_selEndY == m_selStartY) && (m_selEndX > m_selStartX)));
2174                 }
2175                 no_cursor_refresh = true;
2176                 m_cursorX = new_x;
2177                 m_cursorY = new_y;
2178             }
2179         }
2180 
2181         m_selEndX = new_x;
2182         m_selEndY = new_y;
2183 
2184         CalcScrolledPosition( x, y, &x, &y );
2185         wxRect rect( x+2, y+2, w, h );
2186         Refresh( erase_background, &rect );
2187     }
2188     else
2189     {
2190         if (has_selection)
2191         {
2192             int ry1 = m_selEndY;
2193             int ry2 = m_selStartY;
2194             m_selEndX = -1;
2195             m_selEndY = -1;
2196             m_selStartX = -1;
2197             m_selStartY = -1;
2198 
2199             if (ry1 > ry2)
2200             {
2201                 int tmp = ry2;
2202                 ry2 = ry1;
2203                 ry1 = tmp;
2204             }
2205 
2206             int x = 0;
2207             int y = ry1*m_lineHeight;
2208             CalcScrolledPosition( x, y, &x, &y );
2209             wxRect rect( 0, y+2, 10000, (ry2-ry1+1)*m_lineHeight );
2210 
2211             Refresh( true, &rect );
2212         }
2213     }
2214 
2215 /*
2216     printf( "startx %d starty %d endx %d endy %d\n",
2217             m_selStartX, m_selStartY, m_selEndX, m_selEndY );
2218 
2219     printf( "has %d\n", (int)HasSelection() );
2220 */
2221 
2222     if (!no_cursor_refresh)
2223     {
2224         // int x = m_cursorX*m_charWidth;
2225         int x = PosToPixel( m_cursorY, m_cursorX );
2226         int y = m_cursorY*m_lineHeight;
2227         CalcScrolledPosition( x, y, &x, &y );
2228         wxRect rect( x+2, y+2, 4, m_lineHeight+2 );
2229 
2230         m_cursorX = new_x;
2231         m_cursorY = new_y;
2232 
2233         Refresh( true, &rect );
2234 
2235         if (FindFocus() == this)
2236         {
2237             wxClientDC dc(this);
2238             PrepareDC( dc );
2239             dc.SetPen( *wxTRANSPARENT_PEN );
2240             //dc.SetBrush( *wxRED_BRUSH );
2241             dc.SetBrush( *wxBLACK_BRUSH );
2242             // int xx = m_cursorX*m_charWidth;
2243             int xx = PosToPixel( m_cursorY, m_cursorX );
2244             dc.DrawRectangle( xx+2, m_cursorY*m_lineHeight+2, 2, m_lineHeight );
2245         }
2246     }
2247 
2248     int size_x = 0;
2249     int size_y = 0;
2250     GetClientSize( &size_x, &size_y );
2251     size_x /= m_charWidth;
2252     size_y /= m_lineHeight;
2253 
2254     int view_x = 0;
2255     int view_y = 0;
2256     GetViewStart( &view_x, &view_y );
2257 
2258     if (centre)
2259     {
2260         int sy = m_cursorY - (size_y/2);
2261         if (sy < 0) sy = 0;
2262         Scroll( -1, sy );
2263     }
2264     else
2265     {
2266         if (m_cursorY < view_y)
2267             Scroll( -1, m_cursorY );
2268         else if (m_cursorY > view_y+size_y-1)
2269             Scroll( -1, m_cursorY-size_y+1 );
2270     }
2271 
2272     //int xx = m_cursorX;
2273     int xx = PosToPixel( m_cursorY, m_cursorX ) / m_charWidth;
2274 
2275     if (xx < view_x)
2276         Scroll( xx, -1 );
2277     else if (xx > view_x+size_x-1)
2278         Scroll( xx-size_x+1, -1 );
2279 }
2280 
MyAdjustScrollbars()2281 void wxTextCtrl::MyAdjustScrollbars()
2282 {
2283     if (IsSingleLine())
2284         return;
2285 
2286     int y_range = m_lines.GetCount();
2287 
2288     int height = 0;
2289     GetClientSize( NULL, &height );
2290     height -= 4;
2291     if (height >= (int)m_lines.GetCount() *m_lineHeight)
2292         y_range = 0;
2293 
2294     int view_x = 0;
2295     int view_y = 0;
2296     GetViewStart( &view_x, &view_y );
2297 
2298     SetScrollbars( m_charWidth, m_lineHeight, m_longestLine+2, y_range, view_x, view_y );
2299 }
2300 
2301 //-----------------------------------------------------------------------------
2302 //  clipboard handlers
2303 //-----------------------------------------------------------------------------
2304 
OnCut(wxCommandEvent & WXUNUSED (event))2305 void wxTextCtrl::OnCut(wxCommandEvent& WXUNUSED(event))
2306 {
2307     Cut();
2308 }
2309 
OnCopy(wxCommandEvent & WXUNUSED (event))2310 void wxTextCtrl::OnCopy(wxCommandEvent& WXUNUSED(event))
2311 {
2312     Copy();
2313 }
2314 
OnPaste(wxCommandEvent & WXUNUSED (event))2315 void wxTextCtrl::OnPaste(wxCommandEvent& WXUNUSED(event))
2316 {
2317     Paste();
2318 }
2319 
OnUndo(wxCommandEvent & WXUNUSED (event))2320 void wxTextCtrl::OnUndo(wxCommandEvent& WXUNUSED(event))
2321 {
2322     Undo();
2323 }
2324 
OnRedo(wxCommandEvent & WXUNUSED (event))2325 void wxTextCtrl::OnRedo(wxCommandEvent& WXUNUSED(event))
2326 {
2327     Redo();
2328 }
2329 
OnUpdateCut(wxUpdateUIEvent & event)2330 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
2331 {
2332     event.Enable( CanCut() );
2333 }
2334 
OnUpdateCopy(wxUpdateUIEvent & event)2335 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
2336 {
2337     event.Enable( CanCopy() );
2338 }
2339 
OnUpdatePaste(wxUpdateUIEvent & event)2340 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
2341 {
2342     event.Enable( CanPaste() );
2343 }
2344 
OnUpdateUndo(wxUpdateUIEvent & event)2345 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
2346 {
2347     event.Enable( CanUndo() );
2348 }
2349 
OnUpdateRedo(wxUpdateUIEvent & event)2350 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
2351 {
2352     event.Enable( CanRedo() );
2353 }
2354 
DoGetBestSize() const2355 wxSize wxTextCtrl::DoGetBestSize() const
2356 {
2357     if (IsSingleLine())
2358     {
2359         wxSize ret(80, m_lineHeight + 4);
2360 
2361         if (HasFlag(wxBORDER_SUNKEN) || HasFlag(wxBORDER_RAISED))
2362             ret.y += 4;
2363 
2364         if (HasFlag(wxBORDER_SIMPLE))
2365             ret.y += 2;
2366 
2367         return ret;
2368     }
2369     else
2370     {
2371         return wxSize(80, 60);
2372     }
2373 }
2374 
OnSetFocus(wxFocusEvent & event)2375 void wxTextCtrl::OnSetFocus( wxFocusEvent& event )
2376 {
2377     // To hide or show caret, as appropriate
2378     Refresh();
2379 }
2380 
OnKillFocus(wxFocusEvent & event)2381 void wxTextCtrl::OnKillFocus( wxFocusEvent& event )
2382 {
2383     // To hide or show caret, as appropriate
2384     Refresh();
2385 }
2386 
2387 // ----------------------------------------------------------------------------
2388 // text control scrolling
2389 // ----------------------------------------------------------------------------
2390 
ScrollLines(int lines)2391 bool wxTextCtrl::ScrollLines(int lines)
2392 {
2393     wxFAIL_MSG( "wxTextCtrl::ScrollLines not implemented");
2394 
2395     return false;
2396 }
2397 
ScrollPages(int pages)2398 bool wxTextCtrl::ScrollPages(int pages)
2399 {
2400     wxFAIL_MSG( "wxTextCtrl::ScrollPages not implemented");
2401 
2402     return false;
2403 }
2404