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