classdef GemDropDownMenu < GemUserInterfaceObject
    % GemDropDownMenu GEM class for a pop-up menu control
    %
    %
    %     Licence
    %     -------
    %     Part of GEM. https://github.com/tomdoel/gem
    %     Author: Tom Doel, 2013.  www.tomdoel.com
    %     Distributed under the MIT licence. Please see website for details.
    %

    properties (Access = private)
        Callback
        FontSize
        HorizontalAlignment
        MenuItems
        SelectedIndex
        Tag
        ToolTip
    end

    methods
        function obj = GemDropDownMenu(parent, menu_items, tooltip, callback)
            obj = obj@GemUserInterfaceObject(parent);

            obj.MenuItems = menu_items;
            obj.ToolTip = tooltip;
            obj.Callback = callback;
            obj.FontSize = 11;
            obj.HorizontalAlignment = 'left';
            obj.SelectedIndex = 1;
        end

        function delete(obj)
        end

        function CreateGuiComponent(obj, position)
            obj.GraphicalComponentHandle = uicontrol('Style', 'popupmenu', 'Parent', obj.Parent.GetContainerHandle, ...
                'FontAngle', 'normal', 'FontUnits', 'pixels', 'FontSize', obj.FontSize, 'HorizontalAlignment', obj.HorizontalAlignment, ...
                'Units', 'pixels', 'Position', position, 'ToolTipString', obj.ToolTip, 'String', obj.MenuItems, ...
                'Callback', @obj.PopupmenuCallback, 'Value', obj.SelectedIndex);

        end

        function SetMenuItems(obj, menu_items)
            obj.MenuItems = menu_items;
            if obj.ComponentHasBeenCreated
                set(obj.GraphicalComponentHandle, 'String', menu_items);
            end
        end

        function SetSelectedIndex(obj, selected_index)
            obj.SelectedIndex = selected_index;
            if obj.ComponentHasBeenCreated
                current_index = get(obj.GraphicalComponentHandle, 'Value');
                if (current_index ~= obj.SelectedIndex)
                    set(obj.GraphicalComponentHandle, 'Value', obj.SelectedIndex);
                end
            end
        end

    end

    methods (Access = protected)

        function PopupmenuCallback(obj, hObject, ~, ~)
            % Item selected from the pop-up menu

            if ~obj.IsCurrentlyRunning()
                obj.Callback(get(hObject, 'Value'));
            end
        end

    end
end


function [cfg, newCfg ] = loaddefault(cfg, defaultCfg, appendStruct)
%loaddefault will be removed, use ezInput instead.
%
% keepStruct: recursive retain the struct
%LOAD DEFAULT CONFIG
% defaultCfg = struct('a',1,'b',2,'c',3);
% cfg = struct('b',0);
% [cfg, newCfg ] = loaddefault(cfg, defaultCfg)
%
% cfg = struct('b',0, 'd', 1, 'e', 2); % unknown paramvalue
% [cfg, newCfg ] = loaddefault(cfg, defaultCfg)

%     existingfields = isfield(cfg,fieldnames(defaultCfg));
    %if cfg
    if nargin < 3
        appendStruct = false;
    end

     if iscell(cfg)
        cfg = struct(cfg{:});
     end
    if iscell(defaultCfg)
        defaultCfg = struct(defaultCfg{:});
    end

    newCfg = cfg;

    % both are struct

    % defaultCfg --> cfg
    fields = fieldnames(defaultCfg);
    nfields = numel(fields);
    for n = 1:nfields
        if ~isfield(cfg,fields(n))
            cfg.(fields{n}) = defaultCfg.(fields{n});
        else
            if appendStruct && isstruct(defaultCfg.(fields{n}))
                cfg.(fields{n}) = loaddefault(cfg.(fields{n}), ...
                                              defaultCfg.(fields{n}) );
            end
            newCfg = rmfield(newCfg, fields(n));
        end
    end

    % newCfg --> cell
    if nargout > 1
        newCfg = convertToCell(newCfg);
    end
end

function c = convertToCell(s)
    twoRow = [fieldnames(s), struct2cell(s)]';
    c = twoRow(:)';
end

% scatter3_args = rmfield(param, default(1:2:end));
%


function [ s ] = xml2struct( file )
% Convert xml file into a MATLAB structure
%  [ s ] = xml2struct( file )
%
%  A file containing:
%  <XMLname attrib1="Some value">
%    <Element>Some text</Element>
%    <DifferentElement attrib2="2">Some more text</Element>
%    <DifferentElement attrib3="2" attrib4="1">Even more text</DifferentElement>
%  </XMLname>
%
%  Will produce:
%  s.XMLname.Attributes.attrib1 = "Some value";
%  s.XMLname.Element.Text = "Some text";
%  s.XMLname.DifferentElement{1}.Attributes.attrib2 = "2";
%  s.XMLname.DifferentElement{1}.Text = "Some more text";
%  s.XMLname.DifferentElement{2}.Attributes.attrib3 = "2";
%  s.XMLname.DifferentElement{2}.Attributes.attrib4 = "1";
%  s.XMLname.DifferentElement{2}.Text = "Even more text";
%
%  Please note that the following characters are substituted
%  '-' by '_dash_', ':' by '_colon_' and '.' by '_dot_'
%
%  Written by W. Falkena, ASTI, TUDelft, 21-08-2010
%  Attribute parsing speed increased by 40%  by A. Wanner, 14-6-2011
%  Added CDATA support by I. Smirnov, 20-3-2012
%
%  Modified by X. Mo, University of Wisconsin, 12-5-2012

    if (nargin < 1)
        clc;
        help xml2struct
        return
    end

    if isa(file, 'org.apache.xerces.dom.DeferredDocumentImpl') || isa(file, 'org.apache.xerces.dom.DeferredElementImpl')
        %  input is a java xml object
        xDoc = file;
    else
        % check for existance
        if (exist(file,'file') == 0)
            % Perhaps the xml extension was omitted from the file name. Add the
            % extension and try again.
            if (isempty(strfind(file,'.xml')))
                file = [file '.xml'];
            end

            if (exist(file,'file') == 0)
                error(['The file ' file ' could not be found']);
            end
        end
        % read the xml file
        xDoc = xmlread(file);
    end

    % parse xDoc into a MATLAB structure
    s = parseChildNodes(xDoc);

end

%  ----- Subfunction parseChildNodes -----
function [children,ptext,textflag] = parseChildNodes(theNode)
    %  Recurse over node children.
    children = struct;
    ptext = struct; textflag = 'Text';
    if hasChildNodes(theNode)
        childNodes = getChildNodes(theNode);
        numChildNodes = getLength(childNodes);

        for count = 1:numChildNodes
            theChild = item(childNodes,count-1);
            [text,name,attr,childs,textflag] = getNodeData(theChild);

            if (~strcmp(name,'#text') && ~strcmp(name,'#comment') && ~strcmp(name,'#cdata_dash_section'))
                % XML allows the same elements to be defined multiple times,
                % put each in a different cell
                if (isfield(children,name))
                    if (~iscell(children.(name)))
                        % put existsing element into cell format
                        children.(name) = {children.(name)};
                    end
                    index = length(children.(name))+1;
                    % add new element
                    children.(name){index} = childs;
                    if(~isempty(fieldnames(text)))
                        children.(name){index} = text;
                    end
                    if(~isempty(attr))
                        children.(name){index}.('Attributes') = attr;
                    end
                else
                    % add previously unknown (new) element to the structure
                    children.(name) = childs;
                    if(~isempty(text) && ~isempty(fieldnames(text)))
                        children.(name) = text;
                    end
                    if(~isempty(attr))
                        children.(name).('Attributes') = attr;
                    end
                end
            else
                ptextflag = 'Text';
                if (strcmp(name, '#cdata_dash_section'))
                    ptextflag = 'CDATA';
                elseif (strcmp(name, '#comment'))
                    ptextflag = 'Comment';
                end

                % this is the text in an element (i.e., the parentNode)
                if (~isempty(regexprep(text.(textflag),'[\s]*','')))
                    if (~isfield(ptext,ptextflag) || isempty(ptext.(ptextflag)))
                        ptext.(ptextflag) = text.(textflag);
                    else
                        % what to do when element data is as follows:
                        % <element>Text <!--Comment--> More text</element>

                        % put the text in different cells:
                        %  if (~iscell(ptext)) ptext = {ptext}; end
                        %  ptext{length(ptext)+1} = text;

                        % just append the text
                        ptext.(ptextflag) = [ptext.(ptextflag) text.(textflag)];
                    end
                end
            end

        end
    end
end

%  ----- Subfunction getNodeData -----
function [text,name,attr,childs,textflag] = getNodeData(theNode)
    %  Create structure of node info.

    % make sure name is allowed as structure name
    name = toCharArray(getNodeName(theNode))';
    name = strrep(name, '-', '_dash_');
    name = strrep(name, ':', '_colon_');
    name = strrep(name, '.', '_dot_');

    attr = parseAttributes(theNode);
    if (isempty(fieldnames(attr)))
        attr = [];
    end

    % parse child nodes
    [childs,text,textflag] = parseChildNodes(theNode);

    if (isempty(fieldnames(childs)) && isempty(fieldnames(text)))
        % get the data of any childless nodes
        %  faster than if any(strcmp(methods(theNode), 'getData'))
        %  no need to try-catch (?)
        %  faster than text = char(getData(theNode));
        text.(textflag) = toCharArray(getTextContent(theNode))';
    end

end

%  ----- Subfunction parseAttributes -----
function attributes = parseAttributes(theNode)
    %  Create attributes structure.

    attributes = struct;
    if hasAttributes(theNode)
       theAttributes = getAttributes(theNode);
       numAttributes = getLength(theAttributes);

       for count = 1:numAttributes
            % attrib = item(theAttributes,count-1);
            % attr_name = regexprep(char(getName(attrib)),'[-:.]','_');
            % attributes.(attr_name) = char(getValue(attrib));

            % Suggestion of Adrian Wanner
            str = toCharArray(toString(item(theAttributes,count-1)))';
            k = strfind(str,'=');
            attr_name = str(1:(k(1)-1));
            attr_name = strrep(attr_name, '-', '_dash_');
            attr_name = strrep(attr_name, ':', '_colon_');
            attr_name = strrep(attr_name, '.', '_dot_');
            attributes.(attr_name) = str((k(1)+2):(end-1));
       end
    end
end


function replaceMainCatalog(otherCatalog)
    % replaceMainCatalog(otherCatalog)
    % use this instead of a=something
    % protects the main catalog from corruption
    report_this_filefun();
    if isempty(otherCatalog)
        otherCatalog=ZmapCatalog();
    end
    if isa(otherCatalog,'ZmapCatalogView')
        otherCatalog=otherCatalog.Catalog();
    end
    assert(isa(otherCatalog,'ZmapCatalog'));

    ZG = ZmapGlobal.Data;
    ZG.primeCatalog = copy(otherCatalog);
end


function [sys,values] = double(varargin)
% OBSOLETE. Use VALUE instead

% New syntax
switch nargout
    case 0
        double(value(varargin{:}))
    case 1
        sys = double(value(varargin{:}));
    case 2
        [sys,values] = value(varargin{:});
        sys = double(sys);
        values = double(values);
    otherwise
        error('Too many output arguments.');
end


