]> git.saurik.com Git - wxWidgets.git/blob - src/os2/textctrl.cpp
paper size, duplex support
[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 ,(PSZ)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 ,(PSZ)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 char* zStr = (char*)sStr.c_str();
333
334 for ( ; *zStr; zStr++ )
335 {
336 //
337 // this will replace \r\n with just \n
338 //
339 if (*zStr == '\n')
340 *zStr = '\0';
341 if (*zStr == '\r')
342 *zStr = '\n';
343 }
344 return sStr;
345 } // end of wxTextCtrl::GetValue
346
347 void wxTextCtrl::DoSetValue(
348 const wxString& rsValue,
349 int flags
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 if ( flags & SetValue_SendEvent )
361 m_bSkipUpdate = true;
362
363 ::WinSetWindowText(GetHwnd(), (PSZ)rsValue.c_str());
364 AdjustSpaceLimit();
365 }
366 } // end of wxTextCtrl::SetValue
367
368 void wxTextCtrl::WriteText(
369 const wxString& rsValue
370 )
371 {
372 if (m_bIsMLE)
373 ::WinSendMsg(GetHwnd(), MLM_INSERT, MPARAM((PCHAR)rsValue.c_str()), MPARAM(0));
374 else
375 ::WinSetWindowText(GetHwnd(), (PSZ)rsValue.c_str());
376 AdjustSpaceLimit();
377 } // end of wxTextCtrl::WriteText
378
379 void wxTextCtrl::AppendText(
380 const wxString& rsText
381 )
382 {
383 SetInsertionPointEnd();
384 WriteText(rsText);
385 } // end of wxTextCtrl::AppendText
386
387 void wxTextCtrl::Clear()
388 {
389 ::WinSetWindowText(GetHwnd(), "");
390 } // end of wxTextCtrl::Clear
391
392 bool wxTextCtrl::EmulateKeyPress(
393 const wxKeyEvent& rEvent
394 )
395 {
396 SetFocus();
397 return(wxTextCtrlBase::EmulateKeyPress(rEvent));
398 } // end of wxTextCtrl::EmulateKeyPress
399
400 // ----------------------------------------------------------------------------
401 // Clipboard operations
402 // ----------------------------------------------------------------------------
403
404 void wxTextCtrl::Copy()
405 {
406 if (CanCopy())
407 {
408 HWND hWnd = GetHwnd();
409 if (m_bIsMLE)
410 ::WinSendMsg(hWnd, MLM_COPY, 0, 0);
411 else
412 ::WinSendMsg(hWnd, EM_COPY, 0, 0);
413 }
414 } // end of wxTextCtrl::Copy
415
416 void wxTextCtrl::Cut()
417 {
418 if (CanCut())
419 {
420 HWND hWnd = GetHwnd();
421
422 if (m_bIsMLE)
423 ::WinSendMsg(hWnd, MLM_CUT, 0, 0);
424 else
425 ::WinSendMsg(hWnd, EM_CUT, 0, 0);
426 }
427 } // end of wxTextCtrl::Cut
428
429 void wxTextCtrl::Paste()
430 {
431 if (CanPaste())
432 {
433 HWND hWnd = GetHwnd();
434
435 ::WinSendMsg(hWnd, EM_PASTE, 0, 0);
436 }
437 } // end of wxTextCtrl::Paste
438
439 bool wxTextCtrl::CanCopy() const
440 {
441 //
442 // Can copy if there's a selection
443 //
444 long lFrom = 0L;
445 long lTo = 0L;
446
447 GetSelection(&lFrom, &lTo);
448 return (lFrom != lTo);
449 } // end of wxTextCtrl::CanCopy
450
451 bool wxTextCtrl::CanCut() const
452 {
453 //
454 // Can cut if there's a selection
455 //
456 long lFrom = 0L;
457 long lTo = 0L;
458
459 GetSelection(&lFrom, &lTo);
460 return (lFrom != lTo);
461 } // end of wxTextCtrl::CanCut
462
463 bool wxTextCtrl::CanPaste() const
464 {
465 bool bIsTextAvailable = false;
466
467 if (!IsEditable())
468 return false;
469
470 //
471 // Check for straight text on clipboard
472 //
473 if (::WinOpenClipbrd(vHabmain))
474 {
475 bIsTextAvailable = (::WinQueryClipbrdData(vHabmain, CF_TEXT) != 0);
476 ::WinCloseClipbrd(vHabmain);
477 }
478 return bIsTextAvailable;
479 } // end of wxTextCtrl::CanPaste
480
481 // ----------------------------------------------------------------------------
482 // Accessors
483 // ----------------------------------------------------------------------------
484
485 void wxTextCtrl::SetEditable(
486 bool bEditable
487 )
488 {
489 HWND hWnd = GetHwnd();
490
491 if (m_bIsMLE)
492 ::WinSendMsg(hWnd, MLM_SETREADONLY, MPFROMLONG(!bEditable), (MPARAM)0);
493 else
494 ::WinSendMsg(hWnd, EM_SETREADONLY, MPFROMLONG(!bEditable), (MPARAM)0);
495 } // end of wxTextCtrl::SetEditable
496
497 void wxTextCtrl::SetInsertionPoint(
498 long lPos
499 )
500 {
501 HWND hWnd = GetHwnd();
502
503 if (m_bIsMLE)
504 ::WinSendMsg(hWnd, MLM_SETSEL, (MPARAM)lPos, (MPARAM)lPos);
505 else
506 ::WinSendMsg(hWnd, EM_SETSEL, MPFROM2SHORT((USHORT)lPos, (USHORT)lPos), (MPARAM)0);
507 } // end of wxTextCtrl::SetInsertionPoint
508
509 void wxTextCtrl::SetInsertionPointEnd()
510 {
511 wxTextPos lPos = GetLastPosition();
512
513 //
514 // We must not do anything if the caret is already there because calling
515 // SetInsertionPoint() thaws the controls if Freeze() had been called even
516 // if it doesn't actually move the caret anywhere and so the simple fact of
517 // doing it results in horrible flicker when appending big amounts of text
518 // to the control in a few chunks (see DoAddText() test in the text sample)
519 //
520 if (GetInsertionPoint() == GetLastPosition())
521 return;
522 SetInsertionPoint(lPos);
523 } // end of wxTextCtrl::SetInsertionPointEnd
524
525 long wxTextCtrl::GetInsertionPoint() const
526 {
527 WXDWORD dwPos = 0L;
528
529 if (m_bIsMLE)
530 dwPos = (WXDWORD)::WinSendMsg(GetHwnd(), MLM_QUERYSEL, (MPARAM)MLFQS_MINSEL, 0);
531 else
532 {
533 dwPos = (WXDWORD)::WinSendMsg(GetHwnd(), EM_QUERYSEL, 0, 0);
534 dwPos = SHORT1FROMMP((MPARAM)dwPos); // the first 16 bit value is the min pos
535 }
536 return (dwPos & 0xFFFF);
537 } // end of wxTextCtrl::GetInsertionPoint
538
539 wxTextPos wxTextCtrl::GetLastPosition() const
540 {
541 HWND hWnd = GetHwnd();
542 long lCharIndex;
543 long lLineLength;
544
545 if (m_bIsMLE)
546 {
547 lCharIndex = 0;
548
549 //
550 // This just gets the total text length. The last will be this value
551 //
552 lLineLength = (long)::WinSendMsg(hWnd, MLM_QUERYTEXTLENGTH, 0, 0);
553 }
554 else
555 {
556 WNDPARAMS vParams;
557
558 lCharIndex = 0;
559 vParams.fsStatus = WPM_CCHTEXT;
560 if (::WinSendMsg( GetHwnd()
561 ,WM_QUERYWINDOWPARAMS
562 ,&vParams
563 ,0
564 ))
565 {
566 lLineLength = (long)vParams.cchText;
567 }
568 else
569 lLineLength = 0;
570 }
571 return(lCharIndex + lLineLength);
572 } // end of wxTextCtrl::GetLastPosition
573
574 // If the return values from and to are the same, there is no
575 // selection.
576 void wxTextCtrl::GetSelection(
577 long* plFrom
578 , long* plTo
579 ) const
580 {
581 WXDWORD dwPos;
582
583 if (m_bIsMLE)
584 dwPos = (WXDWORD)::WinSendMsg(GetHwnd(), MLM_QUERYSEL, (MPARAM)MLFQS_MINSEL, 0);
585 else
586 {
587 dwPos = (WXDWORD)::WinSendMsg(GetHwnd(), EM_QUERYSEL, 0, 0);
588 }
589 *plFrom = SHORT1FROMMP((MPARAM)dwPos); // the first 16 bit value is the min pos
590 *plTo = SHORT2FROMMP((MPARAM)dwPos); // the first 16 bit value is the min pos
591 } // end of wxTextCtrl::GetSelection
592
593 bool wxTextCtrl::IsEditable() const
594 {
595 if (m_bIsMLE)
596 return((bool)LONGFROMMR(::WinSendMsg(GetHwnd(), MLM_QUERYREADONLY, 0, 0)));
597 else
598 return((bool)LONGFROMMR(::WinSendMsg(GetHwnd(), EM_QUERYREADONLY, 0, 0)));
599 } // end of wxTextCtrl::IsEditable
600
601 // ----------------------------------------------------------------------------
602 // Editing
603 // ----------------------------------------------------------------------------
604
605 void wxTextCtrl::Replace( long lFrom,
606 long lTo,
607 const wxString& rsValue )
608 {
609 #if wxUSE_CLIPBOARD
610 HWND hWnd = GetHwnd();
611
612 //
613 // Set selection and remove it
614 //
615 if (m_bIsMLE)
616 {
617 ::WinSendMsg(hWnd, MLM_SETSEL, MPFROM2SHORT((USHORT)lFrom, (USHORT)lTo), 0);
618 ::WinSendMsg(hWnd, MLM_CUT, 0, 0);
619 }
620 else
621 {
622 ::WinSendMsg(hWnd, EM_SETSEL, MPFROM2SHORT((USHORT)lFrom, (USHORT)lTo), 0);
623 ::WinSendMsg(hWnd, EM_CUT, 0, 0);
624 }
625
626 //
627 // Now replace with 'value', by pasting.
628 //
629 wxSetClipboardData(wxDF_TEXT, (wxObject *) (const wxChar *)rsValue, 0, 0);
630
631 // Paste into edit control
632 if (m_bIsMLE)
633 ::WinSendMsg(hWnd, MLM_PASTE, (MPARAM)0, (MPARAM)0);
634 else
635 ::WinSendMsg(hWnd, EM_PASTE, (MPARAM)0, (MPARAM)0);
636 #else
637 wxUnusedVar(lFrom);
638 wxUnusedVar(lTo);
639 wxUnusedVar(rsValue);
640 wxFAIL_MSG("wxTextCtrl::Replace not implemented if wxUSE_CLIPBOARD is 0.");
641 #endif
642 } // end of wxTextCtrl::Replace
643
644 void wxTextCtrl::Remove(
645 long lFrom
646 , long lTo
647 )
648 {
649 HWND hWnd = GetHwnd();
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 wxWidgets) 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::DoLoadFile(
688 const wxString& rsFile,
689 int fileType
690 )
691 {
692 if ( wxTextCtrlBase::DoLoadFile(rsFile, fileType) )
693 {
694 //
695 // Update the size limit if needed
696 //
697 AdjustSpaceLimit();
698 return true;
699 }
700 return false;
701 } // end of wxTextCtrl::DoLoadFile
702
703 bool wxTextCtrl::IsModified() const
704 {
705 bool bRc;
706
707 if (m_bIsMLE)
708 bRc = (bool)LONGFROMMR(::WinSendMsg(GetHwnd(), MLM_QUERYCHANGED, 0, 0));
709 else
710 bRc = (bool)LONGFROMMR(::WinSendMsg(GetHwnd(), EM_QUERYCHANGED, 0, 0));
711 return bRc;
712 } // end of wxTextCtrl::IsModified
713
714 void wxTextCtrl::MarkDirty()
715 {
716 if (m_bIsMLE)
717 ::WinSendMsg(GetHwnd(), MLM_SETCHANGED, MPFROMLONG(TRUE), 0);
718 else
719 // EM controls do not have a SETCHANGED, what can we do??
720 wxFAIL_MSG( _T("not implemented") );
721 }
722
723 //
724 // Makes 'unmodified'
725 //
726 void wxTextCtrl::DiscardEdits()
727 {
728 if (m_bIsMLE)
729 ::WinSendMsg(GetHwnd(), MLM_SETCHANGED, MPFROMLONG(FALSE), 0);
730 else
731 //
732 // EM controls do not have a SETCHANGED but issuing a query should reset it
733 //
734 ::WinSendMsg(GetHwnd(), EM_QUERYCHANGED, 0, 0);
735 } // end of wxTextCtrl::DiscardEdits
736
737 int wxTextCtrl::GetNumberOfLines() const
738 {
739 int nNumLines;
740
741 if (m_bIsMLE)
742 nNumLines = (int)::WinSendMsg(GetHwnd(), MLM_QUERYLINECOUNT, 0, 0);
743 else
744 nNumLines = 1;
745 return nNumLines;
746 } // end of wxTextCtrl::GetNumberOfLines
747
748 long wxTextCtrl::XYToPosition(
749 long lX
750 , long lY
751 ) const
752 {
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( long WXUNUSED(lPos) )
831 {
832 HWND hWnd = GetHwnd();
833 long lCurrentLineLineNo = 0L;
834
835 // To scroll to a position, we pass the number of lines and characters
836 // to scroll *by*. This means that we need to:
837 // (1) Find the line position of the current line.
838 // (2) Find the line position of pos.
839 // (3) Scroll by (pos - current).
840 // For now, ignore the horizontal scrolling.
841
842 //
843 // Is this where scrolling is relative to - the line containing the caret?
844 // Or is the first visible line??? Try first visible line.
845 //
846 if (m_bIsMLE)
847 {
848 //
849 // In PM this is the actual char position
850 //
851 lCurrentLineLineNo = (long)::WinSendMsg(hWnd, MLM_QUERYFIRSTCHAR, (MPARAM)0, (MPARAM)0);
852
853 //
854 // This will cause a scroll to the selected position
855 //
856 ::WinSendMsg(hWnd, MLM_SETSEL, (MPARAM)lCurrentLineLineNo, (MPARAM)lCurrentLineLineNo);
857 }
858 } // end of wxTextCtrl::ShowPosition
859
860 int wxTextCtrl::GetLineLength( long WXUNUSED(lLineNo) ) const
861 {
862 long lLen = 0L;
863
864 if (m_bIsMLE)
865 {
866 lLen = (long)::WinSendMsg(GetHwnd(), MLM_QUERYLINELENGTH, 0, 0);
867 }
868 else
869 {
870 WNDPARAMS vParams;
871
872 vParams.fsStatus = WPM_CCHTEXT;
873 if (::WinSendMsg( GetHwnd()
874 ,WM_QUERYWINDOWPARAMS
875 ,&vParams
876 ,0
877 ))
878 {
879 lLen = vParams.cchText;
880 }
881 else
882 lLen = 32;
883 }
884 return lLen;
885 } // end ofwxTextCtrl::GetLineLength
886
887 wxString wxTextCtrl::GetLineText(
888 long lLineNo
889 ) const
890 {
891 long lLen = (long)GetLineLength((long)lLineNo) + 1;
892 wxString sStr;
893 wxChar* zBuf;
894
895 //
896 // There must be at least enough place for the length WORD in the
897 // buffer
898 //
899 lLen += sizeof(WORD);
900 zBuf = new wxChar[lLen];
901 if (m_bIsMLE)
902 {
903 long lIndex;
904 long lBuflen;
905 long lCopied;
906
907 lLen = (long)::WinSendMsg(GetHwnd(), MLM_QUERYLINELENGTH, 0, 0);
908 lIndex = lLen * lLineNo;
909
910 ::WinSendMsg(GetHwnd(), MLM_SETSEL, (MPARAM)lIndex, (MPARAM)lIndex);
911 ::WinSendMsg(GetHwnd(), MLM_SETIMPORTEXPORT, MPFROMP(zBuf), MPFROMSHORT((USHORT)WXSIZEOF(zBuf)));
912 lBuflen = (long)::WinSendMsg(GetHwnd(), MLM_QUERYFORMATTEXTLENGTH, MPFROMLONG(lIndex), MPFROMLONG(-1));
913 lCopied = (long)::WinSendMsg(GetHwnd(), MLM_EXPORT, MPFROMP(&lIndex), MPFROMP(&lBuflen));
914 zBuf[lCopied] = '\0';
915 }
916 else
917 {
918 WNDPARAMS vParams;
919
920 vParams.fsStatus = WPM_CCHTEXT;
921 if (::WinSendMsg( GetHwnd()
922 ,WM_QUERYWINDOWPARAMS
923 ,&vParams
924 ,0
925 ))
926 memcpy((char*)zBuf, vParams.pszText, vParams.cchText);
927 zBuf[vParams.cchText] = '\0';
928 }
929 sStr = zBuf;
930 delete [] zBuf;
931 return sStr;
932 } // end of wxTextCtrl::GetLineText
933
934 // ----------------------------------------------------------------------------
935 // Undo/redo
936 // ----------------------------------------------------------------------------
937
938 void wxTextCtrl::Undo()
939 {
940 if (CanUndo())
941 {
942 if (m_bIsMLE)
943 ::WinSendMsg(GetHwnd(), MLM_UNDO, 0, 0);
944 // Simple entryfields cannot be undone
945 }
946 } // end of wxTextCtrl::Undo
947
948 void wxTextCtrl::Redo()
949 {
950 if (CanRedo())
951 {
952 if (m_bIsMLE)
953 ::WinSendMsg(GetHwnd(), MLM_UNDO, 0, 0);
954 // Simple entryfields cannot be undone
955 }
956 } // end of wxTextCtrl::Redo
957
958 bool wxTextCtrl::CanUndo() const
959 {
960 bool bOk;
961
962 if (m_bIsMLE)
963 bOk = (::WinSendMsg(GetHwnd(), MLM_QUERYUNDO, 0, 0) != 0);
964 else
965 bOk = false; // can't undo regular edit fields in PM
966 return bOk;
967 } // end of wxTextCtrl::CanUndo
968
969 bool wxTextCtrl::CanRedo() const
970 {
971 bool bOk;
972
973 if (m_bIsMLE)
974 bOk = (::WinSendMsg(GetHwnd(), MLM_QUERYUNDO, 0, 0) != 0);
975 else
976 bOk = false; // can't undo regular edit fields in PM
977 return bOk;
978 } // end of wxTextCtrl::CanRedo
979
980 // ----------------------------------------------------------------------------
981 // implemenation details
982 // ----------------------------------------------------------------------------
983
984 void wxTextCtrl::Command(
985 wxCommandEvent& rEvent
986 )
987 {
988 SetValue(rEvent.GetString());
989 ProcessCommand (rEvent);
990 } // end of wxTextCtrl::Command
991
992 void wxTextCtrl::OnDropFiles(
993 wxDropFilesEvent& rEvent
994 )
995 {
996 // By default, load the first file into the text window.
997 if (rEvent.GetNumberOfFiles() > 0)
998 {
999 LoadFile(rEvent.GetFiles()[0]);
1000 }
1001 } // end of wxTextCtrl::OnDropFiles
1002
1003 WXHBRUSH wxTextCtrl::OnCtlColor( WXHDC hWxDC,
1004 WXHWND WXUNUSED(hWnd),
1005 WXUINT WXUNUSED(uCtlColor),
1006 WXUINT WXUNUSED(uMessage),
1007 WXWPARAM WXUNUSED(wParam),
1008 WXLPARAM WXUNUSED(lParam) )
1009 {
1010 HPS hPS = (HPS)hWxDC;
1011 wxColour vColBack = GetBackgroundColour();
1012 wxColour vColFore = GetForegroundColour();
1013 wxBrush* pBackgroundBrush = wxTheBrushList->FindOrCreateBrush( vColBack, wxSOLID );
1014
1015 if (m_bUseCtl3D)
1016 {
1017 HBRUSH hBrush = NULLHANDLE;
1018
1019 return hBrush;
1020 }
1021 if (GetParent()->GetTransparentBackground())
1022 ::GpiSetBackMix(hPS, BM_LEAVEALONE);
1023 else
1024 ::GpiSetBackMix(hPS, BM_OVERPAINT);
1025 if (!IsEnabled() && (GetWindowStyle() & wxTE_MULTILINE) == 0)
1026 vColBack = wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE);
1027 ::GpiSetBackColor(hPS, vColBack.GetPixel());
1028 ::GpiSetColor(hPS, vColFore.GetPixel());
1029 return (WXHBRUSH)pBackgroundBrush->GetResourceHandle();
1030 } // end of wxTextCtrl::OnCtlColor
1031
1032 bool wxTextCtrl::OS2ShouldPreProcessMessage(
1033 WXMSG* pMsg
1034 )
1035 {
1036 return wxControl::OS2ShouldPreProcessMessage(pMsg);
1037 } // end of wxTextCtrl::OS2ShouldPreProcessMessage
1038
1039 void wxTextCtrl::OnChar(
1040 wxKeyEvent& rEvent
1041 )
1042 {
1043 switch (rEvent.GetKeyCode())
1044 {
1045 case WXK_RETURN:
1046 if ( !(m_windowStyle & wxTE_MULTILINE) )
1047 {
1048 wxCommandEvent vEvent(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
1049
1050 vEvent.SetEventObject(this);
1051 if ( GetEventHandler()->ProcessEvent(vEvent))
1052 return;
1053 }
1054 //else: multiline controls need Enter for themselves
1055
1056 break;
1057
1058 case WXK_TAB:
1059 // always produce navigation event - even if we process TAB
1060 // ourselves the fact that we got here means that the user code
1061 // decided to skip processing of this TAB - probably to let it
1062 // do its default job.
1063 //
1064 // NB: Notice that Ctrl-Tab is handled elsewhere and Alt-Tab is
1065 // handled by Windows
1066 {
1067 wxNavigationKeyEvent vEventNav;
1068
1069 vEventNav.SetDirection(!rEvent.ShiftDown());
1070 vEventNav.SetWindowChange(false);
1071 vEventNav.SetEventObject(this);
1072
1073 if ( GetEventHandler()->ProcessEvent(vEventNav) )
1074 return;
1075 }
1076 break;
1077 }
1078 rEvent.Skip();
1079 } // end of wxTextCtrl::OnChar
1080
1081 bool wxTextCtrl::OS2Command(
1082 WXUINT uParam
1083 , WXWORD WXUNUSED(vId)
1084 )
1085 {
1086 switch (uParam)
1087 {
1088 case EN_SETFOCUS:
1089 case EN_KILLFOCUS:
1090 {
1091 wxFocusEvent vEvent( uParam == EN_KILLFOCUS ? wxEVT_KILL_FOCUS
1092 : wxEVT_SET_FOCUS
1093 ,m_windowId
1094 );
1095
1096 vEvent.SetEventObject(this);
1097 GetEventHandler()->ProcessEvent(vEvent);
1098 }
1099 break;
1100
1101 case EN_CHANGE:
1102 {
1103 if (m_bSkipUpdate)
1104 {
1105 m_bSkipUpdate = false;
1106 break;
1107 }
1108
1109 wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_UPDATED
1110 ,m_windowId
1111 );
1112
1113 InitCommandEvent(vEvent);
1114 ProcessCommand(vEvent);
1115 }
1116 break;
1117
1118 case EN_OVERFLOW:
1119 //
1120 // The text size limit has been hit - increase it
1121 //
1122 AdjustSpaceLimit();
1123 break;
1124
1125 case EN_SCROLL:
1126 case EN_INSERTMODETOGGLE:
1127 case EN_MEMERROR:
1128 return false;
1129 default:
1130 return false;
1131 }
1132
1133 //
1134 // Processed
1135 //
1136 return true;
1137 } // end of wxTextCtrl::OS2Command
1138
1139 void wxTextCtrl::AdjustSpaceLimit()
1140 {
1141 unsigned int uLen = 0;
1142 unsigned int uLimit = 0;
1143
1144 uLen = ::WinQueryWindowTextLength(GetHwnd());
1145 if (m_bIsMLE)
1146 {
1147 uLimit = (unsigned int)::WinSendMsg( GetHwnd()
1148 ,MLM_QUERYTEXTLIMIT
1149 ,0
1150 ,0
1151 );
1152 }
1153 else
1154 {
1155 ENTRYFDATA Efd;
1156 WNDPARAMS vParams;
1157
1158 vParams.fsStatus = WPM_CBCTLDATA;
1159 vParams.pCtlData = &Efd;
1160 vParams.cbCtlData = sizeof(ENTRYFDATA);
1161
1162 if (::WinSendMsg( GetHwnd()
1163 ,WM_QUERYWINDOWPARAMS
1164 ,&vParams
1165 ,0
1166 ))
1167 uLimit = (unsigned int)Efd.cchEditLimit;
1168 else
1169 uLimit = 32; //PM's default
1170 }
1171 if (uLen >= uLimit)
1172 {
1173 uLimit = uLen + 0x8000; // 32Kb
1174 if (uLimit > 0xffff)
1175 {
1176 uLimit = 0L;
1177 }
1178 if (m_bIsMLE)
1179 ::WinSendMsg(GetHwnd(), MLM_SETTEXTLIMIT, MPFROMLONG(uLimit), 0);
1180 else
1181 ::WinSendMsg(GetHwnd(), EM_SETTEXTLIMIT, MPFROMSHORT(uLimit), 0);
1182 }
1183 } // end of wxTextCtrl::AdjustSpaceLimit
1184
1185 bool wxTextCtrl::AcceptsFocus() const
1186 {
1187 //
1188 // We don't want focus if we can't be edited unless we're a multiline
1189 // control because then it might be still nice to get focus from keyboard
1190 // to be able to scroll it without mouse
1191 //
1192 return (IsEditable() || IsMultiLine()) && wxControl::AcceptsFocus();
1193 } // end of wxTextCtrl::Command
1194
1195 wxSize wxTextCtrl::DoGetBestSize() const
1196 {
1197 int nCx;
1198 int nCy;
1199 wxFont vFont = (wxFont)GetFont();
1200
1201 wxGetCharSize(GetHWND(), &nCx, &nCy, &vFont);
1202
1203 int wText = DEFAULT_ITEM_WIDTH;
1204 int hText = (int)(EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy) * .8);
1205
1206 if (m_windowStyle & wxTE_MULTILINE)
1207 {
1208 hText *= wxMax(GetNumberOfLines(), 5);
1209 }
1210 //else: for single line control everything is ok
1211 return wxSize(wText, hText);
1212 } // end of wxTextCtrl::DoGetBestSize
1213
1214 // ----------------------------------------------------------------------------
1215 // standard handlers for standard edit menu events
1216 // ----------------------------------------------------------------------------
1217
1218 void wxTextCtrl::OnCut( wxCommandEvent& WXUNUSED(rEvent) )
1219 {
1220 Cut();
1221 } // end of wxTextCtrl::OnCut
1222
1223 void wxTextCtrl::OnCopy( wxCommandEvent& WXUNUSED(rEvent) )
1224 {
1225 Copy();
1226 } // end of wxTextCtrl::OnCopy
1227
1228 void wxTextCtrl::OnPaste( wxCommandEvent& WXUNUSED(rEvent) )
1229 {
1230 Paste();
1231 } // end of wxTextCtrl::OnPaste
1232
1233 void wxTextCtrl::OnUndo( wxCommandEvent& WXUNUSED(rEvent) )
1234 {
1235 Undo();
1236 } // end of wxTextCtrl::OnUndo
1237
1238 void wxTextCtrl::OnRedo( wxCommandEvent& WXUNUSED(rEvent) )
1239 {
1240 Redo();
1241 } // end of wxTextCtrl::OnRedo
1242
1243 void wxTextCtrl::OnDelete( wxCommandEvent& WXUNUSED(rEvent) )
1244 {
1245 long lFrom, lTo;
1246
1247 GetSelection( &lFrom, &lTo );
1248
1249 if (lFrom != -1 && lTo != -1)
1250 Remove( lFrom, lTo );
1251 } // end of wxTextCtrl::OnDelete
1252
1253 void wxTextCtrl::OnSelectAll( wxCommandEvent& WXUNUSED(rEvent) )
1254 {
1255 SetSelection(-1, -1);
1256 } // end of wxTextCtrl::OnSelectAll
1257
1258 void wxTextCtrl::OnUpdateCut( wxUpdateUIEvent& rEvent )
1259 {
1260 rEvent.Enable(CanCut());
1261 } // end of wxTextCtrl::OnUpdateCut
1262
1263 void wxTextCtrl::OnUpdateCopy( wxUpdateUIEvent& rEvent )
1264 {
1265 rEvent.Enable(CanCopy());
1266 } // end of wxTextCtrl::OnUpdateCopy
1267
1268 void wxTextCtrl::OnUpdatePaste( wxUpdateUIEvent& rEvent )
1269 {
1270 rEvent.Enable(CanPaste());
1271 } // end of wxTextCtrl::OnUpdatePaste
1272
1273 void wxTextCtrl::OnUpdateUndo( wxUpdateUIEvent& rEvent )
1274 {
1275 rEvent.Enable(CanUndo());
1276 } // end of wxTextCtrl::OnUpdateUndo
1277
1278 void wxTextCtrl::OnUpdateRedo( wxUpdateUIEvent& rEvent )
1279 {
1280 rEvent.Enable(CanRedo());
1281 } // end of wxTextCtrl::OnUpdateRedo
1282
1283 void wxTextCtrl::OnUpdateDelete( wxUpdateUIEvent& rEvent )
1284 {
1285 long lFrom, lTo;
1286
1287 GetSelection( &lFrom, &lTo );
1288 rEvent.Enable( lFrom != -1L && lTo != -1L && lFrom != lTo && IsEditable()) ;
1289 } // end of wxTextCtrl::OnUpdateDelete
1290
1291 void wxTextCtrl::OnUpdateSelectAll( wxUpdateUIEvent& rEvent )
1292 {
1293 rEvent.Enable(GetLastPosition() > 0);
1294 } // end of wxTextCtrl::OnUpdateSelectAll
1295
1296 bool wxTextCtrl::SetBackgroundColour( const wxColour& rColour )
1297 {
1298 if (m_bIsMLE)
1299 ::WinSendMsg(GetHwnd(), MLM_SETBACKCOLOR, (MPARAM)rColour.GetPixel(), MLE_INDEX);
1300 return true;
1301 } // end of wxTextCtrl::SetBackgroundColour
1302
1303 bool wxTextCtrl::SetForegroundColour( const wxColour& rColour )
1304 {
1305 if (m_bIsMLE)
1306 ::WinSendMsg(GetHwnd(), MLM_SETTEXTCOLOR, (MPARAM)rColour.GetPixel(), MLE_INDEX);
1307 return true;
1308 } // end of wxTextCtrl::SetForegroundColour
1309
1310 bool wxTextCtrl::SetStyle( long lStart,
1311 long lEnd,
1312 const wxTextAttr& WXUNUSED(rStyle) )
1313 {
1314 HWND hWnd = GetHwnd();
1315
1316 if (lStart > lEnd)
1317 {
1318 long lTmp = lStart;
1319
1320 lStart = lEnd;
1321 lEnd = lTmp;
1322 }
1323
1324 //
1325 // We can only change the format of the selection, so select the range we
1326 // want and restore the old selection later
1327 //
1328 long lStartOld, lEndOld;
1329
1330 GetSelection( &lStartOld, &lEndOld );
1331
1332 //
1333 // But do we really have to change the selection?
1334 //
1335 bool bChangeSel = lStart != lStartOld ||
1336 lEnd != lEndOld;
1337
1338 if (bChangeSel)
1339 {
1340 if (m_bIsMLE)
1341 ::WinSendMsg(hWnd, MLM_SETSEL, MPFROM2SHORT((USHORT)lStart, (USHORT)lEnd), 0);
1342 else
1343 ::WinSendMsg(hWnd, EM_SETSEL, MPFROM2SHORT((USHORT)lStart, (USHORT)lEnd), 0);
1344 }
1345
1346 //
1347 // TODO:: finish this part
1348 //
1349 return true;
1350 } // end of wxTextCtrl::SetStyle