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