Positioning fixes to compsate for wxWindow's use of the MS backwards standard.
[wxWidgets.git] / src / os2 / textctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: textctrl.cpp
3 // Purpose: wxTextCtrl
4 // Author: David Webster
5 // Modified by:
6 // Created: 10/17/99
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ----------------------------------------------------------------------------
13 // headers
14 // ----------------------------------------------------------------------------
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifndef WX_PRECOMP
20 #include "wx/textctrl.h"
21 #include "wx/settings.h"
22 #include "wx/brush.h"
23 #include "wx/utils.h"
24 #include "wx/log.h"
25 #endif
26
27 #if wxUSE_CLIPBOARD
28 #include "wx/app.h"
29 #include "wx/clipbrd.h"
30 #endif
31
32 #include "wx/textfile.h"
33
34 #include "wx/os2/private.h"
35
36 #include <string.h>
37 #include <stdlib.h>
38 #include <sys/types.h>
39
40 #if wxUSE_IOSTREAMH
41 # include <fstream.h>
42 #else
43 # include <fstream>
44 #endif
45
46
47 // ----------------------------------------------------------------------------
48 // event tables and other macros
49 // ----------------------------------------------------------------------------
50
51 IMPLEMENT_DYNAMIC_CLASS(wxTextCtrl, wxControl)
52
53 BEGIN_EVENT_TABLE(wxTextCtrl, wxControl)
54 EVT_CHAR(wxTextCtrl::OnChar)
55 EVT_DROP_FILES(wxTextCtrl::OnDropFiles)
56
57 EVT_MENU(wxID_CUT, wxTextCtrl::OnCut)
58 EVT_MENU(wxID_COPY, wxTextCtrl::OnCopy)
59 EVT_MENU(wxID_PASTE, wxTextCtrl::OnPaste)
60 EVT_MENU(wxID_UNDO, wxTextCtrl::OnUndo)
61 EVT_MENU(wxID_REDO, wxTextCtrl::OnRedo)
62
63 EVT_UPDATE_UI(wxID_CUT, wxTextCtrl::OnUpdateCut)
64 EVT_UPDATE_UI(wxID_COPY, wxTextCtrl::OnUpdateCopy)
65 EVT_UPDATE_UI(wxID_PASTE, wxTextCtrl::OnUpdatePaste)
66 EVT_UPDATE_UI(wxID_UNDO, wxTextCtrl::OnUpdateUndo)
67 EVT_UPDATE_UI(wxID_REDO, wxTextCtrl::OnUpdateRedo)
68 END_EVENT_TABLE()
69
70
71 // ============================================================================
72 // implementation
73 // ============================================================================
74
75 // ----------------------------------------------------------------------------
76 // creation
77 // ----------------------------------------------------------------------------
78
79 wxTextCtrl::wxTextCtrl()
80 {
81 }
82
83 bool wxTextCtrl::Create(
84 wxWindow* pParent
85 , wxWindowID vId
86 , const wxString& rsValue
87 , const wxPoint& rPos
88 , const wxSize& rSize
89 , long lStyle
90 #if wxUSE_VALIDATORS
91 , const wxValidator& rValidator
92 #endif
93 , const wxString& rsName
94 )
95 {
96 //
97 // Base initialization
98 //
99 if ( !CreateBase( pParent
100 ,vId
101 ,rPos
102 ,rSize
103 ,lStyle
104 #if wxUSE_VALIDATORS
105 ,rValidator
106 #endif
107 ,rsName
108 ))
109 return FALSE;
110
111 wxPoint vPos = rPos; // The OS/2 position
112
113 if (pParent )
114 {
115 pParent->AddChild(this);
116 //
117 // OS2 uses normal coordinates, no bassackwards Windows ones
118 //
119 vPos.y = pParent->GetSize().y - (vPos.y + rSize.y);
120 }
121 else
122 {
123 RECTL vRect;
124
125 ::WinQueryWindowRect(HWND_DESKTOP, &vRect);
126 vPos.y = vRect.yTop - (vPos.y + rSize.y);
127 }
128
129 m_windowStyle = lStyle;
130
131 long lSstyle = WS_VISIBLE | WS_TABSTOP;
132
133 //
134 // Single and multiline edit fields are two different controls in PM
135 //
136 if ( m_windowStyle & wxTE_MULTILINE )
137 {
138 m_bIsMLE = TRUE;
139 m_windowStyle |= wxTE_PROCESS_ENTER;
140
141 if ((m_windowStyle & wxTE_NO_VSCROLL) == 0)
142 lSstyle |= MLS_VSCROLL;
143 if (m_windowStyle & wxHSCROLL)
144 lSstyle |= MLS_HSCROLL;
145 if (m_windowStyle & wxTE_READONLY)
146 lSstyle |= MLS_READONLY;
147 }
148 else
149 {
150 lSstyle |= ES_LEFT;
151
152 if (m_windowStyle & wxHSCROLL)
153 lSstyle |= ES_AUTOSCROLL;
154 if (m_windowStyle & wxTE_READONLY)
155 lSstyle |= ES_READONLY;
156 if (m_windowStyle & wxTE_PASSWORD) // hidden input
157 lSstyle |= ES_UNREADABLE;
158 }
159 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)vPos.x // X pos of origin
166 ,(LONG)vPos.y // Y pos of origin
167 ,(LONG)rSize.x // field width
168 ,(LONG)rSize.y // 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)vPos.x // X pos of origin
183 ,(LONG)vPos.y // Y pos of origin
184 ,(LONG)rSize.x // field width
185 ,(LONG)rSize.y // 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& vFontParent = pParent->GetFont();
205
206 if (vFontParent.Ok())
207 {
208 SetFont(vFontParent);
209 }
210 else
211 {
212 SetFont(wxSystemSettings::GetSystemFont(wxSYS_SYSTEM_FONT));
213 }
214 if (!rsValue.IsEmpty())
215 {
216 SetValue(rsValue);
217 }
218 SetupColours();
219 SetSize( rPos.x
220 ,rPos.y
221 ,rSize.x
222 ,rSize.y
223 );
224 return TRUE;
225 } // end of wxTextCtrl::Create
226
227 //
228 // Make sure the window style (etc.) reflects the HWND style (roughly)
229 //
230 void wxTextCtrl::AdoptAttributesFromHWND()
231 {
232 HWND hWnd = GetHwnd();
233 LONG lStyle = ::WinQueryWindowULong(hWnd, QWL_STYLE);
234
235 wxWindow::AdoptAttributesFromHWND();
236
237 if (m_bIsMLE)
238 {
239 m_windowStyle |= wxTE_MULTILINE;
240 if (lStyle & MLS_READONLY)
241 m_windowStyle |= wxTE_READONLY;
242 }
243 else
244 {
245 if (lStyle & ES_UNREADABLE)
246 m_windowStyle |= wxTE_PASSWORD;
247 if (lStyle & ES_READONLY)
248 m_windowStyle |= wxTE_READONLY;
249 }
250 } // end of wxTextCtrl::AdoptAttributesFromHWND
251
252 void wxTextCtrl::SetupColours()
253 {
254 wxColour vBkgndColour;
255
256 vBkgndColour = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW);
257 SetBackgroundColour(vBkgndColour);
258 SetForegroundColour(GetParent()->GetForegroundColour());
259 } // end of wxTextCtrl::SetupColours
260
261 // ----------------------------------------------------------------------------
262 // set/get the controls text
263 // ----------------------------------------------------------------------------
264
265 wxString wxTextCtrl::GetValue() const
266 {
267 wxString sStr = wxGetWindowText(GetHWND());
268 char* zStr = (char*)sStr.c_str();
269
270 for ( ; *zStr; zStr++ )
271 {
272 //
273 // this will replace \r\n with just \n
274 //
275 if (*zStr == '\n')
276 *zStr = '\0';
277 if (*zStr == '\r')
278 *zStr = '\n';
279 }
280 sStr = zStr;
281 return sStr;
282 } // end of wxTextCtrl::GetValue
283
284 void wxTextCtrl::SetValue(
285 const wxString& rsValue
286 )
287 {
288 //
289 // If the text is long enough, it's faster to just set it instead of first
290 // comparing it with the old one (chances are that it will be different
291 // anyhow, this comparison is there to avoid flicker for small single-line
292 // edit controls mostly)
293 //
294 if ((rsValue.length() > 0x400) || (rsValue != GetValue()))
295 {
296 ::WinSetWindowText(GetHwnd(), rsValue.c_str());
297 AdjustSpaceLimit();
298 }
299 } // end of wxTextCtrl::SetValue
300
301 void wxTextCtrl::WriteText(
302 const wxString& rsValue
303 )
304 {
305 ::WinSetWindowText(GetHwnd(), rsValue.c_str());
306 AdjustSpaceLimit();
307 } // end of wxTextCtrl::WriteText
308
309 void wxTextCtrl::AppendText(
310 const wxString& rsText
311 )
312 {
313 SetInsertionPointEnd();
314 WriteText(rsText);
315 } // end of wxTextCtrl::AppendText
316
317 void wxTextCtrl::Clear()
318 {
319 ::WinSetWindowText(GetHwnd(), "");
320 } // end of wxTextCtrl::Clear
321
322 // ----------------------------------------------------------------------------
323 // Clipboard operations
324 // ----------------------------------------------------------------------------
325
326 void wxTextCtrl::Copy()
327 {
328 if (CanCopy())
329 {
330 HWND hWnd = GetHwnd();
331 if (m_bIsMLE)
332 ::WinSendMsg(hWnd, MLM_COPY, 0, 0);
333 else
334 ::WinSendMsg(hWnd, EM_COPY, 0, 0);
335 }
336 } // end of wxTextCtrl::Copy
337
338 void wxTextCtrl::Cut()
339 {
340 if (CanCut())
341 {
342 HWND hWnd = GetHwnd();
343
344 if (m_bIsMLE)
345 ::WinSendMsg(hWnd, MLM_CUT, 0, 0);
346 else
347 ::WinSendMsg(hWnd, EM_CUT, 0, 0);
348 }
349 } // end of wxTextCtrl::Cut
350
351 void wxTextCtrl::Paste()
352 {
353 if (CanPaste())
354 {
355 HWND hWnd = GetHwnd();
356
357 ::WinSendMsg(hWnd, EM_PASTE, 0, 0);
358 }
359 } // end of wxTextCtrl::Paste
360
361 bool wxTextCtrl::CanCopy() const
362 {
363 //
364 // Can copy if there's a selection
365 //
366 long lFrom = 0L;
367 long lTo = 0L;
368
369 GetSelection(&lFrom, &lTo);
370 return (lFrom != lTo);
371 } // end of wxTextCtrl::CanCopy
372
373 bool wxTextCtrl::CanCut() const
374 {
375 //
376 // Can cut if there's a selection
377 //
378 long lFrom = 0L;
379 long lTo = 0L;
380
381 GetSelection(&lFrom, &lTo);
382 return (lFrom != lTo);
383 } // end of wxTextCtrl::CanCut
384
385 bool wxTextCtrl::CanPaste() const
386 {
387 bool bIsTextAvailable = FALSE;
388
389 if (!IsEditable())
390 return FALSE;
391
392 //
393 // Check for straight text on clipboard
394 //
395 if (::WinOpenClipbrd(vHabmain))
396 {
397 bIsTextAvailable = (::WinQueryClipbrdData(vHabmain, CF_TEXT) != 0);
398 ::WinCloseClipbrd(vHabmain);
399 }
400 return bIsTextAvailable;
401 } // end of wxTextCtrl::CanPaste
402
403 // ----------------------------------------------------------------------------
404 // Accessors
405 // ----------------------------------------------------------------------------
406
407 void wxTextCtrl::SetEditable(
408 bool bEditable
409 )
410 {
411 HWND hWnd = GetHwnd();
412
413 if (m_bIsMLE)
414 ::WinSendMsg(hWnd, MLM_SETREADONLY, MPFROMLONG(!bEditable), (MPARAM)0);
415 else
416 ::WinSendMsg(hWnd, EM_SETREADONLY, MPFROMLONG(!bEditable), (MPARAM)0);
417 } // end of wxTextCtrl::SetEditable
418
419 void wxTextCtrl::SetInsertionPoint(
420 long lPos
421 )
422 {
423 HWND hWnd = GetHwnd();
424
425 if (m_bIsMLE)
426 ::WinSendMsg(hWnd, MLM_SETSEL, (MPARAM)lPos, (MPARAM)lPos);
427 else
428 ::WinSendMsg(hWnd, EM_SETSEL, MPFROM2SHORT((USHORT)lPos, (USHORT)lPos), (MPARAM)0);
429 } // end of wxTextCtrl::SetInsertionPoint
430
431 void wxTextCtrl::SetInsertionPointEnd()
432 {
433 long lPos = GetLastPosition();
434
435 SetInsertionPoint(lPos);
436 } // end of wxTextCtrl::SetInsertionPointEnd
437
438 long wxTextCtrl::GetInsertionPoint() const
439 {
440 WXDWORD dwPos = 0L;
441
442 if (m_bIsMLE)
443 dwPos = (WXDWORD)::WinSendMsg(GetHwnd(), MLM_QUERYSEL, (MPARAM)MLFQS_MINSEL, 0);
444 else
445 {
446 dwPos = (WXDWORD)::WinSendMsg(GetHwnd(), EM_QUERYSEL, 0, 0);
447 dwPos = SHORT1FROMMP((MPARAM)dwPos); // the first 16 bit value is the min pos
448 }
449 return (dwPos & 0xFFFF);
450 } // end of wxTextCtrl::GetInsertionPoint
451
452 long wxTextCtrl::GetLastPosition() const
453 {
454 HWND hWnd = GetHwnd();
455 long lCharIndex;
456 long lLineLength;
457
458 if (m_bIsMLE)
459 {
460 lCharIndex = 0;
461
462 //
463 // This just gets the total text length. The last will be this value
464 //
465 lLineLength = (long)::WinSendMsg(hWnd, MLM_QUERYTEXTLENGTH, 0, 0);
466 }
467 else
468 {
469 WNDPARAMS vParams;
470
471 lCharIndex = 0;
472 vParams.fsStatus = WPM_CCHTEXT;
473 if (::WinSendMsg( GetHwnd()
474 ,WM_QUERYWINDOWPARAMS
475 ,&vParams
476 ,0
477 ))
478 {
479 lLineLength = (long)vParams.cchText;
480 }
481 else
482 lLineLength = 0;
483 }
484 return(lCharIndex + lLineLength);
485 } // end of wxTextCtrl::GetLastPosition
486
487 // If the return values from and to are the same, there is no
488 // selection.
489 void wxTextCtrl::GetSelection(
490 long* plFrom
491 , long* plTo
492 ) const
493 {
494 WXDWORD dwPos;
495
496 if (m_bIsMLE)
497 dwPos = (WXDWORD)::WinSendMsg(GetHwnd(), MLM_QUERYSEL, (MPARAM)MLFQS_MINSEL, 0);
498 else
499 {
500 dwPos = (WXDWORD)::WinSendMsg(GetHwnd(), EM_QUERYSEL, 0, 0);
501 }
502 *plFrom = SHORT1FROMMP((MPARAM)dwPos); // the first 16 bit value is the min pos
503 *plTo = SHORT2FROMMP((MPARAM)dwPos); // the first 16 bit value is the min pos
504 } // end of wxTextCtrl::GetSelection
505
506 bool wxTextCtrl::IsEditable() const
507 {
508 if (m_bIsMLE)
509 return((bool)LONGFROMMR(::WinSendMsg(GetHwnd(), MLM_QUERYREADONLY, 0, 0)));
510 else
511 return((bool)LONGFROMMR(::WinSendMsg(GetHwnd(), EM_QUERYREADONLY, 0, 0)));
512 } // end of wxTextCtrl::IsEditable
513
514 // ----------------------------------------------------------------------------
515 // Editing
516 // ----------------------------------------------------------------------------
517
518 void wxTextCtrl::Replace(
519 long lFrom
520 , long lTo
521 , const wxString& rsValue
522 )
523 {
524 #if wxUSE_CLIPBOARD
525 HWND hWnd = GetHwnd();
526 long lFromChar = lFrom;
527 long lToChar = lTo;
528
529 //
530 // Set selection and remove it
531 //
532 if (m_bIsMLE)
533 {
534 ::WinSendMsg(hWnd, MLM_SETSEL, MPFROM2SHORT((USHORT)lFrom, (USHORT)lTo), 0);
535 ::WinSendMsg(hWnd, MLM_CUT, 0, 0);
536 }
537 else
538 {
539 ::WinSendMsg(hWnd, EM_SETSEL, MPFROM2SHORT((USHORT)lFrom, (USHORT)lTo), 0);
540 ::WinSendMsg(hWnd, EM_CUT, 0, 0);
541 }
542
543 //
544 // Now replace with 'value', by pasting.
545 //
546 wxSetClipboardData(wxDF_TEXT, (wxObject *) (const wxChar *)rsValue, 0, 0);
547
548 // Paste into edit control
549 if (m_bIsMLE)
550 ::WinSendMsg(hWnd, MLM_PASTE, (MPARAM)0, (MPARAM)0);
551 else
552 ::WinSendMsg(hWnd, EM_PASTE, (MPARAM)0, (MPARAM)0);
553 #else
554 wxFAIL_MSG("wxTextCtrl::Replace not implemented if wxUSE_CLIPBOARD is 0.");
555 #endif
556 } // end of wxTextCtrl::Replace
557
558 void wxTextCtrl::Remove(
559 long lFrom
560 , long lTo
561 )
562 {
563 HWND hWnd = GetHwnd();
564 long lFromChar = lFrom;
565 long lToChar = lTo;
566
567 if (m_bIsMLE)
568 {
569 ::WinSendMsg(hWnd, MLM_SETSEL, MPFROM2SHORT((USHORT)lFrom, (USHORT)lTo), 0);
570 ::WinSendMsg(hWnd, MLM_CUT, 0, 0);
571 }
572 else
573 {
574 ::WinSendMsg(hWnd, EM_SETSEL, MPFROM2SHORT((USHORT)lFrom, (USHORT)lTo), 0);
575 ::WinSendMsg(hWnd, EM_CUT, 0, 0);
576 }
577 } // end of wxTextCtrl::Remove
578
579 void wxTextCtrl::SetSelection(
580 long lFrom
581 , long lTo
582 )
583 {
584 HWND hWnd = GetHwnd();
585 long lFromChar = lFrom;
586 long lToChar = lTo;
587
588 //
589 // If from and to are both -1, it means (in wxWindows) that all text should
590 // be selected. Translate into Windows convention
591 //
592 if ((lFrom == -1L) && (lTo == -1L))
593 {
594 lFromChar = 0L;
595 lToChar = -1L;
596 }
597 if (m_bIsMLE)
598 ::WinSendMsg(hWnd, MLM_SETSEL, (MPARAM)lFromChar, (MPARAM)lToChar);
599 else
600 ::WinSendMsg(hWnd, EM_SETSEL, MPFROM2SHORT((USHORT)lFromChar, (USHORT)lToChar), (MPARAM)0);
601 } // end of wxTextCtrl::SetSelection
602
603 bool wxTextCtrl::LoadFile(
604 const wxString& rsFile
605 )
606 {
607 if ( wxTextCtrlBase::LoadFile(rsFile) )
608 {
609 //
610 // Update the size limit if needed
611 //
612 AdjustSpaceLimit();
613 return TRUE;
614 }
615 return FALSE;
616 } // end of wxTextCtrl::LoadFile
617
618 bool wxTextCtrl::IsModified() const
619 {
620 bool bRc;
621
622 if (m_bIsMLE)
623 bRc = (bool)LONGFROMMR(::WinSendMsg(GetHwnd(), MLM_QUERYCHANGED, 0, 0));
624 else
625 bRc = (bool)LONGFROMMR(::WinSendMsg(GetHwnd(), EM_QUERYCHANGED, 0, 0));
626 return bRc;
627 } // end of wxTextCtrl::IsModified
628
629 //
630 // Makes 'unmodified'
631 //
632 void wxTextCtrl::DiscardEdits()
633 {
634 if (m_bIsMLE)
635 ::WinSendMsg(GetHwnd(), MLM_SETCHANGED, MPFROMLONG(FALSE), 0);
636 else
637 //
638 // EM controls do not have a SETCHANGED but issuing a query should reset it
639 //
640 ::WinSendMsg(GetHwnd(), EM_QUERYCHANGED, 0, 0);
641 } // end of wxTextCtrl::DiscardEdits
642
643 int wxTextCtrl::GetNumberOfLines() const
644 {
645 int nNumLines;
646
647 if (m_bIsMLE)
648 nNumLines = (int)::WinSendMsg(GetHwnd(), MLM_QUERYLINECOUNT, 0, 0);
649 else
650 nNumLines = 1;
651 return nNumLines;
652 } // end of wxTextCtrl::GetNumberOfLines
653
654 long wxTextCtrl::XYToPosition(
655 long lX
656 , long lY
657 ) const
658 {
659 HWND hWnd = GetHwnd();
660 long lCharIndex = 0L;
661 long lLen;
662
663 if (m_bIsMLE)
664 {
665 lLen = (long)::WinSendMsg(GetHwnd(), MLM_QUERYLINELENGTH, 0, 0);
666 lCharIndex = ((lLen * lY) + lX);
667 }
668 else
669 lCharIndex = lX;
670 return lCharIndex;
671 } // end of wxTextCtrl::XYToPosition
672
673 bool wxTextCtrl::PositionToXY(
674 long lPos
675 , long* plX
676 , long* plY
677 ) const
678 {
679 HWND hWnd = GetHwnd();
680 long nLineNo = -1;
681 long lCharIndex = 0;
682
683 if (m_bIsMLE)
684 nLineNo = (long)::WinSendMsg(hWnd, MLM_LINEFROMCHAR, (MPARAM)lPos, 0);
685 else
686 nLineNo = 0;
687
688 if (nLineNo == -1)
689 {
690 // no such line
691 return FALSE;
692 }
693
694 //
695 // This gets the char index for the _beginning_ of this line
696 //
697 long lLineWidth;
698
699 if (m_bIsMLE)
700 {
701 lLineWidth = (long)::WinSendMsg(hWnd, MLM_QUERYLINELENGTH, (MPARAM)0, (MPARAM)0);
702 lCharIndex = (nLineNo + 1) * lLineWidth;
703 }
704 else
705 {
706 WNDPARAMS vParams;
707
708 vParams.fsStatus = WPM_CCHTEXT;
709 if (::WinSendMsg( hWnd
710 ,WM_QUERYWINDOWPARAMS
711 ,&vParams
712 ,0
713 ))
714 {
715 lCharIndex = vParams.cchText;
716 }
717 else
718 lCharIndex = 32;
719 }
720
721 if (lCharIndex == -1)
722 {
723 return FALSE;
724 }
725
726 //
727 // The X position must therefore be the difference between pos and charIndex
728 //
729 if (plX)
730 *plX = lPos - lCharIndex;
731 if (plY)
732 *plY = nLineNo;
733
734 return TRUE;
735 } // end of wxTextCtrl::PositionToXY
736
737 void wxTextCtrl::ShowPosition(
738 long lPos
739 )
740 {
741 HWND hWnd = GetHwnd();
742 long lCurrentLineLineNo = 0L;
743
744 // To scroll to a position, we pass the number of lines and characters
745 // to scroll *by*. This means that we need to:
746 // (1) Find the line position of the current line.
747 // (2) Find the line position of pos.
748 // (3) Scroll by (pos - current).
749 // For now, ignore the horizontal scrolling.
750
751 //
752 // Is this where scrolling is relative to - the line containing the caret?
753 // Or is the first visible line??? Try first visible line.
754 //
755 if (m_bIsMLE)
756 {
757 //
758 // In PM this is the actual char position
759 //
760 lCurrentLineLineNo = (long)::WinSendMsg(hWnd, MLM_QUERYFIRSTCHAR, (MPARAM)0, (MPARAM)0);
761
762 //
763 // This will cause a scroll to the selected position
764 //
765 ::WinSendMsg(hWnd, MLM_SETSEL, (MPARAM)lCurrentLineLineNo, (MPARAM)lCurrentLineLineNo);
766 }
767 } // end of wxTextCtrl::ShowPosition
768
769 int wxTextCtrl::GetLineLength(
770 long lLineNo
771 ) const
772 {
773 long lLen = 0L;
774
775 if (m_bIsMLE)
776 lLen = (long)::WinSendMsg(GetHwnd(), MLM_QUERYLINELENGTH, 0, 0);
777 else
778 {
779 WNDPARAMS vParams;
780
781 vParams.fsStatus = WPM_CCHTEXT;
782 if (::WinSendMsg( GetHwnd()
783 ,WM_QUERYWINDOWPARAMS
784 ,&vParams
785 ,0
786 ))
787 {
788 lLen = vParams.cchText;
789 }
790 else
791 lLen = 32;
792 }
793 return lLen;
794 } // end ofwxTextCtrl::GetLineLength
795
796 wxString wxTextCtrl::GetLineText(
797 long lLineNo
798 ) const
799 {
800 long lLen = (long)GetLineLength((long)lLineNo) + 1;
801 wxString sStr;
802 char* zBuf;
803
804 //
805 // There must be at least enough place for the length WORD in the
806 // buffer
807 //
808 lLen += sizeof(WORD);
809 zBuf = new char[lLen];
810 if (m_bIsMLE)
811 {
812 long lIndex;
813 long lBuflen;
814 long lCopied;
815
816 lLen = (long)::WinSendMsg(GetHwnd(), MLM_QUERYLINELENGTH, 0, 0);
817 lIndex = lLen * lLineNo;
818
819 ::WinSendMsg(GetHwnd(), MLM_SETSEL, (MPARAM)lIndex, (MPARAM)lIndex);
820 ::WinSendMsg(GetHwnd(), MLM_SETIMPORTEXPORT, MPFROMP(zBuf), MPFROMSHORT((USHORT)sizeof(zBuf)));
821 lBuflen = (long)::WinSendMsg(GetHwnd(), MLM_QUERYFORMATTEXTLENGTH, MPFROMLONG(lIndex), MPFROMLONG(-1));
822 lCopied = (long)::WinSendMsg(GetHwnd(), MLM_EXPORT, MPFROMP(&lIndex), MPFROMP(&lBuflen));
823 zBuf[lCopied] = '\0';
824 }
825 else
826 {
827 WNDPARAMS vParams;
828
829 vParams.fsStatus = WPM_CCHTEXT;
830 if (::WinSendMsg( GetHwnd()
831 ,WM_QUERYWINDOWPARAMS
832 ,&vParams
833 ,0
834 ))
835 memcpy(zBuf, vParams.pszText, vParams.cchText);
836 zBuf[vParams.cchText] = '\0';
837 }
838 sStr = zBuf;
839 delete [] zBuf;
840 return sStr;
841 } // end of wxTextCtrl::GetLineText
842
843 // ----------------------------------------------------------------------------
844 // Undo/redo
845 // ----------------------------------------------------------------------------
846
847 void wxTextCtrl::Undo()
848 {
849 if (CanUndo())
850 {
851 if (m_bIsMLE)
852 ::WinSendMsg(GetHwnd(), MLM_UNDO, 0, 0);
853 // Simple entryfields cannot be undone
854 }
855 } // end of wxTextCtrl::Undo
856
857 void wxTextCtrl::Redo()
858 {
859 if (CanRedo())
860 {
861 if (m_bIsMLE)
862 ::WinSendMsg(GetHwnd(), MLM_UNDO, 0, 0);
863 // Simple entryfields cannot be undone
864 }
865 } // end of wxTextCtrl::Redo
866
867 bool wxTextCtrl::CanUndo() const
868 {
869 bool bOk;
870
871 if (m_bIsMLE)
872 bOk = (::WinSendMsg(GetHwnd(), MLM_QUERYUNDO, 0, 0) != 0);
873 else
874 bOk = FALSE; // can't undo regular edit fields in PM
875 return bOk;
876 } // end of wxTextCtrl::CanUndo
877
878 bool wxTextCtrl::CanRedo() const
879 {
880 bool bOk;
881
882 if (m_bIsMLE)
883 bOk = (::WinSendMsg(GetHwnd(), MLM_QUERYUNDO, 0, 0) != 0);
884 else
885 bOk = FALSE; // can't undo regular edit fields in PM
886 return bOk;
887 } // end of wxTextCtrl::CanRedo
888
889 // ----------------------------------------------------------------------------
890 // implemenation details
891 // ----------------------------------------------------------------------------
892
893 void wxTextCtrl::Command(
894 wxCommandEvent& rEvent
895 )
896 {
897 SetValue(rEvent.GetString());
898 ProcessCommand (rEvent);
899 } // end of wxTextCtrl::Command
900
901 void wxTextCtrl::OnDropFiles(
902 wxDropFilesEvent& rEvent
903 )
904 {
905 // By default, load the first file into the text window.
906 if (rEvent.GetNumberOfFiles() > 0)
907 {
908 LoadFile(rEvent.GetFiles()[0]);
909 }
910 } // end of wxTextCtrl::OnDropFiles
911
912 WXHBRUSH wxTextCtrl::OnCtlColor(
913 WXHDC hWxDC
914 , WXHWND hWnd
915 , WXUINT uCtlColor
916 , WXUINT uMessage
917 , WXWPARAM wParam
918 , WXLPARAM lParam
919 )
920 {
921 HPS hPS = (HPS)hWxDC;
922 wxBrush* pBrush = NULL;
923 wxColour vColBack = GetBackgroundColour();
924 wxColour vColFore = GetForegroundColour();
925 wxBrush* pBackgroundBrush = wxTheBrushList->FindOrCreateBrush( GetBackgroundColour()
926 ,wxSOLID
927 );
928
929 if (m_bUseCtl3D)
930 {
931 HBRUSH hBrush = NULLHANDLE;
932
933 return hBrush;
934 }
935 if (GetParent()->GetTransparentBackground())
936 ::GpiSetBackMix(hPS, BM_LEAVEALONE);
937 else
938 ::GpiSetBackMix(hPS, BM_OVERPAINT);
939 if (!IsEnabled() && (GetWindowStyle() & wxTE_MULTILINE) == 0)
940 vColBack = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_3DFACE);
941 ::GpiSetBackColor(hPS, vColBack.GetPixel());
942 ::GpiSetColor(hPS, vColFore.GetPixel());
943 return (WXHBRUSH)pBackgroundBrush->GetResourceHandle();
944 } // end of wxTextCtrl::OnCtlColor
945
946 void wxTextCtrl::OnChar(
947 wxKeyEvent& rEvent
948 )
949 {
950 switch (rEvent.KeyCode())
951 {
952 case WXK_RETURN:
953 if ( !(m_windowStyle & wxTE_MULTILINE) )
954 {
955 wxCommandEvent vEvent(wxEVT_COMMAND_TEXT_ENTER, m_windowId);
956
957 vEvent.SetEventObject(this);
958 if ( GetEventHandler()->ProcessEvent(vEvent))
959 return;
960 }
961 //else: multiline controls need Enter for themselves
962
963 break;
964
965 case WXK_TAB:
966 // always produce navigation event - even if we process TAB
967 // ourselves the fact that we got here means that the user code
968 // decided to skip processing of this TAB - probably to let it
969 // do its default job.
970 //
971 // NB: Notice that Ctrl-Tab is handled elsewhere and Alt-Tab is
972 // handled by Windows
973 {
974 wxNavigationKeyEvent vEventNav;
975
976 vEventNav.SetDirection(!rEvent.ShiftDown());
977 vEventNav.SetWindowChange(FALSE);
978 vEventNav.SetEventObject(this);
979
980 if ( GetEventHandler()->ProcessEvent(vEventNav) )
981 return;
982 }
983 break;
984 }
985 rEvent.Skip();
986 } // end of wxTextCtrl::OnChar
987
988 bool wxTextCtrl::OS2Command(
989 WXUINT uParam
990 , WXWORD WXUNUSED(vId)
991 )
992 {
993 switch (uParam)
994 {
995 case EN_SETFOCUS:
996 case EN_KILLFOCUS:
997 {
998 wxFocusEvent vEvent( uParam == EN_KILLFOCUS ? wxEVT_KILL_FOCUS
999 : wxEVT_SET_FOCUS
1000 ,m_windowId
1001 );
1002
1003 vEvent.SetEventObject(this);
1004 GetEventHandler()->ProcessEvent(vEvent);
1005 }
1006 break;
1007
1008 case EN_CHANGE:
1009 {
1010 wxCommandEvent vEvent( wxEVT_COMMAND_TEXT_UPDATED
1011 ,m_windowId
1012 );
1013
1014 InitCommandEvent(vEvent);
1015 vEvent.SetString((char*)GetValue().c_str());
1016 ProcessCommand(vEvent);
1017 }
1018 break;
1019
1020 case EN_OVERFLOW:
1021 //
1022 // The text size limit has been hit - increase it
1023 //
1024 AdjustSpaceLimit();
1025 break;
1026
1027 case EN_SCROLL:
1028 case EN_INSERTMODETOGGLE:
1029 case EN_MEMERROR:
1030 return FALSE;
1031 default:
1032 return FALSE;
1033 }
1034
1035 //
1036 // Processed
1037 //
1038 return TRUE;
1039 } // end of wxTextCtrl::OS2Command
1040
1041 void wxTextCtrl::AdjustSpaceLimit()
1042 {
1043 unsigned int uLen = 0;
1044 unsigned int uLimit = 0;
1045
1046 uLen = ::WinQueryWindowTextLength(GetHwnd());
1047 if (m_bIsMLE)
1048 {
1049 uLimit = (unsigned int)::WinSendMsg( GetHwnd()
1050 ,MLM_QUERYTEXTLIMIT
1051 ,0
1052 ,0
1053 );
1054 }
1055 else
1056 {
1057 ENTRYFDATA* pEfd;
1058 WNDPARAMS vParams;
1059
1060 vParams.fsStatus = WPM_CBCTLDATA;
1061 vParams.cbCtlData = sizeof(ENTRYFDATA);
1062
1063 if (::WinSendMsg( GetHwnd()
1064 ,WM_QUERYWINDOWPARAMS
1065 ,&vParams
1066 ,0
1067 ))
1068 {
1069 pEfd = (ENTRYFDATA*)vParams.pCtlData;
1070 uLimit = (unsigned int)pEfd->cchEditLimit;
1071 }
1072 else
1073 uLimit = 32; //PM's default
1074 }
1075 if (uLen >= uLimit)
1076 {
1077 uLimit = uLen + 0x8000; // 32Kb
1078 if (uLimit > 0xffff)
1079 {
1080 uLimit = 0L;
1081 }
1082 if (m_bIsMLE)
1083 ::WinSendMsg(GetHwnd(), MLM_SETTEXTLIMIT, MPFROMLONG(uLimit), 0);
1084 else
1085 ::WinSendMsg(GetHwnd(), EM_SETTEXTLIMIT, MPFROMLONG(uLimit), 0);
1086 }
1087 } // end of wxTextCtrl::AdjustSpaceLimit
1088
1089 bool wxTextCtrl::AcceptsFocus() const
1090 {
1091 //
1092 // We don't want focus if we can't be edited
1093 //
1094 return IsEditable() && wxControl::AcceptsFocus();
1095 } // end of wxTextCtrl::Command
1096
1097 wxSize wxTextCtrl::DoGetBestSize() const
1098 {
1099 int nCx;
1100 int nCy;
1101
1102 wxGetCharSize(GetHWND(), &nCx, &nCy, (wxFont*)&GetFont());
1103
1104 int wText = DEFAULT_ITEM_WIDTH;
1105 int hText = EDIT_HEIGHT_FROM_CHAR_HEIGHT(nCy);
1106
1107 if (m_windowStyle & wxTE_MULTILINE)
1108 {
1109 hText *= wxMin(GetNumberOfLines(), 5);
1110 }
1111 //else: for single line control everything is ok
1112 return wxSize(wText, hText);
1113 } // end of wxTextCtrl::DoGetBestSize
1114
1115 // ----------------------------------------------------------------------------
1116 // standard handlers for standard edit menu events
1117 // ----------------------------------------------------------------------------
1118
1119 void wxTextCtrl::OnCut(
1120 wxCommandEvent& rEvent
1121 )
1122 {
1123 Cut();
1124 } // end of wxTextCtrl::OnCut
1125
1126 void wxTextCtrl::OnCopy(
1127 wxCommandEvent& rEvent
1128 )
1129 {
1130 Copy();
1131 } // end of wxTextCtrl::OnCopy
1132
1133 void wxTextCtrl::OnPaste(
1134 wxCommandEvent& rEvent
1135 )
1136 {
1137 Paste();
1138 } // end of wxTextCtrl::OnPaste
1139
1140 void wxTextCtrl::OnUndo(
1141 wxCommandEvent& rEvent
1142 )
1143 {
1144 Undo();
1145 } // end of wxTextCtrl::OnUndo
1146
1147 void wxTextCtrl::OnRedo(
1148 wxCommandEvent& rEvent
1149 )
1150 {
1151 Redo();
1152 } // end of wxTextCtrl::OnRedo
1153
1154 void wxTextCtrl::OnUpdateCut(
1155 wxUpdateUIEvent& rEvent
1156 )
1157 {
1158 rEvent.Enable(CanCut());
1159 } // end of wxTextCtrl::OnUpdateCut
1160
1161 void wxTextCtrl::OnUpdateCopy(
1162 wxUpdateUIEvent& rEvent
1163 )
1164 {
1165 rEvent.Enable(CanCopy());
1166 } // end of wxTextCtrl::OnUpdateCopy
1167
1168 void wxTextCtrl::OnUpdatePaste(
1169 wxUpdateUIEvent& rEvent
1170 )
1171 {
1172 rEvent.Enable(CanPaste());
1173 } // end of wxTextCtrl::OnUpdatePaste
1174
1175 void wxTextCtrl::OnUpdateUndo(
1176 wxUpdateUIEvent& rEvent
1177 )
1178 {
1179 rEvent.Enable(CanUndo());
1180 } // end of wxTextCtrl::OnUpdateUndo
1181
1182 void wxTextCtrl::OnUpdateRedo(
1183 wxUpdateUIEvent& rEvent
1184 )
1185 {
1186 rEvent.Enable(CanRedo());
1187 } // end of wxTextCtrl::OnUpdateRedo
1188
1189 bool wxTextCtrl::SetBackgroundColour(
1190 const wxColour& rColour
1191 )
1192 {
1193 if (m_bIsMLE)
1194 ::WinSendMsg(GetHwnd(), MLM_SETBACKCOLOR, (MPARAM)rColour.GetPixel(), MLE_INDEX);
1195 return TRUE;
1196 } // end of wxTextCtrl::SetBackgroundColour
1197
1198 bool wxTextCtrl::SetForegroundColour(
1199 const wxColour& rColour
1200 )
1201 {
1202 if (m_bIsMLE)
1203 ::WinSendMsg(GetHwnd(), MLM_SETTEXTCOLOR, (MPARAM)rColour.GetPixel(), MLE_INDEX);
1204 return TRUE;
1205 } // end of wxTextCtrl::SetForegroundColour
1206