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