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