function getFigure() % This function adds a new menu option to copy the content a figure (axes, % lines, or even the whole figure) into a new figure. % % first call adds the menu, second call deletes it. % - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - % V4.1 - 2022 % Eduard Clotet % http://robotica.udl.cat hmenu = findobj(gcf,'Tag','getFigure'); if (isempty(hmenu)) h_get = uimenu(gcf,'label','getFigure','Tag','getFigure'); uimenu(h_get,'label','Get the complete Figure','callback',{@copy, 'Figure', 'Original'}); uimenu(h_get,'label','Get specific Axes (Original size)','separator','on','callback',{@copy, 'Axes', 'Original'}); uimenu(h_get,'label','Get specific Axes (Full figure size)','callback',{@copy, 'Axes', 'Resize'}); uimenu(h_get,'label','Merge with current Axes','separator','on','callback',@merge); uimenu(h_get,'label','Get one line','separator','on','callback',{@copy, 'Line','Original'}); undoButton = uimenu(h_get,'label','Undo last Get','callback',@undo_copy,'separator','on','enable','off','Tag','UNDO'); uimenu(h_get,'label','Cancel','callback',@cancelCopy,'separator','on','enable','off','Tag','UNDO'); %**************** % UNDO STRUCTURE %**************** % numActions: Number of actions listed % currentAction: ID of the last action % actionsList: List of objects involved in each action undoStructure.numActions = 0; undoStructure.currentAction = 0; undoStructure.actionsList = {}; undoButton.UserData = undoStructure; disp('''getFigure'' menu has been added to the menu'); disp('''getFigure'' ha sido aņadido al menu'); % Set foccus on figure figure(gcf); else delete(hmenu); disp('''getFigure'' menu has been deleted'); disp('''getFigure'' ha sido eliminado del menu'); end end function cancelCopy(src, ~) src.Enable = 'off'; end function copy(src, ~, target, targetSize) % Enable cancel button cancelBtn = src.Parent.Children(1); cancelBtn.Enable = 'on'; % Get destination figure dstFigure = gcf; % Get the current type of element initialObject = gco; switch target case 'Axes' expectedSelectionClass = 'matlab.graphics.axis.Axes'; initialObject = get(dstFigure,'CurrentAxes'); case 'Figure' expectedSelectionClass = 'matlab.ui.Figure'; initialObject = gcf; case 'Line' expectedSelectionClass = 'matlab.graphics.chart.primitive.Line'; initialObject = gco; end % Set targetDectected flag to 0 targetDetected = 0; % Wait untill the user selects an object that matches the target class while ~targetDetected && strcmp(cancelBtn.Enable,'on') if strcmp(target,'Figure') currentElm = gcf; elseif strcmp(target,'Axes') currentElm = get(gcf,'CurrentAxes'); else currentElm = gco; end % Check if the user selected an object matching the target class % and its different from the initial object if isa(currentElm, expectedSelectionClass) && ~isequal(initialObject, currentElm) targetDetected = 1; else refresh(); drawnow(); end end % Check if user cancelled the action if strcmp(cancelBtn.Enable, 'off') disp('Copy action canceled'); return; end % Get the list of elements to copy and the number of elements on that % list [cpyElmsList, numCpyItems] = getTargetElms(currentElm); % Initialize list of newly added objects newlyAddedObjects = {}; % Copy elements on cpyElmsList for i = 1:numCpyItems switch class(cpyElmsList{i}) case 'matlab.graphics.illustration.Legend' la = copyobj([cpyElmsList{i}, cpyElmsList{i}.Axes], dstFigure); case 'matlab.graphics.axis.Axes' la = copyobj(cpyElmsList{i}, dstFigure); case 'matlab.graphics.chart.primitive.Line' dstChildsList = dstFigure.Children; numChilds = length(dstChildsList); targetChild = []; for childID = 1:numChilds if isa(dstChildsList(childID), 'matlab.graphics.axis.Axes') targetChild = dstChildsList(childID); break; end end if isempty(targetChild) figure(dstFigure); targetChild = axes(); end la = copyobj(cpyElmsList{i}, targetChild); end if length(la) == 1 newlyAddedObjects{end+1} = la; %#ok Total number of elements is unknown else numAddedElems = length(la); for elemID = 1:numAddedElems newlyAddedObjects{end+1} = la(elemID); %#ok Total number of elements is unknown end end end if strcmp(targetSize, 'Resize') la.Position = [0.1300 0.1100 0.7750 0.8150]; end % Retrieve undo actions list undoButton = src.Parent.Children(2); undoButton.Enable = 'on'; % Update undo actions list undoStructure = undoButton.UserData; undoStructure.numActions = undoStructure.numActions + 1; undoStructure.currentAction = undoStructure.currentAction + 1; undoStructure.actionsList{undoStructure.currentAction} = newlyAddedObjects; undoButton.UserData = undoStructure; cancelBtn.Enable = 'off'; end function merge(src, ~) cancelBtn = src.Parent.Children(1); cancelBtn.Enable = 'on'; % get destination axes dstAx = gca; expectedSelectionClass = 'matlab.graphics.axis.Axes'; initialObject = gca; targetDetected = 0; while ~targetDetected && strcmp(cancelBtn.Enable,'on') % REVISAR!!!! currentElm = gca; if isa(currentElm, expectedSelectionClass) && ~isequal(initialObject, currentElm) targetDetected = 1; else refresh(); drawnow(); end end % Check if user cancelled the action if strcmp(cancelBtn.Enable, 'off') disp('Exit') return; end [cpyElmsList, numCpyItems] = getTargetElms(currentElm); newlyAddedObjects = {}; for i = 1:numCpyItems switch class(cpyElmsList{i}) case 'matlab.graphics.illustration.Legend' axesObj = cpyElmsList{i}.Axes; case 'matlab.graphics.axis.Axes' axesObj = cpyElmsList{i}; end childList = axesObj.Children; numChildren = length(childList); for childID = numChildren:-1:1 newlyAddedObjects{end+1} = copyobj(childList(childID), dstAx); %#ok unknown total number of elms uistack(newlyAddedObjects{end},'top'); end end % Retrieve undo actions list undoButton = src.Parent.Children(2); undoButton.Enable = 'on'; % Update undo actions list undoStructure = undoButton.UserData; undoStructure.numActions = undoStructure.numActions + 1; undoStructure.currentAction = undoStructure.currentAction + 1; undoStructure.actionsList{undoStructure.currentAction} = newlyAddedObjects; undoButton.UserData = undoStructure; cancelBtn.Enable = 'off'; end function [axesList, lastAxesID] = getTargetElms(srcElm) switch class(srcElm) case 'matlab.graphics.chart.primitive.Line' axesList{1} = srcElm; lastAxesID = 1; case 'matlab.graphics.axis.Axes' childList = srcElm.Children; numChildren = length(childList); axesList = cell(1, 1); % Check if this axis is linked to a Legend object for childID = 1:numChildren if isa(childList(childID),'matlab.graphics.illustration.Legend') if isequal(childList(childID).Axes) % Axes linked to a legend, just return the legend axesList{1} = childList(childID); lastAxesID = 1; return; end end end % No legend was linked to this axes, return the axes object axesList{1} = srcElm; lastAxesID = 1; case 'matlab.ui.Figure' childList = srcElm.Children; numChildren = length(childList); legendsList = cell(1, numChildren); lastLegendID = 0; axesList = cell(1, numChildren); for childID = 1:numChildren if isa(childList(childID),'matlab.graphics.illustration.Legend') lastLegendID = lastLegendID + 1; legendsList{lastLegendID} = childList(childID); axesList{lastLegendID} = legendsList{lastLegendID}.Axes; end end legendsList = legendsList(1:lastLegendID); lastAxesID = lastLegendID; for childID = 1:numChildren if isa(childList(childID),'matlab.graphics.axis.Axes') found = 0; % check if this axes has already been detected as part of legend for legendID = 1:lastLegendID if isequal(childList(childID), axesList{legendID}) found = 1; end end if ~found lastAxesID = lastAxesID + 1; axesList{lastAxesID} = childList(childID); end end end axesList = axesList(1:lastAxesID); axesList(1:lastLegendID) = legendsList; end end function undo_copy(source,~) % UNDO function undoStructure = source.UserData; undoID = undoStructure.currentAction; deleteElems = undoStructure.actionsList{undoID}; % remove one item at a time for elemID = 1:length(deleteElems) if ishandle(deleteElems{elemID}) % Try-catch block as some elements may have been deleted % manually by the user try delete(deleteElems{elemID}); catch end end end % Update UNDO structure undoStructure.actionsList(undoID) = []; undoStructure.currentAction = undoStructure.currentAction - 1; undoStructure.numActions = undoStructure.numActions -1; source.UserData = undoStructure; % Disable undo option if undoStructure.numActions == 0 source.Enable = 'off'; end end