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