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