classdef ScrollPanel < hgsetget
%SCROLLPANEL A uipanel container with scrolling capabilities
%   Uipanels provide containment and groups axes and their children.  The
%   ScrollPanel provides the ability to define a scrollable area and the
%   panel is the viewport onto that area.
%
%   ScrollPanel does support the border properties of the uipanel object,
%   but in a slightly different way.  The border of the ScrollPanel does
%   not intrude upon the client area, but extends outward from it.  The
%   border of a panel is lightweight and would be obscured by the scrolling
%   objects in the scroll area.  The position of the object with the border
%   may be set using the OuterPosition property.
%
%   ScrollPanel properties:
%       Parent        - Identifies the figure or uipanel that contains the
%                       ScrollPanel object.
%       ScrollArea    - Defines the area relative the the object's position
%                       that can be scrolled through.  This area may never
%                       be less than the object's area.
%       Position      - The position of the object relative to its
%                       containing parent.  This position also serves as a
%                       viewport or window into the ScrollArea.
%       OuterPosition - The position of the object relative to its
%                       container, but including the border.
%       Backgroundcolor - The color of the viewport area.
%       Units         - The units of the ScrollPanel object as well as the
%                       ScrollArea.  The units of th me.
%       Visible       - Sets the visibility of the object.
%       ScrollMode          - Controls the appearance of scrollbars on the panel.
%                       'auto'       - automatically shows the appropriate
%                                      verticle or horizontal scrollbar if the
%                                      height or width of the ScrollArea is
%                                      greater than the height or width of the
%                                      object's position. This setting is the
%                                      default.
%                       'verticle'   - Will always display only a verticle
%                                      scrollbar.
%                       'horizontal' - will always display only a
%                                      horizontal scrollbar.
%                       'both'       - will always display both scrollbars.
%       handle        - This handle value should be used parent Handle
%                       Graphics objects to the ScrollPanel object, e.g.
%                       set(ax, 'Parent', h.handle).
%       BorderWidth, BorderPanel, Highlight Color, Shadow color - the
%                       properties of the ScrollPanel object equivalent to
%                       the ones on the uipanel object.
%   
%
%   Examples:
%
%       Create a plot larger than the viewport panels position:
%           h=ScrollPanel;
%           set(h,'Position',[.25 .25 .5 .5];
%           set(h, 'ScrollArea', [0 0 2 2])
%           ax=axes('parent',h.handle)
%           plot(ax,magic(3))
%
%       Scroll around a large image:
%           imdata = imread('ngc6543a.jpg');
%           h=ScrollPanel('Position',[.25 .25 .5 .5], ...
%                         'ScrollArea', [0 0 3 3]);
%           axes('Parent', h.handle, 'Position', [0 0 1 1]);
%           image(imdata);
%
%   An important point to note is that the ScrollPanel object has the same
%   limitations as the uipanel object in terms of clipping.  Heavyweight
%   objects such as uicontrols will not be clipped.  Since scrolling will
%   tend to move these heavyweight object outside the viewport position,
%   care much be used to achieve the desired result.
%
%   The use of OpenGL and surface objects in general is also problematic
%   since they are heavyweight.  So, it is advisable to stick to 2D without
%   transparency.
%
%   See also UIPANEL.

%   Author: Jason Kinchen, MATLAB 7.11.0.514 (R2010b)
%   Contact: jason.kinchen@gmail.com
%   Revision: 1.0 (12-Dec-2010)
%
%   Comments:
%

    properties (Hidden = true, Access = private)
        hBorderPanel            % A panel to manage the borders that won't clipped.
        hViewportPanel          % The main panel
        hScrollingPanel         % The container for the ScrollingArea
        hVScrollBar
        hHScrollBar
        scrollBarWidth = 15;
        privateMode = 'auto'    % The dependent workaround for the ScrollMode property
    end
    properties (Dependent)
        %PARENT Parent object of the SCROLLBAR.
        %   Since ScrollPanel is not an internal Handle Graphics object,
        %   parenting must be done explicitly.  Use this property to set
        %   the parent container of the ScrollPanel object.
        %
        %   See also UIPANEL.
        Parent
        
        %SCROLLAREA The position vector relative to the object's Position.
        %   The ScrollArea property of the ScrollPanel defines the region
        %   that the main viewport panel may scroll.
        %
        %   See also UIPANEL.
        ScrollArea
        
        %POSITION This position vector defines where the visible viewport
        %   of the ScrollPanel appears relative to it's parent.
        %
        %   See also UIPANEL.
        Position
        
        %OUTERPOSITION This position vector defines the postion of the
        %   including the client region and the border.  Use this property
        %   to place the object if its place in the container is more
        %   important than the size of the scrolling viewport.
        OuterPosition
        
        %BACKGROUNDCOLOR The background color of the ScrollArea using a
        %   ColorSpec.
        %
        %   See also UIPANEL.
        BackgroundColor
        
        %UNITS The units (pixels, points, characters, inches, centimeters,
        %   normalized) of both the main viewport and the ScrollArea.
        %
        %   See also UIPANEL.
        Units
        
        %VISIBLE Hides or shows the ScrollPanel without changing any other
        %   property values.
        %
        %   See also UIPANEL.
        Visible
        
        %SCROLLMODE Determines how the scrollbars appear.  Valid values are:
        %      'auto'       - automatically shows the appropriate
        %                     verticle or horizontal scrollbar if the
        %                     height or width of the ScrollArea is
        %                     greater than the height or width of the
        %                     object's position.
        %      'verticle'   - Will always display only a verticle
        %                     scrollbar.
        %      'horizontal' - will always display only a
        %                     horizontal scrollbar.
        %       'both'      - will always display both scrollbars.
        %
        %   See also UIPANEL.
        ScrollMode = 'auto';
        
        %BORDERWIDTH The width of the main viewport panel's border in
        %   pixels.
        %
        %   See also UIPANEL.
        BorderWidth = 1;
        
        %BORDERTYPE 
        %   none | {etchedin} | etchedout | beveledin | beveledout | line
        %
        %   Border of the main viewport. Used to define the panel area graphically.
        %   Etched and beveled borders provide a 3-D look. Use the HighlightColor
        %   and ShadowColor properties to specify the border color of etched and 
        %   beveled borders. A line border is 2-D. Use the ForegroundColor 
        %   property to specify its color. 
        %
        %   See also UIPANEL.
        BorderType = 'etchedin';
        
        %FOREGROUNDCOLOR Color used for the 2-D border line. A three-element 
        %   RGB vector or one of the MATLAB predefined names, specifying the 
        %   font or line color. See the ColorSpec reference page for more 
        %   information on specifying color.
        %
        %   See also UIPANEL.
        ForegroundColor = [1 1 1];
        
        %HIGHLIGHTCOLOR 3-D frame highlight color. A three-element RGB vector 
        %   or one of the MATLAB predefined names, specifying the highlight 
        %   color. See the ColorSpec reference page for more information on 
        %   specifying color.
        %
        %   See also UIPANEL, COLORSPEC.
        HighlightColor = [1 1 1];
        
        %SHADOWCOLOR 3-D frame shadow color. A three-element RGB vector or 
        %   one of the MATLAB predefined names, specifying the shadow color. 
        %   See the ColorSpec reference page for more information on specifying 
        %   color.
        %
        %   See also UIPANEL, COLORSPEC.
        ShadowColor = [.5 .5 .5];
        
    end
    properties (SetAccess = private)
        %HANDLE Since ScrollPanel is not a builtin Handle Graphics object,
        %   this property is used to directly parent object to the
        %   ScrollArea.  This handle should not be used to parent the
        %   ScrollPanel object to some other container.  Use the Parent
        %   property for that.
        %
        %   See also UIPANEL.
        handle
    end
    
    methods
        % The ScrollPanel constructor which takes parameter-value pairs.
        function obj = ScrollPanel(varargin)
            fig = gcf;
            % Detect if the Parent was passed in, otherwise use current
            % figure.
            for i = 1 : 2 : length(varargin)
                name = varargin{i};
                value = varargin{i+1};
                switch name
                    case 'Parent'
                      	fig = value;
                    break;
                    otherwise;
                end
            end
            
            % Create the objects that make up the ScrollPanel.
            obj.hBorderPanel = uipanel('Parent', fig, 'BackgroundColor', 'b',...
                                       'HandleVisibility', 'off');
                                     
            obj.hViewportPanel = uipanel('Parent', fig, 'BackgroundColor', 'r',...
                                         'BorderType', 'none',...
                                         'HandleVisibility', 'off');
            obj.Parent = fig;
            % The ScrollArea defaults to the same size as the Main Viewport
            % panel.
            obj.hScrollingPanel = uipanel('Parent', obj.hViewportPanel, ...
                                          'BorderType', 'none',...
                                          'HandleVisibility','off');
                                      
            % The slider uicontrols (scrollbars) are created invisible, but
            % are positioned in anticipation of being used.
            obj.hVScrollBar = uicontrol('Style', 'slider',...
                                       'Parent', obj.hViewportPanel,...
                                       'Units','pixels',...
                                       'Visible', 'off',...
                                       'Enable', 'off',...
                                       'HandleVisibility', 'off');

            obj.hHScrollBar = uicontrol('Style', 'slider',...
                                       'Parent', obj.hViewportPanel,...
                                       'Units','pixels',...
                                       'Position', [0 0 1 .05],...
                                       'Visible', 'off',...
                                       'Enable', 'off',...
                                       'HandleVisibility', 'off');

            % Setup the scrollbar listeners.
            addlistener(obj.hVScrollBar, 'Action', @obj.scroll);
            addlistener(obj.hHScrollBar, 'Action', @obj.scroll);
            % Setup the main viewport's size listener.  Lot's of stuff
            % needs to happen when that viewport changes.
            addlistener(obj.hViewportPanel, 'SizeChange', @obj.resize);
            
            % The ScrollingPanel is the exposed handle so that objects can
            % be children of it.
            obj.handle = obj.hScrollingPanel;
            
            % Work through the parameter-value pairs and set the initial
            % state of the properties.
            for i = 1 : 2 : length(varargin)
                name = varargin{i};
                value = varargin{i+1};
                switch name
                    case 'Units'
                        obj.Units = value;
                    case 'Position'
                        obj.Position = value;
                        drawnow;
                    case 'OuterPostion'
                        obj.ScrollArea = value;
                    case 'ScrollArea'
                        obj.ScrollArea = value;
                    case 'ScrollMode'
                        obj.ScrollMode = value;
                    case 'Visible'
                        obj.Visible = value;
                    case 'BorderWidth'
                        obj.BorderWidth = value;
                    case 'BorderType'
                        obj.BorderType = value;
                    case 'ForeGroundColor'
                        obj.ForeGroundColor = value;
                    case 'HighlightColor'
                        obj.HighlightColor = value;
                    case 'ShadowColor'
                        obj.ShadowColor = value;
                    otherwise
                        error(['Invalid property ' name]);
                end
            end
            obj.privateMode = obj.ScrollMode;
            obj.setSBPosition('both');
        end
        
        function set.Parent(obj, val)
            set(obj.hViewportPanel, 'Parent', val);
        end
        function val = get.Parent(obj)
            val = get(obj.hViewportPanel, 'Parent');
        end
        function set.ScrollArea(obj, pos)
            % If normalized, the position relative to the figure window is
            % not useful.  From the ScrollArea's perspective, it is from
            % zero -> one.
            if (strcmp(get(obj.hViewportPanel, 'Units'), 'normalized'))
                mPos = [0 0 1 1];
            else
                mPos = get(obj.hViewportPanel, 'Position');
                mPos(1:2)=[0 0];
            end

            % The ScrollArea must completely contain the main viewport
            % area.  If it is larger than the viewport, it must either be
            % inside it's position rectangle or lined up on the sides.
            newSPos(1:2:3) = limitLines(mPos(1:2:3), pos(1:2:3));
            newSPos(2:2:4) = limitLines(mPos(2:2:4), pos(2:2:4));
            if (strcmp(get(obj.hViewportPanel, 'Units'), 'pixels'))
                newSPos(1:2) = newSPos(1:2) + 1;
            end

            if pos(3) > mPos(3) || pos(4) > mPos(4)
                set(obj.hScrollingPanel, 'Position', newSPos);
                
                % In auto mode, the appropriate scrollbars must appear if the
                % length or width of the ScrollArea is greater than that of
                % the main viewport.
                if strcmp(obj.ScrollMode, 'auto')
                    if newSPos(3) > mPos(3)
                        set(obj.hHScrollBar, 'Visible', 'on', 'Enable', 'on');
                    else
                        set(obj.hHScrollBar, 'Visible', 'off', 'Enable', 'off');
                    end
                    if newSPos(4) > mPos(4)
                        set(obj.hVScrollBar, 'Visible', 'on', 'Enable', 'on');
                    else
                        set(obj.hVScrollBar, 'Visible', 'off', 'Enable', 'off');
                    end
                end
            else
                % The ScrollArea cannot be smaller than the main viewport,
                % so if we get here, the height and width is stored in the
                % position vector, the origin needs to be zero, unless the
                % units are pixels, which are 1 based.
                if strcmp(get(obj.hViewportPanel, 'Units'), 'pixels')
                    set(obj.hScrollingPanel, 'Position', [1 1 mPos(3) mPos(4)]);
                else
                    set(obj.hScrollingPanel, 'Position', [0 0 mPos(3) mPos(4)]);
                end

                %  Scrollbars need to go away if the ScrollArea and main
                %  viewport are the same size.
                if strcmp(obj.ScrollMode, 'auto')
                    set(obj.hHScrollBar, 'Visible', 'off', 'Enable', 'off');
                    set(obj.hVScrollBar, 'Visible', 'off', 'Enable', 'off');
                end
            end

            % Make sure the scrollbars are the right size and the thumbs
            % are set to the right position and width.
            obj.setSBPosition('both');                 
        end
        function pos = get.ScrollArea(obj)
            pos = get(obj.hScrollingPanel, 'Position');
        end
        function set.Position(obj, pos)
            % Go ahead and set the main viewport's position.
            drawnow;
            set(obj.hViewportPanel, 'Position', pos);
            setBorderPosition(obj);
            
            if (strcmp(get(obj.hViewportPanel, 'Units'), 'normalized'))
                pos = [0 0 1 1];
            end
            sPos = get(obj.hScrollingPanel, 'Position');
            if sPos(3) <= pos(3)
                % Don't let the width become smaller than the viewport, and
                % turn off the scrollbar if in auto mode.
                sPos(3) = max([pos(3) sPos(3)]);
                if strcmp(obj.ScrollMode, 'auto')
                    set(obj.hHScrollBar, 'Enable', 'off', 'Visible', 'off');
                end
            else
                if strcmp(obj.ScrollMode, 'auto')
                    set(obj.hHScrollBar, 'Enable', 'on', 'Visible', 'on');
                end
            end
            if sPos(4) <= pos(4)
                % Don't let the height become smaller than the viewport,
                % and turn off the scrollbar if in auto mode.
                sPos(4) = max([pos(4) sPos(4)]);
                if strcmp(obj.ScrollMode, 'auto')
                    set(obj.hVScrollBar, 'Enable', 'off', 'Visible', 'off');
                end
            else
                if strcmp(obj.ScrollMode, 'auto')
                    set(obj.hVScrollBar, 'Enable', 'on', 'Visible', 'on');
                end
            end
            set(obj.hScrollingPanel, 'Position', sPos);
            setSBPosition(obj, 'both')
        end
        
        % Set/Get the following properties on the appropriate container.
        function pos = get.Position(obj)
            pos = get(obj.hViewportPanel, 'Position');
        end
        function set.OuterPosition(obj, pos)
        % The OuterPostion extends out from the position. The borderwidth
        % is always in pixels so we do all the adjustments in pixels.
            set(obj.hBorderPanel, 'Position', pos);
            drawnow;
            % The above lines set the postion in the current units and the
            % line below gets the new positoin in pixels.
            pxPos = getpixelposition(obj.hBorderPanel);
            
            % The position of the viewport panel must be adjusted in by the
            % BorderWidth.
            pxPos = [pxPos(1) + borderAdjust(obj) ...
                     pxPos(2) + borderAdjust(obj) ...
                     pxPos(3) - 2 * borderAdjust(obj) ...
                     pxPos(4) - 2 * borderAdjust(obj)];
            drawnow;
            setpixelposition(obj.hViewportPanel, pxPos);
            obj.setSBPosition('both');
        end
        function pos = get.OuterPosition(obj)
            pos = get(obj.hBorderPanel, 'Position');
        end
        function set.BackgroundColor(obj, color)
            set(obj.hScrollingPanel, 'BackgroundColor', color);
        end
        function color = get.BackgroundColor(obj)
            color = set(obj.hScrollingPanel, 'BackgroundColor');
        end
        function set.Units(obj, units)
            set(obj.hBorderPanel', 'Units', units');
            set(obj.hViewportPanel, 'Units', units);
            set(obj.hScrollingPanel, 'Units', units);
        end
        function units = get.Units(obj)
            units = get(obj.hViewportPanel, 'Units');
        end
        function set.Visible(obj, val)
            set(obj.hViewportPanel, 'Visible', val)
        end
        function val = get.Visible(obj)
            val = get(obj.hViewportPanel, 'Visible');
        end
        function set.ScrollMode(obj, val)
            % Check that the value passed in is a valid value.
            valid = {'auto', 'verticle', 'horizontal', 'both'};
            if any(cellfun(@(x) strcmp(x,val),valid))
                % Since this is a dependent property, we need to save the
                % actual value in the private property.
                obj.privateMode = val;
                switch(val)
                    case 'auto'
                        % If auto mode is turned on, all the right things
                        % happen if we call the set method using the
                        % current value.
                        set(obj, 'ScrollArea', get(obj, 'ScrollArea'));
                    case 'verticle'
                        % Enable the verticle, disable the horizontal.
                        set(obj.hVScrollBar, 'Enable', 'on', 'Visible', 'on');
                        set(obj.hHScrollBar, 'Enable', 'off', 'Visible', 'off');
                        obj.setSBPosition('verticle');
                    case 'horizontal'
                        % Enable the horizontal, disable the verticle.
                        set(obj.hHScrollBar, 'Enable', 'on', 'Visible', 'on');
                        set(obj.hVScrollBar, 'Enable', 'off', 'Visible', 'off');
                        obj.setSBPosition('horizontal');
                    case 'both'
                        % Enable the horizontal and the verticle.
                        set(obj.hVScrollBar, 'Enable', 'on', 'Visible', 'on');
                        set(obj.hHScrollBar, 'Enable', 'on', 'Visible', 'on');
                        obj.setSBPosition('both');
                end

            else
                error('ScrollPanel:setScrollMode:badScrollModeValue',...
                      ['Bad property value ' val ' for ScrollMode.']);
            end
        end
        function val = get.ScrollMode(obj)
            val = obj.privateMode;
        end
        function set.BorderWidth(obj, val)
            set(obj.hBorderPanel, 'BorderWidth', val);
            setBorderPosition(obj);
        end
        function val = get.BorderWidth(obj)
            val = get(obj.hBorderPanel, 'BorderWidth');
        end
        function set.BorderType(obj, val)
            set(obj.hBorderPanel, 'BorderType', val);
            setBorderPosition(obj);
        end
        function val = get.BorderType(obj)
            val = get(obj.hBorderPanel, 'BorderType');
        end
        function set.ForegroundColor(obj, val)
            set(obj.hBorderPanel, 'ForegroundColor', val);
        end
        function val = get.ForegroundColor(obj)
            val = get(obj.hBorderPanel, 'ForegroundColor');
        end
        function set.HighlightColor(obj, val)
            set(obj.hBorderPanel, 'HighlightColor', val);
        end
        function val = get.HighlightColor(obj)
            val = get(obj.hBorderPanel, 'HighlightColor');
        end
        function set.ShadowColor(obj, val)
            set(obj.hBorderPanel, 'ShadowColor', val);
        end
        function val = get.ShadowColor(obj)
            val = get(obj.hBorderPanel, 'ShadowColor');
        end
        function delete(obj)
            if ishghandle(obj.hBorderPanel)
                delete(obj.hBorderPanel);
            end
            if ishghandle(obj.hViewportPanel)
                delete(obj.hViewportPanel);
            end
        end
    end
    methods (Access = protected)
        % Don't want to allow the user to call these.
        function setSBPosition(obj, scrollbar)
            % The scrollbars in in pixel units, so we need to get the
            % main viewport's position in pixels.
            pos = getpixelposition(obj.hViewportPanel);
            
            % We are doing similiar position calculations for horizontal
            % and verticle scrollbars.  The following just sets up the
            % appropriate variables.
            if strcmp(scrollbar, 'verticle') || strcmp(scrollbar, 'both')
                hScrollBar = obj.hVScrollBar;
                otherhScrollBar = obj.hHScrollBar;
                origin_i = 2;
                length_i = 4;
                scrPos = [1 + pos(3) - obj.scrollBarWidth ...
                          1 ...
                          obj.scrollBarWidth ...
                          pos(length_i)];
                bothPos = [scrPos(1) ...
                           scrPos(2) + obj.scrollBarWidth ...
                           scrPos(3) ...
                           scrPos(4) - obj.scrollBarWidth];
            else
                hScrollBar = obj.hHScrollBar;
                otherhScrollBar = obj.hVScrollBar;
                origin_i = 1;
                length_i = 3;
                scrPos = [1 ...
                          1 ...
                          pos(3)...
                          obj.scrollBarWidth];
                bothPos = [scrPos(1) ...
                           scrPos(2) ...
                           scrPos(3) - obj.scrollBarWidth ...
                           scrPos(4)];
            end

            % Use the private property scrollBarWidth and set the
            % one-based position based on the viewport's area.  The length
            % of the scrollbar is slightly shorter if the other one is
            % visible.
            if strcmp(get(otherhScrollBar, 'Visible'), 'on')
                set(hScrollBar, 'Position', bothPos);
            else
                set(hScrollBar, 'Position', scrPos);
            end
            sPos = get(obj.hScrollingPanel', 'Position');
            
            % Get the viewport panel's position to calculate the thumbsize
            % and positon of the thumb.
            if strcmp(get(obj.hViewportPanel, 'Units'), 'normalized')
                mPos = [0 0 1 1];
            else
                mPos = get(obj.hViewportPanel, 'Position');
            end
            
            %Stepsize determines the thumb size.
            step = get(hScrollBar, 'SliderStep');
            step(2) = max(0, mPos(length_i)/(sPos(length_i) - mPos(length_i)));
            set(hScrollBar, 'SliderStep', step);
            
            if mPos(origin_i) == sPos(origin_i)
                slpos = 0;
            else if mPos(origin_i) + mPos(length_i) == sPos(origin_i) + sPos(length_i)
                slpos = 1;
                else
                    slpos = min([1, (mPos(origin_i) - sPos(origin_i))/(sPos(length_i)-mPos(length_i))]);
                end
            end
            
            set(hScrollBar, 'Value', slpos);
            
            if strcmp(scrollbar, 'both')
                setSBPosition(obj, 'horizontal');
            end
        end
        function val = borderAdjust(obj)
            val = get(obj.hBorderPanel, 'BorderWidth');
            switch get(obj.hBorderPanel, 'BorderType')
                case 'etchedin'
                    val = val * 2;
                case 'etchedout'
                    val = val * 2;
                case 'none'
                    val = 0;
                otherwise
            end
        end
        function setBorderPosition(obj)
            pxPos = getpixelposition(obj.hViewportPanel);
            setpixelposition(obj.hBorderPanel, [pxPos(1) - borderAdjust(obj) ...
                                                pxPos(2) - borderAdjust(obj) ...
                                                pxPos(3) + 2*borderAdjust(obj) ...
                                                pxPos(4) + 2*borderAdjust(obj)]);
        end
        function resize(obj, ~, ~)
            % After the viewport position is set, we need to move the
            % scrollbars back to the edges.
            drawnow;
            obj.setSBPosition('both');
            setBorderPosition(obj);
        end      
        function scroll(obj, src, ~)
            % Again, normalized coordinates will need to be set manually
            % because it returns those relative to the figure window.
            if strcmp(get(obj.hViewportPanel, 'Units'), 'normalized')
                mPos = [0 0 1 1];
            else
                mPos = get(obj.hViewportPanel, 'Position');
            end
            
            sPos = get(obj.hScrollingPanel, 'Position');
            
            % Setup the variables for the appropriate scrollbar.
            if src == obj.hVScrollBar
                hScrollBar = obj.hVScrollBar;
                length_i = 4;
            else
                hScrollBar = obj.hHScrollBar;
                length_i = 3;
            end

            % Get the position of the slider, calcuate the ratio of
            % viewport to ScrollArea and set the new position of the
            % ScrollArea.
            value = get(hScrollBar, 'Value');
            pos = (sPos(length_i) - mPos(length_i))*(-value);
            if strcmp(get(obj.hScrollingPanel, 'Units'), 'pixels')
                pos = pos + 1;
            end
            if src == obj.hVScrollBar
                sPos = [sPos(1) pos sPos(3) sPos(4)];
            else
                sPos = [pos sPos(2) sPos(3) sPos(4)];
            end
            set(obj.hScrollingPanel, 'Position', sPos);
        end
    end
    methods (Hidden = true)
        function [h v] = getSBPosition(obj)
            h = get(obj.hHScrollBar, 'Position');
            v = get(obj.hVScrollBar, 'Position');
        end
    end
end

function newLine = limitLines(smallLine, largeLine)
% Limit a longer line to the endpoints of the smaller line.  In other
% words, the extents of the smaller line must be within those of the larger
% line.
    sStart = smallLine(1);
    sEnd = smallLine(1) + smallLine(2);
    
    lStart = largeLine(1);
    lEnd = largeLine(1) + largeLine(2);
    lLength = largeLine(2);

    if lStart < sStart && lEnd < sEnd
        newLine(2) = lLength;
        newLine(1) = sEnd - lLength;
    else if lStart > sStart
            newLine(1) = sStart;
            newLine(2) = lLength;
        else
            newLine = largeLine;
        end
    end
end








