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