Code covered by the BSD License  

Highlights from
stsbar

image thumbnail
from stsbar by Primoz Cermelj
Creates a status-bar at the bottom of a figure.

stsbar(h,varargin)
function [nsbh,nfh,Fields] = stsbar(h,varargin)
%STSBAR Creates a status-bar at the bottom of a figure
%[nsbh,nfh,Fields] = stsbar(h,varargin)
%   stsbar creates or updates a status bar that is created. It can either
%   be created on an existing figure or raised along with a newly created figure.
%
%   Syntax:
%       stsbar
%       stsbar(h)
%       stsbar(h,'Close')
%       stsbar([],'Field1',Field1,'Field2',Field2,...)
%       stsbar(h,'Field1',Field1,'Field2',Field2,...)
%       stsbar([],'Parent',fh,'Field1',Field1,'Field2',Field2,...)
%       stsbar(h,'Parent',fh,'Field1',Field1,'Field2',Field2,...)
%       stsbar([],'Title,'Test','Modal',1,fh,'Field1',Field1,'Field2',Field2,...)
%       stsbar(...,'Size',3,'Visible','on')
%       [nsb,nfh,Fields] = stsbar(...)
%
%   Description:
%       stsbar runs a demo
%       stsbar(h) only redraws status bar h
%       stsbar(h,'Close') closes (removes) status h
%       stsbar([],'Field1',Field1,'Field2',Field2,...) cretes a status-bar with several fields (see description of a field's contents below)
%
%   Field:
%       Field is a data structure that defines the type, shape, and contents of each field;
%       it has the following fields:
%           .type:      'text' (default) or 'progress'
%           .size:      a size in percent - the sum of all fields sizes
%                       must be equal to 100
%           .string:    a string to be shown in case of 'text'-typed field
%                       (defaults to '')
%           .shape:     'lowered' (default), 'normal', or 'raised'
%           .value:     an integer from -100..100 representing a progress
%                       percentage for 'progress'-typed field; if a negative value is
%                       given, the percentage number will be hidden - only the bar will
%                       be shown; defaults to 0
%           .color:     valid color specification for text or progress bar
%                       (defaults to 'k' for text and 'b' for progress)
%           .alignment: 'left' (default) or 'center' for 'text'-typed fields only
%
%   Overall properties for the status-bar:
%       'Parent':   a figure handle on which the status is to be created
%                   (if empty or not given a new figure will also be raised)
%       'Visible':  shows/hides the status bar if a figure is also created then this affect the figure too
%       'Title':    a string title that is displayed in the figure when the
%                   status bar is created in a new figure; defaults to an empty string
%       'Size':     height of the status bar; 1..12 (defaults to 1)
%       'FontSize': font size (6..18)     
%       'Modal':    1 for newly created figure to be modal and 0 to be
%                   non-modal (default)
%
%
%   EXAMPLES:   
%       stsbar
%           Runs a demo
%
%       Field1 = struct('type','text','string','Progress:','size',10,'color','k','shape','lowered');      
%       Field2 = struct('type','progress','value',10,'size',90,'color','b','shape','lowered');      
%       fh = figure;
%       [nsbh,nfh,Fields] = stsbar([],'Parent',fh,'Size',1,'Field1',Field1,'Field2',Field2,'Title','Progress');
%       set(fh,'UserData',nsbh,'ResizeFcn','stsbar(get(gcf,''UserData''))');
%           Creates a status bar with 2 fields - the "Progress:" text and
%           the progress bar. Also, the status-bar's handle is saved into
%           userdata section of the figure and an inline function is
%           assigned to figure's ResizeFcn for status-bar to resize along
%           with the figure.
%
%   See also: SBPROGRESS
%
%   Primoz Cermelj, 28.05.2004
%   (c) Primoz Cermelj, primoz.cermelj@email.si
%
%   Version: 1.0.0b
%   Last revision: 30.05.2004
%--------------------------------------------------------------------------

%----------------
% STSBAR history
%----------------
%
% [v.1.0.0] 28.05.2004
% - NEW: First release

global W
W = 400;

if nargin == 0
    % Run a demo
    Field1 = struct('type','text','size',30,'string','Demo status bar','alignment','center','color','k','shape','lowered');
    Field2 = struct('type','text','size',10,'string','Progres:','color','k','shape','lowered');
    Field3 = struct('type','progress','value',10,'size',60,'string','Second status:','color','b','shape','lowered');
    fh = figure;
    [nsbh,nfh,Fields] = stsbar([],'Parent',fh,'Size',1,'Field1',Field1,'Field2',Field2,'Field3',Field3,'Title','Status-bar demo');
    set(fh,'UserData',nsbh,'ResizeFcn','stsbar(get(gcf,''UserData''))');
    return
end

if nargin == 1
    Data = get(h,'UserData');
    [h,fh,FieldsOut] = updatesb(h,1,Data,[],Data.Fields);
    if nargout > 0
        nsbh = h;
        if nargout > 1
            nfh = fh;
            if nargout > 2
                Fields = FieldsOut;
            end
        end
    end
    return
end

%------------
% Task-bar's app data - default one or the existing one - read from an
% existing tb
%------------
if ~isempty(h) & ishandle(h)
    Data = get(h,'UserData');
    hExists = 1;
else
    hExists = 0;
    % Default values for status-bar
    Data.fhCreated = 0; % if a new figure is also created
    Data.nFields = 0;   % # of fields
    Data.hFieldObj = [];  % handle matrix; fields in rows; 3 columns (handles for text, patch, and perc. text)
    Data.hFieldFrame = [];% handle matrix for each field frame; 4 columns as there are 4 lines for each frame
    Data.fh = [];       % figure handle that status-bar is to be created on (the parent)
    Data.Fields = [];   % all the fields; Fields{i}.Type....; set later (see below)
    Data.title = '';    % title of a newly created figure
    Data.modal = 0;     % how newly created figure shows
    Data.visible = 'on';% if tb is visible
    Data.size = 1;      % size of the tb; 1..12    
    Data.fontSize = 8;  % size of the font
end

if nargin > 1
    % ---------------------
    % 'Close' might be given in the second parameter
    % ---------------------
    if strcmpi(varargin{1},'close')
        Data = get(h,'UserData');
        if ~isempty(Data) & ~isempty(Data.fh)
            if Data.fhCreated
                delete(Data.fh);
            else
                delete(h);
            end
        else
            error('Wrong h handle given');
        end        
        return
    end
end

if nargin > 2
    % ---------------------
    % Property property-value pairs and/or Fields are given - parses them
    % ---------------------
    if ischar(varargin{2}) && strcmpi(varargin{2},'remove')
        error('Remove option is not implemented yet!');
        [h,fh,FieldsOut] = removefield(h,hExists,varargin{3});
        if nargout > 0
            nsbh = h;
            if nargout > 1
                nfh = fh;
                if nargout > 2
                    Fields = FieldsOut;
                end
            end
        end
        return
    end 
    fieldNums = [];     % field-numbers given as parameters to be added and/or updated
    FieldsIn = [];      % field-contents given as parameters to be added and/or updated
    kk = 1;
    nProps = nargin - 1;
    if ~logical( 2*floor(nProps/2)==nProps ), error('Properties and/or fields must be given in pairs'), end;
    for ii=1:2:nProps
        if findstr(lower(varargin{ii}),'field')            
            fieldNums = [fieldNums parsefieldname(varargin{ii})];
            FieldsIn{kk} = varargin{ii+1};
            kk = kk + 1;
        elseif strcmpi(varargin{ii},'visible')
            Data.visible = varargin{ii+1};
        elseif strcmpi(varargin{ii},'parent')
            Data.fh = varargin{ii+1};            
        elseif strcmpi(varargin{ii},'size')
            Data.size = round(abs(varargin{ii+1}));
        elseif strcmpi(varargin{ii},'fontsize')
            Data.fontSize = round(abs(varargin{ii+1}));
        elseif strcmpi(varargin{ii},'visible')
            Data.visible = varargin{ii+1};            
        elseif strcmpi(varargin{ii},'modal')
            Data.modal = varargin{ii+1};            
        elseif strcmpi(varargin{ii},'title')
            Data.title = varargin{ii+1};            
        end
    end
end

% ---------------------
% Finally, updates/creates the status-bar
% ---------------------
[h,fh,FieldsOut] = updatesb(h,hExists,Data,fieldNums,FieldsIn);
if nargout > 0
    nsbh = h;
    if nargout > 1
        nfh = fh;
        if nargout > 2
            Fields = FieldsOut;
        end
    end
end








%**************************************************************************
%                   SUBFUNCTIONS
%**************************************************************************

%-----------------------------------------------------
function [nsbh,nfh,Fields] = updatesb(h,hExists,Data,fieldNums,FieldsIn);
% Creates/updates a status bar
border = 4;

if (Data.size < 1) | (Data.size > 12); H = 20; else;  H = round(Data.size) + 19; end;
if (Data.fontSize < 6) | (Data.size > 18); Data.fontSize = 8; end;
fhExists = 0;
if ~isempty(Data.fh) & ishandle(Data.fh)
    fhExists = 1;    
end
if ~fhExists
    Data.fh = createnewfig(H,Data.title,Data.modal,Data.visible);
    Data.fhCreated = 1;
end
%
[fPos,sbPos,fieldPos,fieldExists,Data] = preparedata(Data,H,fhExists,fieldNums,FieldsIn);
w = sbPos(3);   % overall width
%
if ~hExists     % new sb is to be created
    h = axes('Parent',Data.fh);    
    set(Data.fh,'DoubleBuffer','on');
    set(h,'Tag','sbAxes','Units','Pixels','Position',sbPos,'Box','off','Visible','off');    
    Data.hFieldFrame = zeros(Data.nFields,4);
    Data.hFieldObj = zeros(Data.nFields,3);
else            % sb is to be updated only
    set(h,'Position',sbPos);   
end
set(h,'XLim',[0 w],'YLim',[0 H-1]);
nsbh = h;
nfh = Data.fh;
%
% Set/re-set all the fields; each field has 3 handles for all of the
% possible objects: text, patch, percentage text
% and also 4 handles for its frame
for ii=1:Data.nFields
    if Data.Fields{ii}.value < -100;
        Data.Fields{ii}.value = -100;
    elseif Data.Fields{ii}.value > 100
        Data.Fields{ii}.value = 100;
    end
    al = 'left';
    doCenter = 0;
    if strcmpi(Data.Fields{ii}.alignment,'center')
        al = 'center';
        doCenter = 1;
    end        
    if ~fieldExists(ii) % create new field
        Data.hFieldFrame(ii,:) = createframe(h,Data.fh,fieldPos(ii,:),ii,H,Data.Fields{ii}.shape,'new');
        Data.hFieldObj(ii,1) = text(fieldPos(ii,1)+doCenter*(fieldPos(ii,2)-fieldPos(ii,1))/2+~doCenter*border,0.55*H,Data.Fields{ii}.string,'Color',Data.Fields{ii}.color,'Units','Pixels','FontSize',Data.fontSize,'HorizontalAlignment',al,'Visible','Off');
        len = round(fieldPos(ii,1) + abs(Data.Fields{ii}.value)*(fieldPos(ii,2)-2-fieldPos(ii,1))/100);
        Data.hFieldObj(ii,2) = patch([fieldPos(ii,1)+1; len+1; len+1; fieldPos(ii,1)+1],[1; 1; H-3; H-3],Data.Fields{ii}.color,'EdgeColor','none','Visible','off');
        Data.hFieldObj(ii,3) = text( (fieldPos(ii,1)+fieldPos(ii,2))/2,0.55*H,[num2str(abs(Data.Fields{ii}.value)) '%'],'Color',Data.Fields{ii}.color,'Units','Pixels','FontSize',Data.fontSize,'FontWeight','bold','Visible','Off','EraseMode','xor','HorizontalAlignment','Center');
    else                % update field
        Data.hFieldFrame(ii,:) = createframe(h,Data.fh,fieldPos(ii,:),ii,H,Data.Fields{ii}.shape,'update');
        set(Data.hFieldObj(ii,1),'Position',[fieldPos(ii,1)+doCenter*(fieldPos(ii,2)-fieldPos(ii,1))/2+~doCenter*border 0.55*H],'String',Data.Fields{ii}.string,'Color',Data.Fields{ii}.color,'HorizontalAlignment',al);
        len = round(fieldPos(ii,1) + abs(Data.Fields{ii}.value)*(fieldPos(ii,2)-2-fieldPos(ii,1))/100);
        set(Data.hFieldObj(ii,2),'XData',[fieldPos(ii,1)+1; len+1; len+1; fieldPos(ii,1)+1],'YData',[1; 1; H-3; H-3],'FaceColor',Data.Fields{ii}.color);
        set(Data.hFieldObj(ii,3), 'Position',[(fieldPos(ii,1)+fieldPos(ii,2))/2 0.55*H],'String',[num2str(abs(Data.Fields{ii}.value)) '%'],'Color',Data.Fields{ii}.color);     
    end
    if strcmpi(Data.Fields{ii}.type,'text') & strcmpi(Data.visible,'on')
        set(Data.hFieldObj(ii,1),'Visible','on');   
    else
        set(Data.hFieldObj(ii,1),'Visible','off');
    end
    if strcmpi(Data.Fields{ii}.type,'progress') & strcmpi(Data.visible,'on')
        set(Data.hFieldObj(ii,2),'Visible','on');
        if Data.Fields{ii}.value > 0
            set(Data.hFieldObj(ii,3),'Visible','on');
        else
            set(Data.hFieldObj(ii,3),'Visible','off');
        end
    else
        set(Data.hFieldObj(ii,2),'Visible','off');
        set(Data.hFieldObj(ii,3),'Visible','off');        
    end    
end
%-----
if Data.fhCreated
    fPos = get(Data.fh,'Position');
    fPos(4) = H;
    set(Data.fh,'Name',Data.title,'Position',fPos);
    if Data.modal
        set(Data.fh,'WindowStyle','modal');
    else
        set(Data.fh,'WindowStyle','normal');
    end
    if strcmpi(Data.visible,'on')
        set(Data.fh,'Visible','on');
    else
        set(Data.fh,'Visible','off');
    end
end
if strcmpi(Data.visible,'on')
%     set(Data.hFieldObj,'Visible','On');
    set(Data.hFieldFrame,'Visible','On');
else
%     set(Data.hFieldObj,'Visible','Off');
    set(Data.hFieldFrame,'Visible','Off');
end
%-----
% Save data to h's userdata
set(h,'UserData',Data);
Fields = Data.Fields;
drawnow;
set(h,'HandleVisibility','off');
%-----------------------------------------------------


%-----------------------------------------------------
function hFrame = createframe(h,fh,fieldPos,fieldN,H,shape,state);
% Creates a virtual panel surrounding the field starting at fieldPos(1) and
% ending end fieldPos(2) pixels. fh is the figure's handle, h is the sb's handle (axes).
% It returns a handle array designating the frame.
% See also the self-contained function BEVEL.
% pos = get(h,'Position');
% w = pos(3);
% h = pos(4);
from = fieldPos(1);
to = fieldPos(2);
col = rgb2hsv(get(fh,'Color'));
lightColor = col;   lightColor(2) = 0.5*lightColor(2);  lightColor(3) = 0.9; lightColor = hsv2rgb(lightColor);
darkColor = col;    darkColor(3) = 0.4;  darkColor = hsv2rgb(darkColor);  
if strcmpi(shape,'raised')
    tmpColor = lightColor;
    lightColor = darkColor;
    darkColor = tmpColor;
elseif strcmpi(shape,'normal')
    lightColor = 'k';
    darkColor = 'k';    
end
if strcmpi(state,'new')
    frame = zeros(4,1);    
    hFrame(1) = line([from to],[H-2 H-2],'Color',darkColor,'Visible','off');
    hFrame(2) = line([from from],[1 H-2],'Color',darkColor,'Visible','off');
    hFrame(3) = line([from+1 to-1],[1 1],'Color',lightColor,'Visible','off');
    hFrame(4) = line([to-1 to-1],[1 H-2],'Color',lightColor,'Visible','off');
else
    Data = get(h,'UserData');
    hFrame = Data.hFieldFrame(fieldN,:);
    set(hFrame(1),'XData',[from to],'YData',[H-2 H-2]);
    set(hFrame(2),'XData',[from from],'YData',[1 H-2]);
    set(hFrame(3),'XData',[from+1 to-1],'YData',[1 1]);
    set(hFrame(4),'XData',[to-1 to-1],'YData',[1 H-2]);
end
%-----------------------------------------------------



%-----------------------------------------------------
function [fPos,sbPos,fieldPos,fieldExists,DataOut] = preparedata(Data,H,fhExists,fieldNums,FieldsIn)
% Returns coordinates of an existing figure fh and for 
% existing or non-existing axis to be created/updated - axis is a basis for our status-bar.
% Also, all the fields given in input are re-set according to any existing
% fields in data and coordinates for all the fields are also returned.

DataOut = Data;
if ~(isempty(fieldNums) | isempty(FieldsIn))    % if any of the fields has been changed, added,...
    % First check
    if ~unique(fieldNums)
        error('Given fields are not unique');
    end
    % Parse all the fields, sort them and set/re-set their size
    existingNFields = DataOut.nFields;
    [dum,ind] = sort(fieldNums);
    FieldsIn = FieldsIn(ind);
    fieldNums = fieldNums(ind);
    maxFieldNum = max(existingNFields,max(fieldNums));
    fieldExists = zeros(maxFieldNum,1);
    fieldExists(1:existingNFields) = 1;
    len = length(find(fieldNums > existingNFields));
    if (existingNFields + len)~=maxFieldNum
        error('Given fields must be given in a successive way (fields can not be skipped)');
    end
    for ii=1:length(fieldNums)
        if fieldNums(ii) > existingNFields
            DataOut.Fields{ii} = struct('type','text','size',20,'string','','shape','lowered','value',0,'color','k','alignment','left');
        end
        if isfield(FieldsIn{ii},'type');        DataOut.Fields{fieldNums(ii)}.type = FieldsIn{ii}.type; end;
        if isfield(FieldsIn{ii},'size');        DataOut.Fields{fieldNums(ii)}.size = FieldsIn{ii}.size;  end;
        if isfield(FieldsIn{ii},'string');      DataOut.Fields{fieldNums(ii)}.string = FieldsIn{ii}.string;  end;
        if isfield(FieldsIn{ii},'shape');       DataOut.Fields{fieldNums(ii)}.shape = FieldsIn{ii}.shape;  end;
        if isfield(FieldsIn{ii},'value');       DataOut.Fields{fieldNums(ii)}.value = round(FieldsIn{ii}.value);  end;
        if isfield(FieldsIn{ii},'color');       DataOut.Fields{fieldNums(ii)}.color = FieldsIn{ii}.color;  end;    
        if isfield(FieldsIn{ii},'alignment');   DataOut.Fields{fieldNums(ii)}.alignment = FieldsIn{ii}.alignment;  end;    
    end
    DataOut.nFields = maxFieldNum;
    % The size of each field
    fSizes = zeros(maxFieldNum,1);
    for ii=1:maxFieldNum
        DataOut.Fields{ii}.size = round(DataOut.Fields{ii}.size);
        fSizes(ii) = DataOut.Fields{ii}.size;
    end
    s = sum(fSizes);
    if s ~= 100
        warning('The sum of all fields'' sizes is not equal to 100! Fields'' sizes were adjusted!');
        wi = fSizes/s;
        fSizes = round(100*wi);
        fSizes(end) = 100-sum(fSizes(1:end-1));
        for ii=1:maxFieldNum
            DataOut.Fields{ii}.size = fSizes(ii);
        end
    end
else
    fieldExists = ones(DataOut.nFields,1);
end
% Set sb's position
figure(Data.fh);
fUnits = get(Data.fh,'Units');
set(Data.fh,'Units','Pixels');
fPos = get(Data.fh,'Position');
set(Data.fh,'Units',fUnits);
sbPos = fPos;
sbPos(1) = 1;
sbPos(2) = 2;
sbPos(3) = fPos(3)-2;
sbPos(4) = H-1;
% Calculate each field's position (start and end x position) in pixels
fieldPos = zeros(DataOut.nFields,2);
if DataOut.nFields > 0
    w = sbPos(3);    
    fieldPos(1,1) = 1;
    fieldPos(1,2) = round(w/100*DataOut.Fields{1}.size);
    for ii=2:DataOut.nFields
        fieldPos(ii,1) = fieldPos(ii-1,2);
        fieldPos(ii,2) = fieldPos(ii,1) + round(w/100*DataOut.Fields{ii}.size);
    end
end
%-----------------------------------------------------


%-----------------------------------------------------
function [nsbh,nfh,Fields] = removefield(h,hExists,fieldStr);
if ~hExists
    error('Status bar given in h does not exist');
end
fNum = parsefieldname(fieldStr);
Data = get(h,'UserData');
if (fNum > Data.nFields) | (fNum < 1)
    error('Non-existing field number given');
end

%% Data.Fields{fNum} = [];
%?? updatesb(h,hExists,Data);
%-----------------------------------------------------


%-----------------------------------------------------
function fNum = parsefieldname(fieldStr)
fNum = [];
if ~ischar(fieldStr)
    error('Field name must be given as string');
end
ind = strfind(lower(fieldStr),'field');
if isempty(ind) | (ind~=1) | length(fieldStr) < 6
    error('Wrong field string given: field<n> expected with n being a valid field number');
end
fNum = str2num(fieldStr(6:end));
if isempty(fNum)
    error('Wrong field string given: field<n> expected with n being a valid field number');
end
fNum = round(fNum);
%-----------------------------------------------------


%-----------------------------------------------------
function fh = createnewfig(H,title,modal,visible)
global W

if isempty(title); title = ''; end;
set(0,'Units','Pixels');
scr = get(0,'ScreenSize');
fh = figure('Visible','off');
set(fh,'Units','Pixels',...
       'Tag','sbFigure',...
       'Position',[scr(3)/2-W/2 scr(4)/2-H/2 W H],...
       'MenuBar','none',...
       'Resize','off',...
       'NumberTitle','off',...
       'Name',title);
if modal
    set(fh,'WindowStyle','modal');
end
if strcmpi(visible,'on')
    set(fh,'Visible','On');
end
%-----------------------------------------------------

Contact us at files@mathworks.com