Code covered by the BSD License  

Highlights from
Tab panel Copy

image thumbnail
from Tab panel Copy by Arturo Serrano
Creates replicas of a panel created using GUIDE that works like a tab panel.

tabpanelcopyfcn(fcn, varargin)
function varargout = tabpanelcopyfcn(fcn, varargin)
% TABPANELCOPYFCN Helper function for tabpanelcopy
%   Creates replicas of a panel created using GUIDE that works like a tab
%   panel. 
%   Handles of the reference controls in the handles struct are updated every 
%   time you change the active tab, so you can access them in the normal way.
% 
%   Steps:
%       - 1. Create a reference panel with controls with GUIDE.
%       - 2. Initialize tab panel passing the handle of the panel.
%       - 3. Add a tab when you need it.
% 
% 
% tabpanelcopyfcn ('initialize', panel);
% - Create the structure of handles.
% - Creates the controls that hide part of the controls.
% 
% [handles,tab] = tabpanelcopyfcn ('add_tab', panel, 'title', handles);
% - Replicates reference handles.
% - Adds a new button as a tab label and returns it (only needed if you plan to
%   call 'change_tab' programmatically).
% - Since handles changes, remember to refresh handles structure on the caller!
% 
% handles = tabpanelcopyfcn ('change_tab', hObject, eventdata, panel, handles);
% - "Private" function.
% - Hides visible childs of panel, and shows the ones of next active tab.
% - To change to a tab programmatically, just execute the callback on the
%   tab handler returned by 'add_tab' fcn.
% 
% tabpanelcopyfcn ('close_tab', hObject, eventdata, panel);
% - "Private" function.
% - Removes the active tab.
%
%
% Author: Arturo Serrano (arsercar@upvnet.upv.es)
% Created: Jun 04, 2009
% Updated: Jun 25, 2009

varargout = cell (1, nargout);
switch fcn
    case 'initialize'
        initialize(varargin{:});
    case 'add_tab'
        [varargout{:}] = add_tab(varargin{:});
    case 'change_tab'
        [varargout{:}] = change_tab(varargin{:});
    case 'close_tab'
        close_tab(varargin{:});
    otherwise
        error('Unrecognized command option. See HELP TABPANELCOPYFCN');
end

if nargout == 0
    clear varargout;
end

%--------------------------------------------------------------------------

