Audacity 3.2.0
MovableControl.cpp
Go to the documentation of this file.
1/*!********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 @file MovableControl.cpp
6
7 @author Vitaly Sverchinsky
8
9**********************************************************************/
10
11#include "MovableControl.h"
12#include <wx/sizer.h>
13#include <wx/wupdlock.h>
14
15wxDEFINE_EVENT(EVT_MOVABLE_CONTROL_DRAG_STARTED, MovableControlEvent);
16wxDEFINE_EVENT(EVT_MOVABLE_CONTROL_DRAG_POSITION, MovableControlEvent);
17wxDEFINE_EVENT(EVT_MOVABLE_CONTROL_DRAG_FINISHED, MovableControlEvent);
18
19MovableControlEvent::MovableControlEvent(wxEventType eventType, int winid)
20 : wxCommandEvent(eventType, winid)
21{
22}
23
25{
26 mSourceIndex = index;
27}
28
30{
31 return mSourceIndex;
32}
33
35{
36 mTargetIndex = index;
37}
39{
40 return mTargetIndex;
41}
42
44{
45 return new MovableControlEvent(*this);
46}
47
49 wxWindowID id,
50 const wxPoint& pos,
51 const wxSize& size,
52 long style,
53 const wxString& name)
54{
55 Create(parent, id, pos, size, style, name);
56}
57
58void MovableControl::Create(wxWindow* parent,
59 wxWindowID id,
60 const wxPoint& pos,
61 const wxSize& size,
62 long style,
63 const wxString& name)
64{
65 wxWindow::Create(parent, id, pos, size, style, name);
66 Bind(wxEVT_LEFT_DOWN, &MovableControl::OnMouseDown, this);
67 Bind(wxEVT_LEFT_UP, &MovableControl::OnMouseUp, this);
68 Bind(wxEVT_MOTION, &MovableControl::OnMove, this);
69 Bind(wxEVT_KEY_DOWN, &MovableControl::OnKeyDown, this);
70 Bind(wxEVT_MOUSE_CAPTURE_LOST, &MovableControl::OnMouseCaptureLost, this);
71}
72
73void MovableControl::ProcessDragEvent(wxWindow* target, wxEventType eventType)
74{
75 MovableControlEvent event(eventType);
76 event.SetSourceIndex(mSourceIndex);
77 event.SetTargetIndex(mTargetIndex);
78 event.SetEventObject(this);
79 target->GetEventHandler()->ProcessEvent(event);
80}
81
83{
84 auto parent = GetParent();
85 if(!parent)
86 return -1;
87
88 if(auto sizer = parent->GetSizer())
89 {
90 for(size_t i = 0, count = sizer->GetItemCount(); i < count; ++i)
91 {
92 if(sizer->GetItem(i)->GetWindow() == this)
93 return static_cast<int>(i);
94 }
95 }
96 return -1;
97}
98
99void MovableControl::OnKeyDown(wxKeyEvent& evt)
100{
101 const auto keyCode = evt.GetKeyCode();
102 if(evt.AltDown() && (keyCode == WXK_DOWN || keyCode == WXK_UP))
103 {
104#ifdef __WXOSX__
105 {//don't allow auto-repeats
106 static long lastEventTimestamp = 0;
107 if(lastEventTimestamp == evt.GetTimestamp())
108 return;//don't skip
109 lastEventTimestamp = evt.GetTimestamp();
110 }
111#endif
112 const auto sourceIndex = FindIndexInParent();
113 if(sourceIndex == -1)
114 {
115 evt.Skip();
116 return;
117 }
118
119 const auto targetIndex = std::clamp(
120 keyCode == WXK_DOWN ? sourceIndex + 1 : sourceIndex - 1,
121 0,
122 static_cast<int>(GetParent()->GetSizer()->GetItemCount()) - 1
123 );
124 if(sourceIndex != targetIndex)
125 {
126 mSourceIndex = sourceIndex;
127 mTargetIndex = targetIndex;
128 ProcessDragEvent(GetParent(), EVT_MOVABLE_CONTROL_DRAG_FINISHED);
129 }
130 }
131 else
132 evt.Skip();
133}
134
135void MovableControl::OnMouseCaptureLost(wxMouseCaptureLostEvent& event)
136{
137 if(mDragging)
138 DragFinished();
139}
140
142{
143 if(auto parent = GetParent())
144 {
145 wxWindowUpdateLocker freeze(this);
146 ProcessDragEvent(parent, EVT_MOVABLE_CONTROL_DRAG_FINISHED);
147 }
148 mDragging = false;
149}
150
151void MovableControl::OnMouseDown(wxMouseEvent& evt)
152{
153 if(mDragging)
154 {
155 DragFinished();
156 return;
157 }
158
160 if(mSourceIndex != -1)
161 {
162 CaptureMouse();
163 ProcessDragEvent(GetParent(), EVT_MOVABLE_CONTROL_DRAG_STARTED);
164
165 mInitialPosition = evt.GetPosition();
166 mDragging=true;
167 }
168}
169
170void MovableControl::OnMouseUp(wxMouseEvent& evt)
171{
172 if(!mDragging)
173 return;
174
175 ReleaseMouse();
176
177 DragFinished();
178}
179
180void MovableControl::OnMove(wxMouseEvent& evt)
181{
182 if(!mDragging)
183 return;
184
185 auto parent = GetParent();
186 if(!parent)
187 return;
188
189 wxPoint newPosition = wxGetMousePosition() - mInitialPosition;
190 Move(GetParent()->ScreenToClient(newPosition));
191
192 if(auto boxSizer = dynamic_cast<wxBoxSizer*>(parent->GetSizer()))
193 {
194 if(boxSizer->GetOrientation() == wxVERTICAL)
195 {
196 auto targetIndex = mSourceIndex;
197
198 //assuming that items are ordered from top to bottom (i > j <=> y(i) > y(j))
199 //compare wxSizerItem position with the current MovableControl position!
200 if(GetPosition().y < boxSizer->GetItem(mSourceIndex)->GetPosition().y)
201 {
202 //moving up
203 for(int i = 0; i < mSourceIndex; ++i)
204 {
205 const auto item = boxSizer->GetItem(i);
206
207 if(GetRect().GetTop() <= item->GetPosition().y + item->GetSize().y / 2)
208 {
209 targetIndex = i;
210 break;
211 }
212 }
213 }
214 else
215 {
216 //moving down
217 for(int i = static_cast<int>(boxSizer->GetItemCount()) - 1; i > mSourceIndex; --i)
218 {
219 const auto item = boxSizer->GetItem(i);
220 if(GetRect().GetBottom() >= item->GetPosition().y + item->GetSize().y / 2)
221 {
222 targetIndex = i;
223 break;
224 }
225 }
226 }
227
228 if(targetIndex != mTargetIndex)
229 {
230 mTargetIndex = targetIndex;
231 ProcessDragEvent(parent, EVT_MOVABLE_CONTROL_DRAG_POSITION);
232 }
233 }
234 }
235}
wxDEFINE_EVENT(EVT_MOVABLE_CONTROL_DRAG_STARTED, MovableControlEvent)
wxString name
Definition: TagsEditor.cpp:166
void SetTargetIndex(int index) noexcept
int GetSourceIndex() const noexcept
wxEvent * Clone() const override
int GetTargetIndex() const noexcept
void SetSourceIndex(int index) noexcept
MovableControlEvent(wxEventType eventType, int winid=0)
void OnMouseCaptureLost(wxMouseCaptureLostEvent &event)
void OnMove(wxMouseEvent &evt)
wxPoint mInitialPosition
MovableControl()=default
void Create(wxWindow *parent, wxWindowID id, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=0, const wxString &name=wxPanelNameStr)
void OnKeyDown(wxKeyEvent &evt)
void OnMouseUp(wxMouseEvent &evt)
int FindIndexInParent() const
void ProcessDragEvent(wxWindow *target, wxEventType eventType)
void OnMouseDown(wxMouseEvent &evt)