function SaveFigure(path,quality)
% =======================================================================
% Saves figure to specified path
% =======================================================================
% SaveFig(path,quality)
% -----------------------------------------------------------------------
% INPUT
%   - path: path wehere to save the file
% -----------------------------------------------------------------------
% OPTIONAL INPUT
%   - quality: 0 standard, 1 high quality [dflt=0]
% =======================================================================
% Ambrogio Cesa Bianchi, April 2015
% ambrogio.cesabianchi@gmail.com

if ~exist('quality','var')
    quality=0;
end

if quality
    set(gcf, 'Color', 'w');
    export_fig(path,'-pdf','-png','-painters')
else
    print('-dpng','-r100',path)
    print('-deps','-r100',path)
    print('-dpdf','-r100',path)
end


function varargout = poly(varargin) %#ok<STOUT>
%POLY   POLY does not support SINGFUN objects.
%
% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

error('CHEBFUN:SINGFUN:poly:noSupport', ...
      'POLY does not support SINGFUN objects.')

end


function self = text_test_result(stream, verbosity)
%text_test_result contructor.
%  The constructor creates an object of the class text_test_result. The
%  output is written to the value of stream. The parameter verbosity
%  defines, how much output is written. Possible values are 0, 1 and 2.
%
%  Class Info
%  ==========
%  The class text_test_result is inherited from test_result and prints
%  formatted test results to a stream.
%
%  Example
%  =======
%  Output all results to the Matlab Command Window:
%         result = text_test_result(1, 0)
%
%  See also TEST_RESULT.

self.stream = stream;
if (verbosity == 1)
    self.dots = 1;
    self.show_all = 0;
elseif (verbosity > 1)
    self.dots = 0;
    self.show_all = 1;
else
    self.dots = 0;
    self.show_all = 0;
end;
self.verbosity = verbosity;
result = test_result;
self = class(self, 'text_test_result', result);


function varargout = ExportSnirfGUI(varargin)

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @ExportSnirfGUI_OpeningFcn, ...
                   'gui_OutputFcn',  @ExportSnirfGUI_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

function ExportSnirfGUI_OpeningFcn(hObject, eventdata, handles, varargin)

if ~any([isa(varargin{1}, 'RunClass'), isa(varargin{1}, 'SubjClass'), isa(varargin{1}, 'SessClass'), isa(varargin{1}, 'GroupClass')])
    close(handles.exportSnirfGUI)
else
   handles.currElem = varargin{1};
end

handles.textElementName.String = handles.currElem.name;

[handles.dataKeys, handles.dataValues] = handles.currElem.procStream.output.GetAllData();

set(handles.listboxSelectData, 'String', handles.dataKeys);
set(handles.listboxSelectData, 'Max', length(handles.dataKeys));  % Enable multiple selection

handles.output = hObject;
guidata(hObject, handles);

% uiwait(handles.exportSnirfGUI);

% --- Outputs from this function are returned to the command line.
function varargout = ExportSnirfGUI_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;

function buttonSave_Callback(hObject, eventdata, handles)
selected = handles.listboxSelectData.Value;
data = handles.dataValues(selected);

% Prepare exported Snirf file
output = SnirfClass();
output.data = horzcat(data{:});
output.metaDataTags = MetaDataTagsClass();  % Generate default mdt
output.probe = handles.currElem.GetProbe();

