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