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