name = handles.currElem.name;
name(name == '/') = '_';
name(name == '\') = '_';
name = erase(name, '.snirf');

if length(selected) < 1
    return
elseif length(selected) == 1
    suffix = handles.dataKeys{selected};
else
    suffix = 'exp';
end
[file, path, indx] = uiputfile(['homerOutput/', name, '_', suffix, '.snirf']);
if file ~= 0
    wb = waitbar(0.2, string(['Saving to ', file, ', please wait...']));
    output.Save([path, file]);
    waitbar(0.8, wb);
    close(wb);
    close(handles.exportSnirfGUI)
else
    close(handles.exportSnirfGUI)
end

function buttonCancel_Callback(hObject, eventdata, handles)
close(handles.exportSnirfGUI)


classdef FileSelector < wt.abstract.BaseWidget &...
        wt.mixin.Enableable & wt.mixin.FontStyled & wt.mixin.Tooltipable &...
        wt.mixin.FieldColorable & wt.mixin.ButtonColorable
    % A file/folder selection control with browse button

    % Copyright 2020-2021 The MathWorks Inc.

    %% Public properties
    properties (AbortSet)

        % The current value shown. If a RootDirectory is used, this will be
        % a relative path to the root.
        Value (1,1) string

    end %properties

    properties (Dependent, SetAccess = protected)

        % Absolute path to the file. If RootDirectory is used, this will
        % show the full path combining the root and the Value property.
        FullPath (1,1) string

        % Indicates the current value is a valid file path
        ValueIsValidPath (1,1) logical

    end %properties

    properties (AbortSet)

        % Selection type: file or folder
        SelectionType (1,1) wt.enum.FileFolderState = wt.enum.FileFolderState.file

        % Optional root directory. If unspecified, Value uses an absolute
        % path (default). If specified, Value will show a relative path to
        % the root directory and Value must be beneath RootDirectory.
        RootDirectory (1,1) string

        % Indicates whether to show a dropdown of recent folders
        ShowHistory (1,1) matlab.lang.OnOffSwitchState = false

        % List of recently selected folders to display in dropdown
        History (:,1) string

    end %properties

    % These properties do not trigger the update method
    properties (AbortSet, UsedInUpdate = false)

        % Optional default directory to start in when Value does not exist
        % and user clicks the browse button.
        DefaultDirectory (1,1) string

    end %properties

    %% Events
    events (HasCallbackProperty, NotifyAccess = protected)

        % Triggered on value changed, has companion callback
        ValueChanged

    end %events

    %% Internal Properties
    properties ( Transient, NonCopyable, ...
            Access = {?wt.abstract.BaseWidget, ?wt.test.BaseWidgetTest} )

        % Button
        ButtonControl (1,1) matlab.ui.control.Button

        % Edit control or dropdown
        EditControl (1,1) matlab.ui.control.EditField
        DropdownControl (1,1) matlab.ui.control.DropDown

    end %properties

    %% Protected methods
    methods (Access = protected)

        function setup(obj)

            % Adjust default size
            obj.Position(3:4) = [200 25];

            % Call superclass setup first to establish the grid
            obj.setup@wt.abstract.BaseWidget();

            % Configure Grid
            obj.Grid.ColumnWidth = {'1x',25};
            obj.Grid.RowHeight = {'1x'};

            % Create the standard edit control
            obj.EditControl = matlab.ui.control.EditField(...
                "Parent",obj.Grid,...
                "ValueChangedFcn",@(h,e)obj.onTextChanged(e));

            % Create the optional dropdown control
            obj.DropdownControl = matlab.ui.control.DropDown(...
                "Parent",[],...
                "Editable",true,...
                "Value","",...
                "ValueChangedFcn",@(h,e)obj.onTextChanged(e));
            %"Visible",false,...
            %obj.DropdownControl.Layout.Column = 1;

            % Create Button
            obj.ButtonControl = matlab.ui.control.Button(...
                "Parent",obj.Grid,...
                "Text","",...
                "ButtonPushedFcn",@(h,e)obj.onButtonPushed(e));
            obj.updateButtonIcon();

            % Update the internal component lists
            obj.FontStyledComponents = [obj.EditControl, obj.DropdownControl];
            obj.FieldColorableComponents = [obj.EditControl, obj.DropdownControl];
            obj.EnableableComponents = [obj.EditControl, obj.DropdownControl, obj.ButtonControl];
            obj.ButtonColorableComponents = obj.ButtonControl;
            obj.TooltipableComponents = [obj.EditControl, obj.DropdownControl, obj.ButtonControl];

        end %function

        function update(obj)

            % Is history being shown?
            if obj.ShowHistory
                % YES - Using dropdown control

                % Get the dropdown (history) items
                histItems = obj.History;

                % Current value must be in the list
                if ~isempty(obj.Value) && ~any(histItems == obj.Value)
                    histItems = vertcat(obj.Value,histItems);
                end

                % Update the items and value
                obj.DropdownControl.Items = histItems;
                obj.DropdownControl.Value = obj.Value;

            else
                % NO - Using edit control

                % Update the edit control text
                obj.EditControl.Value = obj.Value;

            end %if obj.ShowHistory

        end %function

        function updateButtonIcon(obj)

            % Update the button icon
            if obj.SelectionType == "file"
                obj.ButtonControl.Icon = "folder_file_24.png";
            else
                obj.ButtonControl.Icon = "folder_24.png";
            end

        end %function

        function updateControlType(obj)

            % Is history being shown? If so, update history and items
            if obj.ShowHistory
                % Using dropdown control

                if isempty(obj.DropdownControl.Parent)
                    obj.EditControl.Parent = [];
                    obj.DropdownControl.Parent = obj.Grid;
                    obj.DropdownControl.Layout.Column = 1;
                    obj.DropdownControl.Layout.Row = 1;
                end
            else
                % Using edit control

                if isempty(obj.EditControl.Parent)
                    obj.DropdownControl.Parent = [];
                    obj.EditControl.Parent = obj.Grid;
                    obj.EditControl.Layout.Column = 1;
                    obj.EditControl.Layout.Row = 1;
                end
            end %if obj.ShowHistory

        end %function

        function onButtonPushed(obj,~)
            % Triggered on button pushed

            % What folder should the prompt start at?
            if obj.ValueIsValidPath
                initialPath = obj.FullPath;
            elseif exist(obj.DefaultDirectory,"dir")
                initialPath = obj.DefaultDirectory;
            else
                initialPath = pwd;
            end

            % Prompt user for the path
            if obj.SelectionType == "file"
                [fileName,pathName] = uigetfile(initialPath,"Select a file");
            else
                pathName = uigetdir(initialPath,"Select a folder");
                fileName = "";
            end

            % Proceed if user didn't cancel
            if ~isequal(pathName,0)
                obj.setValueFromFullPath( fullfile(pathName,fileName) );
            end %if ~isequal(pathName,0)

        end %function

        function onTextChanged(obj,evt)
            % Triggered on text interaction

            % Prepare event data
            evtOut = wt.eventdata.PropertyChangedData('Value', evt.Value, obj.Value);

            % Store new result
            obj.Value = evt.Value;

            % Trigger event
            notify(obj,"ValueChanged",evtOut);

        end %function

        function addToHistory(obj,value)
            % Add new item to history and clean up

            % Add this to the top of the history
            histFiles = obj.History;
            histFiles = vertcat(value,histFiles);

            % Clean up the history
            histFiles = wt.utility.cleanPath(histFiles);
            histFiles = unique(histFiles,"stable");

            % Filter to valid paths
            if obj.SelectionType == "file"
                fcn = @(x)gt(exist(fullfile(obj.RootDirectory, x),"file"), 0);
            else
                fcn = @(x)eq(exist(fullfile(obj.RootDirectory, x),"dir"), 7);
            end
            isValidPath = arrayfun(fcn,histFiles);
            histFiles(~isValidPath) = [];

            % Limit history length
            histFiles(11:end) = [];

            % Store the result
            obj.History = histFiles;

        end %function

        function setValueFromFullPath(obj,fullPath)

            arguments
                obj (1,1)
                fullPath (1,1) string
            end %arguments

            fullPath = wt.utility.cleanPath(fullPath);

            if strlength(obj.RootDirectory) && strlength(fullPath)
                % Calculate the relative path for the value

                % Split the paths apart
                rootParts = strsplit(obj.RootDirectory,filesep);
                fullParts = strsplit(fullPath,filesep);

                % Find where the paths diverge
                idx = 1;
                smallestPath = min(numel(rootParts), numel(fullParts));
                while idx<=smallestPath && strcmpi(rootParts(idx),fullParts(idx))
                    idx = idx+1;
                end

                % Is the specified path outside of the root directory?
                numAbove = max(numel(rootParts) - idx + 1, 0);
                if numAbove>0

                    obj.throwError("Path '%s' is not within the root directory '%s'.",...
                        fullPath, obj.RootDirectory);

                else

                    % In case full path is above the RootPath, add ".." paths
                    parentPaths = string(repmat(['..' filesep],1,numAbove));

                    % Form the relative path
                    relPath = filesep + fullfile(parentPaths, fullParts{idx:end});

                    % What if paths are still the same?
                    if isempty(relPath)
                        relPath = "." + filesep;
                    end

                    % Prepare event data
                    evtOut = wt.eventdata.PropertyChangedData('Value',relPath, obj.Value);

                    % Store new result
                    obj.Value = relPath;

                    % Trigger event
                    notify(obj,"ValueChanged",evtOut);

                end

            else

                    % Prepare event data
                    evtOut = wt.eventdata.PropertyChangedData('Value',fullPath, obj.Value);

                    % Store new result
                    obj.Value = fullPath;

                    % Trigger event
                    notify(obj,"ValueChanged",evtOut);

            end %if

        end %function

    end % methods

    %% Accessors
    methods

        function set.Value(obj,value)
            value = wt.utility.cleanPath(value);
            obj.Value = value;
            obj.addToHistory(value)
        end

        function set.RootDirectory(obj,value)
            value = wt.utility.cleanPath(value);
            obj.RootDirectory = value;
            obj.addToHistory(value)
        end

        function set.SelectionType(obj,value)
            obj.SelectionType = value;
            obj.updateButtonIcon()
        end

        function set.ShowHistory(obj,value)
            obj.ShowHistory = value;
            obj.updateControlType()
        end

        function value = get.FullPath(obj)
            value = fullfile(obj.RootDirectory, obj.Value);
        end

        function value = get.ValueIsValidPath(obj)
            filePath = fullfile(obj.RootDirectory, obj.Value);
            value = ( obj.SelectionType == "file" && exist(filePath,"file") ) || ...
                ( obj.SelectionType == "folder" && exist(filePath,"dir") );
        end

    end % methods

end % classdef


classdef MimLinkedDatasetChooser < CoreBaseClass
    % MimLinkedDatasetChooser. Part of the internal framework of the TD MIM Toolkit.
    %
    %     You should not use this class within your own code. It is intended to
    %     be used internally within the framework of the TD MIM Toolkit.
    %
    %     MimLinkedDatasetChooser is used to select between linked datasets.
    %     By default, each dataset acts independently, but you can link datasets
    %     together (for example, if you wanted to register images between two
    %     datasets). When datasets are linked, one is the primary dataset, and
    %     linked results are stored in the primary cache. The primary dataset
    %     may access results from any of its linked datasets (but not vice
    %     versa). Linking can be nested.
    %
    %
    %     Licence
    %     -------
    %     Part of the TD MIM Toolkit. https://github.com/tomdoel
    %     Author: Tom Doel, Copyright Tom Doel 2014.  www.tomdoel.com
    %     Distributed under the MIT licence. Please see website for details.
    %

    properties (Access = private)
        LinkedRecorderSingleton
        DatasetCache
        PrimaryDatasetResults % Handle to the MimDatasetResults object for this dataset
        LinkedDatasetChooserList % Handles to MimLinkedDatasetChooser objects for all linked datasets, including this one
        PrimaryDatasetUid     % The uid of this dataset
    end

    events
        % This event is fired when a plugin has been run for this dataset, and
        % has generated a new preview thumbnail.
        PreviewImageChanged
    end

    methods
        function obj = MimLinkedDatasetChooser(framework_app_def, context_def, image_info, dataset_disk_cache, linked_recorder_singleton, plugin_cache, reporting)
            obj.LinkedRecorderSingleton = linked_recorder_singleton;
            obj.DatasetCache = dataset_disk_cache;
            primary_dataset_results = MimDatasetResults(framework_app_def, context_def, image_info, obj, obj, dataset_disk_cache, plugin_cache, reporting);
            obj.PrimaryDatasetUid = primary_dataset_results.GetImageInfo.ImageUid;
            obj.PrimaryDatasetResults = primary_dataset_results;
            obj.LinkedDatasetChooserList = containers.Map;
            obj.LinkedDatasetChooserList(obj.PrimaryDatasetUid) = obj;
        end

        function AddLinkedDataset(obj, linked_name, linked_dataset_chooser, reporting)
            % Links a different dataset to this one, using the specified name.
            % The name exists only within the scope of this dataset, and is used
            % to identify the linked dataset from which results should be
            % obtained.

            linked_uid = linked_dataset_chooser.PrimaryDatasetUid;
            obj.LinkedDatasetChooserList(linked_uid) = linked_dataset_chooser;
            obj.LinkedDatasetChooserList(linked_name) = linked_dataset_chooser;

            obj.LinkedRecorderSingleton.AddLink(obj.PrimaryDatasetUid, linked_uid, linked_name, reporting);
        end

        function dataset_results = GetDataset(obj, reporting, varargin)
            % Returns a handle to the DatasetResults object for a particular linked dataset.
            % The dataset is identified by its uid in varargin, or an empty
            % input will return the primary dataset.

            if nargin < 3
                dataset_name = [];
            else
                dataset_name = varargin{1};
            end
            if isempty(dataset_name)
                dataset_name = obj.PrimaryDatasetUid;
            end
            if ~obj.LinkedDatasetChooserList.isKey(dataset_name)
                reporting.Error('MimLinkedDatasetChooser:DatasetNotFound', 'No linked dataset was found with this name. Did you add the dataset with LinkDataset()?');
            end
            linked_dataset_chooser = obj.LinkedDatasetChooserList(dataset_name);
            dataset_results = linked_dataset_chooser.PrimaryDatasetResults;
        end

        function is_linked_dataset = IsLinkedDataset(obj, linked_name_or_uid, reporting)
            % Returns true if another dataset has been linked to this one, using
            % the name or uid specified

            is_linked_dataset = obj.LinkedDatasetChooserList.isKey(linked_name_or_uid);
        end

        function ClearMemoryCacheInAllLinkedDatasets(obj)
            % Clears the temporary memory cache of this and all linked
            % datasets
            for linker = obj.LinkedDatasetChooserList.values
                if linker{1} == obj
                    obj.DatasetCache.ClearTemporaryMemoryCache;
                else
                    linker{1}.ClearMemoryCacheInAllLinkedDatasets;
                end
            end
        end

        function NotifyPreviewImageChanged(obj, plugin_name)
            notify(obj,'PreviewImageChanged', CoreEventData(plugin_name));
        end

        function primary_uid = GetPrimaryDatasetUid(obj)
            primary_uid = obj.PrimaryDatasetUid;
        end

    end
end


%CLOSEMESS Close progress message
%
%   CLOSEMESS(FID,N)
%
% Closes a progress message of length N on file-id FID
%
% This routine is obsolete now and just preserved to get
% old code running.

% Copyright: R.P.W. Duin, r.p.w.duin@37steps.com
% Faculty EWI, Delft University of Technology
% P.O. Box 5031, 2600 GA Delft, The Netherlands

function closemess(fid,n)

	prprogress(fid,'\n');

return


classdef DataPuller < handle
%DataPuller Pull olympiad data from SAGE.
%   A DataPuller knows how, for a particular assay, to pull data from SAGE
%   based on a user-specified query, and merge/clean the results into a
%   single struct array. This is an assay-dependent operation; each assay
%   has differerent SAGE views and different requirements for merging and
%   cleaning.
%
%   DataPuller is meant to be used in conjunction with the
%   OlyDat.DataSelector.
%
%   See also OlyDat.DataSelector, OlyDat.Browser.

    properties (Abstract)
        % if true, pull from FS by default.
        tfPullFSDefault;

        % cellstr of options displayed in DataSelector pull-down and passed
        % to pullData function. can be empty.
        options;
    end

    methods (Abstract)
        %pullData/pullDataFS Pull Data from SAGE
        %   pullData is a SAGE data-pulling function for use with
        %   OlyDat.DataSelector. queryObjs is a cell array of query objects
        %   created by the user using the DataSelector. datapath is the
        %   user-specified folder containing experimental directories.
        %   option is a string, selected by the user in the DataSelector;
        %   it is one of the options specified in the DataPuller .options
        %   property.
        %
        %   data should be a struct array that results from pulling data
        %   from the appropriate dataSets and cleaning and merging that
        %   data. This struct array should have one element per experiment
        %   for use with the OlyDat.Browser.
        data = pullData(obj,queryObjs,option)
        data = pullDataFS(obj,queryObjs,datapath,option)
    end

    methods % hook methods

        function s = getCustomFieldPulldownInfo(obj) %#ok<MANU>
            % s = getCustomFieldPulldownInfo(obj)
            % Return info to resolve ambiguities when two or more datasets
            % share fields with the same name. Information returned by this
            % method is used by the DataSelector when populating pulldowns for
            % specifying the field in a query.
            %
            % This is a hook method intended to be overridden.
            %
            % s: struct array with fields
            %   * .Name: name of field
            %   * .DataSetName: name of DataSet whose DataSetField object
            %   should be used
            %   * .PrettyName: (optional). Currently not used/implemented.

            % Default implementation: none
            s = [];
        end

    end

    methods (Static) % utilities

        function fsp = reseatFileSystemPath(fsp,datapath)
            % fsp = reseatFileSystemPath(fsp,datapath)
            [~,fsp] = fileparts(fsp);
            fsp = fullfile(datapath,fsp);
        end

    end
end


classdef PTKSegmentLungs < MimGuiPlugin
    % PTKSegmentLungs. Gui Plugin for activating lung segmentation
    %
    %     You should not use this class within your own code. It is intended to
    %     be used by the gui of the Pulmonary Toolkit.
    %
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2012.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    properties
        ButtonText = 'Lungs'
        SelectedText = 'Lungs'
        ToolTip = 'Segment the lungs'
        Category = 'Segment region'
        Visibility = 'Dataset'
        Mode = 'Segment'

        HidePluginInDisplay = false
        PTKVersion = '1'
        ButtonWidth = 6
        ButtonHeight = 1
        Icon = 'icon_lungs.png'
        Location = 2
    end

    methods (Static)
        function RunGuiPlugin(gui_app)
            gui_app.RunPluginCallback('PTKLeftAndRightLungs');
        end

        function enabled = IsEnabled(gui_app)
            enabled = gui_app.IsDatasetLoaded && (gui_app.IsCT || gui_app.IsMR);
        end

        function is_selected = IsSelected(gui_app)
            is_selected = gui_app.IsDatasetLoaded && strcmp(gui_app.GetCurrentPluginName, 'PTKLeftAndRightLungs');
        end

    end
end


function cttools(mode)

f = gcf;
ui_data = get(f,'userdata');
ui_obj = ui_data{2};
eraser2 = ui_obj.eraser2;
tab_uis = ui_obj.ToolTabs;

% define various shades of grey
grey = get(0,'defaultuicontrolbackground');
ltgrey = [0.5,0.5,0.5]*1.5;
dkgrey = [0.5,0.5,0.5]*0.5;

switch mode
   case 'Freq',

      %sel_dims = [-3,0,+6,+2];
      %unsel_dims = [3,0,-6,-2];

      sel_dims = [0,0,0,+2];
      unsel_dims = [0,0,0,-2];

      sel_tab = findobj(f,'tag','selected_tab2');
      cur_obj = tab_uis(1);
      if sel_tab == cur_obj, return; end

      if length(sel_tab),
         tab_pos = get(sel_tab,'pos');
         set(sel_tab,'pos',tab_pos+unsel_dims,'tag','',...
                     'back',ltgrey);
      end

      cur_pos = get(cur_obj,'pos');
      set(cur_obj,'pos',cur_pos+sel_dims,'tag','selected_tab2',...
                  'back',grey);
      eraser_pos = cur_pos+sel_dims;
      set(eraser2,'pos',[eraser_pos(1:3)+[2,0,-4],2]);

      set([ui_obj.RootUI, ui_obj.TimeUI],'vis','off');
      set(ui_obj.FreqUI,'vis','on');

   case 'Root',

      %sel_dims = [-3,0,+6,+2];
      %unsel_dims = [3,0,-6,-2];

      sel_dims = [0,0,0,+2];
      unsel_dims = [0,0,0,-2];

      sel_tab = findobj(f,'tag','selected_tab2');
      cur_obj = tab_uis(2);
      if sel_tab == cur_obj, return; end

      if length(sel_tab),
         tab_pos = get(sel_tab,'pos');
         set(sel_tab,'pos',tab_pos+unsel_dims,'tag','',...
                     'back',ltgrey);
      end

      cur_pos = get(cur_obj,'pos');
      set(cur_obj,'pos',cur_pos+sel_dims,'tag','selected_tab2',...
                  'back',grey);
      eraser_pos = cur_pos+sel_dims;
      set(eraser2,'pos',[eraser_pos(1:3)+[2,0,-4],2]);

      set([ui_obj.FreqUI, ui_obj.TimeUI],'vis','off');
      set(ui_obj.RootUI,'vis','on');

   case 'Time',

      %sel_dims = [-3,0,+6,+2];
      %unsel_dims = [3,0,-6,-2];

      sel_dims = [0,0,0,+2];
      unsel_dims = [0,0,0,-2];

      sel_tab = findobj(f,'tag','selected_tab2');
      cur_obj = tab_uis(3);
      if sel_tab == cur_obj, return; end

      if length(sel_tab),
         tab_pos = get(sel_tab,'pos');
         set(sel_tab,'pos',tab_pos+unsel_dims,'tag','',...
                     'back',ltgrey);
      end

      cur_pos = get(cur_obj,'pos');
      set(cur_obj,'pos',cur_pos+sel_dims,'tag','selected_tab2',...
                  'back',grey);
      eraser_pos = cur_pos+sel_dims;
      set(eraser2,'pos',[eraser_pos(1:3)+[2,0,-4],2]);

      set([ui_obj.FreqUI, ui_obj.RootUI],'vis','off');
      set(ui_obj.TimeUI,'vis','on');

end


function init(fname, nbytes, opts)
% Initialise binary file on disk
% FORMAT init(fname, nbytes[, opts])
% fname   - filename
% nbytes  - data size {bytes}
% opts    - optional structure with fields:
%   .offset   - file offset {bytes} [default: 0]
%   .wipe     - overwrite exisiting values with 0 [default: false]
%   .truncate - truncate file if larger than requested size [default: true]
%
% This function is normally called by file_array/initialise
%__________________________________________________________________________
% Copyright (C) 2005-2017 Wellcome Trust Centre for Neuroimaging

% Guillaume Flandin
% $Id: init.m 7147 2017-08-03 14:07:01Z spm $

%-This is merely the help file for the compiled routine
error('init.c not compiled - see Makefile');


function varargout = Read_FrictionmodeGUI(varargin)
% Last Modified by GUIDE v2.5 11-Feb-2019 18:03:10

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @Read_FrictionmodeGUI_OpeningFcn, ...
                   'gui_OutputFcn',  @Read_FrictionmodeGUI_OutputFcn, ...
                   'gui_LayoutFcn',  [] , ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
    gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

% --- Executes just before Read_FrictionmodeGUI is made visible.
function Read_FrictionmodeGUI_OpeningFcn(hObject, eventdata, handles, varargin)
% Choose default command line output for Read_FrictionmodeGUI
handles.output = hObject;
a=get(handles.global_slider,'Value');                                           %Get slider value of "global slider"
set(handles.global_text,'String',num2str(a));                                   %Set text above "global slider" to slider value
set(findall(handles.random_panel1, '-property', 'enable'),'enable', 'off');     %Disable Random_panel1
set(findall(handles.random_panel2, '-property', 'enable'),'enable', 'off');     %Disable Random_panel2
set(findall(handles.raceline_panel, '-property', 'enable'),'enable', 'off');    %Disable Raceline_panel
set(findall(handles.uipanel10, '-property', 'enable'),'enable', 'off');         %Disable Raceline percentage mode panel
handles.another_map_1=0;                                                        %Set default value of "another_map" to "0"
% Update handles structure
guidata(hObject, handles);

% --- Outputs from this function are returned to the command line.
function varargout = Read_FrictionmodeGUI_OutputFcn(hObject, eventdata, handles)
varargout{1} = handles.output;

% --- Executes on button press in global_button.
function global_button_Callback(hObject, eventdata, handles)
set(handles.raceline_pathname, 'String', '');                                   %Set raceline pathname to none
set(handles.random_text1,'String','');                                          %Set text above "random slider1" to none
set(handles.random_text2,'String','');                                          %Set text above "random slider2" to none
set(handles.slider1_text2,'String','');                                         %Set text above "raceline slider1" to none
set(handles.slider2_text2,'String','');                                         %Set text above "raceline slider2" to none
cla(handles.axes1);                                                             %Clear axes1
set(findall(handles.global_panel, '-property', 'enable'),'enable', 'on');       %Enable Global panel
set(handles.checkbox, 'Enable','on');                                           %Enable Checkbox of Raceline Percentage Mode
set(findall(handles.random_panel1, '-property', 'enable'),'enable', 'off');     %Disable Random_panel1
set(findall(handles.random_panel2, '-property', 'enable'),'enable', 'off');     %Disable Random_panel2
set(findall(handles.raceline_panel, '-property', 'enable'),'enable', 'off');    %Disable Raceline_panel
a=get(handles.global_slider,'Value');                                           %Get slider value of "global slider"
set(handles.global_text,'String',num2str(a));                                   %Set text above "global slider" to slider value

% --- Executes on button press in random_button.
function random_button_Callback(hObject, eventdata, handles)
set(handles.raceline_pathname, 'String', '');                                   %Set raceline pathname to none
set(handles.global_text,'String','');                                           %Set text above "global slider" to none
set(handles.slider1_text2,'String','');                                         %Set text above "raceline slider1" to none
set(handles.slider2_text2,'String','');                                         %Set text above "raceline slider2" to none
cla(handles.axes1);                                                             %Clear axes1
set(findall(handles.global_panel, '-property', 'enable'),'enable', 'off');      %Disable Global panel
set(handles.checkbox, 'Enable','on');                                           %Enable Checkbox of Raceline Percentage Mode
set(findall(handles.random_panel1, '-property', 'enable'),'enable', 'on');      %Enable Random_panel1
set(findall(handles.random_panel2, '-property', 'enable'),'enable', 'on');      %Enable Random_panel2
set(findall(handles.raceline_panel, '-property', 'enable'),'enable', 'off');    %Disable Raceline_panel
a=get(handles.random_slider1,'Value');                                          %Get slider value of "random slider1"
b=get(handles.random_slider2,'Value');                                          %Get slider value of "random slider2"
set(handles.random_text1,'String',num2str(a));                                  %Set text above "random slider1" to slider value
set(handles.random_text2,'String',num2str(b));                                  %Set text above "random slider2" to slider value

% --- Executes on button press in raceline_button.
function raceline_button_Callback(hObject, eventdata, handles)
set(findall(handles.global_panel, '-property', 'enable'),'enable', 'off');      %Disable Global panel
set(handles.checkbox, 'Value', 0);                                              %Set Checkbox Value to "0"
checkbox_Callback(handles.checkbox, eventdata, handles);                        %Run Checkbox_Callback
set(handles.checkbox, 'Enable','off');                                          %Disable Checkbox of Raceline Percentage Mode
set(handles.raceline_pathname_percent,'String','');                             %Set raceline_pathname_percent to none
set(findall(handles.random_panel1, '-property', 'enable'),'enable', 'off');     %Disable Random_panel1
set(findall(handles.random_panel2, '-property', 'enable'),'enable', 'off');     %Disable Random_panel2
set(findall(handles.raceline_panel, '-property', 'enable'),'enable', 'on');     %Enable Raceline_panel
set(handles.global_text,'String','');                                           %Set text above "global slider" to none
set(handles.random_text1,'String','');                                          %Set text above "random slider1" to none
set(handles.random_text2,'String','');                                          %Set text above "random slider2" to none
a=get(handles.raceline_slider1,'Value');                                        %Get slider value of "raceline slider1"
b=get(handles.raceline_slider2,'Value');                                        %Get slider value of "raceline slider2"
set(handles.slider1_text2,'String',num2str(a));                                 %Set text above "raceline slider1" to slider value
set(handles.slider2_text2,'String',num2str(b));                                 %Set text above "raceline slider2" to slider value
x=-6:0.1:6;                                                                     %Generate array
y=a*exp(-b*0.1*x.^2);                                                           %Generate function value
plot(handles.axes1,x,y)                                                         %Plot function
set(handles.axes1, 'Xlim', [-6,6]);                                             %Set x-limits to [-6,6]

% --- Executes on button press in checkbox.
function checkbox_Callback(hObject, eventdata, handles)
if get(handles.checkbox, 'Value')==1                                            %If checkbox is activated: Enable all features!
    set(findall(handles.uipanel10, '-property', 'enable'),'enable', 'on');      %Enable Raceline percentage mode panel
    set(handles.browse3_button, 'Enable', 'On');                                %Enable Raceline percentage mode browser button
    set(handles.percent_value, 'Enable', 'On');                                 %Enable Raceline percentage mode Value Text
elseif get(handles.checkbox, 'Value')==0                                        %If checkbox is not activated: Disable all features!
    set(findall(handles.uipanel10, '-property', 'enable'),'enable', 'off');     %Disable Raceline percentage mode panel
    set(handles.browse3_button, 'Enable', 'Off');                               %Disable Raceline percentage mode browser button
    set(handles.percent_value, 'Enable', 'Off');                                %Disable Raceline percentage mode Value Text
end

% --- Executes on slider movement.
function raceline_slider1_Callback(hObject, eventdata, handles)
a=get(handles.raceline_slider1,'Value');                                        %Get slider value of "raceline slider1"
b=get(handles.raceline_slider2,'Value');                                        %Get slider value of "raceline slider2"
a=round(a*100)/100;                                                             %Round value of "raceline slider1" to 1/100
set(handles.raceline_slider1,'Value', a);                                       %Set slider value of "raceline slider1" to rounded value
set(handles.slider1_text2,'String',num2str(a));                                 %Set text above "raceline slider1" to slider value
x=-6:0.1:6;                                                                     %Generate array
y=a*exp(-b*0.1*x.^2);                                                           %Generate function value
plot(handles.axes1,x,y)                                                         %Plot function
set(handles.axes1, 'Xlim', [-6,6]);                                             %Set x-limits to [-6,6]

% --- Executes during object creation, after setting all properties.
function raceline_slider1_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function raceline_slider2_Callback(hObject, eventdata, handles)
a=get(handles.raceline_slider1,'Value');                                        %Get slider value of "raceline slider1"
b=get(handles.raceline_slider2,'Value');                                        %Get slider value of "raceline slider2"
b=round(b*100)/100;                                                             %Round value of "raceline slider2" to 1/100
set(handles.raceline_slider2,'Value', b);                                       %Set slider value of "raceline slider2" to rounded value
set(handles.slider2_text2,'String',num2str(b));                                 %Set text above "raceline slider2" to slider value
x=-6:0.1:6;                                                                     %Generate array
y=a*exp(-b*0.1*x.^2);                                                           %Generate function value
plot(handles.axes1,x,y)                                                         %Plot function
set(handles.axes1, 'Xlim', [-6,6]);                                             %Set x-limits to [-6,6]

% --- Executes during object creation, after setting all properties.
function raceline_slider2_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function random_slider1_Callback(hObject, eventdata, handles)
a=get(handles.random_slider1,'Value');                                          %Get slider value of "random slider1"
a=round(a*50)/50;                                                               %Round value of "random slider1" to 1/50
set(handles.random_slider1,'Value', a);                                         %Set slider value of "random slider1" to rounded value
set(handles.random_text1,'String',num2str(a));                                  %Set text above "random slider1" to slider value

% --- Executes during object creation, after setting all properties.
function random_slider1_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function random_slider2_Callback(hObject, eventdata, handles)
a=get(handles.random_slider2,'Value');                                          %Get slider value of "random slider2"
a=round(a*50)/50;                                                               %Round value of "random slider2" to 1/50
set(handles.random_slider2,'Value', a);                                         %Set slider value of "random slider2" to rounded value
set(handles.random_text2,'String',num2str(a));                                  %Set text above "random slider2" to slider value

% --- Executes during object creation, after setting all properties.
function random_slider2_CreateFcn(hObject, eventdata, handles)
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on slider movement.
function global_slider_Callback(hObject, eventdata, handles)
a=get(handles.global_slider,'Value');                                           %Get slider value of "global slider"
a=round(a*50)/50;                                                               %Round value of "global slider" to 1/50
set(handles.global_slider,'Value', a);                                          %Set slider value of "global slider" to rounded value
set(handles.global_text,'String',num2str(a));                                   %Set text above "global slider" to slider value

% --- Executes during object creation, after setting all properties.
function global_slider_CreateFcn(hObject, eventdata, handles) %#ok<*DEFNU,*INUSD>
if isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor',[.9 .9 .9]);
end

% --- Executes on button press in browse2_button.
function browse2_button_Callback(hObject, eventdata, handles)
[filename2, pathname2] = uigetfile('*.csv', 'Pick a .csv file');                    %Browse for file
handles.pathname_raceline = strcat(pathname2, filename2);                           %Connect path name and file name to one string
data_type=lower(filename2(end-2:end));                                              %Extract data type and convert to string
if data_type =='csv'                                                 %#ok<*BDSCA>
    set(handles.raceline_pathname, 'String', handles.pathname_raceline);            %Set GUI.full_path to string fullpathname
else
    set(handles.raceline_pathname, 'String', 'ERROR');                              %Display "ERROR"
end
guidata(hObject, handles);

% --- Executes on button press in browse3_button.
function browse3_button_Callback(hObject, eventdata, handles)
[filename3, pathname3] = uigetfile('*.csv', 'Pick a .csv file');                                %Browse for file
handles.raceline_pathname_percent_name = strcat(pathname3, filename3);                          %Connect path name and file name to one string
data_type=lower(filename3(end-2:end));                                                          %Extract data type and convert to string
if data_type =='csv'                                                 %#ok<*BDSCA>
    set(handles.raceline_pathname_percent, 'String', handles.raceline_pathname_percent_name);   %Set GUI.full_path to string fullpathname
else
    set(handles.raceline_pathname_percent, 'String', 'ERROR');                                  %Display "ERROR"
end
guidata(hObject, handles);

function percent_value_Callback(hObject, eventdata, handles)

% --- Executes during object creation, after setting all properties.
function percent_value_CreateFcn(hObject, eventdata, handles)
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in create_2_map_button.
function create_2_map_button_Callback(hObject, eventdata, handles)
handles.another_map_1=1;                                                            %Set value of "another_map" to "1"
create_map_button_Callback(handles.create_map_button, eventdata, handles);          %Run create_map_button_Callback

% --- Executes on button press in create_map_button.
function create_map_button_Callback(hObject, eventdata, handles) %#ok<*INUSL>
if handles.another_map_1==1                                                         %if "another_map" =1
    assignin('base', 'another_map', 1);                                             %Handover "another_map"==1 to base workspace
else
    assignin('base', 'another_map', 0);                                             %Handover "another_map"==0 to base workspace
end
a=0;                                                                                %Initialize a consistency check variable
%Check Raceline_percentage_panel on consistency
if get(handles.checkbox, 'Value')==1                                                %If Checkbox for Raceline Percentage Mode is activated
    d=str2double(get(handles.percent_value, 'String'));                                 %Get Raceline Percentage Value
    if d>-99 && d<99                                                                    %If Raceline Percentage Value is consistent
        path_percent = get(handles.raceline_pathname_percent, 'String');                    %Get Raceline Percentage Pathname
        if strcmp(path_percent, "") || strcmp(path_percent,'ERROR')                         %If Pathname is not consistent
            set(handles.raceline_pathname_percent, 'String', 'ERROR');                          %Set Raceline Percentage Pathname to "ERROR"
        else                                                                                %Else (if pathname is consistent)
            assignin('base', 'raceline_percentage_mode', 1);                                    %Handover a positive ("1") raceline percentage mode
            assignin('base', 'raceline_percent_value', d);                                      %Handover the Raceline Percentage value
            assignin('base', 'path_raceline', path_percent);                                    %Handover Raceline Path
            a=1;                                                                                %Set Consistency Check Variable to "1"
        end
    else                                                                                %Else (if raceline percentage value is not consistent)
        set(handles.percent_value, 'String', 'ERROR')                                       %Set Raceline Percentage value to "ERROR"
    end
else                                                                                %Else (if checkbox for Raceline Percentage Mode is not activated)
    assignin('base', 'raceline_percentage_mode', 0);                                    %Handover a negative ("0") raceline percentage mode
    a=1;                                                                                %Set Consistency Check Variable to "1"
end
%End of Consistency Check: a=0: not consistent, a=1: consistent
% If everything is consistent, GUI continues
if a==1
    if get(handles.global_button,'Value')                                   %If Global_Button is activated
        global_value=get(handles.global_slider,'Value');                        %Get slider value of "global slider"
        assignin('base', 'global_value', global_value);                         %Handover "global value" to base workspace
        assignin('base', 'mode', 'global');                                     %Handover "mode" to base workspace
        close(Read_FrictionmodeGUI);                                                      %Close Read_FrictionmodeGUI
        Friction_Map_Creation();                                                %Run Friction_Map_Creation
    elseif get(handles.random_button,'Value')                               %If Random_Button is activated
        random_value_1=get(handles.random_slider1,'Value');                     %Get slider value of "random slider1"
        random_value_2=get(handles.random_slider2,'Value');                     %Get slider value of "random slider2"
        if random_value_1<random_value_2                                        %if slider values are consistent
            assignin('base', 'random_value_1', random_value_1);                     %Handover "random value1" to base workspace
            assignin('base', 'random_value_2', random_value_2);                     %Handover "random value2" to base workspace
            assignin('base', 'mode', 'random');                                     %Handover "mode" to base workspace
            close(Read_FrictionmodeGUI);                                                      %Close Read_FrictionmodeGUI
            Friction_Map_Creation();                                                %Run Friction_Map_Creation
        else                                                                    %else (if slider values are not consistent)
            set(handles.random_text1, 'String', '');                                %Set text above "random slider1" to none
            set(handles.random_text2, 'String', '');                                %Set text above "random slider2" to none
        end
    elseif get(handles.raceline_button,'Value')                             %If Raceline_Button is activated
        path = get(handles.raceline_pathname, 'String');                        %Get Raceline Pathname
        if strcmp(path, "")                                                     %If Raceline Pathname is none
            set(handles.raceline_pathname, 'String', 'ERROR');                      %Set Raceline Pathname to "ERROR"
        elseif strcmp(path,'ERROR')                                             %If Raceline Pathname is "ERROR"
            set(handles.raceline_pathname, 'String', 'ERROR');                      %Set Raceline Pathname to "ERROR"
        else                                                                    %else (if Raceline Pathname is consistent)
            a=get(handles.raceline_slider1,'Value');                                %Get slider value of "raceline slider1"
            b=get(handles.raceline_slider2,'Value');                                %Get slider value of "raceline slider2"
            assignin('base', 'raceline_value_1', a);                                %Handover "raceline value1" to base workspace
            assignin('base', 'raceline_value_2', b);                                %Handover "raceline value2" to base workspace
            assignin('base', 'mode', 'raceline');                                   %Handover "mode" to base workspace
            assignin('base','path_raceline', handles.pathname_raceline);            %Handover Path Raceline
            close(Read_FrictionmodeGUI);                                                      %Close Read_FrictionmodeGUI
            Friction_Map_Creation();                                                %Run Friction_Map_Creation
        end
    end
end


function closeAllCERRFigures(varargin)
%Close all figures related to CERR, with the exception of the transverse viewer, which closes itself.
%
% 15 Aug 02, V H Clark
% LM: 30 Dec 02, JOD
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.

global stateS planC

if nargin == 0

	fieldsC = fieldnames(stateS.handle);

	for i = 1 : length(fieldsC)
      if ~strcmp(fieldsC{i},'CERRSliceViewer')
        hV = getfield(stateS.handle,fieldsC{i});
        for j = 1 : length(hV)
          try
            delete(hV(j))
          end
        end
      end
	end

	if ~stateS.workspacePlan & stateS.planLoaded
        clear global planC
	end
	clear global stateS

%If a selective close, only close certain figures.
elseif nargin == 1 & strcmpi(varargin{1},'Selective');
    try, delete(stateS.handle.doseManagementFig);,end;
    try, delete(stateS.handle.doseSubtractionMenuFig);,end;
    try, delete(stateS.handle.IMRTMenuFig);,end;
    try, delete(stateS.handle.DVHMenuFigure);,end;
    try,
        for i=1:length(stateS.handle.DVHPlot)
            try, delete(stateS.handle.DVHPlot),end;
        end
    end
    try, delete(stateS.handle.metricSelectionFig);,end;
    try, delete(stateS.handle.doseShadowFig);,end;
    try, delete(stateS.handle.graphicalComparisonFig);,end;
    try, delete(stateS.handle.aboutCERRFig);,end;
    try, delete(stateS.handle.structureFusionFig);,end;
    try, delete(stateS.handle.navigationMontage);,end;
    try, delete(stateS.handle.deepLearnSegFig);,end;
end


function [ff, pp, fi] = uiget1Dfile()
% open a gui for 1D file selection
% returns the same output as uigetfile

[ff, pp, fi] = uigetfile( {'*.1D;*.1D.dset' , ...
                         'AFNI 1D Files (*.1D, *.1D.dset)';},...
                         'Select 1D file' );
return


function a = subsasgn(a,S,val)
% A.FIELD = val; %Subscripted assignment
%
% SEE ALSO, SET

if isempty(a)
    % Ex. a(1) = chanhandle(filename,channel_num);
    if isequal(S.type, '()')&isa(val,'chanhandle')&isequal(S.subs{:},1)
        a = val;
        return;
    else
        newline= sprintf('\n');
        str = ['Could not initialize chanhandle object with given parameters',newline,...
        'Please note that:',newline,...
        '  1. Right-hand side should be a valid chanhandle object',newline,...
        '  2. Only the first channel should be set',newline,...
        '  3. Property of chanhandle cannot be set until the object itself is initialzed'];
        error(str);
    end;
end;
if nargin == 3
    switch length(S)
    case 1
        switch S.type
        case '()'
            if isa(val,'chanhandle')
                if isequal(S.subs{1}, 1:length(val)) % a(i) = chanhandle_obj;
                    a.handle(S.subs{1}) = getfield(struct(val),'handle');
                elseif isequal(length(S.subs{:}),length(getfield(struct(val),'handle')))
                    % Ex. a(i1,i2,...) = [chanhandle_obj1,chanhandle_obj2,...];
                    for i = 1:length(S.subs)
                        a.handle(S.subs{i}) = getfield(struct(val(i)),'handle');
                    end;
                else
                    error('Input chanhandle structure and Channel number do not match');
                end;
            elseif isstruct(val)  %Ex. a(i) = chanhandle_obj.handle;
                if isequal(length(S.subs{:}),length(val))
                    for i = 1:length(S.subs)
                        a.handle(S.subs{i}) = val(i);
                    end;
                else
                    error('Input chanhandle structure and Channel number do not match');
                end;
            else
                error('RHS must be either a valid structure or a chanhandle object');
            end;
        case '.'
            a = set(a,S.subs,val);      % a.field = val;
        end;
    case 2
        if strcmp(S(1).type,'()')&strcmpi(S(2).type,'.')    % a(i).field = val;
            a = set(a,S(1).subs{:},S(2).subs,val);
        elseif strcmp(S(1).type,'.')&strcmpi(S(2).type,'()')% a.field(i) = val;
            a = set(a,S(1).subs,S(2).subs{:},val);
        elseif strcmp(S(1).type,'.')&strcmpi(S(2).type,'.') % a.field1.field2 = val;
            a = set(a,[S(1).subs,'.',S(2).subs],val);
        else
            error('Sorry - output structure not supported');
        end;
    otherwise
        error('Sorry - output structure not supported');
    end;
else
    error('incorrect number of arguments');
end;


%% <../index.html MATLAB xUnit Test Framework>: How to Run Tests Silently and Query the Results
% When you run a test suite using |runtests|, the results are
% summarized in the Command Window.  This example shows you how to
% run a test suite so that nothing prints to the Command Window, and
% it shows you how to write a program to automatically determine the
% results of running the test suite.
%
% There are four steps to follow.
%
% 1. Construct a |TestSuite| object.  In this example we'll use the |fromPwd|
% method of the |TestSuite| class to construct a test suite using all the test
% cases found in the |examples_general| directory.

cd examples_general
suite = TestSuite.fromPwd();

%%
% You can look up information about the individual test cases.

suite.TestComponents{1}

%%
% You can see above that the first test component in the test suite is itself
% another test suite, which contains the test cases defined by the M-file named
% TestUsingTestCase. Here's what one of these individual test cases looks like:

suite.TestComponents{1}.TestComponents{1}

%%
% 2. Construct a TestLogger object.  This object can receive
% notifications about what happens when a test suite is executed.

logger = TestRunLogger;

%%
% 3. Call the |run| method of the |TestSuite| object, passing it the
% logger.

suite.run(logger);

%%
% The |TestLogger| object can now be queried to determine what
% happened during the test.

logger

%%
% There were eight test cases run (logger.NumTestCases), resulting in
% one test failure and one test error.  Detailed information about
% what went wrong can be found in |logger.Faults|.

logger.Faults(1)

%%

logger.Faults(2)

%%
% You can drill further to determine the names of the failing tests,
% as well as the complete stack trace associated with each failure.

logger.Faults(1).TestCase

%%

logger.Faults(1).Exception.stack(1)

%%

logger.Faults(1).Exception.stack(2)

%%
% <../index.html Back to MATLAB xUnit Test Framework>

%%
% Copyright 2008-2010 The MathWorks, Inc.


function hf=anim8(varargin)

%% Parse input

switch nargin
    case 2
        hf=varargin{1};
        animStruct=varargin{2};
end

%% Visualisation settings

% fontColor='w';
fontSize=15;
% cMap=gjet(250);

scrollBarWidth=50;

%% Defining slider

animTime=animStruct.Time(:);

minT=1;
maxT=numel(animTime);
w=maxT-minT;
sliceIndexI=1; %Initial index
tickSizeMajor_I=ceil(w/20);

%% Initialize display

figure(hf); drawnow;

%Initialize slider
jSlider = javax.swing.JSlider(minT,maxT);
javacomponent(jSlider,[0,0,round(hf.Position(3)),scrollBarWidth]);
set(jSlider, 'MajorTickSpacing',tickSizeMajor_I, 'MinorTickSpacing',1, 'PaintTicks',true, 'PaintLabels',true,...
    'Background',java.awt.Color.white, 'snapToTicks',true, 'StateChangedCallback',{@updateViewFunc,{hf,jSlider}},'Orientation',jSlider.HORIZONTAL);

%% Set resize function

set(hf,'ResizeFcn',{@setScrollSizeFunc,{hf,scrollBarWidth,jSlider}});

%% Initialize figure callbacks

set(hf,'KeyPressFcn', {@figKeyPressFunc,{hf}});%'WindowButtonDownFcn', {@figMouseDown,{hf}},'WindowButtonUpFcn', {@mouseup,hf});

