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