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