From 8a0a7230af7b3ac138503d90691fa2ca8dc067dc Mon Sep 17 00:00:00 2001 From: Dev-iL Date: Tue, 15 Aug 2017 14:25:59 +0300 Subject: [PATCH 1/7] Refactored variables to better reflect function and improve readability --- mlapptools.m | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/mlapptools.m b/mlapptools.m index 8ad75ba..5563a42 100644 --- a/mlapptools.m +++ b/mlapptools.m @@ -3,8 +3,8 @@ % % MLAPPTOOLS methods: - properties (Constant) - querytimeout = 5; % Dojo query timeout period, seconds + properties (Access = private, Constant = true) + QUERY_TIMEOUT = 5; % Dojo query timeout period, seconds end methods @@ -22,8 +22,8 @@ function textAlign(uielement, 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 +32,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,8 +42,8 @@ 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 @@ -54,7 +54,7 @@ function fontColor(uielement, newcolor) mlapptools.togglewarnings('off') tic - while true && (toc < mlapptools.querytimeout) + while true && (toc < mlapptools.TIMEOUT) try % Add check for container change in R2017a (version 9.2) if verLessThan('matlab', '9.2') @@ -74,11 +74,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 +94,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 +111,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 From 54a1d0bbed6c6dac3a94c217f90bfcf327672508 Mon Sep 17 00:00:00 2001 From: Dev-iL Date: Tue, 15 Aug 2017 14:27:30 +0300 Subject: [PATCH 2/7] Added check for UIFigure handle validity --- mlapptools.m | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mlapptools.m b/mlapptools.m index 5563a42..7bf3682 100644 --- a/mlapptools.m +++ b/mlapptools.m @@ -50,8 +50,13 @@ function fontColor(uielement, newcolor) methods (Static, 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.TIMEOUT) From 1fc23c0a1b05a29aeb2ec8905ae247ba10a24133 Mon Sep 17 00:00:00 2001 From: Dev-iL Date: Tue, 15 Aug 2017 14:31:59 +0300 Subject: [PATCH 3/7] Modified the CEF uncovering logic to test for R2016b (instead of R2017a) Also, made more future-proof by transitioning to a switch-statement structure. --- mlapptools.m | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/mlapptools.m b/mlapptools.m index 7bf3682..26f9410 100644 --- a/mlapptools.m +++ b/mlapptools.m @@ -61,11 +61,13 @@ function fontColor(uielement, newcolor) tic while true && (toc < mlapptools.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' % R2016a + win = hController.Container.CEF; + otherwise % R2016b onward + win = struct(hController.PlatformHost).CEF; end break catch err From ce8bb34eaf2e30cf1dc1fc51abdd2a33171fb6c5 Mon Sep 17 00:00:00 2001 From: Dev-iL Date: Tue, 15 Aug 2017 15:52:40 +0300 Subject: [PATCH 4/7] Added the "setStyle" method for setting generic styles - Improved internal documentation of the class. - Added check for JS SyntaxError to use in setStyle. - Readme updated accordingly. --- README.md | 18 +++++++++++++++++ mlapptools.m | 57 +++++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 68 insertions(+), 7 deletions(-) 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 26f9410..33d2215 100644 --- a/mlapptools.m +++ b/mlapptools.m @@ -1,7 +1,13 @@ classdef mlapptools - % MLAPPTOOLS is a class definition + % 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 (Access = private, Constant = true) QUERY_TIMEOUT = 5; % Dojo query timeout period, seconds @@ -13,9 +19,10 @@ clear obj end end - - + methods (Static) + + methods (Access = public, Static = true) function textAlign(uielement, alignment) alignment = lower(alignment); mlapptools.validatealignmentstr(alignment) @@ -45,10 +52,32 @@ function fontColor(uielement, newcolor) 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) mlapptools.togglewarnings('off') % Test if uifigurewindow is a valid handle @@ -194,6 +223,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 From 103b1b2e2a2cdec24ba1ba1dec3c99dec43696e0 Mon Sep 17 00:00:00 2001 From: Dev-iL Date: Tue, 15 Aug 2017 15:53:44 +0300 Subject: [PATCH 5/7] Fixed refactoring error from previous commit. Error was introduced in 8a0a7230af7b3ac138503d90691fa2ca8dc067dc --- mlapptools.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mlapptools.m b/mlapptools.m index 33d2215..ebf6e3b 100644 --- a/mlapptools.m +++ b/mlapptools.m @@ -88,7 +88,7 @@ function fontColor(uielement, newcolor) end tic - while true && (toc < mlapptools.TIMEOUT) + while true && (toc < mlapptools.QUERY_TIMEOUT) try hController = struct(struct(uifigurewindow).Controller); % Check for Controller version: From 4ae3a3b7abd1099e2e39c7290fe4dd72aea431cd Mon Sep 17 00:00:00 2001 From: Dev-iL Date: Tue, 15 Aug 2017 15:54:36 +0300 Subject: [PATCH 6/7] Removed dummy constructor and instead made the class Abstract --- mlapptools.m | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/mlapptools.m b/mlapptools.m index ebf6e3b..ef0e6bc 100644 --- a/mlapptools.m +++ b/mlapptools.m @@ -1,4 +1,4 @@ -classdef mlapptools +classdef (Abstract) mlapptools % MLAPPTOOLS A collection of static methods for customizing various aspects % MATLAB App Designer UIFigures. % @@ -12,15 +12,6 @@ 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) From 92f4f2d119d8d4e5e63e430795bdf8e23606b8be Mon Sep 17 00:00:00 2001 From: Dev-iL Date: Tue, 15 Aug 2017 17:59:15 +0300 Subject: [PATCH 7/7] Corrected the version of the hController logic (thanks @gnovice) See testing at: https://chat.stackoverflow.com/transcript/message/38672352#38672352 --- mlapptools.m | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mlapptools.m b/mlapptools.m index ef0e6bc..eaa555e 100644 --- a/mlapptools.m +++ b/mlapptools.m @@ -84,9 +84,9 @@ function fontColor(uielement, newcolor) hController = struct(struct(uifigurewindow).Controller); % Check for Controller version: switch subsref(ver('matlab'), substruct('.','Version')) - case '9.0' % R2016a + case {'9.0','9.1'} % R2016a or R2016b win = hController.Container.CEF; - otherwise % R2016b onward + otherwise % R2017a onward win = struct(hController.PlatformHost).CEF; end break