1 % NAME: magnifyOnFigure
3 % AUTHOR: David Fernandez Prim (david.fernandez.prim@gmail.com)
5 % PURPOSE: Shows a functional zoom tool, suitable
for publishing of zoomed
9 % figureHandle [
double 1x1]: graphic handle of the target figure
10 % axesHandle [
double 1x1]: graphic handle of the target axes.
17 % $ Adds magnifier on the first axes of the current figure, with
20 % 2) magnifyOnFigure( figureHandle );
21 % $ Adds magnifier on the first axes of the figure with handle
22 %
'figureHandle', with
default behavior.
24 % 3) magnifyOnFigure( figureHandle,
'property1', value1,... );
25 % $ Adds magnifier on the first axes of the figure with handle
26 %
'figureHandle', with modified behavior.
28 % 4) magnifyOnFigure( axesHandle );
29 % $ Adds magnifier on the axes with handle
'axesHandle', with
32 % 5) magnifyOnFigure( axesHandle,
'property1', value1,... );
33 % $ Adds magnifier on the axes with handle
'axesHandle', with
36 % 6) Consecutive calls to
this function (in any of the syntaxes
37 % exposed above) produce multiple selectable magnifiers on the target axes.
39 % USAGE EXAMPLES: see script
'magnifyOnFigure_examples.m' 42 %
'magnifierShape':
'Shape of the magnifier ('rectangle
' or 'ellipse
' allowed, 'rectangle
' as default) 43 % 'secondaryAxesFaceColor
': ColorSpec 44 % 'edgeWidth
' Color of the box surrounding the secondary 45 % axes, magnifier and link. Default 1 46 % 'edgeColor
': Color of the box surrounding the secondary 47 % axes, magnifier and link. Default 'black
' 48 % 'displayLinkStyle
': Style of the link. 'none
', 'straight
' or 49 % 'edges
', with 'straight
' as default. 50 % 'mode
': 'manual
' or 'interactive
' (allowing 51 % adjustments through mouse/keyboard). Default 53 % 'units
' Units in which the position vectors are 54 % given. Only 'pixels
' currently supported 55 % 'initialPositionSecondaryAxes
': Initial position vector ([left bottom width height]) 56 % of secondary axes, in pixels 57 % 'initialPositionMagnifier
': Initial position vector ([left bottom width height]) 58 % of magnifier, in pixels 59 % 'secondaryAxesXLim
': Initial XLim value of the secondary axes 60 % 'secondaryAxesYLim
': Initial YLim value of the secondary axes 61 % 'frozenZoomAspectRatio
': Specially useful for images, forces the use of the same zoom 62 % factor on both X and Y axes, in order to keep the aspect ratio 63 % ('on
' or 'off
' allowed, 'off
' by default 65 % HOT KEYS (active if 'mode
' set to 'interactive
') 67 % -In a figure with multiple tool instances 68 % 'Tab
': Switch the focus from one magnifier instance 69 % to the next one on the current figure. 70 % 'Mouse pointer on secondary axes or magnifier of a tool+
double left click
' 73 % -On the focused magnifier instance 74 % 'up arrow
': Moves magnifier 1 pixel upwards 75 % 'down arrow
': Moves magnifier 1 pixel downwards 76 % 'left arrow
': Moves magnifier 1 pixel to the left 77 % 'right arrow
': Moves magnifier 1 pixel to the right 78 % 'Shift+up arrow
': Expands magnifier 10% on the Y-axis 79 % 'Shift+down arrow
': Compress magnifier 10% on the Y-axis 80 % 'Shift+left arrow
': Compress magnifier 10% on the X-axis 81 % 'Shift+right arrow
': Expands magnifier 10% on the X-axis 82 % 'Control+up arrow
': Moves secondary axes 1 pixel upwards 83 % 'Control+down arrow
': Moves secondary axes 1 pixel downwards 84 % 'Control+left arrow
': Moves secondary axes 1 pixel to the left 85 % 'Control+right arrow
': Moves secondary axes 1 pixel to the right 86 % 'Alt+up arrow
': Expands secondary axes 10% on the Y-axis 87 % 'Alt+down arrow
': Compress secondary axes 10% on the Y-axis 88 % 'Alt+left arrow
': Compress secondary axes 10% on the X-axis 89 % 'Alt+right arrow
': Expands secondary axes 10% on the X-axis 90 % 'PageUp
': Increase additional zooming factor on X-axis 91 % 'PageDown
': Decrease additional zooming factor on X-axis 92 % 'Shift+PageUp
': Increase additional zooming factor on Y-axis 93 % 'Shift+PageDown
': Decrease additional zooming factor on Y-axis 94 % 'Control+Q
': Resets the additional zooming factors to 0 95 % 'Control+A
': Displays position of secondary axes and 96 % magnifier in the command window 97 % 'Control+D
': Deletes the focused tool 98 % 'Control+I
': Shows/hides the tool identifier (red 99 % background color when the tool has the focus, 101 % 'Mouse pointer on magnifier+left click
' Drag magnifier to any 103 % 'Mouse pointer on secondary axes+left click
' Drag secondary axes in any 107 % - Use another axes copy as magnifier instead of rectangle (no ticks). 108 % - Adapt to work on 3D plots. 109 % - Add tip tool with interface description?. 112 % - Secondary axes are not updated when the zoomming or panning tools of the figure are used. 113 % - Degraded performance for big data sets or big window sizes. 114 % - The size and position of the magnifier are modified for 115 % 'PaperPositionMode
' equal to 'auto', when the figure is printed to file 120 % Version | Date | Author | Description 121 %---------------|---------------|-------------------|--------------------------------------- 122 % 1.0 | 28/11/2009 | D. Fernandez | First version 123 % 1.1 | 29/11/2009 | D. Fernandez | Added link from magnifier to secondary axes 124 % 1.2 | 30/11/2009 | D. Fernandez | Keyboard support added 125 % 1.3 | 01/12/2009 | D. Fernandez | Properties added 126 % 1.4 | 02/12/2009 | D. Fernandez | Manual mode supported 127 % 1.5 | 03/12/2009 | D. Fernandez | New link style added ('edges
') 128 % 1.6 | 03/12/2009 | D. Fernandez | Bug solved in display of link style 'edges
' 129 % 1.7 | 04/12/2009 | D. Fernandez | Target axes selection added 130 % 1.8 | 07/12/2009 | D. Fernandez | Solved bug when any of the axes are reversed. 131 % 1.9 | 08/12/2009 | D. Fernandez | Adapted to work under all axes modes (tight, square, image, ...) 132 % 1.10 | 08/12/2009 | D. Fernandez | Added frozenZoomAspectRatio zoom mode, useful for images 133 % 1.11 | 08/12/2009 | D. Fernandez | Solved bug when axes contain other than 'line
' or 'image
' objects 134 % 1.12 | 05/01/2010 | D. Fernandez | Added support to multiple instances 135 % 1.13 | 05/01/2010 | D. Fernandez | Added 'delete' functionality 136 % 1.14 | 05/01/2010 | D. Fernandez | Solved bug when initial positions for secondary axes and/or magnifier are specified 137 % 1.15 | 07/01/2010 | D. Fernandez | Solved bug when resizing window 138 % 1.16 | 07/01/2010 | D. Fernandez | Improved documentation 139 % 1.17 | 28/03/2010 | D. Fernandez | Added tool identifications feature 142 function magnifyOnFigure( varargin ) 144 clear global appDataStruct 148 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 149 %CHECK OUTPUT ARGUMENTS 150 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 155 outputObjectExpected = false; 158 %tool object expected at the output 159 outputObjectExpected = false; 162 error('Number of output arguments not supported.
'); 165 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 166 %CHECK INPUT ARGUMENTS 167 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 169 %Initialize 'appDataStructuct
' with default values 170 appDataStruct = initializeToolStruct(); 172 appDataStruct.figureHandle = gcf; 173 % Get number of axes in the same figure 174 childHandle = get(appDataStruct.figureHandle, 'Children
'); 175 iAxes = find(strcmpi(get(childHandle, 'Type
'), 'axes
')); 176 % If no target axes specified, select the first found as mainAxes 177 appDataStruct.mainAxesHandle = childHandle( iAxes(end) ); 180 if isstruct(varargin{1}) 181 %Initialize 'appDataStructuct
' with existent structure 182 appDataStruct = initializeToolStruct( varargin{1} ); 184 elseif ishandle(varargin{1}) && strcmpi(get(varargin{1}, 'Type
'), 'figure
') 185 %Initialize 'appDataStructuct
' with default values 186 appDataStruct = initializeToolStruct(); 188 appDataStruct.figureHandle = varargin{1}; 189 % Get number of axes in the same figure 190 childHandle = get(appDataStruct.figureHandle, 'Children
'); 191 iAxes = find(strcmpi(get(childHandle, 'Type
'), 'axes
')); 192 % If no target axes specified, select the first found as mainAxes 193 appDataStruct.mainAxesHandle = childHandle( iAxes(end) ); 195 elseif ishandle(varargin{1}) && strcmpi(get(varargin{1}, 'Type
'), 'axes
') 196 %Initialize 'appDataStructuct
' with default values 197 appDataStruct = initializeToolStruct(); 198 appDataStruct.mainAxesHandle = varargin{1}; 200 parentHandle = get(varargin{1}, 'Parent
'); 201 iHandle = find(strcmpi(get(parentHandle, 'Type
'), 'figure
')); 202 % Figure is the parent of the axes 203 appDataStruct.figureHandle = parentHandle( iHandle(1) ); 206 if ishandle(varargin{1}) 207 warning('Wrong figure/axes handle specified. The magnifier will be applied on the current figure.
'); 208 elseif isobject(varargin{1}) 209 error('Wrong
object specified.
'); 211 error('Wrong input
class specified.');
216 if mod(nargin-1, 2) == 0
218 %Check input properties
220 if ~strcmpi( varargin{i},
'frozenZoomAspectRatio' ) &&...
221 ~strcmpi( varargin{i},
'magnifierShape' ) &&...
222 ~strcmpi( varargin{i},
'secondaryaxesxlim' ) &&...
223 ~strcmpi( varargin{i},
'secondaryaxesylim' ) &&...
224 ~strcmpi( varargin{i},
'secondaryaxesfacecolor' ) &&...
225 ~strcmpi( varargin{i},
'edgewidth' ) &&...
226 ~strcmpi( varargin{i},
'edgecolor' ) &&...
227 ~strcmpi( varargin{i},
'displayLinkStyle' ) &&...
228 ~strcmpi( varargin{i},
'mode' ) &&...
229 ~strcmpi( varargin{i},
'units' ) &&...
230 ~strcmpi( varargin{i},
'initialpositionsecondaryaxes' ) &&...
231 ~strcmpi( varargin{i},
'initialpositionmagnifier' )
232 error(
'Illegal property specified. Please check.');
234 if strcmpi( varargin{i},
'frozenZoomAspectRatio' )
235 if ischar(varargin{i+1}) &&...
236 ( strcmpi(varargin{i+1},
'on') || strcmpi(varargin{i+1},
'off') )
237 appDataStruct.globalZoomMode = lower(varargin{i+1});
239 warning(sprintf(
'Specified zoom mode not supported. Default values will be applied [%s].', appDataStruct.globalZoomMode));
242 if strcmpi( varargin{i},
'mode' )
243 if ischar(varargin{i+1}) &&...
244 ( strcmpi(varargin{i+1},
'manual') || strcmpi(varargin{i+1},
'interactive') )
245 appDataStruct.globalMode = lower(varargin{i+1});
247 warning(sprintf(
'Specified mode descriptor not supported. Default values will be applied [%s].', appDataStruct.globalMode));
250 if strcmpi( varargin{i},
'magnifierShape' )
251 if ischar(varargin{i+1}) &&...
252 ( strcmpi(varargin{i+1},
'rectangle') || strcmpi(varargin{i+1},
'ellipse') )
253 appDataStruct.magnifierShape = lower(varargin{i+1});
255 warning(sprintf(
'Specified magnifier shape not supported. Default values will be applied [%s].', appDataStruct.magnifierShape));
258 if strcmpi( varargin{i},
'displayLinkStyle' )
259 if ischar(varargin{i+1}) &&...
260 ( strcmpi(varargin{i+1},
'straight') || strcmpi(varargin{i+1},
'none') || strcmpi(varargin{i+1},
'edges') )
261 if ~strcmpi(appDataStruct.magnifierShape, 'rectangle') && strcmpi(varargin{i+1},
'edges')
262 warning(sprintf(
'Specified link style not supported. Default values will be applied for ''displayLinkStyle''[%s].', appDataStruct.linkDisplayStyle));
264 appDataStruct.linkDisplayStyle = lower(varargin{i+1});
267 warning(sprintf(
'Specified descriptor not supported. Default values will be applied for ''displayLink''[%s].', appDataStruct.linkDisplayStyle));
270 if strcmpi( varargin{i},
'units' )
271 if ischar(varargin{i+1}) && strcmpi(varargin{i+1},
'pixels')
272 appDataStruct.globalUnits = lower(varargin{i+1});
274 warning(sprintf(
'Specified units descriptor not supported. Default values will be applied [%s].', appDataStruct.globalUnits));
277 if strcmpi( varargin{i},
'edgewidth' )
278 if length(varargin{i+1})==1 && isnumeric(varargin{i+1})
279 appDataStruct.globalEdgeWidth = varargin{i+1};
281 warning(sprintf(
'Incorrect edge width value. Default value will be applied [%g].', appDataStruct.globalEdgeWidth ))
284 if strcmpi( varargin{i},
'edgecolor' )
285 if ( length(varargin{i+1})==3 && isnumeric(varargin{i+1}) ) ||...
286 ( ischar(varargin{i+1}) )
287 appDataStruct.globalEdgeColor = varargin{i+1};
289 warning(
'Incorrect edge color value. Default black will be applied.');
292 if strcmpi( varargin{i},
'secondaryaxesfacecolor' )
293 if ( length(varargin{i+1})==3 && isnumeric(varargin{i+1}) ) ||...
294 ( ischar(varargin{i+1}) )
295 appDataStruct.secondaryAxesFaceColor = varargin{i+1};
297 warning(
'Incorrect secondary axes face color value. Default white will be applied.');
301 if strcmpi( varargin{i},
'secondaryaxesxlim' )
302 if ( length(varargin{i+1})==2 && isnumeric(varargin{i+1}) )
303 appDataStruct.secondaryAxesXLim = varargin{i+1};
305 warning(
'Incorrect secondary axes XLim value. Default white will be applied.');
309 if strcmpi( varargin{i},
'secondaryaxesylim' )
310 if ( length(varargin{i+1})==2 && isnumeric(varargin{i+1}) )
311 appDataStruct.secondaryAxesYLim = varargin{i+1};
313 warning(
'Incorrect secondary axes YLim value. Default white will be applied.');
317 if strcmpi( varargin{i},
'initialpositionsecondaryaxes' )
318 if length(varargin{i+1})==4 && isnumeric(varargin{i+1})
319 appDataStruct.secondaryAxesPosition = varargin{i+1};
321 warning(
'Incorrect initial position of secondary axes. Default values will be applied.')
324 if strcmpi( varargin{i},
'initialpositionmagnifier' )
325 if length(varargin{i+1})==4 && isnumeric(varargin{i+1})
326 appDataStruct.magnifierPosition = varargin{i+1};
328 warning(
'Incorrect initial position of magnifier. Default values will be applied.')
334 error('Number of input arguments not supported.');
338 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
341 % Create secondary axes
342 if isempty(appDataStruct.secondaryAxesHandle)
343 appDataStruct.secondaryAxesHandle = copyobj(appDataStruct.mainAxesHandle, appDataStruct.figureHandle);
346 %Configure secondary axis
347 set( appDataStruct.secondaryAxesHandle, 'Color', get(appDataStruct.mainAxesHandle,'Color'), 'Box','on');
348 set( appDataStruct.secondaryAxesHandle, 'FontWeight', 'bold',...
349 'LineWidth', appDataStruct.globalEdgeWidth,...
350 'XColor', appDataStruct.globalEdgeColor,...
351 'YColor', appDataStruct.globalEdgeColor,...
352 'Color', appDataStruct.secondaryAxesFaceColor );
353 set( appDataStruct.figureHandle, 'CurrentAxes', appDataStruct.secondaryAxesHandle );
354 xlabel(''); ylabel(''); zlabel(''); title('');
355 axis( appDataStruct.secondaryAxesHandle, 'normal'); %Ensure that secondary axes are not resizing
356 set( appDataStruct.figureHandle, 'CurrentAxes', appDataStruct.mainAxesHandle );
358 %Default magnifier position
359 if isempty(appDataStruct.magnifierPosition)
360 appDataStruct.magnifierPosition = computeMagnifierDefaultPosition();
363 %Default secondary axes position
364 if isempty(appDataStruct.secondaryAxesPosition)
365 appDataStruct.secondaryAxesPosition = computeSecondaryAxesDefaultPosition();
369 toolArrayAux =
get(appDataStruct.figureHandle,
'userdata');
370 set(appDataStruct.figureHandle,
'userdata', []);
371 % #END PATCH 1 (part 1)
373 %Set initial position of secondary axes
374 setSecondaryAxesPositionInPixels( appDataStruct.secondaryAxesPosition );
375 %Set initial position of magnifier
376 setMagnifierPositionInPixels( appDataStruct.magnifierPosition );
379 set(appDataStruct.figureHandle,
'userdata', toolArrayAux);
380 % #END PATCH 1 (part 2)
382 %Update view limits on secondary axis
383 refreshSecondaryAxisLimits();
385 %Update link between secondary axes and magnifier
386 refreshMagnifierToSecondaryAxesLink();
388 %Set actions
for interactive mode
389 if strcmpi( appDataStruct.globalMode,
'interactive')
391 toolArray = get(appDataStruct.figureHandle, 'userdata');
392 nTools = length(toolArray);
395 %Store figure position
396 appDataStruct.figurePosition = getFigurePositionInPixels();
399 appDataStruct.figureOldWindowButtonDownFcn = get( appDataStruct.figureHandle, 'WindowButtonDownFcn');
400 appDataStruct.figureOldWindowButtonUpFcn = get( appDataStruct.figureHandle, 'WindowButtonUpFcn');
401 appDataStruct.figureOldWindowButtonMotionFcn = get( appDataStruct.figureHandle, 'WindowButtonMotionFcn');
402 appDataStruct.figureOldKeyPressFcn = get( appDataStruct.figureHandle, 'KeyPressFcn');
403 appDataStruct.figureOldDeleteFcn = get( appDataStruct.figureHandle, 'DeleteFcn');
404 appDataStruct.figureOldResizeFcn = get( appDataStruct.figureHandle, 'ResizeFcn');
406 %Set service funcions to events
407 set( appDataStruct.figureHandle, ...
408 'WindowButtonDownFcn', @ButtonDownCallback, ...
409 'WindowButtonUpFcn', @ButtonUpCallback, ...
410 'WindowButtonMotionFcn', @ButtonMotionCallback, ...
411 'KeyPressFcn', @KeyPressCallback, ...
412 'DeleteFcn', @DeleteCallback,...
413 'ResizeFcn', @ResizeCallback...
418 %Set service funcions to events
419 set( appDataStruct.figureHandle, ...
420 'WindowButtonDownFcn', '', ...
421 'WindowButtonUpFcn', '', ...
422 'WindowButtonMotionFcn', '', ...
423 'KeyPressFcn', '', ...
430 appDataStruct.focusOnThisTool = true;
432 %Compute unique ID of this magnifying tool, from handles of its elements
433 toolId = appDataStruct.figureHandle +...
434 appDataStruct.mainAxesHandle +...
435 appDataStruct.magnifierHandle +...
436 appDataStruct.linkHandle +...
437 appDataStruct.secondaryAxesHandle;
438 %Set ID of this magnifying tool
439 appDataStruct.toolId = toolId;
442 figureHandle = appDataStruct.figureHandle;
444 %Save
object of this tool to userdata in figure
object 445 toolArray = get(figureHandle, 'UserData');
446 if isempty(toolArray)
447 toolArray = struct(appDataStruct);
448 toolArray.focusOnThisTool = true;
450 %Set focus to this tool
451 focusedTool = find([toolArray.focusOnThisTool] == 1);
452 toolArray(focusedTool).focusOnThisTool = false;
455 indexFoundToolId = find([toolArray.toolId] == toolId);
456 if isempty(indexFoundToolId)
457 %If not found, create new
458 indexFoundToolId = length(toolArray)+1;
460 toolArray(indexFoundToolId) = struct(appDataStruct);
461 toolArray(indexFoundToolId).focusOnThisTool = true;
464 set( figureHandle, 'UserData', toolArray );
466 %Set callback global behaviour
467 set(appDataStruct.figureHandle, 'Interruptible', 'off');
468 set(appDataStruct.figureHandle, 'BusyAction', 'cancel');
470 %Return created
object if requested
471 if outputObjectExpected == true
472 varargout{1} = appDataStruct;
476 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477 % NAME: refreshSecondaryAxisLimits
479 % PURPOSE: Updates the view on the secondary axis, based on position and
480 % span of magnifier, and extend of secondary axis.
483 % appDataStructuct [
struct 1x1]: global variable
485 % change 'XLim' and 'YLim' of secondary axis (ACTION)
487 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
488 function refreshSecondaryAxisLimits()
490 global appDataStruct;
492 if isempty(appDataStruct)
497 if ~(isempty(appDataStruct.secondaryAxesXLim) ||...
498 isempty(appDataStruct.secondaryAxesYLim))
500 initialXLim = appDataStruct.secondaryAxesXLim;
501 initialYLim = appDataStruct.secondaryAxesYLim;
509 axis(appDataStruct.secondaryAxesHandle, limitsToSet);
511 appDataStruct.secondaryAxesXLim = [];
512 appDataStruct.secondaryAxesYLim = [];
514 %Get main axes limits, in axes units
515 mainAxesXLim = get( appDataStruct.mainAxesHandle, 'XLim' );
516 mainAxesYLim = get( appDataStruct.mainAxesHandle, 'YLim' );
517 mainAxesXDir = get( appDataStruct.mainAxesHandle, 'XDir' );
518 mainAxesYDir = get( appDataStruct.mainAxesHandle, 'YDir' );
520 %Get position and size of main axes in pixels
521 mainAxesPositionInPixels = getMainAxesPositionInPixels();
523 %Compute Pixels-to-axes units conversion factors
524 xMainAxisPixels2UnitsFactor = determineSpan( mainAxesXLim(1), mainAxesXLim(2) )/mainAxesPositionInPixels(3);
525 yMainAxisPixels2UnitsFactor = determineSpan( mainAxesYLim(1), mainAxesYLim(2) )/mainAxesPositionInPixels(4);
527 %Get position and extend of magnifier, in pixels
528 magnifierPosition = getMagnifierPositionInPixels(); %In pixels
530 %Relative to the lower-left corner of the axes
531 magnifierPosition(1) = magnifierPosition(1) - mainAxesPositionInPixels(1);
532 magnifierPosition(2) = magnifierPosition(2) - mainAxesPositionInPixels(2);
534 %Compute position and exted of magnifier, in axes units
535 magnifierPosition(3) = magnifierPosition(3) * xMainAxisPixels2UnitsFactor;
536 magnifierPosition(4) = magnifierPosition(4) * yMainAxisPixels2UnitsFactor;
537 if strcmpi(mainAxesXDir, 'normal') && strcmpi(mainAxesYDir, 'normal')
538 magnifierPosition(1) = mainAxesXLim(1) + magnifierPosition(1)*xMainAxisPixels2UnitsFactor;
539 magnifierPosition(2) = mainAxesYLim(1) + magnifierPosition(2)*yMainAxisPixels2UnitsFactor;
541 if strcmpi(mainAxesXDir, 'normal') && strcmpi(mainAxesYDir, 'reverse')
542 magnifierPosition(1) = mainAxesXLim(1) + magnifierPosition(1)*xMainAxisPixels2UnitsFactor;
543 magnifierPosition(2) = mainAxesYLim(2) - magnifierPosition(2)*yMainAxisPixels2UnitsFactor - magnifierPosition(4);
545 if strcmpi(mainAxesXDir, 'reverse') && strcmpi(mainAxesYDir, 'normal')
546 magnifierPosition(1) = mainAxesXLim(2) - magnifierPosition(1)*xMainAxisPixels2UnitsFactor - magnifierPosition(3);
547 magnifierPosition(2) = mainAxesYLim(1) + magnifierPosition(2)*yMainAxisPixels2UnitsFactor;
549 if strcmpi(mainAxesXDir, 'reverse') && strcmpi(mainAxesYDir, 'reverse')
550 magnifierPosition(1) = mainAxesXLim(2) - magnifierPosition(1)*xMainAxisPixels2UnitsFactor - magnifierPosition(3);
551 magnifierPosition(2) = mainAxesYLim(2) - magnifierPosition(2)*yMainAxisPixels2UnitsFactor - magnifierPosition(4);
554 secondaryAxisXlim = [magnifierPosition(1) magnifierPosition(1)+magnifierPosition(3)];
555 secondaryAxisYlim = [magnifierPosition(2) magnifierPosition(2)+magnifierPosition(4)];
557 zoomFactor = appDataStruct.secondaryAxesAdditionalZoomingFactor;
558 xZoom = zoomFactor(1);
559 yZoom = zoomFactor(2);
561 aux_secondaryAxisXlim(1) = mean(secondaryAxisXlim) -...
562 determineSpan( secondaryAxisXlim(1), mean(secondaryAxisXlim) )*(1-xZoom);
563 aux_secondaryAxisXlim(2) = mean(secondaryAxisXlim) +...
564 determineSpan( secondaryAxisXlim(2), mean(secondaryAxisXlim) )*(1-xZoom);
565 aux_secondaryAxisYlim(1) = mean(secondaryAxisYlim) -...
566 determineSpan( secondaryAxisYlim(1), mean(secondaryAxisYlim) )*(1-yZoom);
567 aux_secondaryAxisYlim(2) = mean(secondaryAxisYlim) +...
568 determineSpan( secondaryAxisYlim(2), mean(secondaryAxisYlim) )*(1-yZoom);
570 if aux_secondaryAxisXlim(1)<aux_secondaryAxisXlim(2) &&...
571 all(isfinite(aux_secondaryAxisXlim))
572 set( appDataStruct.secondaryAxesHandle, 'XLim', aux_secondaryAxisXlim );
574 if aux_secondaryAxisYlim(1)<aux_secondaryAxisYlim(2) &&...
575 all(isfinite(aux_secondaryAxisYlim))
576 set( appDataStruct.secondaryAxesHandle, 'YLim', aux_secondaryAxisYlim );
581 %Increase line width in plots on secondary axis
582 childHandle = get( appDataStruct.secondaryAxesHandle, 'Children');
583 for iChild = 1:length(childHandle)
584 if strcmpi(get(childHandle(iChild), 'Type'), 'line')
585 set(childHandle(iChild), 'LineWidth', 2);
587 if strcmpi(get(childHandle(iChild), 'Type'), 'image')
593 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
594 % NAME: determineSpan
596 % PURPOSE: Computes the distance between two real numbers on a 1D space.
599 % v1 [double 1x1]: first number
600 % v2 [double 1x1]: second number
602 % span [double 1x1]: computed span
604 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
605 function span = determineSpan( v1, v2 )
608 span = max(v1,v2) - min(v1,v2);
617 span = max(-v1,-v2) - min(-v1,-v2);
621 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
622 % NAME: ResizeCallback
624 % PURPOSE: Service routine to Resize event.
631 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
632 function ResizeCallback(src,eventdata)
634 global appDataStruct;
636 if isempty(appDataStruct)
641 toolArray = get(src, 'userdata');
643 if isempty(toolArray)
647 nTools = length( toolArray );
649 %Store Old&New Figure positions
650 oldFigurePosition = toolArray(1).figurePosition;
651 newFigurePosition = getFigurePositionInPixels();
653 %Backup global appDataStruct
654 appDataStructAux = appDataStruct;
658 %Modify global vaiable, accessed by functions called below
659 appDataStruct = initializeToolStruct( toolArray(i) );
661 %Set position of secondaryAxes (automatically modified)
662 toolArray(i).secondaryAxesPosition = getSecondaryAxesPositionInPixels();
665 toolArray(i).magnifierPosition(1) = toolArray(i).magnifierPosition(1) * newFigurePosition(3)/oldFigurePosition(3);
666 toolArray(i).magnifierPosition(2) = toolArray(i).magnifierPosition(2) * newFigurePosition(4)/oldFigurePosition(4);
667 toolArray(i).magnifierPosition(3) = toolArray(i).magnifierPosition(3) * newFigurePosition(3)/oldFigurePosition(3);
668 toolArray(i).magnifierPosition(4) = toolArray(i).magnifierPosition(4) * newFigurePosition(4)/oldFigurePosition(4);
669 setMagnifierPositionInPixels( toolArray(i).magnifierPosition );
671 %Update view limits on secondary axis
672 refreshSecondaryAxisLimits();
673 %Update link between secondary axes and magnifier
674 refreshMagnifierToSecondaryAxesLink();
677 %Update figure position
678 toolArray(i).figurePosition = getFigurePositionInPixels();
679 appDataStruct.figurePosition = toolArray(i).figurePosition;
684 set(toolArray(1).figureHandle, 'userdata', toolArray);
686 %Update appDataStruct
687 appDataStruct = appDataStructAux;
688 %Get current position of seconday axes (in pixels)
689 appDataStruct.secondaryAxesPosition = getSecondaryAxesPositionInPixels();
690 %Get magnifier current position and size
691 appDataStruct.magnifierPosition = getMagnifierPositionInPixels();
693 clear appDataStructAux;
699 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
700 % NAME: KeyPressCallback
702 % PURPOSE: Service routine to KeyPress event.
709 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
710 function KeyPressCallback(src,eventdata)
714 if isempty(appDataStruct)
718 currentCaracter = eventdata.Key;
719 currentModifier = eventdata.Modifier;
721 switch(currentCaracter)
722 case {'leftarrow'} % left arrow
723 %Move magnifier to the left
724 if isempty(currentModifier)
726 position = getMagnifierPositionInPixels();
727 magnifierPosition(1) = position(1)-1;
728 magnifierPosition(2) = position(2);
729 magnifierPosition(3) = position(3);
730 magnifierPosition(4) = position(4);
731 setMagnifierPositionInPixels( magnifierPosition );
733 toolArray = get( src, 'UserData' );
734 focusedTool = find([toolArray.focusOnThisTool] == 1);
735 toolArray(focusedTool) = updateToolId( toolArray(focusedTool), focusedTool, 'noToggle' );
736 set( src, 'UserData', toolArray );
739 %Compress magnifier on the X axis
740 if strcmp(currentModifier, 'shift')
741 position = getMagnifierPositionInPixels();
742 magnifierPosition(3) = position(3)*(1 - 0.1);
743 if strcmpi( appDataStruct.globalZoomMode, 'off')
744 magnifierPosition(4) = position(4);
746 %If 'freezeZoomAspectRatio' to 'on', be consistent
747 magnifierPosition(4) = position(4)*(1 - 0.1);
749 magnifierPosition(1) = position(1)-(-position(3)+magnifierPosition(3))/2;
750 magnifierPosition(2) = position(2)-(-position(4)+magnifierPosition(4))/2;
751 setMagnifierPositionInPixels( magnifierPosition );
753 %Move secondary axes to the left
754 if strcmp(currentModifier, 'control')
755 position = getSecondaryAxesPositionInPixels();
756 secondaryAxesPosition(1) = position(1)-1;
757 secondaryAxesPosition(2) = position(2);
758 secondaryAxesPosition(3) = position(3);
759 secondaryAxesPosition(4) = position(4);
760 setSecondaryAxesPositionInPixels( secondaryAxesPosition );
762 %Compress secondary axes on the X axis
763 if strcmp(currentModifier, 'alt')
764 position = getSecondaryAxesPositionInPixels();
765 secondaryAxesPosition(3) = position(3)*(1 - 0.1);
766 if strcmpi( appDataStruct.globalZoomMode, 'off')
767 secondaryAxesPosition(4) = position(4);
769 %If 'freezeZoomAspectRatio' to 'on', be consistent
770 secondaryAxesPosition(4) = position(4)*(1 - 0.1);
772 secondaryAxesPosition(1) = position(1)-(-position(3)+secondaryAxesPosition(3))/2;
773 secondaryAxesPosition(2) = position(2)-(-position(4)+secondaryAxesPosition(4))/2;
774 setSecondaryAxesPositionInPixels( secondaryAxesPosition );
777 case {'rightarrow'} % right arrow
778 %Move magnifier to the right
779 if isempty(currentModifier)
780 position = getMagnifierPositionInPixels();
781 magnifierPosition(1) = position(1)+1;
782 magnifierPosition(2) = position(2);
783 magnifierPosition(3) = position(3);
784 magnifierPosition(4) = position(4);
785 setMagnifierPositionInPixels( magnifierPosition );
787 toolArray = get( src, 'UserData' );
788 focusedTool = find([toolArray.focusOnThisTool] == 1);
789 toolArray(focusedTool) = updateToolId( toolArray(focusedTool), focusedTool, 'noToggle' );
790 set( src, 'UserData', toolArray );
793 %Expand magnifier on the X axis
794 if strcmp(currentModifier, 'shift')
795 position = getMagnifierPositionInPixels();
796 magnifierPosition(3) = position(3)*(1 + 0.1);
797 if strcmpi( appDataStruct.globalZoomMode, 'off')
798 magnifierPosition(4) = position(4);
800 %If 'freezeZoomAspectRatio' to 'on', be consistent
801 magnifierPosition(4) = position(4)*(1 + 0.1);
803 magnifierPosition(1) = position(1)-(-position(3)+magnifierPosition(3))/2;
804 magnifierPosition(2) = position(2)-(-position(4)+magnifierPosition(4))/2;
805 setMagnifierPositionInPixels( magnifierPosition );
807 %Move secondary axes to the right
808 if strcmp(currentModifier, 'control')
809 position = getSecondaryAxesPositionInPixels();
810 secondaryAxesPosition(1) = position(1)+1;
811 secondaryAxesPosition(2) = position(2);
812 secondaryAxesPosition(3) = position(3);
813 secondaryAxesPosition(4) = position(4);
814 setSecondaryAxesPositionInPixels( secondaryAxesPosition );
816 %Expand secondary axes on the X axis
817 if strcmp(currentModifier, 'alt')
818 position = getSecondaryAxesPositionInPixels();
819 secondaryAxesPosition(3) = position(3)*(1 + 0.1);
820 if strcmpi( appDataStruct.globalZoomMode, 'off')
821 secondaryAxesPosition(4) = position(4);
823 %If 'freezeZoomAspectRatio' to 'on', be consistent
824 secondaryAxesPosition(4) = position(4)*(1 + 0.1);
826 secondaryAxesPosition(1) = position(1)-(-position(3)+secondaryAxesPosition(3))/2;
827 secondaryAxesPosition(2) = position(2)-(-position(4)+secondaryAxesPosition(4))/2;
828 setSecondaryAxesPositionInPixels( secondaryAxesPosition );
831 case {'uparrow'} % up arrow
832 %Move magnifier to the top
833 if isempty(currentModifier)
834 position = getMagnifierPositionInPixels();
835 magnifierPosition(1) = position(1);
836 magnifierPosition(2) = position(2)+1;
837 magnifierPosition(3) = position(3);
838 magnifierPosition(4) = position(4);
839 setMagnifierPositionInPixels( magnifierPosition );
841 toolArray = get( src, 'UserData' );
842 focusedTool = find([toolArray.focusOnThisTool] == 1);
843 toolArray(focusedTool) = updateToolId( toolArray(focusedTool), focusedTool, 'noToggle' );
844 set( src, 'UserData', toolArray );
847 %Expand magnifier on the Y axis
848 if strcmp(currentModifier, 'shift')
849 position = getMagnifierPositionInPixels();
850 if strcmpi( appDataStruct.globalZoomMode, 'off')
851 magnifierPosition(3) = position(3);
853 %If 'freezeZoomAspectRatio' to 'on', be consistent
854 magnifierPosition(3) = position(3)*(1 + 0.1);
856 magnifierPosition(4) = position(4)*(1 + 0.1);
857 magnifierPosition(1) = position(1)-(-position(3)+magnifierPosition(3))/2;
858 magnifierPosition(2) = position(2)-(-position(4)+magnifierPosition(4))/2;
859 setMagnifierPositionInPixels( magnifierPosition );
861 %Move secondary axes to the top
862 if strcmp(currentModifier, 'control')
863 position = getSecondaryAxesPositionInPixels();
864 secondaryAxesPosition(1) = position(1);
865 secondaryAxesPosition(2) = position(2)+1;
866 secondaryAxesPosition(3) = position(3);
867 secondaryAxesPosition(4) = position(4);
868 setSecondaryAxesPositionInPixels( secondaryAxesPosition );
870 %Expand secondary axes on the Y axis
871 if strcmp(currentModifier, 'alt')
872 position = getSecondaryAxesPositionInPixels();
873 if strcmpi( appDataStruct.globalZoomMode, 'off')
874 secondaryAxesPosition(3) = position(3);
876 %If 'freezeZoomAspectRatio' to 'on', be consistent
877 secondaryAxesPosition(3) = position(3)*(1 + 0.1);
879 secondaryAxesPosition(4) = position(4)*(1 + 0.1);
880 secondaryAxesPosition(1) = position(1)-(-position(3)+secondaryAxesPosition(3))/2;
881 secondaryAxesPosition(2) = position(2)-(-position(4)+secondaryAxesPosition(4))/2;
882 setSecondaryAxesPositionInPixels( secondaryAxesPosition );
885 case {'downarrow'} % down arrow
886 %Move magnifier to the bottom
887 if isempty(currentModifier)
888 position = getMagnifierPositionInPixels();
889 magnifierPosition(1) = position(1);
890 magnifierPosition(2) = position(2)-1;
891 magnifierPosition(3) = position(3);
892 magnifierPosition(4) = position(4);
893 setMagnifierPositionInPixels( magnifierPosition );
895 toolArray = get( src, 'UserData' );
896 focusedTool = find([toolArray.focusOnThisTool] == 1);
897 toolArray(focusedTool) = updateToolId( toolArray(focusedTool), focusedTool, 'noToggle' );
898 set( src, 'UserData', toolArray );
901 %Compress magnifier on the Y axis
902 if strcmp(currentModifier, 'shift')
903 position = getMagnifierPositionInPixels();
904 if strcmpi( appDataStruct.globalZoomMode, 'off')
905 magnifierPosition(3) = position(3);
907 %If 'freezeZoomAspectRatio' to 'on', be consistent
908 magnifierPosition(3) = position(3)*(1 - 0.1);
910 magnifierPosition(4) = position(4)*(1 - 0.1);
911 magnifierPosition(1) = position(1)-(-position(3)+magnifierPosition(3))/2;
912 magnifierPosition(2) = position(2)-(-position(4)+magnifierPosition(4))/2;
913 setMagnifierPositionInPixels( magnifierPosition );
915 %Move secondary axes to the bottom
916 if strcmp(currentModifier, 'control')
917 position = getSecondaryAxesPositionInPixels();
918 secondaryAxesPosition(1) = position(1);
919 secondaryAxesPosition(2) = position(2)-1;
920 secondaryAxesPosition(3) = position(3);
921 secondaryAxesPosition(4) = position(4);
922 setSecondaryAxesPositionInPixels( secondaryAxesPosition );
924 %Compress secondary axes on the Y axis
925 if strcmp(currentModifier, 'alt')
926 position = getSecondaryAxesPositionInPixels();
927 if strcmpi( appDataStruct.globalZoomMode, 'off')
928 secondaryAxesPosition(3) = position(3);
930 %If 'freezeZoomAspectRatio' to 'on', be consistent
931 secondaryAxesPosition(3) = position(3)*(1 - 0.1);
933 secondaryAxesPosition(4) = position(4)*(1 - 0.1);
934 secondaryAxesPosition(1) = position(1)-(-position(3)+secondaryAxesPosition(3))/2;
935 secondaryAxesPosition(2) = position(2)-(-position(4)+secondaryAxesPosition(4))/2;
936 setSecondaryAxesPositionInPixels( secondaryAxesPosition );
939 case {'tab'} % Tabulator
940 %Switch focus to next magnifier instance on the current figure
941 toolArray = get( src, 'UserData' );
942 nTools = length(toolArray);
943 focusedTool = find([toolArray.focusOnThisTool] == 1);
944 if focusedTool ~= nTools
945 nextFocusedTool = focusedTool+1;
949 appDataStruct = initializeToolStruct( toolArray(nextFocusedTool) );
950 appDataStruct.focusOnThisTool = 1;
951 toolArray(focusedTool).focusOnThisTool = 0;
952 toolArray(nextFocusedTool).focusOnThisTool = 1;
953 if not(isempty(toolArray(focusedTool).toolIdHandle))
954 set(toolArray(focusedTool).toolIdHandle,'BackgroundColor', 'black', 'Color', 'white');
955 set(toolArray(nextFocusedTool).toolIdHandle,'BackgroundColor', 'red', 'Color', 'white');
958 set( src, 'UserData', toolArray );
961 %Delete focused instance
962 if strcmp(currentModifier, 'control')
963 toolArray = get( src, 'UserData' );
964 nTools = length(toolArray);
965 focusedTool = find([toolArray.focusOnThisTool] == 1);
967 delete(toolArray(focusedTool).magnifierHandle);
968 delete(toolArray(focusedTool).linkHandle);
969 delete(toolArray(focusedTool).secondaryAxesHandle);
972 %Set focus to next instance
973 if focusedTool ~= nTools
974 nextFocusedTool = focusedTool+1;
978 toolArray(nextFocusedTool).focusOnThisTool = 1;
979 appDataStruct = initializeToolStruct( toolArray(nextFocusedTool) );
981 toolArray(focusedTool) = [];
982 set( src, 'UserData', toolArray );
985 %No instance to set focus on
987 set( src, 'UserData', [] );
994 if strcmp(currentModifier, 'control')
995 magnifierPosition = getMagnifierPositionInPixels();
996 disp(sprintf('Magnifier position: [%g %g %g %g];', magnifierPosition(1), magnifierPosition(2), magnifierPosition(3), magnifierPosition(4) ));
997 secondaryAxesPosition = getSecondaryAxesPositionInPixels();
998 disp(sprintf('Secondary axes position: [%g %g %g %g];', secondaryAxesPosition(1), secondaryAxesPosition(2), secondaryAxesPosition(3), secondaryAxesPosition(4) ));
1002 %additional xooming factors reseted
1003 if strcmp(currentModifier, 'control')
1004 appDataStruct.secondaryAxesAdditionalZoomingFactor = [0 0];
1008 %display/hide on-screen tool identifier
1009 if strcmp(currentModifier, 'control')
1010 toolArray = get( src, 'UserData' );
1011 nTools = length(toolArray);
1012 for iTool = 1:nTools
1014 toolArray(iTool) = updateToolId( toolArray(iTool), iTool, 'toggle' );
1017 set( src, 'UserData', toolArray );
1021 case {'pageup'} % '+'
1022 zoomFactor = appDataStruct.secondaryAxesAdditionalZoomingFactor;
1024 %Increase additional zooming factor on X-axis
1025 if isempty(currentModifier)
1026 zoomFactor(1) = zoomFactor(1) + 0.1;
1027 if strcmpi( appDataStruct.globalZoomMode, 'on')
1028 zoomFactor(2) = zoomFactor(2) + 0.1;
1030 appDataStruct.secondaryAxesAdditionalZoomingFactor = zoomFactor;
1032 %Increase additional zooming factor on Y-axis
1033 if strcmp(currentModifier, 'shift')
1034 zoomFactor(2) = zoomFactor(2) + 0.1;
1035 if strcmpi( appDataStruct.globalZoomMode, 'on')
1036 zoomFactor(1) = zoomFactor(1) + 0.1;
1038 appDataStruct.secondaryAxesAdditionalZoomingFactor = zoomFactor;
1041 case {'pagedown'} % '-'
1042 zoomFactor = appDataStruct.secondaryAxesAdditionalZoomingFactor;
1044 %Redude additional zooming factor on X-axis
1045 if isempty(currentModifier)
1046 zoomFactor(1) = zoomFactor(1) - 0.1;
1047 if strcmpi( appDataStruct.globalZoomMode, 'on')
1048 zoomFactor(2) = zoomFactor(2) - 0.1;
1050 appDataStruct.secondaryAxesAdditionalZoomingFactor = zoomFactor;
1052 %Redude additional zooming factor on Y-axis
1053 if strcmp(currentModifier, 'shift')
1054 zoomFactor(2) = zoomFactor(2) - 0.1;
1055 if strcmpi( appDataStruct.globalZoomMode, 'on')
1056 zoomFactor(1) = zoomFactor(1) - 0.1;
1058 appDataStruct.secondaryAxesAdditionalZoomingFactor = zoomFactor;
1066 %Update view limits on secondary axis
1067 refreshSecondaryAxisLimits();
1069 %Update link between secondary axes and magnifier
1070 refreshMagnifierToSecondaryAxesLink();
1073 % toolArray = get(src, 'userdata');
1074 % focusedTool = find([toolArray.focusOnThisTool] == 1);
1075 % toolArray(focusedTool) = appDataStruct;
1076 % set(src, 'userData', toolArray);
1080 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1081 % NAME: ButtonMotionCallback
1083 % PURPOSE: Service routine to ButtonMotion event.
1090 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1091 function ButtonMotionCallback(src,eventdata)
1093 global appDataStruct
1095 if isempty(appDataStruct)
1099 % pointerPos = get(appDataStructuct.figure.handle, 'CurrentPoint');
1100 % disp(sprintf('X: %g ; Y: %g', pointerPos(1), pointerPos(2)) );
1104 %If Left mouse button not pressed, exit
1105 if appDataStruct.ButtonDown == false
1110 %If Left mouse button pressed while the pointer is moving (drag)
1111 switch appDataStruct.pointerArea
1113 case 'insideSecondaryAxis'
1114 %Get current position of seconday axes (in pixels)
1115 appDataStruct.secondaryAxesPosition = getSecondaryAxesPositionInPixels();
1117 %Get pointer position on figure's frame
1118 currentPointerPositionOnFigureFrame = getPointerPositionOnFigureFrame();
1120 pointerPositionOnButtonDown = appDataStruct.pointerPositionOnButtonDown;
1123 secondaryAxisPosition_W = appDataStruct.secondaryAxesPosition(3);
1124 secondaryAxisPosition_H = appDataStruct.secondaryAxesPosition(4);
1125 secondaryAxisPosition_X = appDataStruct.secondaryAxesPosition(1) + (-pointerPositionOnButtonDown(1)+currentPointerPositionOnFigureFrame(1));
1126 secondaryAxisPosition_Y = appDataStruct.secondaryAxesPosition(2) + (-pointerPositionOnButtonDown(2)+currentPointerPositionOnFigureFrame(2));
1127 appDataStruct.pointerPositionOnButtonDown = currentPointerPositionOnFigureFrame;
1129 %Set initial position and size of secondary axes
1130 setSecondaryAxesPositionInPixels( [...
1131 secondaryAxisPosition_X,...
1132 secondaryAxisPosition_Y,...
1133 secondaryAxisPosition_W,...
1134 secondaryAxisPosition_H...
1138 case 'insideMagnifier'
1139 %Get magnifier current position and size
1140 appDataStruct.magnifierPosition = getMagnifierPositionInPixels();
1142 %Get pointer position on figure's frame
1143 currentPointerPosition = getPointerPositionOnFigureFrame();
1145 pointerPositionOnButtonDown = appDataStruct.pointerPositionOnButtonDown;
1147 %Modify magnifier position
1148 magnifierPosition_W = appDataStruct.magnifierPosition(3);
1149 magnifierPosition_H = appDataStruct.magnifierPosition(4);
1150 magnifierPosition_X = appDataStruct.magnifierPosition(1) + (-pointerPositionOnButtonDown(1)+currentPointerPosition(1));
1151 magnifierPosition_Y = appDataStruct.magnifierPosition(2) + (-pointerPositionOnButtonDown(2)+currentPointerPosition(2));
1152 appDataStruct.pointerPositionOnButtonDown = currentPointerPosition;
1154 %Set initial position and size of magnifying rectangle
1155 setMagnifierPositionInPixels( [...
1156 magnifierPosition_X...
1157 magnifierPosition_Y...
1158 magnifierPosition_W...
1159 magnifierPosition_H...
1162 %Refresh zooming on secondary axis, based on magnifier position and extend
1163 refreshSecondaryAxisLimits();
1165 toolArray = get( src, 'UserData' );
1166 focusedTool = find([toolArray.focusOnThisTool] == 1);
1167 toolArray(focusedTool) = updateToolId( toolArray(focusedTool), focusedTool, 'noToggle' );
1168 set( src, 'UserData', toolArray );
1171 % appDataStructuct.pointerArea
1175 %Update link between secondary axes and magnifier
1176 refreshMagnifierToSecondaryAxesLink();
1178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1179 % NAME: ButtonDownCallback
1181 % PURPOSE: Service routine to ButtonDown event.
1188 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1189 function ButtonDownCallback(src,eventdata)
1191 global appDataStruct
1193 if isempty(appDataStruct)
1197 if strcmpi( get(appDataStruct.figureHandle, 'SelectionType'), 'normal' )
1199 %Respond to left mouse button
1200 appDataStruct.ButtonDown = true;
1201 %Get pointer position on figure's frame
1202 appDataStruct.pointerPositionOnButtonDown = getPointerPositionOnFigureFrame();
1204 elseif strcmpi( get(appDataStruct.figureHandle, 'SelectionType'), 'alt' )
1206 %Display contextual menu?
1208 elseif strcmpi( get(appDataStruct.figureHandle, 'SelectionType'), 'open' )
1210 %Is pointer on any active area?
1211 toolArray = get(src, 'userdata');
1212 nTools = length(toolArray);
1213 focusedTool = find([toolArray.focusOnThisTool] == 1);
1214 nextFocusedTool = 0;
1215 foundActive = false;
1216 while nextFocusedTool<=nTools-1 && foundActive == false
1218 nextFocusedTool = nextFocusedTool+1;
1219 appDataStructAux = appDataStruct;
1220 appDataStruct = initializeToolStruct( toolArray(nextFocusedTool) );
1222 if ~strcmp( appDataStruct.pointerArea, 'none')
1227 if foundActive == true
1228 %Switch focus to next magnifier instance on the current figure
1229 appDataStruct = initializeToolStruct( toolArray(nextFocusedTool) );
1230 appDataStruct.focusOnThisTool = 1;
1231 toolArray(focusedTool).focusOnThisTool = 0;
1232 toolArray(nextFocusedTool).focusOnThisTool = 1;
1233 if not(isempty(toolArray(focusedTool).toolIdHandle))
1234 set(toolArray(focusedTool).toolIdHandle,'BackgroundColor', 'black', 'Color', 'white');
1235 set(toolArray(nextFocusedTool).toolIdHandle,'BackgroundColor', 'red', 'Color', 'white');
1237 set( src, 'UserData', toolArray );
1241 appDataStruct = appDataStructAux;
1246 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1247 % NAME: ButtonUpCallback
1249 % PURPOSE: Service routine to ButtonUp event.
1256 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1257 function ButtonUpCallback(src,eventdata)
1259 global appDataStruct
1261 if isempty(appDataStruct)
1265 % if strcmp(appDataStruct.pointerArea, 'insideMagnifier')
1266 % %Refresh zooming on secondary axis, based on magnifier position and extend
1267 % refreshSecondaryAxisLimits();
1270 appDataStruct.ButtonDown = false;
1272 toolArray = get(src, 'userdata');
1273 focusedTool = find([toolArray.focusOnThisTool] == 1);
1274 toolArray(focusedTool).ButtonDown = false;
1275 set(src, 'userdata', toolArray);
1277 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1278 % NAME: DeleteCallback
1280 % PURPOSE: Service routine to Delete event.
1287 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1288 function DeleteCallback(src,eventdata)
1290 global appDataStruct;
1292 if isempty(appDataStruct)
1296 toolArray = get(src, 'UserData');
1298 %Recover old callback handles from the first instance
1299 set( src, 'WindowButtonDownFcn', toolArray(1).figureOldWindowButtonDownFcn );
1300 set( src, 'WindowButtonUpFcn', toolArray(1).figureOldWindowButtonUpFcn );
1301 set( src, 'WindowButtonMotionFcn', toolArray(1).figureOldWindowButtonMotionFcn );
1302 set( src, 'KeyPressFcn', toolArray(1).figureOldKeyPressFcn );
1303 set( src, 'DeleteFcn', toolArray(1).figureOldDeleteFcn );
1304 set( src, 'ResizeFcn', toolArray(1).figureOldResizeFcn );
1306 %Clear global variable when figure is closed
1307 clear global appDataStructuct;
1310 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1311 % NAME: getPointerPositionOnFigureFrame
1313 % PURPOSE: determine if the position of the mouse pointer on the figure frame, in pixels.
1318 % pointerPositionOnFigureFrame [double 1x2]: (X Y)
1321 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1322 function pointerPositionOnFigureFrame = getPointerPositionOnFigureFrame()
1324 global appDataStruct
1326 if isempty(appDataStruct)
1330 %Get position of mouse pointer on screen
1331 defaultUnits = get(appDataStruct.figureHandle,'Units');
1332 set(appDataStruct.figureHandle, 'Units', 'pixels');
1333 pointerPositionOnFigureFrame = get(appDataStruct.figureHandle,'CurrentPoint');
1334 set(appDataStruct.figureHandle, 'Units', defaultUnits);
1336 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1337 % NAME: getPointerArea
1339 % PURPOSE: determine if the mouse pointer is on an active area. Change
1340 % pointer image if this is the case, and communicate the status.
1343 % appDataStructuct [struct 1x1]: global variable
1345 % change image of pointer (ACTION)
1346 % appDataStructuct.pointerArea: ID of the active area
1348 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1349 function getPointerArea()
1351 global appDataStruct
1353 if isempty(appDataStruct)
1357 %Get current pointer position on figure frame
1358 pointerPositionOnFigureFrame = getPointerPositionOnFigureFrame();
1360 %Get current secondaryAxes position
1361 secondaryAxesPosition = getSecondaryAxesPositionInPixels();
1363 %Get current magnifier position
1364 magnifierPosition = getMagnifierPositionInPixels();
1366 %If mouse pointer on the secondary axis
1367 if pointerPositionOnFigureFrame(1)>=secondaryAxesPosition(1) &&...
1368 pointerPositionOnFigureFrame(1)<=secondaryAxesPosition(1)+secondaryAxesPosition(3) &&...
1369 pointerPositionOnFigureFrame(2)>=secondaryAxesPosition(2) &&...
1370 pointerPositionOnFigureFrame(2)<=secondaryAxesPosition(2)+secondaryAxesPosition(4)
1371 %Pointer inside secondary axis
1372 set(appDataStruct.figureHandle, 'Pointer', 'fleur');
1374 appDataStruct.pointerArea = 'insideSecondaryAxis';
1376 elseif pointerPositionOnFigureFrame(1)>=magnifierPosition(1) &&...
1377 pointerPositionOnFigureFrame(1)<=magnifierPosition(1)+magnifierPosition(3) &&...
1378 pointerPositionOnFigureFrame(2)>=magnifierPosition(2) &&...
1379 pointerPositionOnFigureFrame(2)<=magnifierPosition(2)+magnifierPosition(4)
1380 %Pointer inside magnifier
1381 set(appDataStruct.figureHandle, 'Pointer', 'fleur');
1383 appDataStruct.pointerArea = 'insideMagnifier';
1387 set(appDataStruct.figureHandle, 'Pointer', 'arrow');
1389 appDataStruct.pointerArea = 'none';
1392 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1393 % NAME: getFigurePositionInPixels
1395 % PURPOSE: obtain the position and size of the figure, relative to the
1396 % lower left corner of the screen, in pixels.
1401 % position [double 1x4]:
1402 % X of lower left corner of the figure frame
1403 % Y of lower left corner of the figure frame
1404 % Width of the figure frame
1405 % Height of the figure frame
1407 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1408 function position = getFigurePositionInPixels()
1410 global appDataStruct
1412 if isempty(appDataStruct)
1416 defaultUnits = get(appDataStruct.figureHandle,'Units');
1417 set(appDataStruct.figureHandle,'Units', 'pixels');
1418 position = get(appDataStruct.figureHandle,'Position'); %pixels [ low bottom width height]
1419 set(appDataStruct.figureHandle,'Units', defaultUnits);
1421 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1422 % NAME: getMainAxesPositionInPixels
1424 % PURPOSE: obtain the position and size of the main axes, relative to the
1425 % lower left corner of the figure, in pixels. This fucntion locates the
1426 % lower-left corner of the displayed axes, accounting for all conditions of
1427 % DataAspectRatio and PlotBoxAspectRatio.
1432 % position [double 1x4]:
1433 % X of lower left corner of the axis frame
1434 % Y of lower left corner of the axis frame
1435 % Width of the axis frame
1436 % Height of the axis frame
1438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1439 function position = getMainAxesPositionInPixels()
1441 global appDataStruct
1443 if isempty(appDataStruct)
1448 %Characterize mainAxes in axes units
1449 mainAxisXLim = get( appDataStruct.mainAxesHandle, 'XLim' );
1450 mainAxisYLim = get( appDataStruct.mainAxesHandle, 'YLim' );
1451 spanX = determineSpan(mainAxisXLim(1), mainAxisXLim(2) );
1452 spanY = determineSpan(mainAxisYLim(1), mainAxisYLim(2));
1454 %Capture default units of mainAxes, and fix units to 'pixels'
1455 defaultUnits = get(appDataStruct.mainAxesHandle,'Units');
1456 set(appDataStruct.mainAxesHandle, 'Units', 'pixels');
1458 %Obtain values in 'pixels'
1459 mainAxesPosition = get(appDataStruct.mainAxesHandle, 'Position');
1460 dataAspectRatioMode = get(appDataStruct.mainAxesHandle, 'DataAspectRatioMode');
1461 dataAspectRatio = get(appDataStruct.mainAxesHandle, 'DataAspectRatio');
1462 plotBoxAspectRatioMode = get(appDataStruct.mainAxesHandle, 'PlotBoxAspectRatioMode');
1463 plotBoxAspectRatio = get(appDataStruct.mainAxesHandle, 'PlotBoxAspectRatio');
1465 %Determine correction values
1466 dataAspectRatioLimits = (spanX/dataAspectRatio(1))/(spanY/dataAspectRatio(2));
1467 plotBoxAspectRatioRelation = plotBoxAspectRatio(1)/plotBoxAspectRatio(2);
1468 mainAxesRatio = mainAxesPosition(3)/mainAxesPosition(4);
1470 %Id DataAspectRatio to auto and PlotBoxAspectRatio to auto
1471 if ~strcmpi( dataAspectRatioMode, 'manual') && ~strcmpi( plotBoxAspectRatioMode, 'manual')
1473 %Recover default units of mainAxes
1474 set(appDataStruct.mainAxesHandle,'Units', defaultUnits);
1476 %Obtain 'real' position from a temporal axes
1477 temporalAxes = axes('Visible', 'off');
1478 set(temporalAxes, 'Units', 'pixels');
1479 set(temporalAxes, 'Position', mainAxesPosition);
1480 position = get(temporalAxes, 'Position');
1481 delete(temporalAxes);
1486 %If DataAspectRatio to manual
1487 if strcmpi( dataAspectRatioMode, 'manual')
1488 if dataAspectRatioLimits <= mainAxesRatio
1489 position(4) = mainAxesPosition(4);
1490 position(3) = mainAxesPosition(4) * dataAspectRatioLimits;
1491 position(2) = mainAxesPosition(2);
1492 position(1) = mainAxesPosition(1) + (mainAxesPosition(3) - position(3))/2;
1495 position(1) = mainAxesPosition(1);
1496 position(3) = mainAxesPosition(3);
1497 position(4) = mainAxesPosition(3)/dataAspectRatioLimits;
1498 position(2) = mainAxesPosition(2) + (mainAxesPosition(4) - position(4))/2;
1501 elseif strcmpi( plotBoxAspectRatioMode, 'manual')
1502 % Or PlotBoxAspectRatio to manual
1503 if plotBoxAspectRatioRelation <= mainAxesRatio
1504 position(4) = mainAxesPosition(4);
1505 position(3) = mainAxesPosition(4) * plotBoxAspectRatioRelation;
1506 position(2) = mainAxesPosition(2);
1507 position(1) = mainAxesPosition(1) + (mainAxesPosition(3) - position(3))/2;
1510 position(1) = mainAxesPosition(1);
1511 position(3) = mainAxesPosition(3);
1512 position(4) = mainAxesPosition(3)/plotBoxAspectRatioRelation;
1513 position(2) = mainAxesPosition(2) + (mainAxesPosition(4) - position(4))/2;
1518 %Recover default units of mainAxes
1519 set(appDataStruct.mainAxesHandle, 'Units', defaultUnits);
1521 %Obtain 'real' position from a temporal axes
1522 temporalAxes = axes('Visible', 'off');
1523 set(temporalAxes, 'Units', 'pixels');
1524 set(temporalAxes, 'Position', position );
1525 position = get(temporalAxes, 'Position');
1526 delete(temporalAxes);
1530 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1531 % NAME: getMagnifierPositionInPixels
1533 % PURPOSE: obtain the position (of the lower left corner) and size of the
1534 % magnifier, relative to the lower left corner of the figure, in pixels.
1539 % position [double 1x4]:
1540 % X of lower left corner of the magnifier
1541 % Y of lower left corner of the magnifier
1542 % Width of the magnifier
1543 % Height of the magnifier
1545 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1546 function position = getMagnifierPositionInPixels()
1548 global appDataStruct
1550 if isempty(appDataStruct)
1554 defaultUnits = get(appDataStruct.magnifierHandle, 'Units');
1555 set(appDataStruct.magnifierHandle, 'Units', 'pixels');
1556 position = get(appDataStruct.magnifierHandle, 'Position');
1557 set(appDataStruct.magnifierHandle, 'Units', defaultUnits );
1559 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1560 % NAME: getSecondaryAxesPositionInPixels
1562 % PURPOSE: obtain the position and size of the secondary axis, relative to the
1563 % lower left corner of the figure, in pixels. Includes legends and axes
1569 % position [double 1x4]:
1570 % X of lower left corner of the axis frame
1571 % Y of lower left corner of the axis frame
1572 % Width of the axis frame
1573 % Height of the axis frame
1575 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1576 function position = getSecondaryAxesPositionInPixels()
1578 global appDataStruct
1580 if isempty(appDataStruct)
1584 defaultUnits = get(appDataStruct.secondaryAxesHandle,'Units');
1585 set(appDataStruct.secondaryAxesHandle,'Units', 'pixels');
1586 position = get(appDataStruct.secondaryAxesHandle,'Position'); %[ left bottom width height]
1587 set(appDataStruct.secondaryAxesHandle,'Units', defaultUnits);
1590 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1591 % NAME: setSecondaryAxesPositionInPixels
1593 % PURPOSE: fix the position and size of the secondary axis, relative to the
1594 % lower left corner of the figure, in pixels.
1597 % position [double 1x4]:
1598 % X of lower left corner of the axis frame
1599 % Y of lower left corner of the axis frame
1600 % Width of the axis frame
1601 % Height of the axis frame
1605 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1606 function setSecondaryAxesPositionInPixels( position )
1608 global appDataStruct
1610 if isempty(appDataStruct)
1614 %Get position of secondary axes
1615 defaultUnits = get(appDataStruct.secondaryAxesHandle,'Units');
1616 set(appDataStruct.secondaryAxesHandle, 'Units', 'pixels');
1617 set( appDataStruct.secondaryAxesHandle,...
1625 % tightInset = get( appDataStruct.secondaryAxes.handle, 'TightInset' );
1626 set(appDataStruct.secondaryAxesHandle,'Units', defaultUnits);
1628 %Update appDataStruct
1629 appDataStruct.secondaryAxesPosition = getSecondaryAxesPositionInPixels();
1632 toolArray = get(appDataStruct.figureHandle, 'userdata');
1633 if ~isempty(toolArray)
1634 focusedTool = find([toolArray.focusOnThisTool] == 1);
1635 toolArray(focusedTool).secondaryAxesPosition = appDataStruct.secondaryAxesPosition;
1636 set(appDataStruct.figureHandle, 'userdata', toolArray);
1639 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1640 % NAME: setMagnifierPositionInPixels
1642 % PURPOSE: fix the position and size of the magnifier, relative to the
1643 % lower left corner of the figure, in pixels.
1646 % position [double 1x4]:
1647 % X of lower left corner of the magnifier
1648 % Y of lower left corner of the magnifier
1649 % Width of the magnifier frame
1650 % Height of the magnifier frame
1654 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1655 function setMagnifierPositionInPixels( position )
1658 global appDataStruct
1660 if isempty(appDataStruct)
1664 %Limit position of magnifier within the main axes
1665 mainAxesPosition = getMainAxesPositionInPixels();
1666 if position(1)<mainAxesPosition(1)
1667 position(1) = mainAxesPosition(1);
1669 if position(1)+position(3)>mainAxesPosition(1)+mainAxesPosition(3)
1670 position(1) = mainAxesPosition(1)+mainAxesPosition(3)-position(3);
1672 if position(2)<mainAxesPosition(2)
1673 position(2) = mainAxesPosition(2);
1675 if position(2)+position(4)>mainAxesPosition(2)+mainAxesPosition(4)
1676 position(2) = mainAxesPosition(2)+mainAxesPosition(4)-position(4);
1679 %Create of set magnifier
1680 if isempty(appDataStruct.magnifierHandle)
1682 if strcmpi(appDataStruct.magnifierShape, 'rectangle')
1683 appDataStruct.magnifierHandle = ...
1684 annotation( 'rectangle',...
1685 'Units', 'pixels',...
1686 'Position', position,...
1687 'LineWidth', appDataStruct.globalEdgeWidth,...
1689 'EdgeColor', appDataStruct.globalEdgeColor...
1692 if strcmpi(appDataStruct.magnifierShape, 'ellipse')
1693 appDataStruct.magnifierHandle = ...
1694 annotation( 'ellipse',...
1695 'Units', 'pixels',...
1696 'Position', position,...
1697 'LineWidth', appDataStruct.globalEdgeWidth,...
1699 'EdgeColor', appDataStruct.globalEdgeColor...
1704 set( appDataStruct.magnifierHandle,...
1705 'Position', position,...
1706 'LineWidth', appDataStruct.globalEdgeWidth,...
1707 'EdgeColor', appDataStruct.globalEdgeColor );
1710 %Update appDataStruct
1711 appDataStruct.magnifierPosition = getMagnifierPositionInPixels();
1714 toolArray = get(appDataStruct.figureHandle, 'userdata');
1715 if ~isempty(toolArray)
1716 focusedTool = find([toolArray.focusOnThisTool] == 1);
1717 toolArray(focusedTool).magnifierPosition = appDataStruct.magnifierPosition;
1718 set(appDataStruct.figureHandle, 'userdata', toolArray);
1724 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1725 % NAME: refreshMagnifierToSecondaryAxesLink
1727 % PURPOSE: Updates the line connection between the magnifier and the secondary axes.
1733 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1734 function refreshMagnifierToSecondaryAxesLink()
1736 global appDataStruct;
1738 if isempty(appDataStruct)
1742 %Don't display link if not requestred
1743 linkStyle = appDataStruct.linkDisplayStyle;
1744 if strcmpi( linkStyle(1), 'none')
1748 %Get position and size of figure in pixels
1749 figurePosition = getFigurePositionInPixels();
1751 %Get position and size of secondary axes in pixels
1752 secondaryAxesPosition = getSecondaryAxesPositionInPixels();
1754 defaultUnits = get(appDataStruct.secondaryAxesHandle, 'Units');
1755 set(appDataStruct.secondaryAxesHandle, 'Units', 'pixels');
1756 tightInset = get(appDataStruct.secondaryAxesHandle, 'TightInset');
1757 set(appDataStruct.secondaryAxesHandle, 'Units', defaultUnits);
1759 %Get position and size of secondary axes in pixels
1760 magnifierPosition = getMagnifierPositionInPixels();
1763 if strcmpi( linkStyle, 'straight')
1765 %Magnifier Hot points
1766 magnifierHotPoints = [...
1767 magnifierPosition(1) + magnifierPosition(3)/2 magnifierPosition(2);...
1768 magnifierPosition(1) + magnifierPosition(3) magnifierPosition(2)+magnifierPosition(4)/2;...
1769 magnifierPosition(1) + magnifierPosition(3)/2 magnifierPosition(2)+magnifierPosition(4);...
1770 magnifierPosition(1) magnifierPosition(2)+magnifierPosition(4)/2;...
1773 %Secondary axes Hot points
1774 secondaryAxesHotPoints = [...
1775 secondaryAxesPosition(1) + secondaryAxesPosition(3)/2 secondaryAxesPosition(2) - tightInset(2) - 2;...
1776 secondaryAxesPosition(1) + secondaryAxesPosition(3) secondaryAxesPosition(2)+secondaryAxesPosition(4)/2;...
1777 secondaryAxesPosition(1) + secondaryAxesPosition(3)/2 secondaryAxesPosition(2)+secondaryAxesPosition(4);...
1778 secondaryAxesPosition(1) - tightInset(1) - 2 secondaryAxesPosition(2)+secondaryAxesPosition(4)/2;...
1781 %Minimize distance between hot spots
1782 L1 = size(magnifierHotPoints, 1);
1783 L2 = size(secondaryAxesHotPoints, 1);
1784 [iMagnifierHotPoints iSecondaryAxesHotPoints] = meshgrid(1:L1, 1:L2);
1785 D2 = ( magnifierHotPoints(iMagnifierHotPoints(:),1) - secondaryAxesHotPoints(iSecondaryAxesHotPoints(:),1) ).^2 + ...
1786 ( magnifierHotPoints(iMagnifierHotPoints(:),2) - secondaryAxesHotPoints(iSecondaryAxesHotPoints(:),2) ).^2;
1788 [C,I] = sort( D2, 'ascend' );
1790 X(1) = magnifierHotPoints(iMagnifierHotPoints(I(1)),1);
1791 Y(1) = magnifierHotPoints(iMagnifierHotPoints(I(1)),2);
1792 X(2) = secondaryAxesHotPoints(iSecondaryAxesHotPoints(I(1)),1);
1793 Y(2) = secondaryAxesHotPoints(iSecondaryAxesHotPoints(I(1)),2);
1796 if isempty(appDataStruct.linkHandle)
1798 appDataStruct.linkHandle = annotation( 'line', X/figurePosition(3), Y/figurePosition(4),...
1799 'LineWidth', appDataStruct.globalEdgeWidth,...
1800 'Color', appDataStruct.globalEdgeColor );
1804 set(appDataStruct.linkHandle, 'X', X/figurePosition(3), 'Y', Y/figurePosition(4),...
1805 'LineWidth', appDataStruct.globalEdgeWidth,...
1806 'Color', appDataStruct.globalEdgeColor );
1811 if strcmpi( linkStyle, 'edges')
1812 %Magnifier Hot points
1813 magnifierHotPoints = [...
1814 magnifierPosition(1) - 3 magnifierPosition(2);...
1815 magnifierPosition(1) + magnifierPosition(3) magnifierPosition(2);...
1816 magnifierPosition(1) + magnifierPosition(3) magnifierPosition(2)+magnifierPosition(4);...
1817 magnifierPosition(1) - 3 magnifierPosition(2)+magnifierPosition(4)...
1820 %Secondary axes Hot points
1821 secondaryAxesHotPoints = [...
1822 secondaryAxesPosition(1) secondaryAxesPosition(2);...
1823 secondaryAxesPosition(1) + secondaryAxesPosition(3) secondaryAxesPosition(2);...
1824 secondaryAxesPosition(1) + secondaryAxesPosition(3) secondaryAxesPosition(2)+secondaryAxesPosition(4);...
1825 secondaryAxesPosition(1) secondaryAxesPosition(2)+secondaryAxesPosition(4)...
1830 X(1) = magnifierHotPoints(i,1);
1831 Y(1) = magnifierHotPoints(i,2);
1832 X(2) = secondaryAxesHotPoints(i,1);
1833 Y(2) = secondaryAxesHotPoints(i,2);
1835 %If intersection with secondary Axes bottom edge
1836 % intersectionPoint = intersectionPointInPixels(...
1837 % [X(1) Y(1) X(2) Y(2)], ...
1838 % [ secondaryAxesPosition(1)...
1839 % secondaryAxesPosition(2)...
1840 % secondaryAxesPosition(1)+secondaryAxesPosition(3)...
1841 % secondaryAxesPosition(2) ]...
1843 % if ~isempty(intersectionPoint)
1844 % D2_1 = (X(1)-X(2))^2 + (Y(1)-Y(2))^2;
1845 % D2_2 = (X(1)-intersectionPoint(1))^2 + (Y(1)-intersectionPoint(2))^2;
1847 % %link to intersecting point
1848 % X(2) = intersectionPoint(1);
1849 % Y(2) = intersectionPoint(2);
1853 % %If intersection with secondary Axes top edge
1854 % intersectionPoint = intersectionPointInPixels(...
1855 % [X(1) Y(1) X(2) Y(2)], ...
1856 % [ secondaryAxesPosition(1)...
1857 % secondaryAxesPosition(2)+secondaryAxesPosition(4)...
1858 % secondaryAxesPosition(1)+secondaryAxesPosition(3)...
1859 % secondaryAxesPosition(2)+secondaryAxesPosition(4) ]...
1861 % if ~isempty(intersectionPoint)
1862 % D2_1 = (X(1)-X(2))^2 + (Y(1)-Y(2))^2;
1863 % D2_2 = (X(1)-intersectionPoint(1))^2 + (Y(1)-intersectionPoint(2))^2;
1865 % %link to intersecting point
1866 % X(2) = intersectionPoint(1);
1867 % Y(2) = intersectionPoint(2);
1871 % %If intersection with secondary Axes left edge
1872 % intersectionPoint = intersectionPointInPixels(...
1873 % [X(1) Y(1) X(2) Y(2)], ...
1874 % [ secondaryAxesPosition(1)...
1875 % secondaryAxesPosition(2)...
1876 % secondaryAxesPosition(1)...
1877 % secondaryAxesPosition(2)+secondaryAxesPosition(4) ]...
1879 % if ~isempty(intersectionPoint)
1880 % D2_1 = (X(1)-X(2))^2 + (Y(1)-Y(2))^2;
1881 % D2_2 = (X(1)-intersectionPoint(1))^2 + (Y(1)-intersectionPoint(2))^2;
1883 % %link to intersecting point
1884 % X(2) = intersectionPoint(1);
1885 % Y(2) = intersectionPoint(2);
1889 % %If intersection with secondary Axes right edge
1890 % intersectionPoint = intersectionPointInPixels(...
1891 % [X(1) Y(1) X(2) Y(2)], ...
1892 % [ secondaryAxesPosition(1)+secondaryAxesPosition(3)...
1893 % secondaryAxesPosition(2)...
1894 % secondaryAxesPosition(1)+secondaryAxesPosition(3)...
1895 % secondaryAxesPosition(2)+secondaryAxesPosition(4) ]...
1897 % if ~isempty(intersectionPoint)
1898 % D2_1 = (X(1)-X(2))^2 + (Y(1)-Y(2))^2;
1899 % D2_2 = (X(1)-intersectionPoint(1))^2 + (Y(1)-intersectionPoint(2))^2;
1901 % %link to intersecting point
1902 % X(2) = intersectionPoint(1);
1903 % Y(2) = intersectionPoint(2);
1908 if isempty( appDataStruct.linkHandle )
1910 newlinkHandle = annotation( 'line', X/figurePosition(3), Y/figurePosition(4),...
1911 'LineWidth', appDataStruct.globalEdgeWidth,...
1912 'LineStyle', ':',...
1913 'Color', appDataStruct.globalEdgeColor );
1914 linkHandle = appDataStruct.linkHandle;
1915 appDataStruct.linkHandle = [linkHandle newlinkHandle];
1918 linkHandle = appDataStruct.linkhandle;
1919 set( linkHandle(i), 'X', X/figurePosition(3), 'Y', Y/figurePosition(4),...
1920 'LineWidth', appDataStruct.globalEdgeWidth,...
1921 'Color', appDataStruct.globalEdgeColor );
1927 if strcmpi( linkStyle, 'elbow')
1929 %Magnifier Hot points
1930 magnifierHotPoints = [...
1931 magnifierPosition(1) + magnifierPosition(3)/2 magnifierPosition(2);...
1932 magnifierPosition(1) + magnifierPosition(3) magnifierPosition(2)+magnifierPosition(4)/2;...
1933 magnifierPosition(1) + magnifierPosition(3)/2 magnifierPosition(2)+magnifierPosition(4);...
1934 magnifierPosition(1) magnifierPosition(2)+magnifierPosition(4)/2;...
1937 %Secondary axes Hot points
1938 secondaryAxesHotPoints = [...
1939 secondaryAxesPosition(1) + secondaryAxesPosition(3)/2 secondaryAxesPosition(2) - tightInset(2) - 2;...
1940 secondaryAxesPosition(1) + secondaryAxesPosition(3) secondaryAxesPosition(2)+secondaryAxesPosition(4)/2;...
1941 secondaryAxesPosition(1) + secondaryAxesPosition(3)/2 secondaryAxesPosition(2)+secondaryAxesPosition(4);...
1942 secondaryAxesPosition(1) - tightInset(1) - 2 secondaryAxesPosition(2)+secondaryAxesPosition(4)/2;...
1946 %Allowed connections
1947 % iMagnifierHotPoints(1) = 1;
1948 % iSecondaryAxesHotPoints(1) = 4;
1949 % iMagnifierHotPoints(2) = 1;
1950 % iSecondaryAxesHotPoints(2) = 2;
1951 % iMagnifierHotPoints(3) = 2;
1952 % iSecondaryAxesHotPoints(3) = 3;
1953 % iMagnifierHotPoints(4) = 2;
1954 % iSecondaryAxesHotPoints(4) = 1;
1955 % iMagnifierHotPoints(5) = 3;
1956 % iSecondaryAxesHotPoints(5) = 4;
1957 % iMagnifierHotPoints(6) = 3;
1958 % iSecondaryAxesHotPoints(6) = 2;
1959 % iMagnifierHotPoints(7) = 4;
1960 % iSecondaryAxesHotPoints(7) = 1;
1961 % iMagnifierHotPoints(8) = 4;
1962 % iSecondaryAxesHotPoints(8) = 3;
1963 % iMagnifierHotPoints(9) = 1;
1964 % iSecondaryAxesHotPoints(9) = 3;
1965 % iMagnifierHotPoints(10) = 2;
1966 % iSecondaryAxesHotPoints(10) = 4;
1967 % iMagnifierHotPoints(11) = 3;
1968 % iSecondaryAxesHotPoints(11) = 1;
1969 % iMagnifierHotPoints(12) = 4;
1970 % iSecondaryAxesHotPoints(12) = 2;
1972 %Minimize distance between hot spots
1973 L1 = size(magnifierHotPoints, 1);
1974 L2 = size(secondaryAxesHotPoints, 1);
1975 [iMagnifierHotPoints iSecondaryAxesHotPoints] = meshgrid(1:L1, 1:L2);
1976 D2 = ( magnifierHotPoints(iMagnifierHotPoints(:),1) - secondaryAxesHotPoints(iSecondaryAxesHotPoints(:),1) ).^2 + ...
1977 ( magnifierHotPoints(iMagnifierHotPoints(:),2) - secondaryAxesHotPoints(iSecondaryAxesHotPoints(:),2) ).^2;
1979 [C,I] = sort( D2, 'ascend' );
1981 X(1) = magnifierHotPoints(iMagnifierHotPoints(I(1)),1);
1982 Y(1) = magnifierHotPoints(iMagnifierHotPoints(I(1)),2);
1983 X(2) = secondaryAxesHotPoints(iSecondaryAxesHotPoints(I(1)),1);
1984 Y(2) = secondaryAxesHotPoints(iSecondaryAxesHotPoints(I(1)),2);
1987 if isempty( appDataStruct.linkHandle )
1989 newlinkHandle = annotation( 'line', X/figurePosition(3), Y/figurePosition(4),...
1990 'LineWidth', appDataStruct.globalEdgeWidth,...
1991 'Color', appDataStruct.globalEdgeColor );
1992 linkHandle = appDataStruct.linkHandle;
1993 appDataStruct.linkHandle = [linkHandle newlinkHandle];
1996 linkHandle = appDataStruct.linkhandle;
1997 set( linkHandle, 'X', X/figurePosition(3), 'Y', Y/figurePosition(4),...
1998 'LineWidth', appDataStruct.globalEdgeWidth,...
1999 'Color', appDataStruct.globalEdgeColor );
2004 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2005 % NAME: intersectionPointInPixels
2007 % PURPOSE: Computes constrained intersection of two lines in pixels, on the 2D space
2010 % line1 [double 1x4]: [Xstart Ystart Xend Yend]
2011 % line2 [double 1x4]: [Xstart Ystart Xend Yend]
2014 % intersectionPont [double 1x2]: [X Y] intersection
2016 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2017 function intersectionPoint = intersectionPointInPixels( line1, line2)
2019 %Cartessian caracterization of line 1
2025 a1 = (Y1(2) - Y1(1)) / (X1(2) - X1(1));
2026 b1 = Y1(1) - X1(1)*a1;
2028 %Cartessian caracterization of line 2
2034 a2 = (Y2(2) - Y2(1)) / (X2(2) - X2(1));
2035 b2 = Y2(1) - X2(1)*a2;
2038 if isfinite(a1) && isfinite(a2)
2039 intersectionPoint(1) = (b2-b1) / (a1-a2);
2040 intersectionPoint(2) = intersectionPoint(1)*a1 + b1;
2042 %Pathologic case 1 (line2 x=constant)
2043 if isfinite(a1) && ~isfinite(a2)
2044 intersectionPoint(1) = X2(1);
2045 intersectionPoint(2) = intersectionPoint(1)*a1 + b1;
2047 %Pathologic case 2 (line1 x=constant)
2048 if ~isfinite(a1) && isfinite(a2)
2049 intersectionPoint(1) = X1(1);
2050 intersectionPoint(2) = intersectionPoint(1)*a2 + b2;
2053 if intersectionPoint(1)<min([X1(1) X2(1)]) ||...
2054 intersectionPoint(1)>max([X1(2) X2(2)]) ||...
2055 intersectionPoint(2)<min([Y1(1) Y2(1)]) ||...
2056 intersectionPoint(2)>max([Y1(2) Y2(2)])
2058 intersectionPoint = [];
2061 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2062 % NAME: computeSecondaryAxesDefaultPosition
2064 % PURPOSE: obtain the default position and size of the secondary axis, relative to the
2065 % lower left corner of the figure, in pixels. Includes legends and axes
2071 % position [double 1x4]:
2072 % X of lower left corner of the axis frame
2073 % Y of lower left corner of the axis frame
2074 % Width of the axis frame
2075 % Height of the axis frame
2077 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2078 function defaultPosition = computeSecondaryAxesDefaultPosition()
2080 global appDataStruct
2082 if isempty(appDataStruct)
2086 % If image, defualt aspect ratio of magnifier and secondary axes to [1 1]
2087 childHandle = get(appDataStruct.mainAxesHandle, 'Children');
2088 plotFlag = ~isempty( find(strcmpi(get(childHandle, 'Type'), 'line'),1) );
2089 imageFlag = ~isempty( find(strcmpi(get(childHandle, 'Type'), 'image'),1) );
2091 %Get position and size of main Axis (left & bottom relative to figure frame)
2092 mainAxesPosition = getMainAxesPositionInPixels();
2095 %Set initial position and size for secondary axis
2096 secondaryAxisPosition_W = mainAxesPosition(3)*0.3;
2097 secondaryAxisPosition_H = mainAxesPosition(4)*0.3;
2098 secondaryAxisPosition_X = mainAxesPosition(1)+mainAxesPosition(3)-secondaryAxisPosition_W-10;
2099 secondaryAxisPosition_Y = mainAxesPosition(2)+mainAxesPosition(4)-secondaryAxisPosition_H-10;
2101 %Set initial position and size for secondary axis
2102 secondaryAxisPosition_W = mainAxesPosition(3)*0.3;
2103 secondaryAxisPosition_H = mainAxesPosition(4)*0.3;
2104 secondaryAxisPosition_X = mainAxesPosition(1)+mainAxesPosition(3)-secondaryAxisPosition_W-10;
2105 secondaryAxisPosition_Y = mainAxesPosition(2)+mainAxesPosition(4)-secondaryAxisPosition_H-10;
2108 defaultPosition = [...
2109 secondaryAxisPosition_X...
2110 secondaryAxisPosition_Y...
2111 secondaryAxisPosition_W...
2112 secondaryAxisPosition_H...
2116 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2117 % NAME: computeMagnifierDefaultPosition
2119 % PURPOSE: obtain the default position and size of the magnifier, relative to the
2120 % lower left corner of the figure, in pixels. Includes legends and axes
2126 % position [double 1x4]:
2127 % X of lower left corner of the rectangle
2128 % Y of lower left corner of the rectangle
2129 % Width of the rectangle
2130 % Height of the rectangle
2132 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2133 function defaultPosition = computeMagnifierDefaultPosition()
2135 global appDataStruct
2137 if isempty(appDataStruct)
2141 % If image, defualt aspect ratio of magnifier and secondary axes to [1 1]
2142 childHandle = get(appDataStruct.mainAxesHandle, 'Children');
2143 plotFlag = ~isempty( find(strcmpi(get(childHandle, 'Type'), 'line'),1) );
2144 imageFlag = ~isempty( find(strcmpi(get(childHandle, 'Type'), 'image'),1) );
2146 %Set initial position and size of magnifying rectangle
2147 mainAxisXLim = get( appDataStruct.mainAxesHandle, 'XLim' );
2148 mainAxisYLim = get( appDataStruct.mainAxesHandle, 'YLim' );
2149 mainAxesPositionInPixels = getMainAxesPositionInPixels();
2150 xMainAxisUnits2PixelsFactor = mainAxesPositionInPixels(3)/determineSpan( mainAxisXLim(1), mainAxisXLim(2) );
2151 yMainAxisUnits2PixelsFactor = mainAxesPositionInPixels(4)/determineSpan( mainAxisYLim(1), mainAxisYLim(2) );
2154 %Get main axis position and dimensions, in pixels
2155 magnifierPosition_W = determineSpan(mainAxisXLim(1), mainAxisXLim(2))*xMainAxisUnits2PixelsFactor*0.1;
2156 magnifierPosition_H = determineSpan(mainAxisYLim(1), mainAxisYLim(2))*yMainAxisUnits2PixelsFactor*0.3;
2157 magnifierPosition_X = determineSpan(mean(mainAxisXLim), mainAxisXLim(1))*xMainAxisUnits2PixelsFactor - magnifierPosition_W/2;
2158 magnifierPosition_Y = determineSpan(mean(mainAxisYLim), mainAxisYLim(1))*yMainAxisUnits2PixelsFactor - magnifierPosition_H/2;
2160 %Get main axis position and dimensions, in pixels
2161 magnifierPosition_W = determineSpan(mainAxisXLim(1), mainAxisXLim(2))*xMainAxisUnits2PixelsFactor*0.1;
2162 magnifierPosition_H = determineSpan(mainAxisYLim(1), mainAxisYLim(2))*yMainAxisUnits2PixelsFactor*0.1;
2163 magnifierPosition_X = determineSpan(mean(mainAxisXLim), mainAxisXLim(1))*xMainAxisUnits2PixelsFactor - magnifierPosition_W/2;
2164 magnifierPosition_Y = determineSpan(mean(mainAxisYLim), mainAxisYLim(1))*yMainAxisUnits2PixelsFactor - magnifierPosition_H/2;
2167 defaultPosition = [...
2168 magnifierPosition_X+mainAxesPositionInPixels(1)...
2169 magnifierPosition_Y+mainAxesPositionInPixels(2)...
2170 magnifierPosition_W...
2171 magnifierPosition_H...
2175 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2176 % NAME: initializeToolStruct
2178 % PURPOSE: Set value for default properties
2185 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2186 function obj = initializeToolStruct(varargin)
2190 obj.focusOnThisTool = true;
2191 obj.toolIdHandle = [];
2194 obj.figureHandle = [];
2195 obj.figurePosition = [];
2196 obj.figureOldWindowButtonDownFcn = [];
2197 obj.figureOldWindowButtonUpFcn = [];
2198 obj.figureOldWindowButtonMotionFcn = [];
2199 obj.figureOldKeyPressFcn = [];
2200 obj.figureOldDeleteFcn = [];
2201 obj.figureOldResizeFcn = [];
2204 obj.mainAxesHandle = [];
2207 obj.magnifierHandle = [];
2208 obj.magnifierPosition = [];
2209 obj.magnifierShape = 'rectangle';
2212 obj.linkHandle = [];
2213 obj.linkDisplayStyle = 'straight';
2216 obj.secondaryAxesHandle = [];
2217 obj.secondaryAxesFaceColor = 'white';
2218 obj.secondaryAxesPosition = [];
2219 obj.secondaryAxesXLim = [];
2220 obj.secondaryAxesYLim = [];
2221 obj.secondaryAxesAdditionalZoomingFactor = [0 0];
2224 obj.globalUnits = 'pixels';
2225 obj.globalMode = 'interactive';
2226 obj.globalEdgeWidth = 1;
2227 obj.globalEdgeColor = 'black';
2228 obj.globalZoomMode = 'off';
2231 obj.pointerArea = 'none';
2232 obj.ButtonDown = false;
2233 obj.pointerPositionOnButtonDown = [];
2236 if nargin == 1 && isstruct(varargin{1})
2237 structIn = varargin{1};
2238 if all(isfield(structIn, {'toolId','focusOnThisTool',...
2239 'figureHandle', 'figurePosition', 'figureOldWindowButtonDownFcn',...
2240 'figureOldWindowButtonUpFcn', 'figureOldWindowButtonMotionFcn',...
2241 'figureOldKeyPressFcn', 'figureOldDeleteFcn', 'figureOldResizeFcn',...
2242 'mainAxesHandle', 'magnifierHandle', 'magnifierPosition', ...
2243 'magnifierShape', 'linkHandle', 'linkDisplayStyle', 'secondaryAxesHandle',...
2244 'secondaryAxesFaceColor', 'secondaryAxesPosition', 'secondaryAxesXLim',...
2245 'secondaryAxesYLim', 'secondaryAxesAdditionalZoomingFactor', ...
2246 'globalUnits', 'globalMode', 'globalEdgeWidth', 'globalEdgeColor',...
2247 'globalZoomMode', 'pointerArea', 'ButtonDown', 'pointerPositionOnButtonDown'}))
2250 error('Input structure not recognized');
2259 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2260 % NAME: updateToolId
2262 % PURPOSE: Updated position and status of tool id
2265 % toolArray structure of the tool in focus
2269 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2270 function toolArrayOut = updateToolId( toolArrayIn, toolNum, modeStr )
2272 toolArrayOut = toolArrayIn;
2274 set(toolArrayOut.figureHandle, 'currentAxes', toolArrayOut.secondaryAxesHandle);
2276 if strcmp(modeStr, 'toggle')
2277 if isempty(toolArrayOut.toolIdHandle)
2278 xL = get(toolArrayOut.secondaryAxesHandle, 'XLim');
2279 yL = get(toolArrayOut.secondaryAxesHandle, 'YLim');
2280 toolArrayOut.toolIdHandle = text( (xL(2)+xL(1))/2, (yL(2)+yL(1))/2, num2str(toolNum));
2281 set(toolArrayOut.toolIdHandle, 'FontSize', 30, 'FontWeight', 'bold' );
2282 if toolArrayOut.focusOnThisTool
2283 set(toolArrayOut.toolIdHandle,'BackgroundColor', 'red', 'Color', 'white');
2285 set(toolArrayOut.toolIdHandle,'BackgroundColor', 'black', 'Color', 'white');
2288 delete(toolArrayOut.toolIdHandle);
2289 toolArrayOut.toolIdHandle = [];
2292 if not(isempty(toolArrayOut.toolIdHandle))
2293 xL = get(toolArrayOut.secondaryAxesHandle, 'XLim');
2294 yL = get(toolArrayOut.secondaryAxesHandle, 'YLim');
2295 set(toolArrayOut.toolIdHandle, 'Position', [(xL(2)+xL(1))/2, (yL(2)+yL(1))/2] );
2296 if toolArrayOut.focusOnThisTool
2297 set(toolArrayOut.toolIdHandle,'BackgroundColor', 'red', 'Color', 'white');
2299 set(toolArrayOut.toolIdHandle,'BackgroundColor', 'black', 'Color', 'white');
2304 set(toolArrayOut.figureHandle, 'currentAxes', toolArrayOut.mainAxesHandle);