-
Notifications
You must be signed in to change notification settings - Fork 0
/
ginput2.m
285 lines (245 loc) · 9.44 KB
/
ginput2.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
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
function [out1,out2,out3] = ginput2(arg1,varargin)
%GINPUT2 Graphical input from mouse.
% [X,Y] = GINPUT2(N) gets N points from the current axes and returns
% the X- and Y-coordinates in length N vectors X and Y. The cursor
% can be positioned using a mouse. Data points are entered by pressing
% a mouse button or any key on the keyboard except carriage return,
% which terminates the input before N points are entered.
%
% [X,Y] = GINPUT2 gathers an unlimited number of points until the
% return key is pressed.
%
% [X,Y,BUTTON] = GINPUT2(N) returns a third result, BUTTON, that
% contains a vector of integers specifying which mouse button was
% used (1,2,3 from left) or ASCII numbers if a key on the keyboard
% was used.
%
% [__] = GINPUT2(___,Name,Value) takes additional arguments (as opposed
% to the builtin GINPUT). Currently, 'Figure', handle is supported to
% specify a valid figure handle at which figure GINPUT2 should watch for
% input.
%
% Examples:
% [x,y] = ginput;
%
% [x,y] = ginput(5);
%
% [x, y, button] = ginput(1);
%
% See also GINPUT, GTEXT, WAITFORBUTTONPRESS.
% Copyright 1984-2015 The MathWorks, Inc.
out1 = []; out2 = []; out3 = []; y = [];
p=inputParser;
p.addParameter('Figure',gcf,@isvalid);
p.parse(varargin{:});
if ~matlab.ui.internal.isFigureShowEnabled
error(message('MATLAB:hg:NoDisplayNoFigureSupport', 'ginput'))
end
% Check Inputs
if nargin == 0
how_many = -1;
b = [];
else
how_many = arg1;
b = [];
if ~isPositiveScalarIntegerNumber(how_many)
error(message('MATLAB:ginput:NeedPositiveInt'))
end
if how_many == 0
% If input argument is equal to zero points,
% give a warning and return empty for the outputs.
warning (message('MATLAB:ginput:InputArgumentZero'));
end
end
% Get figure
fig = p.Results.Figure;
figure(fig);
% Make sure the figure has an axes
%gca(fig);
% Setup the figure to disable interactive modes and activate pointers.
initialState = setupFcn(fig);
% onCleanup object to restore everything to original state in event of
% completion, closing of figure errors or ctrl+c.
c = onCleanup(@() restoreFcn(initialState));
drawnow
char = 0;
while how_many ~= 0
waserr = 0;
try
keydown = wfbp(fig);
catch %#ok<CTCH>
waserr = 1;
end
if(waserr == 1)
if(ishghandle(fig))
cleanup(c);
error(message('MATLAB:ginput:Interrupted'));
else
cleanup(c);
error(message('MATLAB:ginput:FigureDeletionPause'));
end
end
% g467403 - ginput failed to discern clicks/keypresses on the figure it was
% registered to operate on and any other open figures whose handle
% visibility were set to off
figchildren = allchild(0);
if ~isempty(figchildren)
ptr_fig = figchildren(1);
else
error(message('MATLAB:ginput:FigureUnavailable'));
end
% old code -> ptr_fig = get(0,'CurrentFigure'); Fails when the
% clicked figure has handlevisibility set to callback
if(ptr_fig == fig)
if keydown
char = get(fig, 'CurrentCharacter');
button = abs(get(fig, 'CurrentCharacter'));
else
button = get(fig, 'SelectionType');
if strcmp(button,'open')
button = 1;
elseif strcmp(button,'normal')
button = 1;
elseif strcmp(button,'extend')
button = 2;
elseif strcmp(button,'alt')
button = 3;
else
error(message('MATLAB:ginput:InvalidSelection'))
end
end
axes_handle = gca;
drawnow;
pt = get(axes_handle, 'CurrentPoint');
how_many = how_many - 1;
if(char == 13) % & how_many ~= 0)
% if the return key was pressed, char will == 13,
% and that's our signal to break out of here whether
% or not we have collected all the requested data
% points.
% If this was an early breakout, don't include
% the <Return> key info in the return arrays.
% We will no longer count it if it's the last input.
break;
end
out1 = [out1;pt(1,1)]; %#ok<AGROW>
y = [y;pt(1,2)]; %#ok<AGROW>
b = [b;button]; %#ok<AGROW>
end
end
% Cleanup and Restore
cleanup(c);
if nargout > 1
out2 = y;
if nargout > 2
out3 = b;
end
else
out1 = [out1 y];
end
end
function valid = isPositiveScalarIntegerNumber(how_many)
valid = ~ischar(how_many) && ... % is numeric
isscalar(how_many) && ... % is scalar
(fix(how_many) == how_many) && ... % is integer in value
how_many >= 0; % is positive
end
function key = wfbp(fig)
%WFBP Replacement for WAITFORBUTTONPRESS that has no side effects.
current_char = []; %#ok<NASGU>
% Now wait for that buttonpress, and check for error conditions
waserr = 0;
try
h=findall(fig,'Type','uimenu','Accelerator','C'); % Disabling ^C for edit menu so the only ^C is for
set(h,'Accelerator',''); % interrupting the function.
keydown = waitforbuttonpress;
current_char = double(get(fig,'CurrentCharacter')); % Capturing the character.
if~isempty(current_char) && (keydown == 1) % If the character was generated by the
if(current_char == 3) % current keypress AND is ^C, set 'waserr'to 1
waserr = 1; % so that it errors out.
end
end
set(h,'Accelerator','C'); % Set back the accelerator for edit menu.
catch %#ok<CTCH>
waserr = 1;
end
drawnow;
if(waserr == 1)
set(h,'Accelerator','C'); % Set back the accelerator if it errored out.
error(message('MATLAB:ginput:Interrupted'));
end
if nargout>0, key = keydown; end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
end
function initialState = setupFcn(fig)
% Store Figure Handle.
initialState.figureHandle = fig;
% Suspend figure functions
initialState.uisuspendState = uisuspend(fig);
% Disable Plottools Buttons
initialState.toolbar = findobj(allchild(fig),'flat','Type','uitoolbar');
if ~isempty(initialState.toolbar)
initialState.ptButtons = [uigettool(initialState.toolbar,'Plottools.PlottoolsOff'), ...
uigettool(initialState.toolbar,'Plottools.PlottoolsOn')];
initialState.ptState = get (initialState.ptButtons,'Enable');
set (initialState.ptButtons,'Enable','off');
end
%Setup empty pointer
cdata = NaN(16,16);
hotspot = [8,8];
set(fig,'Pointer','custom','PointerShapeCData',cdata,'PointerShapeHotSpot',hotspot)
% Create uicontrols to simulate fullcrosshair pointer.
initialState.CrossHair = createCrossHair(fig);
% Adding this to enable automatic updating of currentpoint on the figure
% This function is also used to update the display of the fullcrosshair
% pointer and make them track the currentpoint.
set(fig,'WindowButtonMotionFcn',@(o,e) updateCrossHair(o,initialState.CrossHair));
% Get the initial Figure Units
initialState.fig_units = get(fig,'Units');
end
function restoreFcn(initialState)
if ishghandle(initialState.figureHandle)
delete(initialState.CrossHair);
% Figure Units
set(initialState.figureHandle,'Units',initialState.fig_units);
set(initialState.figureHandle,'WindowButtonMotionFcn','');
% Plottools Icons
if ~isempty(initialState.toolbar) && ~isempty(initialState.ptButtons)
set (initialState.ptButtons(1),'Enable',initialState.ptState{1});
set (initialState.ptButtons(2),'Enable',initialState.ptState{2});
end
% UISUSPEND
uirestore(initialState.uisuspendState);
end
end
function updateCrossHair(fig, crossHair)
% update cross hair for figure.
gap = 3; % 3 pixel view port between the crosshairs
cp = hgconvertunits(fig, [fig.CurrentPoint 0 0], fig.Units, 'pixels', fig);
cp = cp(1:2);
figPos = hgconvertunits(fig, fig.Position, fig.Units, 'pixels', fig.Parent);
figWidth = figPos(3);
figHeight = figPos(4);
% Early return if point is outside the figure
if cp(1) < gap || cp(2) < gap || cp(1)>figWidth-gap || cp(2)>figHeight-gap
return
end
set(crossHair, 'Visible', 'on');
thickness = 1; % 1 Pixel thin lines.
set(crossHair(1), 'Position', [0 cp(2) cp(1)-gap thickness]);
set(crossHair(2), 'Position', [cp(1)+gap cp(2) figWidth-cp(1)-gap thickness]);
set(crossHair(3), 'Position', [cp(1) 0 thickness cp(2)-gap]);
set(crossHair(4), 'Position', [cp(1) cp(2)+gap thickness figHeight-cp(2)-gap]);
end
function crossHair = createCrossHair(fig)
% Create thin uicontrols with black backgrounds to simulate fullcrosshair pointer.
% 1: horizontal left, 2: horizontal right, 3: vertical bottom, 4: vertical top
for k = 1:4
crossHair(k) = uicontrol(fig, 'Style', 'text', 'Visible', 'off', 'Units', 'pixels', 'BackgroundColor', [0 0 0], 'HandleVisibility', 'off', 'HitTest', 'off'); %#ok<AGROW>
end
end
function cleanup(c)
if isvalid(c)
delete(c);
end
end