| mltable(fig, hObj, action, columnInfo, rowHeight, cell_data, gFont, varargin)
|
function data = mltable(fig, hObj, action, columnInfo, rowHeight, cell_data, gFont, varargin)
% function data = mltable(fig, hObj, action, columnInfo, rowHeight, cell_data, gFont)
%
% Author: Morris Maynard
% Based on code by Gregory Gershanok
% Last update: 27 Jan 2005
%
% Manages a table with editing and scrolling capability
% Features: varying column widths, entry formatting, insert/delete rows,
% editable or read-only cells, font control, scaled numeric
% display, row selection highlighing, multiple tables per figure,
% optional checkboxes on left-hand side
%
% Usage:
% Supply the parent figure, the handle of the axes object to use, the
% 'CreateTable' action, info about columns, and the cell data
%
% Example usage: (also just run with no arguments to see result)
%
% fig = nf;
% tbl = axes('units', 'pixels','position', [10 10 400 100]);
% cell_data = {...
% 'Alpha', 1, 2, 3,'';...
% 'Bravo', 4, 5, 6,'';...
% 'Charlie', 7, 8, 9,'';...
% 'Dog', 10,11,12,'';...
% 'Echo', 13,14,15,'';...
% 'Foxtrot',16,17,18,'';...
% 'Golf', 19,20,21,'';...
% 'Hotel', 26,27,28,'';...
% };
%
% columninfo.titles={'Param','Lower Limit','Upper Limit','Initial Value','Result'};
% columninfo.formats = {'%4.6g','%4.6g','%4.6g','%4.6g', '%4.6g'};
% columninfo.weight = [ 1, 1, 1, 1, 1];
% columninfo.multipliers = [ 1, 1, 1, 1, 1];
% columninfo.isEditable = [ 1, 1, 1, 1, 0];
% columninfo.isNumeric = [ 0 1, 1, 1, 1];
% columninfo.withCheck = true; % optional to put checkboxes along left side
% columninfo.chkLabel = 'Use'; % optional col header for checkboxes
% rowHeight = 16;
% gFont.size=9;
% gFont.name='Helvetica';
%
% mltable(fig, tbl, 'CreateTable', columninfo, rowHeight, cell_data, gFont);
%
% To use in a GUIDE-created figure:
%
% Create a figure including a blank "axes" object with the tag 'tblParams'
% Put the lines starting with the "cell_data" line above into your figure's
% OpeningFcn, but replace the mltable line with:
%
% mltable(gcf, handles.tblParams, 'CreateTable', columninfo, rowHeight, cell_data, gFont);
%% so clicking outside the table will finish edit in progress...
% endfcn = sprintf('mltable(%14.13f, %14.13f, ''SetCellValue'');', hObject, handles.tblParams);
% set(hObject,'buttondownfcn',endfcn);
%
% To access the data edited by the table:
%
% info = get(tbl, 'userdata');
% data = info.data;
%
%-------------------------------------------------------------------------
% All functions dispatched from here.
% If necessary to call from figure use: mltable(fig, hObj, 'Action',...)
global MINROWS;
MINROWS = 3;
if ~exist('action', 'var')
data = mltest;
return
end
switch(action)
case 'CreateTable'
data = createTable(fig, hObj, columnInfo, rowHeight, cell_data, gFont);
case 'DestroyTable'
data = destroyTable(fig, hObj);
case 'ResizeTable'
fig = resizeTable(fig, hObj);
case 'ScrollData'
fig = scrollData(fig, hObj);
case 'EditCell'
editCell(fig, hObj);
case 'SetCellValue'
setCellValue(fig, hObj);
case 'EndEdit'
setCellValue(fig, hObj);
case 'AddRow'
addRow(fig, hObj);
case 'DelRow'
delRow(fig, hObj);
case 'SetOnSetCell'
setOnSetCell(fig, hObj, varargin{:});
case 'OnSetCell'
data = onSetCell(fig, hObj, varargin{:});
case 'SetDblClick'
setDblClick(fig, hObj, varargin{:});
case 'OnDblClick'
onDblClick(fig, hObj, varargin{:});
case 'OnCheck'
onCheck(fig, hObj, varargin{1});
case 'SetCheck'
setCheck(fig, hObj, varargin{1}, varargin{2});
end
%-------------------------------------------------------------------------
%-------------------------------------------------------------------------
function data = createTable(fig, hObj, columnInfo, rowHeight, cell_data, gFont)
% Initially creates the table
%-------------------------------------------------------------------------
global MINROWS
data.figure = fig;
% get axes position in pixel coordinates
set(hObj, 'units', 'pixels');
set(hObj, 'visible', 'on');
pos_ax = get(hObj, 'position');
% set up grid info structure
ds = size(cell_data);
data.maxRows = ds(1);
if data.maxRows < MINROWS
blanks = cell(1, ds(2));
for ii = data.maxRows+1:MINROWS
cell_data = [cell_data; blanks];
end
data.maxRows = MINROWS;
end
data.data = cell_data;
data.isChecked = zeros(1,size(cell_data, 1));
data.axes = hObj;
data.userModified = zeros(ds);
data.rowHeight = rowHeight;
data.columnInfo = columnInfo;
data.numCols= length(columnInfo.titles);
data.ltGray = [92 92 92]/255;
data.OffscreenPos = [-1000 -1000 30 20];
data.selectedRow = 0;
data.selectedCol = 0;
data.gFont = gFont;
data.doCheck = false;
if isfield(data.columnInfo, 'withCheck') && ...
data.columnInfo.withCheck ~= 0
data.doCheck = true;
end
% use 0...1 scaling on table x and y positions
set(fig, 'CurrentAxes', data.axes);
set(data.axes, 'box', 'on', 'DrawMode', 'fast');
set(data.axes, 'xlimmode', 'manual', 'xlim', [0 1], 'ylim', [0 1], ...
'xtick', [], 'ytick', [], 'xticklabelmode', 'manual', 'xticklabel', []);
if data.doCheck % shrink on left for checkboxes column
data.checkdx = pos_ax(3) * 20 * (1/pos_ax(3)); % chkbox offset
pos_ax(1) = pos_ax(1) + data.checkdx;
pos_ax(3) = pos_ax(3) - data.checkdx;
end
pos_ax(3) = pos_ax(3) - 10; % width of slider
set(data.axes, 'position', pos_ax, 'LineWidth', 2);
% callback for starting editing
editfcn = sprintf('mltable(%14.13f, %14.13f, ''EditCell'');',fig, hObj);
set(data.axes, 'ButtonDownFcn', editfcn);
% callback for scrolling table
scrfcn = sprintf('mltable(%14.13f, %14.13f, ''ScrollData'');',fig, hObj);
data.slider = uicontrol('style', 'slider', 'units', 'pixels',...
'position', [pos_ax(1)+pos_ax(3)+2 pos_ax(2) 16 pos_ax(4)],...
'Callback', scrfcn);
% Add buttons for addrow/delrow
if sum(columnInfo.isEditable) > 0 && (~isfield(columnInfo,'rowsFixed') ||...
~columnInfo.rowsFixed)
btnw = 19; btnh = 15;
btnx = pos_ax(1) + pos_ax(3) - btnw - 2;
btny = pos_ax(2) + pos_ax(4) + 2;
btnfcn = sprintf('mltable(%14.13f, %14.13f, ''AddRow'');',fig, hObj);
data.btnAdd = uicontrol('style', 'pushbutton', 'units', 'pixels',...
'position', [btnx, btny, btnw, btnh],...
'string',' + ','fontsize',12,'Callback', btnfcn,...
'TooltipString','Click to add a row');
btnfcn = sprintf('mltable(%14.13f, %14.13f, ''DelRow'');',fig, hObj);
data.btnDel = uicontrol('style', 'pushbutton', 'units', 'pixels',...
'position', [btnx + btnw + 2, btny, btnw, btnh],...
'string',' - ','fontsize',12,'Callback', btnfcn,...
'TooltipString','Click to remove selected row');
set(data.btnAdd,'Units','normalized');
set(data.btnDel,'Units','normalized');
else
data.btnAdd = [];
data.btnDel = [];
end
set(hObj, 'UserData', data);
% so clicking outside the table will finish edit in progress
endfcn = sprintf('mltable(%14.13f, %14.13f, ''SetCellValue'');', fig, hObj);
set(fig,'buttondownfcn',endfcn);
resizeTable(fig, hObj);
return
%-------------------------------------------------------------------------
%-------------------------------------------------------------------------
function data = resizeTable(fig, hObj)
% fit table within boundaries and update scrollbar
% at this time doesn't handle figure resize
%-------------------------------------------------------------------------
data = get(hObj, 'UserData');
if isempty(data)
return
end
% zap checkboxes if any
if data.doCheck && isfield(data, 'checks')
delete(data.checks(:));
data.checks = [];
end
cla(hObj);
set(hObj, 'units', 'pixels');
set(fig,'CurrentAxes',hObj);
pos_ax = get(hObj,'position');
data.numRows = floor((pos_ax(4)-(2*data.rowHeight))/data.rowHeight);
if data.numRows > data.maxRows
data.numRows = data.maxRows;
end
unit_d_h = 1/pos_ax(3);
unit_d_v = 1/(pos_ax(4) - data.rowHeight);
if(data.numRows < data.maxRows)
set(data.slider,'Units','pixels');
set(data.slider, 'visible', 'on',...
'position', [pos_ax(1)+pos_ax(3)+1 pos_ax(2) 16 pos_ax(4)], ...
'min', 0,...
'max', data.maxRows - data.numRows, 'value', data.maxRows - data.numRows, ...
'sliderstep', [1/(data.maxRows-data.numRows) data.numRows/(data.maxRows-data.numRows)]);
else
set(data.slider, 'visible', 'off');
end
% get gui units for rows and columns
% average column width and row height
d_x = 1/sum(data.columnInfo.weight);
d_y = 1/(data.numRows + 1);
% minimum adjust unit
unit_d_h = 1/(pos_ax(3));
unit_d_v = 1/(pos_ax(4) - data.rowHeight);
% Horizontal line positions
lx_h = ones(2, data.numRows+1);
lx_h(1, :) = 0;
ly_h = [1:data.numRows+1; 1:data.numRows+1]/(data.numRows+1);
% Vertical line positions
ly_v = ones(2, data.numCols);
ly_v(1, :) = 0;
lx_v = [d_x*data.numCols 2:data.numCols; d_x*data.numCols 2:data.numCols]/data.numCols;
for i = 2:data.numCols
lx_v(:, i) = lx_v(:, i-1)+d_x*data.columnInfo.weight(i);
end
% draw initial grid
data.vertLines = line(lx_v, ly_v);
data.vertLines1 = line(lx_v(:, 1:(data.numCols-1)), ly_v(:, 1:(data.numCols-1)));
data.horizLines = line(lx_h, ly_h);
set(data.horizLines, 'color', data.ltGray);
set(data.vertLines, 'color', data.ltGray, 'LineWidth', 2);
set(data.vertLines1, 'color', [1 1 1], 'LineWidth', 0.5);
% now display text in grid
txt_x = [0:data.numCols-1]/data.numCols + 4*unit_d_h;
for i = 2:data.numCols
txt_x(i) = txt_x(i-1) + d_x*data.columnInfo.weight(i-1);
end
data.txt_x = txt_x;
data.txtCells = zeros(data.numRows, data.numCols);
uictx = get(hObj,'UIContextMenu');
chkdx = (pos_ax(3) * 20 * unit_d_h); % chkbox offset
chkdy = pos_ax(4) * d_y;
for j = 1:data.numRows
txt_y = (data.numRows-j+1)/(data.numRows+1) * ones(1, data.numCols);
txt_y = txt_y - (0.9*d_y); % reduce by (almost?) one row (title row)
data.txtCells(j, :) = text(txt_x, txt_y, 'a','Clipping','on');
if data.doCheck % put checkboxes to left of row
poschk = [ pos_ax(1) - chkdx...
pos_ax(2) + 3 + chkdy * (data.numRows - j)...
10 10 ];
data.checks(j) = ...
uicontrol('style','checkbox','units','pixels','position', poschk);
chkfcn = sprintf('mltable(%14.13f, %14.13f,''OnCheck'',[], [], [], [], %d);',...
fig, hObj, j);
set(data.checks(j), 'Units','normalized','Callback', chkfcn);
end
for i = 1:data.numCols
if data.columnInfo.isNumeric(i)
nums = data.data{j, i}/data.columnInfo.multipliers(i);
nums = num2str(nums, data.columnInfo.formats{i});
set(data.txtCells(j, i), 'string', nums);
else
set(data.txtCells(j, i), 'string', StripChars(data.data{j, i}));
end
set(data.txtCells(j, i), 'Position', [txt_x(i), txt_y(i)]);
set(data.txtCells(j, i), 'UIContextMenu', uictx);
end
end
set(data.txtCells(:, :), 'FontSize', data.gFont.size, 'FontName', data.gFont.name, 'FontWeight', 'normal', ...
'HorizontalAlignment','left','VerticalAlignment', 'bottom');
set(data.txtCells(1:data.numRows, 1:data.numCols), 'buttondownfcn', get(data.axes, 'ButtonDownFcn'));
% do title cells
titleCellsy = ones(1, data.numCols);
data.titleCells = text(txt_x, titleCellsy, data.columnInfo.titles);
set(data.titleCells(:, :), 'FontSize', data.gFont.size, 'FontName', data.gFont.name, 'FontWeight', 'bold', ...
'HorizontalAlignment','Center','VerticalAlignment', 'top','Editing','off');
for i = 1:length(data.titleCells)
if i > 1
titleOffset = 0.92 * (lx_v(1,i) - lx_v(1,i-1)) / 2;
else
titleOffset = (lx_v(1,i)) / 2;
end
pos = get(data.titleCells(i), 'position');
pos(1) = pos(1) + titleOffset;
set(data.titleCells(i), 'position', pos);
if(data.columnInfo.isEditable(i) == 0)
set(data.titleCells(i, :), 'FontWeight', 'normal');
set(data.txtCells(:, i), 'FontWeight', 'normal');
end
end
if data.doCheck && isfield(data.columnInfo,'chkLabel')
chkLbl = text(-25*unit_d_h, titleCellsy(1), data.columnInfo.chkLabel);
set(chkLbl, 'FontSize', data.gFont.size, 'FontName', data.gFont.name, 'FontWeight', 'bold', ...
'HorizontalAlignment','left','VerticalAlignment', 'top','Editing','off');
end
row = 1;
x1 = 0; x2 = 1;
y1 = (data.numRows - row + 1)/(data.numRows+1);
y2 = y1 + (1/(data.numRows+1)) + .01;
makepatch(hObj,x1,x2,y1,y2, 0.753);
set(hObj, 'UserData', data);
scrollData(fig, hObj);
set(hObj, 'units', 'normalized');
return
%-------------------------------------------------------------------------
%-------------------------------------------------------------------------
function data = scrollData(fig, hObj)
% handle scrollbar (slider) callback
%-------------------------------------------------------------------------
data = get(hObj, 'UserData');
if isempty(data)
return
end
set(data.slider,'Units','pixels');
if isfield(data,'editBox') && ishandle(data.editBox)
delete(data.editBox);
end
% handle non-scroll case in case slider was switched off
if(strcmp(get(data.slider, 'visible'), 'off') == 1)
ind0 = 0;
for i = 1:data.numRows
if data.doCheck
set(data.checks(i),'value',data.isChecked(i+ind0));
end
for j = 1:data.numCols
if data.columnInfo.isNumeric(j)
nums = data.data{i, j}/data.columnInfo.multipliers(j);
nums = num2str(nums, data.columnInfo.formats{j});
set(data.txtCells(i, j), 'string', nums);
else
set(data.txtCells(i, j), 'string', data.data{i, j});
end
end
end
else
val = get(data.slider, 'Value');
max_val = get(data.slider, 'Max');
min_val = get(data.slider, 'Min');
val0 = data.maxRows - data.numRows;
ind0 = round(val0-val);
% move the text to give illusion of scrolling
for i = ind0+1:(ind0+data.numRows)
if data.doCheck
set(data.checks(i-ind0),'value',data.isChecked(i));
end
for j = 1:data.numCols
if data.columnInfo.isNumeric(j)
nums = data.data{i, j}/data.columnInfo.multipliers(j);
nums = num2str(nums, data.columnInfo.formats{j});
set(data.txtCells(i-ind0, j), 'string', nums);
else
set(data.txtCells(i-ind0, j), 'string', data.data{i, j});
end
end
end
end
% save scroll position
data.ind0 = ind0;
data.hpatch = remakepatch(data.selectedRow, data, hObj);
set(data.slider,'Units','normalized');
set(hObj, 'UserData', data);
return
% -----------------------------------------------------------------------
% -----------------------------------------------------------------------
function [hpatch] = makepatch(hObj, x1, x2, y1, y2, co)
% -----------------------------------------------------------------------
if ~exist('co','var')
co = 0.88;
end
hpatch = ...
patch([x1 x2 x2 x1 x1],[y1 y1 y2 y2 y1],[co co co],...
'HitTest','off','FaceAlpha',0.2);
ch=get(hObj,'children');
% put new patch at bottom layer
c1 = ch(1); % latest object
ch = ch(2:end); % shift up
ch(size(ch,1)+1) = c1; % append new
set(hObj,'children',ch);
return
% -----------------------------------------------------------------------
% -----------------------------------------------------------------------
function [hpatch] = remakepatch(row, data, hObj)
% -----------------------------------------------------------------------
hpatch = []; % empty return if nothing to do
% see if selected row is visible
if ((row - data.ind0) <= (data.numRows) && (row - data.ind0) > 0)
% yes, compute row coordinates
row = row - data.ind0 + 1;
x1 = 0; x2 = 1;
y1 = (data.numRows - row + 1)/(data.numRows+1);
y2 = y1 + (1/(data.numRows+1)) + .005;
% see if a previous patch exists
if isfield(data,'hpatch') && ~isempty(data.hpatch) && ishandle(data.hpatch)
% yes, see if it is on same row
yp = get(data.hpatch,'ydata');
if y1 ~= yp(1)
% no, delete old patch and make new one
delete(data.hpatch);
data.hpatch = makepatch(hObj,x1,x2,y1,y2);
end
else % no previous patch exists, make new one
data.hpatch = makepatch(hObj,x1,x2,y1,y2);
end
hpatch = data.hpatch; % return new or previous patch
else % if patch is no longer visible, delete it
if isfield(data,'hpatch') && ~isempty(data.hpatch) && ishandle(data.hpatch)
delete(data.hpatch);
end
end
return
%-------------------------------------------------------------------------
%-------------------------------------------------------------------------
function data = destroyTable(fig, hObj)
% Destroys the table
%-------------------------------------------------------------------------
data = get(hObj, 'UserData');
if ~isempty(data)
set(hObj, 'visible','off');
cla(hObj);
if isfield(data.columnInfo, 'withCheck') && ...
data.columnInfo.withCheck ~= 0 && ...
isfield(data, 'checks')
delete(data.checks(:));
data.checks = [];
end
% restore orig size
set(data.axes, 'Units', 'pixels');
pos_ax = get(data.axes, 'position');
if data.doCheck % restore on left for checkboxes column
pos_ax(1) = pos_ax(1) - data.checkdx;
pos_ax(3) = pos_ax(3) + data.checkdx;
end
pos_ax(3) = pos_ax(3) + 10; % width of slider;
set(data.axes, 'position', pos_ax);
set(data.axes, 'Units', 'normalized');
delete(data.slider);
delete(data.btnAdd);
delete(data.btnDel);
data = [];
set(hObj, 'UserData', data);
end
return
%-------------------------------------------------------------------------
%-------------------------------------------------------------------------
function data = editCell(fig, hObj)
% put an edit control over the selected cell
%-------------------------------------------------------------------------
persistent lasttime;
data = get(hObj, 'UserData');
if isempty(data)
return
end
if isempty(lasttime)
tic;
lasttime = toc - .400;
end
thistime = toc;
if (thistime - lasttime) < .350
mltable(fig, hObj, 'OnDblClick');
return
end
lasttime = thistime;
set(hObj, 'units', 'pixels');
pt = get(hObj, 'CurrentPoint');
pt=pt(1,:); % strip out 2nd axis info
pos_ax = get(hObj, 'position');
pt(1) = pos_ax(1) + (pt(1) * pos_ax(3));
pt(2) = pt(2) .* pos_ax(4);
d_x = pos_ax(3)/sum(data.columnInfo.weight);
d_y = pos_ax(4)/(data.numRows+1);
% find column index
col = -1;
p1 = 0;
p2 = 0;
for i = 1:data.numCols
p2 = p1 + d_x*data.columnInfo.weight(i);
if((p1 <= (pt(1)-pos_ax(1))) & (p2 >= (pt(1)-pos_ax(1))))
col = i;
break;
else
p1 = p2;
end;
end
if(col == -1)
set(hObj, 'units', 'normalized');
return;
end
% find row index
row = data.numRows - (floor(pt(2) / d_y));
if(row < 1) % could be header row
set(hObj, 'units', 'normalized');
return;
end
data.selectedCol = col;
data.selectedRow = row + data.ind0;
if isfield(data, 'editBox') && ishandle(data.editBox)
delete(data.editBox);
end
data.hpatch = remakepatch(data.selectedRow, data, hObj);
% continue only if editable
if(0 ~= data.columnInfo.isEditable(col) && row <= data.numRows)
unit_d_h = 1/pos_ax(3);
unit_d_v = 1/pos_ax(4);
% handle numeric (or not) data
if data.columnInfo.isNumeric(col)
ebtxt = data.data{row + data.ind0, col}/data.columnInfo.multipliers(col);
ebtxt = num2str(ebtxt, data.columnInfo.formats{col});
else
ebtxt = UnStripChars(data.data{row + data.ind0, col});
end
% set the edt control contents and position
% callback for entering cell data
endfcn = sprintf('mltable(%14.13f, %14.13f, ''SetCellValue'');',fig, hObj);
data.editBox = uicontrol('style', 'edit', 'units', 'pixels',...
'Callback', endfcn);
set(data.editBox, 'FontSize', data.gFont.size, 'FontName', data.gFont.name,...
'FontWeight', 'normal');
set(data.editBox, 'string', ebtxt, 'UserData', [row col]);
ext_eb = get(data.editBox, 'extent');
ext_eb(4) = d_y + 3;
pos = [(pos_ax(1)-unit_d_h+p1) ,...
pos_ax(2) + ... % start of table
ceil((data.numRows - row) * d_y) + ... % cvt index to row #, get offset from ystart
(ceil(d_y) - ext_eb(4))/2, ... % add half of the ctrl height??
floor(d_x*data.columnInfo.weight(col))-unit_d_h, ...
ext_eb(4)];
% fprintf(1, 'Click at point (%3.2f, %3.2f) on cell (%d, %d) coordinates [%3.2f %3.2f %3.2f %3.2f]\n', ...
% pt(1), pt(2), col, row, pos(1), pos(2), pos(3), pos(4));
set(data.editBox, 'Position', pos, 'HorizontalAlignment' ,'Left');
set(fig, 'CurrentObject', data.editBox);
%set(data.editBox,'Editing','true');
end
set(hObj, 'UserData', data);
set(hObj, 'units', 'normalized');
return
%-------------------------------------------------------------------------
%-------------------------------------------------------------------------
function data = setCellValue(fig, hObj)
% when edit control calls back, update data in cell
%-------------------------------------------------------------------------
data = get(hObj, 'UserData');
if isempty(data)
return
end
if ~isfield(data,'editBox') || ~ishandle(data.editBox)
return
end
ind = get(data.editBox, 'UserData');
if isempty(ind)
return;
end;
nums = StripChars(get(data.editBox, 'string'));
row = ind(1) + data.ind0; col = ind(2);
d_old = data.data{row, col};
if data.columnInfo.isNumeric(col)
num = sscanf(nums, '%f');
if(isempty(num))
errordlg('Please enter a valid number', 'Error', 'modal');
return;
end
d_new = num*data.columnInfo.multipliers(col);
if(d_old == d_new)
delete(data.editBox);
return;
end
if mltable(fig, hObj, 'OnSetCell', [], [], [], [], d_old, d_new(1))
nums = num2str(num, data.columnInfo.formats{col});
data.data{row, col} = d_new;
else
nums = num2str(d_old/data.columnInfo.multipliers(col), data.columnInfo.formats{col});
end
else
if mltable(fig, hObj, 'OnSetCell', [], [], [], [], data.data{row, col}, nums)
data.data{row, col} = nums;
else
nums = data.data{row, col};
end
end
% need to check handles, since OnSetCell callback may have refreshed table
if ishandle(data.editBox)
delete(data.editBox);
end
if ishandle(data.txtCells(row - data.ind0, col))
set(data.txtCells(row - data.ind0, col), 'string', nums);
set(hObj,'UserData',data);
end
return
%-------------------------------------------------------------------------
%-------------------------------------------------------------------------
function data = addRow(fig, hObj)
% insert a row into the table
%-------------------------------------------------------------------------
data = get(hObj, 'UserData');
if isempty(data)
return
end
% increase the number of rows
data.maxRows = data.maxRows + 1;
selRow = data.selectedRow;
if selRow < 1
selRow = 1;
end
% move data from new row and following down one row
dtmp = data.data;
ctmp = data.isChecked;
for jj = size(dtmp, 1):-1:selRow % for subsequent rows
ctmp(jj+1) = ctmp(jj);
for ii = 1:size(dtmp,2) % for all columns
dtmp{jj+1, ii} = data.data{jj, ii};
end
end
% zap data in new row
ctmp(selRow) = 0;
for ii = 1:size(dtmp,2) % for all columns
dtmp{selRow, ii} = '';
end
data.data = dtmp;
data.isChecked = ctmp;
set(hObj, 'UserData', data);
resizeTable(fig, hObj);
return
%-------------------------------------------------------------------------
%-------------------------------------------------------------------------
function data = delRow(fig, hObj)
% delete the currently selected row
%-------------------------------------------------------------------------
global MINROWS
data = get(hObj, 'UserData');
if isempty(data)
return
end
selRow = data.selectedRow;
if selRow < 1
selRow = data.maxRows;
end
if data.maxRows < 2
return
end
% decrease the number of rows
data.maxRows = data.maxRows - 1;
mr = data.maxRows;
cols = size(data.data,2);
dtmp = {};
ctmp = [];
% remove the selected row
% copy previous data
for ii = 1:selRow-1
ctmp(ii) = data.isChecked(ii);
for jj = 1:cols
dtmp{ii, jj} = data.data{ii, jj};
end
end
% copy following data
for ii = selRow+1:size(data.data,1)
ctmp(ii-1) = data.isChecked(ii);
for jj = 1:cols
dtmp{ii-1, jj} = data.data{ii, jj};
end
end
if data.maxRows < MINROWS
blanks = cell(1, size(dtmp, 2));
for ii = data.maxRows+1:MINROWS
dtmp = [dtmp; blanks];
ctmp(ii) = 0;
end
data.maxRows = MINROWS;
end
data.data = dtmp;
data.isChecked = ctmp;
set(hObj, 'UserData', data);
resizeTable(fig, hObj);
return
% ------------------------------------------------------------------------
% ------------------------------------------------------------------------
function [] = setOnSetCell(fig, hObj, varargin);
% establishes an action for double-clicking on a cell
% call as "mltable(fig, hobj, 'SetDblClick', 'Myfunc', 'fmt_str', args..."
% where "fmt_str" and args are optional
% function name supplied will be called as
% [] = Myfunc(hObject, [], handles, arg1, arg2, ...)
% ------------------------------------------------------------------------
sfig = varargin{1};
sfunc = varargin{2};
data = get(hObj, 'UserData');
data.OnSetCellFcn{1} = sfig;
data.OnSetCellFcn{2} = sfunc;
% if nargin < -3
if nargin > 4
data.SetCellFmt = varargin{3};
end
set(hObj, 'UserData', data);
return
% ------------------------------------------------------------------------
% ------------------------------------------------------------------------
function [res] = onSetCell(fig, hObj, varargin);
% establishes an action for finising a cell edit
% ------------------------------------------------------------------------
res = true;
data = get(hObj, 'UserData');
if ~isfield(data,'OnSetCellFcn')
return
end
% start with func name, hObject (fig), evdata ([]), and handles
sfmt = '%s(''%s'', %14.13f, [], handles';
sfig = data.OnSetCellFcn{1};
sfunc = data.OnSetCellFcn{2};
if isfield(data,'SetCellFmt')
sfmt = [sfmt ', ' data.SetCellFmt];
end
handles = guidata(fig);
fcn = sprintf(sfmt, sfig, sfunc, hObj, varargin{:});
fcn = [fcn ');'];
try
res = eval(fcn);
catch
res = [];
disp(['error in OnSetCell callback:\n' lasterr]);
end
return
% ------------------------------------------------------------------------
% ------------------------------------------------------------------------
function [] = setDblClick(fig, hObj, varargin);
% establishes an action for double-clicking on a cell
% call as "mltable(fig, hobj, 'SetDblClick', 'Myfunc', 'fmt_str', args..."
% where "fmt_str" and args are optional
% function name supplied will be called as
% [] = Myfunc(hObject, [], handles, arg1, arg2, ...)
% ------------------------------------------------------------------------
sfig = varargin{1};
sfunc = varargin{2};
data = get(hObj, 'UserData');
data.OnDblClickFcn{1} = sfig;
data.OnDblClickFcn{2} = sfunc;
if nargin < -3
data.DblClickFmt = varargin{2};
end
set(hObj, 'UserData', data);
return
% ------------------------------------------------------------------------
% ------------------------------------------------------------------------
function [] = onDblClick(fig, hObj, varargin);
% establishes an action for double-clicking on a cell
% ------------------------------------------------------------------------
data = get(hObj, 'UserData');
if ~isfield(data,'OnDblClickFcn')
return
end
% start with func name, hObject (fig), evdata ([]), and handles
sfmt = '%s(''%s'', %14.13f, [], handles';
sfig = data.OnDblClickFcn{1};
sfunc = data.OnDblClickFcn{2};
if isfield(data,'DblClickFmt')
sfmt = [sfmt ', ' data.DblClickFmt];
end
sfmt = [sfmt ');'];
handles = guidata(fig);
fcn = sprintf(sfmt, sfig, sfunc, hObj, varargin{:});
try
eval(fcn);
end
return
% ------------------------------------------------------------------------
% ------------------------------------------------------------------------
function [] = onCheck(fig, hObj, row);
% What happens when a user clicks on a row's checkbox
% ------------------------------------------------------------------------
data = get(hObj, 'UserData');
rowchk = row + data.ind0;
vchk = get(data.checks(row),'value');
data.isChecked(rowchk) = vchk;
set(hObj,'UserData',data);
return
% ------------------------------------------------------------------------
% ------------------------------------------------------------------------
function [] = setCheck(fig, hObj, row, vchk);
% allows parent to set the data row's checked state
% ------------------------------------------------------------------------
data = get(hObj, 'UserData');
if row > data.maxRows
return
end
if row - data.ind0 <= data.numRows
set(data.checks(row - data.ind0),'value', vchk);
end
data.isChecked(row) = vchk;
set(hObj,'UserData',data);
return
% ------------------------------------------------------------------------
% --------------------------------------------------------------------
function [sout] = StripChars(sin)
sbad = '_';
sout = sin;
stmp = [];
[sf, sr] = strtok(sin, sbad);
while ~isempty(sr) % found a '_' char
stmp = [stmp sf '\_']; % replace with '\_'
[sf, sr] = strtok(sr, sbad);
end
if ~isempty(stmp)
stmp = [stmp sf];
sout = stmp;
end
return
% --------------------------------------------------------------------
function [sout] = UnStripChars(sin)
sbad = '\\';
sout = sin;
stmp = [];
[sf, sr] = strtok(sin, sbad);
while ~isempty(sr) % found a '\' char
stmp = [stmp sf ]; % remove '\'
[sf, sr] = strtok(sr, sbad);
end
if ~isempty(stmp)
stmp = [stmp sf];
sout = stmp;
end
return
function result = trim(string)
[nR, nC] = size(string);
indexStart = 1;
indexEnd = nC;
for i = 1:nC
if(string(1, indexStart) == ' ')
indexStart = indexStart + 1;
else
break;
end
end
for i = nC:-1:1
if(string(1, indexEnd) == ' ')
indexEnd = indexEnd - 1;
else
break;
end
end
result = string(indexStart:indexEnd);
% ------------------------------------------------------------------------
% ------------------------------------------------------------------------
function [data] = mltest
% function to test the table
% ------------------------------------------------------------------------
fig = figure('renderer','zbuffer');
pos = get(fig, 'position');
pos(3) = 440;pos(4)=160;
set(fig,'position',pos);
tbl = axes('units', 'pixels','position', [20 20 400 120]);
cell_data = {...
'Alpha', 1, 2, 3,'';...
'Bravo', 4, 5, 6,'';...
'Charlie', 7, 8, 9,'';...
'Dog', 10,11,12,'';...
'Echo', 13,14,15,'';...
'Foxtrot',16,17,18,'';...
'Golf', 19,20,21,'';...
'Hotel', 26,27,28,'';...
};
columninfo.titles={'Param','Lower Limit','Upper Limit','Initial Value','Result'};
columninfo.formats = {'%4.6g','%4.6g','%4.6g','%4.6g', '%4.6g'};
columninfo.weight = [ 1, .85, .85, .85, .85];
columninfo.multipliers = [ 1, 1, 1, 1, 1];
columninfo.isEditable = [ 1, 1, 1, 1, 0];
columninfo.isNumeric = [ 0 1, 1, 1, 1];
columninfo.withCheck = true;
columninfo.chkLabel = 'Use';
rowHeight = 16;
gFont.size=9;
gFont.name='Helvetica';
data = mltable(fig, tbl, 'CreateTable', columninfo, rowHeight, cell_data, gFont);
return
|
|