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