This repository has been archived by the owner. It is now read-only.
Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
IntrinsicImaging/uiGridLayout.m
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
364 lines (276 sloc)
11.6 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
classdef uiGridLayout < handle | |
%UIGRIDLAYOUT Calculates UI component position | |
% | |
% obj = UIGRIDLAYOUT('PARENT', handle) class constructor based on | |
% parent graphics position. | |
% | |
% obj = UIGRIDLAYOUT(..., 'VGRID', varnum) set vertical grid count | |
% | |
% obj = UIGRIDLAYOUT(..., 'HGRID', varnum) set horizontal grid count | |
% | |
% obj = UIGRIDLAYOUT(..., 'VGAP', varvector) set vertical gap offset, | |
% varvector can be 1x1, 1x2 or 1x3, defining top, middle and bottom offset | |
% | |
% obj = UIGRIDLAYOUT(..., 'HGAP', varvector) set horizontal gap offset, | |
% varvector can be 1x1, 1x2 or 1x3, defining left, center and right offset | |
% | |
% obj.getGrid() method to return default 1,1 grid box position | |
% | |
% obj.getGrid('VIndex', varvector) specify indexes of grid boxes to | |
% include in vertical position, max(varvector) <= VGRID | |
% | |
% obj.getGrid('HIndex', varvector) specify indexes of grid boxes to | |
% include in horizontal position, max(varvector) <= HGRID | |
% | |
% obj.align(handle) aligns given handle that is a child uicontrol in the | |
% grid. | |
% | |
% obj.align(...,'VIndex', varvector, 'HIndex', varvector) specify vertical | |
% and horizontal grid position to align the handle | |
% | |
% obj.align(...,'Anchor', varchar) specify the method of alignment. | |
% VARCHAR can be center(default), north, south, west, east, northwest, | |
% northeast, southwest, southeast | |
% | |
% Georgi Tushev | |
% Max-Planck Institute for Brain Research | |
% sciclist@brain.mpg.de | |
% | |
properties | |
parent | |
verGrid_Count | |
verGrid_Pos | |
verGrid_Size | |
verGrid_GapTop | |
verGrid_GapMiddle | |
verGrid_GapBottom | |
horGrid_Count | |
horGrid_Pos | |
horGrid_Size | |
horGrid_GapLeft | |
horGrid_GapCenter | |
horGrid_GapRight | |
end | |
methods | |
% method :: uiGridLaout | |
% input :: varargin | |
% action :: class constructor | |
function obj = uiGridLayout(varargin) | |
% use parser class | |
parseObj = inputParser; | |
addParameter(parseObj, 'Parent', [],@isgraphics); | |
addParameter(parseObj, 'VGrid', 1, @isnumeric); | |
addParameter(parseObj, 'HGrid', 1, @isnumeric); | |
addParameter(parseObj, 'VGap', [0, 0, 0], @isgap); | |
addParameter(parseObj, 'HGap', [0, 0, 0], @isgap); | |
parse(parseObj, varargin{:}); | |
% parse main properties | |
obj.parent = parseObj.Results.Parent; | |
obj.verGrid_Count = parseObj.Results.VGrid; | |
obj.horGrid_Count = parseObj.Results.HGrid; | |
% parse gap properties | |
obj.setGridGap(parseObj.Results.VGap, 'vertical'); | |
obj.setGridGap(parseObj.Results.HGap, 'horizontal'); | |
% calculate grid size | |
obj.setGridSize(); | |
% calulate grid position | |
obj.setGridPosition(); | |
end | |
% method :: getGrid | |
% input :: class object, varargin | |
% action :: calculate grid coordinates | |
function grid = getGrid(obj, varargin) | |
% use parser | |
parseObj = inputParser; | |
addParameter(parseObj, 'VIndex', 1, @(x) validateattributes(x,{'double'},{'vector'})); | |
addParameter(parseObj, 'HIndex', 1, @(x) validateattributes(x,{'double'},{'vector'})); | |
parse(parseObj, varargin{:}); | |
% set each grid index | |
gridVIndex = parseObj.Results.VIndex; | |
if isempty(gridVIndex) || (max(gridVIndex) > obj.verGrid_Count) | |
error('uiGridLayout:gridVIndex','grid index outside gird.'); | |
end | |
gridHIndex = parseObj.Results.HIndex; | |
if isempty(gridHIndex) || (max(gridHIndex) > obj.horGrid_Count) | |
error('uiGridLayout:gridHIndex','grid index outside gird.'); | |
end | |
% calculate temp grid | |
grid(1) = obj.horGrid_Pos(gridHIndex(1)); | |
grid(2) = obj.verGrid_Pos(gridVIndex(end)); | |
grid(3) = length(gridHIndex) * obj.horGrid_Size + (length(gridHIndex) - 1) * obj.horGrid_GapCenter; | |
grid(4) = length(gridVIndex) * obj.verGrid_Size + (length(gridVIndex) - 1) * obj.verGrid_GapMiddle; | |
end | |
% method :: align | |
% input :: class object, handle, varargin | |
% action :: align handle to grid | |
function obj = align(obj, handle, varargin) | |
% use parser | |
parseObj = inputParser; | |
addParameter(parseObj, 'VIndex', 1, @(x) validateattributes(x,{'double'},{'vector'})); | |
addParameter(parseObj, 'HIndex', 1, @(x) validateattributes(x,{'double'},{'vector'})); | |
addParameter(parseObj, 'Anchor', 'center', @isanchor); | |
parse(parseObj, varargin{:}); | |
% set vars | |
VIndex = parseObj.Results.VIndex; | |
HIndex = parseObj.Results.HIndex; | |
anchor = parseObj.Results.Anchor; | |
% check if handle's parent is the uiGridLayout parent | |
if get(handle, 'Parent') ~= obj.parent | |
error('uiGridLayout:HandleMismatch','given handle has different parent.'); | |
end | |
% get constraints | |
if isgraphics(handle, 'uicontrol') && strcmp(get(handle,'style'),'text') | |
position = get(handle, 'Extent'); | |
else | |
position = get(handle, 'Position'); | |
end | |
VMax = position(4); | |
HMax = position(3); | |
% get current grid | |
tempgrid = obj.getGrid('VIndex',VIndex, 'HIndex', HIndex); | |
% update size | |
if VMax < tempgrid(4) | |
grid(4) = VMax; | |
else | |
grid(4) = tempgrid(4); | |
end | |
if HMax < tempgrid(3) | |
grid(3) = HMax; | |
else | |
grid(3) = tempgrid(3); | |
end | |
% update position | |
% set final grid position | |
switch lower(anchor) | |
case 'center' | |
grid(1) = tempgrid(1) + (tempgrid(3) - grid(3))/2; | |
grid(2) = tempgrid(2) + (tempgrid(4) - grid(4))/2; | |
case 'north' | |
grid(1) = tempgrid(1) + (tempgrid(3) - grid(3))/2; | |
grid(2) = tempgrid(2) + (tempgrid(4) - grid(4)); | |
case 'south' | |
grid(1) = tempgrid(1) + (tempgrid(3) - grid(3))/2; | |
grid(2) = tempgrid(2); | |
case 'west' | |
grid(1) = tempgrid(1); | |
grid(2) = tempgrid(2) + (tempgrid(4) - grid(4))/2; | |
case 'east' | |
grid(1) = tempgrid(1) + (tempgrid(3) - grid(3)); | |
grid(2) = tempgrid(2) + (tempgrid(4) - grid(4))/2; | |
case 'northwest' | |
grid(1) = tempgrid(1); | |
grid(2) = tempgrid(2) + (tempgrid(4) - grid(4)); | |
case 'northeast' | |
grid(1) = tempgrid(1) + (tempgrid(3) - grid(3)); | |
grid(2) = tempgrid(2) + (tempgrid(4) - grid(4)); | |
case 'southwest' | |
grid(1) = tempgrid(1); | |
grid(2) = tempgrid(2); | |
case 'southeast' | |
grid(1) = tempgrid(1) + (tempgrid(3) - grid(3)); | |
grid(2) = tempgrid(2); | |
end | |
% update handle position | |
set(handle, 'Position', grid); | |
end | |
% method :: setGridPosition | |
% input :: class object | |
% action :: calculate grid position | |
function obj = setGridPosition(obj) | |
% calculate grid position | |
obj.verGrid_Pos = flipud(cumsum(... | |
[obj.verGrid_GapBottom;... | |
repmat(obj.verGrid_Size + obj.verGrid_GapMiddle,... | |
obj.verGrid_Count - 1, 1)])); | |
obj.horGrid_Pos = cumsum(... | |
[obj.horGrid_GapLeft;... | |
repmat(obj.horGrid_Size + obj.horGrid_GapCenter,... | |
obj.horGrid_Count -1, 1)]); | |
end | |
% method :: setGridSize | |
% input :: class object | |
% action :: calculate grid size | |
function obj = setGridSize(obj) | |
% get parent position | |
position = get(obj.parent, 'Position'); | |
% calculate grid size | |
obj.verGrid_Size = (position(4) - ... | |
obj.verGrid_GapTop - ... | |
obj.verGrid_GapMiddle * (obj.verGrid_Count - 1) - ... | |
obj.verGrid_GapBottom) / obj.verGrid_Count; | |
obj.horGrid_Size = (position(3) - ... | |
obj.horGrid_GapLeft - ... | |
obj.horGrid_GapCenter * (obj.horGrid_Count - 1) - ... | |
obj.horGrid_GapRight) / obj.horGrid_Count; | |
end | |
% method :: setGridGap | |
% input :: class object, gap, direction | |
% action :: assign gap based on provided values and direction | |
function obj = setGridGap(obj, gap, direction) | |
% distribute gaps based on | |
% provided values | |
switch length(gap) | |
case 1 | |
maxGap = gap; | |
medGap = gap; | |
minGap = gap; | |
case 2 | |
maxGap = gap(1); | |
medGap = gap(2); | |
minGap = gap(1); | |
case 3 | |
maxGap = gap(1); | |
medGap = gap(2); | |
minGap = gap(3); | |
end | |
% assign based on direction | |
if strcmpi('vertical', direction) | |
obj.verGrid_GapTop = maxGap; | |
obj.verGrid_GapMiddle = medGap; | |
obj.verGrid_GapBottom = minGap; | |
elseif strcmpi('horizontal', direction) | |
obj.horGrid_GapLeft = maxGap; | |
obj.horGrid_GapCenter = medGap; | |
obj.horGrid_GapRight = minGap; | |
end | |
end | |
end | |
end | |
%%% --- parser functions --- %%% | |
function tf = isanchor(varchar) | |
% default output | |
tf = true; | |
% check class | |
if ~ischar(varchar) | |
tf = false; | |
end | |
% check if in list | |
reflist = {'center',... | |
'north',... | |
'south',... | |
'west',... | |
'east',... | |
'northwest',... | |
'northeast',... | |
'southwest',... | |
'souteast'}; | |
if ~any(strcmpi(varchar, reflist)) | |
tf = false; | |
end | |
end | |
function tf = isgap(varvalue) | |
% default output | |
tf = true; | |
% check class | |
if ~isa(varvalue, 'double') | |
tf = false; | |
end | |
% check dimension | |
if isempty(varvalue) || (length(varvalue) > 3) | |
tf = false; | |
end | |
% check for full number | |
if any(rem(varvalue,1)) | |
tf = false; | |
end | |
end |