forked from Sneeds-Feed-and-Seed/sneedacity
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUIHandle.h
164 lines (134 loc) · 6 KB
/
UIHandle.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/**********************************************************************
Sneedacity: A Digital Audio Editor
UIHandle.h
Paul Licameli
**********************************************************************/
#ifndef __SNEEDACITY_UI_HANDLE__
#define __SNEEDACITY_UI_HANDLE__
#include <utility>
#include <memory>
#include "TrackPanelDrawable.h" // to inherit
class wxDC;
class wxRect;
class wxRegion;
class wxWindow;
class SneedacityProject;
struct HitTestPreview;
class TrackPanelCell;
struct TrackPanelMouseEvent;
struct TrackPanelMouseState;
/// \brief Short-lived drawing and event-handling object associated with a TrackPanelCell
// A TrackPanelCell reports a handle object of some subclass, in response to a
// hit test at a mouse position; then this handle processes certain events,
// and maintains necessary state through click-drag-release event sequences.
class SNEEDACITY_DLL_API UIHandle /* not final */ : public TrackPanelDrawable
{
public:
// See RefreshCode.h for bit flags:
using Result = unsigned;
// Future: may generalize away from current Track class
using Cell = TrackPanelCell;
virtual ~UIHandle() = 0;
// Before clicking, the handle is notified that it has been "hit"
// This might put the handle into its first rotated state
// (or last, if forward is false) or mark itself as needing a highlight.
// Default does nothing.
virtual void Enter(bool forward, SneedacityProject *pProject);
// Tell whether the handle has more than one TAB key rotation state.
// Default is always false.
virtual bool HasRotation() const;
// If not previously in the last rotation state (or first if !forward),
// change rotation state and return true; else return false
// Default does nothing and returns false
virtual bool Rotate(bool forward);
// Tell whether the handle has its own escape action. In case it is already
// clicked, it will not cancel on Escape key if true.
// Default is always false.
virtual bool HasEscape() const;
// The handle may change state and mark itself for highlight change.
// Default does nothing and returns false
virtual bool Escape(SneedacityProject *pProject);
// Assume hit test (implemented in other classes) was positive.
// May return Cancelled, overriding the hit test decision and stopping drag.
// Otherwise the framework will later call Release or Cancel after
// some number of Drag calls.
virtual Result Click
(const TrackPanelMouseEvent &event, SneedacityProject *pProject) = 0;
// Assume previously Clicked and not yet Released or Cancelled.
// pCell may be other than for Click; may be NULL, and rect empty.
// Return value may include the Cancelled return flag,
// in which case the handle will not be invoked again.
virtual Result Drag
(const TrackPanelMouseEvent &event, SneedacityProject *pProject) = 0;
// Can be called when the handle has been hit but not yet clicked,
// or called after Drag().
// Specifies cursor and status bar message.
virtual HitTestPreview Preview
(const TrackPanelMouseState &state, SneedacityProject *pProject) = 0;
// Assume previously Clicked and not yet Released or Cancelled.
// event.pCell may be other than for Click; may be NULL, and rect empty.
// Can use pParent as parent to pop up a context menu,
// connecting and disconnecting event handlers for the menu items.
// Cancelled in return flags has no effect.
virtual Result Release
(const TrackPanelMouseEvent &event, SneedacityProject *pProject,
wxWindow *pParent) = 0;
// Assume previously Clicked and not yet Released or Cancelled.
// Cancelled in return flags has no effect.
virtual Result Cancel(SneedacityProject *pProject) = 0;
// Whether to force Release (not Cancel!) of the drag when a
// keystroke command is about to be dispatched. Default is always false.
// When default is false, any remembered pointers to tracks should be
// weak_ptrs.
virtual bool StopsOnKeystroke();
// Notification after a command is dispatched; generally, it will need to
// be overridden only in case StopsOnKeystroke() returns false. Default
// does nothing.
// PRL: all former uses of this are now accomplished with weak_ptr instead
// to avoid dangling pointers to tracks. But maybe there will be a future
// use?
virtual void OnProjectChange(SneedacityProject *pProject);
public:
Result GetChangeHighlight() const { return mChangeHighlight; }
void SetChangeHighlight(Result val) { mChangeHighlight = val; }
// If AssignUIHandlePtr is used, then this function is also called before any
// overwrite.
// Make overloads of this for other subclasses, to cause refresh
// of the cell during mouse motion within it.
static UIHandle::Result NeedChangeHighlight
(const UIHandle &/*oldState*/, const UIHandle &/*newState*/)
{
return 0;
}
protected:
// Derived classes can set this nonzero in a constructor, which is enough
// to cause repaint of the cell whenever the pointer hits the target,
// or leaves it without clicking, or releases or escapes from a drag.
Result mChangeHighlight { 0 };
};
using UIHandlePtr = std::shared_ptr<UIHandle>;
// A frequent convenience for defining a hit test.
// Construct a NEW handle as if hit the first time; then either keep it, or
// use it to overwrite the state of a previously constructed handle that has not
// yet been released.
template<typename Subclass>
std::shared_ptr<Subclass> AssignUIHandlePtr
( std::weak_ptr<Subclass> &holder, const std::shared_ptr<Subclass> &pNew )
{
// Either assign to a null weak_ptr, or else rewrite what the weak_ptr
// points at. Thus a handle already pointed at changes its state but not its
// identity. This may matter for the framework that holds the strong
// pointers.
auto ptr = holder.lock();
if (!ptr) {
holder = pNew;
return pNew;
}
else {
auto code = Subclass::NeedChangeHighlight( *ptr, *pNew );
*ptr = std::move(*pNew);
ptr->SetChangeHighlight( code );
return ptr;
}
}
#endif