diff --git a/resources/project/FhYM8VeT-dlS07YkW6aAPpMEDOc/6e44kSUWEpBnPnuEC0rb4FlnrlYd.xml b/resources/project/FhYM8VeT-dlS07YkW6aAPpMEDOc/6e44kSUWEpBnPnuEC0rb4FlnrlYd.xml
new file mode 100644
index 0000000..80b5b16
--- /dev/null
+++ b/resources/project/FhYM8VeT-dlS07YkW6aAPpMEDOc/6e44kSUWEpBnPnuEC0rb4FlnrlYd.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/project/FhYM8VeT-dlS07YkW6aAPpMEDOc/6e44kSUWEpBnPnuEC0rb4FlnrlYp.xml b/resources/project/FhYM8VeT-dlS07YkW6aAPpMEDOc/6e44kSUWEpBnPnuEC0rb4FlnrlYp.xml
new file mode 100644
index 0000000..720ce9b
--- /dev/null
+++ b/resources/project/FhYM8VeT-dlS07YkW6aAPpMEDOc/6e44kSUWEpBnPnuEC0rb4FlnrlYp.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/wAwe9VOvfujTcIcVeNy0Q57c44cd.xml b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/wAwe9VOvfujTcIcVeNy0Q57c44cd.xml
new file mode 100644
index 0000000..80b5b16
--- /dev/null
+++ b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/wAwe9VOvfujTcIcVeNy0Q57c44cd.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/wAwe9VOvfujTcIcVeNy0Q57c44cp.xml b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/wAwe9VOvfujTcIcVeNy0Q57c44cp.xml
new file mode 100644
index 0000000..1034750
--- /dev/null
+++ b/resources/project/elO4D6tOV7Lp-Jfo7ptgr2NlB30/wAwe9VOvfujTcIcVeNy0Q57c44cp.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/FYJ4_1h7UhnnazGirpjMb0ul4QYd.xml b/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/FYJ4_1h7UhnnazGirpjMb0ul4QYd.xml
new file mode 100644
index 0000000..80b5b16
--- /dev/null
+++ b/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/FYJ4_1h7UhnnazGirpjMb0ul4QYd.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/FYJ4_1h7UhnnazGirpjMb0ul4QYp.xml b/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/FYJ4_1h7UhnnazGirpjMb0ul4QYp.xml
new file mode 100644
index 0000000..576d57c
--- /dev/null
+++ b/resources/project/f1CasPtPWEKkULO6lQ_WTjau2Nw/FYJ4_1h7UhnnazGirpjMb0ul4QYp.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/widgets/+wt/+model/ThumbnailCache.m b/widgets/+wt/+model/ThumbnailCache.m
new file mode 100644
index 0000000..5630fc6
--- /dev/null
+++ b/widgets/+wt/+model/ThumbnailCache.m
@@ -0,0 +1,518 @@
+classdef ThumbnailCache
+ % Manages a cache of image thumbnails given a folder or file list
+
+ %% Public properties
+ properties (AbortSet)
+
+ % List of files that get converted to thumbnails
+ SourceFiles (:,1) string {mustBeFile}
+
+ % Thumbnail size
+ DefSize (1,1) double {mustBePositive,mustBeFinite} = 200
+ end
+
+ %% Calculated properties
+ properties (Dependent = true)
+ HighlightColor % Color of the highlight around the selected image
+ end % Calculated properties
+
+ %% Private properties
+ properties (SetAccess='private', GetAccess='private')
+
+ % Indicates if each thumbnail is loaded from cache
+ IsLoaded (1,:) logical
+
+ %indicates if each thumbnail is queued as a future
+ IsQueued (1,:) logical
+
+ ThumbCacheFile char = '';
+
+ ThumbCacheMap (1,1) struct = struct();
+
+ % Timer for background scanning of thumbnails
+ ThumbTimer
+
+ % parallel futures for thumbnail creation
+ ThumbFutures
+
+ TimerPeriod (1,1) double {mustBePositive,mustBeFinite} = 0.2; %TimerPeriod
+
+ ImagesPerBatch (1,1) double {mustBePositive,mustBeFinite} = 10; %ImagesPerBatch
+
+ UseParallel(1,1) logical = false; %UseParallel
+
+ end % Private properties
+
+
+ %% Constant properties
+ properties (Constant, GetAccess='private')
+ PngReadPath = fullfile(matlabroot,'toolbox','matlab','imagesci','private');
+ end % Constant properties
+
+
+ %% Constructor / Destructor
+ methods
+
+ function obj = ThumbnailCache(root)
+
+ % Define arguments
+ arguments
+ root (1,1) string = ""
+ end
+
+ % Prep thumbnail caching
+ obj.initiateThumbCache();
+
+ % Start timer to update thumbnails
+ start(obj.ThumbTimer);
+
+ end % constructor
+
+
+ function delete(obj)
+ % Destroy the ThumbTimer
+ if ~isempty(obj.ThumbTimer) && isvalid(obj.ThumbTimer)
+ stop(obj.ThumbTimer);
+ delete(obj.ThumbTimer);
+ end
+
+ % Store the thumbnail map cache file
+ thumbMap = obj.ThumbCacheMap;
+ save( obj.ThumbCacheFile, '-struct', 'thumbMap' );
+ end
+
+ end %constructor/destructor methods
+
+
+ %% Protected methods
+ methods (Access=protected)
+
+ function initiateThumbCache(obj)
+
+ % Define the thumbnail cache
+ filename = sprintf('ImageSelectorThumbnails_%d.mat',obj.DefSize);
+ obj.ThumbCacheFile = fullfile( tempdir(), filename );
+
+ % Grab the thumbnail map cache file, if one exists
+ MakeNewMap = true;
+ if exist( obj.ThumbCacheFile, 'file' ) == 2
+ thumbMap = load( obj.ThumbCacheFile );
+ if isstruct(thumbMap) &&...
+ isfield(thumbMap,'ThumbFile') && isa(thumbMap.ThumbFile,'containers.Map') &&...
+ isfield(thumbMap,'Size') && isa(thumbMap.Size,'containers.Map') &&...
+ isfield(thumbMap,'Date') && isa(thumbMap.Size,'containers.Map')
+ obj.ThumbCacheMap = thumbMap;
+ MakeNewMap = false;
+ end
+ end
+ if MakeNewMap
+ obj.ThumbCacheMap = struct(...
+ 'ThumbFile', containers.Map('KeyType','char','ValueType','char'),...
+ 'Date', containers.Map('KeyType','char','ValueType','double'),...
+ 'Size', containers.Map('KeyType','char','ValueType','double') );
+ end
+
+ % Create the thumbnail timer, which scans for thumbnails as a
+ % periodic background task
+ obj.ThumbTimer = timer(...
+ 'Name', 'ImageSelectorThumbnailUpdateTimer', ...
+ 'ExecutionMode', 'fixedSpacing', ...
+ 'BusyMode', 'Drop', ...
+ 'TimerFcn', @(t,s)getThumbnails(obj,t,s), ...
+ 'ObjectVisibility', 'off', ...
+ 'StartDelay', obj.TimerPeriod, ...
+ 'Period', obj.TimerPeriod);
+ %'ErrorFcn', @(h,e)assignin('base','errInfo',e),...
+
+ end
+
+
+ function getThumbnails( obj, thisTimer, ~ )
+
+ % Check whether construction is complete and there are
+ % remaining thumbnails to load
+ if obj.IsConstructed && all(obj.IsLoaded)
+
+ % We can stop the timer now - everything is loaded
+ stop(thisTimer);
+
+ elseif obj.IsConstructed
+
+ % First, check for any PCT futures that completed
+ if ~isempty(obj.ThumbFutures)
+
+ IsComplete = strcmp({obj.ThumbFutures.State}, 'finished');
+ idxToFetch = find(IsComplete);
+
+ for idx = 1:numel(idxToFetch)
+
+ % Get the result
+ [thumbFileName, cdata, srcFileName] = obj.ThumbFutures(idxToFetch(idx)).fetchOutputs();
+
+ % Match up the index of this image
+ idxThisImage = strcmp( obj.SourceFiles, srcFileName );
+
+ % Update the thumbnail map
+ if ~isempty(thumbFileName)
+ obj.ThumbCacheMap.ThumbFile(srcFileName) = thumbFileName;
+ obj.IsLoaded(idxThisImage) = true;
+ obj.IsQueued(idxThisImage) = false;
+ end
+
+ % Store original CData in appdata (for enable/disable)
+ setappdata( obj.h.Images(idxThisImage), 'CData', cdata );
+
+ % If widget disabled, move color towards background
+ if strcmpi( obj.Enable, 'off' )
+ bgcol = obj.BackgroundColor;
+ cdata(:,:,1) = 0.5*bgcol(1) + 0.5*cdata(:,:,1);
+ cdata(:,:,2) = 0.5*bgcol(2) + 0.5*cdata(:,:,2);
+ cdata(:,:,3) = 0.5*bgcol(3) + 0.5*cdata(:,:,3);
+ end
+
+ % Update the image cdata to display it
+ set( obj.h.Images(idxThisImage), 'CData', cdata );
+
+ end %for idx = 1:numel(idxToFetch)
+
+ % Remove these futures
+ delete( obj.ThumbFutures(IsComplete) );
+ obj.ThumbFutures(IsComplete) = [];
+
+ end %if ~isempty(obj.ThumbFutures)
+
+ % Which next N number of thumbnails should be loaded?
+ NumThisBatch = obj.ImagesPerBatch - sum(obj.IsQueued);
+ if NumThisBatch <= 0
+ return
+ end
+ CheckToLoad = ~obj.IsLoaded & ~obj.IsQueued;
+ idxToLoad = find(CheckToLoad, NumThisBatch);
+
+ % Quickest way to load existing PNG thumbnails is to call the
+ % mex file pngreadc directly. But we need to cd to the private
+ % folder to be able to call it.
+ currentDir = pwd;
+ cd(obj.PngReadPath);
+
+ % Are any of these thumbnails cached already?
+ IsCached = false(size(idxToLoad));
+ for idx = 1:numel(idxToLoad)
+
+ ii = idxToLoad(idx);
+ srcFileName = obj.SourceFiles{ii};
+
+ % Confirm date and size
+ fInfo = dir(srcFileName);
+ if isscalar(fInfo)
+ srcFileSize = fInfo.bytes;
+ srcFileDate = fInfo.datenum;
+ else
+ warning('Unable to scan thumbnail image: %s',srcFileName);
+ srcFileSize = 0;
+ srcFileDate = 0;
+ end
+
+ % Is it cached?
+ IsCached(idx) = ( ...
+ obj.ThumbCacheMap.ThumbFile.isKey(srcFileName) &&...
+ exist(obj.ThumbCacheMap.ThumbFile(srcFileName),'file')==2 &&...
+ obj.ThumbCacheMap.Size(srcFileName) == srcFileSize &&...
+ obj.ThumbCacheMap.Date(srcFileName) == srcFileDate );
+
+ % Depending on cache, we load or create it
+ if IsCached(idx)
+
+ % Load an existing thumbnail
+ thumbname = obj.ThumbCacheMap.ThumbFile(obj.SourceFiles{ii});
+
+ % Load the thumbnail cache. Use internal mex file pngreadc
+ % for speed, since we know the format.
+ cdata = pngreadc(thumbname, [], false);
+ cdata = permute(cdata, ndims(cdata):-1:1);
+ obj.IsLoaded(ii) = true;
+
+ % Store original CData in appdata (for enable/disable)
+ setappdata( obj.h.Images(ii), 'CData', cdata );
+
+ % If widget disabled, move color towards background
+ if strcmpi( obj.Enable, 'off' )
+ bgcol = obj.BackgroundColor;
+ cdata(:,:,1) = 0.5*bgcol(1) + 0.5*cdata(:,:,1);
+ cdata(:,:,2) = 0.5*bgcol(2) + 0.5*cdata(:,:,2);
+ cdata(:,:,3) = 0.5*bgcol(3) + 0.5*cdata(:,:,3);
+ end
+
+ % Update the image cdata to display it
+ set( obj.h.Images(ii), 'CData', cdata );
+
+ else
+ % If not cached yet, we will cache it but we also
+ % need to store the source file's size and date to
+ % check if it changes later
+ obj.ThumbCacheMap.Size(srcFileName) = srcFileSize;
+ obj.ThumbCacheMap.Date(srcFileName) = srcFileDate;
+
+ end %if IsCached(idx)
+
+ end %for ii = idxToLoad
+
+ % Navigate back to the user's current directory
+ cd(currentDir);
+
+ % Do we need to create thumbnails from this set?
+ if any(~IsCached)
+
+ % Which ones should be created?
+ idxToCreate = idxToLoad(~IsCached);
+
+ % Can we use PCT?
+ if obj.UseParallel
+
+ % Use parfeval to create thumbnails as background tasks
+ for idx = 1:numel(idxToCreate)
+ srcFileName = obj.SourceFiles{idxToCreate(idx)};
+ if isempty(obj.ThumbFutures)
+ obj.ThumbFutures = parfeval(@uiw.utility.createThumbnail, 3, srcFileName, obj.DefSize);
+ else
+ obj.ThumbFutures(end+1) = parfeval(@uiw.utility.createThumbnail, 3, srcFileName, obj.DefSize);
+ end
+ end
+
+ % Mark them as queued in a future
+ obj.IsQueued(idxToCreate) = true;
+
+ else
+
+ % NO - create just one thumbnail now in this timer loop
+ idx = 1;
+ ii = idxToCreate(idx);
+ srcFileName = obj.SourceFiles{idxToCreate(idx)};
+
+ % Create the thumbnail
+ try
+ [thumbFileName, cdata] = uiw.utility.createThumbnail( srcFileName, obj.DefSize );
+ catch err
+ obj.IsLoaded(ii) = true;
+ warning('ImageSelector:createThumbnailError',...
+ 'Unable to create thumbnail for ''%s''. Error: %s',...
+ srcFileName, err.message);
+ return
+ end
+
+ % Update the thumbnail map
+ if ~isempty(thumbFileName) && isscalar(fInfo)
+ obj.ThumbCacheMap.ThumbFile(srcFileName) = thumbFileName;
+ obj.IsLoaded(ii) = true;
+ end
+
+ % Store original CData in appdata (for enable/disable)
+ setappdata( obj.h.Images(ii), 'CData', cdata );
+
+ % If widget disabled, move color towards background
+ if strcmpi( obj.Enable, 'off' )
+ bgcol = obj.BackgroundColor;
+ cdata(:,:,1) = 0.5*bgcol(1) + 0.5*cdata(:,:,1);
+ cdata(:,:,2) = 0.5*bgcol(2) + 0.5*cdata(:,:,2);
+ cdata(:,:,3) = 0.5*bgcol(3) + 0.5*cdata(:,:,3);
+ end
+
+ % Update the image cdata to display it
+ set( obj.h.Images(ii), 'CData', cdata );
+
+ end %if obj.UseParallel
+
+ end %if any(~IsCached)
+
+ end %if obj.IsConstructed && ~all(obj.IsLoaded)
+
+ end % getThumbnails
+
+ end % Protected methods
+
+
+
+ %% Private methods
+ methods (Access='private')
+
+
+
+ function addImage( obj, filename, caption )
+ %addImage: add a new image to the list
+ %
+ % obj.addImage(FILENAME,CAPTION)
+ if nargin<3
+ caption = repmat("",size(filename));
+ end
+ numAdds = numel(filename);
+
+ % For blank thumbnails
+ cdata(obj.DefSize, obj.DefSize, 3) = uint8(0);
+
+ % Note the new indices that will need thumbnails
+ idxThumbnails = numel(obj.h.Images) + (1:numAdds);
+
+ % Get the state of files and captions
+ imageFiles = obj.SourceFiles;
+ captions = obj.Captions;
+
+ % Append items to lists, and create the UI components
+ for ii=1:numAdds
+
+ % Get the index of the next image
+ idx = idxThumbnails(ii);
+
+ % Append the image and caption to the list, if not already
+ % done
+ if numel(imageFiles)
+ obj.IsLoaded(toremove) = []; %#ok
+ obj.IsQueued(toremove) = []; %#ok
+
+ % Now add the new ones
+ toadd = ~iStrIsMember( names, obj.SourceFiles );
+ obj.SourceFiles = horzcat(obj.SourceFiles, names(toadd));
+ obj.addImage( names(toadd) );
+
+ end % set.SourceFiles
+
+
+ end % Data access methods
+
+
+end % classdef
+
+
+
+%% Now some helper functions
+
+%-------------------------------------------------------------------------%
+function tf = iStrIsMember( strsToLookFor, strSet )
+% This is faster than ismember
+n = numel(strsToLookFor);
+tf = false(size(strsToLookFor));
+for idx=1:n
+ tf(idx) = any(strcmp(strsToLookFor{idx},strSet));
+end
+end %iStrIsMember
+
+%-------------------------------------------------------------------------%
+function tf = iIsEqualMember( itemsToLookFor, fullSet )
+% This is faster than ismember
+n = numel(itemsToLookFor);
+tf = false(size(itemsToLookFor));
+for idx=1:n
+ tf(idx) = any(itemsToLookFor(idx) == fullSet);
+end
+end %iIsEqualMember
\ No newline at end of file
diff --git a/widgets/+wt/ImageGallery.m b/widgets/+wt/ImageGallery.m
new file mode 100644
index 0000000..2e4d417
--- /dev/null
+++ b/widgets/+wt/ImageGallery.m
@@ -0,0 +1,193 @@
+classdef ImageGallery < wt.abstract.BaseWidget
+ % A gallery of images
+
+ % Copyright 2020-2021 The MathWorks Inc.
+
+ %RAJ - to do:
+ % verify performance with bigger files
+ % Do we need thumbnail generation??
+ % Enable setting a folder instead of a file list
+ % Enable a file type filter in this case
+
+ %% Public properties
+ properties (AbortSet)
+
+ % Size of the image space in pixels
+ ImageSize (1,1) double = 200
+
+ % Image file sources
+ ImageSource (:,1) string = [""; ""; ""]
+
+ end %properties
+
+
+ %% Internal Properties
+ properties ( Transient, NonCopyable, ...
+ Access = {?wt.abstract.BaseWidget, ?wt.test.BaseWidgetTest} )
+
+ % Image controls
+ Image (1,:) matlab.ui.control.Image
+
+ % Size changed listener
+ SizeChangedListener event.listener
+
+ end %properties
+
+
+ properties (AbortSet, Transient, NonCopyable, ...
+ Access = {?wt.abstract.BaseWidget, ?wt.test.BaseWidgetTest} )
+
+ % Number of visible [rows columns]
+ GridSize (1,2) double = [1 3]
+
+ end %properties
+
+
+
+ %% Protected methods
+ methods (Access = protected)
+
+ function setup(obj)
+
+ % Call superclass setup first to establish the grid
+ obj.setup@wt.abstract.BaseWidget();
+
+ % Set default size
+ obj.Position(3:4) = [400 400];
+ obj.Grid.Padding = [0 0 0 0];
+
+ % Turn on scrollability
+ obj.Grid.Scrollable = true;
+
+ % Listen to resize events
+ obj.SizeChangedListener = event.listener(obj,"SizeChanged",...
+ @(src,evt)obj.onSizeChanged(evt) );
+
+ end %function
+
+
+ function update(obj)
+
+ % How many images are needed?
+ numImg = numel(obj.ImageSource);
+ oldNum = numel(obj.Image);
+
+ % Check and update grid size as needed
+ obj.updateGridSize();
+
+ % Calculate layout position of each image
+ cIdx = repmat(1:obj.GridSize(2), obj.GridSize(1), 1)';
+ rIdx = repmat(1:obj.GridSize(1), obj.GridSize(2), 1);
+
+ % Add new images if needed
+ if numImg > oldNum
+ for idx = oldNum+1:numImg
+ obj.Image(idx) = uiimage(obj.Grid, "ScaleMethod", "fill");
+ obj.Image(idx).Layout.Row = rIdx(idx);
+ obj.Image(idx).Layout.Column = cIdx(idx);
+ end
+ end %if
+
+ % Update each image source
+ for idx = 1:numImg
+ wt.utility.fastSet(obj.Image(idx),...
+ "ImageSource", obj.ImageSource(idx));
+ end %for
+
+ % Delete any extra images
+ delete( obj.Image(numImg+1:end) )
+ obj.Image(numImg+1:end) = [];
+
+ end %function
+
+ end %methods
+
+
+
+ %% Private methods
+ methods %(Access = private)
+
+ function onSizeChanged(obj,~)
+ % Triggered on size changed
+
+ % Check and update grid size as needed
+ %obj.updateGridSize();
+ obj.requestUpdate();
+
+ end %function
+
+
+ function updateGridSize(obj)
+ % Calculate and update the grid size
+
+ % How many images?
+ numImg = numel(obj.ImageSource);
+
+ % How much space do we have?
+ if obj.Units == "pixels"
+ wAvail = obj.Position(3) + obj.Grid.ColumnSpacing;
+ else
+ pos = getpixelposition(obj.Grid);
+ wAvail = (pos(3) + obj.Grid.ColumnSpacing);
+ end
+
+ % How many images do we need to fit?
+ wPerImg = obj.ImageSize + obj.Grid.ColumnSpacing;
+
+ % How many full columns fit across?
+ numCol = max(1, floor(wAvail/wPerImg));
+
+ % How many rows do we need? (Rows can be scrolled down)
+ numRow = max(1, ceil(numImg/numCol));
+
+ % Update the layout size
+ obj.GridSize = [numRow numCol];
+
+ end %function
+
+
+ function updateLayout(obj)
+ % Update the layout based on the current GridSize
+ % This should only be called by set.GridSize
+
+ % How many images?
+ numImg = min( prod(obj.GridSize), numel(obj.Image) );
+
+ % Make the layout updates
+ colWidth = repmat({obj.ImageSize}, 1, obj.GridSize(2));
+ rowHeight = repmat({obj.ImageSize}, 1, obj.GridSize(1));
+
+ % Calculate layout position of each image
+ rIdx = repmat(1:obj.GridSize(1), obj.GridSize(2), 1);
+ cIdx = repmat(1:obj.GridSize(2), obj.GridSize(1), 1)';
+
+ % Update layout position of each image
+ for idx = 1:numImg
+ obj.Image(idx).Layout.Row = rIdx(idx);
+ if obj.Image(idx).Layout.Column ~= cIdx(idx)
+ obj.Image(idx).Layout.Column = cIdx(idx);
+ end
+ end %for
+
+ % Update the grid layout sizes
+ obj.Grid.RowHeight = rowHeight;
+ obj.Grid.ColumnWidth = colWidth;
+
+ end %function
+
+
+ end %methods
+
+
+ %% Accessors
+ methods
+
+ function set.GridSize(obj,value)
+ obj.GridSize = value;
+ obj.updateLayout();
+ end
+
+ end % methods
+
+end % classdef
+
diff --git a/widgets/examples/rjImageGallery.m b/widgets/examples/rjImageGallery.m
new file mode 100644
index 0000000..d58f5bf
--- /dev/null
+++ b/widgets/examples/rjImageGallery.m
@@ -0,0 +1,20 @@
+%% Create the image gallery
+f = uifigure;
+g = uigridlayout(f,[1,1]);
+w = ImageGallery(g,'BackgroundColor','green')
+
+
+%% Show some images from MATLAB
+searchRoot = fullfile(matlabroot,'toolbox','images','imdata');
+fileInfo = dir( fullfile(searchRoot,"*.png") );
+fileNames = sortrows( string({fileInfo.name}') );
+filePaths = fullfile(searchRoot, fileNames);
+w.ImageSource = filePaths;
+
+
+%% Big images
+searchRoot = "C:\Users\rjackey\OneDrive - MathWorks\Pictures\2011-10-31 Argentina\";
+fileInfo = dir( fullfile(searchRoot,"*.jpg") );
+fileNames = sortrows( string({fileInfo.name}') );
+filePaths = fullfile(searchRoot, fileNames);
+w.ImageSource = filePaths;