Audacity 3.2.0
Grabber.cpp
Go to the documentation of this file.
1/**********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 Grabber.cpp
6
7 Leland Lucius
8
9*******************************************************************//*******************************************************************//**********************************************************************/
22
23
24#include "Grabber.h"
25
26#include <wx/defs.h>
27#include <wx/dcclient.h>
28#include <wx/window.h>
29
30#include "AColor.h"
31#include "AllThemeResources.h"
32#include "Internat.h"
33#include "Theme.h"
34
38
39DEFINE_EVENT_TYPE(EVT_GRABBER_CLICKED)
40
41BEGIN_EVENT_TABLE(Grabber, wxWindow)
42 EVT_ENTER_WINDOW(Grabber::OnEnter)
43 EVT_LEAVE_WINDOW(Grabber::OnLeave)
44 EVT_LEFT_DOWN(Grabber::OnLeftDown)
45 EVT_LEFT_UP(Grabber::OnLeftUp)
46 EVT_ERASE_BACKGROUND( Grabber::OnErase )
47 EVT_PAINT(Grabber::OnPaint)
48 EVT_KEY_DOWN(Grabber::OnKeyDown)
50
51//
52// Constructor
53//
54Grabber::Grabber(wxWindow * parent, Identifier id)
55: wxWindow(parent,
56 wxID_ANY,
57 wxDefaultPosition,
58 wxSize(grabberWidth, 27),
59 wxFULL_REPAINT_ON_RESIZE)
60, mIdentifier{ id }
61{
62 mOver = false;
63 mPressed = false;
64 mAsSpacer = false;
65 SetBackgroundColour( theTheme.Colour( clrMedium ) );
66
67 /* i18n-hint: A 'Grabber' is a region you can click and drag on
68 It's used to drag a track around (when in multi-tool mode) rather
69 than requiring that you use the drag tool. It's shown as a series
70 of horizontal bumps */
71 SetLabel(_("Grabber"));
72 SetName(_("Grabber"));
73}
74
75//
76// Destructor
77//
79{
80}
81
82//
83// Queue a drag event
84//
85void Grabber::SendEvent(wxEventType type, const wxPoint & pos, bool escaping)
86{
87 wxWindow *parent = GetParent();
88
89 // Initialize event and convert mouse coordinates to screen space
90 GrabberEvent e(type, mIdentifier, parent->ClientToScreen(pos), escaping);
91
92 // Set the object of our desire
93 e.SetEventObject(parent);
94
95 // Queue the event
96 parent->GetEventHandler()->AddPendingEvent(e);
97}
98
99void Grabber::SetAsSpacer( bool bIsSpacer ) {
100 if( mAsSpacer != bIsSpacer ){
101 // HACK: Use a wider rectangle to also cover one pixel of space just to the right.
102 wxSize siz = GetSize();
103 siz.IncBy( bIsSpacer ? 1:-1, 0 );
104 SetSize( siz );
105 }
106 mAsSpacer = bIsSpacer;
107};
108
110{
111 wxWindow::SetToolTip( toolTip.Stripped().Translation() );
112}
113
114//
115// Draw the grabber
116//
117void Grabber::DrawGrabber( wxDC & dc )
118{
119 wxRect r = GetRect();
120 // PaintDC positions are relative to the grabber, not the parent window.
121 // So use 0,0 as origin for draw, so that the grabber draws right if
122 // positioned in its parent at some non zero position.
123 r.SetPosition( wxPoint(0,0) );
124 int y, left, right, top, bottom;
125
126 AColor::Medium(&dc, mOver );
127 dc.DrawRectangle(r);
128
129 // HACK: We used a wider rectangle to also cover one pixel of space just to the right.
130 if( mAsSpacer )
131 r.width -= 1;
132
133#ifndef __WXMAC__
134
135 // Add a box
136 r.width -= 1;
137 r.height -= 1;
138 AColor::Bevel(dc, !mPressed, r);
139 r.width += 1;
140 r.height += 1;
141
142#endif
143
144 // No bumps in a spacer grabber.
145 if( mAsSpacer )
146 return;
147 // Calculate the bump rectangle
148 r.Deflate(3, 3);
149 if ((r.GetHeight() % 4) < 2) {
150 r.Offset(0, 1);
151 }
152
153 // Cache
154 left = r.GetLeft();
155 right = r.GetRight();
156 top = r.GetTop();
157 bottom = r.GetBottom();
158
159 // Draw the raised bumps
160 if (mPressed) {
161 AColor::Dark(&dc, false);
162 }
163 else {
164 AColor::Light(&dc, false);
165 }
166
167 for (y = top; y < bottom; y += 4) {
168 AColor::Line(dc, left, y, right, y);
169 }
170
171 // Draw the pushed bumps
172 if (mPressed) {
173 AColor::Light(&dc, false);
174 }
175 else {
176 AColor::Dark(&dc, false);
177 }
178
179 for (y = top + 1; y <= bottom; y += 4) {
180 AColor::Line(dc, left, y, right, y);
181 }
182}
183
184//
185// Change the button state
186//
187void Grabber::PushButton(bool state )
188{
189 if( mAsSpacer )
190 return;
191 if (!state)
192 mPressed = state;
193 wxRect r = GetRect();
194 mOver = r.Contains(ScreenToClient(wxGetMousePosition()));
195
196 // Redraw button
197 mPressed = state;
198 Refresh(false);
199}
200
201//
202// Handle left button down events
203//
204void Grabber::OnLeftDown(wxMouseEvent & event)
205{
206 // Button should be drawn pushed
207 PushButton(true);
208
209 // Notify parent
210 SendEvent(EVT_GRABBER_CLICKED, event.GetPosition(), false);
211
212 event.Skip();
213}
214
215//
216// Handle left button up events
217//
218void Grabber::OnLeftUp(wxMouseEvent & event)
219{
220 // Normally, "left up" events are handled by the ToolManager::OnMouse() method
221 // but, if the user double clicks a grabber, the "left up" event will come here
222 // instead, so just "unpush" the button.
223 PushButton(false);
224
225 event.Skip();
226}
227
228//
229// Handle mouse enter events
230//
231void Grabber::OnEnter(wxMouseEvent & WXUNUSED(event))
232{
233#if defined(__WXMAC__)
234 // Bug 2416: On Mac, we can get Enter events from grabbers other
235 // than the one being dragged. So, ignore Enter events if another
236 // window has captured the mouse.
237 if (wxWindow::GetCapture() != nullptr)
238 {
239 return;
240 }
241#endif
242
243 // Bug 1201: On Mac, unsetting and re-setting the tooltip may be needed
244 // to make it pop up when we want it.
245 const auto text = GetToolTipText();
246 UnsetToolTip();
247 wxWindow::SetToolTip(text);
248
249 if( mAsSpacer )
250 return;
251
252 // Redraw highlighted
253 mOver = true;
254 Refresh(false);
255}
256
257//
258// Handle mouse leave events
259//
260void Grabber::OnLeave(wxMouseEvent & WXUNUSED(event))
261{
262#if defined(__WXMAC__)
263 // Bug 2416: On Mac, we can get Leave events from grabbers other
264 // than the one being dragged. So, ignore Leave events if another
265 // window has captured the mouse.
266 if (wxWindow::GetCapture() != nullptr)
267 {
268 return;
269 }
270#endif
271
272 if (!GetCapture()) {
273 // Redraw plain
274 mOver = false;
275 Refresh(false);
276 }
277}
278
279void Grabber::OnErase( wxEraseEvent & WXUNUSED(event) )
280{
281 // Ignore it to prevent flashing
282}
283
284//
285// Handle the paint events
286//
287void Grabber::OnPaint(wxPaintEvent & WXUNUSED(event))
288{
289 wxPaintDC dc(this);
290
291 // Redraw the grabber
292 DrawGrabber(dc);
293}
294
295void Grabber::OnKeyDown(wxKeyEvent &event)
296{
297 event.Skip();
298
299 if(event.GetKeyCode() == WXK_ESCAPE) {
300 // We must not only skip this key event, but propagate it up the window
301 // hierarchy, so that ToolFrame detects it too.
302 event.ResumePropagation(wxEVENT_PROPAGATE_MAX);
303 SendEvent(EVT_GRABBER_CLICKED, wxPoint{ -1, -1 }, true);
304 }
305}
306
307// Piggy back in same source file as Grabber.
308// Audacity Flicker-free StaticBitmap.
309BEGIN_EVENT_TABLE(AStaticBitmap,wxStaticBitmap)
310 EVT_ERASE_BACKGROUND(AStaticBitmap::OnErase)
312
313
END_EVENT_TABLE()
DEFINE_EVENT_TYPE(EVT_FREQWINDOW_RECALC)
#define grabberWidth
Definition: Grabber.h:104
#define _(s)
Definition: Internat.h:73
THEME_API Theme theTheme
Definition: Theme.cpp:82
static void Line(wxDC &dc, wxCoord x1, wxCoord y1, wxCoord x2, wxCoord y2)
Definition: AColor.cpp:187
static void Bevel(wxDC &dc, bool up, const wxRect &r)
Definition: AColor.cpp:266
static void Light(wxDC *dc, bool selected, bool highlight=false)
Definition: AColor.cpp:413
static void Dark(wxDC *dc, bool selected, bool highlight=false)
Definition: AColor.cpp:443
static void Medium(wxDC *dc, bool selected)
Definition: AColor.cpp:424
A widget for bitmaps which ignores the erase event for flicker-free use.
Definition: Grabber.h:155
void OnErase(wxEraseEvent &event)
Definition: Grabber.h:173
Grabber Class.
Definition: Grabber.h:48
The widget to the left of a ToolBar that allows it to be dragged around to NEW positions.
Definition: Grabber.h:107
void SendEvent(wxEventType type, const wxPoint &pos, bool escaping)
Definition: Grabber.cpp:85
void OnLeftUp(wxMouseEvent &event)
Definition: Grabber.cpp:218
void SetAsSpacer(bool bIsSpacer)
Definition: Grabber.cpp:99
bool mAsSpacer
Definition: Grabber.h:146
void DrawGrabber(wxDC &dc)
Definition: Grabber.cpp:117
virtual ~Grabber()
Definition: Grabber.cpp:78
void OnLeave(wxMouseEvent &event)
Definition: Grabber.cpp:260
bool mOver
Definition: Grabber.h:144
void OnErase(wxEraseEvent &event)
Definition: Grabber.cpp:279
const Identifier mIdentifier
Definition: Grabber.h:143
void OnPaint(wxPaintEvent &event)
Definition: Grabber.cpp:287
void OnLeftDown(wxMouseEvent &event)
Definition: Grabber.cpp:204
void OnKeyDown(wxKeyEvent &event)
Definition: Grabber.cpp:295
void OnEnter(wxMouseEvent &event)
Definition: Grabber.cpp:231
bool mPressed
Definition: Grabber.h:145
void SetToolTip(const TranslatableString &toolTip)
Definition: Grabber.cpp:109
void PushButton(bool state)
Definition: Grabber.cpp:187
An explicitly nonlocalized string, not meant for the user to see.
Definition: Identifier.h:22
wxColour & Colour(int iIndex)
Holds a msgid for the translation catalog; may also bind format arguments.
wxString Translation() const
TranslatableString Stripped(unsigned options=MenuCodes) const
non-mutating, constructs another TranslatableString object