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