-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMouseManager_demo.m
270 lines (257 loc) · 12.9 KB
/
MouseManager_demo.m
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
%% |MouseManager| demo
% The |MouseManager| class provides a general-purpose, easy-to-use
% interface for managing mouse-based interactions with objects in a figure.
% A |MouseManager| object is associated with a figure window and helps
% handle any mouse-driven interactions (such as clicking, hovering, and
% scrolling) with multiple graphics objects within the figure, particularly
% axes objects and their children. Below are four examples of how
% |MouseManager| can be used to easily add mouse-based interaction to your
% GUIs.
%%
%% Panning/Zooming/Resetting an axes
% The code for this demo is included below and can be found in the file
% |panning_demo.m|. After running the code, an image will be displayed in a
% figure window. You can left click and drag to pan, scroll to zoom in and
% out, and double-click to reset to the default view:
%
% <include>panning_demo.m</include>
%%
% First, the code loads an image and displays it in a figure window. A
% |MouseManager| object |mmObject| is then created and associated with the
% figure window. The axes object is added as a managed item using the
% |add_item| method and 3 callback functions (in this case nested
% functions) are added:
%
% * |pan_image|, which handles panning of the image, is associated with
% 'normal' (i.e. left) mouse button operations (clicking, dragging, etc.)
% involving the axes object.
% * |zoom_image|, which handles zooming in and out on the image, is
% associated with 'scroll' operations made over the axes object.
% * |reset_image|, which returns the image to its default display, is
% associated with 'click' operations made over the axes, specifically
% 'open' (i.e. double-click) selections made with any mouse button.
%
% Finally, a call to the |enable| method is made to enable |mmObject|,
% which starts in the default 'off' state. This activates all of the above
% mouse-based interactions.
%%
% *The |pan_image| function*
%
% Looking at the |pan_image| function, we can see that it uses the
% |eventData| structure that is automatically passed to it by the
% |MouseManager| object. Since |pan_image| handles all operations for
% 'normal' (left) mouse button selections, the |operation| field of the
% |eventData| structure is used to determine if either a 'click' or 'drag'
% operation is currently being performed. The handle of the currently
% active managed object (i.e. the axes object) is passed as the first
% argument to |pan_image|.
%
% When a left click is initially made, a number of variable are initialized
% that are used to handle the panning operation. This includes the initial
% position of the cursor (|panOrigin|, gotten from the |figurePoint| field
% of the |eventData| structure), the initial limits of the axes
% (|panLimits|), and the scale factor used to compute axes limit changes
% from cursor position changes (|panScale|, which uses the |figureRegion|
% field in the |eventData| structure to get the figure-level position, in
% pixels, of the axes object).
%
% When the left mouse button is clicked and held while the mouse is moved,
% the 'drag' operation is performed. The current cursor position (which
% moves with the mouse) is again gotten from the |figurePoint| field of the
% |eventData| structure and used to calculate the offset which is applied
% to the axes limits. The scaling is such that the axes panning mirrors the
% cursor movements.
%%
% *The |zoom_image| function*
%
% The |zoom_image| function is invoked when a 'scroll' event occurs. It
% fetches the |scrollEventData| field from the |eventData| structure and
% then gets the |VerticalScrollCount| field from that. A fractional change
% in the axes limits is computed and applied to the axes object.
%%
% *The |reset_image| function*
%
% The |reset_image| function is invoked when double-clicking with any mouse
% button over the axes. The axes limits are reset to default values
% (|xLimits| and |yLimits|, whose scope spans the |panning_demo| and
% |reset_image| functions).
%%
% *|MouseManager| object information*
%
% The |panning_demo| function will display the |MouseManager| object
% information in the command window when run. Here's what it displays:
%
% mmObject =
%
% MouseManager object:
%
% hFigure: 'Panning Demo'
% enabled: 1
% defaultHoverFcn: []
%
% Item (Tag) | operation___selection___callbackFcn
% ----------------------+--------------------------------------------------
% axes (AXES_1) | ___click_____normal___@panning_demo/pan_image
% | | \_open_____@panning_demo/reset_image
% | \_drag______normal___@panning_demo/pan_image
% | \_release___normal___@panning_demo/pan_image
% | \_hover_____@panning_demo/pan_image
% | \_scroll____@panning_demo/zoom_image
%
% In addition to listing the name of the associated figure window, enabled
% state of the |MouseManager| object, and the default hover function (see
% the <MouseManager_demo.html#9 *Displaying information while hovering over
% an axes*> section below for more detail about this), a table of managed
% items and their associated callbacks are displayed. The type of object
% and its 'Tag' property, if it has one, is displayed along with a
% heirarchy of operations, mouse selections, and callback functions.
%
% Note that the |pan_image| callback is defined for 'click', 'drag',
% 'release', and 'hover' operations. When we added this callback, we only
% specified the 'normal' selection and no operation arguments:
%
% mmObject.add_item(hAxes, 'normal', @pan_image, ...
%
% As such, *all* possible operations were set to use |pan_image|. This
% includes the 'scroll' operation, although we subsequently overwrote that
% with |zoom_image| when we specified a 'scroll' operation callback. Since
% |pan_image| doesn't do anything for 'release' or 'hover' operations, we
% could be more specific when we add the callbacks, like so:
%
% mmObject.add_item(hAxes, {'click', 'drag'}, 'normal', @pan_image, ...
% 'scroll', @zoom_image, ...
% 'click', 'open', @reset_image);
%
% And the callback heirarchy would now look like this:
%
% Item (Tag) | operation___selection___callbackFcn
% ----------------------+--------------------------------------------------
% axes (AXES_1) | ___click_____normal___@panning_demo/pan_image
% | | \_open_____@panning_demo/reset_image
% | \_drag______normal___@panning_demo/pan_image
% | \_scroll____@panning_demo/zoom_image
%
% There is a lot of flexibility in defining callbacks. You could specify a
% separate callback for every individual operation/selection combination,
% or a single callback function to handle everything for a given object:
%
% mmObject.add_item(hItem, @do_it_all);
%
% |do_it_all| would simply have to fetch the current operation and mouse
% selection from the |operation| and |selectionType| fields, respectively,
% of the |eventData| structure in order to perform the correct action.
%
% In truth, you may gain some slight performance advantages from specifying
% each individual combination, as that reduces the number of switch
% statements and function calls. However, this may be a micro-optimization.
% It's probably more important to organize things logically, like how
% |pan_image| handles all panning operations, and can therefore use
% persistent variables to store initial calculations.
%% Windowing data with sliding markers
% The code for this demo is included below and can be found in the file
% |windowing_demo.m|. After running the code, a plot will be displayed in a
% figure window. You can left click and drag the upper and lower marker
% lines to select a region of the plot between them (shown in red). The
% mean of values in this region is displayed above the plot:
%
% <include>windowing_demo.m</include>
%%
% This demo illustrates a situation similar to how GUIs are created through
% <https://www.mathworks.com/help/matlab/guide-or-matlab-functions.html
% GUIDE>, where object handles are stored in a |handles| structure and
% passed as an extra parameter to callback functions. The code creates a
% figure, axes, two plots of data, and two vertical marker lines that
% define lower and upper bounds on a subset of the plotted data. These two
% lines are added to the |MouseManager| object with an associated callback
% for 'drag' operations using the left ('normal' selection) mouse button.
% This callback function is added as a cell array with the first entry
% being a function handle to the local function |move_line| and the second
% entry being the structure of object handles |handles|. Here's what the
% |windowing_demo| function will display in the command window when run:
%
% mmObject =
%
% MouseManager object:
%
% hFigure: 'Windowing Demo'
% enabled: 1
% defaultHoverFcn: []
%
% Item (Tag) | operation___selection___callbackFcn
% ----------------------+--------------------------------------------------
% line (LOWER) | ___drag______normal___{@move_line, ...}
% ----------------------+--------------------------------------------------
% line (UPPER) | ___drag______normal___{@move_line, ...}
%% Displaying information while hovering over an axes
% The code for this demo is included below and can be found in the file
% |hovering_demo.m|. After running the code, an image will be displayed in
% a figure window. When you hover the mouse over the image, text will
% appear above the cursor displaying the RGB triple for the pixel beneath
% the cursor pointer. This text only appears over the image and no where
% else in the figure.
%
% <include>hovering_demo.m</include>
%%
% This demo illustrates the use of a default hover function for the figure
% window. The axes is first added to |mmObject| as a managed object with a
% callback function |display_rgb| for 'hover' operations. Then the
% |default_hover_fcn| method is used to add |clear_display| as a default
% hover function that executes whenever the cursor is not hovering over and
% other managed object. Here's the |MouseManager| object information that
% the |hovering_demo| function will display in the command window:
%
% mmObject =
%
% MouseManager object:
%
% hFigure: 'Hovering Demo'
% enabled: 1
% defaultHoverFcn: @hovering_demo/clear_display
%
% Item (Tag) | operation___selection___callbackFcn
% ----------------------+--------------------------------------------------
% axes (AXES_1) | ___hover_____@hovering_demo/display_rgb
%%
% The |display_rgb| function is evaluated when the cursor is over the axes,
% specifically when the axes 'CurrentPoint' property is over a pixel of the
% plotted image. If the cursor moves off the edge of the image, that
% movement might take it off the edge of the axes object as well. That
% would mean the |display_rgb| function wouldn't be evaluated again, and
% the last displayed text would still remain in its previous position. The
% use of the default hover function |clear_display| is necessary in this
% case to ensure the text is removed when the cursor moves off the axes.
%% 3D interaction using camera operations
% The code for this demo is included below and can be found in the file
% |camera_demo.m|. After running the code, a 3-D plot of the
% <https://www.mathworks.com/help/matlab/ref/peaks.html |peaks|> function
% will be displayed in a figure window:
%
% <include>camera_demo.m</include>
%%
% Clicking and dragging with the left ('normal') mouse button will invoke
% the |orbit_camera| function, which rotates the camera both horizontally
% and vertically around its target point. Clicking and dragging with the
% right ('alt') mouse button will invoke the |dolly_camera| function, which
% will shift the camera and its target point laterally and up and down.
% Double-clicking ('open') any mouse button will invoke the |reset_camera|
% function to reset the image to its default view, and scrolling with the
% mouse wheel will invoke the |zoom_camera| function to adjust the camera
% view angle. Here's the |MouseManager| object information that the
% |camera_demo| function will display in the command window:
%
% mmObject =
%
% MouseManager object:
%
% hFigure: 'Camera Demo'
% enabled: 1
% defaultHoverFcn: []
%
% Item (Tag) | operation___selection___callbackFcn
% ----------------------+--------------------------------------------------
% axes (AXES_1) | ___click_____normal___@camera_demo/orbit_camera
% | | \_alt______@camera_demo/dolly_camera
% | | \_open_____@camera_demo/reset_camera
% | \_drag______normal___@camera_demo/orbit_camera
% | | \_alt______@camera_demo/dolly_camera
% | \_scroll____@camera_demo/zoom_camera