diff --git a/README.md b/README.md
index 4409527..98f4e4f 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,7 @@ For additional information, see Iliya Romm's guest Undocumented Matlab article,
[`textAlign`](#textAlign) - Modify text alignment
[`fontWeight`](#fontWeight) - Modify font weight
[`fontColor`](#fontColor) - Modify font folor
+[`setStyle`](#setStyle) - Modify a specified style property
#### *mlapptools*.**textAlign**(*uielement*, *alignment*)
@@ -82,4 +83,21 @@ mlapptools.fontColor(myGUI.TextArea, 'aqua');
```MATLAB
myGUI = DOMdemoGUI;
mlapptools.fontColor(myGUI.TextArea, 'rgb(255,165,0)');
+```
+
+
+#### *mlapptools*.**setStyle**(*uielement*, *styleAttr*, *styleValue*)
+##### Description
+Set the style attribute `styleAttr` of the specified UI element, `'uielement'`, to the value `styleValue`. `styleAttr` should be any valid CSS attribute, and `styleValue` a valid setting thereof.
+
+This method provides a general interface to change CSS style attributes, with minimal input testing and error reporting, so it is up to the user to provide valid inputs.
+
+Valid style attributes and corresponding settings can be found [here](https://www.w3schools.com/cssref/).
+
+##### Examples
+Using the demo GUI generated by `./Demo/DOMdemoGUI.m`
+```MATLAB
+myGUI = DOMdemoGUI;
+mlapptools.setStyle(myGUI.TextArea, 'background-image',...
+ 'url(https://upload.wikimedia.org/wikipedia/commons/8/80/Wikipedia-logo-v2.svg)');
```
\ No newline at end of file
diff --git a/mlapptools.m b/mlapptools.m
index 8ad75ba..eaa555e 100644
--- a/mlapptools.m
+++ b/mlapptools.m
@@ -1,29 +1,27 @@
-classdef mlapptools
- % MLAPPTOOLS is a class definition
+classdef (Abstract) mlapptools
+ % MLAPPTOOLS A collection of static methods for customizing various aspects
+ % MATLAB App Designer UIFigures.
%
% MLAPPTOOLS methods:
+ % textAlign - utility method for modifying text alignment.
+ % fontWeight - utility method for modifying font weight (bold etc.).
+ % fontColor - utility method for modifying font color.
+ % setStyle - utility method for modifying styles that do not (yet) have a
+ % dedicated mutator.
- properties (Constant)
- querytimeout = 5; % Dojo query timeout period, seconds
+ properties (Access = private, Constant = true)
+ QUERY_TIMEOUT = 5; % Dojo query timeout period, seconds
end
-
- methods
- function obj = mlapptools
- % Dummy constructor so we don't return an empty class instance
- clear obj
- end
- end
-
-
- methods (Static)
+
+ methods (Access = public, Static = true)
function textAlign(uielement, alignment)
alignment = lower(alignment);
mlapptools.validatealignmentstr(alignment)
[win, widgetID] = mlapptools.getWebElements(uielement);
- alignsetstr = sprintf('dojo.style(dojo.query("#%s")[0], "textAlign", "%s")', widgetID, alignment);
- win.executeJS(alignsetstr);
+ alignSetStr = sprintf('dojo.style(dojo.query("#%s")[0], "textAlign", "%s")', widgetID, alignment);
+ win.executeJS(alignSetStr);
end
@@ -32,8 +30,8 @@ function fontWeight(uielement, weight)
[win, widgetID] = mlapptools.getWebElements(uielement);
- fontwtsetstr = sprintf('dojo.style(dojo.query("#%s")[0], "font-weight", "%s")', widgetID, weight);
- win.executeJS(fontwtsetstr);
+ fontWeightSetStr = sprintf('dojo.style(dojo.query("#%s")[0], "font-weight", "%s")', widgetID, weight);
+ win.executeJS(fontWeightSetStr);
end
@@ -42,25 +40,54 @@ function fontColor(uielement, newcolor)
[win, widgetID] = mlapptools.getWebElements(uielement);
- fontwtsetstr = sprintf('dojo.style(dojo.query("#%s")[0], "color", "%s")', widgetID, newcolor);
- win.executeJS(fontwtsetstr);
+ fontColorSetStr = sprintf('dojo.style(dojo.query("#%s")[0], "color", "%s")', widgetID, newcolor);
+ win.executeJS(fontColorSetStr);
end
- end
-
-
- methods (Static, Access = private)
+
+
+ function widgetID = setStyle(hControl, styleAttr, styleValue)
+ % This method provides a simple interface for modifying style attributes
+ % of uicontrols.
+ %
+ % WARNING: Due to the large amount of available style attributes and
+ % corresponding settings, input checking is not performed. As this
+ % might lead to unexpected results or errors - USE AT YOUR OWN RISK!
+ [win, widgetID] = mlapptools.getWebElements(hControl);
+
+ styleSetStr = sprintf('dojo.style(dojo.query("#%s")[0], "%s", "%s")', widgetID, styleAttr, styleValue);
+ % ^ this might result in junk if widgetId=='null'.
+ try
+ win.executeJS(styleSetStr);
+ % ^ this might crash in case of invalid styleAttr/styleValue.
+ catch ME
+ % Test for "Invalid or unexpected token":
+ ME = mlapptools.checkJavascriptSyntaxError(ME, styleSetStr);
+ rethrow(ME);
+ end
+ end
+
+ end % Public static methods
+
+ methods (Static = true, Access = private)
function [win] = getWebWindow(uifigurewindow)
- % TODO: Check that we've been passed an app designer figure window
mlapptools.togglewarnings('off')
+ % Test if uifigurewindow is a valid handle
+ if ~isa(uifigurewindow,'matlab.ui.Figure') || ...
+ isempty(struct(uifigurewindow).ControllerInfo)
+ msgID = 'mlapptools:getWebWindow:NotUIFigure';
+ error(msgID, 'The provided window handle is not of a UIFigure.');
+ end
tic
- while true && (toc < mlapptools.querytimeout)
+ while true && (toc < mlapptools.QUERY_TIMEOUT)
try
- % Add check for container change in R2017a (version 9.2)
- if verLessThan('matlab', '9.2')
- win = struct(struct(uifigurewindow).Controller).Container.CEF;
- else
- win = struct(struct(struct(uifigurewindow).Controller).PlatformHost).CEF;
+ hController = struct(struct(uifigurewindow).Controller);
+ % Check for Controller version:
+ switch subsref(ver('matlab'), substruct('.','Version'))
+ case {'9.0','9.1'} % R2016a or R2016b
+ win = hController.Container.CEF;
+ otherwise % R2017a onward
+ win = struct(hController.PlatformHost).CEF;
end
break
catch err
@@ -74,11 +101,11 @@ function fontColor(uielement, newcolor)
end
mlapptools.togglewarnings('on')
- if toc >= mlapptools.querytimeout
+ if toc >= mlapptools.QUERY_TIMEOUT
msgID = 'mlapptools:getWidgetID:QueryTimeout';
error(msgID, ...
'WidgetID query timed out after %u seconds, UI needs more time to load', ...
- mlapptools.querytimeout);
+ mlapptools.QUERY_TIMEOUT);
end
end
@@ -94,7 +121,7 @@ function fontColor(uielement, newcolor)
widgetquerystr = sprintf('dojo.getAttr(dojo.query("[data-tag^=''%s''] > div")[0], "widgetid")', data_tag);
tic
- while true && (toc < mlapptools.querytimeout)
+ while true && (toc < mlapptools.QUERY_TIMEOUT)
try
widgetID = win.executeJS(widgetquerystr);
widgetID = widgetID(2:end-1);
@@ -111,11 +138,11 @@ function fontColor(uielement, newcolor)
end
mlapptools.togglewarnings('on')
- if toc >= mlapptools.querytimeout
+ if toc >= mlapptools.QUERY_TIMEOUT
msgID = 'mlapptools:getWidgetID:QueryTimeout';
error(msgID, ...
'WidgetID query timed out after %u seconds, UI needs more time to load', ...
- mlapptools.querytimeout);
+ mlapptools.QUERY_TIMEOUT);
end
end
@@ -187,6 +214,20 @@ function validatealignmentstr(alignment)
function [newcolor] = validateCSScolor(newcolor)
+ % TODO
+ end
+
+
+ function ME = checkJavascriptSyntaxError(ME,styleSetStr)
+ if (strcmp(ME.identifier,'cefclient:webwindow:jserror'))
+ c = strfind(ME.message,'Uncaught SyntaxError:');
+ if ~isempty(c)
+ v = str2double(regexp(ME.message(c:end),'-?\d+\.?\d*|-?\d*\.?\d+','match'));
+ msg = ['Syntax error: unexpected token in styleValue: ' styleSetStr(v(1),v(2))];
+ causeException = MException('mlapptools:setStyle:invalidInputs',msg);
+ ME = addCause(ME,causeException);
+ end
+ end
end
end
end
\ No newline at end of file