]> git.saurik.com Git - wxWidgets.git/blame - src/os2/textctrl.cpp
rewrite to avoid unnecessary redraws
[wxWidgets.git] / src / os2 / textctrl.cpp
CommitLineData
0e320a79
DW
1/////////////////////////////////////////////////////////////////////////////
2// Name: textctrl.cpp
3// Purpose: wxTextCtrl
d90895ac 4// Author: David Webster
0e320a79 5// Modified by:
d90895ac 6// Created: 10/17/99
0e320a79 7// RCS-ID: $Id$
d90895ac
DW
8// Copyright: (c) David Webster
9// Licence: wxWindows licence
0e320a79
DW
10/////////////////////////////////////////////////////////////////////////////
11
d90895ac
DW
12// ----------------------------------------------------------------------------
13// headers
14// ----------------------------------------------------------------------------
15
16// For compilers that support precompilation, includes "wx.h".
17#include "wx/wxprec.h"
18
19#ifndef WX_PRECOMP
20 #include "wx/textctrl.h"
21 #include "wx/settings.h"
22 #include "wx/brush.h"
23 #include "wx/utils.h"
24 #include "wx/log.h"
0e320a79
DW
25#endif
26
d90895ac
DW
27#if wxUSE_CLIPBOARD
28 #include "wx/app.h"
29 #include "wx/clipbrd.h"
30#endif
0e320a79 31
d90895ac
DW
32#include "wx/textfile.h"
33
34#include "wx/os2/private.h"
35
36#include <string.h>
37#include <stdlib.h>
38#include <sys/types.h>
0e320a79 39
d90895ac
DW
40#if wxUSE_IOSTREAMH
41# include <fstream.h>
0e320a79 42#else
d90895ac 43# include <fstream>
0e320a79
DW
44#endif
45
a92d9721
SN
46#if defined(__EMX__) && !defined(MLE_INDEX)
47#define MLE_INDEX 0
48#define MLE_RGB 1
49#endif
50
d90895ac
DW
51
52// ----------------------------------------------------------------------------
53// event tables and other macros
54// ----------------------------------------------------------------------------
55
0e320a79
DW
56IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
57
58BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
d90895ac
DW
59 EVT_CHAR(wxTextCtrl::OnChar)
60 EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
61
0e320a79
DW
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
68 EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
69 EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
70 EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
71 EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
72 EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
73END_EVENT_TABLE()
0e320a79 74
d90895ac
DW
75
76// ============================================================================
77// implementation
78// ============================================================================
79
80// ----------------------------------------------------------------------------
81// creation
82// ----------------------------------------------------------------------------
83
0e320a79 84wxTextCtrl::wxTextCtrl()
0e320a79 85{
0e320a79
DW
86}
87
3bd418ca
DW
88bool wxTextCtrl::Create(
89 wxWindow* pParent
90, wxWindowID vId
91, const wxString& rsValue
92, const wxPoint& rPos
93, const wxSize& rSize
94, long lStyle
5d4b632b 95#if wxUSE_VALIDATORS
3bd418ca 96, const wxValidator& rValidator
5d4b632b 97#endif
3bd418ca
DW
98, const wxString& rsName
99)
100{
101 //
102 // Base initialization
103 //
104 if ( !CreateBase( pParent
105 ,vId
106 ,rPos
107 ,rSize
108 ,lStyle
109#if wxUSE_VALIDATORS
110 ,rValidator
111#endif
112 ,rsName
113 ))
d90895ac 114 return FALSE;
0e320a79 115
45bfc84b
DW
116 wxPoint vPos = rPos; // The OS/2 position
117
3bd418ca 118 if (pParent )
45bfc84b 119 {
3bd418ca 120 pParent->AddChild(this);
45bfc84b
DW
121 //
122 // OS2 uses normal coordinates, no bassackwards Windows ones
123 //
716ed225 124// vPos.y = pParent->GetSize().y - (vPos.y + rSize.y);
45bfc84b
DW
125 }
126 else
127 {
128 RECTL vRect;
129
130 ::WinQueryWindowRect(HWND_DESKTOP, &vRect);
716ed225 131// vPos.y = vRect.yTop - (vPos.y + rSize.y);
45bfc84b 132 }
0e320a79 133
3bd418ca 134 m_windowStyle = lStyle;
d90895ac 135
3bd418ca
DW
136 long lSstyle = WS_VISIBLE | WS_TABSTOP;
137
138 //
139 // Single and multiline edit fields are two different controls in PM
140 //
d90895ac
DW
141 if ( m_windowStyle & wxTE_MULTILINE )
142 {
3bd418ca
DW
143 m_bIsMLE = TRUE;
144 m_windowStyle |= wxTE_PROCESS_ENTER;
d90895ac 145
d90895ac 146 if ((m_windowStyle & wxTE_NO_VSCROLL) == 0)
3bd418ca
DW
147 lSstyle |= MLS_VSCROLL;
148 if (m_windowStyle & wxHSCROLL)
149 lSstyle |= MLS_HSCROLL;
150 if (m_windowStyle & wxTE_READONLY)
151 lSstyle |= MLS_READONLY;
d90895ac 152 }
0e320a79 153 else
3bd418ca
DW
154 {
155 lSstyle |= ES_LEFT;
156
157 if (m_windowStyle & wxHSCROLL)
158 lSstyle |= ES_AUTOSCROLL;
159 if (m_windowStyle & wxTE_READONLY)
160 lSstyle |= ES_READONLY;
161 if (m_windowStyle & wxTE_PASSWORD) // hidden input
162 lSstyle |= ES_UNREADABLE;
163 }
164 if (m_bIsMLE)
165 {
166 m_hWnd = (WXHWND)::WinCreateWindow( (HWND)GetHwndOf(pParent) // Parent window handle
167 ,WC_MLE // Window class
168 ,(PSZ)rsValue.c_str() // Initial Text
169 ,(ULONG)lSstyle // Style flags
716ed225
DW
170 ,(LONG)0 // X pos of origin
171 ,(LONG)0 // Y pos of origin
172 ,(LONG)0 // field width
173 ,(LONG)0 // field height
3bd418ca
DW
174 ,(HWND)GetHwndOf(pParent) // owner window handle (same as parent
175 ,HWND_TOP // initial z position
176 ,(ULONG)vId // Window identifier
177 ,NULL // no control data
178 ,NULL // no Presentation parameters
179 );
180 }
181 else
182 {
183 m_hWnd = (WXHWND)::WinCreateWindow( (HWND)GetHwndOf(pParent) // Parent window handle
184 ,WC_ENTRYFIELD // Window class
185 ,(PSZ)rsValue.c_str() // Initial Text
186 ,(ULONG)lSstyle // Style flags
716ed225
DW
187 ,(LONG)0 // X pos of origin
188 ,(LONG)0 // Y pos of origin
189 ,(LONG)0 // field width
190 ,(LONG)0 // field height
3bd418ca
DW
191 ,(HWND)GetHwndOf(pParent) // owner window handle (same as parent
192 ,HWND_TOP // initial z position
193 ,(ULONG)vId // Window identifier
194 ,NULL // no control data
195 ,NULL // no Presentation parameters
196 );
197 }
198
199 if (m_hWnd == 0)
200 {
201 return FALSE;
202 }
203
d90895ac
DW
204 SubclassWin(GetHWND());
205
3bd418ca
DW
206 //
207 // Set font, position, size and initial value
208 //
209 wxFont& vFontParent = pParent->GetFont();
210
211 if (vFontParent.Ok())
d90895ac 212 {
3bd418ca 213 SetFont(vFontParent);
d90895ac
DW
214 }
215 else
216 {
217 SetFont(wxSystemSettings::GetSystemFont(wxSYS_SYSTEM_FONT));
218 }
3bd418ca
DW
219 if (!rsValue.IsEmpty())
220 {
221 SetValue(rsValue);
222 }
223 SetupColours();
224 SetSize( rPos.x
225 ,rPos.y
226 ,rSize.x
227 ,rSize.y
228 );
0e320a79 229 return TRUE;
3bd418ca 230} // end of wxTextCtrl::Create
0e320a79 231
3bd418ca 232//
d90895ac 233// Make sure the window style (etc.) reflects the HWND style (roughly)
3bd418ca 234//
d90895ac
DW
235void wxTextCtrl::AdoptAttributesFromHWND()
236{
3bd418ca
DW
237 HWND hWnd = GetHwnd();
238 LONG lStyle = ::WinQueryWindowULong(hWnd, QWL_STYLE);
d90895ac 239
3bd418ca 240 wxWindow::AdoptAttributesFromHWND();
d90895ac 241
3bd418ca
DW
242 if (m_bIsMLE)
243 {
244 m_windowStyle |= wxTE_MULTILINE;
245 if (lStyle & MLS_READONLY)
246 m_windowStyle |= wxTE_READONLY;
247 }
248 else
249 {
250 if (lStyle & ES_UNREADABLE)
251 m_windowStyle |= wxTE_PASSWORD;
252 if (lStyle & ES_READONLY)
253 m_windowStyle |= wxTE_READONLY;
254 }
c4955899 255} // end of wxTextCtrl::AdoptAttributesFromHWND
d90895ac
DW
256
257void wxTextCtrl::SetupColours()
258{
c4955899
DW
259 wxColour vBkgndColour;
260
261 vBkgndColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW);
262 SetBackgroundColour(vBkgndColour);
d90895ac 263 SetForegroundColour(GetParent()->GetForegroundColour());
c4955899 264} // end of wxTextCtrl::SetupColours
d90895ac
DW
265
266// ----------------------------------------------------------------------------
267// set/get the controls text
268// ----------------------------------------------------------------------------
269
0e320a79
DW
270wxString wxTextCtrl::GetValue() const
271{
c4955899
DW
272 wxString sStr = wxGetWindowText(GetHWND());
273 char* zStr = (char*)sStr.c_str();
d90895ac 274
c4955899
DW
275 for ( ; *zStr; zStr++ )
276 {
277 //
278 // this will replace \r\n with just \n
279 //
280 if (*zStr == '\n')
281 *zStr = '\0';
282 if (*zStr == '\r')
283 *zStr = '\n';
284 }
285 sStr = zStr;
286 return sStr;
287} // end of wxTextCtrl::GetValue
0e320a79 288
c4955899
DW
289void wxTextCtrl::SetValue(
290 const wxString& rsValue
291)
0e320a79 292{
c4955899
DW
293 //
294 // If the text is long enough, it's faster to just set it instead of first
295 // comparing it with the old one (chances are that it will be different
296 // anyhow, this comparison is there to avoid flicker for small single-line
297 // edit controls mostly)
298 //
299 if ((rsValue.length() > 0x400) || (rsValue != GetValue()))
300 {
301 ::WinSetWindowText(GetHwnd(), rsValue.c_str());
302 AdjustSpaceLimit();
303 }
304} // end of wxTextCtrl::SetValue
d90895ac 305
c4955899
DW
306void wxTextCtrl::WriteText(
307 const wxString& rsValue
308)
309{
1ec46a5b
DW
310 if (m_defaultStyle.HasFont() || m_defaultStyle.HasTextColour())
311 {
312 long lStart;
313 long lEnd;
314
315 GetSelection( &lStart
316 ,&lEnd
317 );
318 SetStyle( lStart
319 ,lEnd
320 ,m_defaultStyle
321 );
322 }
c4955899 323 ::WinSetWindowText(GetHwnd(), rsValue.c_str());
d90895ac 324 AdjustSpaceLimit();
c4955899 325} // end of wxTextCtrl::WriteText
0e320a79 326
c4955899
DW
327void wxTextCtrl::AppendText(
328 const wxString& rsText
329)
d90895ac 330{
d90895ac 331 SetInsertionPointEnd();
c4955899
DW
332 WriteText(rsText);
333} // end of wxTextCtrl::AppendText
d90895ac
DW
334
335void wxTextCtrl::Clear()
336{
c4955899
DW
337 ::WinSetWindowText(GetHwnd(), "");
338} // end of wxTextCtrl::Clear
d90895ac
DW
339
340// ----------------------------------------------------------------------------
0e320a79 341// Clipboard operations
d90895ac
DW
342// ----------------------------------------------------------------------------
343
0e320a79
DW
344void wxTextCtrl::Copy()
345{
d90895ac
DW
346 if (CanCopy())
347 {
348 HWND hWnd = GetHwnd();
3bd418ca
DW
349 if (m_bIsMLE)
350 ::WinSendMsg(hWnd, MLM_COPY, 0, 0);
351 else
352 ::WinSendMsg(hWnd, EM_COPY, 0, 0);
d90895ac 353 }
3bd418ca 354} // end of wxTextCtrl::Copy
0e320a79
DW
355
356void wxTextCtrl::Cut()
357{
d90895ac
DW
358 if (CanCut())
359 {
360 HWND hWnd = GetHwnd();
3bd418ca
DW
361
362 if (m_bIsMLE)
363 ::WinSendMsg(hWnd, MLM_CUT, 0, 0);
364 else
365 ::WinSendMsg(hWnd, EM_CUT, 0, 0);
d90895ac 366 }
c4955899 367} // end of wxTextCtrl::Cut
0e320a79
DW
368
369void wxTextCtrl::Paste()
370{
d90895ac
DW
371 if (CanPaste())
372 {
c4955899
DW
373 HWND hWnd = GetHwnd();
374
375 ::WinSendMsg(hWnd, EM_PASTE, 0, 0);
d90895ac 376 }
c4955899 377} // end of wxTextCtrl::Paste
d90895ac
DW
378
379bool wxTextCtrl::CanCopy() const
380{
c4955899 381 //
d90895ac 382 // Can copy if there's a selection
c4955899
DW
383 //
384 long lFrom = 0L;
385 long lTo = 0L;
386
387 GetSelection(&lFrom, &lTo);
388 return (lFrom != lTo);
389} // end of wxTextCtrl::CanCopy
d90895ac
DW
390
391bool wxTextCtrl::CanCut() const
392{
c4955899 393 //
d90895ac 394 // Can cut if there's a selection
c4955899
DW
395 //
396 long lFrom = 0L;
397 long lTo = 0L;
398
399 GetSelection(&lFrom, &lTo);
400 return (lFrom != lTo);
401} // end of wxTextCtrl::CanCut
d90895ac
DW
402
403bool wxTextCtrl::CanPaste() const
404{
3bd418ca
DW
405 bool bIsTextAvailable = FALSE;
406
d90895ac
DW
407 if (!IsEditable())
408 return FALSE;
409
3bd418ca
DW
410 //
411 // Check for straight text on clipboard
412 //
413 if (::WinOpenClipbrd(vHabmain))
d90895ac 414 {
3bd418ca
DW
415 bIsTextAvailable = (::WinQueryClipbrdData(vHabmain, CF_TEXT) != 0);
416 ::WinCloseClipbrd(vHabmain);
d90895ac 417 }
3bd418ca
DW
418 return bIsTextAvailable;
419} // end of wxTextCtrl::CanPaste
0e320a79 420
d90895ac
DW
421// ----------------------------------------------------------------------------
422// Accessors
423// ----------------------------------------------------------------------------
424
c4955899
DW
425void wxTextCtrl::SetEditable(
426 bool bEditable
427)
0e320a79 428{
c4955899
DW
429 HWND hWnd = GetHwnd();
430
431 if (m_bIsMLE)
432 ::WinSendMsg(hWnd, MLM_SETREADONLY, MPFROMLONG(!bEditable), (MPARAM)0);
433 else
434 ::WinSendMsg(hWnd, EM_SETREADONLY, MPFROMLONG(!bEditable), (MPARAM)0);
435} // end of wxTextCtrl::SetEditable
0e320a79 436
c4955899
DW
437void wxTextCtrl::SetInsertionPoint(
438 long lPos
439)
0e320a79 440{
c4955899
DW
441 HWND hWnd = GetHwnd();
442
443 if (m_bIsMLE)
444 ::WinSendMsg(hWnd, MLM_SETSEL, (MPARAM)lPos, (MPARAM)lPos);
445 else
446 ::WinSendMsg(hWnd, EM_SETSEL, MPFROM2SHORT((USHORT)lPos, (USHORT)lPos), (MPARAM)0);
447} // end of wxTextCtrl::SetInsertionPoint
0e320a79
DW
448
449void wxTextCtrl::SetInsertionPointEnd()
450{
c4955899
DW
451 long lPos = GetLastPosition();
452
453 SetInsertionPoint(lPos);
454} // end of wxTextCtrl::SetInsertionPointEnd
0e320a79
DW
455
456long wxTextCtrl::GetInsertionPoint() const
457{
3bd418ca
DW
458 WXDWORD dwPos = 0L;
459
460 if (m_bIsMLE)
461 dwPos = (WXDWORD)::WinSendMsg(GetHwnd(), MLM_QUERYSEL, (MPARAM)MLFQS_MINSEL, 0);
462 else
463 {
464 dwPos = (WXDWORD)::WinSendMsg(GetHwnd(), EM_QUERYSEL, 0, 0);
465 dwPos = SHORT1FROMMP((MPARAM)dwPos); // the first 16 bit value is the min pos
466 }
467 return (dwPos & 0xFFFF);
468} // end of wxTextCtrl::GetInsertionPoint
0e320a79
DW
469
470long wxTextCtrl::GetLastPosition() const
471{
3bd418ca
DW
472 HWND hWnd = GetHwnd();
473 long lCharIndex;
474 long lLineLength;
0e320a79 475
3bd418ca
DW
476 if (m_bIsMLE)
477 {
478 lCharIndex = 0;
d90895ac 479
3bd418ca
DW
480 //
481 // This just gets the total text length. The last will be this value
482 //
483 lLineLength = (long)::WinSendMsg(hWnd, MLM_QUERYTEXTLENGTH, 0, 0);
484 }
485 else
486 {
487 WNDPARAMS vParams;
488
489 lCharIndex = 0;
490 vParams.fsStatus = WPM_CCHTEXT;
491 if (::WinSendMsg( GetHwnd()
492 ,WM_QUERYWINDOWPARAMS
493 ,&vParams
494 ,0
495 ))
496 {
497 lLineLength = (long)vParams.cchText;
498 }
499 else
500 lLineLength = 0;
501 }
502 return(lCharIndex + lLineLength);
503} // end of wxTextCtrl::GetLastPosition
0e320a79 504
d90895ac
DW
505// If the return values from and to are the same, there is no
506// selection.
c4955899
DW
507void wxTextCtrl::GetSelection(
508 long* plFrom
509, long* plTo
510) const
0e320a79 511{
c4955899 512 WXDWORD dwPos;
0e320a79 513
c4955899
DW
514 if (m_bIsMLE)
515 dwPos = (WXDWORD)::WinSendMsg(GetHwnd(), MLM_QUERYSEL, (MPARAM)MLFQS_MINSEL, 0);
516 else
517 {
518 dwPos = (WXDWORD)::WinSendMsg(GetHwnd(), EM_QUERYSEL, 0, 0);
519 }
520 *plFrom = SHORT1FROMMP((MPARAM)dwPos); // the first 16 bit value is the min pos
521 *plTo = SHORT2FROMMP((MPARAM)dwPos); // the first 16 bit value is the min pos
522} // end of wxTextCtrl::GetSelection
0e320a79 523
d90895ac
DW
524bool wxTextCtrl::IsEditable() const
525{
c4955899
DW
526 if (m_bIsMLE)
527 return((bool)LONGFROMMR(::WinSendMsg(GetHwnd(), MLM_QUERYREADONLY, 0, 0)));
528 else
529 return((bool)LONGFROMMR(::WinSendMsg(GetHwnd(), EM_QUERYREADONLY, 0, 0)));
530} // end of wxTextCtrl::IsEditable
0e320a79 531
d90895ac
DW
532// ----------------------------------------------------------------------------
533// Editing
534// ----------------------------------------------------------------------------
535
c4955899
DW
536void wxTextCtrl::Replace(
537 long lFrom
538, long lTo
539, const wxString& rsValue
540)
0e320a79 541{
d90895ac 542#if wxUSE_CLIPBOARD
c4955899
DW
543 HWND hWnd = GetHwnd();
544 long lFromChar = lFrom;
545 long lToChar = lTo;
0e320a79 546
c4955899 547 //
d90895ac 548 // Set selection and remove it
c4955899
DW
549 //
550 if (m_bIsMLE)
551 {
552 ::WinSendMsg(hWnd, MLM_SETSEL, MPFROM2SHORT((USHORT)lFrom, (USHORT)lTo), 0);
553 ::WinSendMsg(hWnd, MLM_CUT, 0, 0);
554 }
555 else
556 {
557 ::WinSendMsg(hWnd, EM_SETSEL, MPFROM2SHORT((USHORT)lFrom, (USHORT)lTo), 0);
558 ::WinSendMsg(hWnd, EM_CUT, 0, 0);
559 }
0e320a79 560
c4955899 561 //
d90895ac 562 // Now replace with 'value', by pasting.
c4955899
DW
563 //
564 wxSetClipboardData(wxDF_TEXT, (wxObject *) (const wxChar *)rsValue, 0, 0);
0e320a79 565
d90895ac 566 // Paste into edit control
c4955899
DW
567 if (m_bIsMLE)
568 ::WinSendMsg(hWnd, MLM_PASTE, (MPARAM)0, (MPARAM)0);
569 else
570 ::WinSendMsg(hWnd, EM_PASTE, (MPARAM)0, (MPARAM)0);
d90895ac
DW
571#else
572 wxFAIL_MSG("wxTextCtrl::Replace not implemented if wxUSE_CLIPBOARD is 0.");
573#endif
c4955899 574} // end of wxTextCtrl::Replace
0e320a79 575
c4955899
DW
576void wxTextCtrl::Remove(
577 long lFrom
578, long lTo
579)
0e320a79 580{
c4955899
DW
581 HWND hWnd = GetHwnd();
582 long lFromChar = lFrom;
583 long lToChar = lTo;
d90895ac 584
c4955899
DW
585 if (m_bIsMLE)
586 {
587 ::WinSendMsg(hWnd, MLM_SETSEL, MPFROM2SHORT((USHORT)lFrom, (USHORT)lTo), 0);
588 ::WinSendMsg(hWnd, MLM_CUT, 0, 0);
589 }
590 else
591 {
592 ::WinSendMsg(hWnd, EM_SETSEL, MPFROM2SHORT((USHORT)lFrom, (USHORT)lTo), 0);
593 ::WinSendMsg(hWnd, EM_CUT, 0, 0);
594 }
595} // end of wxTextCtrl::Remove
0e320a79 596
c4955899
DW
597void wxTextCtrl::SetSelection(
598 long lFrom
599, long lTo
600)
0e320a79 601{
c4955899
DW
602 HWND hWnd = GetHwnd();
603 long lFromChar = lFrom;
604 long lToChar = lTo;
d90895ac 605
c4955899
DW
606 //
607 // If from and to are both -1, it means (in wxWindows) that all text should
d90895ac 608 // be selected. Translate into Windows convention
c4955899
DW
609 //
610 if ((lFrom == -1L) && (lTo == -1L))
d90895ac 611 {
c4955899
DW
612 lFromChar = 0L;
613 lToChar = -1L;
d90895ac 614 }
c4955899
DW
615 if (m_bIsMLE)
616 ::WinSendMsg(hWnd, MLM_SETSEL, (MPARAM)lFromChar, (MPARAM)lToChar);
617 else
618 ::WinSendMsg(hWnd, EM_SETSEL, MPFROM2SHORT((USHORT)lFromChar, (USHORT)lToChar), (MPARAM)0);
619} // end of wxTextCtrl::SetSelection
d90895ac 620
1ec46a5b
DW
621bool wxTextCtrl::SetStyle(
622 long lStart
623, long lEnd
624, const wxTextAttr& rStyle
625)
626{
627 HWND hWnd = GetHwnd();
628 //
629 // Order the range if needed
630 //
631 if (lStart > lEnd)
632 {
633 long lTmp = lStart;
634
635 lStart = lEnd;
636 lEnd = lTmp;
637 }
638
639 //
640 // We can only change the format of the selection, so select the range we
641 // want and restore the old selection later
642 long lStartOld;
643 long lEndOld;
644
645 GetSelection( &lStartOld
646 ,&lEndOld
647 );
648
649 //
650 // But do we really have to change the selection?
651 //
652 bool bChangeSel = lStart != lStartOld || lEnd != lEndOld;
653
654 if (bChangeSel)
655 {
656 if (m_bIsMLE)
657 ::WinSendMsg(hWnd, MLM_SETSEL, MPFROM2SHORT((USHORT)lStart, (USHORT)lEnd), 0);
658 else
659 ::WinSendMsg(hWnd, EM_SETSEL, MPFROM2SHORT((USHORT)lStart, (USHORT)lEnd), 0);
660 }
661 //
662 // TODO:: finish this by setting fonts and colors
663 //
664 return TRUE;
665} // end of wxTextCtrl::SetStyle
666
c4955899
DW
667bool wxTextCtrl::LoadFile(
668 const wxString& rsFile
669)
0e320a79 670{
c4955899 671 if ( wxTextCtrlBase::LoadFile(rsFile) )
d90895ac 672 {
c4955899
DW
673 //
674 // Update the size limit if needed
675 //
d90895ac 676 AdjustSpaceLimit();
d90895ac
DW
677 return TRUE;
678 }
d90895ac 679 return FALSE;
c4955899 680} // end of wxTextCtrl::LoadFile
0e320a79
DW
681
682bool wxTextCtrl::IsModified() const
683{
c4955899
DW
684 bool bRc;
685
686 if (m_bIsMLE)
687 bRc = (bool)LONGFROMMR(::WinSendMsg(GetHwnd(), MLM_QUERYCHANGED, 0, 0));
688 else
689 bRc = (bool)LONGFROMMR(::WinSendMsg(GetHwnd(), EM_QUERYCHANGED, 0, 0));
690 return bRc;
691} // end of wxTextCtrl::IsModified
0e320a79 692
3bd418ca 693//
0e320a79 694// Makes 'unmodified'
3bd418ca 695//
0e320a79
DW
696void wxTextCtrl::DiscardEdits()
697{
3bd418ca
DW
698 if (m_bIsMLE)
699 ::WinSendMsg(GetHwnd(), MLM_SETCHANGED, MPFROMLONG(FALSE), 0);
700 else
701 //
702 // EM controls do not have a SETCHANGED but issuing a query should reset it
703 //
704 ::WinSendMsg(GetHwnd(), EM_QUERYCHANGED, 0, 0);
705} // end of wxTextCtrl::DiscardEdits
0e320a79
DW
706
707int wxTextCtrl::GetNumberOfLines() const
708{
c4955899 709 int nNumLines;
0e320a79 710
c4955899
DW
711 if (m_bIsMLE)
712 nNumLines = (int)::WinSendMsg(GetHwnd(), MLM_QUERYLINECOUNT, 0, 0);
713 else
714 nNumLines = 1;
715 return nNumLines;
716} // end of wxTextCtrl::GetNumberOfLines
d90895ac 717
c4955899
DW
718long wxTextCtrl::XYToPosition(
719 long lX
720, long lY
721) const
722{
723 HWND hWnd = GetHwnd();
724 long lCharIndex = 0L;
725 long lLen;
0e320a79 726
c4955899
DW
727 if (m_bIsMLE)
728 {
729 lLen = (long)::WinSendMsg(GetHwnd(), MLM_QUERYLINELENGTH, 0, 0);
730 lCharIndex = ((lLen * lY) + lX);
731 }
732 else
733 lCharIndex = lX;
734 return lCharIndex;
735} // end of wxTextCtrl::XYToPosition
736
737bool wxTextCtrl::PositionToXY(
738 long lPos
739, long* plX
740, long* plY
741) const
0e320a79 742{
c4955899
DW
743 HWND hWnd = GetHwnd();
744 long nLineNo = -1;
745 long lCharIndex = 0;
d90895ac 746
c4955899
DW
747 if (m_bIsMLE)
748 nLineNo = (long)::WinSendMsg(hWnd, MLM_LINEFROMCHAR, (MPARAM)lPos, 0);
749 else
750 nLineNo = 0;
d90895ac 751
c4955899 752 if (nLineNo == -1)
d90895ac
DW
753 {
754 // no such line
755 return FALSE;
756 }
757
c4955899 758 //
d90895ac 759 // This gets the char index for the _beginning_ of this line
c4955899
DW
760 //
761 long lLineWidth;
762
763 if (m_bIsMLE)
764 {
765 lLineWidth = (long)::WinSendMsg(hWnd, MLM_QUERYLINELENGTH, (MPARAM)0, (MPARAM)0);
766 lCharIndex = (nLineNo + 1) * lLineWidth;
767 }
768 else
769 {
770 WNDPARAMS vParams;
771
772 vParams.fsStatus = WPM_CCHTEXT;
773 if (::WinSendMsg( hWnd
774 ,WM_QUERYWINDOWPARAMS
775 ,&vParams
776 ,0
777 ))
778 {
779 lCharIndex = vParams.cchText;
780 }
781 else
782 lCharIndex = 32;
783 }
784
785 if (lCharIndex == -1)
d90895ac
DW
786 {
787 return FALSE;
788 }
789
c4955899
DW
790 //
791 // The X position must therefore be the difference between pos and charIndex
792 //
793 if (plX)
794 *plX = lPos - lCharIndex;
795 if (plY)
796 *plY = nLineNo;
d90895ac
DW
797
798 return TRUE;
c4955899 799} // end of wxTextCtrl::PositionToXY
0e320a79 800
c4955899
DW
801void wxTextCtrl::ShowPosition(
802 long lPos
803)
0e320a79 804{
c4955899
DW
805 HWND hWnd = GetHwnd();
806 long lCurrentLineLineNo = 0L;
d90895ac
DW
807
808 // To scroll to a position, we pass the number of lines and characters
809 // to scroll *by*. This means that we need to:
810 // (1) Find the line position of the current line.
811 // (2) Find the line position of pos.
812 // (3) Scroll by (pos - current).
813 // For now, ignore the horizontal scrolling.
814
c4955899 815 //
d90895ac
DW
816 // Is this where scrolling is relative to - the line containing the caret?
817 // Or is the first visible line??? Try first visible line.
c4955899
DW
818 //
819 if (m_bIsMLE)
820 {
821 //
822 // In PM this is the actual char position
823 //
824 lCurrentLineLineNo = (long)::WinSendMsg(hWnd, MLM_QUERYFIRSTCHAR, (MPARAM)0, (MPARAM)0);
d90895ac 825
c4955899
DW
826 //
827 // This will cause a scroll to the selected position
828 //
829 ::WinSendMsg(hWnd, MLM_SETSEL, (MPARAM)lCurrentLineLineNo, (MPARAM)lCurrentLineLineNo);
830 }
831} // end of wxTextCtrl::ShowPosition
0e320a79 832
3bd418ca
DW
833int wxTextCtrl::GetLineLength(
834 long lLineNo
835) const
0e320a79 836{
3bd418ca 837 long lLen = 0L;
d90895ac 838
3bd418ca
DW
839 if (m_bIsMLE)
840 lLen = (long)::WinSendMsg(GetHwnd(), MLM_QUERYLINELENGTH, 0, 0);
841 else
842 {
843 WNDPARAMS vParams;
844
845 vParams.fsStatus = WPM_CCHTEXT;
846 if (::WinSendMsg( GetHwnd()
847 ,WM_QUERYWINDOWPARAMS
848 ,&vParams
849 ,0
850 ))
851 {
852 lLen = vParams.cchText;
853 }
854 else
855 lLen = 32;
856 }
857 return lLen;
c4955899 858} // end ofwxTextCtrl::GetLineLength
0e320a79 859
c4955899
DW
860wxString wxTextCtrl::GetLineText(
861 long lLineNo
862) const
0e320a79 863{
c4955899
DW
864 long lLen = (long)GetLineLength((long)lLineNo) + 1;
865 wxString sStr;
866 char* zBuf;
0e320a79 867
c4955899
DW
868 //
869 // There must be at least enough place for the length WORD in the
870 // buffer
871 //
872 lLen += sizeof(WORD);
873 zBuf = new char[lLen];
874 if (m_bIsMLE)
875 {
876 long lIndex;
877 long lBuflen;
878 long lCopied;
0e320a79 879
c4955899
DW
880 lLen = (long)::WinSendMsg(GetHwnd(), MLM_QUERYLINELENGTH, 0, 0);
881 lIndex = lLen * lLineNo;
0e320a79 882
c4955899
DW
883 ::WinSendMsg(GetHwnd(), MLM_SETSEL, (MPARAM)lIndex, (MPARAM)lIndex);
884 ::WinSendMsg(GetHwnd(), MLM_SETIMPORTEXPORT, MPFROMP(zBuf), MPFROMSHORT((USHORT)sizeof(zBuf)));
885 lBuflen = (long)::WinSendMsg(GetHwnd(), MLM_QUERYFORMATTEXTLENGTH, MPFROMLONG(lIndex), MPFROMLONG(-1));
886 lCopied = (long)::WinSendMsg(GetHwnd(), MLM_EXPORT, MPFROMP(&lIndex), MPFROMP(&lBuflen));
887 zBuf[lCopied] = '\0';
888 }
889 else
890 {
891 WNDPARAMS vParams;
892
893 vParams.fsStatus = WPM_CCHTEXT;
894 if (::WinSendMsg( GetHwnd()
895 ,WM_QUERYWINDOWPARAMS
896 ,&vParams
897 ,0
898 ))
899 memcpy(zBuf, vParams.pszText, vParams.cchText);
900 zBuf[vParams.cchText] = '\0';
901 }
902 sStr = zBuf;
903 delete [] zBuf;
904 return sStr;
905} // end of wxTextCtrl::GetLineText
0e320a79 906
d90895ac 907// ----------------------------------------------------------------------------
0e320a79 908// Undo/redo
d90895ac
DW
909// ----------------------------------------------------------------------------
910
0e320a79
DW
911void wxTextCtrl::Undo()
912{
d90895ac
DW
913 if (CanUndo())
914 {
c4955899
DW
915 if (m_bIsMLE)
916 ::WinSendMsg(GetHwnd(), MLM_UNDO, 0, 0);
917 // Simple entryfields cannot be undone
d90895ac 918 }
c4955899 919} // end of wxTextCtrl::Undo
0e320a79
DW
920
921void wxTextCtrl::Redo()
922{
d90895ac
DW
923 if (CanRedo())
924 {
c4955899
DW
925 if (m_bIsMLE)
926 ::WinSendMsg(GetHwnd(), MLM_UNDO, 0, 0);
927 // Simple entryfields cannot be undone
d90895ac 928 }
c4955899 929} // end of wxTextCtrl::Redo
0e320a79
DW
930
931bool wxTextCtrl::CanUndo() const
932{
3bd418ca
DW
933 bool bOk;
934
935 if (m_bIsMLE)
936 bOk = (::WinSendMsg(GetHwnd(), MLM_QUERYUNDO, 0, 0) != 0);
937 else
938 bOk = FALSE; // can't undo regular edit fields in PM
939 return bOk;
940} // end of wxTextCtrl::CanUndo
0e320a79
DW
941
942bool wxTextCtrl::CanRedo() const
943{
3bd418ca
DW
944 bool bOk;
945
946 if (m_bIsMLE)
947 bOk = (::WinSendMsg(GetHwnd(), MLM_QUERYUNDO, 0, 0) != 0);
948 else
949 bOk = FALSE; // can't undo regular edit fields in PM
950 return bOk;
951} // end of wxTextCtrl::CanRedo
0e320a79 952
d90895ac
DW
953// ----------------------------------------------------------------------------
954// implemenation details
955// ----------------------------------------------------------------------------
0e320a79 956
c4955899
DW
957void wxTextCtrl::Command(
958 wxCommandEvent& rEvent
959)
0e320a79 960{
c4955899
DW
961 SetValue(rEvent.GetString());
962 ProcessCommand (rEvent);
963} // end of wxTextCtrl::Command
0e320a79 964
c4955899
DW
965void wxTextCtrl::OnDropFiles(
966 wxDropFilesEvent& rEvent
967)
0e320a79
DW
968{
969 // By default, load the first file into the text window.
c4955899 970 if (rEvent.GetNumberOfFiles() > 0)
0e320a79 971 {
c4955899 972 LoadFile(rEvent.GetFiles()[0]);
0e320a79 973 }
c4955899
DW
974} // end of wxTextCtrl::OnDropFiles
975
976WXHBRUSH wxTextCtrl::OnCtlColor(
977 WXHDC hWxDC
978, WXHWND hWnd
979, WXUINT uCtlColor
980, WXUINT uMessage
981, WXWPARAM wParam
982, WXLPARAM lParam
983)
d90895ac 984{
c4955899
DW
985 HPS hPS = (HPS)hWxDC;
986 wxBrush* pBrush = NULL;
987 wxColour vColBack = GetBackgroundColour();
988 wxColour vColFore = GetForegroundColour();
989 wxBrush* pBackgroundBrush = wxTheBrushList->FindOrCreateBrush( GetBackgroundColour()
990 ,wxSOLID
991 );
992
993 if (m_bUseCtl3D)
994 {
995 HBRUSH hBrush = NULLHANDLE;
0e320a79 996
c4955899
DW
997 return hBrush;
998 }
999 if (GetParent()->GetTransparentBackground())
1000 ::GpiSetBackMix(hPS, BM_LEAVEALONE);
1001 else
1002 ::GpiSetBackMix(hPS, BM_OVERPAINT);
1003 if (!IsEnabled() && (GetWindowStyle() & wxTE_MULTILINE) == 0)
1004 vColBack = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE);
1005 ::GpiSetBackColor(hPS, vColBack.GetPixel());
1006 ::GpiSetColor(hPS, vColFore.GetPixel());
1007 return (WXHBRUSH)pBackgroundBrush->GetResourceHandle();
1008} // end of wxTextCtrl::OnCtlColor
1009
1010void wxTextCtrl::OnChar(
1011 wxKeyEvent& rEvent
1012)
0e320a79 1013{
c4955899 1014 switch (rEvent.KeyCode())
d90895ac 1015 {
d90895ac
DW
1016 case WXK_RETURN:
1017 if ( !(m_windowStyle & wxTE_MULTILINE) )
1018 {
c4955899
DW
1019 wxCommandEvent vEvent(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
1020
1021 vEvent.SetEventObject(this);
1022 if ( GetEventHandler()->ProcessEvent(vEvent))
d90895ac
DW
1023 return;
1024 }
1025 //else: multiline controls need Enter for themselves
1026
1027 break;
1028
1029 case WXK_TAB:
1030 // always produce navigation event - even if we process TAB
1031 // ourselves the fact that we got here means that the user code
1032 // decided to skip processing of this TAB - probably to let it
1033 // do its default job.
1034 //
1035 // NB: Notice that Ctrl-Tab is handled elsewhere and Alt-Tab is
1036 // handled by Windows
1037 {
c4955899 1038 wxNavigationKeyEvent vEventNav;
d90895ac 1039
c4955899
DW
1040 vEventNav.SetDirection(!rEvent.ShiftDown());
1041 vEventNav.SetWindowChange(FALSE);
1042 vEventNav.SetEventObject(this);
1043
1044 if ( GetEventHandler()->ProcessEvent(vEventNav) )
d90895ac
DW
1045 return;
1046 }
1047 break;
d90895ac 1048 }
c4955899
DW
1049 rEvent.Skip();
1050} // end of wxTextCtrl::OnChar
0e320a79 1051
c4955899
DW
1052bool wxTextCtrl::OS2Command(
1053 WXUINT uParam
1054, WXWORD WXUNUSED(vId)
1055)
0e320a79 1056{
c4955899 1057 switch (uParam)
d90895ac 1058 {
d90895ac
DW
1059 case EN_SETFOCUS:
1060 case EN_KILLFOCUS:
1061 {
c4955899
DW
1062 wxFocusEvent vEvent( uParam == EN_KILLFOCUS ? wxEVT_KILL_FOCUS
1063 : wxEVT_SET_FOCUS
1064 ,m_windowId
1065 );
1066
1067 vEvent.SetEventObject(this);
1068 GetEventHandler()->ProcessEvent(vEvent);
d90895ac
DW
1069 }
1070 break;
1071
1072 case EN_CHANGE:
1073 {
c4955899
DW
1074 wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_UPDATED
1075 ,m_windowId
1076 );
1077
1078 InitCommandEvent(vEvent);
1079 vEvent.SetString((char*)GetValue().c_str());
1080 ProcessCommand(vEvent);
d90895ac
DW
1081 }
1082 break;
1083
c4955899
DW
1084 case EN_OVERFLOW:
1085 //
1086 // The text size limit has been hit - increase it
1087 //
d90895ac
DW
1088 AdjustSpaceLimit();
1089 break;
1090
c4955899
DW
1091 case EN_SCROLL:
1092 case EN_INSERTMODETOGGLE:
1093 case EN_MEMERROR:
1094 return FALSE;
d90895ac
DW
1095 default:
1096 return FALSE;
1097 }
1098
c4955899
DW
1099 //
1100 // Processed
1101 //
d90895ac 1102 return TRUE;
c4955899 1103} // end of wxTextCtrl::OS2Command
0e320a79 1104
d90895ac 1105void wxTextCtrl::AdjustSpaceLimit()
0e320a79 1106{
3bd418ca
DW
1107 unsigned int uLen = 0;
1108 unsigned int uLimit = 0;
d90895ac 1109
3bd418ca
DW
1110 uLen = ::WinQueryWindowTextLength(GetHwnd());
1111 if (m_bIsMLE)
1112 {
1113 uLimit = (unsigned int)::WinSendMsg( GetHwnd()
1114 ,MLM_QUERYTEXTLIMIT
1115 ,0
1116 ,0
1117 );
1118 }
1119 else
1120 {
1121 ENTRYFDATA* pEfd;
1122 WNDPARAMS vParams;
1123
1124 vParams.fsStatus = WPM_CBCTLDATA;
1125 vParams.cbCtlData = sizeof(ENTRYFDATA);
1126
1127 if (::WinSendMsg( GetHwnd()
1128 ,WM_QUERYWINDOWPARAMS
1129 ,&vParams
1130 ,0
1131 ))
1132 {
1133 pEfd = (ENTRYFDATA*)vParams.pCtlData;
1134 uLimit = (unsigned int)pEfd->cchEditLimit;
1135 }
d90895ac 1136 else
3bd418ca 1137 uLimit = 32; //PM's default
d90895ac 1138 }
3bd418ca
DW
1139 if (uLen >= uLimit)
1140 {
1141 uLimit = uLen + 0x8000; // 32Kb
1142 if (uLimit > 0xffff)
1143 {
1144 uLimit = 0L;
1145 }
1146 if (m_bIsMLE)
1147 ::WinSendMsg(GetHwnd(), MLM_SETTEXTLIMIT, MPFROMLONG(uLimit), 0);
1148 else
1149 ::WinSendMsg(GetHwnd(), EM_SETTEXTLIMIT, MPFROMLONG(uLimit), 0);
1150 }
1151} // end of wxTextCtrl::AdjustSpaceLimit
0e320a79 1152
d90895ac 1153bool wxTextCtrl::AcceptsFocus() const
0e320a79 1154{
c4955899
DW
1155 //
1156 // We don't want focus if we can't be edited
1157 //
d90895ac 1158 return IsEditable() && wxControl::AcceptsFocus();
c4955899 1159} // end of wxTextCtrl::Command
0e320a79 1160
e78c4d50 1161wxSize wxTextCtrl::DoGetBestSize() const
0e320a79 1162{
c4955899
DW
1163 int nCx;
1164 int nCy;
0e320a79 1165
c4955899 1166 wxGetCharSize(GetHWND(), &nCx, &nCy, (wxFont*)&GetFont());
d90895ac 1167
c4955899
DW
1168 int wText = DEFAULT_ITEM_WIDTH;
1169 int hText = EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy);
1170
1171 if (m_windowStyle & wxTE_MULTILINE)
d90895ac
DW
1172 {
1173 hText *= wxMin(GetNumberOfLines(), 5);
1174 }
1175 //else: for single line control everything is ok
d90895ac 1176 return wxSize(wText, hText);
c4955899 1177} // end of wxTextCtrl::DoGetBestSize
0e320a79 1178
d90895ac
DW
1179// ----------------------------------------------------------------------------
1180// standard handlers for standard edit menu events
1181// ----------------------------------------------------------------------------
1182
c4955899
DW
1183void wxTextCtrl::OnCut(
1184 wxCommandEvent& rEvent
1185)
0e320a79
DW
1186{
1187 Cut();
c4955899 1188} // end of wxTextCtrl::OnCut
0e320a79 1189
c4955899
DW
1190void wxTextCtrl::OnCopy(
1191 wxCommandEvent& rEvent
1192)
0e320a79
DW
1193{
1194 Copy();
c4955899 1195} // end of wxTextCtrl::OnCopy
0e320a79 1196
c4955899
DW
1197void wxTextCtrl::OnPaste(
1198 wxCommandEvent& rEvent
1199)
0e320a79
DW
1200{
1201 Paste();
c4955899 1202} // end of wxTextCtrl::OnPaste
0e320a79 1203
c4955899
DW
1204void wxTextCtrl::OnUndo(
1205 wxCommandEvent& rEvent
1206)
0e320a79
DW
1207{
1208 Undo();
c4955899 1209} // end of wxTextCtrl::OnUndo
0e320a79 1210
c4955899
DW
1211void wxTextCtrl::OnRedo(
1212 wxCommandEvent& rEvent
1213)
0e320a79
DW
1214{
1215 Redo();
c4955899 1216} // end of wxTextCtrl::OnRedo
0e320a79 1217
c4955899
DW
1218void wxTextCtrl::OnUpdateCut(
1219 wxUpdateUIEvent& rEvent
1220)
0e320a79 1221{
c4955899
DW
1222 rEvent.Enable(CanCut());
1223} // end of wxTextCtrl::OnUpdateCut
0e320a79 1224
c4955899
DW
1225void wxTextCtrl::OnUpdateCopy(
1226 wxUpdateUIEvent& rEvent
1227)
0e320a79 1228{
c4955899
DW
1229 rEvent.Enable(CanCopy());
1230} // end of wxTextCtrl::OnUpdateCopy
0e320a79 1231
c4955899
DW
1232void wxTextCtrl::OnUpdatePaste(
1233 wxUpdateUIEvent& rEvent
1234)
0e320a79 1235{
c4955899
DW
1236 rEvent.Enable(CanPaste());
1237} // end of wxTextCtrl::OnUpdatePaste
0e320a79 1238
c4955899
DW
1239void wxTextCtrl::OnUpdateUndo(
1240 wxUpdateUIEvent& rEvent
1241)
0e320a79 1242{
c4955899
DW
1243 rEvent.Enable(CanUndo());
1244} // end of wxTextCtrl::OnUpdateUndo
1245
1246void wxTextCtrl::OnUpdateRedo(
1247 wxUpdateUIEvent& rEvent
1248)
1249{
1250 rEvent.Enable(CanRedo());
1251} // end of wxTextCtrl::OnUpdateRedo
0e320a79 1252
c4955899
DW
1253bool wxTextCtrl::SetBackgroundColour(
1254 const wxColour& rColour
1255)
0e320a79 1256{
c4955899
DW
1257 if (m_bIsMLE)
1258 ::WinSendMsg(GetHwnd(), MLM_SETBACKCOLOR, (MPARAM)rColour.GetPixel(), MLE_INDEX);
1259 return TRUE;
1260} // end of wxTextCtrl::SetBackgroundColour
1261
1262bool wxTextCtrl::SetForegroundColour(
1263 const wxColour& rColour
1264)
1265{
1266 if (m_bIsMLE)
1267 ::WinSendMsg(GetHwnd(), MLM_SETTEXTCOLOR, (MPARAM)rColour.GetPixel(), MLE_INDEX);
1268 return TRUE;
1269} // end of wxTextCtrl::SetForegroundColour
d90895ac 1270