1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/univ/scrarrow.cpp
3 // Purpose: wxScrollArrows class implementation
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 22.01.01
7 // Copyright: (c) 2001 SciTech Software, Inc. (www.scitechsoft.com)
8 // Licence: wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 #include "wx/wxprec.h"
20
21
22 #ifndef WX_PRECOMP
23 #include "wx/window.h"
24 #endif
25
26 #include "wx/univ/scrtimer.h"
27 #include "wx/univ/scrarrow.h"
28
29 #include "wx/univ/renderer.h"
30 #include "wx/univ/inphand.h"
31 #include "wx/univ/theme.h"
32
33 #if wxUSE_SCROLLBAR
34 // ----------------------------------------------------------------------------
35 // wxScrollArrowCaptureData: contains the data used while the arrow is being
36 // pressed by the user
37 // ----------------------------------------------------------------------------
38
39 struct wxScrollArrowCaptureData
40 {
wxScrollArrowCaptureDatawxScrollArrowCaptureData41 wxScrollArrowCaptureData()
42 {
43 m_arrowPressed = wxScrollArrows::Arrow_None;
44 m_window = NULL;
45 m_btnCapture = -1;
46 #if wxUSE_TIMER
47 m_timerScroll = NULL;
48 #endif // wxUSE_TIMER
49 }
50
~wxScrollArrowCaptureDatawxScrollArrowCaptureData51 ~wxScrollArrowCaptureData()
52 {
53 if ( m_window )
54 m_window->ReleaseMouse();
55
56 #if wxUSE_TIMER
57 delete m_timerScroll;
58 #endif // wxUSE_TIMER
59 }
60
61 // the arrow being held pressed (may be Arrow_None)
62 wxScrollArrows::Arrow m_arrowPressed;
63
64 // the mouse button which started the capture (-1 if none)
65 int m_btnCapture;
66
67 // the window which has captured the mouse
68 wxWindow *m_window;
69
70 #if wxUSE_TIMER
71 // the timer for generating the scroll events
72 wxScrollTimer *m_timerScroll;
73 #endif
74 };
75
76 // ----------------------------------------------------------------------------
77 // wxScrollArrowTimer: a wxScrollTimer which calls OnArrow()
78 // ----------------------------------------------------------------------------
79
80 #if wxUSE_TIMER
81
82 class wxScrollArrowTimer : public wxScrollTimer
83 {
84 public:
wxScrollArrowTimer(wxControlWithArrows * control,wxScrollArrows::Arrow arrow)85 wxScrollArrowTimer(wxControlWithArrows *control,
86 wxScrollArrows::Arrow arrow)
87 {
88 m_control = control;
89 m_arrow = arrow;
90
91 StartAutoScroll();
92 }
93
94 protected:
DoNotify()95 virtual bool DoNotify()
96 {
97 return m_control->OnArrow(m_arrow);
98 }
99
100 wxControlWithArrows *m_control;
101 wxScrollArrows::Arrow m_arrow;
102 };
103
104 #endif // wxUSE_TIMER
105
106 // ============================================================================
107 // implementation of wxScrollArrows
108 // ============================================================================
109
110 // ----------------------------------------------------------------------------
111 // con/destruction
112 // ----------------------------------------------------------------------------
113
wxScrollArrows(wxControlWithArrows * control)114 wxScrollArrows::wxScrollArrows(wxControlWithArrows *control)
115 {
116 m_control = control;
117 m_captureData = NULL;
118 }
119
~wxScrollArrows()120 wxScrollArrows::~wxScrollArrows()
121 {
122 // it should have been destroyed
123 wxASSERT_MSG( !m_captureData, wxT("memory leak in wxScrollArrows") );
124 }
125
126 // ----------------------------------------------------------------------------
127 // drawing
128 // ----------------------------------------------------------------------------
129
DrawArrow(Arrow arrow,wxDC & dc,const wxRect & rect,bool scrollbarLike) const130 void wxScrollArrows::DrawArrow(Arrow arrow,
131 wxDC& dc,
132 const wxRect& rect,
133 bool scrollbarLike) const
134 {
135 static const wxDirection arrowDirs[2][Arrow_Max] =
136 {
137 { wxLEFT, wxRIGHT },
138 { wxUP, wxDOWN }
139 };
140
141 if ( scrollbarLike )
142 m_control->GetRenderer()->DrawScrollbarArrow(
143 dc,
144 arrowDirs[m_control->IsVertical()][arrow],
145 rect,
146 m_control->GetArrowState(arrow));
147 else
148 m_control->GetRenderer()->DrawArrow(
149 dc,
150 arrowDirs[m_control->IsVertical()][arrow],
151 rect,
152 m_control->GetArrowState(arrow));
153 }
154
155 // ----------------------------------------------------------------------------
156 // input handling
157 // ----------------------------------------------------------------------------
158
UpdateCurrentFlag(Arrow arrow,Arrow arrowCur) const159 void wxScrollArrows::UpdateCurrentFlag(Arrow arrow, Arrow arrowCur) const
160 {
161 m_control->SetArrowFlag(arrow, wxCONTROL_CURRENT, arrow == arrowCur);
162 }
163
HandleMouseMove(const wxMouseEvent & event) const164 bool wxScrollArrows::HandleMouseMove(const wxMouseEvent& event) const
165 {
166 Arrow arrow;
167 if ( event.Leaving() )
168 {
169 // no arrow has mouse if it left the window completely
170 arrow = Arrow_None;
171 }
172 else // Moving() or Entering(), treat them the same here
173 {
174 arrow = m_control->HitTestArrow(event.GetPosition());
175 }
176
177 #if wxUSE_TIMER
178 if ( m_captureData && m_captureData->m_timerScroll)
179 {
180 // the mouse is captured, we may want to pause scrolling if it goes
181 // outside the arrow or to resume it if we had paused it before
182 wxTimer *timer = m_captureData->m_timerScroll;
183 if ( !timer->IsRunning() )
184 {
185 // timer is paused
186 if ( arrow == m_captureData->m_arrowPressed )
187 {
188 // resume now
189 m_control->SetArrowFlag(arrow, wxCONTROL_PRESSED, true);
190 timer->Start();
191
192 return true;
193 }
194 }
195 else // if ( 1 ) FIXME: m_control->ShouldPauseScrolling() )
196 {
197 // we may want to stop it
198 if ( arrow != m_captureData->m_arrowPressed )
199 {
200 // stop as the mouse left the arrow
201 m_control->SetArrowFlag(m_captureData->m_arrowPressed,
202 wxCONTROL_PRESSED, false);
203 timer->Stop();
204
205 return true;
206 }
207 }
208
209 return false;
210 }
211 #endif // wxUSE_TIMER
212
213 // reset the wxCONTROL_CURRENT flag for the arrows which don't have the
214 // mouse and set it for the one which has
215 UpdateCurrentFlag(Arrow_First, arrow);
216 UpdateCurrentFlag(Arrow_Second, arrow);
217
218 // return true if it was really an event for an arrow
219 return !event.Leaving() && arrow != Arrow_None;
220 }
221
HandleMouse(const wxMouseEvent & event) const222 bool wxScrollArrows::HandleMouse(const wxMouseEvent& event) const
223 {
224 int btn = event.GetButton();
225 if ( btn == -1 )
226 {
227 // we only care about button press/release events
228 return false;
229 }
230
231 if ( event.ButtonDown() || event.ButtonDClick() )
232 {
233 if ( !m_captureData )
234 {
235 Arrow arrow = m_control->HitTestArrow(event.GetPosition());
236 if ( arrow == Arrow_None )
237 {
238 // mouse pressed over something else
239 return false;
240 }
241
242 if ( m_control->GetArrowState(arrow) & wxCONTROL_DISABLED )
243 {
244 // don't allow to press disabled arrows
245 return true;
246 }
247
248 wxConstCast(this, wxScrollArrows)->m_captureData =
249 new wxScrollArrowCaptureData;
250 m_captureData->m_arrowPressed = arrow;
251 m_captureData->m_btnCapture = btn;
252 m_captureData->m_window = m_control->GetWindow();
253 m_captureData->m_window->CaptureMouse();
254
255 #if wxUSE_TIMER
256 // start scrolling
257 wxScrollArrowTimer *tmpTimerScroll =
258 new wxScrollArrowTimer(m_control, arrow);
259 #endif // wxUSE_TIMER
260
261 // Because in some cases wxScrollArrowTimer can cause
262 // m_captureData to be destructed we need to test if it
263 // is still valid before using.
264 if (m_captureData)
265 {
266 #if wxUSE_TIMER
267 m_captureData->m_timerScroll = tmpTimerScroll;
268 #endif // wxUSE_TIMER
269
270 m_control->SetArrowFlag(arrow, wxCONTROL_PRESSED, true);
271 }
272 else
273 {
274 #if wxUSE_TIMER
275 delete tmpTimerScroll;
276 #endif // wxUSE_TIMER
277 }
278 }
279 //else: mouse already captured, nothing to do
280 }
281 // release mouse if the *same* button went up
282 else if ( m_captureData && (btn == m_captureData->m_btnCapture) )
283 {
284 Arrow arrow = m_captureData->m_arrowPressed;
285
286 delete m_captureData;
287 wxConstCast(this, wxScrollArrows)->m_captureData = NULL;
288
289 m_control->SetArrowFlag(arrow, wxCONTROL_PRESSED, false);
290 }
291 else
292 {
293 // we don't process this
294 return false;
295 }
296
297 return true;
298 }
299 #endif // wxUSE_SCROLLBAR
300