function initialize (panel)

    % constants (modify if u want)
    BORDERTYPE = 'beveledout';          % border of the tabpanel       
    LINE_OFFSET  = [1 -1 -1 1];         % auxiliar control position
    PATCH_OFFSET = [1 -16 -2 15];       % auxiliar control position
    TABLIST_WIDTH = 19;                 % menu tablist
    CLOSETAB_OFFSET = [3 1 -5 -4];      % button closetab
    
    TAB_OFFSET = 10;                    % separation between tabs
    TAB_WIDTH  = 100;                   % tab width
    TAB_HEIGHT = 22;                    % tab height (default)
    LABEL_OFFSET = [-1 -1 +2 +4];       % label offset when is active
    
    % we are gonna need these later
    setappdata (panel, 'tablist_width', TABLIST_WIDTH);
    setappdata (panel, 'tab_offset', TAB_OFFSET);  
    setappdata (panel, 'tab_width', TAB_WIDTH); 
    setappdata (panel, 'tab_height', TAB_HEIGHT);
    setappdata (panel, 'label_offset', LABEL_OFFSET);
    
    % position of panel
    set (panel, 'title', [], 'bordertype', BORDERTYPE, 'visible', 'off');
    
    % creates controls to pretty the thing
    pos = get_position_pixels (panel);
    
    % tab labels (buttons actually) are showed in front of the panel. 
    % a line makes the border of the panel. 
    % a patch hides the bottom of the label.
    pos(2) = pos(2) + pos(4);       % initial y of line and patch
    pos(4) = 0;                     % initial height of line and patch
    % line makes a mistake in a pixel near the end of the line. not very
    %   annoying, it could be solved with a white-backgrounded text
    line = uicontrol ('style', 'edit', 'tag', 'border', 'units', 'normalized');
    set_position_pixels (line, pos + LINE_OFFSET)
    patch = uicontrol ('style', 'text', 'tag', 'patch', 'units', 'normalized');
    set_position_pixels (patch, pos + PATCH_OFFSET);

    % tab list menu
    callback = @(hObject,eventdata) ...
                change_tab (hObject, eventdata, panel, guidata (hObject));
    tabList = uicontrol ('style', 'popupmenu', 'tag', 'tablist', ...
                         'enable', 'off', 'string', {''}, 'callback', callback, ...
                         'units', 'normalized');
    tablistpos = get_position_pixels (tabList);
    tablistpos(1) = pos(1) + pos(3) - TABLIST_WIDTH;
    tablistpos(2) = pos(2);
    tablistpos(3) = TABLIST_WIDTH;
    set_position_pixels (tabList, tablistpos);    
    
    % close tab button (above an auxiliar popupmenu to mimic tabList look)
    callback = @(hObject,eventdata) ...
                close_tab (hObject, eventdata, panel, guidata (hObject));
	closeTabAux = uicontrol ('style', 'popupmenu', 'tag', 'closetabaux', ...
                             'enable', 'off', 'string', {''}, ...
                             'units', 'normalized');
    closetabpos = get_position_pixels (closeTabAux);
    closetabpos(1) = pos(1) + pos(3) - TABLIST_WIDTH - TABLIST_WIDTH - 2;
    closetabpos(2) = pos(2);
    closetabpos(3) = TABLIST_WIDTH;
    set_position_pixels (closeTabAux, closetabpos);    
 
    closeTab = uicontrol ('style', 'pushbutton', 'tag', 'closetab', ...
                          'string', 'x', 'fontweight', 'bold', ...
                          'enable', 'off', 'callback', callback, ...
                          'units', 'normalized');
    set_position_pixels (closeTab, closetabpos + CLOSETAB_OFFSET);

    % save data in tabs struct
    setappdata (panel, 'tabs', struct ('label', {}, 'panel', {}, ...
                                       'handles', {}, 'tags', {}));
    setappdata (panel, 'active', 0);
    setappdata (panel, 'tablist', tabList);
    setappdata (panel, 'closetab', closeTab);

    % and auxiliar controls
    setappdata (panel, 'line', line);
    setappdata (panel, 'patch', patch);

        
function [handles,new_tab] = add_tab (panel, title, handles)

    % get the number of tabs, and create a "label"
    tabs = getappdata (panel, 'tabs');
    
    callback = @(hObject,eventdata)  ...
                change_tab (hObject, eventdata, panel, guidata (hObject));
    new_tab = uicontrol ('style', 'pushbutton', 'tag', 'tab', ...
                         'enable', 'inactive', 'string', title, ...
                         'buttondownfcn', callback, ...
                         'units', 'normalized');
    set_label_position (new_tab, numel(tabs)+1, panel);
    
    % replicate reference panel    
    new_panel = copyobj (panel, get (panel, 'parent'));
    set (new_panel, 'visible', 'on');
    
    % save tags of children
    childs = findobj (get (new_panel, 'children'));
    tags = get (childs, 'tag'); 
    if numel (tags) == 1, tags = {tags}; end               % tags must be a cell
    
    % update tab list
    tabList  = getappdata (panel, 'tablist');
    closeTab = getappdata (panel, 'closetab');
    if numel (tabs) == 0
        contents = {title};
        % enable el tabList y closetab
        set (tabList, 'enable', 'on');
        set (closeTab, 'enable', 'on');
    else
        contents = get (tabList, 'string');
        contents{end+1} = title;
    end
    set (tabList, 'string', contents);    
    
    % save them in the tab structure
    tabs(end+1).label = new_tab;
    tabs(end).panel = new_panel;  
    tabs(end).handles = childs;
    tabs(end).tags = tags;
    
    setappdata (panel, 'tabs', tabs);
    
    handles = change_tab (new_tab, [], panel, handles);
    
        
