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