]> git.saurik.com Git - wxWidgets.git/blob - src/os2/textctrl.cpp
don't call SelectObject() twice in SetBrush() nor SetFont() neither
[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 //
511 // We must not do anything if the caret is already there because calling
512 // SetInsertionPoint() thaws the controls if Freeze() had been called even
513 // if it doesn't actually move the caret anywhere and so the simple fact of
514 // doing it results in horrible flicker when appending big amounts of text
515 // to the control in a few chunks (see DoAddText() test in the text sample)
516 //
517 if (GetInsertionPoint() == GetLastPosition())
518 return;
519 SetInsertionPoint(lPos);
520 } // end of wxTextCtrl::SetInsertionPointEnd
521
522 long wxTextCtrl::GetInsertionPoint() const
523 {
524 WXDWORD dwPos = 0L;
525
526 if (m_bIsMLE)
527 dwPos = (WXDWORD)::WinSendMsg(GetHwnd(), MLM_QUERYSEL, (MPARAM)MLFQS_MINSEL, 0);
528 else
529 {
530 dwPos = (WXDWORD)::WinSendMsg(GetHwnd(), EM_QUERYSEL, 0, 0);
531 dwPos = SHORT1FROMMP((MPARAM)dwPos); // the first 16 bit value is the min pos
532 }
533 return (dwPos & 0xFFFF);
534 } // end of wxTextCtrl::GetInsertionPoint
535
536 long wxTextCtrl::GetLastPosition() const
537 {
538 HWND hWnd = GetHwnd();
539 long lCharIndex;
540 long lLineLength;
541
542 if (m_bIsMLE)
543 {
544 lCharIndex = 0;
545
546 //
547 // This just gets the total text length. The last will be this value
548 //
549 lLineLength = (long)::WinSendMsg(hWnd, MLM_QUERYTEXTLENGTH, 0, 0);
550 }
551 else
552 {
553 WNDPARAMS vParams;
554
555 lCharIndex = 0;
556 vParams.fsStatus = WPM_CCHTEXT;
557 if (::WinSendMsg( GetHwnd()
558 ,WM_QUERYWINDOWPARAMS
559 ,&vParams
560 ,0
561 ))
562 {
563 lLineLength = (long)vParams.cchText;
564 }
565 else
566 lLineLength = 0;
567 }
568 return(lCharIndex + lLineLength);
569 } // end of wxTextCtrl::GetLastPosition
570
571 // If the return values from and to are the same, there is no
572 // selection.
573 void wxTextCtrl::GetSelection(
574 long* plFrom
575 , long* plTo
576 ) const
577 {
578 WXDWORD dwPos;
579
580 if (m_bIsMLE)
581 dwPos = (WXDWORD)::WinSendMsg(GetHwnd(), MLM_QUERYSEL, (MPARAM)MLFQS_MINSEL, 0);
582 else
583 {
584 dwPos = (WXDWORD)::WinSendMsg(GetHwnd(), EM_QUERYSEL, 0, 0);
585 }
586 *plFrom = SHORT1FROMMP((MPARAM)dwPos); // the first 16 bit value is the min pos
587 *plTo = SHORT2FROMMP((MPARAM)dwPos); // the first 16 bit value is the min pos
588 } // end of wxTextCtrl::GetSelection
589
590 bool wxTextCtrl::IsEditable() const
591 {
592 if (m_bIsMLE)
593 return((bool)LONGFROMMR(::WinSendMsg(GetHwnd(), MLM_QUERYREADONLY, 0, 0)));
594 else
595 return((bool)LONGFROMMR(::WinSendMsg(GetHwnd(), EM_QUERYREADONLY, 0, 0)));
596 } // end of wxTextCtrl::IsEditable
597
598 // ----------------------------------------------------------------------------
599 // Editing
600 // ----------------------------------------------------------------------------
601
602 void wxTextCtrl::Replace(
603 long lFrom
604 , long lTo
605 , const wxString& rsValue
606 )
607 {
608 #if wxUSE_CLIPBOARD
609 HWND hWnd = GetHwnd();
610 long lFromChar = lFrom;
611 long lToChar = lTo;
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 wxFAIL_MSG("wxTextCtrl::Replace not implemented if wxUSE_CLIPBOARD is 0.");
639 #endif
640 } // end of wxTextCtrl::Replace
641
642 void wxTextCtrl::Remove(
643 long lFrom
644 , long lTo
645 )
646 {
647 HWND hWnd = GetHwnd();
648 long lFromChar = lFrom;
649 long lToChar = lTo;
650
651 if (m_bIsMLE)
652 {
653 ::WinSendMsg(hWnd, MLM_SETSEL, MPFROM2SHORT((USHORT)lFrom, (USHORT)lTo), 0);
654 ::WinSendMsg(hWnd, MLM_CUT, 0, 0);
655 }
656 else
657 {
658 ::WinSendMsg(hWnd, EM_SETSEL, MPFROM2SHORT((USHORT)lFrom, (USHORT)lTo), 0);
659 ::WinSendMsg(hWnd, EM_CUT, 0, 0);
660 }
661 } // end of wxTextCtrl::Remove
662
663 void wxTextCtrl::SetSelection(
664 long lFrom
665 , long lTo
666 )
667 {
668 HWND hWnd = GetHwnd();
669 long lFromChar = lFrom;
670 long lToChar = lTo;
671
672 //
673 // If from and to are both -1, it means (in wxWindows) that all text should
674 // be selected. Translate into Windows convention
675 //
676 if ((lFrom == -1L) && (lTo == -1L))
677 {
678 lFromChar = 0L;
679 lToChar = -1L;
680 }
681 if (m_bIsMLE)
682 ::WinSendMsg(hWnd, MLM_SETSEL, (MPARAM)lFromChar, (MPARAM)lToChar);
683 else
684 ::WinSendMsg(hWnd, EM_SETSEL, MPFROM2SHORT((USHORT)lFromChar, (USHORT)lToChar), (MPARAM)0);
685 } // end of wxTextCtrl::SetSelection
686
687 bool wxTextCtrl::LoadFile(
688 const wxString& rsFile
689 )
690 {
691 if ( wxTextCtrlBase::LoadFile(rsFile) )
692 {
693 //
694 // Update the size limit if needed
695 //
696 AdjustSpaceLimit();
697 return TRUE;
698 }
699 return FALSE;
700 } // end of wxTextCtrl::LoadFile
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( _T("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 HWND hWnd = GetHwnd();
753 long lCharIndex = 0L;
754 long lLen;
755
756 if (m_bIsMLE)
757 {
758 lLen = (long)::WinSendMsg(GetHwnd(), MLM_QUERYLINELENGTH, 0, 0);
759 lCharIndex = ((lLen * lY) + lX);
760 }
761 else
762 lCharIndex = lX;
763 return lCharIndex;
764 } // end of wxTextCtrl::XYToPosition
765
766 bool wxTextCtrl::PositionToXY(
767 long lPos
768 , long* plX
769 , long* plY
770 ) const
771 {
772 HWND hWnd = GetHwnd();
773 long nLineNo = -1;
774 long lCharIndex = 0;
775
776 if (m_bIsMLE)
777 nLineNo = (long)::WinSendMsg(hWnd, MLM_LINEFROMCHAR, (MPARAM)lPos, 0);
778 else
779 nLineNo = 0;
780
781 if (nLineNo == -1)
782 {
783 // no such line
784 return FALSE;
785 }
786
787 //
788 // This gets the char index for the _beginning_ of this line
789 //
790 long lLineWidth;
791
792 if (m_bIsMLE)
793 {
794 lLineWidth = (long)::WinSendMsg(hWnd, MLM_QUERYLINELENGTH, (MPARAM)0, (MPARAM)0);
795 lCharIndex = (nLineNo + 1) * lLineWidth;
796 }
797 else
798 {
799 WNDPARAMS vParams;
800
801 vParams.fsStatus = WPM_CCHTEXT;
802 if (::WinSendMsg( hWnd
803 ,WM_QUERYWINDOWPARAMS
804 ,&vParams
805 ,0
806 ))
807 {
808 lCharIndex = vParams.cchText;
809 }
810 else
811 lCharIndex = 32;
812 }
813
814 if (lCharIndex == -1)
815 {
816 return FALSE;
817 }
818
819 //
820 // The X position must therefore be the difference between pos and charIndex
821 //
822 if (plX)
823 *plX = lPos - lCharIndex;
824 if (plY)
825 *plY = nLineNo;
826
827 return TRUE;
828 } // end of wxTextCtrl::PositionToXY
829
830 void wxTextCtrl::ShowPosition(
831 long lPos
832 )
833 {
834 HWND hWnd = GetHwnd();
835 long lCurrentLineLineNo = 0L;
836
837 // To scroll to a position, we pass the number of lines and characters
838 // to scroll *by*. This means that we need to:
839 // (1) Find the line position of the current line.
840 // (2) Find the line position of pos.
841 // (3) Scroll by (pos - current).
842 // For now, ignore the horizontal scrolling.
843
844 //
845 // Is this where scrolling is relative to - the line containing the caret?
846 // Or is the first visible line??? Try first visible line.
847 //
848 if (m_bIsMLE)
849 {
850 //
851 // In PM this is the actual char position
852 //
853 lCurrentLineLineNo = (long)::WinSendMsg(hWnd, MLM_QUERYFIRSTCHAR, (MPARAM)0, (MPARAM)0);
854
855 //
856 // This will cause a scroll to the selected position
857 //
858 ::WinSendMsg(hWnd, MLM_SETSEL, (MPARAM)lCurrentLineLineNo, (MPARAM)lCurrentLineLineNo);
859 }
860 } // end of wxTextCtrl::ShowPosition
861
862 int wxTextCtrl::GetLineLength(
863 long lLineNo
864 ) const
865 {
866 long lLen = 0L;
867
868 if (m_bIsMLE)
869 lLen = (long)::WinSendMsg(GetHwnd(), MLM_QUERYLINELENGTH, 0, 0);
870 else
871 {
872 WNDPARAMS vParams;
873
874 vParams.fsStatus = WPM_CCHTEXT;
875 if (::WinSendMsg( GetHwnd()
876 ,WM_QUERYWINDOWPARAMS
877 ,&vParams
878 ,0
879 ))
880 {
881 lLen = vParams.cchText;
882 }
883 else
884 lLen = 32;
885 }
886 return lLen;
887 } // end ofwxTextCtrl::GetLineLength
888
889 wxString wxTextCtrl::GetLineText(
890 long lLineNo
891 ) const
892 {
893 long lLen = (long)GetLineLength((long)lLineNo) + 1;
894 wxString sStr;
895 char* zBuf;
896
897 //
898 // There must be at least enough place for the length WORD in the
899 // buffer
900 //
901 lLen += sizeof(WORD);
902 zBuf = new char[lLen];
903 if (m_bIsMLE)
904 {
905 long lIndex;
906 long lBuflen;
907 long lCopied;
908
909 lLen = (long)::WinSendMsg(GetHwnd(), MLM_QUERYLINELENGTH, 0, 0);
910 lIndex = lLen * lLineNo;
911
912 ::WinSendMsg(GetHwnd(), MLM_SETSEL, (MPARAM)lIndex, (MPARAM)lIndex);
913 ::WinSendMsg(GetHwnd(), MLM_SETIMPORTEXPORT, MPFROMP(zBuf), MPFROMSHORT((USHORT)sizeof(zBuf)));
914 lBuflen = (long)::WinSendMsg(GetHwnd(), MLM_QUERYFORMATTEXTLENGTH, MPFROMLONG(lIndex), MPFROMLONG(-1));
915 lCopied = (long)::WinSendMsg(GetHwnd(), MLM_EXPORT, MPFROMP(&lIndex), MPFROMP(&lBuflen));
916 zBuf[lCopied] = '\0';
917 }
918 else
919 {
920 WNDPARAMS vParams;
921
922 vParams.fsStatus = WPM_CCHTEXT;
923 if (::WinSendMsg( GetHwnd()
924 ,WM_QUERYWINDOWPARAMS
925 ,&vParams
926 ,0
927 ))
928 memcpy(zBuf, vParams.pszText, vParams.cchText);
929 zBuf[vParams.cchText] = '\0';
930 }
931 sStr = zBuf;
932 delete [] zBuf;
933 return sStr;
934 } // end of wxTextCtrl::GetLineText
935
936 // ----------------------------------------------------------------------------
937 // Undo/redo
938 // ----------------------------------------------------------------------------
939
940 void wxTextCtrl::Undo()
941 {
942 if (CanUndo())
943 {
944 if (m_bIsMLE)
945 ::WinSendMsg(GetHwnd(), MLM_UNDO, 0, 0);
946 // Simple entryfields cannot be undone
947 }
948 } // end of wxTextCtrl::Undo
949
950 void wxTextCtrl::Redo()
951 {
952 if (CanRedo())
953 {
954 if (m_bIsMLE)
955 ::WinSendMsg(GetHwnd(), MLM_UNDO, 0, 0);
956 // Simple entryfields cannot be undone
957 }
958 } // end of wxTextCtrl::Redo
959
960 bool wxTextCtrl::CanUndo() const
961 {
962 bool bOk;
963
964 if (m_bIsMLE)
965 bOk = (::WinSendMsg(GetHwnd(), MLM_QUERYUNDO, 0, 0) != 0);
966 else
967 bOk = FALSE; // can't undo regular edit fields in PM
968 return bOk;
969 } // end of wxTextCtrl::CanUndo
970
971 bool wxTextCtrl::CanRedo() const
972 {
973 bool bOk;
974
975 if (m_bIsMLE)
976 bOk = (::WinSendMsg(GetHwnd(), MLM_QUERYUNDO, 0, 0) != 0);
977 else
978 bOk = FALSE; // can't undo regular edit fields in PM
979 return bOk;
980 } // end of wxTextCtrl::CanRedo
981
982 // ----------------------------------------------------------------------------
983 // implemenation details
984 // ----------------------------------------------------------------------------
985
986 void wxTextCtrl::Command(
987 wxCommandEvent& rEvent
988 )
989 {
990 SetValue(rEvent.GetString());
991 ProcessCommand (rEvent);
992 } // end of wxTextCtrl::Command
993
994 void wxTextCtrl::OnDropFiles(
995 wxDropFilesEvent& rEvent
996 )
997 {
998 // By default, load the first file into the text window.
999 if (rEvent.GetNumberOfFiles() > 0)
1000 {
1001 LoadFile(rEvent.GetFiles()[0]);
1002 }
1003 } // end of wxTextCtrl::OnDropFiles
1004
1005 WXHBRUSH wxTextCtrl::OnCtlColor(
1006 WXHDC hWxDC
1007 , WXHWND hWnd
1008 , WXUINT uCtlColor
1009 , WXUINT uMessage
1010 , WXWPARAM wParam
1011 , WXLPARAM lParam
1012 )
1013 {
1014 HPS hPS = (HPS)hWxDC;
1015 wxBrush* pBrush = NULL;
1016 wxColour vColBack = GetBackgroundColour();
1017 wxColour vColFore = GetForegroundColour();
1018 wxBrush* pBackgroundBrush = wxTheBrushList->FindOrCreateBrush( GetBackgroundColour()
1019 ,wxSOLID
1020 );
1021
1022 if (m_bUseCtl3D)
1023 {
1024 HBRUSH hBrush = NULLHANDLE;
1025
1026 return hBrush;
1027 }
1028 if (GetParent()->GetTransparentBackground())
1029 ::GpiSetBackMix(hPS, BM_LEAVEALONE);
1030 else
1031 ::GpiSetBackMix(hPS, BM_OVERPAINT);
1032 if (!IsEnabled() && (GetWindowStyle() & wxTE_MULTILINE) == 0)
1033 vColBack = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
1034 ::GpiSetBackColor(hPS, vColBack.GetPixel());
1035 ::GpiSetColor(hPS, vColFore.GetPixel());
1036 return (WXHBRUSH)pBackgroundBrush->GetResourceHandle();
1037 } // end of wxTextCtrl::OnCtlColor
1038
1039 bool wxTextCtrl::OS2ShouldPreProcessMessage(
1040 WXMSG* pMsg
1041 )
1042 {
1043 return wxControl::OS2ShouldPreProcessMessage(pMsg);
1044 } // end of wxTextCtrl::OS2ShouldPreProcessMessage
1045
1046 void wxTextCtrl::OnChar(
1047 wxKeyEvent& rEvent
1048 )
1049 {
1050 switch (rEvent.KeyCode())
1051 {
1052 case WXK_RETURN:
1053 if ( !(m_windowStyle & wxTE_MULTILINE) )
1054 {
1055 wxCommandEvent vEvent(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
1056
1057 vEvent.SetEventObject(this);
1058 if ( GetEventHandler()->ProcessEvent(vEvent))
1059 return;
1060 }
1061 //else: multiline controls need Enter for themselves
1062
1063 break;
1064
1065 case WXK_TAB:
1066 // always produce navigation event - even if we process TAB
1067 // ourselves the fact that we got here means that the user code
1068 // decided to skip processing of this TAB - probably to let it
1069 // do its default job.
1070 //
1071 // NB: Notice that Ctrl-Tab is handled elsewhere and Alt-Tab is
1072 // handled by Windows
1073 {
1074 wxNavigationKeyEvent vEventNav;
1075
1076 vEventNav.SetDirection(!rEvent.ShiftDown());
1077 vEventNav.SetWindowChange(FALSE);
1078 vEventNav.SetEventObject(this);
1079
1080 if ( GetEventHandler()->ProcessEvent(vEventNav) )
1081 return;
1082 }
1083 break;
1084 }
1085 rEvent.Skip();
1086 } // end of wxTextCtrl::OnChar
1087
1088 bool wxTextCtrl::OS2Command(
1089 WXUINT uParam
1090 , WXWORD WXUNUSED(vId)
1091 )
1092 {
1093 switch (uParam)
1094 {
1095 case EN_SETFOCUS:
1096 case EN_KILLFOCUS:
1097 {
1098 wxFocusEvent vEvent( uParam == EN_KILLFOCUS ? wxEVT_KILL_FOCUS
1099 : wxEVT_SET_FOCUS
1100 ,m_windowId
1101 );
1102
1103 vEvent.SetEventObject(this);
1104 GetEventHandler()->ProcessEvent(vEvent);
1105 }
1106 break;
1107
1108 case EN_CHANGE:
1109 {
1110 wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_UPDATED
1111 ,m_windowId
1112 );
1113
1114 InitCommandEvent(vEvent);
1115 vEvent.SetString((char*)GetValue().c_str());
1116 ProcessCommand(vEvent);
1117 }
1118 break;
1119
1120 case EN_OVERFLOW:
1121 //
1122 // The text size limit has been hit - increase it
1123 //
1124 AdjustSpaceLimit();
1125 break;
1126
1127 case EN_SCROLL:
1128 case EN_INSERTMODETOGGLE:
1129 case EN_MEMERROR:
1130 return FALSE;
1131 default:
1132 return FALSE;
1133 }
1134
1135 //
1136 // Processed
1137 //
1138 return TRUE;
1139 } // end of wxTextCtrl::OS2Command
1140
1141 void wxTextCtrl::AdjustSpaceLimit()
1142 {
1143 unsigned int uLen = 0;
1144 unsigned int uLimit = 0;
1145
1146 uLen = ::WinQueryWindowTextLength(GetHwnd());
1147 if (m_bIsMLE)
1148 {
1149 uLimit = (unsigned int)::WinSendMsg( GetHwnd()
1150 ,MLM_QUERYTEXTLIMIT
1151 ,0
1152 ,0
1153 );
1154 }
1155 else
1156 {
1157 ENTRYFDATA Efd;
1158 WNDPARAMS vParams;
1159
1160 vParams.fsStatus = WPM_CBCTLDATA;
1161 vParams.pCtlData = &Efd;
1162 vParams.cbCtlData = sizeof(ENTRYFDATA);
1163
1164 if (::WinSendMsg( GetHwnd()
1165 ,WM_QUERYWINDOWPARAMS
1166 ,&vParams
1167 ,0
1168 ))
1169 uLimit = (unsigned int)Efd.cchEditLimit;
1170 else
1171 uLimit = 32; //PM's default
1172 }
1173 if (uLen >= uLimit)
1174 {
1175 uLimit = uLen + 0x8000; // 32Kb
1176 if (uLimit > 0xffff)
1177 {
1178 uLimit = 0L;
1179 }
1180 if (m_bIsMLE)
1181 ::WinSendMsg(GetHwnd(), MLM_SETTEXTLIMIT, MPFROMLONG(uLimit), 0);
1182 else
1183 ::WinSendMsg(GetHwnd(), EM_SETTEXTLIMIT, MPFROMSHORT(uLimit), 0);
1184 }
1185 } // end of wxTextCtrl::AdjustSpaceLimit
1186
1187 bool wxTextCtrl::AcceptsFocus() const
1188 {
1189 //
1190 // We don't want focus if we can't be edited unless we're a multiline
1191 // control because then it might be still nice to get focus from keyboard
1192 // to be able to scroll it without mouse
1193 //
1194 return (IsEditable() || IsMultiLine()) && wxControl::AcceptsFocus();
1195 } // end of wxTextCtrl::Command
1196
1197 wxSize wxTextCtrl::DoGetBestSize() const
1198 {
1199 int nCx;
1200 int nCy;
1201
1202 wxGetCharSize(GetHWND(), &nCx, &nCy, (wxFont*)&GetFont());
1203
1204 int wText = DEFAULT_ITEM_WIDTH;
1205 int hText = (EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy) * .8);
1206
1207 if (m_windowStyle & wxTE_MULTILINE)
1208 {
1209 hText *= wxMax(GetNumberOfLines(), 5);
1210 }
1211 //else: for single line control everything is ok
1212 return wxSize(wText, hText);
1213 } // end of wxTextCtrl::DoGetBestSize
1214
1215 // ----------------------------------------------------------------------------
1216 // standard handlers for standard edit menu events
1217 // ----------------------------------------------------------------------------
1218
1219 void wxTextCtrl::OnCut(
1220 wxCommandEvent& rEvent
1221 )
1222 {
1223 Cut();
1224 } // end of wxTextCtrl::OnCut
1225
1226 void wxTextCtrl::OnCopy(
1227 wxCommandEvent& rEvent
1228 )
1229 {
1230 Copy();
1231 } // end of wxTextCtrl::OnCopy
1232
1233 void wxTextCtrl::OnPaste(
1234 wxCommandEvent& rEvent
1235 )
1236 {
1237 Paste();
1238 } // end of wxTextCtrl::OnPaste
1239
1240 void wxTextCtrl::OnUndo(
1241 wxCommandEvent& rEvent
1242 )
1243 {
1244 Undo();
1245 } // end of wxTextCtrl::OnUndo
1246
1247 void wxTextCtrl::OnRedo(
1248 wxCommandEvent& rEvent
1249 )
1250 {
1251 Redo();
1252 } // end of wxTextCtrl::OnRedo
1253
1254 void wxTextCtrl::OnDelete(
1255 wxCommandEvent& rEvent
1256 )
1257 {
1258 long lFrom;
1259 long lTo;
1260
1261 GetSelection( &lFrom
1262 ,&lTo
1263 );
1264 if (lFrom != -1 && lTo != -1)
1265 Remove( lFrom
1266 ,lTo
1267 );
1268 } // end of wxTextCtrl::OnDelete
1269
1270 void wxTextCtrl::OnSelectAll(
1271 wxCommandEvent& rEvent
1272 )
1273 {
1274 SetSelection(-1, -1);
1275 } // end of wxTextCtrl::OnSelectAll
1276
1277 void wxTextCtrl::OnUpdateCut(
1278 wxUpdateUIEvent& rEvent
1279 )
1280 {
1281 rEvent.Enable(CanCut());
1282 } // end of wxTextCtrl::OnUpdateCut
1283
1284 void wxTextCtrl::OnUpdateCopy(
1285 wxUpdateUIEvent& rEvent
1286 )
1287 {
1288 rEvent.Enable(CanCopy());
1289 } // end of wxTextCtrl::OnUpdateCopy
1290
1291 void wxTextCtrl::OnUpdatePaste(
1292 wxUpdateUIEvent& rEvent
1293 )
1294 {
1295 rEvent.Enable(CanPaste());
1296 } // end of wxTextCtrl::OnUpdatePaste
1297
1298 void wxTextCtrl::OnUpdateUndo(
1299 wxUpdateUIEvent& rEvent
1300 )
1301 {
1302 rEvent.Enable(CanUndo());
1303 } // end of wxTextCtrl::OnUpdateUndo
1304
1305 void wxTextCtrl::OnUpdateRedo(
1306 wxUpdateUIEvent& rEvent
1307 )
1308 {
1309 rEvent.Enable(CanRedo());
1310 } // end of wxTextCtrl::OnUpdateRedo
1311
1312 void wxTextCtrl::OnUpdateDelete(
1313 wxUpdateUIEvent& rEvent
1314 )
1315 {
1316 long lFrom;
1317 long lTo;
1318
1319 GetSelection( &lFrom
1320 ,&lTo
1321 );
1322 rEvent.Enable( lFrom != -1L && lTo != -1L && lFrom != lTo && IsEditable()) ;
1323 } // end of wxTextCtrl::OnUpdateDelete
1324
1325 void wxTextCtrl::OnUpdateSelectAll(
1326 wxUpdateUIEvent& rEvent
1327 )
1328 {
1329 rEvent.Enable(GetLastPosition() > 0);
1330 } // end of wxTextCtrl::OnUpdateSelectAll
1331
1332 bool wxTextCtrl::SetBackgroundColour(
1333 const wxColour& rColour
1334 )
1335 {
1336 if (m_bIsMLE)
1337 ::WinSendMsg(GetHwnd(), MLM_SETBACKCOLOR, (MPARAM)rColour.GetPixel(), MLE_INDEX);
1338 return TRUE;
1339 } // end of wxTextCtrl::SetBackgroundColour
1340
1341 bool wxTextCtrl::SetForegroundColour(
1342 const wxColour& rColour
1343 )
1344 {
1345 if (m_bIsMLE)
1346 ::WinSendMsg(GetHwnd(), MLM_SETTEXTCOLOR, (MPARAM)rColour.GetPixel(), MLE_INDEX);
1347 return TRUE;
1348 } // end of wxTextCtrl::SetForegroundColour
1349
1350 bool wxTextCtrl::SetStyle(
1351 long lStart
1352 , long lEnd
1353 , const wxTextAttr& rStyle
1354 )
1355 {
1356 HWND hWnd = GetHwnd();
1357
1358 if (lStart > lEnd)
1359 {
1360 long lTmp = lStart;
1361
1362 lStart = lEnd;
1363 lEnd = lTmp;
1364 }
1365
1366 //
1367 // We can only change the format of the selection, so select the range we
1368 // want and restore the old selection later
1369 //
1370 long lStartOld;
1371 long lEndOld;
1372
1373 GetSelection( &lStartOld
1374 ,&lEndOld
1375 );
1376
1377 //
1378 // But do we really have to change the selection?
1379 //
1380 bool bChangeSel = lStart != lStartOld ||
1381 lEnd != lEndOld;
1382
1383 if (bChangeSel)
1384 {
1385 if (m_bIsMLE)
1386 ::WinSendMsg(hWnd, MLM_SETSEL, MPFROM2SHORT((USHORT)lStart, (USHORT)lEnd), 0);
1387 else
1388 ::WinSendMsg(hWnd, EM_SETSEL, MPFROM2SHORT((USHORT)lStart, (USHORT)lEnd), 0);
1389 }
1390
1391 //
1392 // TODO:: finish this part
1393 //
1394 return TRUE;
1395 } // end of wxTextCtrl::SetStyle
1396