1 struct TSCanvas : public wxScrolledWindow { 2 MyFrame *frame; 3 Document *doc; 4 5 int mousewheelaccum; 6 bool lastrmbwaswithctrl; 7 8 wxPoint lastmousepos; 9 10 TSCanvas(MyFrame *fr, wxWindow *parent, const wxSize &size = wxDefaultSize) frameTSCanvas11 : frame(fr), 12 wxScrolledWindow(parent, wxID_ANY, wxDefaultPosition, size, 13 wxScrolledWindowStyle | wxWANTS_CHARS), 14 mousewheelaccum(0), 15 doc(nullptr), 16 lastrmbwaswithctrl(false) { 17 SetBackgroundStyle(wxBG_STYLE_PAINT); 18 SetBackgroundColour(*wxWHITE); 19 DisableKeyboardScrolling(); 20 // Without this, ScrolledWindow does its own scrolling upon mousewheel events, which 21 // interferes with our own. 22 EnableScrolling(false, false); 23 } 24 ~TSCanvasTSCanvas25 ~TSCanvas() { 26 DELETEP(doc); 27 frame = nullptr; 28 } 29 OnPaintTSCanvas30 void OnPaint(wxPaintEvent &event) { 31 #ifdef __WXMAC__ 32 wxPaintDC dc(this); 33 #else 34 auto sz = GetClientSize(); 35 wxBitmap buffer(sz.GetX(), sz.GetY(), 24); 36 wxBufferedPaintDC dc(this, buffer); 37 #endif 38 // DoPrepareDC(dc); 39 doc->Draw(dc); 40 }; 41 UpdateHoverTSCanvas42 void UpdateHover(int mx, int my, wxDC &dc) { 43 int x, y; 44 CalcUnscrolledPosition(mx, my, &x, &y); 45 DoPrepareDC(dc); 46 doc->Hover(x / doc->currentviewscale, y / doc->currentviewscale, dc); 47 } 48 OnMotionTSCanvas49 void OnMotion(wxMouseEvent &me) { 50 wxClientDC dc(this); 51 UpdateHover(me.GetX(), me.GetY(), dc); 52 if (me.LeftIsDown() || me.RightIsDown()) { 53 doc->Drag(dc); 54 } else if (me.MiddleIsDown()) { 55 wxPoint p = me.GetPosition() - lastmousepos; 56 CursorScroll(-p.x, -p.y); 57 } 58 59 lastmousepos = me.GetPosition(); 60 } 61 SelectClickTSCanvas62 void SelectClick(int mx, int my, bool right, int isctrlshift) { 63 if (mx < 0 || my < 0) 64 return; // for some reason, using just the "menu" key sends a right-click at (-1, -1) 65 wxClientDC dc(this); 66 UpdateHover(mx, my, dc); 67 doc->Select(dc, right, isctrlshift); 68 } 69 OnLeftDownTSCanvas70 void OnLeftDown(wxMouseEvent &me) { 71 #ifndef __WXMSW__ 72 // seems to not want to give the sw focus otherwise (thinks its already in focus 73 // when its not?) 74 if (frame->filter) frame->filter->SetFocus(); 75 #endif 76 SetFocus(); 77 if (me.ShiftDown()) 78 OnMotion(me); 79 else 80 SelectClick(me.GetX(), me.GetY(), false, me.CmdDown() + me.AltDown() * 2); 81 } 82 OnLeftUpTSCanvas83 void OnLeftUp(wxMouseEvent &me) { 84 if (me.CmdDown() || me.AltDown()) doc->SelectUp(); 85 } 86 OnRightDownTSCanvas87 void OnRightDown(wxMouseEvent &me) { 88 SetFocus(); 89 SelectClick(me.GetX(), me.GetY(), true, 0); 90 lastrmbwaswithctrl = me.CmdDown(); 91 #ifndef __WXMSW__ 92 me.Skip(); // otherwise EVT_CONTEXT_MENU won't be triggered? 93 #endif 94 } 95 OnLeftDoubleClickTSCanvas96 void OnLeftDoubleClick(wxMouseEvent &me) { 97 wxClientDC dc(this); 98 UpdateHover(me.GetX(), me.GetY(), dc); 99 Status(doc->DoubleClick(dc)); 100 } 101 OnKeyDownTSCanvas102 void OnKeyDown(wxKeyEvent &ce) { ce.Skip(); } OnCharTSCanvas103 void OnChar(wxKeyEvent &ce) { 104 /* 105 if (sys->insidefiledialog) 106 { 107 ce.Skip(); 108 return; 109 } 110 */ 111 112 // Without this check, Alt+F (keyboard menu nav) Alt+1..6 (style changes), Alt+cursor 113 // (scrolling) don't work. 114 // The 128 makes sure unicode entry on e.g. Polish keyboards still works. 115 // (on Linux in particular). 116 if ((ce.GetModifiers() == wxMOD_ALT) && (ce.GetUnicodeKey() < 128)) { 117 ce.Skip(); 118 return; 119 } 120 121 wxClientDC dc(this); 122 DoPrepareDC(dc); 123 bool unprocessed = false; 124 Status(doc->Key(dc, ce.GetUnicodeKey(), ce.GetKeyCode(), ce.AltDown(), ce.CmdDown(), 125 ce.ShiftDown(), unprocessed)); 126 if (unprocessed) ce.Skip(); 127 } 128 OnMouseWheelTSCanvas129 void OnMouseWheel(wxMouseEvent &me) { 130 bool ctrl = me.CmdDown(); 131 if (sys->zoomscroll) ctrl = !ctrl; 132 wxClientDC dc(this); 133 if (me.AltDown() || ctrl || me.ShiftDown()) { 134 mousewheelaccum += me.GetWheelRotation(); 135 int steps = mousewheelaccum / me.GetWheelDelta(); 136 if (!steps) return; 137 mousewheelaccum -= steps * me.GetWheelDelta(); 138 139 UpdateHover(me.GetX(), me.GetY(), dc); 140 Status(doc->Wheel(dc, steps, me.AltDown(), ctrl, me.ShiftDown())); 141 } else if (me.GetWheelAxis()) { 142 CursorScroll(me.GetWheelRotation() * g_scrollratewheel, 0); 143 UpdateHover(me.GetX(), me.GetY(), dc); 144 } else { 145 CursorScroll(0, -me.GetWheelRotation() * g_scrollratewheel); 146 UpdateHover(me.GetX(), me.GetY(), dc); 147 } 148 } 149 OnSizeTSCanvas150 void OnSize(wxSizeEvent &se) { doc->Refresh(); } OnContextMenuClickTSCanvas151 void OnContextMenuClick(wxContextMenuEvent &cme) { 152 if (lastrmbwaswithctrl) { 153 wxMenu *tagmenu = new wxMenu(); 154 doc->RecreateTagMenu(*tagmenu); 155 PopupMenu(tagmenu); 156 delete tagmenu; 157 } else { 158 PopupMenu(frame->editmenupopup); 159 } 160 } 161 CursorScrollTSCanvas162 void CursorScroll(int dx, int dy) { 163 int x, y; 164 GetViewStart(&x, &y); 165 x += dx; 166 y += dy; 167 // EnableScrolling(true, true); 168 Scroll(x, y); 169 // EnableScrolling(false, false); 170 } 171 172 void Status(const wxChar *msg = nullptr) { 173 if (frame->GetStatusBar() && (!msg || *msg)) 174 frame->SetStatusText(msg ? msg : L"", 0); 175 } 176 177 DECLARE_EVENT_TABLE() 178 }; 179