%% Initialise buttons

filePath=mfilename('fullpath');
toolboxPath=fileparts(fileparts(filePath));
iconPath=fullfile(toolboxPath,'icons');

% hb = findall(hf,'Type','uitoolbar');
hb = uitoolbar(hf);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Help button

%get icon
D=importdata(fullfile(iconPath,'help.jpg'));
S=double(D);
S=S-min(S(:));
S=S./max(S(:));
S(S==1)=NaN;
if size(S,3)==1
    S=repmat(S,[1 1 3]);
end
% Create a uipushtool in the toolbar
uipushtool(hb,'TooltipString','Help','CData',S,'Tag','help_button','ClickedCallback',@helpFunc,'Separator','on');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Play button

%get icon 1
D=importdata(fullfile(iconPath,'play.jpg'));
S=double(D);
S=S-min(S(:));
S=S./max(S(:));
S(S==1)=NaN;
if size(S,3)==1
    S=repmat(S,[1 1 3]);
end
iconPlay=S;

%get icon 2
D=importdata(fullfile(iconPath,'stop.jpg'));
S=double(D);
S=S-min(S(:));
S=S./max(S(:));
S(S==1)=NaN;
if size(S,3)==1
    S=repmat(S,[1 1 3]);
end
iconStop=S;

% Create a uitoggletool in the toolbar
hPlay=uitoggletool(hb,'TooltipString','Play','CData',iconPlay,'Tag','play_button','ClickedCallback',{@playFunc,{hf}});

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Time button

