classdef subplot_grid < handle
  
  properties
    version = '6.0'
    hgVersion;
    current_axes = [1,1]
    titles = struct('template',struct('valid',0,'hax',[],'htxt',[],'txtbox_sizes',0,'ratios',[]),...
      'title',struct('valid',0,'hax',[],'htxt',[],'txtbox_sizes',0,'ratios',[]),...
      'subtitle',struct('valid',0,'hax',[],'htxt',[],'txtbox_sizes',0,'ratios',[]),...
      'rowtitles_left',struct('valid',0,'hax',[],'htxt',[],'txtbox_sizes',0,'ratios',[]),...
      'rowtitles_right',struct('valid',0,'hax',[],'htxt',[],'txtbox_sizes',0,'ratios',[]),...
      'coltitles_top',struct('valid',0,'hax',[],'htxt',[],'txtbox_sizes',0,'ratios',[]),...
      'coltitles_bottom',struct('valid',0,'hax',[],'htxt',[],'txtbox_sizes',0,'ratios',[]));
    nof_rows
    nof_columns
    mergelist
    hfig
    hax
    Iax
    Rax
    Cax
    hlegend
    subplotzoom_enabled
    interaxes_selection_mods = struct('LineWidth',2,...
      'LineStyle','-')
    legend_data
    legend_data_defaults = struct('valid',false,...
      'location','nei',...
      'tag',[],...
      'buffer_px',2*ones(1,4),...
      'print_legend_title',true);
    
    loose_inset_px = 10*ones(1,4);
    subplotzoom_data
    hcolorbar;
    zoomlinklist;
    zoom_button_size_x = 10;
    zoom_button_size_y = 10;
    zoomed
    hidden_axes
    hidden_axes_manual
    interaxes_data = struct([]);
    interaxes_supported_types = {'line';
      'image';
      'surface';
      };
    viewer = struct('nof_minor_rows',0,...
      'starting_index',0);
    loose_inset_px_default = 5*ones(1,4)
    in_panel = false;
    panel_padding = 2; % pixels
    hparent
    pos_parent_in_figure = [0 0 1 1];
    subplotzoom_init_state = 1;
    
    colorbar_data
    colorbar_data_defaults = struct('valid',false,...
      'location','eeo',...
      'tag',[],...
      'cmap','auto',...
      'shortdim_px',10,...
      'buffer_px',2*ones(1,4),...
      'scaled','auto',...
      'datalim','auto');
    
  end
  
  methods
    
    function this = subplot_grid(varargin)
      
      %
      % ****************************************************************
      % *** THIS VERSION IS ONLY TESTED ON MATLAB R2014b
      % *** CORRECT FUNCTIONING FOR EARLIER RELEASES IS NOT GUARANTEED
      % *** (and not even expected)
      % ****************************************************************
      %
      %
      % SUBPLOT_GRID generates a figure containing the number of subplots
      %   wanted. Subplots can be merged through a variable input parameters.
      %
      %   subplot_grid or subplot_grid('demo') will render a sequence
      %   showing some of the features of subplot_grid. Via a keypress the
      %   sequence moves one step.
      %
      %   hsg = subplot_grid(nax) creates a figure with nax
      %   laid-out in a 2D matrix. hsg is the subplot_grid object
      %   which properties can be called and which methods (see
      %   below) can be invoked.
      %
      %   hsg = subplot_grid(nrows,ncols) creates a figure with nrows
      %   rows and ncols columns of axes.
      %
      %   hsg = subplot_grid('viewer',nax) creates a subplot_grid
      %   panel with a big 5-row spanning axes and nax small axes.
      %
      %   hsg = subplot_grid('viewer',nax,nrows) places the little
      %   axes in nrows rows below the major graph.
      %
      %   hsg = subplot_grid('viewer',nax,nrows,mode) places nrows of
      %   little axes either below or above the major axes. Mode can
      %   hold either 'top' or 'bottom'.
      %   Note that using the method 'set_gca' is modified:
      %   hsg.set_gca(1) will make the big axes the current axes,
      %   while hsg.set_gca('viewer',1) will make the first little
      %   axes current.
      %
      %   Some properties have been defined which can be set via the
      %   property/value pairs after the mandatory nax or nrows and
      %   ncols parameters. These properties do not work in 'viewer'
      %   mode.
      %
      %   hsg = subplot_grid(nax,'property',value,...) or hsg =
      %   subplot_grid(nrows,ncols,'property',value,...) sets these
      %   properties. No particular order is required. See the demo
      %   to check how it works.
      %
      %   The valid properties are:
      %
      %   'mergelist'
      %              Cell array of vectors. Every vector contains subplot
      %              indices. The subplots to merge are the subplots in the
      %              rectangle spanning all subplots indices in the vector. A 2D
      %              vector is therefore sufficient to merge multiple
      %              subplots.
      %
      %   'zoomlinklist'
      %              Cell array of vectors. Every vector contains
      %              subplot indices for axes to link while zooming
      %              out. That is, when clicked on the + sign, all
      %              axes linked are enlarged together in a single column.
      %
      %   'parent'
      %              Gives the handle of the object (either a figure or a panel) in
      %              which subplot_grid creates its axes and works its stuff
      %
      %   'no_zoom'
      %             Does not need any value(s), but indicates that
      %             subplot_grid should not place zoom-buttons in the
      %             axes (generally used in case some print-out needs
      %             to be made and the buttons look ugly)
      %
      %   The possibility of saving and reloading the figure exists. Saving
      %   the figure as a .fig file via the 'Save Figure' toolbar button
      %   will work fine when reloading via 'openfig'. However, some bug
      %   has been found - and not solved yet- in case hgload and hgsave
      %   are used. So please refrain from using these functions in
      %   combination with subplot_grid.
      %
      %   Re-loading a saved subplot_grid object will show the figure panel
      %   and contents plus creates a handle to the subplot_grid object
      %   called 'o_subplot_grid'. This could be renamed to whatever is
      %   handy. Via the properties and methods of this object, anything
      %   should be enabled again.
      %
      %   After the subplot_grid object has been create the contents may be
      %   modified via the following user methods.
      %
      % USER METHODS:
      %
      %   NOTE: every user method help function can be inspected by typing
      %   'subplot_grid.<method>'.
      %
      %   *Listed alphabetically*
      %
      %   colorbar              adds a colorbar to the current axes.
      %                         when resizing or zooming, this
      %                         colorbar will remain correct. The contents
      %                         of the colorbar can be, but are not
      %                         required to be linked to the axes'
      %                         contents.
      %   coltitles             Adds column titles above/below every column
      %   disable_interaxes     Disables the interaxes functionality
      %   disable_subplotzoom   Disable the subplot zoom buttons
      %   enable_interaxes      Enable the interaxes functionality in which the
      %                         axes become clickable (implemented for
      %                         'line','surface' and 'image' graphical objects)
      %   enable_subplotzoom    Enable the subplot zoom buttons
      %   extract_axes          Creates a new figure from one of the
      %                         axes.
      %   figplace              Locate the figure somewhere on a grid
      %                         covering the screen(s). calling
      %                         FIGPLACE without parameters maximizes
      %                         the figure window.
      %   figtitle              Adds a figure title above the subplots
      %   hide_axes             Hides an axes (by default all subplots are
      %                         generated
      %   hide_empty_axes       Hides all axes which do not contain any graphical
      %                         content/objects.
      %   legend                creates a legend without connection to content.
      %   overwrite_interaxes_selection_mods
      %                         Overwrites the default selection modifications
      %                         per axes.
      %   redraw                Redraws the subplot_grid figure. This
      %                         realigns and resets axes, legends and
      %                         colorbars
      %   remove_legend         Removes the legends from one or multiple
      %                         subplots
      %   rowtitles             Adds row titles to the left/right of every row.
      %   set_gca               Set the actual axis as current axes for that
      %                         figure
      %   set_padding           resets the padding space around the
      %                         axes in pixels (default = 5px)
      %   show_axes             Shows an axes which has been hidden before.
      %   subfigtitle           Adds a subtitle to the figure.
      %   sync_axes             Will synchronize one or more axes
      %                         (i.e., x, y and/or color axes).
      %                         Zooming within an axes will keep the
      %                         same axes.
      %   zoomlink_axes         Link axes on zooming in via
      %                         subplotzoom.
      %
      %
      % SYNTAX:
      %   obj = subplot_grid(varargin)
      %
      %
      % PROPERTIES:
      %
      % Can be asked via 'properties(hsg)' or via the generic structured
      % object hierarchy: typing 'hsg'  in the command-window will show all
      % properties. (of course only when you've named your subplot_grid
      % object 'hsg', otherwise use your subplot_grid variable/object
      % name).
      %
      %
      % OUTPUT PARAMETER:
      %   Object of type 'subplot_grid'
      %
      % VERSION:
      %   6.0
      %
      % FUTURE WORK:
      %
      % KNOWN LIMITATIONS:
      %   20120203 : (joris) The MATLAB function PLOTYY does not work
      %                      correctly with subplot_grid, because of the
      %                      fact that PLOTYY uses two overlaying
      %                      axes; one with an y-axis on the left,
      %                      and one with an y-axes on the right.
      %
      % ABOUT:
      %   Birthdate: december 6, 2010
      %   Authors: Joris Kampman/Benno Schl�nsen/Dan Kominsky
      
      %% MODIFICATIONS:
      % <pre release>
      %   20101206 : (Joris) Fixed a bug in the ordering of row and column
      %                      titles in the subfunction 'subplot_resize_fcn'.
      %   20101208 : (Joris) Fixed a bug regarding the resizing of plots that
      %                      have colorbars.
      %   20101210 : (Benno) Modified the function to class, and
      %                      added subplotzoom functionality.
      %   20101213 : (Joris) Modified and cleaned up class code.
      %   20101213 : (Joris) Fixed bug in resizing while zoomed-out.
      %   20101214 : (Joris) Added 'extract_axes' function which creates a new
      %                      figure in which the wanted axes contents are copied.
      %   20101218 : (Joris) Added 'interaxes' function which enables the use of
      %                      the mouse click and arrow buttons for navigation
      %                      through the axis. To be set.
      %   20101218 : (Joris) Fixed a bug regarding the placement after addition
      %                      of row titles.
      %   20101222 : (Joris) Some minor bugfixes and addition of the maintainance
      %                      of the interaxes function after the
      %                      'extract_subplot' command.
      % <<==== version 1.0 created ====>>
      %   20110103 : (Joris) Bugfix: interaxes functionality did not correctly
      %                      function after 'extract_axes' method.
      %   20110103 : (Joris) Bugfix: method 'disable_interaxes' gave errors
      % <<=== version 1.1 created ===>>
      %   20110104 : (Joris) Bugfix: resizing with no row and/or column titles
      %                      gave an error.
      % <<=== version 1.2 created ==>>
      %   20110106 : (Joris) Added the moving to the top of the plot object stack
      %                      when zoomed via subplotzoom.
      %   20110106 : (Joris) Bugfix: adding column titles when Nr != Nc crashed
      % <<=== version 1.3 created ==>>
      %   20110118 : (Joris) Naming update: changed property 'hax_subplots' to 'hax'.
      %                      Naming update: changed method 'set_actual_subplot'
      %                      to 'set_gca'
      % <<=== version 1.4 created ===>>
      %   20110201 : (Joris) Added methods 'show_axes' and 'hide_axes', which
      %                      control the visibility of any of the subplot axes
      %                      created by default at instantiation of this class.
      % <<=== version 1.5 created ==>>
      %   20110201 : (Joris) Bugfix: when using 'hide_axes' and zooming via the
      %                     subplotzoom callback. On zooming back out to the
      %                     orginal axes position, the hidden axes appears. This
      %                     is fixed.
      % <<=== version 1.6 created ==>>
      %   20110203 : (Joris) Adding the method 'hide_empty_axes' which hide all
      %                      axes that do not contain any graphical objects.
      %   20110207 : (Joris) Added the possibility to use a subplot index instead
      %                      of only the row and column indices. Numbering is
      %                      equal to the matlab SUBPLOT function indexing.
      %   20110207 : (Joris) Added the possibility for most methods to give a
      %                      set of axes as parameters which will be looped.
      %   20110207 : (Joris) Bugfix: disabling and enabling INTERAXES for a set
      %                      of axes did not function properly.
      %   20110207 : (Joris) Added the possibility to enable and disable
      %                      SUBPLOTZOOM for a subset of all axes.
      %                      subset of axes.
      %   20110207 : (Joris) Added help data for all methods
      % <<=== version 2.0 created ===>>
      %   20110214 : (Joris) Modified subplot_grid to function correctly during
      %                      saving and loading the figure. A function
      %                      'reset_handles' is added. When loading, and the
      %                      resize function cannot find the handles specifies,
      %                      it calls this reset_handles function
      %   20110310 : (Joris) Added the 'viewer' mode. This is a major subplot and
      %                      a row of minor subplots. Easy to use for one
      %                      combined plot, and several individual plots.
      %   20110310 : (Joris) Added the possibility for single-parameter usage.
      %                      This calculates the number of rows and columns itself.
      % <<=== version 3.0 created ===>>
      %   20110526 : (Joris) Added the possibility to add a subtitle to the
      %                      figure.
      %   20110804 : (Joris) Added the methods ROWTITLES and COLTITLES for a more
      %                      intuitive feel, since there are multiple rows and
      %                      columns which are to be titled.
      %   20111130 : (Joris) Added the possibility to add a fixed legend
      %                      (predefined), not necessarily related to actual
      %                      content. Use method LEGEND to create this. Re
      %                      locating can be done with the method PLACE_LEGEND
      % <<=== version 4.0 created ===>>
      %   20111206 : (Joris) Added the possibility to place a legend 'outside'
      %                      the axes and auto-scaling the axes. Resizing and
      %                      zooming functions work also for legends placed
      %                      outside the axes.
      %   20111206 : (Joris) Added the methods RELOCATE_LEGEND and REMOVE_LEGEND
      %                      in this class. See their respective help functions
      %                      for more information on syntax.
      % <<=== version 4.1 created ===>>
      %   20111208 : (Joris) Set 'LooseInset' property of all axes to a fixed
      %                      width. See property 'loose_inset_px' for the values.
      %   20111213 : (Joris) Cleaned up code, and fixed some warnings. In the
      %                      process fixed some small bugs (although there are
      %                      without a doubt some left).
      %   20111213 : (Joris) Extended the demo (call SUBPLOT_GRID) to incorporate
      %                      some zooming, legend creation and interaxes
      %                      functionality.
      % <<=== version 4.2 created ===>>
      %   20111219 : (Joris) Extended the LEGEND method to be able to handle
      %                      all plot properties. See help of LEGEND method for
      %                      more information.
      % <<=== version 4.3 created ===>>
      %   20120101 : (Joris) in the LEGEND method, changed the number of markers
      %                      from 3 to a single marker in the centre of the line,
      %                      to mimic the MATLAB-style legend
      %   20120117 : (Benno) Added x_sync_axes to synchronise axes x.
      %                      TODO: - Link Y, link both, unlink
      %                            - Add consistency checks
      %   20120302 : (Joris) Bugfix in the placement of the legend
      %                      using SUBPLOTZOOM to enlarge and
      %                      contract again.
      %   20120302 : (Joris) Added functionality to correctly handle
      %                      the deletion/closing of axes or clearing
      %                      the figure. Also on resizing.
      %   20120302 : (Joris) Bugfix in the zooming of an axes with legends on other
      %                      axes. The axes with legends did not recover correctly
      %   20120302 : (Joris) Added COLORBAR method to add a colorbar
      %                      with the same inputs as the normal
      %                      MATLAB colorbar function.
      %   20120302 : (Joris) Added method SET_PADDING which allows
      %                      control over the amount of whitespace
      %                      between axes (Default: [5,5,5,5] pixels)
      % <<=== version 4.4 created ===>>
      %   20121118 : (Joris) Added a second VARARGIN parameter with which
      %                      axes can be linked on zooming in.
      %   20121118 : (Joris) Added the method ZOOMLINK_AXES with
      %                      which axes can be linked on zooming in.
      % <<=== version 4.5 created ===>>
      %   20121120 : (Joris) Debugged the use of linked axes in
      %                      combination with merged axes and a
      %                      legend.
      % <<=== version 4.6 beta created ===>>
      %   20130423 : (Dan) 	 Improved the 'set_zoom_button_position' to
      %                      significantly improve speeds (by approx.
      %                      22 percent).
      %   20130429 : (Joris/Dan)
      %                      Because of the number of properties, all
      %                      varargin parameters are changed to
      %                      property-value pairs.
      %   20130430 : (Joris) Rewritten the help function completely.
      %   20130430 : (Joris) Implemented 'viewer' mode in demo
      %   20130430 : (Joris) Added use of 'parent' property in demo
      %   20130715 : (Joris) Added method REDRAW to reset or redraw
      %                      legends, colorbars and titles.
      %   20130716 : (Joris) Added method FIGPLACE with which the
      %                      figure can be placed in a grid of
      %                      figures.
      %   20130713 : (Joris) Added method SYNC_AXES with which the
      %                      axes of multiple axes can be
      %                      synchronized based on the content.
      % <<=== version 4.7 created ===>>
      %   20130719 : (Joris) Modified the SYNC_AXES method to
      %                      include padding percentages.
      %   20131014 : (Joris) Modified ZOOMLINK_AXES method to keep the
      %                      current relative vertical sizes of the
      %                      linked axes
      %   20140525 : (Joris) Added property SUBPLOTZOOM_INIT_STATE
      %                      used to either force subplotzoom to be
      %                      enabled or disabled at startup
      %   20140627 : (Joris) Added input property 'no_zoom' to
      %                      disable all subplotzoom buttons and
      %                      actions. Makes for nicer prints.
      %   20140627 : (Joris) Removed X_SYNC_AXES. Has been superseded
      %                      by the more generic SYNC_AXES
      % <<=== version 4.8 created ===>>
      %   20140627 : (Joris) calling REDRAW after adding texts
      %   201...... NO SCORE KEPT ANYMORE!
      %
      
      %% initialization
      %%------------------------------------------------------------------------
      if nargin == 0 || strcmpi(varargin{1},'demo'), % demo
        this.demo
        return
      end
      
      this.hfig = gcf;
      set(this.hfig,'Toolbar','figure'); % set toolbar to figure
      this.hparent = this.hfig;
      if isequal('double',class(this.hfig)),
        this.hgVersion = 1;
      else
        this.hgVersion = 2;
      end
      
      %% exception one: viewer mode!
      if strcmpi(varargin{1},'viewer'), % if: viewer mode
        nof_figures = varargin{2};
        valid_modes = {'bottom','top','left','right'};
        mode = 'bottom'; % options: top, left,bottom, right... indicates the position of the list of smaller plots
        nof_minor_rows = 1;
        if nargin > 2,
          if ischar(varargin{3}),
            % check if it contains a mode or another input parameter
            imode = find(strcmpi(valid_modes,varargin{3}));
            if any(imode),
              mode = varargin{3};
              % check if the number of minor rows is given
              if nargin > 3,
                if ~ischar(varargin{4}),
                  nof_minor_rows = varargin{4};
                end
              end
            end
          end
        end
        
        %% find input parameters
        if any(strcmpi('mergelist',varargin)),
          imergelist = 1 + find(strcmpi('mergelist',varargin));
          if iscell(varargin{imergelist}),
            this.mergelist = varargin{imergelist};
          else
            error('The provided ''mergelist'' is not a cell array');
          end
        else
          this.mergelist = {};
        end
        
        if any(strcmpi('zoomlinklist',varargin)),
          izoomlinklist = 1 + find(strcmpi('zoomlinklist',varargin));
          if iscell(varargin{izoomlinklist}),
            this.zoomlinklist = varargin{izoomlinklist};
          else
            error('The provided ''zoomlinklist'' is not a cell array');
          end
        else
          this.zoomlinklist = {};
        end
        
        if any(strcmpi('parent',varargin)),
          iparent = 1 + find(strcmpi('parent',varargin));
          if ishandle(varargin{iparent}),
            this.hparent = varargin{iparent};
            this.in_panel = true;
          else
            error('The provided ''parent'' is not a handle!');
          end
        end
        
        if any(strcmpi('no_zoom',varargin)),
          this.subplotzoom_init_state = false;
        end
        this.viewer.nof_minor_rows = nof_minor_rows;
        
        nof_major_rows = 5;
        nr = nof_minor_rows + nof_major_rows;
        nc = ceil(nof_figures/nof_minor_rows);
        switch mode
          case 'bottom',
            this.mergelist = {[1,nof_major_rows*nc]};
            this.viewer.starting_index = nof_major_rows*nc + 1;
            
          case 'top',
            this.mergelist = {[nof_minor_rows*nc+1,nr*nc]};
            this.viewer.starting_index = 1;
            
          otherwise
            this.mergelist = {[1,nof_major_rows*nc]};
            this.viewer.starting_index = nof_major_rows*nc + 1;
            
        end % switch: mode
        
        %% normal mode (not 'viewer')
      else % not in viewer mode
        
        %% handle inputs
        if nargin == 1 || (ischar(varargin{2}) || iscell(varargin{2})), % 1 or 2 first are scalars, if string then property
          nc = round(ceil(2*sqrt(varargin{1}))/2);
          nr = round(floor(2*sqrt(varargin{1}))/2);
        else
          nr = varargin{1};
          nc = varargin{2};
        end
        
        % option 1: mergelist
        % Check for old calling syntax:
        cellInputs = find(cellfun(@iscell,varargin));
        for iCell = cellInputs
          if ~ischar(varargin{iCell-1}) || ~(any(strcmpi(varargin{iCell-1},{'mergelist','parent','zoomlinklist','no_zoom'})))
            error('subplot_grid:oldSyntax','Subplot_grid has been called with an obsolete syntax');
          end
        end
        
        
        %% find input parameters
        if any(strcmpi('mergelist',varargin)),
          imergelist = 1 + find(strcmpi('mergelist',varargin));
          if iscell(varargin{imergelist}),
            this.mergelist = varargin{imergelist};
          else
            error('The provided ''mergelist'' is not a cell array');
          end
        else
          this.mergelist = {};
        end
        
        if any(strcmpi('zoomlinklist',varargin)),
          izoomlinklist = 1 + find(strcmpi('zoomlinklist',varargin));
          if iscell(varargin{izoomlinklist}),
            this.zoomlinklist = varargin{izoomlinklist};
          else
            error('The provided ''zoomlinklist'' is not a cell array');
          end
        else
          this.zoomlinklist = {};
        end
        
        if any(strcmpi('parent',varargin)),
          iparent = 1 + find(strcmpi('parent',varargin));
          if ishandle(varargin{iparent}),
            this.hparent = varargin{iparent};
            this.in_panel = true;
          else
            error('The provided ''parent'' is not a handle!');
          end
        end
        
        if any(strcmpi('no_zoom',varargin)),
          this.subplotzoom_init_state = false;
        end
        
      end % ifelse: viewer mode or not??
      
      
      %% create axes
      this.nof_rows = nr;
      this.nof_columns = nc;
      this.hlegend = nan(nr,nc);
      this.hcolorbar = nan(nr,nc);
      this.hidden_axes = false(nr,nc);
      this.hidden_axes_manual = false(nr,nc);
      this.zoomed = false(nr,nc);
      
      boxheight = 1/nr;
      boxwidth = 1/nc;
      
      this.hax = zeros(nr,nc);
      this.Iax = this.hax;
      legnames = fieldnames(this.legend_data_defaults);
      cbnames = fieldnames(this.colorbar_data_defaults);
      
      for ir = 1:nr, % all rows
        for ic = 1:nc, % al columns
          %% create axes
          position = [((ic - 1)*boxwidth) ((nr - ir)*boxheight) boxwidth boxheight];
          
          this.hax(ir,ic) = axes('Parent',this.hparent,...
            'Units','normalized',...
            'OuterPosition',position,...
            'Tag',sprintf('hax_%d_%d',ir,ic));
          set(this.hax(ir,ic),'Units','pixels','LooseInset',this.loose_inset_px); % set loose inset
          
          %% save misc properties
          this.Iax(ir,ic) = sub2ind(size(this.hax.'),ic,ir);
          this.Rax(ir,ic) = ir;
          this.Cax(ir,ic) = ic;
          
          %% zoomed flag (set to false)
          this.zoomed(ir,ic) = false; % init: not zoomed in of course
          
          %% init interaxes grid
          this.interaxes_data(ir,ic).valid = false;
          this.interaxes_data(ir,ic).selected_object_handle = nan;
          this.interaxes_data(ir,ic).selected_object_props = [];
          this.interaxes_data(ir,ic).local_selection_mods = this.interaxes_selection_mods;
          
          %% Create subplot zoom buttons and prepare subplot zoom data
          this.subplotzoom_data(ir,ic).zm_btn = uicontrol(this.hparent,...
            'style','push',...
            'tag',sprintf('subplotzoom_%d_%d',ir,ic),...
            'units','pixels',...
            'string','+',...
            'fontsize',6,...
            'Interruptible','off',...
            'callback',@(src, event)subplotzoom_cb(this,ir,ic));
          this.subplotzoom_enabled(ir,ic) = this.subplotzoom_init_state; % 1 => with suplot zoom, 0 => without subplot zoom
          this.set_zoom_button_position(ir,ic); % set positions in axes (upper right corner)
          
          % init legend data to nan
          for ilegn = 1:numel(legnames),
            this.legend_data(ir,ic).(legnames{ilegn}) = this.legend_data_defaults.(legnames{ilegn});
          end
          
          % init colorbar data tot nan
          for icbn = 1:numel(cbnames),
            this.colorbar_data(ir,ic).(cbnames{icbn}) = this.colorbar_data_defaults.(cbnames{icbn});
          end
                    
          % find axes it's linked to
          index = sub2ind([nc,nr],ic,ir);
          this.subplotzoom_data(ir,ic).zoomlinked_with = index;
          for icell = 1:numel(this.zoomlinklist),
            if ismember(index,this.zoomlinklist{icell}),
              this.subplotzoom_data(ir,ic).zoomlinked_with = this.zoomlinklist{icell};
            end
          end % for: all in zoomlinklist
        end % for: all columns
      end % for: all rows
      
      %% merge axes
      %%------------------------------------------------------------------------
      if ~isempty(this.mergelist),
        if ~iscell(this.mergelist),
          this.mergelist = {this.mergelist};
        end
        
        nof_combs = numel(this.mergelist);
        for icomb = 1:nof_combs,
          sp2merge = this.mergelist{icomb};
          
          [ic,ir] = ind2sub([nc,nr],sp2merge);
          leftpos = get(this.hax(min(ir),min(ic)),'OuterPosition');
          rightpos = get(this.hax(max(ir),max(ic)),'OuterPosition');
          
          mergepos = [leftpos(1),...
            rightpos(2),...
            rightpos(1) + rightpos(3) - leftpos(1),...
            leftpos(2) + leftpos(4) - rightpos(2)];
          
          
          % remove redundant subplots including reduncant subplot
          % zoom buttons and data
          
          for rrem = (min(ir)):1:max(ir),
            for crem = (min(ic)):1:max(ic),
              if rrem > min(ir) || crem > min(ic),
                delete(this.hax(rrem,crem)); % delete axis
                delete(this.subplotzoom_data(rrem,crem).zm_btn) % delete subplotzoom button
                this.subplotzoom_data(rrem,crem) = this.subplotzoom_data(min(ir),min(ic)); % delete subplotzoom_data
                clear this.subplotzoom_data(rrem,crem);
                this.hax(rrem,crem) = this.hax(min(ir),min(ic));
                this.Iax(rrem,crem) = this.Iax(min(ir),min(ic));
                this.Rax(rrem,crem) = this.Rax(max(ir),max(ic));
                this.Rax(ir,ic) = this.Rax(max(ir),max(ic));
                this.Cax(rrem,crem) = this.Cax(min(ir),min(ic));
                
              end
            end
          end
          
          set(this.hax(min(ir),min(ic)),'OuterPosition',mergepos,'ActivePositionProperty','OuterPosition');
          set(this.hax(min(ir),min(ic)),'Units','pixels','LooseInset',this.loose_inset_px);
          set(this.hax(min(ir),min(ic)),'Units','normalized');
          
        end % for: all combinations
      end
      
      
      if ~this.subplotzoom_enabled,
        this.disable_subplotzoom;
      end
      
      %% Resizing function (if present)
      %%------------------------------------------------------------------------
      pause(0.1);
      set(this.hfig,'ResizeFcn',@(src,evt)this.reposition_content);
%       this.hfig.SizeChangeFcn = this.reposition_content
%       set(this.hfig,'SizeChangeFcn',@this.reposition_content);
      set(this.hax(:),'DeleteFcn',@this.delete_axes);
      this.set_gca(1,1);
      
      
      set(this.hfig,'Units','pixels');
      set(this.hparent,'Units','pixels');
      figpos = get(this.hfig,'Position');
      parpos = get(this.hparent,'Position');
      if this.in_panel,
        this.pos_parent_in_figure = [parpos(1)/figpos(3),parpos(2)/figpos(4),parpos(3)/figpos(3),parpos(4)/figpos(4)];
      else
        this.pos_parent_in_figure = [0 0 1 1];
      end
      
      this.reposition_content;
      this.set_gca(1,1);
      
      
    end % fcn: constructor
    
    
    function figtitle(this, titlestring,varargin)
      
      %
      % FIGTITLE adds a - multi-row - title for the entire figure. The
      %   extension of the title to multiple rows is done via the use of a
      %   cell array of strings. The text properties may be altered by the
      %   normal properties as VARARGIN parameters
      %
      % SYNTAX:
      %   <obj>.figtitle(titlestring,VARARGIN);
      %
      % INPUT PARAMETER:
      %   titlestring   A string or a cell array of strings containing the
      %                 text to use as the figure title.
      %
      % VARARGIN PARAMETERS:
      %   The varargin parameters can be used to set the text properties of
      %   the figure title. The VARARGIN parameters come in pairs:
      %   'property_name' and 'property_value'. An extensive list can thus
      %   be created.
      %
      
      set(0,'CurrentFigure',this.hfig);
      if isempty(titlestring),
        if this.titles.title.valid,
          delete(this.titles.title.hax);
          this.titles.title = this.titles.template;
        end
        this.reposition_content;
        return
      end
      
      if ~iscell(titlestring),
        titlestring = {titlestring};
      end
      
      %% undo zooming (temporarily)
      [irzoomed,iczoomed] = find(this.zoomed == 1);
      if any(irzoomed),
        this.subplotzoom_cb(irzoomed(1),iczoomed(1));
      end
      
      
      %% row and coltitle dimensions
      %--------------------------------------------------------------
      
      % delete existing figure title
      if this.titles.title.valid,
        delete(this.titles.title.hax);
      end
      
      
      %% create figure title axes and text box
      %%----------------------------------------------------------------------
      % AXES
      hax_figtitle = axes('Parent',this.hparent,...
        'Units','normalized',...
        'Position',[0 0 1 1],...
        'Tag','figtitle',...
        'Visible','off',...
        'XTick',[],...
        'YTick',[],...
        'Box','off');
      
      % TEXTBOX
      htext_figtitle = text(0.5,0.5,'',...
        'Units','normalized',...
        'HorizontalAlignment','center',...
        'VerticalAlignment','middle',...
        'LineStyle','none',...
        'EdgeColor',[0 1 0],...
        'Tag','figtitle',...
        'FontWeight','bold',...
        'FontSize',12);
      
      % VARARGIN (text properties)
      if nargin > 2,
        for iarg = 2:2:nargin-1,
          set(htext_figtitle,varargin{iarg-1},varargin{iarg});
        end
      end
      
      % text in textbox
      set(htext_figtitle,'String',titlestring,'Units','pixels');
      pos = get(htext_figtitle,'Extent');
      set(htext_figtitle,'Units','normalized');
      this.titles.title = struct('valid',true,...
        'hax',hax_figtitle,...
        'htxt',htext_figtitle,...
        'txtbox_sizes',pos(4),...
        'ratios',[]);
      
      %% reposition everything
      this.reposition_content
      
    end % fcn
    
    
    function subfigtitle(this, titlestring, varargin)
      
      %
      % SUBFIGTITLE adds a - multi-row - SUBtitle for the entire figure. The
      %   extension of the title to multiple rows is done via the use of a
      %   cell array of strings. The text properties may be altered by the
      %   normal properties as VARARGIN parameters
      %
      % SYNTAX:
      %   <obj>.subfigtitle(titlestring,VARARGIN);
      %
      % INPUT PARAMETER:
      %   titlestring   A string or a cell array of strings containing the
      %                 text to use as the figure title.
      %
      % VARARGIN PARAMETERS:
      %   The varargin parameters can be used to set the text properties of
      %   the figure title. The VARARGIN parameters come in pairs:
      %   'property_name' and 'property_value'. An extensive list can thus
      %   be created.
      %
      
      set(0,'CurrentFigure',this.hfig);
      if isempty(titlestring),
        if this.titles.subtitle.valid,
          delete(this.titles.subtitle.hax);
          this.titles.subtitle = this.titles.template;
        end
        this.reposition_content;
        return
      end
      
      if ~iscell(titlestring),
        titlestring = {titlestring};
      end
      
      %% undo zooming (temporarily)
      [irzoomed,iczoomed] = find(this.zoomed == 1);
      if any(irzoomed),
        this.subplotzoom_cb(irzoomed(1),iczoomed(1));
      end
      
      if this.titles.subtitle.valid,
        delete(this.titles.subtitle.hax);
      end
      
      %% (re)create figure title axes and text box
      %%----------------------------------------------------------------------
      
      % AXES
      hax_subfigtitle = axes('Parent',this.hparent,...
        'Units','normalized',...
        'Position',[0 0 1 1],...
        'Tag','subfigtitle',...
        'Visible','off',...
        'XTick',[],...
        'YTick',[],...
        'Box','off');
      
      % TEXTBOX
      htext_subfigtitle = text(0.5,0.5,'',...
        'Units','normalized',...
        'HorizontalAlignment','center',...
        'VerticalAlignment','middle',...
        'LineStyle','none',...
        'EdgeColor',[0 1 0],...
        'Tag','subfigtitle',...
        'FontWeight','bold',...
        'FontSize',10);
      
      % VARARGIN
      if nargin > 2,
        for iarg = 2:2:nargin-1,
          set(htext_subfigtitle,varargin{iarg-1},varargin{iarg});
        end
      end
      
      
      % text in textbox
      set(htext_subfigtitle,'String',titlestring,'Units','pixels');
      pos = get(htext_subfigtitle,'Extent');
      set(htext_subfigtitle,'Units','normalized');
      this.titles.subtitle = struct('valid',true,...
        'hax',hax_subfigtitle,...
        'htxt',htext_subfigtitle,...
        'txtbox_sizes',pos(4),...
        'ratios',[]);
      
      
      this.reposition_content;
      
    end % fcn
    
    
    function rowtitles(this,rowstring,varargin)
      
      %
      % ROWTITLES adds vertically aligned texts on the left or the right side of the window.
      %
      %   obj.rowtitles(C) adds the texts in cell array C to the left (=default) side of the
      %   figure window, evenly spaced to span the entire available length. The number of
      %   elements in C does NOT have to be equal to the number of axes or such. These are not
      %   connected. The cell array C can hold multi-line texts in case an element of C is
      %   itself a cell array.
      %
      %   obj.rowtitles(C,R) will use the vector R to determine the relative sizes of the
      %   titles. Default R = ones(number of elements,1).
      %
      %   obj.rowtitles(C,loc,...) will place the row titles on the side given by 'loc' and
      %   can hold two options: 'left' or 'right'
      %
      %   obj.rowtitles(C,...,VARARGIN) uses the standard text property name/value pairs to
      %   modify the text properties.
      %
      %   obj.rowtitles([]) will remove all row titles on both sides and expands the axes again to
      %   fill the empty space.
      %
      %   EXAMPLE:
      %
      %     obj.rowtitles({'first',{'second.1','second.2'},'third'},'right',[1 2 1])
      %
      %     this example will plot three row titles of which the second consists of two lines.
      %
      %     the second parameter 'right' ensures the row titles to be on the right side of the
      %     window.
      %
      %     The third parameter [1 2 1] ensures that the size of the texts has the ratio
      %     1:2:1. That is, the second texts is twice the size of the other two texts.
      %
      %   VARARGIN PARAMETERS:
      %
      %     The varargin parameters can be used to set the text properties of the row
      %     titles.
      %
      
      set(0,'CurrentFigure',this.hfig);
      location = 'left'; % default
      
      %% gather titles dimensions
      %%-------------------------------------------------------------------
      
      %% process empty input
      if isempty(rowstring),
        if this.titles.rowtitles_left.valid,
          delete(this.titles.rowtitles_left.hax);
          this.titles.rowtitles_left = this.titles.template;
        end
        if this.titles.rowtitles_right.valid,
          delete(this.titles.rowtitles_right.hax);
          this.titles.rowtitles_right = this.titles.template;
        end
        this.reposition_content;
        return
      end
      
      %% handle input parameters
      if ~iscell(rowstring),
        rowstring = {rowstring};
      end
      nof_rowtitles = numel(rowstring);
      
      nvargin = numel(varargin);
      argos = 0;
      size_ratios = ones(1,nof_rowtitles);
      valid_positions = {'left','right'};
      if nargin > 2,
        if any(find(strcmpi(varargin{1},valid_positions))),
          location = varargin{1};
          argos = 1;
          if nargin > 3,
            if ~ischar(varargin{2}),
              argos = 2;
              size_ratios = varargin{2};
            end
          end
        elseif ~ischar(varargin{1}),
          argos = 1;
          size_ratios = varargin{1};
        end
      end
      
      size_ratios = size_ratios/sum(size_ratios); % normalize
      
      
      %% delete existing row titles
      switch location
        case 'left',
          delete(this.titles.rowtitles_left.hax);
          this.titles.rowtitles_left = this.titles.template;
          this.titles.rowtitles_left.ratios = size_ratios;
          
        case 'right',
          delete(this.titles.rowtitles_right.hax);
          this.titles.rowtitles_right = this.titles.template;
          this.titles.rowtitles_right.ratios = size_ratios;
          
      end % switch: location
      
      
      %% undo zooming and legends(temporarily)
      [irzoomed,iczoomed] = find(this.zoomed == 1);
      if any(irzoomed),
        this.subplotzoom_cb(irzoomed(1),iczoomed(1));
      end
      
      %% create title axes and texts
      %%-----------------------------------------------------------
      switch location
        case 'left',
          rotation = 90;
          tag = 'rowtitles_left';
        case 'right',
          rotation = -90;
          tag = 'rowtitles_right';
      end
      
      hax_rowtitles = zeros(1,nof_rowtitles);
      htext_rtitle = zeros(1,nof_rowtitles);
      txtbox_sizes = zeros(1,nof_rowtitles);
      for ir = 1:nof_rowtitles,
        
        % AXES
        hax_rowtitles(ir) = axes('Parent',this.hparent,'Units','normalized',...
          'Position',[0 0 1 1],...
          'Tag',sprintf('%s_%d',tag,ir),...
          'Visible','off',...
          'XTick',[],...
          'YTick',[],...
          'Units','normalized',...
          'Box','off');
        
        % TEXTBOX
        htext_rtitle(ir) = text(0.5,0.5,'',...
          'HorizontalAlignment','center',...
          'VerticalAlignment','middle',...
          'EdgeColor',[1 0 0],...
          'LineStyle','none',...
          'Rotation',rotation,...
          'Tag',sprintf('%s_%d',tag,ir),...
          'FontWeight','bold');
        
        % text properties
        if nargin > (nargin - nvargin + argos),
          for iarg = (1 + argos):2:(nvargin),
            set(htext_rtitle(ir),varargin{iarg},varargin{iarg+1});
          end
        end
        
        
        % text in textbox
        set(htext_rtitle(ir),'String',rowstring{ir},'Units','pixels');
        pos = get(htext_rtitle(ir),'Extent');
        txtbox_sizes(ir) = max(1e-6,pos(3));
        set(htext_rtitle(ir),'Units','normalized');
      end % for: all row titles
      
      
      datastruct = struct('valid',true,...
        'hax',hax_rowtitles,...
        'htxt',htext_rtitle,...
        'txtbox_sizes',txtbox_sizes,...
        'ratios',size_ratios);
      switch location,
        case 'left',
          this.titles.rowtitles_left = datastruct;
        case 'right',
          this.titles.rowtitles_right = datastruct;
      end
      
      %% reposition
      this.reposition_content;
      
    end % fcn: rowtitles
    
    
    function coltitles(this,colstring,varargin)
      
      %
      % COLTITLES adds horizontally aligned texts on the top or bottom of the window.
      %
      %   obj.coltitles(C) adds the texts in cell array C to the top (=default) of the
      %   figure window, evenly spaced to span the entire available length. The number of
      %   elements in C does NOT have to be equal to the number of axes or such. These are not
      %   connected. The cell array C can hold multi-line texts in case an element of C is
      %   itself a cell array.
      %
      %   obj.coltitles(C,R) will use the vector R to determine the relative sizes of the
      %   titles. Default R = ones(number of elements,1).
      %
      %   obj.coltitles(C,loc,...) will place the column titles on the side given by 'loc' and
      %   can hold two options: 'top' or 'bottom'
      %
      %   obj.coltitles(C,...,VARARGIN) uses the standard text property name/value pairs to
      %   modify the text properties.
      %
      %   obj.coltitles([]) will remove all column titles on both sides and expands the axes again to
      %   fill the empty space.
      %
      %   EXAMPLE:
      %
      %     obj.coltitles({'first',{'second.1','second.2'},'third'},'bottom',[1 2 1])
      %
      %     this example will plot three column titles of which the second consists of two lines.
      %
      %     the second parameter 'bottom' ensures the column titles to be on the bottom of the
      %     window.
      %
      %     The third parameter [1 2 1] ensures that the size of the texts has the ratio
      %     1:2:1. That is, the second texts is twice the size of the other two texts.
      %
      %   VARARGIN PARAMETERS:
      %
      %     The varargin parameters can be used to set the text properties of the column
      %     titles.
      %
      
      %% handle input parameters
      location = 'top';
      set(0,'CurrentFigure',this.hfig);
      if isempty(colstring),
        if this.titles.coltitles_top.valid,
          delete(this.titles.coltitles_top.hax);
          this.titles.coltitles_top = this.titles.template;
        end
        if this.titles.coltitles_bottom.valid,
          delete(this.titles.coltitles_bottom.hax);
          this.titles.coltitles_bottom = this.titles.template;
        end
      end
      
      
      if ~iscell(colstring),
        colstring = {colstring};
      end
      nof_coltitles = numel(colstring);
      size_ratios = ones(1,nof_coltitles);
      
      nvargin = numel(varargin);
      argos = 0;
      valid_positions = {'bottom','top'};
      if nargin > 2,
        if any(find(strcmpi(varargin{1},valid_positions))),
          location = varargin{1};
          argos = 1;
          if nargin > 3,
            if ~ischar(varargin{2}),
              argos = 2;
              size_ratios = varargin{2};
            end
          end
        elseif ~ischar(varargin{1}), % is vector of ratios
          argos = 1;
          size_ratios = varargin{1};
        end
      end
      
      size_ratios = size_ratios/sum(size_ratios);
      
      %% delete existing axes
      switch location
        case 'top',
          if this.titles.coltitles_top.valid,
            delete(this.titles.coltitles_top.hax);
            this.titles.coltitles_top = this.titles.template;
          end
        case 'bottom',
          if this.titles.coltitles_bottom.valid,
            delete(this.titles.coltitles_bottom.hax);
            this.titles.coltitles_bottom = this.titles.template;
          end
      end
      
      %% undo zooming and legend effects
      %%-------------------------------------------------------------------
      [irzoomed,iczoomed] = find(this.zoomed == 1);
      if any(irzoomed),
        this.subplotzoom_cb(irzoomed(1),iczoomed(1));
      end
      
      %% create axes and text boxes
      %%-----------------------------------------------------------
      switch location,
        case 'top',
          tag = 'coltitles_top';
        case 'bottom',
          tag = 'coltitles_bottom';
      end
      
      hax_coltitles = zeros(1,nof_coltitles);
      htext_ctitle = zeros(1,nof_coltitles);
      txtbox_sizes = zeros(1,nof_coltitles);
      for ic = 1:nof_coltitles,
        % define initial axes
        hax_coltitles(ic) = axes('Parent',this.hparent,'Units','normalized',...
          'Position',[0 0 1 1],...
          'Tag',sprintf('%s_%d',tag,ic),...
          'Visible','off',...
          'XTick',[],...
          'YTick',[],...
          'Units','normalized',...
          'Box','off');
        
        % create wrongly located text box
        htext_ctitle(ic) = text(0.5,0.5,'',...
          'HorizontalAlignment','center',...
          'VerticalAlignment','middle',...
          'LineStyle','none',...
          'EdgeColor',[0 1 1],...
          'Tag',sprintf('%s_%d',tag,ic),...
          'FontWeight','bold');
        
        if nargin > (nargin - nvargin + argos),
          for iarg = (1 + argos):2:(nvargin),
            set(htext_ctitle(ic),varargin{iarg},varargin{iarg+1});
          end
        end
        
        % text in textbox
        set(htext_ctitle(ic),'String',colstring{ic},'Units','pixels');
        pos = get(htext_ctitle(ic),'Extent');
        txtbox_sizes(ic) = max(1e-6,pos(4));
        set(htext_ctitle(ic),'Units','normalized');
        
      end % for: all col titles
      
      %% set property titles
      datastruct = struct('valid',true,...
        'hax',hax_coltitles,...
        'htxt',htext_ctitle,...
        'txtbox_sizes',txtbox_sizes,...
        'ratios',size_ratios);
      switch location,
        case 'top',
          this.titles.coltitles_top = datastruct;
        case 'bottom',
          this.titles.coltitles_bottom = datastruct;
      end
      
      %% reposition content
      
      this.reposition_content;
      
    end % fcn: coltitles
    
    
    function enable_subplotzoom(this,varargin)
      
      %
      % ENABLE_SUBPLOTZOOM sets the subplotzoom button in the top-right
      %   corner of the axes. The method is controlled via VARARGIN
      %   parameters, with which a - set of - axes indices, or a set of
      %   axes row and column positions may be presented.
      %
      %   Omitting a VARARGIN parameter will cause the script to enable
      %   SUBPLOTZOOM for all axes.
      %
      % SYNTAX:
      %   <obj>.enable_subplotzoom(VARARGIN);
      %
      % VARARGIN PARAMETERS:
      %   <no input parameters> : SUBPLOTZOOM will be enabled for all axes
      %   1 input parameter :   A vector containing the axes indices for
      %                         which SUBPLOTZOOM must be enabled.
      %   2 input parameters :  Two vectors containing the row and column
      %                         indices of the axes for which SUBPLOTZOOM
      %                         must be enabled
      %
      
      if nargin == 1,
        Iax = 1:this.nof_rows*this.nof_columns;
        [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],Iax);
      elseif nargin == 2,
        Iax = varargin{1};
        [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],Iax);
      elseif nargin == 3,
        Ir = varargin{1};
        Ic = varargin{2};
      end
      
      for iter = 1:numel(Ir),
        ir = Ir(iter);
        ic = Ic(iter);
        if ishandle(this.hax(ir,ic)),
          if ~isempty(this.subplotzoom_data(ir,ic))
            % *** corner ***
            set(this.subplotzoom_data(ir,ic).zm_btn,'Visible','on');     % Set axis units
            this.subplotzoom_enabled(ir,ic) = 1;
          end
        end
      end % for: all sets
      
      this.reposition_content;
      
    end % fcn
    
    
    function disable_subplotzoom(this,varargin)
      
      %
      % DISABLE_SUBPLOTZOOM disables the subplotzoom button in the top-right
      %   corner of the axes. The method is controlled via VARARGIN
      %   parameters, with which a - set of - axes indices, or a set of
      %   axes row and column positions may be presented.
      %
      %   Omitting a VARARGIN parameter will cause the script to disable
      %   SUBPLOTZOOM for all axes.
      %
      % SYNTAX:
      %   <obj>.disable_subplotzoom(VARARGIN);
      %
      % VARARGIN PARAMETERS:
      %   <no input parameters> : SUBPLOTZOOM will be disabled for all axes
      %   1 input parameter :   A vector containing the axes indices for
      %                         which SUBPLOTZOOM must be disabled.
      %   2 input parameters :  Two vectors containing the row and column
      %                         indices of the axes for which SUBPLOTZOOM
      %                         must be disabled
      %
      
      if nargin == 1,
        Iax = 1:this.nof_rows*this.nof_columns;
        [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],Iax);
      elseif nargin == 2,
        Iax = varargin{1};
        [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],Iax);
      elseif nargin == 3,
        Ir = varargin{1};
        Ic = varargin{2};
      end
      
      for iter = 1:numel(Ir),
        ir = Ir(iter);
        ic = Ic(iter);
        % *** corner ***
        if ishandle(this.hax(ir,ic)),
          set(this.subplotzoom_data(ir,ic).zm_btn,'Visible','off');     % Set axis units
          this.subplotzoom_enabled(this.hax == this.hax(ir,ic)) = 0;
        end
      end % for: all inputs
    end % fcn
    
    
    function set_gca(this,varargin)
      
      %
      % SET_GCA sets the current axes of the figure. The behaviour is
      %   controlled by VARARGIN inputs.
      %
      % SYNTAX:
      %   <obj>.set_gca(VARARGIN);
      %
      % VARARGIN PARAMETERS:
      %   1 input parameter :   The index of the axes to be made the
      %                         current one
      %   2 input parameters :  The row and column indices for the axes to
      %                         be made the current one
      %
      %                         or
      %
      %                         parameter 1 : 'viewer', parameter 2 : axes
      %                         index
      %
      
      
      if nargin == 1,
        ir = this.current_axes(1);
        ic = this.current_axes(2);
      else
        if strcmp(varargin{1},'viewer'),
          [ic,ir] = ind2sub([this.nof_columns,this.nof_rows],this.viewer.starting_index + varargin{2} - 1);
        else
          if nargin == 2,
            [ic,ir] = ind2sub([this.nof_columns,this.nof_rows],varargin{1});
          elseif nargin == 3,
            ir = varargin{1};
            ic = varargin{2};
          end
        end
      end
      
      if (ir > 0) && (ir <= this.nof_rows) && (ic > 0) && (ic <= this.nof_columns),
        set(0,'CurrentFigure',this.hfig);
        set(this.hfig,'CurrentAxes',this.hax(ir,ic));
      else
        disp('Invalid subplot index')
      end
      
      this.current_axes = [ir,ic];
    end % fcn: set_gca
    
    
    function hide_axes(this,varargin)
      
      %
      % HIDE_AXES hides a set of axes from the figure. Can be used to blank
      %   'empty' axes or create space for annotational texts.
      %
      % SYNTAX:
      %   <obj>.hide_axes(VARARGIN);
      %
      % VARARGIN PARAMETERS:
      %   <no input parameters> : all axes will be hidden.
      %   1 input parameter : A vector containing the axes indices to
      %                       hide
      %   2 input parameters : Two vectors containing the row and column
      %                        indices of the axes to hide
      %
      
      mode = 'manual';
      argos = 0;
      if nargin > 1,
        if ischar(varargin{1}),
          mode = varargin{1};
          argos = 1;
        end
      end
      
      if nargin == 1+argos,
        Iax = 1:(this.nof_rows*this.nof_columns);
        [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],Iax);
      elseif nargin == 2+argos,
        [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],varargin{argos + 1});
      elseif nargin == 3+argos,
        Ir = varargin{argos + 1};
        Ic = varargin{argos + 2};
      end
      
      for iter = 1:numel(Ir),
        ir = Ir(iter);
        ic = Ic(iter);
        kids = allchild(this.hax(ir,ic));
        set(this.hax(ir,ic),'Visible','off');
        if ~isempty(kids),
          set(kids(isprop(kids,'Visible')),'Visible','off');
        end
        set(this.subplotzoom_data(ir,ic).zm_btn,'Visible','off');
        this.hidden_axes(ir,ic) = true;
        if ishandle(this.hlegend(ir,ic)),
          set(findobj(this.hlegend(ir,ic)),'Visible','off');
        end
        if ishandle(this.hcolorbar(ir,ic)),
          set(findobj(this.hcolorbar(ir,ic)),'Visible','off');
        end
        
        switch mode,
          case 'manual',
            this.hidden_axes_manual(this.Iax == this.Iax(ir,ic)) = true;
            
          case 'zoom',
            this.hidden_axes(this.Iax == this.Iax(ir,ic)) = true;
        end
      end
      
      
      
    end % hide axes
    
    
    function hide_empty_axes(this)
      
      %
      % HIDE_EMPTY_AXES hides all axes without graphical content in the
      %   figure.
      %
      % SYNTAX:
      %   <obj>.hide_empty_axes;
      %
      %
      
      for ir = 1:this.nof_rows,
        for ic = 1:this.nof_columns,
          if numel(findobj(this.hax(ir,ic),'-not','Type','text')) == 1,
            this.hide_axes('manual',ir,ic);
          end % if: only axes itself is found
        end
      end % for: all axes
      
    end % fcn: hide_empty_axes
    
    
    function show_axes(this,varargin)
      
      %
      % SHOW_AXES can be used to make axes which have been hidden by
      %   re-appear. By default, at startup, all axes are shown.
      %
      % SYNTAX:
      %   <obj>.show_axes(VARARGIN);
      %
      % VARARGIN PARAMETERS:
      %   <no input parameters> : all axes will be shown.
      %   1 input parameter : A vector containing the axes indices to
      %                       show
      %   2 input parameters : Two vectors containing the row and column
      %                        indices of the axes to show
      %
      
      mode = 'manual';
      argos = 0;
      if nargin > 1,
        if ischar(varargin{1}),
          mode = varargin{1};
          argos = 1;
        end
      end
      
      if nargin == 1+argos,
        Iax = 1:(this.nof_rows*this.nof_columns);
        [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],Iax);
      elseif nargin == 2+argos,
        [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],varargin{argos + 1});
      elseif nargin == 3+argos,
        Ir = varargin{argos + 1};
        Ic = varargin{argos + 2};
      end
      
      for iter = 1:numel(Ir),
        ir = Ir(iter);
        ic = Ic(iter);
        kids = allchild(this.hax(ir,ic));
        set(this.hax(ir,ic),'Visible','on');
        if ~isempty(kids),
          set(kids(isprop(kids,'Visible')),'Visible','on');
        end
        
        if this.subplotzoom_enabled(ir,ic),
          set(this.subplotzoom_data(ir,ic).zm_btn,'Visible','on');
        end
        this.hidden_axes(ir,ic) = false;
        if ishandle(this.hlegend(ir,ic)),
          set(findobj(this.hlegend(ir,ic)),'Visible','on');
        end
        if ishandle(this.hcolorbar(ir,ic)),
          set(findobj(this.hcolorbar(ir,ic)),'Visible','on');
        end
        
        switch mode
          case 'manual',
            this.hidden_axes_manual(this.Iax == this.Iax(ir,ic)) = false;
          case 'zoom',
            this.hidden_axes(this.Iax == this.Iax(ir,ic)) = false;
        end
      end
      
    end % show axes
    
    
    function enable_interaxes(this,varargin)
      
      %
      % ENABLE_INTERAXES enables the INTERAXES functionality for a set of
      %   axes.
      %
      %   With the INTERAXES function enabled, the user may click on the
      %   graph and the data points closest to the clicked-on point are
      %   selected. This implies a highlighting of the line (in case of
      %   line graphs) and the display of the data point location in the
      %   title.
      %
      %   In addition, after selection, the use of the arrow keys will move
      %   the selection box in that direction.
      %
      %   NOTE: it has been checked to work correctly for graphical
      %   objects: LINE, IMAGE and SURFACE.
      %
      % SYNTAX:
      %   <obj>.enable_interaxes(VARARGIN);
      %
      % VARARGIN PARAMETERS:
      %   <no input parameters> : INTERAXES will be enabled for all axes
      %   1 input parameter : A vector containing the axes indices to
      %                       enable INTERAXES for
      %   2 input parameters : Two vectors containing the row and column
      %                        indices of the axes to enable INTERAXES for
      %
      
      Iax_ = 1:(this.nof_rows*this.nof_columns);
      [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],Iax_);
      if nargin > 1,
        [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],varargin{1});
        if nargin > 2,
          Ir = varargin{1};
          Ic = varargin{2};
        end
      end
      
      for iter = 1:numel(Ir),
        ir = Ir(iter);
        ic = Ic(iter);
        
        if ishandle(this.hax(ir,ic)),
          % check for valid plot types
          plottypes = get(get(this.hax(ir,ic),'Children'),'Type');
          
          if isempty(plottypes),
            % do nothing
          elseif ~sum(ismember(this.interaxes_supported_types,plottypes)),
            warning(sprintf('Axes (%d,%d) does not contain valid plot types. INTERAXES function not enabled',ir,ic));
          else
            haxc = this.hax(ir,ic);
            set(haxc,'ButtonDownFcn',@(src,evt)this.interaxes(src,evt,ir,ic));
            set(allchild(haxc),'ButtonDownFcn',@(src,evt)this.interaxes(src,evt,ir,ic));
            set(this.hfig,'WindowKeyPressFcn',@(src,evt)this.interaxes(src,evt,ir,ic));
            ttl = get(get(haxc,'Title'),'String');
            if ~iscell(ttl),
              ttl = {ttl};
              set(get(haxc,'Title'),'String',ttl)
            end
            
            % set interaxes_state
            this.interaxes_data(ir,ic) = struct('valid',true,...
              'selected_object_handle',nan,...
              'selected_object_props',[],...
              'local_selection_mods',this.interaxes_selection_mods);
          end % ifelse: any and correct plottypes?
          
        end
        
      end % for: all inputs
      
    end % fcn
    
    
    function disable_interaxes(this,varargin)
      
      %
      % DISABLE_INTERAXES disables the INTERAXES functionality for a set of
      %   axes.
      %
      %   With the INTERAXES function enabled, the user may click on the
      %   graph and the data points closest to the clicked-on point are
      %   selected. This implies a highlighting of the line (in case of
      %   line graphs) and the display of the data point location in the
      %   title.
      %
      %   In addition, after selection, the use of the arrow keys will move
      %   the selection box in that direction.
      %
      %   NOTE: it has been checked to work correctly for graphical
      %   objects: LINE, IMAGE and SURFACE.
      %
      % SYNTAX:
      %   <obj>.disable_interaxes(VARARGIN);
      %
      % VARARGIN PARAMETERS:
      %   <no input parameters> : INTERAXES will be disabled for all axes
      %   1 input parameter : A vector containing the axes indices to
      %                       disable INTERAXES for
      %   2 input parameters : Two vectors containing the row and column
      %                        indices of the axes to disable INTERAXES for
      %
      
      if nargin > 0, % no inputs
        Iax_ = 1:this.nof_rows*this.nof_columns;
        [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],Iax_);
        if nargin > 1, % indices
          Iax_ = varargin{1};
          [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],Iax_);
          if nargin > 2,
            Ir = varargin{1};
            Ic = varargin{2};
          end
        end
      end
      
      for iter = 1:numel(Ir),
        ir = Ir(iter);
        ic = Ic(iter);
        if this.interaxes_data(ir,ic).valid,
          set(this.hax(ir,ic),'ButtonDownFcn',[]);
          kids = allchild(this.hax(ir,ic));
          bdkids = isprop(kids,'ButtonDownFcn');
          set(kids(bdkids),'ButtonDownFcn',[]);
          % remove selection box
          hselbox = findobj(this.hax(ir,ic),'Tag','selbox');
          delete(hselbox);
          % correct title
          ttl = get(get(this.hax(ir,ic),'Title'),'String');
          if iscell(ttl) && numel(ttl{end}) >= 11,
            if strcmp(ttl{end}(1:11),'Datapoint :'),
              ttl(end) = [];
              set(get(gca,'Title'),'String',ttl);
              set(get(this.hax(ir,ic),'Title'),'String',ttl);
            end % if: wording 'Datapoint :' exists
          end % if: enough title chars exist
          
          
          % reset selection modifications
          fnames = fieldnames(this.interaxes_data(ir,ic).local_selection_mods);
          for ifield = 1:numel(fnames),
            if isprop(this.interaxes_data(ir,ic).selected_object_handle,fnames{ifield}),
              set(this.interaxes_data(ir,ic).selected_object_handle,fnames{ifield},this.interaxes_data(ir,ic).selected_object_props.(fnames{ifield}));
            end
          end
          % save 'interaxes_state'
          this.interaxes_data(ir,ic).valid = false;
          
          
          % reset zoom button
          this.set_zoom_button_position(ir,ic);
          
        end % for: all to-check axes
      end % for: all axes
      
      
    end % fcn: disable interaxes
    
    
    function overwrite_interaxes_selection_mods(this,varargin)
      
      %
      % OVERWRITE_INTERAXES_SELECTION_MODS sets/overwrites the properties
      %   of the selected objects. Any object property may be set. If the
      %   set is left empty, than no difference between a selected and a
      %   not-selected object is seen.
      %
      %   By default, the selection mods are 'LineWidth' == 2, and
      %   'LineStyle' = '-'.
      %
      %   The selection mods are modifyable per axes.
      %
      % SYNTAX:
      %   <obj>.overwrite_interaxes_selection_mods(VARARGIN);
      %
      % VARARGIN PARAMETERS:
      %   2 input parameters :
      %       1.  The index of the axes for which the selection mods must be
      %           changed
      %       2.  A cell array of plot properties to be set as the
      %           selection mods for the specific axes
      %   3 input parameters:
      %       1.  The row index of the axes for which the selections mods
      %           must be changed
      %       2.  It's corresponding column index.
      %       3.  A cell array of plot properties to be set as the
      %           selection mods for the specific axes
      %
      
      if nargin == 3,
        [ic,ir] = ind2sub([this.nof_columns,this.nof_rows],varargin{1});
        input = varargin{2};
      elseif nargin == 4,
        ir = varargin{1};
        ic = varargin{2};
        input = varargin{4};
      end
      haxc = this.hax(ir,ic);
      iinteraxes = find(cat(1,this.interaxes_data(:).axes_handle) == haxc);
      
      if any(iinteraxes),
        this.interaxes_data(iinteraxes).local_selection_mods = input;
      end
      
    end % fcn
    
    
    function legend(this,elmspecs,textlines,varargin)
      
      %
      % LEGEND creates a non-dependend legend to a specific subplot.
      %
      %   It works by supplying a set of element specifications (e.g.,
      %   'r+--', to plot red a dotted line with +'s for markers) and a set
      %   (of equal size) of text lines.
      %
      %   Omission of text lines results in the taking of empty strings for
      %   the elements.
      %
      %   The default location of the legend is the 'northeast' position
      %   inside the axes.
      %
      %   It is possible to add plot properties for every element by
      %   breaking down the cell structure in two more parts. A valid call
      %   to this method is for example:
      %
      %     this.legend({{'ko:','Color',0.7*[1 1 1]},'r+},{'string
      %     1';'string2'});
      %
      %   In the above example, the first legend element has it's color
      %   changed to light grey. The list may be extended at will.
      %
      % SYNTAX:
      %   <obj>.legend(element_specs,textlines,VARARGIN);
      %
      % INPUT PARAMETERS:
      %   element_specs   [cell] An array of plot specifications in the
      %                          formats allowed for functions as 'plots.
      %                          For example 'r+--' is a valid entry.
      %
      %                          A comma-separated list of plot properties
      %                          may be added to modify the plotted line.
      %   textlines       [cell] An array of text lines belonging to the
      %                          element specs
      %
      % VARARGIN PARAMETERS:
      %   1. (location)  [char] A string specifying the location of the
      %                         legend. The legend can be place both inside
      %                         and outside the axes (i.e., total of 20
      %                         positions). The naming scheme is a
      %                         3-character string in which the first two
      %                         chars are the winddirection and the 3rd is
      %                         an 'i' for 'inside' and an 'o' for
      %                         'outside.
      %                         The principal directions 'n', 'e', 's' and
      %                         'w' are doubled. Thus 'nno', means
      %                         'north' and 'outside' placement.
      %                         (in fact there are more than a 100 options,
      %                         but sticking to this keeps the syntax
      %                         simple). 
      %                         Example locations are:
      %                           'nni' = north inside the axes
      %                           'eno' = east north outside (east north
      %                           differs from north east only outside the
      %                           axes. It has to do with resizing the
      %                           axes. Try and find out)
      %                           'nwi' = north west inside (is equal to
      %                           'wni').
      %   2. (print_legend_title) [bool] Indicates whether the legend
      %                                  should have the title 'legend' in
      %                                  bold face on the top row
      %
      
      % find axes
      ir = this.current_axes(1);
      ic = this.current_axes(2);
      
      print_legend_title = this.legend_data(ir,ic).print_legend_title;
      if nargin > 3,
        [locflag,locstr] = this.input_string_check('legend',varargin{1});
        if ~locflag,
          error('subplot_grid:InvalidLocation','The location string provided (= ''%s'') is not valid.',varargin{1});
        end
        this.legend_data(ir,ic).location = locstr;
        if nargin > 4,
          print_legend_title = varargin{2};
        end
      end
      location = this.legend_data(ir,ic).location;
      
      % remove existing
      if this.legend_data(ir,ic).valid,
        this.remove_legend(ir,ic);
      end      
      
      if ~iscell(textlines),
        textlines = {textlines};
      end
      
      if numel(elmspecs) > numel(textlines),
        warning('Number of elements (%d) exceeds number of text lines (%d). Empty lines added!\n',numel(elmspecs),numel(textlines));
        textlines((1+numel(textlines)):numel(elmspecs)) = cell(1,(numel(elmspecs) - numel(textlines)));
      end
      
      nof_elements = numel(elmspecs);
      
      this.hlegend(ir,ic) = axes('Parent',this.hparent,...
        'position',[0 0 1 1]);
      set(this.hlegend(ir,ic),...
        'Box','on',...
        'Tag',sprintf('legend_%d_%d',ir,ic),...
        'YLim',[-nof_elements-1-this.legend_data(ir,ic).print_legend_title 0],...
        'Units','pixels',...
        'NextPlot','add');
      
      
      % set x axis to pixel sizes
      legpos = get(this.hlegend(ir,ic),'Position');
      set(this.hlegend(ir,ic),'XLim',[0 legpos(3)-1]);
      
      totalheight = 0;
      legend_text_width = 0;
      if this.legend_data(ir,ic).print_legend_title,
        hlegtitle = text(0,0,' Legend:',...
          'HorizontalAlignment','left',...
          'VerticalAlignment','top',...
          'FontWeight','bold',...
          'FontSize',8);
        
        set(hlegtitle,'Units','pixels');
        exttop = get(hlegtitle,'Extent');
        textheight = exttop(4);
        totalheight = textheight;
        legend_text_width = exttop(3);
        set(hlegtitle,'Units','data');
      end % i: add 'legend' as title
      
      set(this.hfig,'CurrentAxes',this.hlegend(ir,ic));
      for iel = 1:nof_elements,
        yval = -(iel + this.legend_data(ir,ic).print_legend_title);
        
        nof_props = 0;
        if iscell(elmspecs{iel}),
          elmspec_start = elmspecs{iel}{1};
          nof_props = floor((numel(elmspecs{iel}) - 1)/2);
        else
          elmspec_start = elmspecs{iel};
        end
        hplot = plot(linspace(10,50,3),yval+[0 0 0],elmspec_start);hold on;
        for iprop = 1:nof_props,
          locname = (iprop - 1)*2 + 1;
          locval = iprop*2; %#ok<NASGU>
          eval(['set(hplot,''',elmspecs{iel}{1+locname},''',elmspecs{iel}{1+locval})'])
        end
        hcopy = copyobj(hplot,gca); % copy marker
        set(hcopy,'XData',30,'YData',yval); % create a single marker
        set(hplot,'Marker','none'); % remove 3 old markers
        clear htmp
        htmp = text(65,yval,textlines{iel},...
          'HorizontalAlignment','left',...
          'VerticalAlignment','middle',...
          'FontSize',8);
        
        set(htmp,'Units','pixels');
        ext = get(htmp,'Extent');
        
        set(htmp,'Units','data');
        totalheight = totalheight + ext(4);
        legend_text_width = max(legend_text_width,(ext(3) + ext(1)));
        
      end % for: all elements
      
      legpos(3) = legend_text_width;
      legpos(4) = totalheight;
      set(this.hlegend(ir,ic),'Position',legpos,...
        'XLim',[0 legend_text_width-1],...
        'Box','on',...
        'XTick',[],...
        'YTick',[]);
      
      Isame = find(this.Iax == this.Iax(ir,ic));
      
      for isame = 1:numel(Isame),
        this.legend_data(Isame(isame)).valid = true;
        this.legend_data(Isame(isame)).location = location;
        this.legend_data(Isame(isame)).tag = get(this.hlegend(ir,ic),'Tag');
        this.legend_data(Isame(isame)).print_legend_title = print_legend_title;
        this.hlegend(Isame(isame)) = this.hlegend(ir,ic);
      end
      
      this.reposition_content;
      
    end % fcn: legend
    
    
    function remove_legend(this,varargin)
      
      %
      % REMOVE_LEGEND Remove the legend of one or more subplots.
      %
      % SYNTAX:
      %   <obj>.remove_legend(VARARGIN);
      %
      % VARARGIN PARAMETERS:
      %   <no input parameters> : The legends of all subplots will be
      %                           removed
      %   1 input parameter : A vector containing the axes indices to
      %                       remove legends for
      %   2 input parameters : Two vectors containing the row and column
      %                        indices of the axes to remove the legends for
      %
      
      if nargin > 0, % no inputs
        Iax_ = 1:this.nof_rows*this.nof_columns;
        [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],Iax_);
        if nargin > 1, % indices
          Iax_ = varargin{1};
          [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],Iax_);
          if nargin > 2,
            Ir = varargin{1};
            Ic = varargin{2};
          end
        end
      end
      
      Iax_unq = unique(this.Iax(Ir,Ic));
      nof_ax_unq = numel(Iax_unq);
      for iiax = 1:nof_ax_unq,
        iax = Iax_unq(iiax);
        Isame = find(this.Iax == iax);
        if ~isnan(this.hlegend(Isame(1))),
          
          delete(this.hlegend(Isame(1)));
          this.hlegend(Isame) = nan;
          
        end % if: axes has legend
        
        for isame = 1:numel(Isame),
          fnames = fieldnames(this.legend_data_defaults);
          for iname = 1:numel(fnames),
            this.legend_data(Isame(isame)).(fnames{iname}) = this.legend_data_defaults.(fnames{iname});
          end
        end
        
      end % for: all axes
      
      this.reposition_content;
      
    end % fcn: remove legend
    
    
    function colorbar(this,varargin)
      
      %
      % COLORBAR creates a non-dependend colorbar to a specific subplot.
      %
      %   colorbar without any input parameters creates a colorbar
      %   similarly to matlab's default colorbar creation: it is linked to
      %   the contents.
      %
      %   colorbar(...,'location') creates a colorbar at the specific
      %   location wanted. The syntax of these location strings is set out
      %   below.
      %
      %   colorbar(cmap,...) creates a colorbar according to the colormap
      %   provided. The cmap parameters is a Nx3 matrix of RGB values. This
      %   makes for colorbars not-adhering to the figure's default colormap.
      %   Setting cmap = [] will use the default figure colormap.
      %
      %   colorbar(...,scaled,...) will use the flag scaled to determine
      %   whether the colorbar must be scaled with the contents of the
      %   axes. In case this is set to [], the default ('scaled' = true) is
      %   used.
      %
      %   colorbar(...,datalim,...) sets the colorbar to span the values in
      %   the 2D vector datalim. This can cut-off some outliers, and might
      %   be handy in such cases.
      %
      % SYNTAX:
      %   <obj>.colorbar(VARARGIN);
      %
      %
      % VARARGIN PARAMETERS:
      %   1. (cmap)   [double]  a Nx3 matrix defining the colormap for the
      %                         colorbar. In case set to [], the default
      %                         figure colormap is used.
      %   2. (scaled) [bool]  A flag stating whether the colormap must be
      %                       scaled with the data contents or the remain
      %                       direct. In case set to [], the default for
      %                       the data contents is used.
      %   3. (datalim)  [double]  A 2D vector giving the region within
      %                           which the colorbar must be created. This
      %                           might be useful in case outliers ruin the
      %                           colorbar, and you want a certain cut-off
      %                           value.
      %   last. (location)  [char] A string specifying the location of the
      %                         legend. This input parameter is ALWAYS the
      %                         last on of the set input parameters!.
      %
      %                         The legend can be place both inside
      %                         and outside the axes (i.e., total of 20
      %                         positions). The naming scheme is a
      %                         3-character string in which the first two
      %                         chars are the winddirection and the 3rd is
      %                         an 'i' for 'inside' and an 'o' for
      %                         'outside.
      %
      %                         The principal directions 'n', 'e', 's' and
      %                         'w' are doubled. Thus 'nno', means
      %                         'north' and 'outside' placement.
      %                         (in fact there are more than a 100 options,
      %                         but sticking to this keeps the syntax
      %                         simple. But a check in the method
      %                         'input_string_check' will show all
      %                         possibilities).
      
      %                         Example locations are:
      %                           'nni' = north inside the axes
      %                           'eno' = east north outside (east north
      %                           differs from north east only outside the
      %                           axes. It has to do with resizing the
      %                           axes. Try and find out)
      %                           'nwi' = north west inside (is equal to
      %                           'wni' because it is inside).
      %
      
      
      % find axes to which it belongs
      ax_parent = gca;
      set(ax_parent,'units','pixels','ActivePositionProperty','OuterPosition');
      
      ir = this.current_axes(1);
      ic = this.current_axes(2);
        
      % set properties to auto
      this.colorbar_data(ir,ic).cmap = 'auto';
      this.colorbar_data(ir,ic).scaled = 'auto';
      this.colorbar_data(ir,ic).datalim = 'auto';
      
      % gather information from image
      cmap = get(this.hfig,'Colormap');
      him = findobj(ax_parent,'Type','image');
      if ~isempty(him),
        data_values = unique(get(him,'CData'));
        if isequal(get(him,'CDataMapping'),'direct'),
          scaled = false;
        elseif isequal(get(him,'CDataMapping'),'scaled'),
          scaled = true;
        end
      else
        data_values = 1:size(cmap,1);
        scaled = false;
      end
      
      %% input parameter handling
      % check for location (always in final input parameter)
      iargin_os = 0;
      if nargin > 1,
        if ischar(varargin{end}),
          [locflag,locstr] = this.input_string_check('colorbar',varargin{end});
          if ~locflag,
            error('subplot_grid:InvalidLocation','The location string provided (= ''%s'') is not valid.',varargin{end});
          end
          this.colorbar_data(ir,ic).location = locstr;
          iargin_os = 1;
        end
      end
      location = this.colorbar_data(ir,ic).location;
      
      for iargin = 2:(nargin - iargin_os),
        if iargin > 1,
          if ~isempty(varargin{1}),
            cmap = varargin{1}; % generally taken from figure to which cbar belongs
            this.colorbar_data(ir,ic).cmap = cmap;
          end
          if iargin > 2,
            scaled = varargin{2}; % generally taken from image to which cbar belongs
            this.colorbar_data(ir,ic).scaled = scaled;
            if iargin > 3,
              data_values = varargin{3}; % generally taken from image to which cbar belongs
              this.colorbar_data(ir,ic).datalim = [min(data_values(:)),max(data_values(:))];
            end % if: more than three
          end % if: more than 2
        end % if: more than 1
      end % for: all varargins
      nof_colors = size(cmap,1);
      clim = [min(data_values(:)),max(data_values(:))];
      
      % remove existing
      if this.colorbar_data(ir,ic).valid,
        this.remove_colorbar(ir,ic);
      end
      
      % initiate axes
      this.hcolorbar(ir,ic) = axes('Parent',this.hparent,...
        'position',[0 0 1 1]); % initiation is ALWAYS in normalized units
      
      set(this.hcolorbar(ir,ic),...
        'Box','on',...
        'Tag',sprintf('colorbar_%d_%d',ir,ic),...
        'Units','pixels',...
        'NextPlot','add');
      
      % plot (scaled) image
      xvals = ones(1,nof_colors);
      if scaled, % imagesc
        yvals = linspace(clim(1),clim(2),nof_colors);
      else % unscaled (image)
        yvals = 1:nof_colors;
      end
      
      switch location(1:2),
        case {'ww','ee'},
          imagesc(xvals,...
            yvals,...
            permute(shiftdim(cmap.',-1),[3,1,2]));axis xy;
            set(this.hcolorbar(ir,ic),...
                'XLim',1/2 + [0 1],...
                'XTick',[],...
                'YLim',clim);
        case {'nn','ss'},
          imagesc(yvals,...
            xvals,...
            shiftdim(cmap,-1));axis xy;
            set(this.hcolorbar(ir,ic),...
                'YLim',1/2 + [0 1],...
                'YTick',[],...
                'XLim',clim);
      end

           
      %% find if it is a merged axes
      this.colorbar_data(ir,ic).valid = true; % set flag to true
      this.colorbar_data(ir,ic).location = location;
      this.colorbar_data(ir,ic).tag = get(this.hcolorbar(ir,ic),'Tag');
      Isame = find(this.Iax == this.Iax(ir,ic));
      fnames = fieldnames(this.colorbar_data(ir,ic));
      for iisame = 1:numel(Isame),
        isame = Isame(iisame);
        for ifld = 1:numel(fnames),
          this.colorbar_data(isame).(fnames{ifld}) = this.colorbar_data(ir,ic).(fnames{ifld});
        end
        this.hcolorbar(isame) = this.hcolorbar(ir,ic);
      end
      
      % reposition and set current axes again
      this.reposition_content;
      
    end % fcn: colorbar
    
    
    function remove_colorbar(this,varargin)
      %
      % REMOVE_COLORBAR Remove the colorbar of one or more subplots.
      %
      % SYNTAX:
      %   <obj>.remove_colorbar(VARARGIN);
      %
      % VARARGIN PARAMETERS:
      %   <no input parameters> : The colorbars of all subplots will be
      %                           removed
      %   1 input parameter : A vector containing the axes indices to
      %                       remove colorbars for
      %   2 input parameters : Two vectors containing the row and column
      %                        indices of the axes to remove the colorbars for
      %
      
      if nargin > 0, % no inputs
        Iax_ = 1:this.nof_rows*this.nof_columns;
        [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],Iax_);
        if nargin > 1, % indices
          Iax_ = varargin{1};
          [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],Iax_);
          if nargin > 2,
            Ir = varargin{1};
            Ic = varargin{2};
          end
        end
      end
      
      Iax_unq = unique(this.Iax(Ir,Ic));
      nof_ax_unq = numel(Iax_unq);
      for iiax = 1:nof_ax_unq,
        iax = Iax_unq(iiax);
        Isame = find(this.Iax == iax);
        if ~isnan(this.hcolorbar(Isame(1))),
          
          delete(this.hcolorbar(Isame(1)));
          this.hcolorbar(Isame) = nan;
          
        end % if: axes has legend
        
        for isame = 1:numel(Isame),
          fnames = fieldnames(this.colorbar_data_defaults);
          for iname = 1:numel(fnames),
            this.colorbar_data(Isame(isame)).(fnames{iname}) = this.colorbar_data_defaults.(fnames{iname});
          end
        end
        
        
      end % for: all axes
      
      this.reposition_content;
      
    end % remove_colorbar

    
    function set_padding(this,varargin)
      
      %
      % SET_PADDING (re)sets the whitespace padding between axes.
      %
      %   The input is in pixels and should be a 1x4 vector for all 4
      %   sides of the axes.
      %
      % SYNTAX:
      %   <obj>.set_padding(VARARGIN);
      %
      % VARARGIN PARAMETERS:
      %   <no input>    : The padding is reset to the default value
      %                   of 5 pixels around.
      %   parameter 1   : 1x4 vector containing the padding in pixels
      %                   for all 4 sides. The format is [left,bottom,right,top]
      %
      
      this.loose_inset_px = this.loose_inset_px_default;
      if nargin > 1,
        this.loose_inset_px = varargin{1};
      end
      
      set(this.hax(:),'LooseInset',this.loose_inset_px);
      this.reposition_content;
      
    end % fcn: set_padding
    
    
    function zoomlink_axes(this,varargin)
      
      %
      % ZOOMLINK_AXES (un)links a set of axes during zooming in.
      %
      %   The input can be a cell array of vectors, for which a single
      %   cell contains a vector of axes indices to be linked.
      %
      %   Example: zoomlink_axes({[1,3,6]}) linkes axes 1,3 and 6 on
      %   zooming in. The axes will be plot underneath eachother
      %   starting with the lowest index on top.
      %
      % SYNTAX:
      %   <obj>.zoomlink_axes(VARARGIN);
      %
      % VARARGIN PARAMETER:
      %   <no input>          Unlinks all linked axes
      %   1 input parameter   A cell array containing one or more
      %                       axes indices vectors. Every vectors
      %                       contains the axes indices to be linked
      %                       on zooming in.
      %
      
      this.zoomlinklist = {};
      if nargin > 1,
        this.zoomlinklist = varargin{1};
      end
      
      % reset all axes
      for ir = 1:this.nof_rows,
        for ic = 1:this.nof_columns,
          this.subplotzoom_data(ir,ic).zoomlinked_with = sub2ind([this.nof_columns,this.nof_rows],ic,ir);
        end
      end
      
      % set new ones
      for icell = 1:numel(this.zoomlinklist),
        nof_links = numel(this.zoomlinklist{icell});
        for ilink = 1:nof_links,
          index = this.zoomlinklist{icell}(ilink);
          [ic,ir] = ind2sub([this.nof_columns,this.nof_rows],index);
          this.subplotzoom_data(ir,ic).zoomlinked_with = this.zoomlinklist{icell};
        end % for: all linked axes
      end % for: all cells
      nof_axes = numel(this.hax);
      
    end % fcn: zoomlink_axes
    
    
    function redraw(this)
      
      %
      % REDRAW redraws the figure and its contents.
      %
      %   this.redraw redraws the figure and resets its content.
      %   Especially useful when some colorbars and/or legends are
      %   present.
      %
      
      this.reposition_content;
    end % fcn: redraw
    
    
    function figplace(this,varargin)
      
      %
      % FIGPLACE  places the figure in a grid of figures on the screen
      %
      %   this.figplace without input parameters maximizes the figure on
      %   the first screen (in case of multiple screens).
      %
      %   this.figplace(Ngrid,ifig) creates a grid for Ngrid figures that
      %   best fits the monitor size and configuration. The place index
      %   ifig counts starting from the upper left grid position
      %   starting of in horizontal direction.
      %
      %   this.figplace(Rgrid,Cgrid,ifig) creates a grid with Rgrid rows
      %   and Cgrid columns. The figure is again placed in index ifig.
      %
      %   this.figplace(Rgrid,Cgrid,rfig,cfig) creates a grid with
      %   Rgrid rows and Cgrid columns. The figure is placed at grid
      %   row position rfig and grid column position cfig.
      %
      
      mon_pos = get(0,'MonitorPositions');
      nof_mons = size(mon_pos,1);
      if nargin == 1,
        set(this.hfig,'Units','normalized','Position',[0 0 1 1]);
        return
      end
      if nargin == 2,
        input = varargin{1};
        set(0,'Units','pixels');
        screenpos = get(0,'ScreenSize');
        ny = screenpos(4);
        nx = screenpos(3);
        scaling = 1;
        if numel(input) > 1,
          scaling = eval(sprintf('1%s',input(2:end)));
        end
        
        switch input(1),
          case 'p',
            % get scaling
            nx_wanted = ny/sqrt(2);
            ny_wanted = ny;
            
          case 'l',
            
            nx_wanted = nx;
            ny_wanted = nx/sqrt(2);
            
        end % switch: a4 type sizing
        set(this.hfig,'Units','pixels','Position',[1 1 scaling*nx_wanted scaling*ny_wanted]);
        
        return
      end
      if nargin == 3,
        nof_fig_cols = round(ceil(nof_mons*2*sqrt(varargin{1}))/2);
        nof_fig_rows = round(floor(2*sqrt(varargin{1})/nof_mons)/2);
        ibox = varargin{2};
        [icol,irow] = ind2sub([nof_fig_cols,nof_fig_rows],ibox);
      elseif nargin >= 4,
        nof_fig_rows = varargin{1};
        nof_fig_cols = varargin{2};
        ibox = varargin{3};
        [icol,irow] = ind2sub([nof_fig_cols,nof_fig_rows],ibox);
        if nargin == 5,
          irow = varargin{3};
          icol = varargin{4};
        end
      end
      
      prevunits = get(this.hfig,'Units');
      set(this.hfig,'Unit','normalized');
      hz_start = nof_mons*(icol - 1)/nof_fig_cols;
      vt_start = (nof_fig_rows - irow)/nof_fig_rows;
      
      this.hfig.Units = 'normalized';
      this.hfig.Position = [hz_start,vt_start,nof_mons/nof_fig_cols,1/nof_fig_rows];
      set(this.hfig,'Units',prevunits);
      
      pause(0.2)
      this.reposition_content;
      
    end % fcn: figplace
    
    
    function sync_axes(this,varargin)
      
      %
      % SYNC_AXES synchronizes the x and/or y axes of different axes
      %
      %   this.sync_axes without parameters sets the x and y limits of
      %   all axes such that all data is contained (type = 'wide')
      %
      %   this.sync_axes(H,...) with the set of axes handles H sets the
      %   limits of the wanted axes of only the axes set H.
      %
      %   this.sync_axes(I,...) with the indices vector I synchronizes
      %   the axes with indices I.
      %
      %   this.sync_axes(...,T,...) uses the type indicator string T to
      %   select how the limits of the axes to synch are to be
      %   determined. Options are:
      %     1. 'wide'   (default) This sets the limits such that all
      %                 data is contained within the axes limits.
      %     2. 'tight'  This sets the limits such that the largest
      %                 overlapping limits are selected.
      %     3. 'median' This sets the median limits of the axes. Useful
      %                 when one graph has outlying limits.
      %
      %   this.sync_axes(...,A,...) uses the axes indicator to
      %   determine which axes to sync. Options are any combination of 'x', 'y' and 'c':
      %     1. 'x'  syncs the horizontal axes
      %     2. 'y'  syncs the vertical axes
      %     3. 'c'  syncs the color axes (useful for indexed images)
      %
      %   this.sync_axes(...,b,...) sets the vertical padding to b
      %     percent of the entire data range. b can be a 2-element vector
      %     in which b(1) is the bottom padding and b(2) the top padding.
      %     In case b = a single value, this value will be used for
      %     both top and bottom padding.
      %
      %   Using sync_axes will also ensure a linking on zooming.
      %
      
      
      perc_buffer = 0; %
      sync_dir_list = {'x','y','xy','xc','yc','xyc','c'};
      sync_type_list = {'wide','tight','median'};
      sync_dir = 'xy'; % option: 'x', 'y', 'c' or in any combination
      sync_type = 'wide'; % options: wide, tight, mean
      haxes = this.hax(:);
      argoffset = 0;
      
      if nargin > 1,
        if isnumeric(varargin{1}),
          if ishandle(varargin{1}),
            haxes = varargin{1};
          else
            haxes = this.hax(varargin{1});
          end
          argoffset = 1;
        end
      end
      
      for ivarargin = (1 + argoffset):numel(varargin)
        if ischar(varargin{ivarargin})
          if ismember(varargin{ivarargin},sync_dir_list),
            sync_dir = varargin{ivarargin};
          elseif ismember(varargin{ivarargin},sync_type_list),
            sync_type = varargin{ivarargin};
          end
        else % must be buffer value
          perc_buffer = varargin{ivarargin};
        end
      end % for: all remaining input parameters
      
      if numel(perc_buffer) == 1,
        perc_buffer = perc_buffer*[1 1];
      end
      
      nof_axes = numel(haxes);
      xminax = inf(nof_axes,1);
      yminax = inf(nof_axes,1);
      xmaxax = -inf(nof_axes,1);
      ymaxax = -inf(nof_axes,1);
      cminax = inf(nof_axes,1);
      cmaxax = -inf(nof_axes,1);
      for iax = 1:nof_axes,
        
        climkid = get(haxes(iax),'CLim');
        cminax(iax) = min(cminax(iax),min(climkid));
        cmaxax(iax) = max(cmaxax(iax),max(climkid));
        hkids = findobj(haxes(iax),'Type','line','-or','Type','image','-or','Type','patch');
        for ikid = 1:numel(hkids),
          xdatakid = get(hkids(ikid),'XData');
          ydatakid = get(hkids(ikid),'YData');
          xdatakid(isnan(xdatakid)) = [];
          xdatakid(isinf(xdatakid)) = [];
          ydatakid(isnan(ydatakid)) = [];
          ydatakid(isinf(ydatakid)) = [];
          xminax(iax) = min(xminax(iax),min(xdatakid(:)));
          xmaxax(iax) = max(xmaxax(iax),max(xdatakid(:)));
          yminax(iax) = min(yminax(iax),min(ydatakid(:)));
          ymaxax(iax) = max(ymaxax(iax),max(ydatakid(:)));
        end % for: all kids
      end % for: all axes to sync
      
      switch sync_type,
        case 'wide',
          xlim = [min(xminax),max(xmaxax)];
          ylim = [min(yminax),max(ymaxax)];
          clim = [min(cminax),max(cmaxax)];
          
        case 'tight',
          xlim = [max(xminax),min(xmaxax)];
          ylim = [max(yminax),min(ymaxax)];
          clim = [max(cminax),min(cmaxax)];
          
        case 'median'
          xlim = [median(xminax),median(xmaxax)];
          ylim = [median(yminax),median(ymaxax)];
          clim = [median(cminax),median(cmaxax)];
          
      end % switch: sync type
      
      if strfind(sync_dir,'x'),
        set(haxes,'XLim',xlim);
      end
      if strfind(sync_dir,'y'),
        padding = [-1,1].*perc_buffer*(ylim(2) - ylim(1))/100;
        set(haxes,'YLim',ylim + padding);
      end
      if strfind(sync_dir,'c'),
        set(haxes,'CLim',clim);
      end
      
      ic = strfind(sync_dir,'c');
      sync_dir(ic) = [];
      if any(sync_dir),
        linkaxes(haxes,sync_dir);
      end
    end % fcn: sync_axes
    
    
    function reposition_content(this)
      
      %% loaded from a file?
      if ~ishandle(this.hax(1)),
        warning('subplot_grid:LoadedFigure','File loaded! Old handles to be overwritten!\n');
        this.reset_handles
      end
      %% figure position
      set(this.hfig,'Units','pixels');
      
      % set parent relative to figure position (pixels -> normalized ->
      % pixels)
      padding = 0;
      if this.in_panel,
        padding = this.panel_padding;
        set(this.hparent,'Units','normalized','Position',this.pos_parent_in_figure);
      end
      set(this.hparent,'Units','pixels');
      
      parpos = get(this.hparent,'Position') + padding*[1 1 -2 -2]; % position vector in pixels
      
      hleftover = parpos(3) - max(this.titles.rowtitles_left.txtbox_sizes) - max(this.titles.rowtitles_right.txtbox_sizes);
      vleftover = parpos(4) - this.titles.title.txtbox_sizes - this.titles.subtitle.txtbox_sizes - max(this.titles.coltitles_top.txtbox_sizes) - max(this.titles.coltitles_bottom.txtbox_sizes);
      
      
      %% title
      if this.titles.title.valid,
        pos = [0,...
          parpos(4) - this.titles.title.txtbox_sizes,...
          parpos(3),...
          this.titles.title.txtbox_sizes];
        set(this.titles.title.hax,'Units','pixels','Position',pos);
      end
      
      
      %% subtitle
      if this.titles.subtitle.valid,
        pos = [0,...
          parpos(4) - this.titles.title.txtbox_sizes - this.titles.subtitle.txtbox_sizes,...
          parpos(3),...
          this.titles.subtitle.txtbox_sizes];
        set(this.titles.subtitle.hax,'Units','pixels','Position',pos);
      end
      
      
      %% row titles
      % left
      if this.titles.rowtitles_left.valid,
        nof_txt = numel(this.titles.rowtitles_left.hax);
        offsets = 1 - [cumsum(this.titles.rowtitles_left.ratios)];
        for itxt = 1:nof_txt,
          pos = [0,...
            max(this.titles.coltitles_bottom.txtbox_sizes) + offsets(itxt)*vleftover,...
            this.titles.rowtitles_left.txtbox_sizes(itxt),...
            this.titles.rowtitles_left.ratios(itxt)*vleftover];
          set(this.titles.rowtitles_left.hax(itxt),'Units','pixels','Position',pos);
        end % for: all texts
      end
      
      % right
      if this.titles.rowtitles_right.valid,
        nof_txt = numel(this.titles.rowtitles_right.hax);
        offsets = 1 - [cumsum(this.titles.rowtitles_right.ratios)];
        for itxt = 1:nof_txt,
          pos = [parpos(3) - max(this.titles.rowtitles_right.txtbox_sizes),...
            max(this.titles.coltitles_bottom.txtbox_sizes) + offsets(itxt)*vleftover,...
            this.titles.rowtitles_right.txtbox_sizes(itxt),...
            this.titles.rowtitles_right.ratios(itxt)*vleftover];
          
          set(this.titles.rowtitles_right.hax(itxt),'Units','pixels','Position',pos);
        end
      end
      
      %% column titles
      % top
      if this.titles.coltitles_top.valid,
        nof_txt = numel(this.titles.coltitles_top.hax);
        offsets = [0,cumsum(this.titles.coltitles_top.ratios)];
        for itxt = 1:nof_txt,
          pos = [max(this.titles.rowtitles_left.txtbox_sizes) + offsets(itxt)*hleftover,...
            parpos(4) - this.titles.title.txtbox_sizes - this.titles.subtitle.txtbox_sizes - max(this.titles.coltitles_top.txtbox_sizes),...
            this.titles.coltitles_top.ratios(itxt)*hleftover,...
            this.titles.coltitles_top.txtbox_sizes(itxt)];
          set(this.titles.coltitles_top.hax(itxt),'Units','pixels','Position',pos);
        end % for: all txts
      end
      
      % bottom
      if this.titles.coltitles_bottom.valid,
        nof_txt = numel(this.titles.coltitles_bottom.hax);
        offsets = [0,cumsum(this.titles.coltitles_bottom.ratios)];
        for itxt = 1:nof_txt,
          pos = [max(this.titles.rowtitles_left.txtbox_sizes) + offsets(itxt)*hleftover,...
            0,...
            this.titles.coltitles_bottom.ratios(itxt)*hleftover,...
            this.titles.coltitles_bottom.txtbox_sizes(itxt)];
          set(this.titles.coltitles_bottom.hax(itxt),'Units','pixels','Position',pos);
        end % for: all txts
      end
      
      
      %% axes
      % determine plot box dimensions
      axwidth_new = hleftover/this.nof_columns;
      axheight_new = vleftover/this.nof_rows;
      
      Iax_unq = unique(this.Iax);
      for iiax = 1:numel(Iax_unq),
        [Rfnd,Cfnd] = find(this.Iax == Iax_unq(iiax));
        rowspan = numel(unique(Rfnd));
        colspan = numel(unique(Cfnd));
        rax = this.Rax(Rfnd(1),Cfnd(1));
        cax = this.Cax(Rfnd(1),Cfnd(1));
        unitstring = get(this.hax(rax,cax),'Units');
        
        pos_new = [max(this.titles.rowtitles_left.txtbox_sizes) + (cax - 1)*axwidth_new,...
          max(this.titles.coltitles_bottom.txtbox_sizes) + (this.nof_rows - rax)*axheight_new,...
          colspan*axwidth_new,...
          rowspan*axheight_new];
        set(this.hax(rax,cax),'Units','pixels','OuterPosition',pos_new,'ActivePositionProperty','OuterPosition');
        set(this.hax(rax,cax),'Units',unitstring); % reset to previous setting
        
        this.place_colorbar(rax,cax);
        this.place_legend(rax,cax);
        this.set_zoom_button_position(rax,cax);
        
        if this.hidden_axes(rax,cax) || this.hidden_axes_manual(rax,cax),
          this.hide_axes('zoom',rax,cax);
        end
        
        if this.zoomed(rax,cax),
          this.expand_axes(rax,cax);
        end

      end % for: all unique axes
      
      this.set_gca;
      
    end % fcn: reposition_content
    
    
  end  % Methods
  
  
  methods(Access=private)
    
    
    function reset_handles(this)
      
      this.hfig = gcf;
      
      % titles
      this.titles.title.hax = findobj(this.hparent,'Type','axes','-and','Tag','figtitle');
      this.titles.title.htxt = findobj(this.hparent,'Type','text','-and','Tag','figtitle');
      this.titles.subtitle.hax = findobj(this.hparent,'Type','axes','-and','Tag','subfigtitle');
      this.titles.subtitle.htxt = findobj(this.hparent,'Type','text','-and','Tag','subfigtitle');
      for itxt = 1:numel(this.titles.rowtitles_left.hax),
        this.titles.rowtitles_left.hax(itxt) = findobj(this.hparent,'Type','axes','-and','Tag',sprintf('rowtitles_left_%d',itxt));
        this.titles.rowtitles_left.htxt(itxt) = findobj(this.hparent,'Type','text','-and','Tag',sprintf('rowtitles_left_%d',itxt));
      end
      for itxt = 1:numel(this.titles.rowtitles_right.hax),
        this.titles.rowtitles_right.hax(itxt) = findobj(this.hparent,'Type','axes','-and','Tag',sprintf('rowtitles_right_%d',itxt));
        this.titles.rowtitles_right.htxt(itxt) = findobj(this.hparent,'Type','text','-and','Tag',sprintf('rowtitles_right_%d',itxt));
      end
      for itxt = 1:numel(this.titles.coltitles_top.hax),
        this.titles.coltitles_top.hax(itxt) = findobj(this.hparent,'Type','axes','-and','Tag',sprintf('coltitles_top_%d',itxt));
        this.titles.coltitles_top.htxt(itxt) = findobj(this.hparent,'Type','text','-and','Tag',sprintf('coltitles_top_%d',itxt));
      end
      for itxt = 1:numel(this.titles.coltitles_bottom.hax),
        this.titles.coltitles_bottom.hax(itxt) = findobj(this.hparent,'Type','axes','-and','Tag',sprintf('coltitles_bottom_%d',itxt));
        this.titles.coltitles_bottom.htxt(itxt) = findobj(this.hparent,'Type','text','-and','Tag',sprintf('coltitles_bottom_%d',itxt));
      end
      
      % axes
      Iax_unq = unique(this.Iax);
      for iiax = 1:numel(Iax_unq),
        iax = Iax_unq(iiax);
        Isame = find(this.Iax == iax);
        [ic,ir] = ind2sub([this.nof_columns,this.nof_rows],iax);
        
        for iisame = 1:numel(Isame),
          this.hax(Isame(iisame)) = findobj(this.hfig,'Tag',sprintf('hax_%d_%d',ir,ic)); % axes handles
          this.subplotzoom_data(Isame(iisame)).zm_btn = findobj(this.hfig,'Tag',sprintf('subplotzoom_%d_%d',ir,ic)); % subplotzoom handles
          if this.legend_data(ir,ic).valid,
            this.hlegend(Isame(iisame)) = findobj(this.hfig,'Tag',this.legend_data(ir,ic).tag);
          end
          if this.colorbar_data(ir,ic).valid,
            this.hcolorbar(Isame(iisame)) = findobj(this.hfig,'Tag',this.colorbar_data(ir,ic).tag);
          end
        end
        
      end % for: all axes
      
      % set parent
      this.hparent = get(this.hax(1),'Parent');
      
      % create output object
      assignin('base','o_subplot_grid',this);
      
    end % fcn : reset_handles
    
    
    function set_zoom_button_position(this, ir, ic)
      
      if this.subplotzoom_enabled(ir,ic),
        % *** corner ***
        set(this.hfig,'Units','pixels');
        set(this.hax(ir,ic),'Units','pixels');     % Set axis units
        pos = get(this.hax(ir,ic),'Position');     % Load current axis position
        corner.x = pos(1)+pos(3)-0;    % X coordinate of top right corner of axis position
        corner.y = pos(2)+pos(4)-0;   % Y coordinate of top right corner of axis position
        set(this.subplotzoom_data(ir,ic).zm_btn,...
          'position',[corner.x-this.zoom_button_size_x corner.y-this.zoom_button_size_y this.zoom_button_size_x this.zoom_button_size_y]);
        
        %               pause(0.1)
        %               keyboard
        %             hkids = get(this.subplotzoom_data(ir,ic).zm_btn.Parent,'Children')
        %             izm = find(hkids.double == this.subplotzoom_data(ir,ic).zm_btn.double)
        % %             if izm > 0, % then must be moved to top
        %               Iorder = [setdiff(1:numel(hkids),izm),izm]
        %               set(this.subplotzoom_data(ir,ic).zm_btn.Parent,'Children',hkids(Iorder))
        % %             end
        %
        %             keyboard
        %             %DWK: Inlining the layering command provides modest speed improvement
        %             %                         uistack(this.subplotzoom_data(ir,ic).zm_btn,'top');
        %             parentObj = get(this.subplotzoom_data(ir,ic).zm_btn,'Parent')
        %             allDescendents = get(parentObj,'Children')
        %             this.subplotzoom_data(ir,ic).zm_btn.double
        %             keyboard
        %             % Only changing the layering if necessary makes a big difference
        %             zmBtnIndex = find(allDescendents.double == this.subplotzoom_data(ir,ic).zm_btn.double,1)
        %             thisAXIndex = find(allDescendents.double == this.hax(ir,ic),1)
        %             if zmBtnIndex < thisAXIndex,
        %               newOrder = [allDescendents(allDescendents~=this.subplotzoom_data(ir,ic).zm_btn);this.subplotzoom_data(ir,ic).zm_btn]
        % %               set(parentObj,'Children',allDescendents([)
        %             end
        
        %             keyboard
        %             set(this.subplotzoom_data(ir,ic).zm_btn,'units','pixels');
        %             set(this.hax(ir,ic),'units','normalized');     % Set axis units
      end % if: subplotzoom enabled
    end % set zoom_button position
    
    
    function subplotzoom_cb(this,ir,ic)
      
      %
      % callback that handles the subplotzoom functionality
      %
      
      if this.zoomed(ir,ic), % if: zoomed-in
        
        this.collapse_axes;
        
      else % not yet zoomed in
        this.expand_axes(ir,ic);
        
      end % ifelse: zoomed in or out??
      
    end % fcn: subplotzoom_cb
    
    
    function expand_axes(this,ir,ic,varargin)
      
      %% switch
      extraction_mode = false;
      if nargin > 3,
        extraction_mode = varargin{1};
      end
      
      if extraction_mode,
        set([this.titles.title.htxt;
          this.titles.subtitle.htxt],'Visible','off');
      end
      
      %% switch OFF titles
      set([this.titles.rowtitles_left.htxt(:);
        this.titles.rowtitles_right.htxt(:);
        this.titles.coltitles_top.htxt(:);
        this.titles.coltitles_bottom.htxt(:)],'Visible','off');
      
      %% switch of all axes
      this.hide_axes('zoom');
      
      %% figure position
      set(this.hparent,'Units','pixels');
      parpos = get(this.hparent,'Position');
      
      % set leftover pixels
      vleftover = parpos(4); % to be modified with figure title
      if ~extraction_mode,
        vleftover = vleftover -  this.titles.title.txtbox_sizes - this.titles.subtitle.txtbox_sizes;
      end
      
      %% handle zoomlinks
      zoomlinked_with = sort(this.subplotzoom_data(ir,ic).zoomlinked_with,'ascend');
      nof_zoomlinked = numel(zoomlinked_with);
      
      if extraction_mode,
        nof_zoomlinked = 1;
      end
      
      for izm = 1:nof_zoomlinked,
        if extraction_mode,
          iir = ir;
          iic = ic;
        else
          [iic,iir] = ind2sub([this.nof_columns,this.nof_rows],zoomlinked_with(izm));
        end
        
        pos_exp = [0,...
          (izm - 1)*vleftover/nof_zoomlinked,...
          parpos(3),...
          vleftover/nof_zoomlinked];
        
        set(this.hax(iir,iic),'Units','pixels','OuterPosition',pos_exp,'Visible','on');
        
        this.zoomed(this.Iax == zoomlinked_with(izm)) = true; % set flag to zoomed
        
        % reset zoom button
        this.show_axes('zoom',iir,iic);
        this.place_colorbar(iir,iic);
        this.place_legend(iir,iic);
        this.set_zoom_button_position(iir,iic);
        
      end % for: all zoomlinked axes to expand
      
      
    end % fcn: expand_axes
    
    
    function collapse_axes(this)
      
      this.show_axes('zoom'); % show everything again
      
      set([this.titles.rowtitles_left.htxt(:);
        this.titles.rowtitles_right.htxt(:);
        this.titles.coltitles_top.htxt(:);
        this.titles.coltitles_bottom.htxt(:);
        this.titles.title.htxt;
        this.titles.subtitle.htxt],'Visible','on');
      
      this.zoomed(:) = false;
      this.reposition_content;
      
      
    end % fcn: collapse_axes
    
    
    function interaxes(this,src,evt,ir,ic)
      
      % find all plot objects which are allowed
      kidstypes = get(allchild(this.hax(ir,ic)),'Type');
      kids = allchild(this.hax(ir,ic));
      hobjs = kids(ismember(kidstypes,this.interaxes_supported_types));
      
      % remove selection box
      hselbox = findobj(this.hax(ir,ic),'Tag','selbox');
      hobjs = setdiff(hobjs,hselbox);
      
      % axial ratios
      ylim = get(this.hax(ir,ic),'YLim');
      xlim = get(this.hax(ir,ic),'XLim');
      zlim = get(this.hax(ir,ic),'ZLim');
      xrange = xlim(2) - xlim(1);
      yrange = ylim(2) - ylim(1);
      zrange = zlim(2) - zlim(1);
      axial_ratiox = yrange/xrange;
      axial_ratioz = yrange/zrange;
      clear xrange yrange zrange kidstypes kids
      
      % undo selection properties
      fnames = fieldnames(this.interaxes_data(ir,ic).local_selection_mods);
      for ifield = 1:numel(fnames),
        if isprop(this.interaxes_data(ir,ic).selected_object_handle,fnames{ifield}),
          set(this.interaxes_data(ir,ic).selected_object_handle,this.interaxes_data(ir,ic).selected_object_props);
        end
      end
      
      %==============================================================
      % KEY PRESSED
      %==============================================================
      
      if src == gcf,
        
        
        %============== NOTHING SELECTED ======================%
        if ~ishandle(this.interaxes_data(ir,ic).selected_object_handle),
          % do nothing
          return
        end
        
        
        %============== SELECTION EXISTS ======================%
        hsel = this.interaxes_data(ir,ic).selected_object_handle; % handle of selected on object
        graphtype = get(hsel,'Type');
        
        switch graphtype,
          
          
          %************** KEYPRES - IMAGE/SURFACE ******************
          
          case {'image','surface'},
            
            xdata = get(hsel,'XData');
            ydata = get(hsel,'YData');
            cdata = get(hsel,'CData');
            if isprop(hsel,'ZData'),
              zdata = get(hsel,'ZData');
            end
            
            if numel(xdata) == 2,
              xdata = xdata(1):xdata(2);
              ydata = ydata(1):ydata(2);
              [xdata,ydata] = meshgrid(xdata,ydata);
            end
            if isvector(xdata),
              [xdata,ydata] = meshgrid(xdata,ydata);
            end
            
            xpos = get(hselbox,'XData');
            ypos = get(hselbox,'YData');
            
            Ix = find(xdata == xpos);
            Iy = find(ydata == ypos);
            
            [Rthis,Cthis] = ind2sub(size(xdata),intersect(Ix,Iy));
            Rnew = Rthis;
            Cnew = Cthis;
            
            switch evt.Key
              case 'leftarrow',
                if Cthis == 1,
                  Cnew = size(xdata,2);
                else
                  Cnew = Cthis - 1;
                end
                
              case 'rightarrow',
                if Cthis == size(xdata,2),
                  Cnew = 1;
                else
                  Cnew = Cthis + 1;
                end
                
              case 'uparrow',
                switch get(this.hax(ir,ic),'YDir'),
                  case 'reverse',
                    if Rthis == 1,
                      Rnew = size(xdata,1);
                    else
                      Rnew = Rthis - 1;
                    end
                    
                  case 'normal',
                    if Rthis == size(xdata,1),
                      Rnew = 1;
                    else
                      Rnew = Rthis + 1;
                    end
                end
                
              case 'downarrow',
                
                switch get(this.hax(ir,ic),'YDir'),
                  case 'reverse',
                    if Rthis == size(xdata,1);
                      Rnew = 1;
                    else
                      Rnew = Rthis + 1;
                    end
                    
                  case 'normal',
                    if Rthis == 1;
                      Rnew = size(xdata,1);
                    else
                      Rnew = Rthis - 1;
                    end
                end
                
              otherwise
                % do nothing
                
            end % switch: key indicator
            
            if exist('zdata','var'),
              posstr = sprintf('Datapoint : [%g ; %g ; %g ; %g]',xdata(Rnew,Cnew),ydata(Rnew,Cnew),zdata(Rnew,Cnew),cdata(Rnew,Cnew));
            else
              posstr = sprintf('Datapoint : [%g ; %g ; %g]',xdata(Rnew,Cnew),ydata(Rnew,Cnew),cdata(Rnew,Cnew));
            end
            
            %************** KEYPRES - LINE **************************
            
          case {'line'},
            nof_objs = numel(hobjs);
            
            xdata = get(hsel,'XData');
            ydata = get(hsel,'YData');
            
            xdiff = axial_ratiox*(xdata - get(hselbox,'XData'));
            ydiff = ydata - get(hselbox,'YData');
            dist = sqrt(xdiff.^2 + ydiff.^2);
            Ithis = find(dist == min(dist(:)),1);
            Cnew = Ithis;
            Rnew = 1;
            if Ithis == 1,
              xwindow(1) = -(xdata(Ithis+1) - xdata(Ithis));
            else
              xwindow(1) = xdata(Ithis-1) - xdata(Ithis);
            end
            if Ithis == numel(xdiff),
              xwindow(2) = xdata(Ithis) - xdata(Ithis-1);
            else
              xwindow(2) = xdata(Ithis+1) - xdata(Ithis);
            end
            xwindow = xdata(Ithis) + xwindow;
            
            
            switch evt.Key,
              
              case 'leftarrow',
                Ih = find(xdata >= xlim(1) & xdata <= xlim(2));
                Iv = find(ydata >= ylim(1) & ydata <= ylim(2));
                C = intersect(Ih,Iv);
                Cnew = C(find(C < Ithis,1,'last'));
                if isempty(Cnew),
                  Cnew = C(end);
                end
                
                
              case 'rightarrow',
                Ih = find(xdata >= xlim(1) & xdata <= xlim(2));
                Iv = find(ydata >= ylim(1) & ydata <= ylim(2));
                C = intersect(Ih,Iv);
                Cnew = C(find(C > Ithis,1,'first'));
                if isempty(Cnew),
                  Cnew = C(1);
                end
                
                
              case 'uparrow', % go to other dataset
                
                mindist = inf;
                iobj_closest = nan; % init
                for iobj = 1:nof_objs,
                  % get x/y data
                  xdata1 = get(hobjs(iobj),'XData');
                  ydata1 = get(hobjs(iobj),'YData');
                  [Rvalid,Cvalid] = find(xdata1 > xwindow(1) & xdata1 < xwindow(2) & xdata1 < xlim(2) & xdata1 > xlim(1) & ydata1 > ylim(1) & ydata1 < ylim(2));
                  Ivalid = sub2ind(size(xdata1),Rvalid,Cvalid);
                  
                  if any(Ivalid),
                    xdata2 = xdata1(Ivalid);
                    ydata2 = ydata1(Ivalid);
                    
                    xdiff = axial_ratiox*(xdata2 - get(hselbox,'XData'));
                    ydiff = ydata2 - get(hselbox,'YData');
                    dist = sqrt(xdiff.^2 + ydiff.^2);
                    [Itmp] = find(dist == min(dist(:)),1,'first');
                    
                    Rmin = Rvalid(Itmp);
                    Cmin = Cvalid(Itmp);
                    if min(dist(:)) < mindist && ydata2(Itmp) > get(hselbox,'YData'),
                      mindist = min(dist(:));
                      iobj_closest = iobj;
                      Rnew = Rmin;
                      Cnew = Cmin;
                      xdata = xdata1;
                      ydata = ydata1;
                      
                    end % if: closer by current selection and above it
                  end % if: valid points found
                end % for: all graphics objects
                
                % nothing above this point
                if isnan(iobj_closest),
                  maxdist = 0;
                  for iobj = 1:nof_objs,
                    % get x/y data
                    xdata1 = get(hobjs(iobj),'XData');
                    ydata1 = get(hobjs(iobj),'YData');
                    [Rvalid,Cvalid] = find(xdata1 > xwindow(1) & xdata1 < xwindow(2) & xdata1 <= xlim(2) & xdata1 >= xlim(1) & ydata1 >= ylim(1) & ydata1 <= ylim(2));
                    if isequal(hobjs(iobj),hsel),
                      Rvalid(Rnew) = [];
                      Cvalid(Rnew) = [];
                    end
                    
                    Ivalid = sub2ind(size(xdata1),Rvalid,Cvalid);
                    if any(Ivalid),
                      xdata2 = xdata1(Ivalid);
                      ydata2 = ydata1(Ivalid);
                      
                      xdiff = axial_ratiox*(xdata2 - get(hselbox,'XData'));
                      ydiff = ydata2 - get(hselbox,'YData');
                      dist = sqrt(xdiff.^2 + ydiff.^2);
                      [Itmp] = find(dist == max(dist),1);
                      Rmin = Rvalid(Itmp);
                      Cmin = Cvalid(Itmp);
                      if max(dist(:)) > maxdist && ydata2(Itmp) < get(hselbox,'YData'),
                        maxdist = max(dist(:));
                        iobj_closest = iobj;
                        Rnew = Rmin;
                        Cnew = Cmin;
                        xdata = xdata1;
                        ydata = ydata1;
                        
                      end % for: all graphics objects
                    end % if: valid points found
                  end % for: all graphics objects
                end % if: nothing above current selection
                
                if ~isnan(iobj_closest),
                  hsel = hobjs(iobj_closest);
                end
                
                
              case 'downarrow',
                
                mindist = inf;
                iobj_closest = nan; % init
                for iobj = 1:nof_objs,
                  % get x/y data
                  xdata1 = get(hobjs(iobj),'XData');
                  ydata1 = get(hobjs(iobj),'YData');
                  [Rvalid,Cvalid] = find(xdata1 > xwindow(1) & xdata1 < xwindow(2) & xdata1 < xlim(2) & xdata1 > xlim(1) & ydata1 > ylim(1) & ydata1 < ylim(2));
                  Ivalid = sub2ind(size(xdata1),Rvalid,Cvalid);
                  if any(Ivalid),
                    xdata2 = xdata1(Ivalid);
                    ydata2 = ydata1(Ivalid);
                    
                    xdiff = axial_ratiox*(xdata2 - get(hselbox,'XData'));
                    ydiff = ydata2 - get(hselbox,'YData');
                    dist = sqrt(xdiff.^2 + ydiff.^2);
                    [Itmp] = find(dist(:) == max(dist(:)),1);
                    Rmin = Rvalid(Itmp);
                    Cmin = Cvalid(Itmp);
                    if min(dist(:)) < mindist && ydata2(Itmp) < get(hselbox,'YData'),
                      mindist = min(dist(:));
                      iobj_closest = iobj;
                      Rnew = Rmin;
                      Cnew = Cmin;
                      xdata = xdata1;
                      ydata = ydata1;
                    end % if: closer by current selection and above it
                  end % if: valid points found
                end % for: all graphics objects
                
                % nothing above this point
                if isnan(iobj_closest),
                  maxdist = 0;
                  for iobj = 1:nof_objs,
                    % get x/y data
                    xdata1 = get(hobjs(iobj),'XData');
                    ydata1 = get(hobjs(iobj),'YData');
                    [Rvalid,Cvalid] = find(xdata1 > xwindow(1) & xdata1 < xwindow(2) & xdata1 <= xlim(2) & xdata1 >= xlim(1) & ydata1 >= ylim(1) & ydata1 <= ylim(2));
                    if isequal(hobjs(iobj),hsel),
                      Rvalid(Rnew) = [];
                      Cvalid(Rnew) = [];
                    end
                    Ivalid = sub2ind(size(xdata1),Rvalid,Cvalid);
                    if any(Ivalid),
                      xdata2 = xdata1(Ivalid);
                      ydata2 = ydata1(Ivalid);
                      
                      xdiff = axial_ratiox*(xdata2 - get(hselbox,'XData'));
                      ydiff = ydata2 - get(hselbox,'YData');
                      dist = sqrt(xdiff.^2 + ydiff.^2);
                      [Itmp] = find(dist == max(dist),1);
                      Rmin = Rvalid(Itmp);
                      Cmin = Cvalid(Itmp);
                      if max(dist(:)) > maxdist && ydata2(Itmp) > get(hselbox,'YData'),
                        maxdist = max(dist(:));
                        iobj_closest = iobj;
                        Rnew = Rmin;
                        Cnew = Cmin;
                        xdata = xdata1;
                        ydata = ydata1;
                        
                      end % for: all graphics objects
                    end % if: valid points found
                  end % for: all graphics objects
                end % if: nothing above current selection
                
                if ~isnan(iobj_closest),
                  hsel = hobjs(iobj_closest);
                end
                
            end % switch: key type
            
            posstr = sprintf('Datapoint : [%g ; %g]',xdata(Rnew,Cnew),ydata(Rnew,Cnew));
            
          otherwise
            fprintf(1,'%s is NOT implemented yet\n',upper(graphtype));
            
        end % switch graph type
        
        
        % modify title string
        ttl = get(get(this.hax(ir,ic),'Title'),'String');
        ttl{end} = posstr;
        set(get(this.hax(ir,ic),'Title'),'String',ttl);
        
        % move selection box
        if exist('zdata','var'),
          set(hselbox,'XData',xdata(Rnew,Cnew),'YData',ydata(Rnew,Cnew),'ZData',zdata(Rnew,Cnew));
        else
          set(hselbox,'XData',xdata(Rnew,Cnew),'YData',ydata(Rnew,Cnew));
        end
        
        %==============================================================
        % MOUSE CLICK
        %==============================================================
        
        
      else % else: click on axes
        
        set(gcf,'CurrentAxes',this.hax(ir,ic));
        
        % =========== RIGHT MOUSE CLICK ========= %
        
        switch get(gcf,'SelectionType'),
          case 'alt',
            
            % delete selection box
            if ~isempty(findobj(this.hax(ir,ic),'Tag','selbox')),
              delete(findobj(this.hax(ir,ic),'Tag','selbox'));
              
              % reset title
              ttl = get(get(this.hax(ir,ic),'Title'),'String');
              if strcmp(ttl{end}(1:11),'Datapoint :'),
                ttl(end) = [];
                set(get(this.hax(ir,ic),'Title'),'String',ttl);
              end
              
              % remove current handle selection
              this.interaxes_data(ir,ic).selected_object_handle = nan;
              
              % set zoom button
              if this.interaxes_data(ir,ic).valid,
                this.set_zoom_button_position(ir,ic);
              end
              return
            end
            
            % =========== LEFT MOUSE CLICK ========= %
            
          case 'normal',
            
            % point clicked on
            cp = get(this.hax(ir,ic),'CurrentPoint');
            cpx = mean(cp(:,1));
            cpy = mean(cp(:,2));
            cpz = mean(cp(:,3));
            clear cp
            
            % what was clicked ?
            if isempty(gco) || isequal(gco,hselbox),
              hclicked = this.hax(ir,ic);
            else
              if ismember(get(gco,'Type'),cat(1,'axes',this.interaxes_supported_types)),
                hclicked = gco;
              else
                warning('Ojbects of type ''%s'' are not supported and can not be selected!\nSearching closest valid object point',get(gco,'Type'));
                hclicked = this.hax(ir,ic);
              end
            end
            
            hsel = hclicked; % init
            
            if isempty(hclicked),
              return;
            end
            
            switch get(hclicked,'Type'),
              case 'surface',
                xdata = get(gco,'XData');
                ydata = get(gco,'YData');
                zdata = get(gco,'ZData');
                cdata = get(gco,'CData');
                xdiff = axial_ratiox*(xdata - cpx);
                ydiff = ydata - cpy;
                zdiff = axial_ratioz*(zdata - cpz);
                dist = sqrt(xdiff.^2 + ydiff.^2 + zdiff.^2);
                Iclosest = find(dist(:) == min(dist(:)),1);
                
              case 'image',
                xdata = get(gco,'XData');
                ydata = get(gco,'YData');
                cdata = get(gco,'CData');
                if numel(xdata) == 2,
                  xdata = xdata(1):xdata(2);
                  ydata = ydata(1):ydata(2);
                end
                [xdata,ydata] = meshgrid(xdata,ydata);
                xdiff = axial_ratiox*(xdata - cpx);
                ydiff = ydata - cpy;
                dist = sqrt(xdiff.^2 + ydiff.^2);
                Iclosest = find(dist(:) == min(dist(:)),1);
                
                
              case 'line',
                xdata = get(hclicked,'XData');
                ydata = get(hclicked,'YData');
                xdiff = axial_ratiox*(xdata - cpx);
                ydiff = ydata - cpy;
                dist = sqrt(xdiff.^2 + ydiff.^2);
                Iclosest = find(dist(:) == min(dist(:)),1);
                
              case 'axes',
                % find closest object
                nof_objs = numel(hobjs);
                mindist = inf;
                for iobj = 1:nof_objs,
                  xdata1 = get(hobjs(iobj),'XData');
                  ydata1 = get(hobjs(iobj),'YData');
                  
                  switch get(hobjs(iobj),'Type'),
                    
                    case 'image',
                      cdata = get(hobjs(iobj),'CData');
                      if numel(xdata1) == 2,
                        xdata = xdata1(1):xdata1(2);
                        ydata = ydata1(1):ydata1(2);
                      end
                      [xdata1,ydata1] = meshgrid(xdata1,ydata1);
                      xdiff = axial_ratiox*(xdata1 - cpx);
                      ydiff = ydata1 - cpy;
                      dist = sqrt(xdiff.^2 + ydiff.^2);
                      
                    otherwise
                      
                      xdata1 = get(hobjs(iobj),'XData');
                      ydata1 = get(hobjs(iobj),'YData');
                      xdiff = axial_ratiox*(xdata1 - cpx);
                      ydiff = ydata1 - cpy;
                      
                      zdata1 = get(hobjs(iobj),'ZData');
                      if isempty(zdata1),
                        zdata1 = zeros(size(xdata1));
                      end
                      zdiff = axial_ratioz*(zdata1 - cpz);
                      dist = sqrt(xdiff.^2 + ydiff.^2 + zdiff.^2);
                      
                  end
                  
                  if min(dist(:)) < mindist,
                    xdata = xdata1(:);
                    ydata = ydata1(:);
                    if exist('zdata1','var'),
                      zdata = zdata1(:);
                    end
                    mindist = min(dist(:));
                    iobj_closest = iobj;
                    Iclosest = find(dist(:) == min(dist(:)),1);
                  end
                  
                end
                hsel = hobjs(iobj_closest);
                if isprop(hsel,'CData'),
                  cdata = get(hsel,'CData');
                end
                
                
              otherwise
                
                % do nothing, everything is filtered out
                
            end % switch: graphics type
            
            
            % create position title string
            switch get(hsel,'Type'),
              
              case {'surface'},
                posstr = sprintf('Datapoint : [%g ; %g ; %g ; %g]',xdata(Iclosest),ydata(Iclosest),zdata(Iclosest),cdata(Iclosest));
                
              case {'image'},
                posstr = sprintf('Datapoint : [%g ; %g ; %g]',xdata(Iclosest),ydata(Iclosest),cdata(Iclosest));
                
              otherwise
                posstr = sprintf('Datapoint : [%g ; %g]',xdata(Iclosest),ydata(Iclosest));
            end % switch: selected graphics object
            
            % modify title string and location of selection box
            ttl = get(get(this.hax(ir,ic),'Title'),'String');

            if ~isempty(hselbox), % if: already something selected
              ttl{end} = posstr;
              % move selection box
              if exist('zdata','var'),
                set(hselbox,'XData',xdata(Iclosest),'YData',ydata(Iclosest),'ZData',zdata(Iclosest));
              else
                set(hselbox,'XData',xdata(Iclosest),'YData',ydata(Iclosest));
              end
            else % else: nothing selected yet
              ttl = cat(1,ttl,posstr);
              % create selection box
              if ~ishold,
                hold on; % toggle ON
                if exist('zdata','var'),
                  hselbox = plot3(xdata(Iclosest),ydata(Iclosest),zdata(Iclosest),'ks','MarkerSize',15,'LineWidth',3,'Tag','selbox','ButtonDownFcn',@(src,evt)this.interaxes(src,evt,ir,ic));
                else
                  hselbox = plot(xdata(Iclosest),ydata(Iclosest),'ks','MarkerSize',15,'LineWidth',3,'Tag','selbox','ButtonDownFcn',@(src,evt)this.interaxes(src,evt,ir,ic));
                end
                hold off; % toggle OFF
              else
                hselbox = plot(xdata(Iclosest),ydata(Iclosest),'ks','MarkerSize',15,'LineWidth',3,'Tag','selbox','ButtonDownFcn',@(src,evt)this.interaxes(src,evt,ir,ic));
              end
            end % ifelse: anything selected yet ?
            set(get(this.hax(ir,ic),'Title'),'String',ttl);
            
            % =========== DOUBLE CLICK ========= %
            
          case 'open', % double click
            
            % not implemented yet
            
            
        end % switch: mouse button
        
      end % ifelse: keypress or mouse click?
      
      % correct zoom button position
      this.set_zoom_button_position(ir,ic);
      
      if exist('hsel','var'),
        % set and save properties
        this.interaxes_data(ir,ic).selected_object_handle = hsel;
        modfields = fieldnames(this.interaxes_data(ir,ic).local_selection_mods);
        for ifield = 1:numel(modfields),
          if isprop(hsel,modfields{ifield}),
            this.interaxes_data(ir,ic).selected_object_props.(modfields{ifield}) = get(hsel,modfields{ifield});
            set(hsel,modfields{ifield},this.interaxes_data(ir,ic).local_selection_mods.(modfields{ifield}));
          end
        end
        % move object to top of stack
        uistack(hsel,'top');
        uistack(hselbox,'top');
      end % if: selection made?
      
    end % fcn: interaxes
    
    
    function delete_axes(this,src,~)
      
      [Iax] = find(this.hax == src);
      for iax = 1:numel(Iax),
        [ir,ic] = ind2sub(size(this.hax),Iax(iax));
        this.hax(ir,ic) = nan;
        this.subplotzoom_enabled(ir,ic) = 0;
        if ishandle(this.subplotzoom_data(ir,ic).zm_btn),
          delete(this.subplotzoom_data(ir,ic).zm_btn);
        end
        this.subplotzoom_data(ir,ic).zm_btn = nan;
        if ishandle(this.hlegend(ir,ic)),
          delete(this.hlegend(ir,ic));
          this.hlegend(ir,ic) = nan;
          this.legend_data(ir,ic) = {this.legend_data_struct};
        end
        if ishandle(this.hcolorbar(ir,ic)),
          delete(this.hcolorbar(ir,ic));
        end
      end
      if isequal(gca,findobj(this.hparent,'Type','axes')),
        set(this.hfig,'ResizeFcn',[]);
        set(this.hfig,'SizeChangeFcn',[]);
      end
    end % fcn: delete_axes
    
    
    function place_legend(this,ir,ic)
      
      if this.legend_data(ir,ic).valid,
        [~,locstr] = this.input_string_check('legend',this.legend_data(ir,ic).location); % cast to variable for ease
        
        ax_parent = this.hax(ir,ic); % colorbar parent axes
        
        set(ax_parent,'Units','pixels'); % set to pixels
        set(this.hlegend(ir,ic),'Units','pixels','LooseInset',[0 0 0 0]);
        axposi = get(ax_parent,'Position'); % original position of the axes (NOT the outerposition!!!)
        if isequal(locstr(3),'i'), % if: inside axes, outer boundary is (inner)position
          axposo = axposi;
        else % else: outside axes, outer boundary is outerposition
          axposo = get(ax_parent,'OuterPosition');
        end
        axti = get(ax_parent,'TightInset');
               
        
        %% determine cbar position (touching outerPosition)
        legpos = get(this.hlegend(ir,ic),'Position');
        w = legpos(3);
        h = legpos(4);
        buffer_px = this.legend_data(ir,ic).buffer_px;
        
        % determine [x y w h] for OUTER position (corrections to be added
        % in case it is an inner position
        if ~isempty(find(strcmp(locstr(1:2),{'ne','en','ee','es','se'}),1)),
          x = axposo(1) + axposo(3) - w - buffer_px(3);
        elseif ~isempty(find(strcmp(locstr(1:2),{'sw','ws','ww','wn','nw'}),1))
          x = axposo(1) + buffer_px(1);
        else
          x = axposo(1) + axposo(3)/2 - w/2;
        end
        
        if ~isempty(find(strcmp(locstr(1:2),{'wn','nw','nn','ne','en'}),1)),
          y = axposo(2) + axposo(4) - h - buffer_px(4);
        elseif ~isempty(find(strcmp(locstr(1:2),{'es','se','ss','sw','ws'}),1)),
          y = axposo(2) + buffer_px(2);
        else
          y = axposo(2) + axposo(4)/2 - h/2;
        end
                
        legpos = [x y w h];
        
        set(this.hlegend(ir,ic),'Units','pixels','Position',legpos);
        
        %% shrink position (keep outerposition)
        if isequal(locstr(3),'o'), % if: outside -> axes must shrink
          x = axposi(1);
          y = axposi(2);
          w = axposi(3);
          h = axposi(4);
          
          if ~isempty(find(strcmp(locstr(1:2),{'en','ee','es'}),1)), % east
            w = w - (legpos(3) + buffer_px(1));
          elseif ~isempty(find(strcmp(locstr(1:2),{'ws','ww','wn'}),1)), % west
            w = w - (legpos(3) + buffer_px(3));
            x = legpos(1) + legpos(3) + buffer_px(1) + axti(1);
          else % pure north or south
            % do nothing for x
          end

          if ~isempty(find(strcmp(locstr(1:2),{'nw','nn','ne'}),1)), % north
            h = h - (legpos(4) + buffer_px(2));
          elseif ~isempty(find(strcmp(locstr(1:2),{'se','ss','sw'}),1)), % south
            h = h - (legpos(4) + buffer_px(4));
            y = legpos(2) + legpos(4) + buffer_px(4) + axti(2);
          else % pure east or west
            % do nothing for y
          end
          
          h = max(10,h);
          w = max(10,w);
          x = max(axposi(1),x);
          x = min(axposi(1) + axposi(3),x);
          y = max(axposi(2),y);
          y = min(axposi(2) + axposi(4),y);
          axpos_new = [x y w h];
          
          set(ax_parent,'Position',axpos_new);
          
          % reposition colorbar to shrunken axes
          if this.colorbar_data(ir,ic).valid && strcmp('i',this.colorbar_data(ir,ic).location(3)), % if: colorbar is inside
            this.place_colorbar(ir,ic);
          end
        end % if: legend outside -> shrink axes
        
        
      end % if: legend exist for this subplot
      
    end % place_legend
    
    
    function place_colorbar(this,ir,ic)
      
      if this.colorbar_data(ir,ic).valid,
        [~,locstr] = this.input_string_check('colorbar',this.colorbar_data(ir,ic).location); % cast to variable for ease
        
        ax_parent = this.hax(ir,ic); % colorbar parent axes
        
        
        is_inside = false; % use for extra shortening of longest dimension
        set(ax_parent,'Units','pixels'); % set to pixels
        set(this.hcolorbar(ir,ic),'Units','pixels','LooseInset',[0 0 0 0]);
        axposi = get(ax_parent,'Position'); % original position of the axes (NOT the outerposition!!!)
        if isequal(locstr(3),'i'), % if: inside axes, outer boundary is (inner)position
          axposo = axposi;
          is_inside = true;
        else % else: outside axes, outer boundary is outerposition
          axposo = get(ax_parent,'OuterPosition');
        end
        axti = get(ax_parent,'TightInset');
                
        %% determine cbar position (touching outerPosition)
        shortdim_px = this.colorbar_data(ir,ic).shortdim_px;
        buffer_px = this.colorbar_data(ir,ic).buffer_px;
        
        cbti = get(this.hcolorbar(ir,ic),'TightInset');
        
        % determine [x y w h] for OUTER position (corrections to be added
        % in case it is an inner position
        switch lower(locstr(1:2)),
          case 'nn',
            x = axposo(1) + is_inside*buffer_px(1);
            y = axposo(2) + axposo(4) - shortdim_px - buffer_px(4);
            w = axposo(3) - is_inside*sum(buffer_px([1,3]));
            h = shortdim_px;
            
          case 'ss',
            x = axposo(1) + is_inside*buffer_px(1);
            y = axposo(2) + cbti(2) + buffer_px(2);
            w = axposo(3) - is_inside*sum(buffer_px([1,3]));
            h = shortdim_px;
            
          case 'ee',
            x = axposo(1) + axposo(3) - shortdim_px - buffer_px(3);
            y = axposo(2) + is_inside*buffer_px(2);
            w = shortdim_px;
            h = axposo(4) - is_inside*sum(buffer_px([2 4]));
            
          case 'ww',
            x = axposo(1) + cbti(1) + buffer_px(1);
            y = axposo(2) + is_inside*buffer_px(2);
            w = shortdim_px;
            h = axposo(4) - is_inside*sum(buffer_px([2,4]));
            
        end
        h = max(10,h);
        w = max(10,w);
        x = max(axposo(1),x);
        x = min(axposo(1) + axposo(3),x);
        y = max(axposo(2),y);
        y = min(axposo(2) + axposo(4),y);
        cbpos = [x y w h];
        
        set(this.hcolorbar(ir,ic),'Units','pixels','Position',cbpos);
        
        %% shrink position (keep outerposition)
        if isequal(locstr(3),'o'), % if: outside -> axes must shrink
          x = axposi(1);
          y = axposi(2);
          w = axposi(3);
          h = axposi(4);
          
          switch locstr(1:2),
            
            case 'nn',
              h = h - (cbpos(4) + cbti(2) + buffer_px(2));
              
            case 'ss',
              h = h - (cbpos(4) + cbti(2) + buffer_px(4));
              y = cbpos(2) + cbpos(4) + buffer_px(4) + axti(2);

            case 'ee',
              w = w - (cbpos(3) + cbti(1) + buffer_px(3));
              
            case 'ww',
              w = w - (cbpos(3) + cbti(1) + buffer_px(1));
              x = cbpos(1) + cbpos(3) + buffer_px(1) + axti(1);

          end
          
          h = max(10,h);
          w = max(10,w);
          x = max(axposi(1),x);
          x = min(axposi(1) + axposi(3),x);
          y = max(axposi(2),y);
          y = min(axposi(2) + axposi(4),y);
          axpos_new = [x y w h];
          
          set(ax_parent,'Position',axpos_new,'ActivePositionProperty','OuterPosition');
          
          % reposition legend to shrunken axes
          if this.legend_data(ir,ic).valid && strcmp('i',this.legend_data(ir,ic).location(3)), % if: colorbar is inside
            this.place_legend(ir,ic);
          end
        end % if: legend outside -> shrink axes
        
      
      end % if: legend exist for this subplot
      
    end % fcn: place_colorbar
    
    
    function [flag,varargout] = input_string_check(~,type,input)
      
      flag = true;
      convstr = [];
      switch type,
        case 'legend',
          switch input,
            case {'north','northinside','n','ni','nni'},
              convstr = 'nni';
              
            case {'northoutside','no','nno'},
              convstr = 'nno';
              
            case {'northeast','northeastinside','ne','nei','en','eni','eastnorth','eastnorthinside'},
              convstr = 'nei';
              
            case {'northeastoutside','neo'},
              convstr = 'neo';
              
            case {'eastnorthoutside','eno'},
              convstr = 'eno';
              
            case {'east','e','eastinside','ei','eei'},
              convstr = 'eei';
              
            case {'eastoutside','eo','eeo'},
              convstr = 'eeo';
              
            case {'eastsouthoutside','eso'},
              convstr = 'eso';
              
            case {'southeast','se','southeastinside','sei','es','esi','eastsouth','eastsouthinside'},
              convstr = 'sei';
              
            case {'southeastoutside','seo'},
              convstr = 'seo';
              
            case {'south','s','southinside','si','ssi'},
              convstr = 'ssi';
              
            case {'southoutside','so','sso'},
              convstr = 'sso';
              
            case {'southwest','sw','southwestinside','swi','ws','wsi','westsouth','westsouthinside'},
              convstr = 'swi';
              
            case {'southwestoutside','swo'},
              convstr = 'swo';
              
            case {'westsouthoutside','wso'},
              convstr = 'wso';
              
            case {'west','w','westinside','wi','wwi'},
              convstr = 'wwi';
              
            case {'westoutside','wo','wwo'},
              convstr = 'wwo';
              
            case {'westnorthoutside','wno'},
              convstr = 'wno';
              
            case {'northwest','nw','northwestinside','nwi','wn','wni','westnorth','westnorthinside'},
              convstr = 'nwi';
              
            case {'northwestoutside','nwo'},
              convstr = 'nwo';
              
            otherwise
              flag = false;
          end % switch: input string
            
        case 'colorbar',
          switch input,
            case {'northinside','ni','nni'},
              convstr = 'nni';
              
            case {'n','north','northoutside','no','nno'},
              convstr = 'nno';
              
            case {'eastinside','ei','eei'},
              convstr = 'eei';
              
            case {'e','east','eastoutside','eo','eeo'},
              convstr = 'eeo';
              
            case {'southinside','si','ssi'},
              convstr = 'ssi';
              
            case {'s','south','southoutside','so','sso'},
              convstr = 'sso';
              
            case {'westinside','wi','wwi'},
              convstr = 'wwi';
              
            case {'w','west','westoutside','wo','wwo'},
              convstr = 'wwo';
              
            otherwise
              flag = false;
          end % switch: input string
          
      end % switch: type
      
      if nargout > 1,
        varargout{1} = convstr;
      end
      
    end % input_string_check
      
    %% to be removed in later versions
    
    function relocate_legend(this,location,varargin)
      
      %
      % RELOCATE_LEGEND relocates the legend of one or more subplots
      %
      % SYNTAX:
      %   <obj>.legend(VARARGIN);
      %
      %
      % INPUT PARAMETERS:
      %   location  [char] String specifying the location of the legend(s).
      %                    Options are:
      %                       'north'
      %                       'northeast' (default)
      %                       'east'
      %                       'southeast'
      %                       'south'
      %                       'southwest'
      %                       'west'
      %                       'northwest'
      %                    The post-fix 'outside' may be added. This
      %                    will result in the placement of the legend
      %                    outside the axes. The axes will be resized
      %                    to accomodate this.
      %
      % VARARGIN PARAMETERS:
      % VARARGIN PARAMETERS:
      %   <no input parameters> : The legends of all subplots will be
      %                           removed
      %   1 input parameter : A vector containing the axes indices to
      %                       relocate the legends for
      %   2 input parameters : Two vectors containing the row and column
      %                        indices of the axes to relocate the legends
      %                        for.
      %
      
      pause(0.2);
      if nargin == 2,
        Ir = this.current_axes(1);
        Ic = this.current_axes(2);
      else
        if nargin > 2, % indices
          Iax = varargin{1};
          [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],Iax);
          if nargin > 3,
            Ir = varargin{1};
            Ic = varargin{2};
          end % if: all input parameters
        end % if: 3 input parameters
      end % if only location given
      
      for iax = 1:numel(Ir),
        ir = Ir(iax);
        ic = Ic(iax);
        Imerged = find(this.hax(:) == this.hax(ir,ic));
        for iaxm = 1:numel(Imerged),
          this.legend_data(Imerged(iaxm)).location = location;
        end
        this.place_legend(ir,ic,location);
      end
      
      this.reposition_content;
      
    end % fcn: relocate_legend
    
    
    function extract_axes(this,varargin)
      
      %
      % EXTRACT_AXES extracts the wanted axes or set of axes from the
      %   subplot_grid object created.
      %
      % SYNTAX:
      %   <obj>.extract_axes(VARARGIN);
      %
      % VARARGIN PARAMETERS:
      %   1 input parameter :   A vector of axes indices to be extracted
      %                         from the subplot_grid object
      %   2 input parameters :  The vectors for the row and column axes
      %                         positions to be extracted.
      %
      
      
      hfigs = [];
      Iax_ = 1:this.nof_rows*this.nof_columns;
      [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],Iax_);
      if nargin > 1,
        Iax_ = varargin{1};
        [Ic,Ir] = ind2sub([this.nof_columns,this.nof_rows],Iax_);
        if nargin > 2,
          Ir = varargin{1};
          Ic = varargin{2};
          if nargin  > 3,
            hfigs = varargin{3};
          end
        end
      end
      nof_axes_to_extract = numel(Ir);
      nof_figure_handles_given = numel(hfigs);
      
      
      for iext = 1:nof_axes_to_extract,
        ir = Ir(iext);
        ic = Ic(iext);
        
        % expand axes
        this.expand_axes(ir,ic,true);
        
        if iext <= nof_figure_handles_given,
          hfige = hfigs(iext);
        else
          hfige = figure;
        end
        set(hfige,'WindowKeyPressFcn',get(this.hfig,'WindowKeyPressFcn'));
        
        %% interaxes
        if this.interaxes_data(ir,ic).valid,
          
          % reset current selection
          if ~isnan(this.interaxes_data(ir,ic).selected_object_handle), % if: selection active -> disable
            modfields = fieldnames(this.interaxes_data(ir,ic).local_selection_mods);
            
            for ifield = 1:numel(modfields),
              if isprop(this.interaxes_data(ir,ic).selected_object_handle,modfields{ifield}),
                saveprops.(modfields{ifield}) = get(this.interaxes_data(ir,ic).selected_object_handle,modfields{ifield});
              end
            end
            set(this.interaxes_data(ir,ic).selected_object_handle,this.interaxes_data(ir,ic).selected_object_props);
            haxnew = copyobj(haxc,hfige);
            
            % set selection properties back
            set(this.interaxes_data(ir,ic).selected_object_handle,saveprops);
          else
            haxnew = copyobj(haxc,hfige);
          end % if: selection active
          
          ttl = get(get(haxnew,'Title'),'String');
          ttl(end) = [];
          set(get(haxnew,'Title'),'String',ttl);
          
          delete(findobj(haxnew,'Tag','selbox'));
        else
          haxnew = copyobj(this.hax(ir,ic),hfige);
        end % if: interaxes enabled?
        
        %% legend
        if this.legend_data(ir,ic).valid,
          copyobj(this.hlegend(ir,ic),hfige);
        end
        
        %% colorbar
        if ishandle(this.hcolorbar(ir,ic)),
          copyobj(this.hcolorbar(ir,ic),hfige);
        end
        
      end % for: all to-extract axes
      
      
      % expand axes
      this.collapse_axes;
      
      
    end % fcn:extract_axes
    

  end % methods
  
  
  methods(Static)
    
    function demo
      vpause = 0;
      
      %% init
      fprintf(1,'=============================================================\n');
      fprintf(1,'\t\tDEMO STARTED\n');
      fprintf(1,'=============================================================\n\n');
      fprintf(1,'Please check the subtitle for information\n\n');
      
      % simple layout
      titlestr = 'Demo of SUBPLOT_GRID function';
      figure;
      curfig = gcf;
      set(curfig,'Units','pixels','Position',[261 125 1467 833],'Color',0.7*[1 1 1]);
      hsg = subplot_grid(4,5,'no_zoom');
      hsg.figtitle(titlestr,'Interpreter','none');
      hsg.subfigtitle({'Watch this subtitle for information on what''s happening and press any key to continue'});
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      hsg.subfigtitle({'BTW. The figure title was added through FIGTITLE and the subtitle through SUBFIGTITLE'})
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      hsg.subfigtitle({'If applicable the methods used are indicated via m:<method>, and input parameters via p:<parameter>'})
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      %% panelize
      delete(findobj(curfig,'Type','axes','-or','Type','text'));
      delete(gca)

      hpnl_left = uipanel('Parent',curfig,'Position',[0.025 0.2 0.15 0.78],'BackgroundColor',0.85*[1 1 1]);
      hpnl_bottom = uipanel('Parent',curfig,'Position',[0.025 0.025 0.95 0.15],'BackgroundColor',0.85*[1 1 1]);
      hpnl_right = uipanel('Parent',curfig,'Position',[0.2 0.2 0.775 0.78],'BackgroundColor',0.85*[1 1 1]); % add panel
      
      htext = uicontrol(hpnl_left,...
        'Style','text',...
        'Units','normalized',...
        'Position',[0 0 1 1],...
        'String','This is a panel excluded from subplot_grid',...
        'BackgroundColor',0.85*[1 1 1]);
      htext = uicontrol(hpnl_bottom,...
        'Style','text',...
        'Units','normalized',...
        'Position',[0 0 1 1],...
        'String','This is a panel excluded from subplot_grid',...
        'BackgroundColor',0.85*[1 1 1]);

      hsg = subplot_grid(4,5,'no_zoom','parent',hpnl_right);
      hsg.figtitle(titlestr,'Interpreter','none');
      hsg.subfigtitle('subplot\_grid in a figure panel only (p:''parent'')');
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      %% add row titles (Both sides)
      hsg.subfigtitle('Per row multi-line titles may be added (m:rowtitles)');
      rowstr = {'Row title 1',...
        {'Row title 2','Second line'},...
        'third row',...
        'also the 4th row'};
      hsg.rowtitles(rowstr,'fontsize',8);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      % add row/column titles not matching to axes
      hsg.subfigtitle(sprintf('The number of row titles is INDEPENDENT of the number/layout of axes (m:rowtitles)'));
      rowstr = {'Row title 1',...
        {'Row title 2','Second line'},...
        'Above is empty'};
      hsg.rowtitles(rowstr,'left','fontsize',8);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      % place non-matching row titles
      hsg.subfigtitle(sprintf('The relative sizes can be used to place non-matching titles (m:rowtitles)'));
      rowstrl = {'Row title 1',...
        {'Row title 2','Second line'},...
        'tire-iron'};
      hsg.rowtitles(rowstrl,[1 2 1],'fontsize',8);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      % right side
      hsg.subfigtitle(sprintf('Also on the right side of the figure titles may be placed (m:rowtitles)'));
      rowstrr = {'A row title on the right side','another small one'};
      hsg.rowtitles(rowstrr,'right',[3 1],'fontsize',8);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      %% column titles
      colstrt = {'Column 1';...
        'Column 2';...
        {'Column 3';'Sub-column title'};...
        'Another one';...
        {'Title spread out';'over';'3 lines'}};
      hsg.subfigtitle('.. Obviously this also works for columns (m:coltitles)');
      hsg.coltitles(colstrt,'fontsize',8);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      colstrb = {'Single bottom column text (size 12)'};
      hsg.subfigtitle('.. and on the bottom (m:coltitles)');
      hsg.coltitles(colstrb,'bottom','fontsize',12);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      %% merge subplots
      set(curfig,'Units','pixels','Position',[261 125 1467 833]);
      delete(findobj(gcf,'Type','axes','-or','Type','text','-or','Type','uipanel'));
      delete(gca)
      
      hpnl_left = uipanel('Parent',curfig,'Position',[0.025 0.2 0.15 0.78],'BackgroundColor',0.85*[1 1 1]);
      hpnl_bottom = uipanel('Parent',curfig,'Position',[0.025 0.025 0.95 0.15],'BackgroundColor',0.85*[1 1 1]);
      hpnl_right = uipanel('Parent',curfig,'Position',[0.2 0.2 0.775 0.78],'BackgroundColor',0.85*[1 1 1]); % add panel
      
%       adsf
      uicontrol(hpnl_left,...
        'Style','text',...
        'Units','normalized',...
        'Position',[0 0 1 1],...
        'String','This is a panel excluded from subplot_grid',...
        'BackgroundColor',0.85*[1 1 1]);
      uicontrol(hpnl_bottom,...
        'Style','text',...
        'Units','normalized',...
        'Position',[0 0 1 1],...
        'String','This is a panel excluded from subplot_grid',...
        'BackgroundColor',0.85*[1 1 1]);
      
      hsg = subplot_grid(4,5,'mergelist',{[1 7],[10 20],[12 14]},'no_zoom','parent',hpnl_right);
      hsg.figtitle(titlestr,'Interpreter','none');
      hsg.subfigtitle('Axes may be merged to create larger axes (p:''mergelist'')');
      hsg.rowtitles(rowstrl,'left','fontsize',8);
      hsg.coltitles(colstrt,'top','fontsize',8);
      hsg.rowtitles(rowstrr,'right','fontsize',8);
      hsg.coltitles(colstrb,'bottom','fontsize',12);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      % match titles
      hsg.subfigtitle('Match row/column titles to merged axes if wanted! (m:rowtitles,m:coltitles)');
      hsg.rowtitles(rowstrl,'left',[2 1 1],'Fontsize',8);
      hsg.rowtitles(rowstrr,'right',[1 3],'fontsize',8);
      hsg.coltitles({'merged title','small','as small','similar'},[2 1 1 1],'fontsize',8);
      
      %% general resize
      hsg.subfigtitle('figure resizing preserves optimal space usage');
      newpos = [0.1 0.1 0.4 0.8];
      set(curfig,'Units','normalized','Position',newpos);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      %% figplace
      hsg.subfigtitle('Place figure in screen raster (m:figplace(1,2,1)');
      hsg.figplace(1,2,1);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      hsg.subfigtitle('Place figure in screen raster (m:figplace(2,2,3)');
      hsg.figplace(2,2,3);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      %% add image
      newpos = [0.1 0.1 0.8 0.8];
      set(curfig,'Units','normalized','Position',newpos);
      hsg.reposition_content;
      
      hsg.subfigtitle(sprintf('A - tiny - image added to axes (2,3)\nThe title/xlabel/ylabel function normally'));
      hsg.set_gca(2,4);
      image;
      axis ij tight;
      title('The matlab example IMAGE');
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      %% add subplotzoom
      hsg.subfigtitle({'use SUBPLOTZOOM to expand a single subplot (p:''no\_zoom'', m:enable\_subplotzoom)';'Notice the added + button!!'});
      hsg.enable_subplotzoom(2,4);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      % expand image
      hsg.subfigtitle('Click on +-button to expand subplot');
      hsg.expand_axes(2,4);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      % collapse
      hsg.subfigtitle('Clicking again on +-button resets subplot to its original size');
      hsg.collapse_axes;
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      %% create legend
      hsg.subfigtitle('Creating a legend INSIDE an axes (m:legend)');
      hsg.set_gca(1,1);
      hsg.legend({'r+--';'go';'b.-'},{'Graph 1';'Second thingy';'Final element'},'northeast',1);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      % add data to axes
      hsg.subfigtitle('Adding data to the axes matching the legend');
      hsg.set_gca(1,1);
      t = 1:1000;
      s = exp(1j*2*pi*0.01*t);
      n = randn(size(t)) + 1j*randn(size(t));
      s0 = s + 0.05*n;
      f1 = real(s0);
      f2 = imag(s0);
      f3 = abs(s0);
      plot(t,f1,'r+--');hold on;
      plot(t,f2,'go');
      plot(t,f3,'b.-');
      title('Some title string');
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      % move legend
      hsg.subfigtitle('In this case the legend can be moved outside the axes (m:relocate\_legend)');
      hsg.legend({'r+--';'go';'b.-'},{'Graph 1';'Second thingy';'Final element'},'eastoutside',1);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      % expansion preserves legend locations
      hsg.subfigtitle('On expansion the legend stays preserved')
      %         hsg.enable_subplotzoom(1,2);
      hsg.expand_axes(1,2);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      %% remove legend
      hsg.subfigtitle('Removing the legend and zooming out (m:remove\_legend)');
      hsg.remove_legend(1,1);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      %% colorbar
      hsg.subfigtitle('create image with colorbar (m:colorbar) OUTSIDE axes');
      hsg.set_gca(4,2);
      im = image;
      imagesc(326*mod(im.CData,1));
      title('default image 2');
      hsg.colorbar;
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      % inside image
      hsg.subfigtitle('Create colorbar INSIDE image');
      hsg.colorbar('ni');
      if any(vpause),
        pause(vpause);
      else
        pause
      end

      % colorbar not connected to contents
      hsg.subfigtitle('The colorbar can take any colormap ...');
      hsg.colorbar(jet(256),'e');
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      % colorbar not scaled
      hsg.subfigtitle('The colorbar does not have to be scaled/linked with the contents ...');
      hsg.colorbar(jet(256),false);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      % any colorbar
      hsg.subfigtitle('Colorbars are not linked to the content. Thus you can place any colorbar, anywhere');
      hsg.set_gca(3,2);
      hsg.colorbar(hot(256),'ei');
      if any(vpause),
        pause(vpause);
      else
        pause
      end
            
      % colorbar while zoomed
      hsg.subfigtitle('Zooming now still works');
      hsg.subplotzoom_cb(4,2);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      % colorbar
      hsg.subfigtitle('Return to normal with correctly placed colorbar');
      hsg.collapse_axes;
      hsg.colorbar;
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      %% interaxes
      hsg.subfigtitle('enable INTERAXES function to get values from data points by clicking (m:enable\_interaxes)');
      hsg.enable_interaxes(1,1);
      cp = [0.3030 0.6944];
      set(hsg.hfig,'Units','normalized','SelectionType','normal','CurrentPoint',cp);
      hsg.interaxes([],[],1,1);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      % using arrow keys works too
      hsg.subfigtitle('Using the left/right arrow keys scrolls through single graph');
      for iter = 1:20,
        evt.Key = 'leftarrow';
        hsg.interaxes(gcf,evt,1,1);
        pause(0.1);
      end
      for iter = 1:20,
        evt.Key = 'rightarrow';
        hsg.interaxes(hsg.hfig,evt,1,1);
        pause(0.1);
      end
      
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      % up down keys
      hsg.subfigtitle('Using the up/down arrow keys moves the selection to the closest graph');
      for iter = 1:5,
        evt.Key = 'uparrow';
        hsg.interaxes(hsg.hfig,evt,1,1);
        pause(0.5);
      end
      for iter = 1:5,
        evt.Key = 'downarrow';
        hsg.interaxes(hsg.hfig,evt,1,1);
        pause(0.5);
      end
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      % right click
      hsg.subfigtitle('right-clicking in the axes removes the selection');
      src = [];
      evt = [];
      set(hsg.hfig,'SelectionType','alt');
      hsg.interaxes(src,evt,1,1);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      %% 'zoomlink' mode
      hsg.subfigtitle('Link axes in zooming in (m:zoomlink\_axes, p:''zoomlinklist'')');
      hsg.zoomlink_axes({[1,9,17]});
      hsg.expand_axes(2,4);
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      %% viewer mode
      set(curfig,'Units','pixels','Position',[261 125 1467 833]);
      delete(findobj(curfig,'Type','axes','-or','Type','text'));
      delete(gca);
      
      hpnl_left = uipanel('Parent',curfig,'Position',[0.025 0.2 0.15 0.78]);
      hpnl_bottom = uipanel('Parent',curfig,'Position',[0.025 0.025 0.95 0.15]);
      hpnl_right = uipanel('Parent',curfig,'Position',[0.2 0.2 0.775 0.78]); % add panel
      uicontrol(hpnl_left,...
        'Style','text',...
        'Units','normalized',...
        'Position',[0 0 1 1],...
        'String','This is a panel excluded from subplot_grid');
      uicontrol(hpnl_bottom,...
        'Style','text',...
        'Units','normalized',...
        'Position',[0 0 1 1],...
        'String','This is a panel excluded from subplot_grid');
      
      hsg = subplot_grid('viewer',5,'no_zoom','parent',hpnl_right);
      hsg.figtitle(titlestr,'Interpreter','none');
      hsg.subfigtitle({'Viewer mode creates one big and row(s) of smaller images instantly (parameter ''viewer'')','NEXT: subplot_grid in a specific panel ..'});
      t = linspace(0,1,100);
      colorlist = {'rx-','go-','b.-','c+-','ms-'};
      thetas = (1:5)*13.45;
      amps = 2*rand(1,5) - 1;
      for iplot = 1:5,
        sig = amps(iplot)*sind(thetas(iplot) + 360*t);
        hsg.set_gca(1);
        plot(t,sig,colorlist{iplot});grid on;hold on;
        hsg.set_gca('viewer',iplot);
        plot(t,sig,colorlist{iplot});grid on;
      end % for: all plots
      if any(vpause),
        pause(vpause);
      else
        pause
      end
      
      %% demo ended
      hsg.subfigtitle({'DEMO FINISHED!!!';'See help per method for more information'})
      fprintf(1,'=============================================================\n');
      fprintf(1,'\t\tDEMO ENDED\n');
      fprintf(1,'=============================================================\n\n');
      
    end % fcn
    
  end %methods(Static)
  
end % classdef subplot_grid