function varargout = change_tab (hObject, eventdata, panel, handles) %#ok<INUSL>
% callback from tab labels or tab list: new_tab can be a button or a popmenu

    % offset of labels when they are active
    label_offset = getappdata (panel, 'label_offset');

    % tabs
    tabs = getappdata (panel, 'tabs');
    
    % set current tab off
    active = getappdata (panel, 'active');
    if active > 0        
        % change position of label (and color)
        pos = get_position_pixels (tabs(active).label);
        set_position_pixels (tabs(active).label, pos - label_offset);
        % set (tabs(active).label, 'background', 'white');
        
        % moving the active panel through the uistack doesn't seems to work...
        %   so we must hide it
        set (tabs(active).panel, 'visible', 'off');
    end
    
    % extract active tab depending on wether hObject is a button or a menu
    if strcmp (get (hObject, 'style'), 'popupmenu')
        active = get (hObject, 'value');
        new_tab = tabs(active).label;
    elseif strcmp (get (hObject, 'style'), 'pushbutton')
        active = find ([tabs.label] == hObject);
        new_tab = hObject;
        % update value of tablist
        set (getappdata (panel, 'tablist'), 'value', active);
    end
    
    % set new tab on and show it
    if new_tab
        set_position_pixels (new_tab, get_position_pixels (new_tab) + label_offset);
        set (tabs(active).panel, 'visible', 'on');
        % set (new_tab, 'background', get(0,'defaultUicontrolBackgroundColor'));
    end
    
    % update the graphic patches
    uistack ([getappdata(panel,'patch'), ...
              new_tab, getappdata(panel,'line')], ...
              'top');                              % order matters: first go top
         
    % change caller handles by children of this panel
    childs = tabs(active).handles;
    tags = tabs(active).tags;
    for itag = 1:numel (tags)
        handles.(tags{itag}) = childs(itag);
    end
    
    % update guidata
    guidata (panel, handles);

    % save data
    setappdata (panel, 'active', active);
    
    if nargout == 1
        varargout{1} = handles;
    end
    
    
function close_tab (hObject, eventdata, panel, handles) %#ok<INUSL>

    tabs = getappdata (panel, 'tabs');

    % get the active tab from tablist
    active = get (getappdata (panel, 'tablist'), 'value');
    
    % delete handles of the active tab
    delete (tabs(active).label);
    delete (tabs(active).panel);
%     delete (tabs(active).handles);
    
    % delete from tabs struct and update
    tabs(active) = [];
    setappdata (panel, 'tabs', tabs);
    setappdata (panel, 'active', 0);      % dont disable any tab in change_tab
    
    % update tab list
    tabList = getappdata (panel, 'tablist');
    contents = get (tabList, 'string');
    contents(active) = [];
    if isempty (contents), contents = {''}; end                % cant be empty
    set (tabList, 'string', contents);    

    % new active tab (last if was last, next if not)
    active = min (active, numel (tabs));
        
    % change to new tab 
    if active > 0
        
        % reorder tabs from the active to last
        for idx = active:numel (tabs)
            set_label_position (tabs(idx).label, idx, panel);
        end
  
        change_tab (tabs(active).label, eventdata, panel, handles);
    else
        % disable tablist and closetab
        set (tabList, 'enable', 'off');
        set (getappdata (panel, 'closetab'), 'enable', 'off');
    end
    
%-------------------------------------------------------------------------------

function set_label_position (label, idx, panel)

    tab_offset = getappdata (panel, 'tab_offset');
    tab_width = getappdata (panel, 'tab_width');
    tab_height = getappdata (panel, 'tab_height');
    
    % position of the labels
    pos = get_position_pixels (panel);
    
    tab_x = pos(1) + (tab_width+tab_offset)*(idx-1) + tab_offset;
    tab_y = pos(2) + pos(4) - 5;
    set_position_pixels (label, [tab_x, tab_y, tab_width, tab_height]);
                             
    % change visible property
    tablist_width = getappdata (panel, 'tablist_width');
    % tab ends beyond closetab position (a little more)
    if tab_x+tab_width < pos(1)+pos(3)-3*tablist_width
        set (label, 'visible', 'on')
    else
        set (label, 'visible', 'off');
    end

%-------------------------------------------------------------------------------

function set_position_pixels(hObject, position)

    units = get (hObject, 'units');
    set (hObject, 'units', 'pixels');
    set (hObject, 'position', position)
    set( hObject, 'units', units);


function position = get_position_pixels (hObject)
    
    units = get (hObject, 'units');
    set (hObject, 'units', 'pixels');
    position = get (hObject, 'position');
    set (hObject, 'units', units);

Contact us at files@mathworks.com