1//////////////////////////////////////////////////////////////////////////// 2// Name: ScintillaWX.cxx 3// Purpose: A wxWidgets implementation of Scintilla. A class derived 4// from ScintillaBase that uses the "wx platform" defined in 5// PlatformWX.cxx This class is one end of a bridge between 6// the wx world and the Scintilla world. It needs a peer 7// object of type wxStyledTextCtrl to function. 8// 9// Author: Robin Dunn 10// 11// Created: 13-Jan-2000 12// RCS-ID: $Id: ScintillaWX.cpp 62074 2009-09-24 13:16:56Z JS $ 13// Copyright: (c) 2000 by Total Control Software 14// Licence: wxWindows license 15///////////////////////////////////////////////////////////////////////////// 16 17#include "wx/wx.h" 18#include "wx/textbuf.h" 19#include "wx/dataobj.h" 20#include "wx/clipbrd.h" 21#include "wx/dnd.h" 22 23#include "ScintillaWX.h" 24#include "ExternalLexer.h" 25#include "wx/stc/stc.h" 26#include "PlatWX.h" 27 28#ifdef __WXMSW__ 29 // GetHwndOf() 30 #include "wx/msw/private.h" 31#endif 32 33//---------------------------------------------------------------------- 34// Helper classes 35 36class wxSTCTimer : public wxTimer { 37public: 38 wxSTCTimer(ScintillaWX* swx) { 39 this->swx = swx; 40 } 41 42 void Notify() { 43 swx->DoTick(); 44 } 45 46private: 47 ScintillaWX* swx; 48}; 49 50 51#if wxUSE_DRAG_AND_DROP 52class wxStartDragTimer : public wxTimer { 53public: 54 wxStartDragTimer(ScintillaWX* swx) { 55 this->swx = swx; 56 } 57 58 void Notify() { 59 swx->DoStartDrag(); 60 } 61 62private: 63 ScintillaWX* swx; 64}; 65 66 67bool wxSTCDropTarget::OnDropText(wxCoord x, wxCoord y, const wxString& data) { 68 return swx->DoDropText(x, y, data); 69} 70 71wxDragResult wxSTCDropTarget::OnEnter(wxCoord x, wxCoord y, wxDragResult def) { 72 return swx->DoDragEnter(x, y, def); 73} 74 75wxDragResult wxSTCDropTarget::OnDragOver(wxCoord x, wxCoord y, wxDragResult def) { 76 return swx->DoDragOver(x, y, def); 77} 78 79void wxSTCDropTarget::OnLeave() { 80 swx->DoDragLeave(); 81} 82#endif // wxUSE_DRAG_AND_DROP 83 84 85#if wxUSE_POPUPWIN && wxSTC_USE_POPUP 86#include <wx/popupwin.h> 87#define wxSTCCallTipBase wxPopupWindow 88#define param2 wxBORDER_NONE // popup's 2nd param is flags 89#else 90#define wxSTCCallTipBase wxFrame 91#define param2 -1 // wxWindow's 2nd param is ID 92#endif 93 94#include "wx/dcbuffer.h" 95 96class wxSTCCallTip : public wxSTCCallTipBase { 97public: 98 wxSTCCallTip(wxWindow* parent, CallTip* ct, ScintillaWX* swx) : 99#if wxUSE_POPUPWIN && wxSTC_USE_POPUP 100 wxSTCCallTipBase(parent, wxBORDER_NONE), 101#else 102 wxSTCCallTipBase(parent, -1, wxEmptyString, wxDefaultPosition, wxDefaultSize, 103 wxFRAME_NO_TASKBAR 104 | wxFRAME_FLOAT_ON_PARENT 105 | wxBORDER_NONE 106#ifdef __WXMAC__ 107 | wxPOPUP_WINDOW 108#endif 109 ), 110#endif 111 m_ct(ct), m_swx(swx), m_cx(wxDefaultCoord), m_cy(wxDefaultCoord) 112 { 113 } 114 115 ~wxSTCCallTip() { 116#if wxUSE_POPUPWIN && wxSTC_USE_POPUP && defined(__WXGTK__) 117 wxRect rect = GetRect(); 118 rect.x = m_cx; 119 rect.y = m_cy; 120 GetParent()->Refresh(false, &rect); 121#endif 122 } 123 124 bool AcceptsFocus() const { return false; } 125 126 void OnPaint(wxPaintEvent& WXUNUSED(evt)) 127 { 128 wxBufferedPaintDC dc(this); 129 Surface* surfaceWindow = Surface::Allocate(); 130 surfaceWindow->Init(&dc, m_ct->wDraw.GetID()); 131 m_ct->PaintCT(surfaceWindow); 132 surfaceWindow->Release(); 133 delete surfaceWindow; 134 } 135 136 void OnFocus(wxFocusEvent& event) 137 { 138 GetParent()->SetFocus(); 139 event.Skip(); 140 } 141 142 void OnLeftDown(wxMouseEvent& event) 143 { 144 wxPoint pt = event.GetPosition(); 145 Point p(pt.x, pt.y); 146 m_ct->MouseClick(p); 147 m_swx->CallTipClick(); 148 } 149 150 virtual void DoSetSize(int x, int y, 151 int width, int height, 152 int sizeFlags = wxSIZE_AUTO) 153 { 154 // convert coords to screen coords since we're a top-level window 155 if (x != wxDefaultCoord) { 156 m_cx = x; 157 GetParent()->ClientToScreen(&x, NULL); 158 } 159 if (y != wxDefaultCoord) { 160 m_cy = y; 161 GetParent()->ClientToScreen(NULL, &y); 162 } 163 wxSTCCallTipBase::DoSetSize(x, y, width, height, sizeFlags); 164 } 165 166#if wxUSE_POPUPWIN && wxSTC_USE_POPUP 167#else 168 virtual bool Show( bool show = true ) 169 { 170 // Although we're a frame, we always want the parent to be active, so 171 // raise it whenever we get shown. 172 bool rv = wxSTCCallTipBase::Show(show); 173 if (rv && show) 174 { 175 wxTopLevelWindow *frame = wxDynamicCast( 176 wxGetTopLevelParent(GetParent()), wxTopLevelWindow); 177 if (frame) 178 frame->Raise(); 179 } 180 return rv; 181 } 182#endif 183 184 wxPoint GetMyPosition() 185 { 186 return wxPoint(m_cx, m_cy); 187 } 188 189private: 190 CallTip* m_ct; 191 ScintillaWX* m_swx; 192 int m_cx, m_cy; 193 DECLARE_EVENT_TABLE() 194}; 195 196BEGIN_EVENT_TABLE(wxSTCCallTip, wxSTCCallTipBase) 197 EVT_PAINT(wxSTCCallTip::OnPaint) 198 EVT_SET_FOCUS(wxSTCCallTip::OnFocus) 199 EVT_LEFT_DOWN(wxSTCCallTip::OnLeftDown) 200END_EVENT_TABLE() 201 202 203//---------------------------------------------------------------------- 204 205#if wxUSE_DATAOBJ 206static wxTextFileType wxConvertEOLMode(int scintillaMode) 207{ 208 wxTextFileType type; 209 210 switch (scintillaMode) { 211 case wxSTC_EOL_CRLF: 212 type = wxTextFileType_Dos; 213 break; 214 215 case wxSTC_EOL_CR: 216 type = wxTextFileType_Mac; 217 break; 218 219 case wxSTC_EOL_LF: 220 type = wxTextFileType_Unix; 221 break; 222 223 default: 224 type = wxTextBuffer::typeDefault; 225 break; 226 } 227 return type; 228} 229#endif // wxUSE_DATAOBJ 230 231 232//---------------------------------------------------------------------- 233// Constructor/Destructor 234 235 236ScintillaWX::ScintillaWX(wxStyledTextCtrl* win) { 237 capturedMouse = false; 238 focusEvent = false; 239 wMain = win; 240 stc = win; 241 wheelRotation = 0; 242 Initialise(); 243#ifdef __WXMSW__ 244 sysCaretBitmap = 0; 245 sysCaretWidth = 0; 246 sysCaretHeight = 0; 247#endif 248#if wxUSE_DRAG_AND_DROP 249 startDragTimer = new wxStartDragTimer(this); 250#endif // wxUSE_DRAG_AND_DROP 251} 252 253 254ScintillaWX::~ScintillaWX() { 255#if wxUSE_DRAG_AND_DROP 256 delete startDragTimer; 257#endif // wxUSE_DRAG_AND_DROP 258 Finalise(); 259} 260 261//---------------------------------------------------------------------- 262// base class virtuals 263 264 265void ScintillaWX::Initialise() { 266 //ScintillaBase::Initialise(); 267#if wxUSE_DRAG_AND_DROP 268 dropTarget = new wxSTCDropTarget; 269 dropTarget->SetScintilla(this); 270 stc->SetDropTarget(dropTarget); 271#endif // wxUSE_DRAG_AND_DROP 272#ifdef __WXMAC__ 273 vs.extraFontFlag = false; // UseAntiAliasing 274#else 275 vs.extraFontFlag = true; // UseAntiAliasing 276#endif 277} 278 279 280void ScintillaWX::Finalise() { 281 ScintillaBase::Finalise(); 282 SetTicking(false); 283 SetIdle(false); 284 DestroySystemCaret(); 285} 286 287 288void ScintillaWX::StartDrag() { 289#if wxUSE_DRAG_AND_DROP 290 // We defer the starting of the DnD, otherwise the LeftUp of a normal 291 // click could be lost and the STC will think it is doing a DnD when the 292 // user just wanted a normal click. 293 startDragTimer->Start(200, true); 294#endif // wxUSE_DRAG_AND_DROP 295} 296 297void ScintillaWX::DoStartDrag() { 298#if wxUSE_DRAG_AND_DROP 299 wxString dragText = stc2wx(drag.s, drag.len); 300 301 // Send an event to allow the drag text to be changed 302 wxStyledTextEvent evt(wxEVT_STC_START_DRAG, stc->GetId()); 303 evt.SetEventObject(stc); 304 evt.SetDragText(dragText); 305 evt.SetDragAllowMove(true); 306 evt.SetPosition(wxMin(stc->GetSelectionStart(), 307 stc->GetSelectionEnd())); 308 stc->GetEventHandler()->ProcessEvent(evt); 309 dragText = evt.GetDragText(); 310 311 if (dragText.length()) { 312 wxDropSource source(stc); 313 wxTextDataObject data(dragText); 314 wxDragResult result; 315 316 source.SetData(data); 317 dropWentOutside = true; 318 result = source.DoDragDrop(evt.GetDragAllowMove()); 319 if (result == wxDragMove && dropWentOutside) 320 ClearSelection(); 321 inDragDrop = false; 322 SetDragPosition(invalidPosition); 323 } 324#endif // wxUSE_DRAG_AND_DROP 325} 326 327 328bool ScintillaWX::SetIdle(bool on) { 329 if (idler.state != on) { 330 // connect or disconnect the EVT_IDLE handler 331 if (on) 332 stc->Connect(wxID_ANY, wxEVT_IDLE, 333 (wxObjectEventFunction) (wxEventFunction) (wxIdleEventFunction) &wxStyledTextCtrl::OnIdle); 334 else 335 stc->Disconnect(wxID_ANY, wxEVT_IDLE, 336 (wxObjectEventFunction) (wxEventFunction) (wxIdleEventFunction) &wxStyledTextCtrl::OnIdle); 337 idler.state = on; 338 } 339 return idler.state; 340} 341 342 343void ScintillaWX::SetTicking(bool on) { 344 wxSTCTimer* steTimer; 345 if (timer.ticking != on) { 346 timer.ticking = on; 347 if (timer.ticking) { 348 steTimer = new wxSTCTimer(this); 349 steTimer->Start(timer.tickSize); 350 timer.tickerID = steTimer; 351 } else { 352 steTimer = (wxSTCTimer*)timer.tickerID; 353 steTimer->Stop(); 354 delete steTimer; 355 timer.tickerID = 0; 356 } 357 } 358 timer.ticksToWait = caret.period; 359} 360 361 362void ScintillaWX::SetMouseCapture(bool on) { 363 if (mouseDownCaptures) { 364 if (on && !capturedMouse) 365 stc->CaptureMouse(); 366 else if (!on && capturedMouse && stc->HasCapture()) 367 stc->ReleaseMouse(); 368 capturedMouse = on; 369 } 370} 371 372 373bool ScintillaWX::HaveMouseCapture() { 374 return capturedMouse; 375} 376 377 378void ScintillaWX::ScrollText(int linesToMove) { 379 int dy = vs.lineHeight * (linesToMove); 380 stc->ScrollWindow(0, dy); 381 stc->Update(); 382} 383 384void ScintillaWX::SetVerticalScrollPos() { 385 if (stc->m_vScrollBar == NULL) { // Use built-in scrollbar 386 stc->SetScrollPos(wxVERTICAL, topLine); 387 } 388 else { // otherwise use the one that's been given to us 389 stc->m_vScrollBar->SetThumbPosition(topLine); 390 } 391} 392 393void ScintillaWX::SetHorizontalScrollPos() { 394 if (stc->m_hScrollBar == NULL) { // Use built-in scrollbar 395 stc->SetScrollPos(wxHORIZONTAL, xOffset); 396 } 397 else { // otherwise use the one that's been given to us 398 stc->m_hScrollBar->SetThumbPosition(xOffset); 399 } 400} 401 402 403const int H_SCROLL_STEP = 20; 404 405bool ScintillaWX::ModifyScrollBars(int nMax, int nPage) { 406 bool modified = false; 407 408 int vertEnd = nMax; 409 if (!verticalScrollBarVisible) 410 vertEnd = 0; 411 412 // Check the vertical scrollbar 413 if (stc->m_vScrollBar == NULL) { // Use built-in scrollbar 414 int sbMax = stc->GetScrollRange(wxVERTICAL); 415 int sbThumb = stc->GetScrollThumb(wxVERTICAL); 416 int sbPos = stc->GetScrollPos(wxVERTICAL); 417 if (sbMax != vertEnd || sbThumb != nPage) { 418 stc->SetScrollbar(wxVERTICAL, sbPos, nPage, vertEnd+1); 419 modified = true; 420 } 421 } 422 else { // otherwise use the one that's been given to us 423 int sbMax = stc->m_vScrollBar->GetRange(); 424 int sbPage = stc->m_vScrollBar->GetPageSize(); 425 int sbPos = stc->m_vScrollBar->GetThumbPosition(); 426 if (sbMax != vertEnd || sbPage != nPage) { 427 stc->m_vScrollBar->SetScrollbar(sbPos, nPage, vertEnd+1, nPage); 428 modified = true; 429 } 430 } 431 432 433 // Check the horizontal scrollbar 434 PRectangle rcText = GetTextRectangle(); 435 int horizEnd = scrollWidth; 436 if (horizEnd < 0) 437 horizEnd = 0; 438 if (!horizontalScrollBarVisible || (wrapState != eWrapNone)) 439 horizEnd = 0; 440 int pageWidth = rcText.Width(); 441 442 if (stc->m_hScrollBar == NULL) { // Use built-in scrollbar 443 int sbMax = stc->GetScrollRange(wxHORIZONTAL); 444 int sbThumb = stc->GetScrollThumb(wxHORIZONTAL); 445 int sbPos = stc->GetScrollPos(wxHORIZONTAL); 446 if ((sbMax != horizEnd) || (sbThumb != pageWidth) || (sbPos != 0)) { 447 stc->SetScrollbar(wxHORIZONTAL, sbPos, pageWidth, horizEnd); 448 modified = true; 449 if (scrollWidth < pageWidth) { 450 HorizontalScrollTo(0); 451 } 452 } 453 } 454 else { // otherwise use the one that's been given to us 455 int sbMax = stc->m_hScrollBar->GetRange(); 456 int sbThumb = stc->m_hScrollBar->GetPageSize(); 457 int sbPos = stc->m_hScrollBar->GetThumbPosition(); 458 if ((sbMax != horizEnd) || (sbThumb != pageWidth) || (sbPos != 0)) { 459 stc->m_hScrollBar->SetScrollbar(sbPos, pageWidth, horizEnd, pageWidth); 460 modified = true; 461 if (scrollWidth < pageWidth) { 462 HorizontalScrollTo(0); 463 } 464 } 465 } 466 467 return modified; 468} 469 470 471void ScintillaWX::NotifyChange() { 472 stc->NotifyChange(); 473} 474 475 476void ScintillaWX::NotifyParent(SCNotification scn) { 477 stc->NotifyParent(&scn); 478} 479 480 481// This method is overloaded from ScintillaBase in order to prevent the 482// AutoComplete window from being destroyed when it gets the focus. There is 483// a side effect that the AutoComp will also not be destroyed when switching 484// to another window, but I think that is okay. 485void ScintillaWX::CancelModes() { 486 if (! focusEvent) 487 AutoCompleteCancel(); 488 ct.CallTipCancel(); 489 Editor::CancelModes(); 490} 491 492 493 494void ScintillaWX::Copy() { 495 if (currentPos != anchor) { 496 SelectionText st; 497 CopySelectionRange(&st); 498 CopyToClipboard(st); 499 } 500} 501 502 503void ScintillaWX::Paste() { 504 pdoc->BeginUndoAction(); 505 ClearSelection(); 506 507#if wxUSE_DATAOBJ 508 wxTextDataObject data; 509 bool gotData = false; 510 511 if (wxTheClipboard->Open()) { 512 wxTheClipboard->UsePrimarySelection(false); 513 gotData = wxTheClipboard->GetData(data); 514 wxTheClipboard->Close(); 515 } 516 if (gotData) { 517 wxString text = wxTextBuffer::Translate(data.GetText(), 518 wxConvertEOLMode(pdoc->eolMode)); 519 wxWX2MBbuf buf = (wxWX2MBbuf)wx2stc(text); 520 521#if wxUSE_UNICODE 522 // free up the old character buffer in case the text is real big 523 data.SetText(wxEmptyString); 524 text = wxEmptyString; 525#endif 526 int len = strlen(buf); 527 pdoc->InsertString(currentPos, buf, len); 528 SetEmptySelection(currentPos + len); 529 } 530#endif // wxUSE_DATAOBJ 531 532 pdoc->EndUndoAction(); 533 NotifyChange(); 534 Redraw(); 535} 536 537 538void ScintillaWX::CopyToClipboard(const SelectionText& st) { 539#if wxUSE_CLIPBOARD 540 if ( !st.len ) 541 return; 542 if (wxTheClipboard->Open()) { 543 wxTheClipboard->UsePrimarySelection(false); 544 wxString text = wxTextBuffer::Translate(stc2wx(st.s, st.len-1)); 545 wxTheClipboard->SetData(new wxTextDataObject(text)); 546 wxTheClipboard->Close(); 547 } 548#else 549 wxUnusedVar(st); 550#endif // wxUSE_CLIPBOARD 551} 552 553 554bool ScintillaWX::CanPaste() { 555#if wxUSE_CLIPBOARD 556 bool canPaste = false; 557 bool didOpen; 558 559 if (Editor::CanPaste()) { 560 didOpen = !wxTheClipboard->IsOpened(); 561 if ( didOpen ) 562 wxTheClipboard->Open(); 563 564 if (wxTheClipboard->IsOpened()) { 565 wxTheClipboard->UsePrimarySelection(false); 566 canPaste = wxTheClipboard->IsSupported(wxUSE_UNICODE ? wxDF_UNICODETEXT : wxDF_TEXT); 567 if (didOpen) 568 wxTheClipboard->Close(); 569 } 570 } 571 return canPaste; 572#else 573 return false; 574#endif // wxUSE_CLIPBOARD 575} 576 577void ScintillaWX::CreateCallTipWindow(PRectangle) { 578 if (! ct.wCallTip.Created() ) { 579 ct.wCallTip = new wxSTCCallTip(stc, &ct, this); 580 ct.wDraw = ct.wCallTip; 581 } 582} 583 584 585void ScintillaWX::AddToPopUp(const char *label, int cmd, bool enabled) { 586 if (!label[0]) 587 ((wxMenu*)popup.GetID())->AppendSeparator(); 588 else 589 ((wxMenu*)popup.GetID())->Append(cmd, wxGetTranslation(stc2wx(label))); 590 591 if (!enabled) 592 ((wxMenu*)popup.GetID())->Enable(cmd, enabled); 593} 594 595 596// This is called by the Editor base class whenever something is selected 597void ScintillaWX::ClaimSelection() { 598#if 0 599 // Until wxGTK is able to support using both the primary selection and the 600 // clipboard at the same time I think it causes more problems than it is 601 // worth to implement this method. Selecting text should not clear the 602 // clipboard. --Robin 603#ifdef __WXGTK__ 604 // Put the selected text in the PRIMARY selection 605 if (currentPos != anchor) { 606 SelectionText st; 607 CopySelectionRange(&st); 608 if (wxTheClipboard->Open()) { 609 wxTheClipboard->UsePrimarySelection(true); 610 wxString text = stc2wx(st.s, st.len); 611 wxTheClipboard->SetData(new wxTextDataObject(text)); 612 wxTheClipboard->UsePrimarySelection(false); 613 wxTheClipboard->Close(); 614 } 615 } 616#endif 617#endif 618} 619 620 621void ScintillaWX::UpdateSystemCaret() { 622#ifdef __WXMSW__ 623 if (hasFocus) { 624 if (HasCaretSizeChanged()) { 625 DestroySystemCaret(); 626 CreateSystemCaret(); 627 } 628 Point pos = LocationFromPosition(currentPos); 629 ::SetCaretPos(pos.x, pos.y); 630 } 631#endif 632} 633 634 635bool ScintillaWX::HasCaretSizeChanged() { 636#ifdef __WXMSW__ 637 if (( (0 != vs.caretWidth) && (sysCaretWidth != vs.caretWidth) ) 638 || (0 != vs.lineHeight) && (sysCaretHeight != vs.lineHeight)) { 639 return true; 640 } 641#endif 642 return false; 643} 644 645bool ScintillaWX::CreateSystemCaret() { 646#ifdef __WXMSW__ 647 sysCaretWidth = vs.caretWidth; 648 if (0 == sysCaretWidth) { 649 sysCaretWidth = 1; 650 } 651 sysCaretHeight = vs.lineHeight; 652 int bitmapSize = (((sysCaretWidth + 15) & ~15) >> 3) * sysCaretHeight; 653 char *bits = new char[bitmapSize]; 654 memset(bits, 0, bitmapSize); 655 sysCaretBitmap = ::CreateBitmap(sysCaretWidth, sysCaretHeight, 1, 656 1, reinterpret_cast<BYTE *>(bits)); 657 delete [] bits; 658 BOOL retval = ::CreateCaret(GetHwndOf(stc), sysCaretBitmap, 659 sysCaretWidth, sysCaretHeight); 660 ::ShowCaret(GetHwndOf(stc)); 661 return retval != 0; 662#else 663 return false; 664#endif 665} 666 667bool ScintillaWX::DestroySystemCaret() { 668#ifdef __WXMSW__ 669 ::HideCaret(GetHwndOf(stc)); 670 BOOL retval = ::DestroyCaret(); 671 if (sysCaretBitmap) { 672 ::DeleteObject(sysCaretBitmap); 673 sysCaretBitmap = 0; 674 } 675 return retval != 0; 676#else 677 return false; 678#endif 679} 680 681 682//---------------------------------------------------------------------- 683 684 685sptr_t ScintillaWX::DefWndProc(unsigned int /*iMessage*/, 686 uptr_t /*wParam*/, 687 sptr_t /*lParam*/) { 688 return 0; 689} 690 691sptr_t ScintillaWX::WndProc(unsigned int iMessage, 692 uptr_t wParam, 693 sptr_t lParam) { 694 switch (iMessage) { 695 case SCI_CALLTIPSHOW: { 696 // NOTE: This is copied here from scintilla/src/ScintillaBase.cxx 697 // because of the little tweak that needs done below for wxGTK. 698 // When updating new versions double check that this is still 699 // needed, and that any new code there is copied here too. 700 Point pt = LocationFromPosition(wParam); 701 char* defn = reinterpret_cast<char *>(lParam); 702 AutoCompleteCancel(); 703 pt.y += vs.lineHeight; 704 int ctStyle = ct.UseStyleCallTip() ? STYLE_CALLTIP : STYLE_DEFAULT; 705 if (ct.UseStyleCallTip()) 706 { 707 ct.SetForeBack(vs.styles[STYLE_CALLTIP].fore, vs.styles[STYLE_CALLTIP].back); 708 709 } 710 PRectangle rc = ct.CallTipStart(currentPos, pt, 711 defn, 712 vs.styles[ctStyle].fontName, 713 vs.styles[ctStyle].sizeZoomed, 714 CodePage(), 715 vs.styles[ctStyle].characterSet, 716 wMain); 717 // If the call-tip window would be out of the client 718 // space, adjust so it displays above the text. 719 PRectangle rcClient = GetClientRectangle(); 720 if (rc.bottom > rcClient.bottom) { 721#ifdef __WXGTK__ 722 int offset = int(vs.lineHeight * 1.25) + rc.Height(); 723#else 724 int offset = vs.lineHeight + rc.Height(); 725#endif 726 rc.top -= offset; 727 rc.bottom -= offset; 728 } 729 // Now display the window. 730 CreateCallTipWindow(rc); 731 ct.wCallTip.SetPositionRelative(rc, wMain); 732 ct.wCallTip.Show(); 733 break; 734 } 735 736#ifdef SCI_LEXER 737 case SCI_LOADLEXERLIBRARY: 738 LexerManager::GetInstance()->Load((const char*)lParam); 739 break; 740#endif 741 742 default: 743 return ScintillaBase::WndProc(iMessage, wParam, lParam); 744 } 745 return 0; 746} 747 748 749 750//---------------------------------------------------------------------- 751// Event delegates 752 753void ScintillaWX::DoPaint(wxDC* dc, wxRect rect) { 754 755 paintState = painting; 756 Surface* surfaceWindow = Surface::Allocate(); 757 surfaceWindow->Init(dc, wMain.GetID()); 758 rcPaint = PRectangleFromwxRect(rect); 759 PRectangle rcClient = GetClientRectangle(); 760 paintingAllText = rcPaint.Contains(rcClient); 761 762 ClipChildren(*dc, rcPaint); 763 Paint(surfaceWindow, rcPaint); 764 765 delete surfaceWindow; 766 if (paintState == paintAbandoned) { 767 // Painting area was insufficient to cover new styling or brace 768 // highlight positions 769 FullPaint(); 770 } 771 paintState = notPainting; 772} 773 774 775void ScintillaWX::DoHScroll(int type, int pos) { 776 int xPos = xOffset; 777 PRectangle rcText = GetTextRectangle(); 778 int pageWidth = rcText.Width() * 2 / 3; 779 if (type == wxEVT_SCROLLWIN_LINEUP || type == wxEVT_SCROLL_LINEUP) 780 xPos -= H_SCROLL_STEP; 781 else if (type == wxEVT_SCROLLWIN_LINEDOWN || type == wxEVT_SCROLL_LINEDOWN) 782 xPos += H_SCROLL_STEP; 783 else if (type == wxEVT_SCROLLWIN_PAGEUP || type == wxEVT_SCROLL_PAGEUP) 784 xPos -= pageWidth; 785 else if (type == wxEVT_SCROLLWIN_PAGEDOWN || type == wxEVT_SCROLL_PAGEDOWN) { 786 xPos += pageWidth; 787 if (xPos > scrollWidth - rcText.Width()) { 788 xPos = scrollWidth - rcText.Width(); 789 } 790 } 791 else if (type == wxEVT_SCROLLWIN_TOP || type == wxEVT_SCROLL_TOP) 792 xPos = 0; 793 else if (type == wxEVT_SCROLLWIN_BOTTOM || type == wxEVT_SCROLL_BOTTOM) 794 xPos = scrollWidth; 795 else if (type == wxEVT_SCROLLWIN_THUMBTRACK || type == wxEVT_SCROLL_THUMBTRACK) 796 xPos = pos; 797 798 HorizontalScrollTo(xPos); 799} 800 801void ScintillaWX::DoVScroll(int type, int pos) { 802 int topLineNew = topLine; 803 if (type == wxEVT_SCROLLWIN_LINEUP || type == wxEVT_SCROLL_LINEUP) 804 topLineNew -= 1; 805 else if (type == wxEVT_SCROLLWIN_LINEDOWN || type == wxEVT_SCROLL_LINEDOWN) 806 topLineNew += 1; 807 else if (type == wxEVT_SCROLLWIN_PAGEUP || type == wxEVT_SCROLL_PAGEUP) 808 topLineNew -= LinesToScroll(); 809 else if (type == wxEVT_SCROLLWIN_PAGEDOWN || type == wxEVT_SCROLL_PAGEDOWN) 810 topLineNew += LinesToScroll(); 811 else if (type == wxEVT_SCROLLWIN_TOP || type == wxEVT_SCROLL_TOP) 812 topLineNew = 0; 813 else if (type == wxEVT_SCROLLWIN_BOTTOM || type == wxEVT_SCROLL_BOTTOM) 814 topLineNew = MaxScrollPos(); 815 else if (type == wxEVT_SCROLLWIN_THUMBTRACK || type == wxEVT_SCROLL_THUMBTRACK) 816 topLineNew = pos; 817 818 ScrollTo(topLineNew); 819} 820 821void ScintillaWX::DoMouseWheel(int rotation, int delta, 822 int linesPerAction, int ctrlDown, 823 bool isPageScroll ) { 824 int topLineNew = topLine; 825 int lines; 826 827 if (ctrlDown) { // Zoom the fonts if Ctrl key down 828 if (rotation < 0) { 829 KeyCommand(SCI_ZOOMIN); 830 } 831 else { 832 KeyCommand(SCI_ZOOMOUT); 833 } 834 } 835 else { // otherwise just scroll the window 836 if ( !delta ) 837 delta = 120; 838 wheelRotation += rotation; 839 lines = wheelRotation / delta; 840 wheelRotation -= lines * delta; 841 if (lines != 0) { 842 if (isPageScroll) 843 lines = lines * LinesOnScreen(); // lines is either +1 or -1 844 else 845 lines *= linesPerAction; 846 topLineNew -= lines; 847 ScrollTo(topLineNew); 848 } 849 } 850} 851 852 853void ScintillaWX::DoSize(int WXUNUSED(width), int WXUNUSED(height)) { 854 ChangeSize(); 855} 856 857void ScintillaWX::DoLoseFocus(){ 858 focusEvent = true; 859 SetFocusState(false); 860 focusEvent = false; 861 DestroySystemCaret(); 862} 863 864void ScintillaWX::DoGainFocus(){ 865 focusEvent = true; 866 SetFocusState(true); 867 focusEvent = false; 868 DestroySystemCaret(); 869 CreateSystemCaret(); 870} 871 872void ScintillaWX::DoSysColourChange() { 873 InvalidateStyleData(); 874} 875 876void ScintillaWX::DoLeftButtonDown(Point pt, unsigned int curTime, bool shift, bool ctrl, bool alt) { 877 ButtonDown(pt, curTime, shift, ctrl, alt); 878} 879 880void ScintillaWX::DoLeftButtonUp(Point pt, unsigned int curTime, bool ctrl) { 881 ButtonUp(pt, curTime, ctrl); 882#if wxUSE_DRAG_AND_DROP 883 if (startDragTimer->IsRunning()) { 884 startDragTimer->Stop(); 885 SetDragPosition(invalidPosition); 886 SetEmptySelection(PositionFromLocation(pt)); 887 ShowCaretAtCurrentPosition(); 888 } 889#endif // wxUSE_DRAG_AND_DROP 890} 891 892void ScintillaWX::DoLeftButtonMove(Point pt) { 893 ButtonMove(pt); 894} 895 896#ifdef __WXGTK__ 897void ScintillaWX::DoMiddleButtonUp(Point pt) { 898 // Set the current position to the mouse click point and 899 // then paste in the PRIMARY selection, if any. wxGTK only. 900 int newPos = PositionFromLocation(pt); 901 MovePositionTo(newPos, noSel, true); 902 903 pdoc->BeginUndoAction(); 904 wxTextDataObject data; 905 bool gotData = false; 906 if (wxTheClipboard->Open()) { 907 wxTheClipboard->UsePrimarySelection(true); 908 gotData = wxTheClipboard->GetData(data); 909 wxTheClipboard->UsePrimarySelection(false); 910 wxTheClipboard->Close(); 911 } 912 if (gotData) { 913 wxString text = wxTextBuffer::Translate(data.GetText(), 914 wxConvertEOLMode(pdoc->eolMode)); 915 wxWX2MBbuf buf = (wxWX2MBbuf)wx2stc(text); 916 int len = strlen(buf); 917 pdoc->InsertString(currentPos, buf, len); 918 SetEmptySelection(currentPos + len); 919 } 920 pdoc->EndUndoAction(); 921 NotifyChange(); 922 Redraw(); 923 924 ShowCaretAtCurrentPosition(); 925 EnsureCaretVisible(); 926} 927#else 928void ScintillaWX::DoMiddleButtonUp(Point WXUNUSED(pt)) { 929} 930#endif 931 932 933void ScintillaWX::DoAddChar(int key) { 934#if wxUSE_UNICODE 935 wxChar wszChars[2]; 936 wszChars[0] = (wxChar)key; 937 wszChars[1] = 0; 938 wxWX2MBbuf buf = (wxWX2MBbuf)wx2stc(wszChars); 939 AddCharUTF((char*)buf.data(), strlen(buf)); 940#else 941 AddChar((char)key); 942#endif 943} 944 945 946int ScintillaWX::DoKeyDown(const wxKeyEvent& evt, bool* consumed) 947{ 948 int key = evt.GetKeyCode(); 949 bool shift = evt.ShiftDown(), 950 ctrl = evt.ControlDown(), 951 alt = evt.AltDown(); 952 953 if (ctrl && key >= 1 && key <= 26 && key != WXK_BACK) 954 key += 'A' - 1; 955 956 switch (key) { 957 case WXK_DOWN: key = SCK_DOWN; break; 958 case WXK_UP: key = SCK_UP; break; 959 case WXK_LEFT: key = SCK_LEFT; break; 960 case WXK_RIGHT: key = SCK_RIGHT; break; 961 case WXK_HOME: key = SCK_HOME; break; 962 case WXK_END: key = SCK_END; break; 963 case WXK_PAGEUP: key = SCK_PRIOR; break; 964 case WXK_PAGEDOWN: key = SCK_NEXT; break; 965 case WXK_NUMPAD_DOWN: key = SCK_DOWN; break; 966 case WXK_NUMPAD_UP: key = SCK_UP; break; 967 case WXK_NUMPAD_LEFT: key = SCK_LEFT; break; 968 case WXK_NUMPAD_RIGHT: key = SCK_RIGHT; break; 969 case WXK_NUMPAD_HOME: key = SCK_HOME; break; 970 case WXK_NUMPAD_END: key = SCK_END; break; 971 case WXK_NUMPAD_PAGEUP: key = SCK_PRIOR; break; 972 case WXK_NUMPAD_PAGEDOWN: key = SCK_NEXT; break; 973 case WXK_NUMPAD_DELETE: key = SCK_DELETE; break; 974 case WXK_NUMPAD_INSERT: key = SCK_INSERT; break; 975 case WXK_DELETE: key = SCK_DELETE; break; 976 case WXK_INSERT: key = SCK_INSERT; break; 977 case WXK_ESCAPE: key = SCK_ESCAPE; break; 978 case WXK_BACK: key = SCK_BACK; break; 979 case WXK_TAB: key = SCK_TAB; break; 980 case WXK_NUMPAD_ENTER: // fall through 981 case WXK_RETURN: key = SCK_RETURN; break; 982 case WXK_ADD: // fall through 983 case WXK_NUMPAD_ADD: key = SCK_ADD; break; 984 case WXK_SUBTRACT: // fall through 985 case WXK_NUMPAD_SUBTRACT: key = SCK_SUBTRACT; break; 986 case WXK_DIVIDE: // fall through 987 case WXK_NUMPAD_DIVIDE: key = SCK_DIVIDE; break; 988 case WXK_CONTROL: key = 0; break; 989 case WXK_ALT: key = 0; break; 990 case WXK_SHIFT: key = 0; break; 991 case WXK_MENU: key = 0; break; 992 } 993 994#ifdef __WXMAC__ 995 if ( evt.MetaDown() ) { 996 // check for a few common Mac Meta-key combos and remap them to Ctrl 997 // for Scintilla 998 switch ( key ) { 999 case 'Z': // Undo 1000 case 'X': // Cut 1001 case 'C': // Copy 1002 case 'V': // Paste 1003 case 'A': // Select All 1004 ctrl = true; 1005 break; 1006 } 1007 } 1008#endif 1009 1010 int rv = KeyDown(key, shift, ctrl, alt, consumed); 1011 1012 if (key) 1013 return rv; 1014 else 1015 return 1; 1016} 1017 1018 1019void ScintillaWX::DoCommand(int ID) { 1020 Command(ID); 1021} 1022 1023 1024void ScintillaWX::DoContextMenu(Point pt) { 1025 if (displayPopupMenu) 1026 ContextMenu(pt); 1027} 1028 1029void ScintillaWX::DoOnListBox() { 1030 AutoCompleteCompleted(); 1031} 1032 1033 1034void ScintillaWX::DoOnIdle(wxIdleEvent& evt) { 1035 1036 if ( Idle() ) 1037 evt.RequestMore(); 1038 else 1039 SetIdle(false); 1040} 1041 1042//---------------------------------------------------------------------- 1043 1044#if wxUSE_DRAG_AND_DROP 1045bool ScintillaWX::DoDropText(long x, long y, const wxString& data) { 1046 SetDragPosition(invalidPosition); 1047 1048 wxString text = wxTextBuffer::Translate(data, 1049 wxConvertEOLMode(pdoc->eolMode)); 1050 1051 // Send an event to allow the drag details to be changed 1052 wxStyledTextEvent evt(wxEVT_STC_DO_DROP, stc->GetId()); 1053 evt.SetEventObject(stc); 1054 evt.SetDragResult(dragResult); 1055 evt.SetX(x); 1056 evt.SetY(y); 1057 evt.SetPosition(PositionFromLocation(Point(x,y))); 1058 evt.SetDragText(text); 1059 stc->GetEventHandler()->ProcessEvent(evt); 1060 1061 dragResult = evt.GetDragResult(); 1062 if (dragResult == wxDragMove || dragResult == wxDragCopy) { 1063 DropAt(evt.GetPosition(), 1064 wx2stc(evt.GetDragText()), 1065 dragResult == wxDragMove, 1066 false); // TODO: rectangular? 1067 return true; 1068 } 1069 return false; 1070} 1071 1072 1073wxDragResult ScintillaWX::DoDragEnter(wxCoord WXUNUSED(x), wxCoord WXUNUSED(y), wxDragResult def) { 1074 dragResult = def; 1075 return dragResult; 1076} 1077 1078 1079wxDragResult ScintillaWX::DoDragOver(wxCoord x, wxCoord y, wxDragResult def) { 1080 SetDragPosition(PositionFromLocation(Point(x, y))); 1081 1082 // Send an event to allow the drag result to be changed 1083 wxStyledTextEvent evt(wxEVT_STC_DRAG_OVER, stc->GetId()); 1084 evt.SetEventObject(stc); 1085 evt.SetDragResult(def); 1086 evt.SetX(x); 1087 evt.SetY(y); 1088 evt.SetPosition(PositionFromLocation(Point(x,y))); 1089 stc->GetEventHandler()->ProcessEvent(evt); 1090 1091 dragResult = evt.GetDragResult(); 1092 return dragResult; 1093} 1094 1095 1096void ScintillaWX::DoDragLeave() { 1097 SetDragPosition(invalidPosition); 1098} 1099#endif // wxUSE_DRAG_AND_DROP 1100//---------------------------------------------------------------------- 1101 1102// Force the whole window to be repainted 1103void ScintillaWX::FullPaint() { 1104#ifndef __WXMAC__ 1105 stc->Refresh(false); 1106#endif 1107 stc->Update(); 1108} 1109 1110 1111void ScintillaWX::DoScrollToLine(int line) { 1112 ScrollTo(line); 1113} 1114 1115 1116void ScintillaWX::DoScrollToColumn(int column) { 1117 HorizontalScrollTo(column * vs.spaceWidth); 1118} 1119 1120// wxGTK doesn't appear to need this explicit clipping code any longer, but I 1121// will leave it here commented out for a while just in case... 1122void ScintillaWX::ClipChildren(wxDC& WXUNUSED(dc), PRectangle WXUNUSED(rect)) 1123{ 1124// wxRegion rgn(wxRectFromPRectangle(rect)); 1125// if (ac.Active()) { 1126// wxRect childRect = ((wxWindow*)ac.lb->GetID())->GetRect(); 1127// rgn.Subtract(childRect); 1128// } 1129// if (ct.inCallTipMode) { 1130// wxSTCCallTip* tip = (wxSTCCallTip*)ct.wCallTip.GetID(); 1131// wxRect childRect = tip->GetRect(); 1132// #if wxUSE_POPUPWIN && wxSTC_USE_POPUP 1133// childRect.SetPosition(tip->GetMyPosition()); 1134// #endif 1135// rgn.Subtract(childRect); 1136// } 1137// dc.SetClippingRegion(rgn); 1138} 1139 1140 1141void ScintillaWX::SetUseAntiAliasing(bool useAA) { 1142 vs.extraFontFlag = useAA; 1143 InvalidateStyleRedraw(); 1144} 1145 1146bool ScintillaWX::GetUseAntiAliasing() { 1147 return vs.extraFontFlag; 1148} 1149 1150//---------------------------------------------------------------------- 1151//---------------------------------------------------------------------- 1152