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