%get icon
D=importdata(fullfile(iconPath,'time.jpg'));
S=double(D);
S=S-min(S(:));
S=S./max(S(:));
S(S==1)=NaN;
if size(S,3)==1
    S=repmat(S,[1 1 3]);
end
% Create a uipushtool in the toolbar
uipushtool(hb,'TooltipString','Time','CData',S,'Tag','time_button','ClickedCallback',{@timeFunc,{hf}}); %,'Separator','on'

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Cycle button

%get icon
D=importdata(fullfile(iconPath,'cycle.jpg'));
S=double(D);
S=S-min(S(:));
S=S./max(S(:));
S(S==1)=NaN;
if size(S,3)==1
    S=repmat(S,[1 1 3]);
end
% Create a uitoggletool in the toolbar
hCycle=uitoggletool(hb,'TooltipString','Cycle forward-backward','CData',S,'Tag','cycle_button');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Save animation button

%get icon
D=importdata(fullfile(iconPath,'saveAnimation.jpg'));
S=double(D);
S=S-min(S(:));
S=S./max(S(:));
S(S==1)=NaN;
if size(S,3)==1
    S=repmat(S,[1 1 3]);
end
% Create a uipushtool in the toolbar
uipushtool(hb,'TooltipString','Save .gif animation','CData',S,'Tag','saveAnimation_button','ClickedCallback',{@saveAnimationFunc,{hf}}); %,'Separator','on'

