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