Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 39 additions & 13 deletions code/+nansen/+manage/OptionsManager.m
Original file line number Diff line number Diff line change
Expand Up @@ -384,12 +384,22 @@ function setOptions(obj, optionsName, options)

sEditor = structeditor(obj.Options, 'OptionsManager', obj, 'Title', name);
sEditor.waitfor()
wasAborted = sEditor.wasCanceled;

if wasAborted
obj.Options = sEditor.dataOrig;

if isprop(sEditor, 'FinishState')
wasAborted = sEditor.FinishState ~= "Finished";
if wasAborted
obj.Options = sEditor.OriginalData;
else
obj.Options = sEditor.Data;
end
else
obj.Options = sEditor.dataEdit;
wasAborted = sEditor.wasCanceled;

if wasAborted
obj.Options = sEditor.dataOrig;
else
obj.Options = sEditor.dataEdit;
end
end

delete(sEditor)
Expand Down Expand Up @@ -420,8 +430,13 @@ function setOptions(obj, optionsName, options)
'OptionsManager', obj, ...
'Title', titleStr, ...
'Prompt', promptStr );

hOptionsEditor.changeOptionsSelectionDropdownValue(optionsName);

if ismethod(hOptionsEditor, 'changeOptionsSelectionDropdownValue')
hOptionsEditor.changeOptionsSelectionDropdownValue(optionsName);
else
plugin = hOptionsEditor.getPlugin("nansen.manage.OptionsManagerPlugin");
plugin.setCurrentOptionsName(optionsName);
end

end

Expand Down Expand Up @@ -449,14 +464,25 @@ function setOptions(obj, optionsName, options)

sEditor = obj.openOptionsEditor(optsName, optsStruct);
sEditor.waitfor()

wasAborted = sEditor.wasCanceled;

if sEditor.wasCanceled
optsStruct = sEditor.dataOrig;
if isprop(sEditor, 'FinishState')
wasAborted = sEditor.FinishState ~= "Finished";
plugin = sEditor.getPlugin("nansen.manage.OptionsManagerPlugin");
if wasAborted
optsStruct = sEditor.OriginalData;
else
optsStruct = sEditor.Data;
optsName = plugin.CurrentOptionsName;
end
else
optsStruct = sEditor.dataEdit;
optsName = sEditor.currentOptionsName;
wasAborted = sEditor.wasCanceled;

if sEditor.wasCanceled
optsStruct = sEditor.dataOrig;
else
optsStruct = sEditor.dataEdit;
optsName = sEditor.currentOptionsName;
end
end

% Clear modified options!
Expand Down
212 changes: 212 additions & 0 deletions code/+nansen/+manage/OptionsManagerPlugin.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
classdef OptionsManagerPlugin < handle

properties (SetAccess = private)
OptionsManager
CurrentOptionsName char = ''
end

properties (Access = private)
Editor
HeaderGrid matlab.ui.container.GridLayout
OptionsDropDown matlab.ui.control.DropDown
SaveButton matlab.ui.control.Button
DefaultButton matlab.ui.control.Button
IsUpdating (1,1) logical = false
end

methods
function obj = OptionsManagerPlugin(optionsManager, optionsName)
arguments
optionsManager
optionsName char = ''
end

obj.OptionsManager = optionsManager;
if isempty(optionsName)
optionsName = optionsManager.OptionsName;
end
if isempty(optionsName)
optionsName = optionsManager.getPreferredOptionsName();
end
obj.CurrentOptionsName = char(optionsName);
end

function attach(obj, editor)
obj.Editor = editor;
parent = editor.getAttachmentContainer("header");

obj.HeaderGrid = uigridlayout(parent);
obj.HeaderGrid.ColumnWidth = {'1x', 82, 96};
obj.HeaderGrid.RowHeight = {'1x'};
obj.HeaderGrid.Padding = [0 0 0 0];
obj.HeaderGrid.ColumnSpacing = 6;

obj.OptionsDropDown = uidropdown(obj.HeaderGrid);
obj.OptionsDropDown.Layout.Row = 1;
obj.OptionsDropDown.Layout.Column = 1;
obj.OptionsDropDown.ValueChangedFcn = @obj.onOptionsSetChanged;