%% Text fields

% title(sprintf('%6.16e ',T),'FontSize',hf.UserData.anim8.fontSize);
% title(sprintf('%f',T),'FontSize',hf.UserData.anim8.fontSize);

hTextTime = uicontrol(hf,'Style','text',...
    'String',[' Time: ',sprintf('%f',animTime(1))],...
    'Position',[0 scrollBarWidth round(hf.Position(3)) round(scrollBarWidth/2)],'BackgroundColor',[1 1 1],'HorizontalAlignment','Left'); %hf.Color

%% Set figure UserData

hf.UserData.anim8.sliderHandles={jSlider};
% hf.UserData.anim8.ButtonHandles.Sample=hSample;
hf.UserData.anim8.animStruct=animStruct;
hf.UserData.anim8.fontSize=fontSize;
% animHandles=animStruct.Handles; %Handles of objects to animate
% animProps=animStruct.Props; %Properties of objects to animate
% animSets=animStruct.Set; %Property values for to set in order to animate
% animTime=animStruct.Time;
hf.UserData.anim8.playDir=1;
hf.UserData.anim8.ButtonHandles.Play=hPlay;
hf.UserData.anim8.ButtonHandles.hCycle=hCycle;
hf.UserData.anim8.ButtonHandles.hTextTime=hTextTime;
hf.UserData.anim8.pauseTime=3/numel(animStruct.Time);%mean(diff(animStruct.Time));
hf.UserData.anim8.shiftMag=1;%ceil(numel(animStruct.Time)/20);
hf.UserData.anim8.icons.play=iconPlay;
hf.UserData.anim8.icons.stop=iconStop;

% Store current settings
hf.UserData.anim8.WindowButtonDownFcn=hf.WindowButtonDownFcn;
hf.UserData.anim8.WindowButtonUpFcn=hf.WindowButtonUpFcn;
hf.UserData.anim8.KeyPressFcn=hf.KeyPressFcn;
hf.UserData.anim8.WindowScrollWheelFcn=hf.WindowScrollWheelFcn;
hf.UserData.anim8.BusyAction=hf.BusyAction;

%Export figure widget settings
hf.UserData.efw.defaultPath=fullfile(cd,'efw');
hf.UserData.efw.imName=['figure',num2str(get(hf,'Number'))];
hf.UserData.efw.imExt='png';
hf.UserData.efw.imRes='50';
hf.UserData.efw.exportFigOpt='-nocrop';
hf.UserData.efw.exportGifOpt='1';

%% Initialize slider locations
set(jSlider,'Value',sliceIndexI);

%%
drawnow;
end

%% Scroll bar resizing

function setScrollSizeFunc(~,~,inputCell)
hf=inputCell{1};
scrollBarWidth=inputCell{2};

jSlider=inputCell{3};
javacomponent(jSlider,[0,0,round(hf.Position(3)), scrollBarWidth]);

