]> git.saurik.com Git - wxWidgets.git/blame - src/msw/textctrl.cpp
Minor fixes mainly to get stuff compiled using the mingw32 (cross) compiler
[wxWidgets.git] / src / msw / textctrl.cpp
CommitLineData
2bda0e17
KB
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
c085e333 9// Licence: wxWindows license
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
a1b82138
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
2bda0e17 16#ifdef __GNUG__
a1b82138 17 #pragma implementation "textctrl.h"
2bda0e17
KB
18#endif
19
a1b82138
VZ
20// ----------------------------------------------------------------------------
21// headers
22// ----------------------------------------------------------------------------
23
2bda0e17
KB
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
a1b82138 28 #pragma hdrstop
2bda0e17
KB
29#endif
30
31#ifndef WX_PRECOMP
a1b82138
VZ
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"
2bda0e17
KB
37#endif
38
47d67540 39#if wxUSE_CLIPBOARD
a1b82138
VZ
40 #include "wx/app.h"
41 #include "wx/clipbrd.h"
2bda0e17
KB
42#endif
43
a1b82138
VZ
44#include "wx/textfile.h"
45
46#include <windowsx.h>
47
2bda0e17
KB
48#include "wx/msw/private.h"
49
a1b82138 50#include <string.h>
2bda0e17 51#include <stdlib.h>
a1b82138 52#include <sys/types.h>
fbc535ff
JS
53
54#if wxUSE_IOSTREAMH
3f4a0c5b 55# include <fstream.h>
fbc535ff 56#else
3f4a0c5b 57# include <fstream>
fbc535ff 58#endif
2bda0e17 59
57c208c5 60#if wxUSE_RICHEDIT && !defined(__GNUWIN32__)
cd471848 61 #include <richedit.h>
2bda0e17
KB
62#endif
63
64#if !USE_SHARED_LIBRARY
e702ff0f 65
a1b82138
VZ
66// ----------------------------------------------------------------------------
67// event tables and other macros
68// ----------------------------------------------------------------------------
69
2bda0e17
KB
70IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
71
72BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
a1b82138
VZ
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)
2bda0e17 87END_EVENT_TABLE()
e702ff0f 88
cd471848 89#endif // USE_SHARED_LIBRARY
2bda0e17 90
a1b82138
VZ
91// ============================================================================
92// implementation
93// ============================================================================
94
95// ----------------------------------------------------------------------------
96// creation
97// ----------------------------------------------------------------------------
98
cd471848 99wxTextCtrl::wxTextCtrl()
2bda0e17 100{
cd471848 101#if wxUSE_RICHEDIT
a1b82138 102 m_isRich = FALSE;
cd471848 103#endif
2bda0e17
KB
104}
105
debe6624 106bool wxTextCtrl::Create(wxWindow *parent, wxWindowID id,
c085e333
VZ
107 const wxString& value,
108 const wxPoint& pos,
a1b82138
VZ
109 const wxSize& size,
110 long style,
c085e333
VZ
111 const wxValidator& validator,
112 const wxString& name)
2bda0e17 113{
a1b82138
VZ
114 // base initialization
115 if ( !CreateBase(parent, id, pos, size, style, name) )
116 return FALSE;
2bda0e17 117
a1b82138
VZ
118 SetValidator(validator);
119 if ( parent )
120 parent->AddChild(this);
2bda0e17 121
a1b82138
VZ
122 // set colours
123 SetupColours();
2bda0e17 124
a1b82138
VZ
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)") );
5fb9fcfc 133
a1b82138
VZ
134 msStyle |= ES_MULTILINE | ES_WANTRETURN | WS_VSCROLL;
135 m_windowStyle |= wxTE_PROCESS_ENTER;
136 }
137 else
138 msStyle |= ES_AUTOHSCROLL;
2bda0e17 139
a1b82138
VZ
140 if (m_windowStyle & wxTE_READONLY)
141 msStyle |= ES_READONLY;
2bda0e17 142
a1b82138
VZ
143 if (m_windowStyle & wxHSCROLL)
144 msStyle |= (WS_HSCROLL | ES_AUTOHSCROLL);
145 if (m_windowStyle & wxTE_PASSWORD) // hidden input
146 msStyle |= ES_PASSWORD;
2bda0e17 147
101f488c
VZ
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
a1b82138
VZ
163 // do create the control - either an EDIT or RICHEDIT
164 const wxChar *windowClass = _T("EDIT");
cd471848 165
57c208c5 166#if wxUSE_RICHEDIT
a1b82138
VZ
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;
cd471848 178#endif
2bda0e17 179
a1b82138
VZ
180 bool want3D;
181 WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D);
2bda0e17 182
a1b82138
VZ
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;
2bda0e17 187
a1b82138
VZ
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);
2bda0e17 200
a1b82138 201 wxCHECK_MSG( m_hWnd, FALSE, _T("Failed to create text ctrl") );
c085e333 202
1f112209 203#if wxUSE_CTL3D
a1b82138
VZ
204 if ( want3D )
205 {
206 Ctl3dSubclassCtl(GetHwnd());
207 m_useCtl3D = TRUE;
208 }
2bda0e17
KB
209#endif
210
57c208c5 211#if wxUSE_RICHEDIT
a1b82138
VZ
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 }
2bda0e17
KB
218#endif
219
a1b82138 220 SubclassWin(GetHWND());
2bda0e17 221
a1b82138
VZ
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 }
2bda0e17 232
a1b82138 233 // Causes a crash for Symantec C++ and WIN32 for some reason
2bda0e17 234#if !(defined(__SC__) && defined(__WIN32__))
a1b82138
VZ
235 if ( !value.IsEmpty() )
236 {
237 SetValue(value);
238 }
2bda0e17
KB
239#endif
240
a1b82138
VZ
241 SetSize(pos.x, pos.y, size.x, size.y);
242
243 return TRUE;
2bda0e17
KB
244}
245
246// Make sure the window style (etc.) reflects the HWND style (roughly)
cd471848 247void wxTextCtrl::AdoptAttributesFromHWND()
2bda0e17 248{
c085e333 249 wxWindow::AdoptAttributesFromHWND();
2bda0e17 250
789295bf 251 HWND hWnd = GetHwnd();
a1b82138 252 long style = GetWindowLong(hWnd, GWL_STYLE);
2bda0e17 253
cd471848
VZ
254 // retrieve the style to see whether this is an edit or richedit ctrl
255#if wxUSE_RICHEDIT
837e5743 256 wxChar buf[256];
2bda0e17 257
a1b82138 258 GetClassName(hWnd, buf, WXSIZEOF(buf));
2bda0e17 259
a1b82138 260 if ( wxStricmp(buf, _T("EDIT")) == 0 )
c085e333
VZ
261 m_isRich = FALSE;
262 else
263 m_isRich = TRUE;
a1b82138 264#endif // wxUSE_RICHEDIT
c085e333
VZ
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;
2bda0e17
KB
274}
275
cd471848 276void wxTextCtrl::SetupColours()
2bda0e17 277{
a1b82138
VZ
278 // FIXME why is bg colour not inherited from parent?
279 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
280 SetForegroundColour(GetParent()->GetForegroundColour());
2bda0e17
KB
281}
282
a1b82138
VZ
283// ----------------------------------------------------------------------------
284// set/get the controls text
285// ----------------------------------------------------------------------------
286
cd471848 287wxString wxTextCtrl::GetValue() const
2bda0e17 288{
789295bf 289 return wxGetWindowText(GetHWND());
2bda0e17
KB
290}
291
292void wxTextCtrl::SetValue(const wxString& value)
293{
a1b82138 294 wxString valueDos = wxTextFile::Translate(value, wxTextFileType_Dos);
789295bf 295
a1b82138
VZ
296 SetWindowText(GetHwnd(), valueDos);
297
298 AdjustSpaceLimit();
2bda0e17
KB
299}
300
a1b82138 301void wxTextCtrl::WriteText(const wxString& value)
2bda0e17 302{
a1b82138 303 wxString valueDos = wxTextFile::Translate(value, wxTextFileType_Dos);
2bda0e17 304
a1b82138 305 SendMessage(GetHwnd(), EM_REPLACESEL, 0, (LPARAM)valueDos.c_str());
2bda0e17 306
a1b82138 307 AdjustSpaceLimit();
2bda0e17
KB
308}
309
a1b82138
VZ
310void wxTextCtrl::AppendText(const wxString& text)
311{
312 SetInsertionPointEnd();
313 WriteText(text);
314}
315
316void wxTextCtrl::Clear()
317{
318 SetWindowText(GetHwnd(), _T(""));
319}
320
321// ----------------------------------------------------------------------------
2bda0e17 322// Clipboard operations
a1b82138
VZ
323// ----------------------------------------------------------------------------
324
cd471848 325void wxTextCtrl::Copy()
2bda0e17 326{
e702ff0f
JS
327 if (CanCopy())
328 {
789295bf 329 HWND hWnd = GetHwnd();
e702ff0f
JS
330 SendMessage(hWnd, WM_COPY, 0, 0L);
331 }
2bda0e17
KB
332}
333
cd471848 334void wxTextCtrl::Cut()
2bda0e17 335{
e702ff0f
JS
336 if (CanCut())
337 {
789295bf 338 HWND hWnd = GetHwnd();
e702ff0f
JS
339 SendMessage(hWnd, WM_CUT, 0, 0L);
340 }
2bda0e17
KB
341}
342
cd471848 343void wxTextCtrl::Paste()
2bda0e17 344{
e702ff0f
JS
345 if (CanPaste())
346 {
789295bf 347 HWND hWnd = GetHwnd();
e702ff0f
JS
348 SendMessage(hWnd, WM_PASTE, 0, 0L);
349 }
2bda0e17
KB
350}
351
a1b82138
VZ
352bool 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
360bool 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
368bool 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
debe6624 395void wxTextCtrl::SetEditable(bool editable)
2bda0e17 396{
a1b82138
VZ
397 HWND hWnd = GetHwnd();
398 SendMessage(hWnd, EM_SETREADONLY, (WPARAM)!editable, (LPARAM)0L);
2bda0e17
KB
399}
400
debe6624 401void wxTextCtrl::SetInsertionPoint(long pos)
2bda0e17 402{
a1b82138 403 HWND hWnd = GetHwnd();
2bda0e17 404#ifdef __WIN32__
57c208c5 405#if wxUSE_RICHEDIT
a1b82138
VZ
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);
2bda0e17
KB
426}
427
cd471848 428void wxTextCtrl::SetInsertionPointEnd()
2bda0e17 429{
a1b82138
VZ
430 long pos = GetLastPosition();
431 SetInsertionPoint(pos);
2bda0e17
KB
432}
433
cd471848 434long wxTextCtrl::GetInsertionPoint() const
2bda0e17 435{
57c208c5 436#if wxUSE_RICHEDIT
a1b82138
VZ
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 }
2bda0e17
KB
445#endif
446
a1b82138
VZ
447 DWORD Pos = (DWORD)SendMessage(GetHwnd(), EM_GETSEL, 0, 0L);
448 return Pos & 0xFFFF;
2bda0e17
KB
449}
450
cd471848 451long wxTextCtrl::GetLastPosition() const
2bda0e17 452{
789295bf 453 HWND hWnd = GetHwnd();
2bda0e17
KB
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);
39136494 460
2bda0e17
KB
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
a1b82138
VZ
468// If the return values from and to are the same, there is no
469// selection.
470void 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
494bool 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
debe6624 505void wxTextCtrl::Replace(long from, long to, const wxString& value)
2bda0e17 506{
acbd13a3 507#if wxUSE_CLIPBOARD
789295bf 508 HWND hWnd = GetHwnd();
2bda0e17
KB
509 long fromChar = from;
510 long toChar = to;
39136494 511
2bda0e17
KB
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.
837e5743 521 wxSetClipboardData(wxDF_TEXT, (wxObject *) (const wxChar *)value, 0, 0);
2bda0e17
KB
522
523 // Paste into edit control
524 SendMessage(hWnd, WM_PASTE, (WPARAM)0, (LPARAM)0L);
acbd13a3
JS
525#else
526 wxFAIL_MSG("wxTextCtrl::Replace not implemented if wxUSE_CLIPBOARD is 0.");
527#endif
2bda0e17
KB
528}
529
debe6624 530void wxTextCtrl::Remove(long from, long to)
2bda0e17 531{
789295bf 532 HWND hWnd = GetHwnd();
2bda0e17
KB
533 long fromChar = from;
534 long toChar = to;
39136494 535
2bda0e17
KB
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
debe6624 545void wxTextCtrl::SetSelection(long from, long to)
2bda0e17 546{
789295bf 547 HWND hWnd = GetHwnd();
2bda0e17
KB
548 long fromChar = from;
549 long toChar = to;
a1b82138
VZ
550
551 // if from and to are both -1, it means (in wxWindows) that all text should
552 // be selected. Translate into Windows convention
2bda0e17
KB
553 if ((from == -1) && (to == -1))
554 {
555 fromChar = 0;
556 toChar = -1;
557 }
39136494 558
2bda0e17
KB
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
568bool wxTextCtrl::LoadFile(const wxString& file)
569{
a1b82138 570 if ( wxTextCtrlBase::LoadFile(file) )
cd471848 571 {
a1b82138
VZ
572 // update the size limit if needed
573 AdjustSpaceLimit();
2bda0e17 574
a1b82138 575 return TRUE;
2bda0e17 576 }
2bda0e17 577
a1b82138 578 return FALSE;
2bda0e17
KB
579}
580
cd471848 581bool wxTextCtrl::IsModified() const
2bda0e17 582{
789295bf 583 return (SendMessage(GetHwnd(), EM_GETMODIFY, 0, 0) != 0);
2bda0e17
KB
584}
585
586// Makes 'unmodified'
cd471848 587void wxTextCtrl::DiscardEdits()
2bda0e17 588{
a1b82138 589 SendMessage(GetHwnd(), EM_SETMODIFY, FALSE, 0L);
2bda0e17
KB
590}
591
cd471848 592int wxTextCtrl::GetNumberOfLines() const
2bda0e17 593{
789295bf 594 return (int)SendMessage(GetHwnd(), EM_GETLINECOUNT, (WPARAM)0, (LPARAM)0);
2bda0e17
KB
595}
596
debe6624 597long wxTextCtrl::XYToPosition(long x, long y) const
2bda0e17 598{
789295bf 599 HWND hWnd = GetHwnd();
2bda0e17
KB
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
0efe5ba7 606bool wxTextCtrl::PositionToXY(long pos, long *x, long *y) const
2bda0e17 607{
789295bf 608 HWND hWnd = GetHwnd();
2bda0e17
KB
609
610 // This gets the line number containing the character
0efe5ba7
VZ
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
2bda0e17
KB
627 // This gets the char index for the _beginning_ of this line
628 int charIndex = (int)SendMessage(hWnd, EM_LINEINDEX, (WPARAM)lineNo, (LPARAM)0);
0efe5ba7
VZ
629 if ( charIndex == -1 )
630 {
631 return FALSE;
632 }
633
2bda0e17 634 // The X position must therefore be the different between pos and charIndex
0efe5ba7
VZ
635 if ( x )
636 *x = (long)(pos - charIndex);
637 if ( y )
638 *y = (long)lineNo;
639
640 return TRUE;
2bda0e17
KB
641}
642
debe6624 643void wxTextCtrl::ShowPosition(long pos)
2bda0e17 644{
789295bf 645 HWND hWnd = GetHwnd();
2bda0e17
KB
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);
39136494 661
2bda0e17
KB
662 int linesToScroll = specifiedLineLineNo - currentLineLineNo;
663
2bda0e17 664 if (linesToScroll != 0)
de4d7713 665 (void)SendMessage(hWnd, EM_LINESCROLL, (WPARAM)0, (LPARAM)linesToScroll);
2bda0e17
KB
666}
667
debe6624 668int wxTextCtrl::GetLineLength(long lineNo) const
2bda0e17
KB
669{
670 long charIndex = XYToPosition(0, lineNo);
4438caf4 671 int len = (int)SendMessage(GetHwnd(), EM_LINELENGTH, charIndex, 0);
2bda0e17
KB
672 return len;
673}
674
debe6624 675wxString wxTextCtrl::GetLineText(long lineNo) const
2bda0e17 676{
a1b82138 677 size_t len = (size_t)GetLineLength(lineNo) + 1;
4438caf4
VZ
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;
2bda0e17
KB
688}
689
a1b82138 690// ----------------------------------------------------------------------------
ca8b28f2 691// Undo/redo
a1b82138
VZ
692// ----------------------------------------------------------------------------
693
ca8b28f2
JS
694void wxTextCtrl::Undo()
695{
696 if (CanUndo())
697 {
789295bf 698 ::SendMessage(GetHwnd(), EM_UNDO, 0, 0);
ca8b28f2
JS
699 }
700}
701
702void wxTextCtrl::Redo()
703{
704 if (CanRedo())
705 {
706 // Same as Undo, since Undo undoes the undo, i.e. a redo.
789295bf 707 ::SendMessage(GetHwnd(), EM_UNDO, 0, 0);
ca8b28f2
JS
708 }
709}
710
711bool wxTextCtrl::CanUndo() const
712{
789295bf 713 return (::SendMessage(GetHwnd(), EM_CANUNDO, 0, 0) != 0);
ca8b28f2
JS
714}
715
716bool wxTextCtrl::CanRedo() const
717{
789295bf 718 return (::SendMessage(GetHwnd(), EM_CANUNDO, 0, 0) != 0);
ca8b28f2
JS
719}
720
a1b82138
VZ
721// ----------------------------------------------------------------------------
722// implemenation details
723// ----------------------------------------------------------------------------
39136494 724
2bda0e17
KB
725void wxTextCtrl::Command(wxCommandEvent & event)
726{
a1b82138
VZ
727 SetValue(event.GetString());
728 ProcessCommand (event);
2bda0e17
KB
729}
730
731void wxTextCtrl::OnDropFiles(wxDropFilesEvent& event)
732{
a1b82138
VZ
733 // By default, load the first file into the text window.
734 if (event.GetNumberOfFiles() > 0)
735 {
736 LoadFile(event.GetFiles()[0]);
737 }
2bda0e17
KB
738}
739
debe6624 740WXHBRUSH wxTextCtrl::OnCtlColor(WXHDC pDC, WXHWND pWnd, WXUINT nCtlColor,
a1b82138
VZ
741 WXUINT message, WXWPARAM wParam,
742 WXLPARAM lParam)
2bda0e17 743{
1f112209 744#if wxUSE_CTL3D
a1b82138
VZ
745 if ( m_useCtl3D )
746 {
747 HBRUSH hbrush = Ctl3dCtlColorEx(message, wParam, lParam);
748 return (WXHBRUSH) hbrush;
749 }
2bda0e17
KB
750#endif
751
a1b82138
VZ
752 HDC hdc = (HDC)pDC;
753 SetBkMode(hdc, GetParent()->GetTransparentBackground() ? TRANSPARENT
754 : OPAQUE);
2bda0e17 755
a1b82138
VZ
756 ::SetBkColor(hdc, RGB(GetBackgroundColour().Red(), GetBackgroundColour().Green(), GetBackgroundColour().Blue()));
757 ::SetTextColor(hdc, RGB(GetForegroundColour().Red(), GetForegroundColour().Green(), GetForegroundColour().Blue()));
2bda0e17 758
a1b82138 759 wxBrush *backgroundBrush = wxTheBrushList->FindOrCreateBrush(GetBackgroundColour(), wxSOLID);
2bda0e17 760
a1b82138 761 return (WXHBRUSH) backgroundBrush->GetResourceHandle();
2bda0e17
KB
762}
763
764void wxTextCtrl::OnChar(wxKeyEvent& event)
765{
42e69d6b 766 switch ( event.KeyCode() )
cd471848 767 {
cd471848 768 case WXK_RETURN:
39136494 769 if ( !(m_windowStyle & wxTE_MULTILINE) )
cd471848
VZ
770 {
771 wxCommandEvent event(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
772 event.SetEventObject( this );
773 if ( GetEventHandler()->ProcessEvent(event) )
774 return;
775 }
5fb9fcfc
VZ
776 //else: multiline controls need Enter for themselves
777
778 break;
4d91c1d1 779
cd471848 780 case WXK_TAB:
319fefa9
VZ
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.
5fb9fcfc
VZ
785 //
786 // NB: Notice that Ctrl-Tab is handled elsewhere and Alt-Tab is
787 // handled by Windows
cd471848 788 {
5fb9fcfc
VZ
789 wxNavigationKeyEvent eventNav;
790 eventNav.SetDirection(!event.ShiftDown());
791 eventNav.SetWindowChange(FALSE);
792 eventNav.SetEventObject(this);
39136494 793
5fb9fcfc 794 if ( GetEventHandler()->ProcessEvent(eventNav) )
cd471848
VZ
795 return;
796 }
341c92a8 797 break;
4d91c1d1
VZ
798
799 default:
800 event.Skip();
39136494 801 return;
cd471848 802 }
39136494 803
cd471848
VZ
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
42e69d6b
VZ
807
808 // FIXME
809 event.Skip();
2bda0e17
KB
810}
811
debe6624 812bool wxTextCtrl::MSWCommand(WXUINT param, WXWORD WXUNUSED(id))
2bda0e17 813{
789295bf
VZ
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;
ae29de83 826
789295bf
VZ
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;
2bda0e17 837
789295bf
VZ
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;
2bda0e17
KB
854}
855
789295bf
VZ
856void wxTextCtrl::AdjustSpaceLimit()
857{
25889d3c 858#ifndef __WIN16__
789295bf
VZ
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
5ea105e0 865#if wxUSE_RICHEDIT
789295bf 866 if ( m_isRich || limit > 0xffff )
5ea105e0
RR
867#else
868 if ( limit > 0xffff )
869#endif
789295bf
VZ
870 ::SendMessage(GetHwnd(), EM_LIMITTEXT, 0, limit);
871 else
872 ::SendMessage(GetHwnd(), EM_LIMITTEXT, limit, 0);
873 }
25889d3c 874#endif
789295bf 875}
2bda0e17 876
a1b82138 877bool wxTextCtrl::AcceptsFocus() const
2bda0e17 878{
a1b82138
VZ
879 // we don't want focus if we can't be edited
880 return IsEditable() && wxControl::AcceptsFocus();
881}
c085e333 882
a1b82138
VZ
883wxSize 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);
2bda0e17 898}
a1b82138
VZ
899
900// ----------------------------------------------------------------------------
901// standard handlers for standard edit menu events
902// ----------------------------------------------------------------------------
2bda0e17 903
e702ff0f
JS
904void wxTextCtrl::OnCut(wxCommandEvent& event)
905{
906 Cut();
907}
908
909void wxTextCtrl::OnCopy(wxCommandEvent& event)
910{
911 Copy();
912}
913
914void wxTextCtrl::OnPaste(wxCommandEvent& event)
915{
916 Paste();
917}
918
919void wxTextCtrl::OnUndo(wxCommandEvent& event)
920{
921 Undo();
922}
923
924void wxTextCtrl::OnRedo(wxCommandEvent& event)
925{
926 Redo();
927}
928
929void wxTextCtrl::OnUpdateCut(wxUpdateUIEvent& event)
930{
931 event.Enable( CanCut() );
932}
933
934void wxTextCtrl::OnUpdateCopy(wxUpdateUIEvent& event)
935{
936 event.Enable( CanCopy() );
937}
938
939void wxTextCtrl::OnUpdatePaste(wxUpdateUIEvent& event)
940{
941 event.Enable( CanPaste() );
942}
943
944void wxTextCtrl::OnUpdateUndo(wxUpdateUIEvent& event)
945{
946 event.Enable( CanUndo() );
947}
948
949void wxTextCtrl::OnUpdateRedo(wxUpdateUIEvent& event)
950{
951 event.Enable( CanRedo() );
952}
953