classdef TSSlider < toolpack.component.component
  % Toolstrip slider.
  %
  % Example:
  %   min = -10; max = 10; value = 5;
  %
  %   sld = toolpack.component.TSSlider;
  %   sld = toolpack.component.TSSlider(min, max);
  %   sld = toolpack.component.TSSlider(min, max, value);

  % Author(s): Bora Eryilmaz
  % Revised:
  % Copyright 2010-2015 The MathWorks, Inc.
  
  % ----------------------------------------------------------------------------
  properties (Dependent, Access = public, SetObservable, AbortSet)
    % Component's slider value (double, default = mid-point of slider range)
    Value
  end
  
  properties (Dependent, Access = public)
    % Slider's minimum value (double)
    Minimum
    % Slider's Maximum value (double)
    Maximum
    % Slider's number of values between major tick marks (double, default = 0)
    MajorTickSpacing
    % Slider's number of values between minor tick marks (double, default = 0)
    MinorTickSpacing
    % Paint status of slider's tick marks (logical, default = false)
    PaintTicks
    % Paint status of slider's labels  (logical, default = false)
    PaintLabels
    % Labels drawn at given values (cell array, default = cell(0,2))
    LabelTable
  end
  
  properties (Access = private)
    % Double
    Value_
  end
  
  % ----------------------------------------------------------------------------
  events
    % Event sent upon state changes.
    StateChanged
  end
  
  % ----------------------------------------------------------------------------
  methods
    function this = TSSlider(min, max, value)
      % Creates a toolstrip slider.
      this = this@toolpack.component.component;
      cls = 'com.mathworks.toolstrip.components.TSSlider';

      if nargin == 0
        % TSSlider();
        this.Peer = javaObjectEDT(cls);
      elseif nargin == 2
        % TSSlider(min, max)
        this.Peer = javaObjectEDT(cls, min, max);
      else
        % TSSlider(min, max, value)
        this.Peer = javaObjectEDT(cls, min, max, value);
      end
      this.Value = this.Peer.getValue;
      addStateChangedListener( this, {@LocalStateChanged, this} )
    end
    
    function value = get.Value(this)
      % GET function for Value property.
      value = this.Value_;
    end
    
    function set.Value(this, value)
      % SET function for Value property.
      if ~isnumeric(value)
        ctrlMsgUtils.error('Controllib:toolpack:InvalidPropertyValue', 'Value')
      end
      this.Value_ = value;
      % Break Java --> MCOS -->x Java loop
      if ~isequal(value, this.Peer.getValue)
        this.Peer.setValue(value);
      end
    end
    
    function value = get.Minimum(this)
      % GET function for Minimum property.
      value = this.Peer.getMinimum;
    end
    
    function set.Minimum(this, value)
      % SET function for Minimum property.
      if ~isnumeric(value)
        ctrlMsgUtils.error('Controllib:toolpack:InvalidPropertyValue', 'Minimum')
      end
      this.Peer.setMinimum(value);
    end
    
    function value = get.Maximum(this)
      % GET function for Maximum property.
      value = this.Peer.getMaximum;
    end
    
    function set.Maximum(this, value)
      % SET function for Maximum property.
      if ~isnumeric(value)
        ctrlMsgUtils.error('Controllib:toolpack:InvalidPropertyValue', 'Maximum')
      end
      this.Peer.setMaximum(value);
    end
    
    function value = get.MajorTickSpacing(this)
      % GET function for MajorTickSpacing property.
      value = this.Peer.getMajorTickSpacing;
    end
    
    function set.MajorTickSpacing(this, value)
      % SET function for MajorTickSpacing property.
      if ~isnumeric(value)
        ctrlMsgUtils.error('Controllib:toolpack:InvalidPropertyValue', 'MajorTickSpacing')
      end
      this.Peer.setMajorTickSpacing(value);
    end
    
    function value = get.MinorTickSpacing(this)
      % GET function for MinorTickSpacing property.
      value = this.Peer.getMinorTickSpacing;
    end
    
    function set.MinorTickSpacing(this, value)
      % SET function for MinorTickSpacing property.
      if ~isnumeric(value)
        ctrlMsgUtils.error('Controllib:toolpack:InvalidPropertyValue', 'MinorTickSpacing')
      end
      this.Peer.setMinorTickSpacing(value);
    end
    
    function value = get.PaintTicks(this)
      % GET function for PaintTicks property.
      value = this.Peer.getPaintTicks;
    end
    
    function set.PaintTicks(this, value)
      % SET function for PaintTicks property.
      if ~islogical(value)
        ctrlMsgUtils.error('Controllib:toolpack:InvalidPropertyValue', 'PaintTicks')
      end
      this.Peer.setPaintTicks(value);
    end
    
    function value = get.PaintLabels(this)
      % GET function for PaintLabels property.
      value = this.Peer.getPaintLabels;
    end
    
    function set.PaintLabels(this, value)
      % SET function for PaintLabels property.
      if ~islogical(value)
        ctrlMsgUtils.error('Controllib:toolpack:InvalidPropertyValue', 'PaintLabels')
      end
      this.Peer.setPaintLabels(value);
    end
    
    function value = get.LabelTable(this)
      % GET function for LabelTable property.
      labeltable = this.Peer.getLabelTable;
      if isempty(labeltable)
        value = cell(0,2);
        return
      end
      
      % Non-empty label table.
      n = labeltable.size;
      value = cell(n,2);
      keys = labeltable.keys;
      k = 1;
      while keys.hasMoreElements
        key = keys.nextElement;
        value{k,1} = double(key);
        value{k,2} = char( labeltable.get( java.lang.Integer(key) ).getText );
        k = k + 1;
      end
    end
    
    function set.LabelTable(this, value)
      % SET function for LabelTable property.
      if isempty(value)
        this.Peer.setLabelTable([]);
        return
      end
      
      % Reset label text
      labeltable = this.Peer.createStandardLabels(this.MajorTickSpacing);
      keys = labeltable.keys;
      while keys.hasMoreElements
          key = keys.nextElement;
          labeltable.get(java.lang.Integer(key)).setText('');
      end

      % Update label text from provided values
      for k = 1:size(value,1)
          lbl = labeltable.get(java.lang.Integer(value{k,1}));
          if ~isempty(lbl)
              lbl.setText(value{k,2});
          end
      end
      this.Peer.setLabelTable(labeltable);
    end
  end
  
  methods (Access = private)
    function addStateChangedListener(this, fcn)
      % Do not modify. Use as is to prevent Java memory leaks.
      L = addlistener(this.Peer, 'StateChanged', fcn);
      this.Listeners = [this.Listeners; L];
    end
  end
end

% ------------------------------------------------------------------------------
function LocalStateChanged(~,~,obj)
obj.Value = obj.Peer.getValue;
obj.notify('StateChanged')
end