set(hf.UserData.anim8.ButtonHandles.hTextTime,'Position',[0 scrollBarWidth round(hf.Position(3)) round(scrollBarWidth/2)]);
end

%% Help

function helpFunc(~,~)

msgText={'* Play button or press the space bar -> Start animation',...
    '* Stop button or press the space bar -> Stop animation',...
    '* Time button -> Change time stepping settings',...
    '* Cycle button -> Toggle forward / forward-backward mode',...
    '* Save button -> Export snap shorts (e.g. jpg) and animated .gif files',...
    '* Press the v key to activate the view control widget (vcw), note that vcw changes key press functions until vcw is deactivated',...
    };
helpdlg(msgText,'Help information');

end

%% play

function playFunc(~,~,inputCell)
hf=inputCell{1};
shiftMag=hf.UserData.anim8.shiftMag;

set(hf.UserData.anim8.ButtonHandles.Play,'CData',hf.UserData.anim8.icons.stop,'TooltipString','Stop');

while strcmp(get(hf.UserData.anim8.ButtonHandles.Play,'State'),'on')
    tic
    if strcmp(get(hf.UserData.anim8.ButtonHandles.hCycle,'State'),'on')

        jSlider=hf.UserData.anim8.sliderHandles{1};

        sliderValue=get(jSlider,'Value');
        sliderValueNew=sliderValue+(shiftMag*hf.UserData.anim8.playDir);

        sliderMax=get(jSlider,'Maximum');
        sliderMin=get(jSlider,'Minimum');

        if sliderValueNew<sliderMin
            hf.UserData.anim8.playDir=hf.UserData.anim8.playDir*-1;
            sliderValueNew=sliderValue+(shiftMag*hf.UserData.anim8.playDir);
        elseif sliderValueNew>sliderMax
            hf.UserData.anim8.playDir=hf.UserData.anim8.playDir*-1;
            sliderValueNew=sliderValue+(shiftMag*hf.UserData.anim8.playDir);
        end

        set(jSlider,'Value',sliderValueNew);

    else
        shiftSlider(hf.UserData.anim8.sliderHandles{1},shiftMag);
    end

    drawnow;

    t=toc;
    if (hf.UserData.anim8.pauseTime-t)>0
        pause(hf.UserData.anim8.pauseTime-t);
    end
end

set(hf.UserData.anim8.ButtonHandles.Play,'CData',hf.UserData.anim8.icons.play,'TooltipString','Play');

end

%% Time
function timeFunc(~,~,inputCell)
hf=inputCell{1};

prompt = {'Enter pause time:','Enter step size:'};
dlg_title = 'Time stepping settings';
defaultOptions = {num2str(hf.UserData.anim8.pauseTime),num2str(hf.UserData.anim8.shiftMag)};
s=40+max([cellfun(@numel,prompt) cellfun(@numel,defaultOptions)]);
Q = inputdlg(prompt,dlg_title,[1 s],defaultOptions);
if ~isempty(Q)
    if ~isempty(Q{1})
        hf.UserData.anim8.pauseTime=str2double(Q{1});
    end
    if ~isempty(Q{2})
        hf.UserData.anim8.shiftMag=str2double(Q{2});
    end
end

end

%% Save Animation

function saveAnimationFunc(~,~,inputCell)
hf=inputCell{1};
jSlider=hf.UserData.anim8.sliderHandles{1};

%%

defStruct=hf.UserData.efw;
prompt = {'Save path (leave empty to browse to desired folder instead):',...
    'Image name:','Image extension (i.e. png, jpg, bmp, or tif):',...
    'Image resolution (e.g. 120):',...
    'Extra export_fig options (comma seperated, no spaces e.g. -nocrop,-transparent,-painters):',...
    'Export gif option'};
dlg_title = 'Export Gif Widget (see: help efw and help export_fig)';
defaultOptions = {defStruct.defaultPath,defStruct.imName,defStruct.imExt,defStruct.imRes,defStruct.exportFigOpt,hf.UserData.efw.exportGifOpt};

s=25+max([cellfun(@numel,prompt) cellfun(@numel,defaultOptions)]);

Q = inputdlg(prompt,dlg_title,[1 s],defaultOptions);

if ~isempty(Q)
    if isempty(Q{1})
        Q{1}=uigetdir(defStruct.defaultPath,'Select save path');
        if Q{1}==0
            return;
        end
    end

    if isempty(Q{2})
        error('Empty input. Please enter a file name');
    end

    if ~exist(Q{1},'dir') %create output folder if it does not exist already
        mkdir(Q{1});
    end

    if isempty(Q{3})
        warning('Empty input. No image format specified, using jpg files.');
        Q{3}='jpg';
    end

    fileName=fullfile(Q{1},Q{2});
    exportGifCell{1,1}=fileName;

    stringSet=Q{3}; %The image extension
    stringNoSpaces=regexprep(stringSet,'[^\w'']',''); %Remove potential extra spaces

    if ~strcmp(stringNoSpaces(1),'-') %If first character is not '-'
        stringNoSpaces=['-',stringNoSpaces]; %Add '-' to start, e.g. 'jpg' becomes '-jpg'
    end

    %Check format validaty and keep if valid
    if any(strcmp(stringNoSpaces,{'-png','-jpg','-tiff','-bmp'}))
        exportGifCell{1,end+1}=stringNoSpaces; %Add to input list
    else
        error('Wrong image format requested');
    end

    figRes=['-r',Q{4}];
    exportGifCell{1,end+1}=figRes;

    if ~isempty(Q{5})
        stringSet=Q{5}; %The set of potentially multiple options
        stringSetSep = strsplit(stringSet,',');
        for q=1:1:numel(stringSetSep)
            stringNoSpaces=regexprep(stringSetSep{q},'[^\w'']',''); %Remove potential extra spaces
            if ~strcmp(stringNoSpaces(1),'-') %If first character is not '-'
                stringNoSpaces=['-',stringNoSpaces]; %Add '-' to start, e.g. 'jpg' becomes '-jpg'
            end
            exportGifCell{1,end+1}=stringNoSpaces; %Add to input list
        end
    end

    if ~isempty(Q{6})
        exportGifOpt=Q{6};
    end

    fileNameGif=exportGifCell{1,1};
    exportGifCellSub=exportGifCell;

    c=1;
    stepRange=1:hf.UserData.anim8.shiftMag:numel(hf.UserData.anim8.animStruct.Time);
    for q=stepRange
        set(jSlider,'Value',q);
        fileNameNow=[fileNameGif,'_',num2str(q)];
        exportGifCellSub{1,1}=fileNameNow;
        figure(hf);
        export_fig(exportGifCellSub{:});
        gifStruct.FileNames{c}=[fileNameNow,'.',exportGifCell{1,2}(2:end)];
        c=c+1;
    end

    if strcmp(exportGifOpt,'1')
        %Add reverse path
        if strcmp(get(hf.UserData.anim8.ButtonHandles.hCycle,'State'),'on')
            numFiles=numel(gifStruct.FileNames);
            if numFiles>2
                for q=(numFiles-1):-1:2
                    gifStruct.FileNames{end+1}=gifStruct.FileNames{q};
                end
            end
        end

        gifStruct.DelayTime=hf.UserData.anim8.pauseTime;
        gifStruct.FileNameGif=fileNameGif;

        exportGif(gifStruct);
    end

    %Override defaults
    defStruct.defaultPath=Q{1};
    defStruct.imName=Q{2};
    defStruct.imExt=Q{3};
    defStruct.imRes=Q{4};
    defStruct.exportFigOpt=Q{5};
    defStruct.efw.exportGifOpt=Q{6};

    hf.UserData.efw=defStruct;

end

end

%% Figure key press

function figKeyPressFunc(~,eventData,inputCell)

hf=inputCell{1}; %Figure handle

% step = 1;
% if ismember('shift', eventData.Modifier)
%     step = -step; %Make negative while shift is down
% end
%
% if ismember('control', eventData.Modifier)
%     step = step * 4; %Increase speed
% end

% Key input options
switch eventData.Key
    case {'leftarrow','downarrow'}
        shiftSlider(hf.UserData.anim8.sliderHandles{1},-1*hf.UserData.anim8.shiftMag);
    case {'rightarrow','uparrow'}
        shiftSlider(hf.UserData.anim8.sliderHandles{1},1*hf.UserData.anim8.shiftMag);
    case 'v' % Activate vcw
        set(hf.UserData.cFigure.Handles.vcw,'State','On');
    case'space'
        if strcmp(get(hf.UserData.anim8.ButtonHandles.Play,'State'),'off')
            set(hf.UserData.anim8.ButtonHandles.Play,'State','on');
            playFunc([],[],{hf});
        else
            set(hf.UserData.anim8.ButtonHandles.Play,'State','off');
        end
end

end

%% updateViewFunc

function updateViewFunc(~,~,inputCell)

hf=inputCell{1};
jSlider=inputCell{2};
animStruct=hf.UserData.anim8.animStruct;

sliderValue=get(jSlider,'Value');

T=animStruct.Time(sliderValue);
H=animStruct.Handles{sliderValue};%e.g. [hp,hp]; %Handles of objects to animate
P=animStruct.Props{sliderValue};% e.g. {'FaceColor','Vertices'}; %Properties of objects to animate
S=animStruct.Set{sliderValue};%e.g.{c(q,:),V}; %Property values for to set in order to animate

set(hf.UserData.anim8.ButtonHandles.hTextTime,'String',[' Time: ',sprintf('%f',T)],'FontSize',hf.UserData.anim8.fontSize);

for q=1:1:numel(H)
    h=H(q); % Current graphics handle
    p=P{q}; % Current graphics property
    s=S{q}; % Current property setting
    h.(p)=s;% Setting the property
end

end

%% Shift slider

function shiftSlider(jSlider,shiftMag)

sliderValue=get(jSlider,'Value');
sliderValueNew=sliderValue+shiftMag;

sliderMax=get(jSlider,'Maximum');
sliderMin=get(jSlider,'Minimum');

if sliderValueNew<sliderMin
    set(jSlider,'Value',sliderMax);
elseif sliderValueNew>sliderMax
    set(jSlider,'Value',1);
else
    set(jSlider,'Value',sliderValueNew);
end

end

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2017  Kevin Mattheus Moerman
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


function [] = defaultlinecreatefcn(varargin)
% This is a createfcn for line objects.  To ensure that all lines created
% in the future automatically use LINECMENU, follow these instructions:
%
% 1.  Put this file and LINECMENU on your path.  I.e., put this file and
%     LINECMENU in one of the folders you see when you type:  path
% 2.  In STARTUP put this line:
%
%                 set(0,'defaultlinecreat',@defaultlinecreatefcn)
%
%    If you don't already have a STARTUP file, create one and make sure it
%    is on your path.  This is the file which MATLAB runs when it first
%    starts.
%
% The next time MATLAB is started, all lines will automatically have the
% LINECMENU options.  To make the changes effective without restarting
% MATLAB, simply execute the above call to SET from the command line.

set(varargin{1},'uicontextmenu',linecmenu);


function airwayAxisMenu(command, varargin)
%"airwayAxisMenu"
%   Handles callbacks from the right click menus for all CERR axes.  Also
%   creates new right click menus in passed axes, and interfaces with the
%   ud.axisInfo field that all CERR viewer axes have.
%
%APA 5/11/2021
%
%Usage:
%   function airwayAxisMenu(command, varargin)
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR is free software: you can redistribute it and/or modify
%     it under the terms of the GNU General Public License as published by
%     the Free Software Foundation, either version 3 of the License, or
%     (at your option) any later version.
%
% CERR is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
% without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
% See the GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with CERR.  If not, see <http://www.gnu.org/licenses/>.

