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