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