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