classdef (Sealed) ToggleTool < spcwidgets.AbstractWidget
    %ToggleTool   Define the ToggleTool class.
    
    %   Copyright 2009-2011 The MathWorks, Inc.
    
    properties        
        Parent;
        ClickedCallback;        
        Callback;
        OffCallback;
        OnCallback;                                      
    end
        
    properties (SetObservable, AbortSet)                  
        Tooltips = {};      
        Icons = {};
    end
    
    properties(Dependent, SetObservable, AbortSet)
        State;
        Tag;
        Visible;        
        Enable;
        Separator; 
        BusyAction;
        Interruptible; 
    end
        
    properties (SetAccess = private)
        Type = 'spcwidgets.ToggleTool';
    end
    
    properties (GetAccess = private, SetAccess = private)       
        hbutton;   
    end
    
    methods        
        function this = ToggleTool(hParent, varargin)
            %ToggleTool   Construct the ToggleTool class.
                 
            mlock;
            
            % Instantiate push button widget
            this.Parent = hParent;
            this.hbutton = builtin('uitoggletool',this.Parent);
            set(this.hbutton,'OnCallback',     @(p,e) execCallBack(this,'OnCallback'));
            set(this.hbutton,'OffCallback',    @(p,e) execCallBack(this,'OffCallback'));
            set(this.hbutton,'ClickedCallback',@(p,e) execCallBack(this,'ClickedCallback'));
            
            % Set optional property values for this object
            if ~isempty(varargin)
                set(this, varargin{:});
            end            
        end
        
        function set.Tooltips(this,val)
            % Set-function for Tooltips property
            %  - must be a string or cell-array of strings
            %  - an empty string is allowed
            
            % if a single string is passed, wrap in a cell
            if ischar(val) || (isstring(val) && isscalar(val))
                val={val};
            end
            % Validate setting
            if ~iscell(val) && ~(isstring(val) && isscalar(val))
                error(message('Spcuilib:scopes:TooltipsMustBeString'));
            end
            numTips = numel(val);
            for i=1:numTips
                if ~ischar(val{i})
                    error(message('Spcuilib:scopes:TooltipsMustBeString'));
                end
            end
            
            % Cross-check with # of icons
            %  - scalar expansion demands 1 or N icons, where N=# tooltips
            %  - empty/zero entries is treated like 1 entry
            numIcons = numel(this.Icons); %#ok<*MCSUP>
            if (numTips~=numIcons) && (numTips>1) && (numIcons>1)
                error(message('Spcuilib:scopes:NumTooltipsAndIcons',numTips,numIcons));
            end
            this.Tooltips = val;
            
            localAutoUpdate(this);
        end

        function set.Icons(this,val)
            % Set-function for Icons property
            %
            % Must be an array or cell-array of arrays
            %
            % Each icon must be either a 2-D matrix or a 3-D arrays with 3rd dim set to
            % 3, but we leave this reporting to when the icon is actually selected, so
            % the checking is not replicated here.
            
            % if a single array is passed, wrap in a cell
            if isnumeric(val)
                val={val};
            end
            % Validate setting
            if ~iscell(val)
                error(message('Spcuilib:scopes:ToggleToolInvalidIcons'));
            end
            numIcons = numel(val);
            for i=1:numIcons
                if ~isnumeric(val{i})
                    error(message('Spcuilib:scopes:ToggleToolInvalidIcons'));
                end
            end
            
            % Cross-check with # of icons
            %  - scalar expansion demands 1 or N icons, where N=# tooltips
            %  - empty/zero entries is treated like 1 entry
            numTips = numel(this.Tooltips);
            if (numTips~=numIcons) && (numTips>1) && (numIcons>1)
                error(message('Spcuilib:scopes:NumTooltipsAndIcons',numTips,numIcons));
            end
            this.Icons = val;
            
            localAutoUpdate(this);
        end  
        
        function set.State(this, v)
            set(this.hbutton,'State', v);
            localAutoUpdate(this);
        end
        
        function v = get.State(this)
            v = get(this.hbutton,'State');
        end
        
        function set.Tag(this, v)
            set(this.hbutton, 'Tag', v);
        end
        
        function v = get.Tag(this)
            v = get(this.hbutton, 'Tag');
        end
        
        function set.Visible(this, v)
            set(this.hbutton, 'Visible', v);
        end
        
        function v = get.Visible(this)
            v = get(this.hbutton, 'Visible');
        end
        
        function set.Enable(this, v)
            set(this.hbutton, 'Enable', v);
        end
        
        function v = get.Enable(this)
            v = get(this.hbutton, 'Enable');
        end
        
        function set.Separator(this, v)
            set(this.hbutton, 'Separator', v);
        end
        
        function v = get.Separator(this)
            v = get(this.hbutton, 'Separator');
        end
        
        function set.Interruptible(this, val)            
            set(this.hbutton, 'Interruptible', val);
        end     

        function val = get.Interruptible(this)            
            val = get(this.hbutton, 'Interruptible');
        end
        
        function set.BusyAction(this, val)            
            set(this.hbutton, 'BusyAction', val);
        end
        
        function val = get.BusyAction(this)            
            val = get(this.hbutton, 'BusyAction');
        end        
        
        function delete(h)
            %DELETE
            
            if ishandle(h.hbutton)
                delete(h.hbutton);
            end
            h.hbutton=[];
        end        
    end
    
    methods (Access = 'protected')
        function execCallBack(this,prop)
            % Execute callback and side-effect (local update)
            %  as dispatched from underlying uitoggletool button
            %
            % 'prop' describes one of the callback properties in the
            % widget object (either 'OnCallback', 'OffCallback', or
            % 'ClickedCallback')
            %
            localAutoUpdate(this);
            cbFcn=this.(prop);
            if ~isempty(cbFcn)
                if ischar(cbFcn) || (isstring(cbFcn) && isscalar(cbFcn))
                    % Callback string - simple eval:
                    eval(cbFcn);
                else
                    % Pass two standard args (just like HG):
                    %  handle to parent object, and
                    %  event structure (which is empty here)
                    feval(cbFcn,this,[]);
                end
            end
        end
        
        function localAutoUpdate(this)
            % Change selection based on State
            
            v = this.State;
            switch v
                case 'on'
                    select = 1;
                otherwise
                    % May only be one selection
                    select = max([1 numel(this.Icons) numel(this.Tooltips)]);
            end
            
            % Change button tooltip, implement scalar-expansion
            i=min(select, numel(this.Tooltips));
            if i>0 % if i==0, leave HG default
                set(this.hbutton,'TooltipString',this.Tooltips{i});
            end
            
            % Change button icon, implement scalar-expansion
            % Could be zero as well
            i=min(select, numel(this.Icons));
            if i>0 % if i==0, leave HG default
                set(this.hbutton,'CData',this.Icons{i});
            end
        end
    end    
end

% [EOF]
