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