]> git.saurik.com Git - wxWidgets.git/blob - src/msw/textctrl.cpp
1. panels pass focus to the next item in parent panel
[wxWidgets.git] / src / msw / textctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: textctrl.cpp
3 // Purpose: wxTextCtrl
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 #ifdef __GNUG__
17 #pragma implementation "textctrl.h"
18 #endif
19
20 // ----------------------------------------------------------------------------
21 // headers
22 // ----------------------------------------------------------------------------
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32 #include "wx/textctrl.h"
33 #include "wx/settings.h"
34 #include "wx/brush.h"
35 #include "wx/utils.h"
36 #include "wx/log.h"
37 #endif
38
39 #if wxUSE_CLIPBOARD
40 #include "wx/app.h"
41 #include "wx/clipbrd.h"
42 #endif
43
44 #include "wx/textfile.h"
45
46 #include <windowsx.h>
47
48 #include "wx/msw/private.h"
49
50 #include <string.h>
51 #include <stdlib.h>
52 #include <sys/types.h>
53
54 #if wxUSE_IOSTREAMH
55 # include <fstream.h>
56 #else
57 # include <fstream>
58 #endif
59
60 #if wxUSE_RICHEDIT && !defined(__GNUWIN32__)
61 #include <richedit.h>
62 #endif
63
64 #if !USE_SHARED_LIBRARY
65
66 // ----------------------------------------------------------------------------
67 // event tables and other macros
68 // ----------------------------------------------------------------------------
69
70 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
71
72 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
73 EVT_CHAR(wxTextCtrl::OnChar)
74 EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
75
76 EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
77 EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
78 EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
79 EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
80 EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
81
82 EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
83 EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
84 EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
85 EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
86 EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
87 END_EVENT_TABLE()
88
89 #endif // USE_SHARED_LIBRARY
90
91 // ============================================================================
92 // implementation
93 // ============================================================================
94
95 // ----------------------------------------------------------------------------
96 // creation
97 // ----------------------------------------------------------------------------
98
99 wxTextCtrl::wxTextCtrl()
100 {
101 #if wxUSE_RICHEDIT
102 m_isRich = FALSE;
103 #endif
104 }
105
106 bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
107 const wxString& value,
108 const wxPoint& pos,
109 const wxSize& size,
110 long style,
111 const wxValidator& validator,
112 const wxString& name)
113 {
114 // base initialization
115 if ( !CreateBase(parent, id, pos, size, style, name) )
116 return FALSE;
117
118 SetValidator(validator);
119 if ( parent )
120 parent->AddChild(this);
121
122 // set colours
123 SetupColours();
124
125 // translate wxWin style flags to MSW ones, checking for consistency while
126 // doing it
127 long msStyle = ES_LEFT | WS_VISIBLE | WS_CHILD | WS_TABSTOP;
128 if ( m_windowStyle & wxTE_MULTILINE )
129 {
130 wxASSERT_MSG( !(m_windowStyle & wxTE_PROCESS_ENTER),
131 _T("wxTE_PROCESS_ENTER style is ignored for multiline "
132 "text controls (they always process it)") );
133
134 msStyle |= ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL;
135 m_windowStyle |= wxTE_PROCESS_ENTER;
136 }
137 else
138 msStyle |= ES_AUTOHSCROLL;
139
140 if (m_windowStyle & wxTE_READONLY)
141 msStyle |= ES_READONLY;
142
143 if (m_windowStyle & wxHSCROLL)
144 msStyle |= (WS_HSCROLL | ES_AUTOHSCROLL);
145 if (m_windowStyle & wxTE_PASSWORD) // hidden input
146 msStyle |= ES_PASSWORD;
147
148 // we always want the characters and the arrows
149 m_lDlgCode = DLGC_WANTCHARS | DLGC_WANTARROWS;
150
151 // we may have several different cases:
152 // 1. normal case: both TAB and ENTER are used for dialog navigation
153 // 2. ctrl which wants TAB for itself: ENTER is used to pass to the next
154 // control in the dialog
155 // 3. ctrl which wants ENTER for itself: TAB is used for dialog navigation
156 // 4. ctrl which wants both TAB and ENTER: Ctrl-ENTER is used to pass to
157 // the next control
158 if ( m_windowStyle & wxTE_PROCESS_ENTER )
159 m_lDlgCode |= DLGC_WANTMESSAGE;
160 if ( m_windowStyle & wxTE_PROCESS_TAB )
161 m_lDlgCode |= DLGC_WANTTAB;
162
163 // do create the control - either an EDIT or RICHEDIT
164 const wxChar *windowClass = _T("EDIT");
165
166 #if wxUSE_RICHEDIT
167 // multiline edit controls are RICHEDITs except for those which have a
168 // simple border (VZ: why??)
169 if ( (m_windowStyle & wxTE_MULTILINE) &&
170 !(m_windowStyle & wxSIMPLE_BORDER) )
171 {
172 msStyle |= ES_AUTOVSCROLL;
173 m_isRich = TRUE;
174 windowClass = _T("RICHEDIT");
175 }
176 else
177 m_isRich = FALSE;
178 #endif
179
180 bool want3D;
181 WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D);
182
183 // Even with extended styles, need to combine with WS_BORDER for them to
184 // look right.
185 if ( want3D || wxStyleHasBorder(m_windowStyle) )
186 msStyle |= WS_BORDER;
187
188 // NB: don't use pos and size as CreateWindowEx arguments because they
189 // might be -1 in which case we should use the default values (and
190 // SetSize called below takes care of it)
191 m_hWnd = (WXHWND)::CreateWindowEx(exStyle,
192 windowClass,
193 NULL,
194 msStyle,
195 0, 0, 0, 0,
196 GetHwndOf(parent),
197 (HMENU)m_windowId,
198 wxGetInstance(),
199 NULL);
200
201 wxCHECK_MSG( m_hWnd, FALSE, _T("Failed to create text ctrl") );
202
203 #if wxUSE_CTL3D
204 if ( want3D )
205 {
206 Ctl3dSubclassCtl(GetHwnd());
207 m_useCtl3D = TRUE;
208 }
209 #endif
210
211 #if wxUSE_RICHEDIT
212 if (m_isRich)
213 {
214 // Have to enable events
215 ::SendMessage(GetHwnd(), EM_SETEVENTMASK, 0,
216 ENM_CHANGE | ENM_DROPFILES | ENM_SELCHANGE | ENM_UPDATE);
217 }
218 #endif
219
220 SubclassWin(GetHWND());
221
222 // set font, position, size and initial value
223 wxFont& fontParent = parent->GetFont();
224 if ( fontParent.Ok() )
225 {
226 SetFont(fontParent);
227 }
228 else
229 {
230 SetFont(wxSystemSettings::GetSystemFont(wxSYS_SYSTEM_FONT));
231 }
232
233 // Causes a crash for Symantec C++ and WIN32 for some reason
234 #if !(defined(__SC__) && defined(__WIN32__))
235 if ( !value.IsEmpty() )
236 {
237 SetValue(value);
238 }
239 #endif
240
241 SetSize(pos.x, pos.y, size.x, size.y);
242
243 return TRUE;
244 }
245
246 // Make sure the window style (etc.) reflects the HWND style (roughly)
247 void wxTextCtrl::AdoptAttributesFromHWND()
248 {
249 wxWindow::AdoptAttributesFromHWND();
250
251 HWND hWnd = GetHwnd();
252 long style = GetWindowLong(hWnd, GWL_STYLE);
253
254 // retrieve the style to see whether this is an edit or richedit ctrl
255 #if wxUSE_RICHEDIT
256 wxChar buf[256];
257
258 GetClassName(hWnd, buf, WXSIZEOF(buf));
259
260 if ( wxStricmp(buf, _T("EDIT")) == 0 )
261 m_isRich = FALSE;
262 else
263 m_isRich = TRUE;
264 #endif // wxUSE_RICHEDIT
265
266 if (style & ES_MULTILINE)
267 m_windowStyle |= wxTE_MULTILINE;
268 if (style & ES_PASSWORD)
269 m_windowStyle |= wxTE_PASSWORD;
270 if (style & ES_READONLY)
271 m_windowStyle |= wxTE_READONLY;
272 if (style & ES_WANTRETURN)
273 m_windowStyle |= wxTE_PROCESS_ENTER;
274 }
275
276 void wxTextCtrl::SetupColours()
277 {
278 // FIXME why is bg colour not inherited from parent?
279 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
280 SetForegroundColour(GetParent()->GetForegroundColour());
281 }
282
283 // ----------------------------------------------------------------------------
284 // set/get the controls text
285 // ----------------------------------------------------------------------------
286
287 wxString wxTextCtrl::GetValue() const
288 {
289 return wxGetWindowText(GetHWND());
290 }
291
292 void wxTextCtrl::SetValue(const wxString& value)
293 {
294 wxString valueDos = wxTextFile::Translate(value, wxTextFileType_Dos);
295
296 SetWindowText(GetHwnd(), valueDos);
297
298 AdjustSpaceLimit();
299 }
300
301 void wxTextCtrl::WriteText(const wxString& value)
302 {
303 wxString valueDos = wxTextFile::Translate(value, wxTextFileType_Dos);
304
305 SendMessage(GetHwnd(), EM_REPLACESEL, 0, (LPARAM)valueDos.c_str());
306
307 AdjustSpaceLimit();
308 }
309
310 void wxTextCtrl::AppendText(const wxString& text)
311 {
312 SetInsertionPointEnd();
313 WriteText(text);
314 }
315
316 void wxTextCtrl::Clear()
317 {
318 SetWindowText(GetHwnd(), _T(""));
319 }
320
321 // ----------------------------------------------------------------------------
322 // Clipboard operations
323 // ----------------------------------------------------------------------------
324
325 void wxTextCtrl::Copy()
326 {
327 if (CanCopy())
328 {
329 HWND hWnd = GetHwnd();
330 SendMessage(hWnd, WM_COPY, 0, 0L);
331 }
332 }
333
334 void wxTextCtrl::Cut()
335 {
336 if (CanCut())
337 {
338 HWND hWnd = GetHwnd();
339 SendMessage(hWnd, WM_CUT, 0, 0L);
340 }
341 }
342
343 void wxTextCtrl::Paste()
344 {
345 if (CanPaste())
346 {
347 HWND hWnd = GetHwnd();
348 SendMessage(hWnd, WM_PASTE, 0, 0L);
349 }
350 }
351
352 bool wxTextCtrl::CanCopy() const
353 {
354 // Can copy if there's a selection
355 long from, to;
356 GetSelection(& from, & to);
357 return (from != to);
358 }
359
360 bool wxTextCtrl::CanCut() const
361 {
362 // Can cut if there's a selection
363 long from, to;
364 GetSelection(& from, & to);
365 return (from != to);
366 }
367
368 bool wxTextCtrl::CanPaste() const
369 {
370 #if wxUSE_RICHEDIT
371 if (m_isRich)
372 {
373 int dataFormat = 0; // 0 == any format
374 return (::SendMessage( GetHwnd(), EM_CANPASTE, (WPARAM) (UINT) dataFormat, 0) != 0);
375 }
376 #endif
377 if (!IsEditable())
378 return FALSE;
379
380 // Standard edit control: check for straight text on clipboard
381 bool isTextAvailable = FALSE;
382 if ( ::OpenClipboard(GetHwndOf(wxTheApp->GetTopWindow())) )
383 {
384 isTextAvailable = (::IsClipboardFormatAvailable(CF_TEXT) != 0);
385 ::CloseClipboard();
386 }
387
388 return isTextAvailable;
389 }
390
391 // ----------------------------------------------------------------------------
392 // Accessors
393 // ----------------------------------------------------------------------------
394
395 void wxTextCtrl::SetEditable(bool editable)
396 {
397 HWND hWnd = GetHwnd();
398 SendMessage(hWnd, EM_SETREADONLY, (WPARAM)!editable, (LPARAM)0L);
399 }
400
401 void wxTextCtrl::SetInsertionPoint(long pos)
402 {
403 HWND hWnd = GetHwnd();
404 #ifdef __WIN32__
405 #if wxUSE_RICHEDIT
406 if ( m_isRich)
407 {
408 CHARRANGE range;
409 range.cpMin = pos;
410 range.cpMax = pos;
411 SendMessage(hWnd, EM_EXSETSEL, 0, (LPARAM) &range);
412 SendMessage(hWnd, EM_SCROLLCARET, (WPARAM)0, (LPARAM)0);
413 }
414 else
415 #endif // wxUSE_RICHEDIT
416 {
417 SendMessage(hWnd, EM_SETSEL, pos, pos);
418 SendMessage(hWnd, EM_SCROLLCARET, (WPARAM)0, (LPARAM)0);
419 }
420 #else // Win16
421 SendMessage(hWnd, EM_SETSEL, 0, MAKELPARAM(pos, pos));
422 #endif // Win32/16
423
424 static const char *nothing = "";
425 SendMessage(hWnd, EM_REPLACESEL, 0, (LPARAM)nothing);
426 }
427
428 void wxTextCtrl::SetInsertionPointEnd()
429 {
430 long pos = GetLastPosition();
431 SetInsertionPoint(pos);
432 }
433
434 long wxTextCtrl::GetInsertionPoint() const
435 {
436 #if wxUSE_RICHEDIT
437 if (m_isRich)
438 {
439 CHARRANGE range;
440 range.cpMin = 0;
441 range.cpMax = 0;
442 SendMessage(GetHwnd(), EM_EXGETSEL, 0, (LPARAM) &range);
443 return range.cpMin;
444 }
445 #endif
446
447 DWORD Pos = (DWORD)SendMessage(GetHwnd(), EM_GETSEL, 0, 0L);
448 return Pos & 0xFFFF;
449 }
450
451 long wxTextCtrl::GetLastPosition() const
452 {
453 HWND hWnd = GetHwnd();
454
455 // Will always return a number > 0 (according to docs)
456 int noLines = (int)SendMessage(hWnd, EM_GETLINECOUNT, (WPARAM)0, (LPARAM)0L);
457
458 // This gets the char index for the _beginning_ of the last line
459 int charIndex = (int)SendMessage(hWnd, EM_LINEINDEX, (WPARAM)(noLines-1), (LPARAM)0L);
460
461 // Get number of characters in the last line. We'll add this to the character
462 // index for the last line, 1st position.
463 int lineLength = (int)SendMessage(hWnd, EM_LINELENGTH, (WPARAM)charIndex, (LPARAM)0L);
464
465 return (long)(charIndex + lineLength);
466 }
467
468 // If the return values from and to are the same, there is no
469 // selection.
470 void wxTextCtrl::GetSelection(long* from, long* to) const
471 {
472 #if wxUSE_RICHEDIT
473 if (m_isRich)
474 {
475 CHARRANGE charRange;
476 ::SendMessage(GetHwnd(), EM_EXGETSEL, 0, (LPARAM) (CHARRANGE*) & charRange);
477
478 *from = charRange.cpMin;
479 *to = charRange.cpMax;
480
481 return;
482 }
483 #endif
484 DWORD dwStart, dwEnd;
485 WPARAM wParam = (WPARAM) (DWORD*) & dwStart; // receives starting position
486 LPARAM lParam = (LPARAM) (DWORD*) & dwEnd; // receives ending position
487
488 ::SendMessage(GetHwnd(), EM_GETSEL, wParam, lParam);
489
490 *from = dwStart;
491 *to = dwEnd;
492 }
493
494 bool wxTextCtrl::IsEditable() const
495 {
496 long style = ::GetWindowLong(GetHwnd(), GWL_STYLE);
497
498 return ((style & ES_READONLY) == 0);
499 }
500
501 // ----------------------------------------------------------------------------
502 // Editing
503 // ----------------------------------------------------------------------------
504
505 void wxTextCtrl::Replace(long from, long to, const wxString& value)
506 {
507 #if wxUSE_CLIPBOARD
508 HWND hWnd = GetHwnd();
509 long fromChar = from;
510 long toChar = to;
511
512 // Set selection and remove it
513 #ifdef __WIN32__
514 SendMessage(hWnd, EM_SETSEL, fromChar, toChar);
515 #else
516 SendMessage(hWnd, EM_SETSEL, (WPARAM)0, (LPARAM)MAKELONG(fromChar, toChar));
517 #endif
518 SendMessage(hWnd, WM_CUT, (WPARAM)0, (LPARAM)0);
519
520 // Now replace with 'value', by pasting.
521 wxSetClipboardData(wxDF_TEXT, (wxObject *) (const wxChar *)value, 0, 0);
522
523 // Paste into edit control
524 SendMessage(hWnd, WM_PASTE, (WPARAM)0, (LPARAM)0L);
525 #else
526 wxFAIL_MSG("wxTextCtrl::Replace not implemented if wxUSE_CLIPBOARD is 0.");
527 #endif
528 }
529
530 void wxTextCtrl::Remove(long from, long to)
531 {
532 HWND hWnd = GetHwnd();
533 long fromChar = from;
534 long toChar = to;
535
536 // Cut all selected text
537 #ifdef __WIN32__
538 SendMessage(hWnd, EM_SETSEL, fromChar, toChar);
539 #else
540 SendMessage(hWnd, EM_SETSEL, (WPARAM)0, (LPARAM)MAKELONG(fromChar, toChar));
541 #endif
542 SendMessage(hWnd, WM_CUT, (WPARAM)0, (LPARAM)0);
543 }
544
545 void wxTextCtrl::SetSelection(long from, long to)
546 {
547 HWND hWnd = GetHwnd();
548 long fromChar = from;
549 long toChar = to;
550
551 // if from and to are both -1, it means (in wxWindows) that all text should
552 // be selected. Translate into Windows convention
553 if ((from == -1) && (to == -1))
554 {
555 fromChar = 0;
556 toChar = -1;
557 }
558
559 #ifdef __WIN32__
560 SendMessage(hWnd, EM_SETSEL, (WPARAM)fromChar, (LPARAM)toChar);
561 SendMessage(hWnd, EM_SCROLLCARET, (WPARAM)0, (LPARAM)0);
562 #else
563 // WPARAM is 0: selection is scrolled into view
564 SendMessage(hWnd, EM_SETSEL, (WPARAM)0, (LPARAM)MAKELONG(fromChar, toChar));
565 #endif
566 }
567
568 bool wxTextCtrl::LoadFile(const wxString& file)
569 {
570 if ( wxTextCtrlBase::LoadFile(file) )
571 {
572 // update the size limit if needed
573 AdjustSpaceLimit();
574
575 return TRUE;
576 }
577
578 return FALSE;
579 }
580
581 bool wxTextCtrl::IsModified() const
582 {
583 return (SendMessage(GetHwnd(), EM_GETMODIFY, 0, 0) != 0);
584 }
585
586 // Makes 'unmodified'
587 void wxTextCtrl::DiscardEdits()
588 {
589 SendMessage(GetHwnd(), EM_SETMODIFY, FALSE, 0L);
590 }
591
592 int wxTextCtrl::GetNumberOfLines() const
593 {
594 return (int)SendMessage(GetHwnd(), EM_GETLINECOUNT, (WPARAM)0, (LPARAM)0);
595 }
596
597 long wxTextCtrl::XYToPosition(long x, long y) const
598 {
599 HWND hWnd = GetHwnd();
600
601 // This gets the char index for the _beginning_ of this line
602 int charIndex = (int)SendMessage(hWnd, EM_LINEINDEX, (WPARAM)y, (LPARAM)0);
603 return (long)(x + charIndex);
604 }
605
606 bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
607 {
608 HWND hWnd = GetHwnd();
609
610 // This gets the line number containing the character
611 int lineNo;
612 #if wxUSE_RICHEDIT
613 if ( m_isRich )
614 {
615 lineNo = (int)SendMessage(hWnd, EM_EXLINEFROMCHAR, 0, (LPARAM)pos);
616 }
617 else
618 #endif // wxUSE_RICHEDIT
619 lineNo = (int)SendMessage(hWnd, EM_LINEFROMCHAR, (WPARAM)pos, 0);
620
621 if ( lineNo == -1 )
622 {
623 // no such line
624 return FALSE;
625 }
626
627 // This gets the char index for the _beginning_ of this line
628 int charIndex = (int)SendMessage(hWnd, EM_LINEINDEX, (WPARAM)lineNo, (LPARAM)0);
629 if ( charIndex == -1 )
630 {
631 return FALSE;
632 }
633
634 // The X position must therefore be the different between pos and charIndex
635 if ( x )
636 *x = (long)(pos - charIndex);
637 if ( y )
638 *y = (long)lineNo;
639
640 return TRUE;
641 }
642
643 void wxTextCtrl::ShowPosition(long pos)
644 {
645 HWND hWnd = GetHwnd();
646
647 // To scroll to a position, we pass the number of lines and characters
648 // to scroll *by*. This means that we need to:
649 // (1) Find the line position of the current line.
650 // (2) Find the line position of pos.
651 // (3) Scroll by (pos - current).
652 // For now, ignore the horizontal scrolling.
653
654 // Is this where scrolling is relative to - the line containing the caret?
655 // Or is the first visible line??? Try first visible line.
656 // int currentLineLineNo1 = (int)SendMessage(hWnd, EM_LINEFROMCHAR, (WPARAM)-1, (LPARAM)0L);
657
658 int currentLineLineNo = (int)SendMessage(hWnd, EM_GETFIRSTVISIBLELINE, (WPARAM)0, (LPARAM)0L);
659
660 int specifiedLineLineNo = (int)SendMessage(hWnd, EM_LINEFROMCHAR, (WPARAM)pos, (LPARAM)0L);
661
662 int linesToScroll = specifiedLineLineNo - currentLineLineNo;
663
664 if (linesToScroll != 0)
665 (void)SendMessage(hWnd, EM_LINESCROLL, (WPARAM)0, (LPARAM)linesToScroll);
666 }
667
668 int wxTextCtrl::GetLineLength(long lineNo) const
669 {
670 long charIndex = XYToPosition(0, lineNo);
671 int len = (int)SendMessage(GetHwnd(), EM_LINELENGTH, charIndex, 0);
672 return len;
673 }
674
675 wxString wxTextCtrl::GetLineText(long lineNo) const
676 {
677 size_t len = (size_t)GetLineLength(lineNo) + 1;
678 char *buf = (char *)malloc(len);
679 *(WORD *)buf = len;
680 int noChars = (int)SendMessage(GetHwnd(), EM_GETLINE, lineNo, (LPARAM)buf);
681 buf[noChars] = 0;
682
683 wxString str(buf);
684
685 free(buf);
686
687 return str;
688 }
689
690 // ----------------------------------------------------------------------------
691 // Undo/redo
692 // ----------------------------------------------------------------------------
693
694 void wxTextCtrl::Undo()
695 {
696 if (CanUndo())
697 {
698 ::SendMessage(GetHwnd(), EM_UNDO, 0, 0);
699 }
700 }
701
702 void wxTextCtrl::Redo()
703 {
704 if (CanRedo())
705 {
706 // Same as Undo, since Undo undoes the undo, i.e. a redo.
707 ::SendMessage(GetHwnd(), EM_UNDO, 0, 0);
708 }
709 }
710
711 bool wxTextCtrl::CanUndo() const
712 {
713 return (::SendMessage(GetHwnd(), EM_CANUNDO, 0, 0) != 0);
714 }
715
716 bool wxTextCtrl::CanRedo() const
717 {
718 return (::SendMessage(GetHwnd(), EM_CANUNDO, 0, 0) != 0);
719 }
720
721 // ----------------------------------------------------------------------------
722 // implemenation details
723 // ----------------------------------------------------------------------------
724
725 void wxTextCtrl::Command(wxCommandEvent & event)
726 {
727 SetValue(event.GetString());
728 ProcessCommand (event);
729 }
730
731 void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
732 {
733 // By default, load the first file into the text window.
734 if (event.GetNumberOfFiles() > 0)
735 {
736 LoadFile(event.GetFiles()[0]);
737 }
738 }
739
740 WXHBRUSH wxTextCtrl::OnCtlColor(WXHDC pDC, WXHWND pWnd, WXUINT nCtlColor,
741 WXUINT message, WXWPARAM wParam,
742 WXLPARAM lParam)
743 {
744 #if wxUSE_CTL3D
745 if ( m_useCtl3D )
746 {
747 HBRUSH hbrush = Ctl3dCtlColorEx(message, wParam, lParam);
748 return (WXHBRUSH) hbrush;
749 }
750 #endif
751
752 HDC hdc = (HDC)pDC;
753 SetBkMode(hdc, GetParent()->GetTransparentBackground() ? TRANSPARENT
754 : OPAQUE);
755
756 ::SetBkColor(hdc, RGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue()));
757 ::SetTextColor(hdc, RGB(GetForegroundColour().Red(), GetForegroundColour().Green(), GetForegroundColour().Blue()));
758
759 wxBrush *backgroundBrush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID);
760
761 return (WXHBRUSH) backgroundBrush->GetResourceHandle();
762 }
763
764 void wxTextCtrl::OnChar(wxKeyEvent& event)
765 {
766 switch ( event.KeyCode() )
767 {
768 case WXK_RETURN:
769 if ( !(m_windowStyle & wxTE_MULTILINE) )
770 {
771 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
772 event.SetEventObject( this );
773 if ( GetEventHandler()->ProcessEvent(event) )
774 return;
775 }
776 //else: multiline controls need Enter for themselves
777
778 break;
779
780 case WXK_TAB:
781 // always produce navigation event - even if we process TAB
782 // ourselves the fact that we got here means that the user code
783 // decided to skip processing of this TAB - probably to let it
784 // do its default job.
785 //
786 // NB: Notice that Ctrl-Tab is handled elsewhere and Alt-Tab is
787 // handled by Windows
788 {
789 wxNavigationKeyEvent eventNav;
790 eventNav.SetDirection(!event.ShiftDown());
791 eventNav.SetWindowChange(FALSE);
792 eventNav.SetEventObject(this);
793
794 if ( GetEventHandler()->ProcessEvent(eventNav) )
795 return;
796 }
797 break;
798
799 default:
800 event.Skip();
801 return;
802 }
803
804 // don't just call event.Skip() because this will cause TABs and ENTERs
805 // be passed upwards and we don't always want this - instead process it
806 // right here
807
808 // FIXME
809 event.Skip();
810 }
811
812 bool wxTextCtrl::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
813 {
814 switch (param)
815 {
816 case EN_SETFOCUS:
817 case EN_KILLFOCUS:
818 {
819 wxFocusEvent event(param == EN_KILLFOCUS ? wxEVT_KILL_FOCUS
820 : wxEVT_SET_FOCUS,
821 m_windowId);
822 event.SetEventObject( this );
823 GetEventHandler()->ProcessEvent(event);
824 }
825 break;
826
827 case EN_CHANGE:
828 {
829 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_windowId);
830 wxString val(GetValue());
831 if ( !val.IsNull() )
832 event.m_commandString = WXSTRINGCAST val;
833 event.SetEventObject( this );
834 ProcessCommand(event);
835 }
836 break;
837
838 case EN_ERRSPACE:
839 // the text size limit has been hit - increase it
840 AdjustSpaceLimit();
841 break;
842
843 // the other notification messages are not processed
844 case EN_UPDATE:
845 case EN_MAXTEXT:
846 case EN_HSCROLL:
847 case EN_VSCROLL:
848 default:
849 return FALSE;
850 }
851
852 // processed
853 return TRUE;
854 }
855
856 void wxTextCtrl::AdjustSpaceLimit()
857 {
858 #ifndef __WIN16__
859 unsigned int len = ::GetWindowTextLength(GetHwnd()),
860 limit = ::SendMessage(GetHwnd(), EM_GETLIMITTEXT, 0, 0);
861 if ( len > limit )
862 {
863 limit = len + 0x8000; // 32Kb
864
865 #if wxUSE_RICHEDIT
866 if ( m_isRich || limit > 0xffff )
867 #else
868 if ( limit > 0xffff )
869 #endif
870 ::SendMessage(GetHwnd(), EM_LIMITTEXT, 0, limit);
871 else
872 ::SendMessage(GetHwnd(), EM_LIMITTEXT, limit, 0);
873 }
874 #endif
875 }
876
877 bool wxTextCtrl::AcceptsFocus() const
878 {
879 // we don't want focus if we can't be edited
880 return IsEditable() && wxControl::AcceptsFocus();
881 }
882
883 wxSize wxTextCtrl::DoGetBestSize()
884 {
885 int cx, cy;
886 wxGetCharSize(GetHWND(), &cx, &cy, &GetFont());
887
888 int wText = DEFAULT_ITEM_WIDTH;
889
890 int hText = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
891 if ( m_windowStyle & wxTE_MULTILINE )
892 {
893 hText *= wxMin(GetNumberOfLines(), 5);
894 }
895 //else: for single line control everything is ok
896
897 return wxSize(wText, hText);
898 }
899
900 // ----------------------------------------------------------------------------
901 // standard handlers for standard edit menu events
902 // ----------------------------------------------------------------------------
903
904 void wxTextCtrl::OnCut(wxCommandEvent& event)
905 {
906 Cut();
907 }
908
909 void wxTextCtrl::OnCopy(wxCommandEvent& event)
910 {
911 Copy();
912 }
913
914 void wxTextCtrl::OnPaste(wxCommandEvent& event)
915 {
916 Paste();
917 }
918
919 void wxTextCtrl::OnUndo(wxCommandEvent& event)
920 {
921 Undo();
922 }
923
924 void wxTextCtrl::OnRedo(wxCommandEvent& event)
925 {
926 Redo();
927 }
928
929 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
930 {
931 event.Enable( CanCut() );
932 }
933
934 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
935 {
936 event.Enable( CanCopy() );
937 }
938
939 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
940 {
941 event.Enable( CanPaste() );
942 }
943
944 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
945 {
946 event.Enable( CanUndo() );
947 }
948
949 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
950 {
951 event.Enable( CanRedo() );
952 }
953