Code covered by the BSD License  

Highlights from
IMAGEVIEWER

image thumbnail

IMAGEVIEWER

by

 

14 Nov 2006 (Updated )

A GUI for viewing and interactively exploring image files.

Editor's Notes:

This file was selected as MATLAB Central Pick of the Week

ImageViewer
classdef ImageViewer < handle
    %IMAGEVIEWER  Interactively pan and zoom images on the computer.
    %   IMAGEVIEWER starts a GUI for opening image files and interactive
    %   panning and zooming.
    %
    %   IMAGEVIEWER(DIRNAME) starts the GUI with DIRNAME as the initial
    %   directory.
    %
    %   The GUI allows you to navigate through your computer and quickly view
    %   image files. It also allows you to interactively explore your images by
    %   panning (clicking and drag), zooming (right-click and drag), and
    %   centering view (double-clicking).
    %
    
    % Copyright 2006-2012 The MathWorks, Inc.
    
    % VERSIONS:
    %   v1.0 - first version. (was pictureviewer.m)
    %   v1.1 - convert to nested functions. (Nov 13, 2006)
    %   v1.2 - bug fix to deal with different image types (Nov 15, 2006)
    %   v1.3 - bug fix for centering, sorting of image files.
    %          add resize window feature.
    %          change FINDOBJ to FINDALL (Nov 16, 2006)
    %   v1.4 - cosmetic changes to the GUI.
    %          a better timer management. (Dec 2, 2006)
    %   v1.5 - added scroll wheel zoom functionality. This only works with
    %          R2007a or later. (Jan 10, 2007)
    %   v1.51 - add white background under red zoom line (June 2007)
    %   v2.0 - Implemented in MATLAB Classes. (Aug 2012)
    %
    % Jiro Doke
    % April 2006
    
    properties (Hidden, Access=protected)
        handles
    end
    
    properties (Constant, Hidden, Access=protected)
        closedHandPointer = [
            NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN
            NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN
            NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN
            NaN,NaN,NaN,NaN,2  ,2  ,NaN,2  ,2  ,NaN,2  ,2  ,NaN,NaN,NaN,NaN
            NaN,NaN,NaN,2  ,1  ,1  ,2  ,1  ,1  ,2  ,1  ,1  ,2  ,2  ,NaN,NaN
            NaN,NaN,2  ,1  ,2  ,2  ,1  ,2  ,2  ,1  ,2  ,2  ,1  ,1  ,2  ,NaN
            NaN,NaN,2  ,1  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,1  ,2  ,1  ,2
            NaN,NaN,NaN,2  ,1  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,1  ,2
            NaN,NaN,2  ,1  ,1  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,1  ,2
            NaN,2  ,1  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,1  ,2
            NaN,2  ,1  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,1  ,2
            NaN,2  ,1  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,1  ,2  ,NaN
            NaN,NaN,2  ,1  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,1  ,2  ,NaN
            NaN,NaN,NaN,2  ,1  ,2  ,2  ,2  ,2  ,2  ,2  ,2  ,1  ,2  ,NaN,NaN
            NaN,NaN,NaN,NaN,2  ,1  ,2  ,2  ,2  ,2  ,2  ,2  ,1  ,2  ,NaN,NaN
            NaN,NaN,NaN,NaN,2  ,1  ,2  ,2  ,2  ,2  ,2  ,2  ,1  ,2  ,NaN,NaN
            ];
        
        zoomInOutPointer = [
            NaN,NaN,NaN,2  ,2  ,NaN,NaN,NaN,NaN,NaN,NaN,2  ,2  ,NaN,NaN,NaN
            NaN,NaN,2  ,1  ,1  ,2  ,NaN,NaN,NaN,NaN,2  ,1  ,1  ,2  ,NaN,NaN
            NaN,2  ,1  ,1  ,1  ,1  ,2  ,NaN,NaN,2  ,2  ,1  ,1  ,2  ,2  ,NaN
            2  ,1  ,1  ,1  ,1  ,1  ,1  ,2  ,2  ,1  ,1  ,1  ,1  ,1  ,1  ,2
            2  ,1  ,2  ,1  ,1  ,2  ,1  ,2  ,2  ,1  ,1  ,1  ,1  ,1  ,1  ,2
            NaN,2  ,2  ,1  ,1  ,2  ,2  ,NaN,NaN,2  ,2  ,1  ,1  ,2  ,2  ,NaN
            NaN,NaN,2  ,1  ,1  ,2  ,NaN,NaN,NaN,NaN,2  ,1  ,1  ,2  ,NaN,NaN
            NaN,NaN,NaN,2  ,2  ,NaN,NaN,NaN,NaN,NaN,NaN,2  ,2  ,NaN,NaN,NaN
            NaN,NaN,NaN,2  ,2  ,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN
            NaN,NaN,2  ,1  ,1  ,2  ,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN
            NaN,2  ,2  ,1  ,1  ,2  ,2  ,NaN,NaN,2  ,2  ,2  ,2  ,2  ,2  ,NaN
            2  ,1  ,2  ,1  ,1  ,2  ,1  ,2  ,2  ,1  ,1  ,1  ,1  ,1  ,1  ,2
            2  ,1  ,1  ,1  ,1  ,1  ,1  ,2  ,2  ,1  ,1  ,1  ,1  ,1  ,1  ,2
            NaN,2  ,1  ,1  ,1  ,1  ,2  ,NaN,NaN,2  ,2  ,2  ,2  ,2  ,2  ,NaN
            NaN,NaN,2  ,1  ,1  ,2  ,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN
            NaN,NaN,NaN,2  ,2  ,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN,NaN
            ];
        
    end
    
    methods
        function obj = ImageViewer(dirname)
            
            verNumber = '2.0';
            
            if nargin == 0
                dirname = pwd;
            else
                if ~ischar(dirname) || ~isdir(dirname)
                    error('Invalid input argument.\n  Syntax: %s(DIRNAME)', upper(mfilename));
                end
            end
            
            delete(findall(0, 'type', 'figure', 'tag', 'ImageViewer'));
            
            bgcolor1 = [.8 .8 .8];
            txtcolor = [.3 .3 .3];
            
            figH = figure(...
                'units'                         , 'normalized', ...
                'busyaction'                    , 'queue', ...
                'color'                         , bgcolor1, ...
                'deletefcn'                     , @obj.stopTimerFcn, ...
                'doublebuffer'                  , 'on', ...
                'handlevisibility'              , 'callback', ...
                'interruptible'                 , 'on', ...
                'menubar'                       , 'none', ...
                'name'                          , upper(mfilename), ...
                'numbertitle'                   , 'off', ...
                'outerposition'                 , [.1 .1 .8 .8], ...
                'resize'                        , 'on', ...
                'resizefcn'                     , @obj.resizeFcn, ...
                'tag'                           , 'ImageViewer', ...
                'toolbar'                       , 'none', ...
                'visible'                       , 'off', ...
                'defaultaxesunits'              , 'pixels', ...
                'defaulttextfontunits'          , 'pixels', ...
                'defaulttextfontname'           , 'Verdana', ...
                'defaulttextfontsize'           , 12, ...
                'defaultuicontrolunits'         , 'pixels', ...
                'defaultuicontrolfontunits'     , 'pixels', ...
                'defaultuicontrolfontsize'      , 10, ...
                'defaultuicontrolfontname'      , 'Verdana', ...
                'defaultuicontrolinterruptible' , 'off');
            
            try
                if ~verLessThan('matlab', '7.4')
                    set(figH, 'windowscrollwheelfcn', @obj.scrollWheelFcn);
                end
            catch %#ok<CTCH>
                % verLessThan was introduced in v7.4
                % if there is an error, that means it is less than 7.4
            end
            
            uph(1) = uipanel(...
                'units'                     , 'pixels', ...
                'backgroundcolor'           , bgcolor1, ...
                'parent'                    , figH, ...
                'bordertype'                , 'beveledin', ...
                'tag'                       , 'versionPanel');
            uicontrol(...
                'style'                     , 'text', ...
                'foregroundcolor'           , txtcolor, ...
                'backgroundcolor'           , bgcolor1, ...
                'horizontalalignment'       , 'center', ...
                'fontweight'                , 'bold', ...
                'string'                    , sprintf('Ver %s', verNumber), ...
                'parent'                    , uph(1), ...
                'tag'                       , 'versionText');
            uph(2) = uipanel(...
                'units'                     , 'pixels', ...
                'backgroundcolor'           , bgcolor1, ...
                'parent'                    , figH, ...
                'bordertype'                , 'beveledin', ...
                'tag'                       , 'statusPanel');
            uicontrol(...
                'style'                     , 'text', ...
                'foregroundcolor'           , txtcolor, ...
                'backgroundcolor'           , bgcolor1, ...
                'horizontalalignment'       , 'right', ...
                'fontweight'                , 'bold', ...
                'string'                    , '', ...
                'parent'                    , uph(2), ...
                'tag'                       , 'statusText');
            uph(3) = uipanel(...
                'units'                     , 'pixels', ...
                'bordertype'                , 'etchedout', ...
                'fontname'                  , 'Verdana', ...
                'fontweight'                , 'bold', ...
                'title'                     , 'View', ...
                'titleposition'             , 'centertop', ...
                'backgroundcolor'           , bgcolor1, ...
                'parent'                    , figH, ...
                'tag'                       , 'frame1');
            uicontrol(...
                'style'                     , 'text', ...
                'string'                    , '', ...
                'horizontalalignment'       , 'center', ...
                'fontweight'                , 'bold', ...
                'fontsize'                  , 12, ...
                'backgroundcolor'           , bgcolor1, ...
                'foregroundcolor'           , [.2, .2, .2], ...
                'parent'                    , uph(3), ...
                'tag'                       , 'ZoomCaptionText');
            uicontrol(...
                'style'                     , 'pushbutton', ...
                'string'                    , 'Full', ...
                'fontweight'                , 'bold', ...
                'callback'                  , @obj.resetView, ...
                'enable'                    , 'off', ...
                'tooltipstring'             , 'View full image', ...
                'parent'                    , uph(3), ...
                'tag'                       , 'ResetViewBtn1');
            uicontrol(...
                'style'                     , 'pushbutton', ...
                'string'                    , '100%', ...
                'fontweight'                , 'bold', ...
                'callback'                  , @obj.resetView, ...
                'enable'                    , 'off', ...
                'tooltipstring'             , 'View true size', ...
                'parent'                    , uph(3), ...
                'tag'                       , 'ResetViewBtn2');
            uicontrol(...
                'style'                     , 'pushbutton', ...
                'string'                    , 'Help', ...
                'fontweight'                , 'bold', ...
                'callback'                  , @helpBtnCallback, ...
                'enable'                    , 'on', ...
                'parent'                    , figH, ...
                'tag'                       , 'HelpBtn');
            uicontrol(...
                'style'                     , 'togglebutton', ...
                'string'                    , 'File Info', ...
                'fontweight'                , 'bold', ...
                'callback'                  , @obj.fileInfoBtnCallback, ...
                'enable'                    , 'off', ...
                'parent'                    , figH, ...
                'tag'                       , 'FileInfoBtn');
            uph(4) = uipanel(...
                'units'                     , 'pixels', ...
                'backgroundcolor'           , bgcolor1, ...
                'parent'                    , figH, ...
                'bordertype'                , 'beveledin', ...
                'tag'                       , 'CurrentDirectoryPanel');
            uicontrol(...
                'style'                     , 'text', ...
                'backgroundcolor'           , bgcolor1, ...
                'horizontalalignment'       , 'left', ...
                'parent'                    , uph(4), ...
                'tag'                       , 'CurrentDirectoryEdit');
            uicontrol(...
                'style'                     , 'pushbutton', ...
                'string'                    , '...', ...
                'backgroundcolor'           , bgcolor1, ...
                'callback'                  , @obj.chooseDirectoryCallback, ...
                'parent'                    , figH, ...
                'tag'                       , 'ChooseDirectoryBtn');
            
            % Up Directory Icon
            map = [0 0 0;bgcolor1;1 1 0;1 1 1];
            upDirIcon = uint8([
                1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
                1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
                1 1 1 0 0 0 0 0 1 1 1 1 1 1 1 1
                1 1 0 3 2 3 2 3 0 1 1 1 1 1 1 1
                1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
                1 0 2 3 2 3 2 3 2 3 2 3 2 3 2 0
                1 0 3 2 3 2 0 2 3 2 3 2 3 2 3 0
                1 0 2 3 2 0 0 0 2 3 2 3 2 3 2 0
                1 0 3 2 0 0 0 0 0 2 3 2 3 2 3 0
                1 0 2 3 2 3 0 3 2 3 2 3 2 3 2 0
                1 0 3 2 3 2 0 2 3 2 3 2 3 2 3 0
                1 0 2 3 2 3 0 0 0 0 0 3 2 3 2 0
                1 0 3 2 3 2 3 2 3 2 3 2 3 2 3 0
                1 0 2 3 2 3 2 3 2 3 2 3 2 3 2 0
                1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
                1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
                ]);
            rgbIcon = ind2rgb(upDirIcon, map);
            
            uicontrol(...
                'style'                     , 'pushbutton', ...
                'cdata'                     , rgbIcon, ...
                'backgroundcolor'           , bgcolor1, ...
                'callback'                  , @obj.upDirectoryCallback, ...
                'parent'                    , figH, ...
                'tag'                       , 'UpDirectoryBtn');
            uicontrol(...
                'style'                     , 'listbox', ...
                'backgroundcolor'           , 'white', ...
                'callback'                  , @obj.fileListBoxCallback, ...
                'fontname'                  , 'FixedWidth', ...
                'parent'                    , figH, ...
                'tag'                       , 'FileListBox');
            
            uph(5) = uipanel(...
                'units'                     , 'pixels', ...
                'bordertype'                , 'etchedout', ...
                'backgroundcolor'           , bgcolor1, ...
                'fontname'                  , 'Verdana', ...
                'fontsize'                  , 10, ...
                'fontweight'                , 'bold', ...
                'title'                     , 'Preview', ...
                'titleposition'             , 'centertop', ...
                'parent'                    , figH, ...
                'tag'                       , 'PreviewImagePanel');
            
            axes(...
                'handlevisibility'          , 'callback', ...
                'parent'                    , uph(5), ...
                'visible'                   , 'off', ...
                'tag'                       , 'PreviewImageAxes');
            
            axes(...
                'box'                       , 'on', ...
                'xtick'                     , [], ...
                'ytick'                     , [], ...
                'handlevisibility'          , 'callback', ...
                'parent'                    , figH, ...
                'tag'                       , 'ImageAxes');
            
            % for drawing the zoom line
            axH = axes(...
                'units'                     , 'normalized', ...
                'position'                  , [0 0 1 1], ...
                'box'                       , 'on', ...
                'hittest'                   , 'off', ...
                'xlim'                      , [0 1], ...
                'xtick'                     , [], ...
                'ylim'                      , [0 1], ...
                'ytick'                     , [], ...
                'handlevisibility'          , 'callback', ...
                'visible'                   , 'off', ...
                'parent'                    , figH, ...
                'tag'                       , 'InvisibleAxes');
            
            line(NaN, NaN, ...
                'linestyle'                 , '-', ...
                'linewidth'                 , 3, ...
                'color'                     , 'w', ...
                'parent'                    , axH, ...
                'tag'                       , 'ZoomLine');
            line(NaN, NaN, ...
                'linestyle'                 , '--', ...
                'linewidth'                 , 2, ...
                'color'                     , 'r', ...
                'parent'                    , axH, ...
                'tag'                       , 'ZoomLine');
            
            uicontrol(...
                'style'                     , 'listbox', ...
                'backgroundcolor'           , [.75, .75, 1], ...
                'fontname'                  , 'FixedWidth', ...
                'fontsize'                  , 14, ...
                'visible'                   , 'off', ...
                'enable'                    , 'inactive', ...
                'interruptible'             , 'off', ...
                'busyaction'                , 'queue', ...
                'horizontalalignment'       , 'left', ...
                'parent'                    , figH, ...
                'tag'                       , 'MessageTextBox');
            
            obj.handles             = guihandles(figH);
            obj.handles.figPos      = [];
            obj.handles.axPos       = [];
            obj.handles.lastDir     = dirname;
            obj.handles.ImX         = [];
            obj.handles.tm          = timer(...
                'name'            , 'image preview timer', ...
                'executionmode'   , 'fixedspacing', ...
                'objectvisibility', 'off', ...
                'taskstoexecute'  , inf, ...
                'period'          , 0.001, ...
                'startdelay'      , 3, ...
                'timerfcn'        , @obj.getPreviewImages);
            
            resizeFcn(obj);
            
            % Show initial directory
            showDirectory(obj);
            
            set(figH, 'visible', 'on');
            
        end
        %--------------------------------------------------------------------------
        % resizeFcn
        %   This resizes the figure window appropriately
        %--------------------------------------------------------------------------
        function resizeFcn(obj, varargin)
            
            set(obj.handles.ImageViewer, 'units', 'pixels');
            figPos = get(obj.handles.ImageViewer, 'position');
            
            % figure can't be too small or off the screen
            if figPos(3) < 750 || figPos(4) < 500
                figPos(3) = max([750 figPos(3)]);
                figPos(4) = max([500 figPos(4)]);
                screenSize = get(0, 'screensize');
                if figPos(1)+figPos(3) > screenSize(3)
                    figPos(1) = screenSize(3) - figPos(3) - 50;
                end
                if figPos(2)+figPos(4) > screenSize(4)
                    figPos(2) = screenSize(4) - figPos(4) - 50;
                end
                
                set(obj.handles.ImageViewer, 'position', figPos);
                
            end
            
            set(obj.handles.versionPanel         , 'position', [1, 1, 100, 25]);
            set(obj.handles.versionText          , 'position', [2, 2, 96, 20]);
            set(obj.handles.statusPanel          , 'position', [102, 1, figPos(3)-102, 25]);
            set(obj.handles.statusText           , 'position', [2, 2, figPos(3)-107, 20]);
            set(obj.handles.frame1               , 'position', [figPos(3)-115, figPos(4)-55, 110, 53]);
            set(obj.handles.ZoomCaptionText      , 'position', [5, 22, 100, 17]);
            set(obj.handles.ResetViewBtn1        , 'position', [5, 2, 47, 20]);
            set(obj.handles.ResetViewBtn2        , 'position', [55, 2, 47, 20]);
            set(obj.handles.HelpBtn              , 'position', [figPos(3)-220, figPos(4)-28, 100, 20]);
            set(obj.handles.FileInfoBtn          , 'position', [figPos(3)-220, figPos(4)-50, 100, 20]);
            set(obj.handles.CurrentDirectoryPanel, 'position', [20, figPos(4)-30, 215, 20]);
            set(obj.handles.CurrentDirectoryEdit , 'position', [1, 1, 213, 18]);
            set(obj.handles.ChooseDirectoryBtn   , 'position', [237, figPos(4)-30, 20, 20]);
            set(obj.handles.UpDirectoryBtn       , 'position', [259, figPos(4)-30, 20, 20]);
            set(obj.handles.FileListBox          , 'position', [20, 270, 260, figPos(4)-310]);
            set(obj.handles.PreviewImagePanel    , 'position', [20, 40, 260, 220]);
            set(obj.handles.PreviewImageAxes     , 'position', [5, 5, 245, 190]);
            set(obj.handles.ImageAxes            , 'position', [300, 40, figPos(3)-310, figPos(4)-120]);
            axPos = get(obj.handles.ImageAxes    , 'position');
            
            textBoxDim  = [400, 200];
            rightMargin = figPos(3)-(axPos(1)+axPos(3));
            topMargin   = figPos(4)-(axPos(2)+axPos(4));
            set(obj.handles.MessageTextBox      , 'position', [figPos(3)-rightMargin-textBoxDim(1), ...
                figPos(4)-topMargin-textBoxDim(2), ...
                textBoxDim]);
            obj.handles.figPos = figPos;
            obj.handles.axPos  = axPos;
            
            titleStr = get(get(obj.handles.ImageAxes, 'title'), 'string');
            if ~isempty(titleStr)
                % resize image as well
                loadImage(obj, titleStr);
            end
            
        end
        
        
        %--------------------------------------------------------------------------
        % fileInfoBtnCallback
        %   This displays the file info of the image that's displayed
        %--------------------------------------------------------------------------
        function fileInfoBtnCallback(obj, varargin)
            
            hObj = varargin{1};
            
            if get(hObj, 'value')
                
                % First 9 fields of IMFINFO are always the same
                fnames      = fieldnames(obj.handles.iminfo); fnames = fnames(1:9);
                vals        = struct2cell(obj.handles.iminfo); vals = vals(1:9);
                
                % Only show file name (not full path)
                [p, n, e]   = fileparts(vals{1}); %#ok<ASGLU>
                vals{1}     = [n e];
                sID         = cellfun('isclass', vals, 'char');
                dID         = cellfun('isclass', vals, 'double');
                fmt         = cell(2, 9);
                fmt(1, :)   = repmat({'%15s: '}, 1, 9);
                fmt(2, sID) = repmat({'%s|'}, 1, length(find(sID)));
                fmt(2, dID) = repmat({'%d|'}, 1, length(find(dID)));
                tmp         = [fnames(:),vals(:)]';
                str         = sprintf([fmt{:}], tmp{:});
                set(obj.handles.MessageTextBox, 'string', str, 'visible', 'on');
                
            else
                set(obj.handles.MessageTextBox, 'visible', 'off');
                
            end
            
        end
        
        %--------------------------------------------------------------------------
        % showDirectory
        %   This function shows a list of image files in the directory
        %--------------------------------------------------------------------------
        function showDirectory(obj, dirname)
            
            % Reset settings and images
            stopTimer(obj);
            cla(obj.handles.PreviewImageAxes);
            axis(obj.handles.PreviewImageAxes, 'normal');
            clearImageAxes(obj);
            %----------------------------------------------------------------------
            
            if nargin == 2
                obj.handles.lastDir = dirname;
            else
                if isempty(obj.handles.lastDir)
                    obj.handles.lastDir = pwd;
                end
            end
            
            set(obj.handles.CurrentDirectoryEdit, 'string', ...
                fixLongDirName(obj.handles.lastDir), ...
                'tooltipstring', obj.handles.lastDir);
            
            % Get image formats
            imf  = imformats;
            exts = lower([imf.ext]);
            exts_str = sprintf('%s|', exts{:}); exts_str(end) = '';
            d = dir(obj.handles.lastDir);

            filenames = sort({d(~[d.isdir]).name});
            filenames_L = lower(filenames);
            
            % Find all the image files
            imagefiles_idx = regexp(filenames_L, sprintf('[^ \f\n\r\t\v.]+\\.(%s)',exts_str));
            imagefiles = filenames(~cellfun(@isempty, imagefiles_idx));

            dirnames = sort({d([d.isdir]).name});
            dirnames(ismember(dirnames, {'.', '..'})) = '';            
            
            if isempty(imagefiles)
                obj.handles.imageID = [];
                obj.handles.imageNames = {};
                obj.handles.imagePreviews = {};
                runTimer = false;
            else
                obj.handles.imageID = 1:length(imagefiles);
                obj.handles.imageNames = imagefiles;
                obj.handles.imagePreviews = cell(1,length(imagefiles));
                runTimer = true;
            end
            
            if isempty(dirnames)
                n = imagefiles;
            else
                dirnames = strcat(repmat({'['}, 1, length(dirnames)), dirnames, repmat({']'}, 1, length(dirnames)));
                n = [dirnames, imagefiles];
                
                obj.handles.imageID = obj.handles.imageID + length(dirnames);
            end
            set(obj.handles.FileListBox, 'string', n, 'value', 1);
            
            if runTimer
                startTimer(obj);
            end
            
            if ~isempty(obj.handles.imageID)
                set(obj.handles.ImageViewer, 'selectiontype', 'normal');
                set(obj.handles.FileListBox, 'value', obj.handles.imageID(1));
                fileListBoxCallback(obj);
            end
            
        end
        
        %--------------------------------------------------------------------------
        % getPreviewImages
        %   This is the TimerFcn for the preview timer object
        %--------------------------------------------------------------------------
        function getPreviewImages(obj, varargin)
            
            try
                
                id = find(cellfun('isempty', obj.handles.imagePreviews));
                
                if ~isempty(id)
                    set(obj.handles.statusText, 'string', ...
                        sprintf('Generating Thumbnails ... %d of %d', ...
                        length(obj.handles.imagePreviews)-length(id)+1, ...
                        length(obj.handles.imagePreviews)));
                    drawnow;
                    obj.handles.imagePreviews{id(1)} = ...
                        getPreviewImageData(obj, ...
                        fullfile(get(obj.handles.CurrentDirectoryEdit, 'tooltipstring'), ...
                        obj.handles.imageNames{id(1)}));
                    
                else % All previews are generated. Stop timer
                    set(obj.handles.statusText, 'string', '');
                    stopTimer(obj);
                    
                end
                
            catch %#ok<CTCH>
                
            end
            
        end
        
        %--------------------------------------------------------------------------
        % getPreviewImageData
        %   This reads in image file for thumbnails
        %--------------------------------------------------------------------------
        function x = getPreviewImageData(obj, filename)
            
            x = readImageFileFcn(obj, filename);
            if ~isnan(x)
                sz = size(x);
                r = [200, 260] ./ sz(1:2);
                
                % Crude IMRESIZE (non-toolbox)
                xd = round(linspace(1,sz(1), round(sz(1) * min(r))));
                yd = round(linspace(1,sz(2), round(sz(2) * min(r))));
                x = x(xd, yd, :);
            end
            
        end
        
        %--------------------------------------------------------------------------
        % fileListBoxCallback
        %   This gets called when an entry is selected in the file list box
        %--------------------------------------------------------------------------
        function fileListBoxCallback(obj, hObj, varargin)
            
            if nargin == 1
                hObj = obj.handles.FileListBox;
            end
            stopTimer(obj);
            val = get(hObj, 'value');
            str = cellstr(get(hObj, 'string'));
            
            if ~isempty(str)
                
                switch get(obj.handles.ImageViewer, 'selectiontype')
                    case 'normal'   % single click - show preview
                        
                        if str{val}(1) == '[' && str{val}(end) == ']'
                            cla(obj.handles.PreviewImageAxes);
                            axis(obj.handles.PreviewImageAxes, 'normal');
                            
                        else
                            id = find(obj.handles.imageID == val);
                            if isempty(obj.handles.imagePreviews{id});
                                obj.handles.imagePreviews{id} = ...
                                    getPreviewImageData(obj, ...
                                    fullfile(...
                                    get(obj.handles.CurrentDirectoryEdit, 'tooltipstring'), ...
                                    str{val}));
                            end
                            
                            if ~isnan(obj.handles.imagePreviews{id})
                                image(obj.handles.imagePreviews{id}, ...
                                    'parent', obj.handles.PreviewImageAxes, ...
                                    'hittest', 'off');
                                set(obj.handles.PreviewImagePanel, 'buttondownfcn', @previewImageClickFcn);
                                
                            else % unable to load image
                                cla(obj.handles.PreviewImageAxes);
                                set(obj.handles.PreviewImagePanel, 'buttondownfcn', '');
                                text(0.5, 0.5, 'Can''t Load Image', ...
                                    'parent', obj.handles.PreviewImageAxes, ...
                                    'horizontalalignment', 'center', ...
                                    'verticalalignment', 'middle');
                                set(obj.handles.PreviewImageAxes, 'xlim', [0 1], 'ylim', [0 1]);
                                
                            end
                            
                            axis(obj.handles.PreviewImageAxes, 'equal');
                            set(obj.handles.PreviewImageAxes, 'visible', 'off');
                            
                        end
                        startTimer(obj);
                        
                    case 'open'   % double click - open image and display
                        
                        if str{val}(1) == '[' && str{val}(end) == ']'
                            dirname = get(obj.handles.CurrentDirectoryEdit, 'tooltipstring');
                            newdirname = fullfile(dirname, str{val}(2:end-1));
                            showDirectory(obj, newdirname)
                            
                        else
                            obj.handles.ImX = [];
                            loadImage(obj, fullfile(get(obj.handles.CurrentDirectoryEdit, 'tooltipstring'), str{val}));
                            
                            startTimer(obj);
                        end
                end
                
            end
            
            %----------------------------------------------------------------------
            % previewImageClickFcn
            %   This loads the image when the thumbnail is double-clicked
            %----------------------------------------------------------------------
            function previewImageClickFcn(varargin)
                
                switch get(obj.handles.ImageViewer, 'selectiontype')
                    
                    case 'open'   % double-click
                        
                        stopTimer(obj);
                        
                        obj.handles.ImX = [];
                        loadImage(obj, fullfile(get(obj.handles.CurrentDirectoryEdit, 'tooltipstring'), str{val}));
                        
                        startTimer(obj);
                        
                end
            end
            
        end
        
        %--------------------------------------------------------------------------
        % chooseDirectoryCallback
        %   This opens a directory selector
        %--------------------------------------------------------------------------
        function chooseDirectoryCallback(obj, varargin)
            
            stopTimer(obj);
            dirname = uigetdir(get(obj.handles.CurrentDirectoryEdit, 'tooltipstring'), ...
                'Choose Directory');
            if ischar(dirname)
                showDirectory(obj, dirname)
            end
            
        end
        
        %--------------------------------------------------------------------------
        % upDirectoryCallback
        %   This moves up the current directory
        %--------------------------------------------------------------------------
        function upDirectoryCallback(obj, varargin)
            
            stopTimer(obj);
            dirname = get(obj.handles.CurrentDirectoryEdit, 'tooltipstring');
            dirname2 = fileparts(dirname);
            if ~isequal(dirname, dirname2)
                showDirectory(obj, dirname2)
            end
            
        end
        
        %--------------------------------------------------------------------------
        % resetView
        %   This resets the view to "Full" or "100%" magnification
        %--------------------------------------------------------------------------
        function resetView(obj, varargin)
            
            hObj = varargin{1};
            stopTimer(obj);
            set(obj.handles.MessageTextBox, 'visible', 'off');
            set(obj.handles.FileInfoBtn, 'value', false);
            
            switch get(hObj, 'string')
                case 'Full'
                    xlimit = obj.handles.xlimFull;
                    ylimit = obj.handles.ylimFull;
                    
                case '100%'
                    xlimit = obj.handles.xlim100;
                    ylimit = obj.handles.ylim100;
            end
            
            xl = xlim(obj.handles.ImageAxes); xd = (xlimit - xl)/10;
            yl = ylim(obj.handles.ImageAxes); yd = (ylimit - yl)/10;
            
            % Restore only if needed
            if ~(isequal(xd, [0 0]) && isequal(yd, [0 0]))
                
                set(obj.handles.statusText, 'string', 'Restoring View...');
                
                % Animate with "good" speed
                for id = [1, 4, 6.5, 7.8, 8.5, 9, 9.3, 9.6, 9.8, 10]
                    
                    set(obj.handles.ImageAxes, ...
                        'xlim'                , xl + xd * id, ...
                        'ylim'                , yl + yd * id, ...
                        'cameraviewanglemode' , 'auto', ...
                        'dataaspectratiomode' , 'auto', ...
                        'plotboxaspectratio'  , obj.handles.pbar);
                    set(obj.handles.ZoomCaptionText, 'string', sprintf('%d %%', ...
                        round(diff(obj.handles.xlim100)/diff(xl + xd * id)*100)));
                    
                    pause(0.01);
                end
                
                set(obj.handles.statusText, 'string', '');
                
            end
            
            startTimer(obj);
            
        end
        
        %--------------------------------------------------------------------------
        % loadImage
        %   This loads the selected image and displays it
        %--------------------------------------------------------------------------
        function loadImage(obj, filename)
            
            try
                if isempty(obj.handles.ImX)
                    clearImageAxes(obj);
                    set(obj.handles.statusText, 'string', 'Loading Image...');
                    drawnow;
                    [obj.handles.ImX, obj.handles.iminfo] = readImageFileFcn(obj, filename);
                end
                
                if ~isnan(obj.handles.ImX)
                    iH = image(obj.handles.ImX, 'parent', obj.handles.ImageAxes);
                    set(iH, 'hittest', 'off');
                    axis(obj.handles.ImageAxes, 'equal');
                    set(obj.handles.ImageAxes, ...
                        'box'             , 'on', ...
                        'xtick'           , [], ...
                        'ytick'           , [], ...
                        'buttondownfcn'   , @obj.winBtnDownFcn, ...
                        'interruptible'   , 'off', ...
                        'busyaction'      , 'queue', ...
                        'handlevisibility', 'callback');
                    set(obj.handles.ResetViewBtn1, 'enable', 'on');
                    set(obj.handles.ResetViewBtn2, 'enable', 'on');
                    set(obj.handles.FileInfoBtn  , 'enable', 'on');
                    set(get(obj.handles.ImageAxes, 'title'), ...
                        'string'      , sprintf('%s', filename), ...
                        'interpreter' , 'none');
                    obj.handles.pbar     = get(obj.handles.ImageAxes, 'plotboxaspectratio');
                    obj.handles.xlimFull = get(obj.handles.ImageAxes, 'xlim');
                    obj.handles.ylimFull = get(obj.handles.ImageAxes, 'ylim');
                    
                    % If image is small, show at 100% size
                    sz              = size(obj.handles.ImX);
                    obj.handles.xlim100 = sz(2)/2 + [-1, 1] * obj.handles.axPos(3)/2;
                    obj.handles.ylim100 = sz(1)/2 + [-1, 1] * obj.handles.axPos(4)/2;
                    if all(obj.handles.axPos(3:4) > sz([2 1]))
                        set(obj.handles.ImageAxes, ...
                            'xlim'                , obj.handles.xlim100, ...
                            'ylim'                , obj.handles.ylim100, ...
                            'cameraviewanglemode' , 'auto', ...
                            'dataaspectratiomode' , 'auto', ...
                            'plotboxaspectratio'  , obj.handles.pbar);
                        set(obj.handles.ZoomCaptionText, 'string', '100 %');
                        
                    else
                        set(obj.handles.ZoomCaptionText, 'string', sprintf('%d %%', ...
                            round(diff(obj.handles.xlim100)/diff(obj.handles.xlimFull)*100)));
                    end
                end
                
            catch ME
                errordlg({'Could not open image file', ME.message}, 'Error');
                clearImageAxes(obj);
                
            end
            
            set(obj.handles.statusText, 'string', '');
            
        end
        
        %--------------------------------------------------------------------------
        % clearImageAxes
        %   This clears the image axis
        %--------------------------------------------------------------------------
        function clearImageAxes(obj)
            
            cla(obj.handles.ImageAxes);
            axis(obj.handles.ImageAxes, 'normal');
            set(get(obj.handles.ImageAxes, 'title') , 'string'        , '');
            set(obj.handles.ImageAxes               , 'buttondownfcn' , '');
            set(obj.handles.ResetViewBtn1           , 'enable'        , 'off');
            set(obj.handles.ResetViewBtn2           , 'enable'        , 'off');
            set(obj.handles.FileInfoBtn             , 'enable'        , 'off', ...
                'value'         , false);
            set(obj.handles.ZoomCaptionText         , 'string'        , '');
            set(obj.handles.MessageTextBox          , 'visible'       , 'off');
            obj.handles.ImX = [];
            
        end
        
        %--------------------------------------------------------------------------
        % winBtnDownFcn
        %   This is called when the mouse is clicked in one of the axes
        %   NORMAL clicks will start panning mode.
        %   ALT clicks will start zooming mode.
        %   OPEN clicks will center the view.
        %--------------------------------------------------------------------------
        function winBtnDownFcn(obj, hObj, varargin)
            
            stopTimer(obj);
            set(obj.handles.MessageTextBox, 'visible', 'off');
            set(obj.handles.FileInfoBtn, 'value', false);
            
            switch get(obj.handles.ImageViewer, 'selectiontype')
                case 'normal'
                    % Start panning mode
                    
                    xy = get(hObj, 'currentpoint');
                    set(obj.handles.ImageViewer, ...
                        'pointer'               , 'custom', ...
                        'pointershapecdata'     , ImageViewer.closedHandPointer, ...
                        'windowbuttonmotionfcn' , @winBtnMotionFcn);
                    set(obj.handles.ImageViewer, 'windowbuttonupfcn', @obj.winBtnUpFcn);
                    
                case 'alt'
                    % Start zooming mode
                    
                    xl = get(hObj, 'xlim'); midX = mean(xl); rngXhalf = diff(xl) / 2;
                    yl = get(hObj, 'ylim'); midY = mean(yl); rngYhalf = diff(yl) / 2;
                    curPt  = mean(get(hObj, 'currentpoint'));curPt = curPt(1:2);
                    curPt2 = (curPt-[midX, midY]) ./ [rngXhalf, rngYhalf];
                    curPt  = [curPt; curPt];
                    curPt2 = [-(1+curPt2).*[rngXhalf, rngYhalf];...
                        (1-curPt2).*[rngXhalf, rngYhalf]];
                    initPt = get(obj.handles.ImageViewer, 'currentpoint');
                    set(obj.handles.statusText, 'string', 'Zooming...');
                    set(obj.handles.ImageViewer, ...
                        'pointer'               , 'custom', ...
                        'pointershapecdata'     , ImageViewer.zoomInOutPointer, ...
                        'windowbuttonmotionfcn' , @zoomMotionFcn);
                    set(obj.handles.ImageViewer, 'windowbuttonupfcn', @obj.winBtnUpFcn);
                    
                case 'open'
                    % Center the view
                    
                    set(obj.handles.ImageViewer, 'windowbuttonupfcn', @obj.winBtnUpFcn);
                    
                    % Get current units
                    un    = get(0, 'units');
                    set(0, 'units', 'pixels');
                    pt2   = get(0, 'pointerlocation');
                    pt    = get(hObj, 'currentpoint');
                    axPos = get(hObj, 'position');
                    xl = get(hObj, 'xlim'); midX = mean(xl);
                    yl = get(hObj, 'ylim'); midY = mean(yl);
                    
                    % update figure position in case it was moved
                    obj.handles.figPos = get(obj.handles.ImageViewer, 'position');
                    
                    % get distance between cursor and center of axes
                    d = norm(pt2 - (obj.handles.figPos(1:2) + axPos(1:2) + axPos(3:4)/2));
                    
                    if d > 2  % center only if distance is at least 2 pixels away
                        ld = (mean(pt(:, 1:2)) - [midX, midY]) / 10;
                        pd = ((obj.handles.figPos(1:2) + axPos(1:2) + axPos(3:4) / 2) - pt2) / 10;
                        
                        set(obj.handles.statusText, 'string', 'Centering...');
                        
                        % Animate with "good" speed
                        for id = [1, 4, 6.5, 7.8, 8.5, 9, 9.3, 9.6, 9.8, 10]
                            
                            % Set axes limits and automatically set ticks
                            % Set aspect ratios
                            set(hObj, ...
                                'xlim'                , xl + id * ld(1), ...
                                'ylim'                , yl + id * ld(2), ...
                                'cameraviewanglemode' , 'auto', ...
                                'dataaspectratiomode' , 'auto', ...
                                'plotboxaspectratio'  , obj.handles.pbar);
                            
                            % Move pointer with limits
                            set(0, 'pointerlocation', pt2 + id * pd);
                            
                            pause(0.01);
                        end
                        
                    end
                    
                    % Reset UNITS
                    set(0, 'units', un);
                    
            end
            
            %----------------------------------------------------------------------
            % winBtnMotionFcn (nested under winBtnDownFcn)
            %   This function is called when click-n-drag (panning) is happening
            %----------------------------------------------------------------------
            function winBtnMotionFcn(varargin)
                
                pt = get(obj.handles.ImageAxes, 'currentpoint');
                
                % Update axes limits and automatically set ticks
                % Set aspect ratios
                set(obj.handles.ImageAxes, ...
                    'xlim', get(obj.handles.ImageAxes, 'xlim') + (xy(1,1)-(pt(1,1)+pt(2,1))/2), ...
                    'ylim', get(obj.handles.ImageAxes, 'ylim') + (xy(1,2)-(pt(1,2)+pt(2,2))/2), ...
                    'cameraviewanglemode' , 'auto', ...
                    'dataaspectratiomode' , 'auto', ...
                    'plotboxaspectratio'  , obj.handles.pbar);
                set(obj.handles.statusText, 'string', 'Panning...');
                
            end
            
            
            %----------------------------------------------------------------------
            % zoomMotionFcn (nested under winBtnDownFcn)
            %   This performs the click-n-drag zooming function. The pointer
            %   location relative to the initial point determines the amount of
            %   zoom (in or out).
            %----------------------------------------------------------------------
            function zoomMotionFcn(hObj, varargin)
                
                % Power law allows for the inverse to work:
                %      C^(x) * C^(-x) = 1
                % Choose C to get "appropriate" zoom factor
                C                   = 50;
                pt                  = get(hObj, 'currentpoint');
                r                   = C ^ ((initPt(2) - pt(2)) / obj.handles.figPos(4));
                newLimSpan          = r * curPt2; dTemp = diff(newLimSpan);
                pt(1)               = initPt(1);
                
                % Determine new limits based on r
                lims                = curPt + newLimSpan;
                
                % Update axes limits and automatically set ticks
                % Set aspect ratios
                set(obj.handles.ImageAxes, ...
                    'xlim'                , lims(:,1), ...
                    'ylim'                , lims(:,2), ...
                    'cameraviewanglemode' , 'auto', ...
                    'dataaspectratiomode' , 'auto', ...
                    'plotboxaspectratio'  , obj.handles.pbar);
                
                % Update zoom indicator line
                set(obj.handles.ZoomLine, ...
                    'xdata', [initPt(1), pt(1)]/obj.handles.figPos(3), ...
                    'ydata', [initPt(2), pt(2)]/obj.handles.figPos(4));
                set(obj.handles.ZoomCaptionText, 'string', sprintf('%d %%', ...
                    round(diff(obj.handles.xlim100)/dTemp(1)*100)));
                
            end
            
        end
        
        
        function scrollWheelFcn(obj, varargin)
            
            stopTimer(obj);
            
            if ~isempty(obj.handles.ImX)
                
                % Power law allows for the inverse to work:
                %      C^(x) * C^(-x) = 1
                % Choose C to get "appropriate" zoom factor
                C                   = 1.02;
                
                xl = get(obj.handles.ImageAxes, 'xlim'); midX = mean(xl); rngXhalf = diff(xl) / 2;
                yl = get(obj.handles.ImageAxes, 'ylim'); midY = mean(yl); rngYhalf = diff(yl) / 2;
                curPt  = mean(get(obj.handles.ImageAxes, 'currentpoint'));curPt = curPt(1:2);
                curPt2 = (curPt-[midX, midY]) ./ [rngXhalf, rngYhalf];
                curPt  = [curPt; curPt];
                curPt2 = [-(1+curPt2).*[rngXhalf, rngYhalf];...
                    (1-curPt2).*[rngXhalf, rngYhalf]];
                
                edata = varargin{2};
                r = C^(edata.VerticalScrollCount*edata.VerticalScrollAmount);
                newLimSpan          = r * curPt2;dTemp = diff(newLimSpan);
                
                % Determine new limits based on r
                lims                = curPt + newLimSpan;
                
                % Update axes limits and automatically set ticks
                % Set aspect ratios
                set(obj.handles.ImageAxes, ...
                    'xlim'                , lims(:,1), ...
                    'ylim'                , lims(:,2), ...
                    'cameraviewanglemode' , 'auto', ...
                    'dataaspectratiomode' , 'auto', ...
                    'plotboxaspectratio'  , obj.handles.pbar);
                
                % Update zoom value
                set(obj.handles.ZoomCaptionText, 'string', sprintf('%d %%', ...
                    round(diff(obj.handles.xlim100)/dTemp(1)*100)));
                
            end
            
            startTimer(obj);
            
        end
        
        %--------------------------------------------------------------------------
        % winBtnUpFcn
        %   This is called when the mouse is released
        %--------------------------------------------------------------------------
        function winBtnUpFcn(obj, hObj, varargin)
            
            set(hObj, ...
                'pointer'               , 'arrow', ...
                'windowbuttonmotionfcn' , '');
            set(obj.handles.statusText, 'string', '');
            set(obj.handles.ZoomLine, 'xdata', NaN, 'ydata', NaN);
            set(obj.handles.ImageViewer, 'windowbuttonupfcn', '');
            
            startTimer(obj);
            
        end
        
        
        %--------------------------------------------------------------------------
        % startTimer
        %   This starts the timer. If the timer object is invalid, it creates a new
        %   one.
        %--------------------------------------------------------------------------
        function startTimer(obj)
            
            try
                
                if ~strcmpi(obj.handles.tm.Running, 'on');
                    start(obj.handles.tm);
                end
                
            catch %#ok<CTCH>
                
                obj.handles.tm          = timer(...
                    'name'            , 'image preview timer', ...
                    'executionmode'   , 'fixedspacing', ...
                    'objectvisibility', 'off', ...
                    'taskstoexecute'  , inf, ...
                    'period'          , 0.001, ...
                    'startdelay'      , 3, ...
                    'timerfcn'        , @obj.getPreviewImages);
                start(obj.handles.tm);
                
            end
            
        end
        
        
        %--------------------------------------------------------------------------
        % stopTimerFcn
        %   This gets called when the figure is closed.
        %--------------------------------------------------------------------------
        function stopTimerFcn(obj, varargin)
            
            stop(obj.handles.tm);
            % wait until timer stops
            while ~strcmpi(obj.handles.tm.Running, 'off')
                drawnow;
            end
            delete(obj.handles.tm);
            
        end
        
        
        %--------------------------------------------------------------------------
        % stopTimer
        %   This stops the timer object used for generating image previews
        %--------------------------------------------------------------------------
        function stopTimer(obj, varargin)
            
            stop(obj.handles.tm);
            
            % wait until timer stops
            while ~strcmpi(obj.handles.tm.Running, 'off')
                drawnow;
            end
            
            set(obj.handles.statusText, 'string', '');
            
        end
        
        
        %--------------------------------------------------------------------------
        % readImageFileFcn
        %   This function reads in the image file and converts to TRUECOLOR
        %--------------------------------------------------------------------------
        function [x, info] = readImageFileFcn(obj, filename)
            
            try
                [x, mp] = imread(filename);
                info = imfinfo(filename);
                info = info(1);
                
                switch info.ColorType
                    case 'grayscale'
                        switch class(x)
                            case 'logical'
                                x = uint8(x);
                                mp = [0 0 0;1 1 1];
                                
                            case 'uint8'
                                mp = gray(256);
                                
                            case 'uint16'
                                mp = gray(2^16);
                                
                            case {'double','single'}
                                cmapsz = size(get(obj.handles.ImageViewer, 'Colormap'), 1);
                                mp = gray(cmapsz);
                                
                            case 'int16'
                                x = double(x)+2^15;
                                x = uint16((x-min(x(:)))/(max(x(:))-min(x(:)))*(2^16));
                                mp = gray(2^16);
                                
                            otherwise
                                cmapsz = size(get(obj.handles.ImageViewer, 'Colormap'), 1);
                                mp = gray(cmapsz);
                        end
                        x = ind2rgb(x, mp);
                        
                    case 'indexed'
                        if isempty(mp)
                            mp = info.Colormap;
                        end
                        x = ind2rgb(x, mp);
                        
                    otherwise
                end
                
            catch %#ok<CTCH>
                x = NaN;
                info = [];
                
            end
        end
        
    end
