1 // Copyright (C) 2015 Kazuhiro Fujieda <fujieda@users.osdn.me>
\r
3 // Licensed under the Apache License, Version 2.0 (the "License");
\r
4 // you may not use this file except in compliance with the License.
\r
5 // You may obtain a copy of the License at
\r
7 // http://www.apache.org/licenses/LICENSE-2.0
\r
9 // Unless required by applicable law or agreed to in writing, software
\r
10 // distributed under the License is distributed on an "AS IS" BASIS,
\r
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
12 // See the License for the specific language governing permissions and
\r
13 // limitations under the License.
\r
16 using System.Drawing;
\r
17 using System.Runtime.InteropServices;
\r
18 using System.Windows.Forms;
\r
19 using static System.Math;
\r
21 namespace KancolleSniffer.View
\r
23 public class SwipeScrollify
\r
25 private readonly MouseFilter _filter;
\r
27 public SwipeScrollify()
\r
29 _filter = new MouseFilter();
\r
30 Application.AddMessageFilter(_filter);
\r
33 public void AddPanel(Panel panel)
\r
35 var handler = new PanelHandler(panel);
\r
36 _filter.MouseDown += handler.MouseDown;
\r
37 _filter.MouseMove += handler.MouseMove;
\r
38 _filter.MouseUp += handler.MouseUp;
\r
41 public void AddShipListPanel(ShipListPanel panel)
\r
43 var handler = new ShipListPanelHandler(panel);
\r
44 _filter.MouseDown += handler.MouseDown;
\r
45 _filter.MouseMove += handler.MouseMove;
\r
46 _filter.MouseUp += handler.MouseUp;
\r
49 public void AddTreeView(TreeView treeView)
\r
51 var handler = new TreeViewHandler(treeView);
\r
52 _filter.MouseDown += handler.MouseDown;
\r
53 _filter.MouseMove += handler.MouseMove;
\r
54 _filter.MouseUp += handler.MouseUp;
\r
57 private class MouseFilter : IMessageFilter
\r
59 public delegate void MouseHandler(IntPtr handle, ref bool handled);
\r
61 public event MouseHandler MouseMove, MouseDown, MouseUp;
\r
63 // ReSharper disable InconsistentNaming
\r
64 // ReSharper disable IdentifierTypo
\r
65 private const int WM_MOUSEMOVE = 0x0200;
\r
66 private const int WM_LBUTTONDOWN = 0x0201;
\r
68 private const int WM_LBUTTONUP = 0x0202;
\r
69 // ReSharper restore IdentifierTypo
\r
70 // ReSharper restore InconsistentNaming
\r
72 public bool PreFilterMessage(ref Message m)
\r
74 var handled = false;
\r
77 case WM_LBUTTONDOWN:
\r
78 MouseDown?.Invoke(m.HWnd, ref handled);
\r
81 MouseMove?.Invoke(m.HWnd, ref handled);
\r
84 MouseUp?.Invoke(m.HWnd, ref handled);
\r
91 private class PanelHandler
\r
93 private readonly Panel _panel;
\r
94 private bool _touch;
\r
95 private Point _mouseStart;
\r
96 private Point _panelStart;
\r
97 private Point _scrollStart;
\r
98 private const int ScrollCount = 6;
\r
100 public PanelHandler(Panel panel)
\r
105 public void MouseDown(IntPtr handle, ref bool handled)
\r
107 if (!_mouseStart.IsEmpty)
\r
109 if (!_panel.RectangleToScreen(_panel.ClientRectangle).Contains(Control.MousePosition))
\r
112 for (var control = Control.FromHandle(handle); control != null; control = control.Parent)
\r
114 if (control != _panel)
\r
121 _mouseStart = _scrollStart = Control.MousePosition;
\r
122 _panelStart = _panel.AutoScrollPosition;
\r
125 public void MouseMove(IntPtr handle, ref bool handled)
\r
127 if (_mouseStart.IsEmpty)
\r
129 var cur = Control.MousePosition;
\r
130 var dx = cur.X - _mouseStart.X;
\r
131 var dy = cur.Y - _mouseStart.Y;
\r
134 if (!(Abs(dx) > ScrollCount || Abs(dy) > ScrollCount))
\r
138 if (Abs(_scrollStart.X - cur.X) > ScrollCount || Abs(_scrollStart.Y - cur.Y) > ScrollCount)
\r
140 _panel.AutoScrollPosition = new Point(-_panelStart.X - dx, -_panelStart.Y - dy);
\r
141 _scrollStart = cur;
\r
145 public void MouseUp(IntPtr handle, ref bool handled)
\r
148 _mouseStart = _panelStart = Point.Empty;
\r
152 private class ShipListPanelHandler
\r
154 private readonly ShipListPanel _panel;
\r
155 private bool _touch;
\r
156 private Point _mouseStart;
\r
157 private int _barStart = -1;
\r
158 private Point _scrollStart;
\r
159 private const int ScrollCount = ShipListPanel.LineHeight;
\r
161 public ShipListPanelHandler(ShipListPanel panel)
\r
166 public void MouseDown(IntPtr handle, ref bool handled)
\r
168 if (!_panel.ScrollBar.Visible)
\r
170 if (!_mouseStart.IsEmpty)
\r
172 if (!_panel.RectangleToScreen(_panel.ClientRectangle).Contains(Control.MousePosition) ||
\r
173 _panel.ScrollBar.RectangleToScreen(_panel.ScrollBar.ClientRectangle)
\r
174 .Contains(Control.MousePosition))
\r
177 for (var control = Control.FromHandle(handle); control != null; control = control.Parent)
\r
179 if (control != _panel)
\r
186 _mouseStart = _scrollStart = Control.MousePosition;
\r
187 _barStart = _panel.ScrollBar.Value;
\r
190 public void MouseMove(IntPtr handle, ref bool handled)
\r
192 if (_mouseStart.IsEmpty)
\r
194 var cur = Control.MousePosition;
\r
195 var dy = cur.Y - _mouseStart.Y;
\r
198 if (Abs(dy) <= ScrollCount)
\r
202 if (Abs(_scrollStart.Y - cur.Y) > ScrollCount)
\r
204 var bar = _panel.ScrollBar;
\r
205 bar.Value = Max(0, Min(bar.Maximum - bar.LargeChange + 1, _barStart - dy / ScrollCount));
\r
206 _scrollStart = cur;
\r
210 public void MouseUp(IntPtr handle, ref bool handled)
\r
214 _mouseStart = Point.Empty;
\r
218 private class TreeViewHandler
\r
220 private readonly TreeView _treeView;
\r
221 private bool _touch;
\r
222 private Point _mouseStart;
\r
223 private Point _panelStart;
\r
225 [DllImport("user32.dll")]
\r
226 private static extern int GetScrollPos(IntPtr hWnd, int nBar);
\r
228 [DllImport("user32.dll")]
\r
229 private static extern int SetScrollPos(IntPtr hWnd, int nBar, int nPos, bool bRedraw);
\r
231 // ReSharper disable InconsistentNaming
\r
232 // ReSharper disable IdentifierTypo
\r
233 private const int GWL_STYLE = -16;
\r
234 private const int WS_HSCROLL = 0x00100000;
\r
236 private const int WS_VSCROLL = 0x00200000;
\r
237 // ReSharper restore IdentifierTypo
\r
238 // ReSharper restore InconsistentNaming
\r
240 [DllImport("user32.dll")]
\r
241 private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
\r
243 public TreeViewHandler(TreeView treeView)
\r
245 _treeView = treeView;
\r
248 public void MouseDown(IntPtr handle, ref bool handled)
\r
250 if (!_mouseStart.IsEmpty)
\r
252 var control = Control.FromHandle(handle);
\r
253 if (control == null || control != _treeView)
\r
255 if (!_treeView.RectangleToScreen(_treeView.ClientRectangle).Contains(Control.MousePosition))
\r
257 var loc = _treeView.HitTest(_treeView.PointToClient(Control.MousePosition)).Location;
\r
258 // アイテムをクリックするとWM_LBUTTONUPが来ないので避ける
\r
259 if (loc == TreeViewHitTestLocations.Label || loc == TreeViewHitTestLocations.Image)
\r
261 _mouseStart = Control.MousePosition;
\r
262 _panelStart = ScrollPosition();
\r
265 public void MouseMove(IntPtr handle, ref bool handled)
\r
267 if (_mouseStart.IsEmpty)
\r
269 if (!_treeView.RectangleToScreen(_treeView.ClientRectangle).Contains(Control.MousePosition))
\r
271 // TreeViewではうまく動かないので外に出たら止める
\r
273 _mouseStart = _panelStart = Point.Empty;
\r
276 var cur = Control.MousePosition;
\r
277 var dx = cur.X - _mouseStart.X;
\r
278 var dy = cur.Y - _mouseStart.Y;
\r
279 var style = GetWindowLong(_treeView.Handle, GWL_STYLE);
\r
282 _treeView.BeginUpdate();
\r
283 if ((style & WS_HSCROLL) != 0)
\r
284 SetScrollPos(_treeView.Handle, 0, _panelStart.X - dx, true);
\r
285 if ((style & WS_VSCROLL) != 0)
\r
286 SetScrollPos(_treeView.Handle, 1, _panelStart.Y - dy / _treeView.ItemHeight, true);
\r
287 _treeView.EndUpdate();
\r
290 else if (Abs(dx) > 5 || Abs(dy) > 5)
\r
294 public void MouseUp(IntPtr handle, ref bool handled)
\r
296 if (_touch && !_panelStart.IsEmpty && _panelStart != ScrollPosition())
\r
299 _mouseStart = _panelStart = Point.Empty;
\r
302 private Point ScrollPosition()
\r
304 return new Point(GetScrollPos(_treeView.Handle, 0), GetScrollPos(_treeView.Handle, 1));
\r