1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/wince/textctrlce.cpp
3 // Purpose: wxTextCtrl implementation for Smartphones
4 // Author: Wlodzimierz ABX Skiba
8 // Copyright: (c) Wlodzimierz Skiba
9 // License: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
13 // ============================================================================
15 // ============================================================================
17 // ----------------------------------------------------------------------------
19 // ----------------------------------------------------------------------------
21 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
22 #pragma implementation "textctrlce.h"
25 // For compilers that support precompilation, includes "wx.h".
26 #include "wx/wxprec.h"
33 #include "wx/textctrl.h"
36 #include "wx/spinbutt.h"
37 #include "wx/textfile.h"
40 #include "wx/msw/missing.h"
41 #include "wx/msw/winundef.h"
43 #if wxUSE_TEXTCTRL && defined(__SMARTPHONE__)
45 #define GetBuddyHwnd() (HWND)(m_hwndBuddy)
47 #define IsVertical(wxStyle) (true)
49 // ----------------------------------------------------------------------------
50 // event tables and other macros
51 // ----------------------------------------------------------------------------
53 #if wxUSE_EXTENDED_RTTI
56 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl
, wxControl
)
59 BEGIN_EVENT_TABLE(wxTextCtrl
, wxControl
)
60 EVT_CHAR(wxTextCtrl::OnChar
)
62 EVT_MENU(wxID_CUT
, wxTextCtrl::OnCut
)
63 EVT_MENU(wxID_COPY
, wxTextCtrl::OnCopy
)
64 EVT_MENU(wxID_PASTE
, wxTextCtrl::OnPaste
)
65 EVT_MENU(wxID_UNDO
, wxTextCtrl::OnUndo
)
66 EVT_MENU(wxID_REDO
, wxTextCtrl::OnRedo
)
67 EVT_MENU(wxID_CLEAR
, wxTextCtrl::OnDelete
)
68 EVT_MENU(wxID_SELECTALL
, wxTextCtrl::OnSelectAll
)
70 EVT_UPDATE_UI(wxID_CUT
, wxTextCtrl::OnUpdateCut
)
71 EVT_UPDATE_UI(wxID_COPY
, wxTextCtrl::OnUpdateCopy
)
72 EVT_UPDATE_UI(wxID_PASTE
, wxTextCtrl::OnUpdatePaste
)
73 EVT_UPDATE_UI(wxID_UNDO
, wxTextCtrl::OnUpdateUndo
)
74 EVT_UPDATE_UI(wxID_REDO
, wxTextCtrl::OnUpdateRedo
)
75 EVT_UPDATE_UI(wxID_CLEAR
, wxTextCtrl::OnUpdateDelete
)
76 EVT_UPDATE_UI(wxID_SELECTALL
, wxTextCtrl::OnUpdateSelectAll
)
78 EVT_SET_FOCUS(wxTextCtrl::OnSetFocus
)
81 // ----------------------------------------------------------------------------
83 // ----------------------------------------------------------------------------
85 // the margin between the up-down control and its buddy (can be arbitrary,
86 // choose what you like - or may be decide during run-time depending on the
88 static const int MARGIN_BETWEEN
= 0;
90 // ============================================================================
92 // ============================================================================
94 wxArrayTextSpins
wxTextCtrl::ms_allTextSpins
;
96 // ----------------------------------------------------------------------------
97 // wnd proc for the buddy text ctrl
98 // ----------------------------------------------------------------------------
100 LRESULT APIENTRY _EXPORT
wxBuddyTextCtrlWndProc(HWND hwnd
,
105 wxTextCtrl
*spin
= (wxTextCtrl
*)wxGetWindowUserData(hwnd
);
107 // forward some messages (the key and focus ones only so far) to
112 // if the focus comes from the spin control itself, don't set it
113 // back to it -- we don't want to go into an infinite loop
114 if ( (WXHWND
)wParam
== spin
->GetHWND() )
123 spin
->MSWWindowProc(message
, wParam
, lParam
);
125 // The control may have been deleted at this point, so check.
126 if ( !::IsWindow(hwnd
) || wxGetWindowUserData(hwnd
) != spin
)
131 // we want to get WXK_RETURN in order to generate the event for it
132 return DLGC_WANTCHARS
;
135 return ::CallWindowProc(CASTWNDPROC spin
->GetBuddyWndProc(),
136 hwnd
, message
, wParam
, lParam
);
139 // ----------------------------------------------------------------------------
141 // ----------------------------------------------------------------------------
143 void wxTextCtrl::Init()
145 m_suppressNextUpdate
= false;
146 m_isNativeCaretShown
= true;
149 wxTextCtrl::~wxTextCtrl()
153 bool wxTextCtrl::Create(wxWindow
*parent
, wxWindowID id
,
154 const wxString
& value
,
158 const wxValidator
& validator
,
159 const wxString
& name
)
161 if ( (style
& wxBORDER_MASK
) == wxBORDER_DEFAULT
)
162 style
|= wxBORDER_SIMPLE
;
164 SetWindowStyle(style
);
167 WXDWORD msStyle
= MSWGetStyle(GetWindowStyle(), & exStyle
) ;
169 wxSize
sizeText(size
), sizeBtn(size
);
170 sizeBtn
.x
= GetBestSpinerSize(IsVertical(style
)).x
/ 2;
172 if ( sizeText
.x
== wxDefaultCoord
)
174 // DEFAULT_ITEM_WIDTH is the default width for the text control
175 sizeText
.x
= DEFAULT_ITEM_WIDTH
+ MARGIN_BETWEEN
+ sizeBtn
.x
;
178 sizeText
.x
-= sizeBtn
.x
+ MARGIN_BETWEEN
;
179 if ( sizeText
.x
<= 0 )
181 wxLogDebug(_T("not enough space for wxSpinCtrl!"));
185 posBtn
.x
+= sizeText
.x
+ MARGIN_BETWEEN
;
187 // we need to turn '\n's into "\r\n"s for the multiline controls
189 if ( m_windowStyle
& wxTE_MULTILINE
)
191 valueWin
= wxTextFile::Translate(value
, wxTextFileType_Dos
);
198 // we must create the list control before the spin button for the purpose
199 // of the dialog navigation: if there is a static text just before the spin
200 // control, activating it by Alt-letter should give focus to the text
201 // control, not the spin and the dialog navigation code will give focus to
202 // the next control (at Windows level), not the one after it
204 // create the text window
206 m_hwndBuddy
= (WXHWND
)::CreateWindowEx
208 exStyle
, // sunken border
209 _T("EDIT"), // window class
210 valueWin
, // no window title
211 msStyle
, // style (will be shown later)
212 pos
.x
, pos
.y
, // position
213 0, 0, // size (will be set later)
214 GetHwndOf(parent
), // parent
215 (HMENU
)-1, // control id
216 wxGetInstance(), // app instance
217 NULL
// unused client data
222 wxLogLastError(wxT("CreateWindow(buddy text window)"));
227 // initialize wxControl
228 if ( !CreateControl(parent
, id
, posBtn
, sizeBtn
, style
, validator
, name
) )
231 // now create the real HWND
232 WXDWORD spiner_style
= WS_VISIBLE
|
237 if ( !IsVertical(style
) )
238 spiner_style
|= UDS_HORZ
;
240 if ( style
& wxSP_WRAP
)
241 spiner_style
|= UDS_WRAP
;
243 if ( !MSWCreateControl(UPDOWN_CLASS
, spiner_style
, posBtn
, sizeBtn
, _T(""), 0) )
246 // subclass the text ctrl to be able to intercept some events
247 wxSetWindowUserData(GetBuddyHwnd(), this);
248 m_wndProcBuddy
= (WXFARPROC
)wxSetWindowProc(GetBuddyHwnd(),
249 wxBuddyTextCtrlWndProc
);
251 // set up fonts and colours (This is nomally done in MSWCreateControl)
254 SetFont(GetDefaultAttributes().font
);
256 // set the size of the text window - can do it only now, because we
257 // couldn't call DoGetBestSize() before as font wasn't set
258 if ( sizeText
.y
<= 0 )
261 wxGetCharSize(GetHWND(), &cx
, &cy
, GetFont());
263 sizeText
.y
= EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy
);
268 (void)::ShowWindow(GetBuddyHwnd(), SW_SHOW
);
270 // associate the list window with the spin button
271 (void)::SendMessage(GetHwnd(), UDM_SETBUDDY
, (WPARAM
)GetBuddyHwnd(), 0);
273 // do it after finishing with m_hwndBuddy creation to avoid generating
274 // initial wxEVT_COMMAND_TEXT_UPDATED message
275 ms_allTextSpins
.Add(this);
280 // Make sure the window style (etc.) reflects the HWND style (roughly)
281 void wxTextCtrl::AdoptAttributesFromHWND()
283 wxWindow::AdoptAttributesFromHWND();
285 long style
= ::GetWindowLong(GetBuddyHwnd(), GWL_STYLE
);
287 if (style
& ES_MULTILINE
)
288 m_windowStyle
|= wxTE_MULTILINE
;
289 if (style
& ES_PASSWORD
)
290 m_windowStyle
|= wxTE_PASSWORD
;
291 if (style
& ES_READONLY
)
292 m_windowStyle
|= wxTE_READONLY
;
293 if (style
& ES_WANTRETURN
)
294 m_windowStyle
|= wxTE_PROCESS_ENTER
;
295 if (style
& ES_CENTER
)
296 m_windowStyle
|= wxTE_CENTRE
;
297 if (style
& ES_RIGHT
)
298 m_windowStyle
|= wxTE_RIGHT
;
301 WXDWORD
wxTextCtrl::MSWGetStyle(long style
, WXDWORD
*exstyle
) const
303 // we never have an external border
304 WXDWORD msStyle
= wxControl::MSWGetStyle
306 (style
& ~wxBORDER_MASK
) | wxBORDER_NONE
, exstyle
309 msStyle
|= WS_VISIBLE
;
311 // styles which we alaways add by default
312 if ( style
& wxTE_MULTILINE
)
314 wxASSERT_MSG( !(style
& wxTE_PROCESS_ENTER
),
315 wxT("wxTE_PROCESS_ENTER style is ignored for multiline text controls (they always process it)") );
317 msStyle
|= ES_MULTILINE
| ES_WANTRETURN
;
318 if ( !(style
& wxTE_NO_VSCROLL
) )
320 // always adjust the vertical scrollbar automatically if we have it
321 msStyle
|= WS_VSCROLL
| ES_AUTOVSCROLL
;
324 style
|= wxTE_PROCESS_ENTER
;
328 // there is really no reason to not have this style for single line
330 msStyle
|= ES_AUTOHSCROLL
;
333 // note that wxTE_DONTWRAP is the same as wxHSCROLL so if we have a horz
334 // scrollbar, there is no wrapping -- which makes sense
335 if ( style
& wxTE_DONTWRAP
)
337 // automatically scroll the control horizontally as necessary
339 // NB: ES_AUTOHSCROLL is needed for richedit controls or they don't
340 // show horz scrollbar at all, even in spite of WS_HSCROLL, and as
341 // it doesn't seem to do any harm for plain edit controls, add it
343 msStyle
|= WS_HSCROLL
| ES_AUTOHSCROLL
;
346 if ( style
& wxTE_READONLY
)
347 msStyle
|= ES_READONLY
;
349 if ( style
& wxTE_PASSWORD
)
350 msStyle
|= ES_PASSWORD
;
352 if ( style
& wxTE_NOHIDESEL
)
353 msStyle
|= ES_NOHIDESEL
;
355 // note that we can't do do "& wxTE_LEFT" as wxTE_LEFT == 0
356 if ( style
& wxTE_CENTRE
)
357 msStyle
|= ES_CENTER
;
358 else if ( style
& wxTE_RIGHT
)
361 msStyle
|= ES_LEFT
; // ES_LEFT is 0 as well but for consistency...
366 // ----------------------------------------------------------------------------
367 // set/get the controls text
368 // ----------------------------------------------------------------------------
370 wxString
wxTextCtrl::GetValue() const
372 // range 0..-1 is special for GetRange() and means to retrieve all text
373 return GetRange(0, -1);
376 wxString
wxTextCtrl::GetRange(long from
, long to
) const
380 if ( from
>= to
&& to
!= -1 )
382 // nothing to retrieve
387 str
= wxGetWindowText(GetBuddyHwnd());
389 // need only a range?
392 str
= str
.Mid(from
, to
- from
);
395 // WM_GETTEXT uses standard DOS CR+LF (\r\n) convention - convert to the
396 // canonical one (same one as above) for consistency with the other kinds
397 // of controls and, more importantly, with the other ports
398 str
= wxTextFile::Translate(str
, wxTextFileType_Unix
);
403 void wxTextCtrl::SetValue(const wxString
& value
)
405 // if the text is long enough, it's faster to just set it instead of first
406 // comparing it with the old one (chances are that it will be different
407 // anyhow, this comparison is there to avoid flicker for small single-line
408 // edit controls mostly)
409 if ( (value
.length() > 0x400) || (value
!= GetValue()) )
411 DoWriteText(value
, false);
413 // for compatibility, don't move the cursor when doing SetValue()
414 SetInsertionPoint(0);
418 // still send an event for consistency
422 // we should reset the modified flag even if the value didn't really change
424 // mark the control as being not dirty - we changed its text, not the
429 void wxTextCtrl::WriteText(const wxString
& value
)
434 void wxTextCtrl::DoWriteText(const wxString
& value
, bool selectionOnly
)
437 if ( m_windowStyle
& wxTE_MULTILINE
)
438 valueDos
= wxTextFile::Translate(value
, wxTextFileType_Dos
);
442 // in some cases we get 2 EN_CHANGE notifications after the SendMessage
443 // call below which is confusing for the client code and so should be
446 if ( ( selectionOnly
&& HasSelection() ) )
448 m_suppressNextUpdate
= true;
451 ::SendMessage(GetBuddyHwnd(), selectionOnly
? EM_REPLACESEL
: WM_SETTEXT
,
452 0, (LPARAM
)valueDos
.c_str());
454 if ( !selectionOnly
)
456 // Windows already sends an update event for single-line
458 if ( m_windowStyle
& wxTE_MULTILINE
)
465 void wxTextCtrl::AppendText(const wxString
& text
)
467 SetInsertionPointEnd();
472 void wxTextCtrl::Clear()
474 ::SetWindowText(GetBuddyHwnd(), wxEmptyString
);
476 // Windows already sends an update event for single-line
478 if ( m_windowStyle
& wxTE_MULTILINE
)
482 // ----------------------------------------------------------------------------
483 // Clipboard operations
484 // ----------------------------------------------------------------------------
486 void wxTextCtrl::Copy()
490 ::SendMessage(GetBuddyHwnd(), WM_COPY
, 0, 0L);
494 void wxTextCtrl::Cut()
498 ::SendMessage(GetBuddyHwnd(), WM_CUT
, 0, 0L);
502 void wxTextCtrl::Paste()
506 ::SendMessage(GetBuddyHwnd(), WM_PASTE
, 0, 0L);
510 bool wxTextCtrl::HasSelection() const
513 GetSelection(&from
, &to
);
517 bool wxTextCtrl::CanCopy() const
519 // Can copy if there's a selection
520 return HasSelection();
523 bool wxTextCtrl::CanCut() const
525 return CanCopy() && IsEditable();
528 bool wxTextCtrl::CanPaste() const
533 // Standard edit control: check for straight text on clipboard
534 if ( !::OpenClipboard(GetHwndOf(wxTheApp
->GetTopWindow())) )
537 bool isTextAvailable
= ::IsClipboardFormatAvailable(CF_TEXT
) != 0;
540 return isTextAvailable
;
543 // ----------------------------------------------------------------------------
545 // ----------------------------------------------------------------------------
547 void wxTextCtrl::SetEditable(bool editable
)
549 SendMessage(GetBuddyHwnd(), EM_SETREADONLY
, (WPARAM
)!editable
, (LPARAM
)0L);
552 void wxTextCtrl::SetInsertionPoint(long pos
)
554 DoSetSelection(pos
, pos
);
557 void wxTextCtrl::SetInsertionPointEnd()
559 if ( GetInsertionPoint() != GetLastPosition() )
560 SetInsertionPoint(GetLastPosition());
563 long wxTextCtrl::GetInsertionPoint() const
565 DWORD Pos
= (DWORD
)::SendMessage(GetBuddyHwnd(), EM_GETSEL
, 0, 0L);
569 long wxTextCtrl::GetLastPosition() const
571 int numLines
= GetNumberOfLines();
572 long posStartLastLine
= XYToPosition(0, numLines
- 1);
574 long lenLastLine
= GetLengthOfLineContainingPos(posStartLastLine
);
576 return posStartLastLine
+ lenLastLine
;
579 void wxTextCtrl::GetSelection(long* from
, long* to
) const
581 DWORD dwStart
, dwEnd
;
582 ::SendMessage(GetBuddyHwnd(), EM_GETSEL
, (WPARAM
)&dwStart
, (LPARAM
)&dwEnd
);
588 bool wxTextCtrl::IsEditable() const
590 if ( !GetBuddyHwnd() )
593 long style
= ::GetWindowLong(GetBuddyHwnd(), GWL_STYLE
);
595 return (style
& ES_READONLY
) == 0;
598 // ----------------------------------------------------------------------------
600 // ----------------------------------------------------------------------------
602 void wxTextCtrl::SetSelection(long from
, long to
)
604 // if from and to are both -1, it means (in wxWidgets) that all text should
605 // be selected - translate into Windows convention
606 if ( (from
== -1) && (to
== -1) )
612 DoSetSelection(from
, to
);
615 void wxTextCtrl::DoSetSelection(long from
, long to
, bool scrollCaret
)
617 ::SendMessage(GetBuddyHwnd(), EM_SETSEL
, (WPARAM
)from
, (LPARAM
)to
);
621 ::SendMessage(GetBuddyHwnd(), EM_SCROLLCARET
, (WPARAM
)0, (LPARAM
)0);
625 // ----------------------------------------------------------------------------
626 // Working with files
627 // ----------------------------------------------------------------------------
629 bool wxTextCtrl::LoadFile(const wxString
& file
)
631 if ( wxTextCtrlBase::LoadFile(file
) )
633 // update the size limit if needed
642 // ----------------------------------------------------------------------------
644 // ----------------------------------------------------------------------------
646 void wxTextCtrl::Replace(long from
, long to
, const wxString
& value
)
648 // Set selection and remove it
649 DoSetSelection(from
, to
, false);
651 DoWriteText(value
, true);
654 void wxTextCtrl::Remove(long from
, long to
)
656 Replace(from
, to
, wxEmptyString
);
659 bool wxTextCtrl::IsModified() const
661 return ::SendMessage(GetBuddyHwnd(), EM_GETMODIFY
, 0, 0) != 0;
664 void wxTextCtrl::MarkDirty()
666 ::SendMessage(GetBuddyHwnd(), EM_SETMODIFY
, TRUE
, 0L);
669 void wxTextCtrl::DiscardEdits()
671 ::SendMessage(GetBuddyHwnd(), EM_SETMODIFY
, FALSE
, 0L);
674 int wxTextCtrl::GetNumberOfLines() const
676 return (int)::SendMessage(GetBuddyHwnd(), EM_GETLINECOUNT
, 0, 0L);
679 // ----------------------------------------------------------------------------
680 // Positions <-> coords
681 // ----------------------------------------------------------------------------
683 long wxTextCtrl::XYToPosition(long x
, long y
) const
685 // This gets the char index for the _beginning_ of this line
686 long charIndex
= ::SendMessage(GetBuddyHwnd(), EM_LINEINDEX
, (WPARAM
)y
, (LPARAM
)0);
688 return charIndex
+ x
;
691 bool wxTextCtrl::PositionToXY(long pos
, long *x
, long *y
) const
693 // This gets the line number containing the character
694 long lineNo
= ::SendMessage(GetBuddyHwnd(), EM_LINEFROMCHAR
, (WPARAM
)pos
, 0);
702 // This gets the char index for the _beginning_ of this line
703 long charIndex
= ::SendMessage(GetBuddyHwnd(), EM_LINEINDEX
, (WPARAM
)lineNo
, (LPARAM
)0);
704 if ( charIndex
== -1 )
709 // The X position must therefore be the different between pos and charIndex
711 *x
= pos
- charIndex
;
718 wxTextCtrlHitTestResult
719 wxTextCtrl::HitTest(const wxPoint
& pt
, long *posOut
) const
721 // first get the position from Windows
722 // for the plain ones, we are limited to 16 bit positions which are
723 // combined in a single 32 bit value
724 LPARAM lParam
= MAKELPARAM(pt
.x
, pt
.y
);
726 LRESULT pos
= ::SendMessage(GetBuddyHwnd(), EM_CHARFROMPOS
, 0, lParam
);
730 // this seems to indicate an error...
731 return wxTE_HT_UNKNOWN
;
734 // for plain EDIT controls the higher word contains something else
738 // next determine where it is relatively to our point: EM_CHARFROMPOS
739 // always returns the closest character but we need to be more precise, so
740 // double check that we really are where it pretends
743 LRESULT lRc
= SendMessage(GetBuddyHwnd(), EM_POSFROMCHAR
, pos
, 0);
747 // this is apparently returned when pos corresponds to the last
754 ptReal
.x
= LOWORD(lRc
);
755 ptReal
.y
= HIWORD(lRc
);
758 wxTextCtrlHitTestResult rc
;
760 if ( pt
.y
> ptReal
.y
+ GetCharHeight() )
762 else if ( pt
.x
> ptReal
.x
+ GetCharWidth() )
765 rc
= wxTE_HT_ON_TEXT
;
773 void wxTextCtrl::ShowPosition(long pos
)
775 int currentLineLineNo
= (int)::SendMessage(GetBuddyHwnd(), EM_GETFIRSTVISIBLELINE
, 0, 0L);
777 int specifiedLineLineNo
= (int)::SendMessage(GetBuddyHwnd(), EM_LINEFROMCHAR
, (WPARAM
)pos
, 0L);
779 int linesToScroll
= specifiedLineLineNo
- currentLineLineNo
;
781 if (linesToScroll
!= 0)
782 (void)::SendMessage(GetBuddyHwnd(), EM_LINESCROLL
, 0, (LPARAM
)linesToScroll
);
785 long wxTextCtrl::GetLengthOfLineContainingPos(long pos
) const
787 return ::SendMessage(GetBuddyHwnd(), EM_LINELENGTH
, (WPARAM
)pos
, 0L);
790 int wxTextCtrl::GetLineLength(long lineNo
) const
792 long pos
= XYToPosition(0, lineNo
);
794 return GetLengthOfLineContainingPos(pos
);
797 wxString
wxTextCtrl::GetLineText(long lineNo
) const
799 size_t len
= (size_t)GetLineLength(lineNo
) + 1;
801 // there must be at least enough place for the length WORD in the
807 wxStringBufferLength
tmp(str
, len
);
810 *(WORD
*)buf
= (WORD
)len
;
811 len
= (size_t)::SendMessage(GetBuddyHwnd(), EM_GETLINE
, lineNo
, (LPARAM
)buf
);
813 // remove the '\n' at the end, if any (this is how this function is
814 // supposed to work according to the docs)
815 if ( buf
[len
- 1] == _T('\n') )
827 void wxTextCtrl::SetMaxLength(unsigned long len
)
829 ::SendMessage(GetBuddyHwnd(), EM_LIMITTEXT
, len
, 0);
832 // ----------------------------------------------------------------------------
834 // ----------------------------------------------------------------------------
836 void wxTextCtrl::Undo()
840 ::SendMessage(GetBuddyHwnd(), EM_UNDO
, 0, 0);
844 void wxTextCtrl::Redo()
848 ::SendMessage(GetBuddyHwnd(), EM_UNDO
, 0, 0);
852 bool wxTextCtrl::CanUndo() const
854 return ::SendMessage(GetBuddyHwnd(), EM_CANUNDO
, 0, 0) != 0;
857 bool wxTextCtrl::CanRedo() const
859 return ::SendMessage(GetBuddyHwnd(), EM_CANUNDO
, 0, 0) != 0;
862 // ----------------------------------------------------------------------------
864 // ----------------------------------------------------------------------------
866 // ----------------------------------------------------------------------------
867 // implemenation details
868 // ----------------------------------------------------------------------------
870 void wxTextCtrl::Command(wxCommandEvent
& event
)
872 SetValue(event
.GetString());
873 ProcessCommand (event
);
876 // ----------------------------------------------------------------------------
877 // kbd input processing
878 // ----------------------------------------------------------------------------
880 void wxTextCtrl::OnChar(wxKeyEvent
& event
)
882 switch ( event
.GetKeyCode() )
885 if ( !HasFlag(wxTE_MULTILINE
) )
887 wxCommandEvent
event(wxEVT_COMMAND_TEXT_ENTER
, m_windowId
);
888 InitCommandEvent(event
);
889 event
.SetString(GetValue());
890 if ( GetEventHandler()->ProcessEvent(event
) )
893 //else: multiline controls need Enter for themselves
898 // ok, so this is getting absolutely ridiculous but I don't see
899 // any other way to fix this bug: when a multiline text control is
900 // inside a wxFrame, we need to generate the navigation event as
901 // otherwise nothing happens at all, but when the same control is
902 // created inside a dialog, IsDialogMessage() *does* switch focus
903 // all by itself and so if we do it here as well, it is advanced
904 // twice and goes to the next control... to prevent this from
905 // happening we're doing this ugly check, the logic being that if
906 // we don't have focus then it had been already changed to the next
909 // the right thing to do would, of course, be to understand what
910 // the hell is IsDialogMessage() doing but this is beyond my feeble
911 // forces at the moment unfortunately
912 if ( !(m_windowStyle
& wxTE_PROCESS_TAB
))
914 if ( FindFocus() == this )
917 if (!event
.ShiftDown())
918 flags
|= wxNavigationKeyEvent::IsForward
;
919 if (event
.ControlDown())
920 flags
|= wxNavigationKeyEvent::WinChange
;
927 // Insert tab since calling the default Windows handler
928 // doesn't seem to do it
929 WriteText(wxT("\t"));
934 // no, we didn't process it
938 WXLRESULT
wxTextCtrl::MSWWindowProc(WXUINT nMsg
, WXWPARAM wParam
, WXLPARAM lParam
)
940 WXLRESULT lRc
= wxTextCtrlBase::MSWWindowProc(nMsg
, wParam
, lParam
);
942 if ( nMsg
== WM_GETDLGCODE
)
944 // we always want the chars and the arrows: the arrows for navigation
945 // and the chars because we want Ctrl-C to work even in a read only
947 long lDlgCode
= DLGC_WANTCHARS
| DLGC_WANTARROWS
;
951 // we may have several different cases:
952 // 1. normal case: both TAB and ENTER are used for dlg navigation
953 // 2. ctrl which wants TAB for itself: ENTER is used to pass to the
954 // next control in the dialog
955 // 3. ctrl which wants ENTER for itself: TAB is used for dialog
957 // 4. ctrl which wants both TAB and ENTER: Ctrl-ENTER is used to go
958 // to the next control
960 // the multiline edit control should always get <Return> for itself
961 if ( HasFlag(wxTE_PROCESS_ENTER
) || HasFlag(wxTE_MULTILINE
) )
962 lDlgCode
|= DLGC_WANTMESSAGE
;
964 if ( HasFlag(wxTE_PROCESS_TAB
) )
965 lDlgCode
|= DLGC_WANTTAB
;
971 // NB: use "=", not "|=" as the base class version returns the
972 // same flags is this state as usual (i.e. including
973 // DLGC_WANTMESSAGE). This is strange (how does it work in the
974 // native Win32 apps?) but for now live with it.
982 // ----------------------------------------------------------------------------
983 // text control event processing
984 // ----------------------------------------------------------------------------
986 bool wxTextCtrl::SendUpdateEvent()
988 // is event reporting suspended?
989 if ( m_suppressNextUpdate
)
991 // do process the next one
992 m_suppressNextUpdate
= false;
997 wxCommandEvent
event(wxEVT_COMMAND_TEXT_UPDATED
, GetId());
998 InitCommandEvent(event
);
999 event
.SetString(GetValue());
1001 return ProcessCommand(event
);
1004 bool wxTextCtrl::MSWCommand(WXUINT param
, WXWORD
WXUNUSED(id
))
1011 wxFocusEvent
event(param
== EN_KILLFOCUS
? wxEVT_KILL_FOCUS
1014 event
.SetEventObject(this);
1015 GetEventHandler()->ProcessEvent(event
);
1024 // the text size limit has been hit -- try to increase it
1025 if ( !AdjustSpaceLimit() )
1027 wxCommandEvent
event(wxEVT_COMMAND_TEXT_MAXLEN
, m_windowId
);
1028 InitCommandEvent(event
);
1029 event
.SetString(GetValue());
1030 ProcessCommand(event
);
1034 // the other edit notification messages are not processed
1043 WXHBRUSH
wxTextCtrl::OnCtlColor(WXHDC pDC
, WXHWND
WXUNUSED(pWnd
), WXUINT
WXUNUSED(nCtlColor
),
1049 WXUINT
WXUNUSED(message
),
1050 WXWPARAM
WXUNUSED(wParam
),
1051 WXLPARAM
WXUNUSED(lParam
)
1058 HBRUSH hbrush
= Ctl3dCtlColorEx(message
, wParam
, lParam
);
1059 return (WXHBRUSH
) hbrush
;
1061 #endif // wxUSE_CTL3D
1064 wxColour colBack
= GetBackgroundColour();
1066 if (!IsEnabled() && (GetWindowStyle() & wxTE_MULTILINE
) == 0)
1067 colBack
= wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE
);
1069 ::SetBkColor(hdc
, wxColourToRGB(colBack
));
1070 ::SetTextColor(hdc
, wxColourToRGB(GetForegroundColour()));
1072 wxBrush
*brush
= wxTheBrushList
->FindOrCreateBrush(colBack
, wxSOLID
);
1074 return (WXHBRUSH
)brush
->GetResourceHandle();
1077 bool wxTextCtrl::AdjustSpaceLimit()
1079 unsigned int limit
= ::SendMessage(GetBuddyHwnd(), EM_GETLIMITTEXT
, 0, 0);
1081 // HACK: we try to automatically extend the limit for the amount of text
1082 // to allow (interactively) entering more than 64Kb of text under
1083 // Win9x but we shouldn't reset the text limit which was previously
1084 // set explicitly with SetMaxLength()
1086 // we could solve this by storing the limit we set in wxTextCtrl but
1087 // to save space we prefer to simply test here the actual limit
1088 // value: we consider that SetMaxLength() can only be called for
1090 if ( limit
< 0x8000 )
1092 // we've got more text than limit set by SetMaxLength()
1096 unsigned int len
= ::GetWindowTextLength(GetBuddyHwnd());
1099 limit
= len
+ 0x8000; // 32Kb
1101 if ( limit
> 0xffff )
1103 // this will set it to a platform-dependent maximum (much more
1104 // than 64Kb under NT)
1108 ::SendMessage(GetBuddyHwnd(), EM_LIMITTEXT
, limit
, 0L);
1111 // we changed the limit
1115 bool wxTextCtrl::AcceptsFocus() const
1117 // we don't want focus if we can't be edited unless we're a multiline
1118 // control because then it might be still nice to get focus from keyboard
1119 // to be able to scroll it without mouse
1120 return (IsEditable() || IsMultiLine()) && wxControl::AcceptsFocus();
1123 void wxTextCtrl::DoMoveWindow(int x
, int y
, int width
, int height
)
1125 int widthBtn
= GetBestSpinerSize(IsVertical(GetWindowStyle())).x
/ 2;
1126 int widthText
= width
- widthBtn
- MARGIN_BETWEEN
;
1127 if ( widthText
<= 0 )
1129 wxLogDebug(_T("not enough space for wxSpinCtrl!"));
1132 if ( !::MoveWindow(GetBuddyHwnd(), x
, y
, widthText
, height
, TRUE
) )
1134 wxLogLastError(wxT("MoveWindow(buddy)"));
1137 x
+= widthText
+ MARGIN_BETWEEN
;
1138 if ( !::MoveWindow(GetHwnd(), x
, y
, widthBtn
, height
, TRUE
) )
1140 wxLogLastError(wxT("MoveWindow"));
1144 wxSize
wxTextCtrl::DoGetBestSize() const
1147 wxGetCharSize(GetBuddyHwnd(), &cx
, &cy
, GetFont());
1149 int wText
= DEFAULT_ITEM_WIDTH
;
1152 if ( m_windowStyle
& wxTE_MULTILINE
)
1154 hText
*= wxMax(GetNumberOfLines(), 5);
1156 //else: for single line control everything is ok
1158 // we have to add the adjustments for the control height only once, not
1159 // once per line, so do it after multiplication above
1160 hText
+= EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy
) - cy
;
1162 return wxSize(wText
, hText
);
1165 // ----------------------------------------------------------------------------
1166 // standard handlers for standard edit menu events
1167 // ----------------------------------------------------------------------------
1169 void wxTextCtrl::OnCut(wxCommandEvent
& WXUNUSED(event
))
1174 void wxTextCtrl::OnCopy(wxCommandEvent
& WXUNUSED(event
))
1179 void wxTextCtrl::OnPaste(wxCommandEvent
& WXUNUSED(event
))
1184 void wxTextCtrl::OnUndo(wxCommandEvent
& WXUNUSED(event
))
1189 void wxTextCtrl::OnRedo(wxCommandEvent
& WXUNUSED(event
))
1194 void wxTextCtrl::OnDelete(wxCommandEvent
& WXUNUSED(event
))
1197 GetSelection(& from
, & to
);
1198 if (from
!= -1 && to
!= -1)
1202 void wxTextCtrl::OnSelectAll(wxCommandEvent
& WXUNUSED(event
))
1204 SetSelection(-1, -1);
1207 void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent
& event
)
1209 event
.Enable( CanCut() );
1212 void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent
& event
)
1214 event
.Enable( CanCopy() );
1217 void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent
& event
)
1219 event
.Enable( CanPaste() );
1222 void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent
& event
)
1224 event
.Enable( CanUndo() );
1227 void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent
& event
)
1229 event
.Enable( CanRedo() );
1232 void wxTextCtrl::OnUpdateDelete(wxUpdateUIEvent
& event
)
1235 GetSelection(& from
, & to
);
1236 event
.Enable(from
!= -1 && to
!= -1 && from
!= to
&& IsEditable()) ;
1239 void wxTextCtrl::OnUpdateSelectAll(wxUpdateUIEvent
& event
)
1241 event
.Enable(GetLastPosition() > 0);
1244 void wxTextCtrl::OnSetFocus(wxFocusEvent
& WXUNUSED(event
))
1246 // be sure the caret remains invisible if the user had hidden it
1247 if ( !m_isNativeCaretShown
)
1249 ::HideCaret(GetBuddyHwnd());
1253 #endif // wxUSE_TEXTCTRL && __SMARTPHONE__