end



%--------------------------------------------------------------------------
% fixLongDirName
%   This truncates the directory string if it is too long to display
%--------------------------------------------------------------------------
function newdirname = fixLongDirName(dirname)
% Modify string for long directory names
if length(dirname) > 20
    [tmp1, tmp2] = strtok(dirname, filesep); %#ok<ASGLU>
    if isempty(tmp2)
        newdirname = dirname;
        
    else
        % in case the directory name starts with a file separator.
        id = strfind(dirname, tmp2);
        tmp1 = dirname(1:id(1));
        [p, tmp2] = fileparts(dirname);
        if strcmp(tmp1, p) || isempty(tmp2)
            newdirname = dirname;
            
        else
            newdirname = fullfile(tmp1, '...', tmp2);
            tmp3 = '';
            while length(newdirname) < 20
                tmp3 = fullfile(tmp2, tmp3);
                [p, tmp2] = fileparts(p);
                if strcmp(tmp1, p)  % reach root directory
                    newdirname = dirname;
                    %break; % it will break because dirname is longer than 30 chars
                    
                else
                    newdirname = fullfile(tmp1, '...', tmp2, tmp3);
                    
                end
            end
        end
    end
else
    newdirname = dirname;
end

end


%--------------------------------------------------------------------------
% helpBtnCallback
%   This opens up a help dialog box
%--------------------------------------------------------------------------
function helpBtnCallback(varargin)

helpdlg({...
    'Navigate through directories using the list box on the left.', ...
    'Single-click to see the preview.', ...
    'Double-click (list box OR preview image) to open and display image.', ...
    '', 'Click and drag to pan the image.', ...
    'Right click and drag to zoom. (or scroll wheel if R2007a or later)', ...
    'Double-click to center view.', ...
    '''Full'' displays the whole image.', ...
    '''100%'' displays the image at the true resolution.', ...
    '''File Info'' displays the current image file info.'}, 'Help');

end

Contact us