obj.SaveButton = uibutton(obj.HeaderGrid, ...
"Text", "Save Options", ...
"ButtonPushedFcn", @obj.onSaveOptionsPushed);
obj.SaveButton.Layout.Row = 1;
obj.SaveButton.Layout.Column = 2;

obj.DefaultButton = uibutton(obj.HeaderGrid, ...
"Text", "Make Default", ...
"ButtonPushedFcn", @obj.onMakeDefaultPushed);
obj.DefaultButton.Layout.Row = 1;
obj.DefaultButton.Layout.Column = 3;

obj.refreshOptionsDropdown();
end

function setCurrentOptionsName(obj, optionsName)
obj.CurrentOptionsName = char(optionsName);
obj.refreshOptionsDropdown();
end

function onDataChanged(obj, ~, ~)
if obj.IsUpdating || isempty(obj.OptionsDropDown)
return
end

opts = obj.Editor.Data;
currentName = obj.CurrentOptionsName;

if contains(currentName, 'Modified')
obj.OptionsManager.appendModifiedOptions(opts, currentName)
else
obj.CurrentOptionsName = sprintf('%s (Modified)', currentName);
obj.OptionsManager.appendModifiedOptions(opts, obj.CurrentOptionsName)
end

obj.refreshOptionsDropdown();
end

function onFinishStateChanged(~, ~, ~)
% Hook kept for the generic plugin lifecycle. OptionsManager
% state is read by callers after editor.waitfor returns.
end

function control = getTestControl(obj, controlName)
control = obj.(controlName);
end
end

methods (Access = private)
function onOptionsSetChanged(obj, src, ~)
newName = char(src.Value);
oldName = obj.CurrentOptionsName;

if strcmp(newName, oldName)
return
end

if contains(oldName, 'Modified')
obj.OptionsManager.appendModifiedOptions(obj.Editor.Data, oldName)
end

if obj.OptionsManager.isModified(newName)
newOptions = obj.OptionsManager.getModifiedOptions(newName);
else
newOptions = obj.OptionsManager.getOptions(newName);
end

obj.IsUpdating = true;
cleanupObj = onCleanup(@() obj.clearUpdatingFlag());
obj.Editor.replaceData(newOptions);
obj.CurrentOptionsName = newName;
obj.refreshOptionsDropdown();
delete(cleanupObj)
end

function onSaveOptionsPushed(obj, ~, ~)
currentName = obj.CurrentOptionsName;
givenName = obj.OptionsManager.saveCustomOptions(obj.Editor.Data);
if isempty(givenName)
return
end

if contains(currentName, 'Modified')
obj.OptionsManager.removeModifiedOptions(currentName)
end

obj.CurrentOptionsName = givenName;
obj.refreshOptionsDropdown();
end

function onMakeDefaultPushed(obj, ~, ~)
if isempty(obj.CurrentOptionsName) || contains(obj.CurrentOptionsName, 'Modified')
return
end

obj.OptionsManager.setDefault(obj.CurrentOptionsName);
obj.refreshOptionsDropdown();
end

function refreshOptionsDropdown(obj)
if isempty(obj.OptionsDropDown) || ~isvalid(obj.OptionsDropDown)
return
end

[displayNames, optionNames] = obj.getDropdownNames();
obj.OptionsDropDown.Items = displayNames;
obj.OptionsDropDown.ItemsData = optionNames;

if any(strcmp(optionNames, obj.CurrentOptionsName))
obj.OptionsDropDown.Value = obj.CurrentOptionsName;
elseif ~isempty(optionNames)
obj.CurrentOptionsName = optionNames{1};
obj.OptionsDropDown.Value = obj.CurrentOptionsName;
end

obj.updateButtonStates();
end

function [displayNames, optionNames] = getDropdownNames(obj)
presetNames = obj.OptionsManager.PresetOptionNames;
customNames = obj.OptionsManager.CustomOptionNames;
editedNames = obj.OptionsManager.EditedOptionNames;
optionNames = [presetNames, customNames, editedNames];

