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