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