1 #include "filezilla.h"
2 #include "drop_target_ex.h"
3
4 #include "listctrlex.h"
5 #include "treectrlex.h"
6
7 template<class Control>
CScrollableDropTarget(Control * pCtrl)8 CScrollableDropTarget<Control>::CScrollableDropTarget(Control* pCtrl)
9 : m_pCtrl(pCtrl)
10 {
11 m_timer.SetOwner(this);
12 }
13
14
15 template<class Control>
OnDrop(wxCoord,wxCoord)16 bool CScrollableDropTarget<Control>::OnDrop(wxCoord, wxCoord)
17 {
18 m_timer.Stop();
19 return true;
20 }
21
22 template<class Control>
OnDragOver(wxCoord x,wxCoord y,wxDragResult def)23 wxDragResult CScrollableDropTarget<Control>::OnDragOver(wxCoord x, wxCoord y, wxDragResult def)
24 {
25 def = FixupDragResult(def);
26 if (!m_timer.IsRunning() && IsScroll(wxPoint(x, y))) {
27 m_timer.Start(100, true);
28 m_count = 0;
29 }
30 return def;
31 }
32
33 template<class Control>
OnLeave()34 void CScrollableDropTarget<Control>::OnLeave()
35 {
36 m_timer.Stop();
37 }
38
39 template<class Control>
OnEnter(wxCoord x,wxCoord y,wxDragResult def)40 wxDragResult CScrollableDropTarget<Control>::OnEnter(wxCoord x, wxCoord y, wxDragResult def)
41 {
42 def = FixupDragResult(def);
43 if (!m_timer.IsRunning() && IsScroll(wxPoint(x, y))) {
44 m_timer.Start(100, true);
45 m_count = 0;
46 }
47 return def;
48 }
49
50 template<class Control>
IsScroll(wxPoint p) const51 bool CScrollableDropTarget<Control>::IsScroll(wxPoint p) const
52 {
53 return IsTopScroll(p) || IsBottomScroll(p);
54 }
55
56 template<class Control>
IsTopScroll(wxPoint p) const57 bool CScrollableDropTarget<Control>::IsTopScroll(wxPoint p) const
58 {
59 if (!m_pCtrl->GetItemCount()) {
60 return false;
61 }
62
63 wxRect itemRect;
64 if (!m_pCtrl->GetItemRect(m_pCtrl->GetTopItem(), itemRect)) {
65 return false;
66 }
67
68 wxRect windowRect = m_pCtrl->GetActualClientRect();
69
70 if (itemRect.GetTop() < 0) {
71 itemRect.SetTop(0);
72 }
73 if (itemRect.GetHeight() > windowRect.GetHeight() / 4) {
74 itemRect.SetHeight(wxMax(windowRect.GetHeight() / 4, 8));
75 }
76
77 if (p.y < 0 || p.y >= itemRect.GetBottom()) {
78 return false;
79 }
80
81 if (p.x < 0 || p.x > windowRect.GetWidth()) {
82 return false;
83 }
84
85 auto top = m_pCtrl->GetTopItem();
86 if (!m_pCtrl->Valid(top) || top == m_pCtrl->GetFirstItem()) {
87 return false;
88 }
89
90 wxASSERT(m_pCtrl->GetTopItem() != m_pCtrl->GetFirstItem());
91
92 return true;
93 }
94
95 template<class Control>
IsBottomScroll(wxPoint p) const96 bool CScrollableDropTarget<Control>::IsBottomScroll(wxPoint p) const
97 {
98 if (!m_pCtrl->GetItemCount()) {
99 return false;
100 }
101
102 wxRect itemRect;
103 if (!m_pCtrl->GetItemRect(m_pCtrl->GetFirstItem(), itemRect)) {
104 return false;
105 }
106
107 wxRect const windowRect = m_pCtrl->GetActualClientRect();
108
109 int scrollHeight = itemRect.GetHeight();
110 if (scrollHeight > windowRect.GetHeight() / 4) {
111 scrollHeight = wxMax(windowRect.GetHeight() / 4, 8);
112 }
113
114 if (p.y > windowRect.GetBottom() || p.y < windowRect.GetBottom() - scrollHeight) {
115 return false;
116 }
117
118 if (p.x < 0 || p.x > windowRect.GetWidth()) {
119 return false;
120 }
121
122 auto bottom = m_pCtrl->GetBottomItem();
123 if (!m_pCtrl->Valid(bottom) || bottom == m_pCtrl->GetLastItem()) {
124 return false;
125 }
126
127 wxASSERT(m_pCtrl->GetLastItem() != m_pCtrl->GetBottomItem());
128
129 return true;
130 }
131
132 template<class Control>
OnTimer(wxTimerEvent &)133 void CScrollableDropTarget<Control>::OnTimer(wxTimerEvent& /*event*/)
134 {
135 if (!m_pCtrl->GetItemCount()) {
136 return;
137 }
138
139 wxPoint p = wxGetMousePosition();
140 wxWindow* ctrl = m_pCtrl->GetMainWindow();
141 p = ctrl->ScreenToClient(p);
142
143 if (IsTopScroll(p)) {
144 auto top = m_pCtrl->GetTopItem();
145 wxASSERT(m_pCtrl->Valid(top));
146 wxASSERT(top != m_pCtrl->GetFirstItem());
147 m_pCtrl->EnsureVisible(m_pCtrl->GetPrevItemSimple(top));
148 }
149 else if (IsBottomScroll(p)) {
150 auto bottom = m_pCtrl->GetBottomItem();
151 wxASSERT(m_pCtrl->Valid(bottom));
152 wxASSERT(bottom != m_pCtrl->GetLastItem());
153 m_pCtrl->EnsureVisible(m_pCtrl->GetNextItemSimple(bottom));
154 }
155 else {
156 return;
157 }
158
159 DisplayDropHighlight(p);
160
161 if (m_count < 90) {
162 ++m_count;
163 }
164 m_timer.Start(100 - m_count, true);
165 }
166
167 template<class Control>
FixupDragResult(wxDragResult res)168 wxDragResult CScrollableDropTarget<Control>::FixupDragResult(wxDragResult res)
169 {
170 #ifdef __WXMAC__
171 if (res == wxDragNone && wxGetKeyState(WXK_CONTROL)) {
172 res = wxDragCopy;
173 }
174 #endif
175
176 if (res == wxDragLink) {
177 res = wxGetKeyState(WXK_CONTROL) ? wxDragCopy : wxDragMove;
178 }
179
180 return res;
181 }
182
183 BEGIN_EVENT_TABLE_TEMPLATE1(CScrollableDropTarget, wxEvtHandler, Control)
184 EVT_TIMER(wxID_ANY, CScrollableDropTarget::OnTimer)
185 END_EVENT_TABLE()
186
187 template class CScrollableDropTarget<wxTreeCtrlEx>;
188 template class CScrollableDropTarget<wxListCtrlEx>;
189