displayNames = [ ...
obj.OptionsManager.formatPresetNames(presetNames), ...
customNames, ...
obj.OptionsManager.formatEditedNames(editedNames)];

defaultName = obj.OptionsManager.getPreferredOptionsName();
isDefault = strcmp(optionNames, defaultName);
displayNames(isDefault) = obj.OptionsManager.formatDefaultName(displayNames(isDefault));
end

function updateButtonStates(obj)
if isempty(obj.SaveButton) || ~isvalid(obj.SaveButton)
return
end

isModified = contains(obj.CurrentOptionsName, 'Modified');
obj.SaveButton.Enable = obj.onOff(isModified);

defaultName = obj.OptionsManager.getPreferredOptionsName();
canMakeDefault = ~isempty(obj.CurrentOptionsName) ...
&& ~isModified ...
&& ~strcmp(obj.CurrentOptionsName, defaultName);
obj.DefaultButton.Enable = obj.onOff(canMakeDefault);
end

function clearUpdatingFlag(obj)
obj.IsUpdating = false;
end
end

methods (Static, Access = private)
function value = onOff(tf)
if tf
value = 'on';
else
value = 'off';
end
end
end
end
14 changes: 11 additions & 3 deletions code/apps/+imviewer/+plugin/@RoiSignalVideo/RoiSignalVideo.m
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,22 @@
obj.loadSettings()
obj.imviewerRef.displayMessage('Preparing video export')

sEditor = structeditor.App(obj.settings, 'Title', 'Set preferences for video export');
sEditor = structeditor(obj.settings, 'Title', 'Set preferences for video export');
sEditor.waitfor()

if sEditor.wasCanceled
if isprop(sEditor, 'FinishState')
wasCanceled = sEditor.FinishState ~= "Finished";
editedSettings = sEditor.Data;
else
wasCanceled = sEditor.wasCanceled;
editedSettings = sEditor.dataEdit;
end

if wasCanceled
obj.imviewerRef.clearMessage
return
else
obj.settings = sEditor.dataEdit;
obj.settings = editedSettings;
obj.saveSettings()
end

Expand Down
24 changes: 16 additions & 8 deletions code/apps/+imviewer/@App/App.m
Original file line number Diff line number Diff line change
Expand Up @@ -4338,18 +4338,26 @@ function uiEditStackMetadata(obj)
S.PhysicalUnits = obj.ImageStack.MetaData.getPhysicalUnits();
S.SampleRate = obj.ImageStack.getSampleRate();

h = structeditor.App(S, 'Title', 'ImageStack Properties', ...
h = structeditor(S, 'Title', 'ImageStack Properties', ...
'Prompt', 'Set ImageStack Properties:');
h.waitfor()

if ~h.wasCanceled
obj.ImageStack.MetaData.SampleRate = h.dataEdit.SampleRate;
obj.ImageStack.MetaData.SpatialPosition = h.dataEdit.SpatialPosition;
physSize = h.dataEdit.PhysicalSize;
if numel(h.dataEdit.PhysicalUnits) == 1
physUnits = strsplit(h.dataEdit.PhysicalUnits{1}, ', ');
if isprop(h, 'FinishState')
if h.FinishState ~= "Finished"; return; end
editedData = h.Data;
else
if h.wasCanceled; return; end
editedData = h.dataEdit;
end

if ~isempty(editedData)
obj.ImageStack.MetaData.SampleRate = editedData.SampleRate;
obj.ImageStack.MetaData.SpatialPosition = editedData.SpatialPosition;
physSize = editedData.PhysicalSize;
if numel(editedData.PhysicalUnits) == 1
physUnits = strsplit(editedData.PhysicalUnits{1}, ', ');
else
physUnits = h.dataEdit.PhysicalUnits;
physUnits = editedData.PhysicalUnits;
end
obj.ImageStack.MetaData.PhysicalSizeX = physSize(1);
obj.ImageStack.MetaData.PhysicalSizeY = physSize(2);
Expand Down
Loading