global airwayStateS stateS

if ishandle(command) & strcmpi(get(command, 'type'), 'axes')
    varargin{1} = command;
    command     = 'init';
elseif ~ischar(command)
    error('Invalid call to airwayAxisMenu.');
end

switch upper(command)

    case 'UPDATE_MENU'
        hMenu = gcbo;
        ud = get(hMenu, 'userdata');
        hpV = ud{1};
        elemDoseV = ud{2};
        elemRadV = ud{3};
        elemDiffDistV = ud{4};

        %Wipe out old submenus.
        kids = get(hMenu, 'children');
        delete(kids);

        %Create top level menus.
        hDose        = uimenu(hMenu, 'Label', 'dose - Gy','Callback',...
            'airwayAxisMenu(''CHANGE_MAP'')', 'userdata', {hpV, elemDoseV});
        hSize        = uimenu(hMenu, 'Label', 'min surface dist - cm', 'Callback',...
            'airwayAxisMenu(''CHANGE_MAP'')', 'userdata', {hpV, elemRadV});
        %hArea        = uimenu(hMenu, 'Label', 'Area', 'Callback',...
        %    'airwayAxisMenu(''CHANGE_MAP'')', 'userdata', {hpV, elemAreaV});
        hSizeChange  = uimenu(hMenu, 'Label', 'change in min surface distance - %','Callback',...
            'airwayAxisMenu(''CHANGE_MAP'')', 'userdata', {hpV, elemDiffDistV});
        nodeStart  = uimenu(hMenu, 'Label', 'Select starting node','Callback',...
            'airwayAxisMenu(''SELECT_START_NODE'')', 'userdata', {hpV});
        nodeStop  = uimenu(hMenu, 'Label', 'Select ending node','Callback',...
            'airwayAxisMenu(''SELECT_END_NODE'')', 'userdata', {hpV});

    case 'INIT_START_STOP_VIEW_NODES'
        hMenu = gcbo;
        %Wipe out old submenus.
        kids = get(hMenu, 'children');
        delete(kids);
        ud = get(hMenu, 'userdata');
        axisType = ud{1};
        hAxis = ud{2};
        hPlot = ud{3};
        basePt = ud{4};
%         hStartStop  = uimenu(hMenu, 'Label', 'Add nodes','Callback',...
%             'airwayAxisMenu(''ADD_START_STOP_NODES'')', 'userdata', {hAxis,hPlot,axisType});
%         hRemoveNodes  = uimenu(hMenu, 'Label', 'Remove nodes','Callback',...
%             'airwayAxisMenu(''REMOVE_START_STOP_NODES'')', 'userdata', {hAxis,hPlot,axisType});
        if strcmpi(axisType,'base')
            %             vf = ud{5};
            %             xFieldV = ud{6};
            %             yFieldV = ud{7};
            %             zUnifV = ud{8};
            %             followupPt = ud{9};
            %             minDistBaseV = ud{10};
            %             radiusDiffV = ud{11};
            %             nodeOrigDoseV = ud{12};
            nodeXyzInterpM = ud{5};
            followupPt = ud{6};
            minDistBaseV = ud{7};
            radiusDiffV = ud{8};
            nodeOrigDoseV = ud{9};
%             hCerrViewer  = uimenu(hMenu, 'Label', 'View location in viewer','Callback',...
%                 'airwayAxisMenu(''SHOW_IN_CERR_VIEWER'')', 'userdata', ...
%                 {hPlot,axisType,basePt,vf,xFieldV,yFieldV,zUnifV,followupPt});
%             hCerrViewer  = uimenu(hMenu, 'Label', 'View location in viewer','Callback',...
%                 'airwayAxisMenu(''SHOW_IN_CERR_VIEWER'')', 'userdata', ...
%                 {hPlot,axisType,basePt,nodeXyzInterpM,followupPt});
            hDose        = uimenu(hMenu, 'Label', 'dose - Gy','Callback',...
                'airwayAxisMenu(''CHANGE_MAP'')', 'userdata', {hPlot, nodeOrigDoseV});
            hSize        = uimenu(hMenu, 'Label', 'min surface dist - cm', 'Callback',...
                'airwayAxisMenu(''CHANGE_MAP'')', 'userdata', {hPlot, minDistBaseV});
            %hArea        = uimenu(hMenu, 'Label', 'Area', 'Callback',...
            %    'airwayAxisMenu(''CHANGE_MAP'')', 'userdata', {hpV, elemAreaV});
            hSizeChange  = uimenu(hMenu, 'Label', 'change in min surface distance - %','Callback',...
                'airwayAxisMenu(''CHANGE_MAP'')', 'userdata', {hPlot, radiusDiffV});
            hNoColor  = uimenu(hMenu, 'Label', 'No color','Callback',...
                'airwayAxisMenu(''CHANGE_MAP'')', 'userdata', {hPlot, [0.5,0.5,0.5]});

%             if airwayStateS.baseAddNodes
%                 set(hStartStop,'checked', 'on')
%             end
%             if airwayStateS.baseShowInCerrViewer
%                 set(hCerrViewer,'checked', 'on')
%             end
%             if airwayStateS.baseRemoveNodes
%                 set(hRemoveNodes,'checked', 'on')
%             end
        else
%             hCerrViewer  = uimenu(hMenu, 'Label', 'View location in viewer','Callback',...
%                 'airwayAxisMenu(''SHOW_IN_CERR_VIEWER'')', 'userdata', {hPlot,axisType,basePt});
%             if airwayStateS.followupAddNodes
%                 set(hStartStop,'checked', 'on')
%             end
%             if airwayStateS.followupShowInCerrViewer
%                 set(hCerrViewer,'checked', 'on')
%             end
%             if airwayStateS.followupRemoveNodes
%                 set(hRemoveNodes,'checked', 'on')
%             end
        end

    case 'ADD_START_STOP_NODES'
        disp('starting node')
        menuLabel   = get(gcbo, 'Label');
        ud       = get(gcbo, 'userdata');
        hAxis = ud{1};
        hPlot = ud{2};
        axisType = ud{3};
        if strcmpi(axisType,'base')
            airwayStateS.baseAddNodes = 1;
            airwayStateS.baseShowInCerrViewer = 0;
            airwayStateS.baseRemoveNodes = 0;
        else
            airwayStateS.followupAddNodes = 1;
            airwayStateS.followupShowInCerrViewer = 0;
            airwayStateS.followupRemoveNodes = 0;
        end
        % Callback to add nodes
        buttonDownFcn = @pickStatrStopNodes;
        set(hPlot,'ButtonDownFcn',{buttonDownFcn,hAxis,axisType});
        %hp = ud{1};
        %set(hp,'ButtonDownFcn',{@pickStatrStopNodes});

    case 'REMOVE_START_STOP_NODES'
        disp('ending node')
        ud       = get(gcbo, 'userdata');
        hAxis = ud{1};
        hPlot = ud{2};
        axisType = ud{3};
        if strcmpi(axisType,'base')
            airwayStateS.baseAddNodes = 0;
            airwayStateS.baseShowInCerrViewer = 0;
            airwayStateS.baseRemoveNodes = 1;
        else
            airwayStateS.followupAddNodes = 0;
            airwayStateS.followupShowInCerrViewer = 0;
            airwayStateS.followupRemoveNodes = 1;
        end
        % Callback to add nodes
        buttonDownFcn = @pickStatrStopNodes;
        set(hPlot,'ButtonDownFcn',{buttonDownFcn,hAxis,axisType});
        %hp = ud{1};
        %set(hp,'ButtonDownFcn',{@pickStatrStopNodes});

    case 'SHOW_IN_CERR_VIEWER'
        airwayStateS.addNodes = 0;
        airwayStateS.showInCerrViewer = 1;
        airwayStateS.removeNodes = 0;
        disp('location in viewer')
        ud       = get(gcbo, 'userdata');
        %axisType = ud{1};
        hPlot = ud{1};
        % Callback to show nodes in Viewer
        buttonDownFcn = @showNodeInCerrViewer;
        %set(hPlotBase,'ButtonDownFcn',{buttonDownFcn,axisType,vf,xFieldV,yFieldV,zUnifV,...
        %    basePt,followupPt})
        set(hPlot,'ButtonDownFcn',{buttonDownFcn,ud{2:end}})

    case 'CHANGE_MAP'
        %         stateS.viewChanged = 1;
        if isfield(airwayStateS,'hCbar') && ishandle(airwayStateS.hCbar)
            delete(airwayStateS.hCbar)
        end
        menuLabel   = get(gcbo, 'Label');
        ud       = get(gcbo, 'userdata');
        hp = ud{1};
        elemValV = ud{2};
        hAxis = get(hp,'parent');
        set(hp,'cData',elemValV)
        if length(elemValV)==3 %assume single rgb color
            title(hAxis,'Baseline')
            return;
        end
        minDist = min(elemValV);
        maxDist = max(elemValV);
        %         maxMinusMinDist = maxDist - minDist;
        cmapM = CERRColorMap('jetmod');
        %         cmapSiz = size(cmapM,1)-1;
        %         cmapIndV = round((elemValV - minDist) / maxMinusMinDist * cmapSiz) + 1;
        %         for i = 1:length(hp)
        %             if ~isnan(cmapIndV(i))
        %             set(hp,'MarkerFaceColor',[cmapM(cmapIndV(i),:)])
        %             end
        %         end
        set(hAxis,'cLim',[minDist,maxDist])
        colormap(cmapM)
        ticksV = linspace(minDist,maxDist,5);
        tickC = {};
        for i = 1:length(ticksV)
            tickC{i} = num2str(ticksV(i));
        end
        airwayStateS.hCbar = colorbar(hAxis,'Ticks',ticksV,'TickLabels',tickC,...
            'units','normalized','position',[0.45,0.7,0.02,0.2]);
        titleStr = ['Baseline (',menuLabel,')'];
        title(hAxis,titleStr)
        %hCbarLine = line('parent',hCbar,'xdata',[-5 5],...
        %    'ydata',[level level],'color','k','LineWidth',3);

end


function flag=deletemeshfile(fname)
%
% flag=deletemeshfile(fname)
%
% delete a given work mesh file under the working directory
%
% author: Qianqian Fang, <q.fang at neu.edu>
%
% input:
%     fname: specified file name (without path)
%
% output:
%     flag: not used
%
% -- this function is part of iso2mesh toolbox (http://iso2mesh.sf.net)
%

try
    if(~isempty(dir(fname)))
        delete(fname);
    end
catch
    error(['You do not have permission to delete temporary files. If you are working in a multi-user ',...
         'environment, such as Unix/Linux and there are other users using iso2mesh, ',...
         'you may need to define ISO2MESH_SESSION=''yourstring'' to make your output ',...
         'files different from others; if you do not have permission to ',mwpath(''),...
         ' as the temporary directory, you have to define ISO2MESH_TEMP=''/path/you/have/write/permission'' ',...
         'in matlab/octave base workspace.']);
end


function ids = database_ids( database, gt_set )
    index_file = fullfile(root_dir,'datasets',database, 'gt_sets',[gt_set '.txt']);
    fileID = fopen(index_file);
    ids = textscan(fileID, '%s');
    ids = ids{1};
    fclose(fileID);
end


%XOR Mapping overload