Code covered by the BSD License  

Highlights from
Fireworks GUI

image thumbnail

Fireworks GUI

by

 

30 Dec 2010 (Updated )

Enjoy some fireworks (with sound) with this interactive GUI

Editor's Notes:

This file was selected as MATLAB Central Pick of the Week

FireworksGUI
classdef FireworksGUI < handle
    % FireworksGUI    Fireworks GUI
    %
    % This creates a GUI for displaying fireworks (using Fireworks class). The
    % class contains a command line interface, but almost all the features are
    % available via the GUI.
    %
    % FireworksGUI Properties:
    %   DemoMode     - Toggle option for demo mode.   true/[false]
    %   RecordMode   - Toggle option for recording.   true/[false]
    %   MovieType    - The format of the saved movie. ['gif']/'avi'
    %   SoundMode    - Toggle option for sounds.      [true]/false
    %
    % FireworksGUI Methods:
    %   FireworksGUI        - Constructor
    %   newFireworks        - Launch new fireworks
    %   newPresetFireworks  - Launch a preset fireworks combination
    %
    %   run (Static)        - Statically run the GUI.
    %
    % Examples:
    %   s = FireworksGUI;        % starts the GUI
    %   newFireworks(s, 10);     % launches 10 fireworks
    %   newPresetFireworks(s);   % launches a random fireworks combination
    %
    %   * In the GUI, click on the black region to launch new fireworks.
    %   * The top left button toggles demo mode.
    %   * The red button toggles recording mode.
    %   * The numbered buttons are different fireworks presets.
    %   * Click on the question mark for more information regarding interactive
    %     use. There are a number of operations associated with key presses and
    %     mouse clicks.
    %
    % See also FireworksGUI, FireworksGUI.newFireworks,
    % FireworksGUI.newPresetFireworks, FireworksAxes.
    %
    % For more info, <a href="matlab:doc('FireworksGUI')">doc FireworksGUI</a>
    
    % Author: Jiro Doke
    % Date: August 01, 2012
    % Copyright 2010-2012 The MathWorks, Inc.
    
    %% Properties
    properties
        % DemoMode  Toggle demo mode
        %   true/false. Default is false. During Demo Mode, it cycles through
        %   randomly selected Presets one after the other. It continues until the
        %   Demo toggle button is clicked of DemoMode is set to false. Default is
        %   false.
        DemoMode = false
        
        % RecordMode   Start and stop recording (to Animated GIF or AVI)
        %   true/false. Default is false. The recording will be in either Animated
        %   GIF or AVI, whichever one is set in the property MovieType. The movie
        %   will NOT include audio. The GUI title bar indicates the time elapsed of
        %   the recording. The recording will continue until the Record toggle
        %   button on the GUI is clicked or RecordMode is set to false. The movie
        %   will be saved in the current folder with the naming convention of
        %   "movie_<CurrentTime>.gif" (or .avi), where CurrentTime is in the form
        %   of yyyymmddTHHMMSS. The maximum length of the movie is specified by the
        %   hidden (and protected) property MaxRecordTime. Change the property
        %   value in the CLASSDEF file.
        RecordMode = false
        
        % MovieType   Format of the movie when recording
        %   'gif'/'avi'. Default is 'gif'. This is the format of the movie file.
        %   The movie will be saved in the current folder with the naming
        %   convention of "movie_<CurrentTime>.gif" (or .avi), where CurrentTime is
        %   in the form of yyyymmddTHHMMSS.
        MovieType = 'gif'
    end
    
    properties (Dependent)
        % SoundMode   Turn on and off sounds
        %   true/false. Default is true. This toggles the fireworks sounds in the
        %   GUI.
        SoundMode
    end
    
    properties (Hidden, Access = protected)
        GuiHandles
        MaxRecordTime = 600  % seconds
        MaxSimultaneousFireworks = 20

        FWAxes            % FireworksAxes object

        DemoTimer         % Timer for running in demo mode
        RecordTimer       % Timer for recording
        
        Tic               % Stores start time for recording
        AVI               % AVI object
        GIFFileName       % Animated GIF file name
        
        DemoRepeaterListener % Listener for Fireworks objects
        
        PresetFireworks   % Array to store selected Presets
        
        TracePoints       % Array to store mouse trace points
    end
        
    %% Public Methods
    methods
        %% Main Methods
        function obj = FireworksGUI()
            % FireworksGUI   Starts the Fireworks GUI.
            %   FWGUI = FireworksGUI()
            %
            %   It is meant to be run interactively through the GUI, but you can also
            %   control via command line. The properties "DemoMode", "RecordMode",
            %   "MovieType", and "SoundMode" changes the various modes. The methods
            %   "newFireworks" and "newPresetFireworks" adds fireworks to the scene.
            %
            %   See also FireworksGUI.newFireworks, FireworksGUI.newPresetFireworks
            
            % Set up GUI (Can only have one Fireworks GUI
            fh = findall(0, 'Type', 'Figure', 'Tag', 'FireworksFig');
            if ~isempty(fh)
                delete(fh);
            end
            
            fh = figure(...
                'Color', 'black', ...
                'Tag', 'FireworksFig', ...
                'NumberTitle', 'off', ...
                'Name', 'Fireworks GUI', ...
                'Menu', 'none', ...
                'DockControl', 'off', ...
                'Units', 'pixels', ...
                'HandleVisibility', 'on', ...
                'CloseRequestFcn', @(o,e) obj.figureCloseFcn, ...
                'WindowButtonDownFcn', @obj.windowButtonDownFcn, ...
                'WindowButtonUpFcn', @obj.windowButtonUpFcn, ...
                'WindowKeyPressFcn', @obj.windowKeyPressFcn, ...
                'WindowScrollWheelFcn', @obj.windowScrollWheelFcn);
            
            hToolbar = uitoolbar('Parent', fh);
            
            % Demo toggle button
            uitoggletool(...
                'Parent', hToolbar, ...
                'CData', createCData('demo'), ...
                'Tag', 'DemoToggleButton', ...
                'TooltipString', 'Demo Mode: OFF', ...
                'ClickedCallback', @(o, e) obj.demoToggleFcn);
            
            % Movie type toggle button
            uipushtool(...
                'Parent', hToolbar, ...
                'CData', createCData('gif'), ...
                'Separator', 'on', ...
                'Tag', 'MovieTypeButton', ...
                'ClickedCallback', @(o, e) obj.movieTypeToggleFcn, ...
                'TooltipString', 'Movie type: GIF (click to change)');
            
            % Record button
            uitoggletool(...
                'Parent', hToolbar, ...
                'CData', createCData('record'), ...
                'Tag', 'RecordToggleButton', ...
                'TooltipString', 'Record Mode: OFF', ...
                'ClickedCallback', @(o, e) obj.recordToggleFcn);
            
            % Sound button
            uipushtool(...
                'Parent', hToolbar, ...
                'CData', createCData('sound'), ...
                'Separator', 'on', ...
                'Tag', 'SoundButton', ...
                'ClickedCallback', @(o, e) obj.soundToggleFcn, ...
                'TooltipString', 'Sound: ON');
            
            % Preset Fireworks combination buttons
            strs = {'Random Timing', 'Left to Right', 'Right to Left', ...
                'Flares', 'Geyser', 'Steady Stream', 'Random Location', ...
                'Rapid Fire', '"Happy New Year!"', 'MATLAB'};
            ComboFireworksButton = nan(1, 10);
            for id = 1:10
                ComboFireworksButton(id) = uipushtool(...
                    'Parent', hToolbar, ...
                    'CData', createNumberCData(id), ...
                    'TooltipString', strs{id}, ...
                    'ClickedCallback', @(o, e) obj.presetButtonFcn(id));
            end
            set(ComboFireworksButton(1), 'Separator', 'on');
            
            % Help button
            uipushtool(...
                'Parent', hToolbar, ...
                'CData', createCData('help'), ...
                'Separator', 'on', ...
                'Tag', 'HelpButton', ...
                'TooltipString', 'Help', ...
                'ClickedCallback', @(o, e) fireworksHelp);
            
            % Axes for fireworks
            ah = axes('Parent', fh, 'Units', 'pixels');
            obj.FWAxes = FireworksAxes(ah);
                        
            obj.DemoTimer = timer(...
                'Name', 'DemoTimer', ...
                'ExecutionMode', 'fixedSpacing', ...
                'Period', 0.1, ...
                'TimerFcn', @obj.delayedFireworksTimerFcn, ...
                'ObjectVisibility', 'off', ...
                'Tag', 'fireworks_timers');
            
            obj.RecordTimer = timer(...
                'Name', 'RecordTimer', ...
                'ExecutionMode', 'fixedRate', ...
                'Period', 0.1, ...
                'TimerFcn', @obj.recordTimerFcn, ...
                'StartFcn', @obj.recordStartFcn, ...
                'StopFcn', @obj.recordStopFcn, ...
                'ObjectVisibility', 'off', ...
                'Tag', 'fireworks_timers');
            
            % This listener is used only in Demo Mode. It listens to the change in the
            % array of fireworks. Once the array is empty, it runs another Preset
            % fireworks combination.
            obj.DemoRepeaterListener = addlistener(obj.FWAxes, ...
                'FireworksEmpty', @(s, e) obj.fireworksRepeater);
            
            % Store handles to GUI components
            obj.GuiHandles = guihandles(fh);
            obj.GuiHandles.ComboFireworksButton = ComboFireworksButton;
            
            % Set up resize function to adjust x limits
            set(fh, 'ResizeFcn', @obj.figureResizeFcn);
            figureResizeFcn(obj, fh);
            
            obj.SoundMode = obj.FWAxes.SoundMode;

        end
        
        function newFireworks(obj, varargin)
            % newFireworks   Launch new fireworks
            %
            %   obj.newFireworks() launches a single fireworks. The location, type,
            %       speed are randomly set.
            %   obj.newFireworks(NUM) launches NUM fireworks at the same time. The
            %       location, type, speed are randomly set.
            %
            %   obj.newFireworks(PROP1, VAL1, PROP2, VAL2, ...)
            %   obj.newFireworks(NUM, PROP1, VAL1, PROP2, VAL2, ...)
            %       You can pass in additional Property-Value pairs as input arguments,
            %       and they allow you to set the location, type, and speed of the
            %       fireworks. See the help for FireworksAxes class to learn about
            %       valid properties.
            %
            %   This is disabled during Demo Mode.
            %
            % Examples:
            %   fw = FireworksGUI;
            %   fw.newFireworks();
            %   fw.newFireworks(10);
            %   fw.newFireworks(10, 'LaunchPos', 0);
            %
            % See also FireworksGUI.newPresetFireworks, FireworksAxes.
            
            if ~obj.DemoMode
                obj.FWAxes.newFireworks(varargin{:});
            end
        end
        
        function newPresetFireworks(obj, num)
            % newPresetFireworks  Launch a preset fireworks combination
            %
            %   obj.newPresetFireworks(NUM) launches a preset defined by NUM. NUM
            %       has to be an integer between (and including) 1 and 10.
            %
            %   obj.newPresetFireworks() launches a randomly chosen preset.
            %
            %   This is disabled during Demo Mode. Also, you cannot launch a new preset
            %   until all previously launched fireworks have finished. This is to
            %   prevent too many fireworks objects to be on the screen at one time.
            %
            % Examples:
            %   fw = FireworksGUI;
            %   fw.newPresetFireworks(5);       % launch Preset 5
            %
            %   % wait until all the fireworks are gone
            %   fw.newPresetFireworks();        % launch random preset
            %
            % See also FireworksGUI.newFireworks.
            
            % Don't random fireworks when there are already fireworks flying. This is
            % to prevent over crowding the sky with fireworks.
            if ~obj.DemoMode && obj.FWAxes.isFireworksEmpty
                if nargin == 1
                    obj.selectPresetFireworks();
                else
                    obj.selectPresetFireworks(num);
                end
            end
        end
        
        %% Setter Functions
        function set.RecordMode(obj, val)
            validateattributes(val, {'logical'}, {'scalar'}, mfilename, 'RecordMode')
            
            switch val
                case true
                    startrecording(obj)
                    obj.RecordMode = true;
                case false
                    stoprecording(obj)
                    obj.RecordMode = false;
            end
        end
        
        function set.MovieType(obj, val)
            val = validatestring(val, {'avi', 'gif'}, mfilename, 'MovieType');
            
            if obj.RecordMode == false %#ok<MCSUP>
                obj.MovieType = val;
                changeMovieType(obj);
            end
        end
        
        function set.DemoMode(obj, val)
            validateattributes(val, {'logical'}, {'scalar'}, mfilename, 'DemoMode')
            
            switch val
                case true
                    startdemo(obj);
                    obj.DemoMode = true;
                case false
                    stopdemo(obj);
                    obj.DemoMode = false;
            end
        end
        
        function set.SoundMode(obj, val)
            validateattributes(val, {'logical'}, {'scalar'}, mfilename, ...
                'SoundMode');
                        
            obj.FWAxes.SoundMode = val;
            
            if obj.SoundMode
                set(obj.GuiHandles.SoundButton, ...
                    'CData', createCData('sound'), ...
                    'TooltipString', 'Sound: ON');
            else
                set(obj.GuiHandles.SoundButton, ...
                    'CData', createCData('sound_mute'), ...
                    'TooltipString', 'Sound: OFF');
            end
            
            if ~verLessThan('matlab', '7.12') && verLessThan('matlab', '7.13')
                set(obj.GuiHandles.SoundButton, ...
                    'Enable', 'off', ...
                    'TooltipString', 'Sound Disabled in R2011a');
            end

        end
        
        function val = get.SoundMode(obj)
            val = obj.FWAxes.SoundMode;
        end
                
    end
    
    methods (Hidden)
        function delete(obj)
            warning('off', 'MATLAB:class:DestructorError');
            
            if isvalid(obj.DemoTimer)
                set(obj.DemoTimer, 'StopFcn', '');
                stop(obj.DemoTimer);
                while strcmpi(obj.DemoTimer.Running, 'on');end
                delete(obj.DemoTimer);
            end
            
            if isvalid(obj.RecordTimer)
                set(obj.RecordTimer, 'StopFcn', '');
                stop(obj.RecordTimer);
                while strcmpi(obj.RecordTimer.Running, 'on');end
                delete(obj.RecordTimer);
            end

            if ishandle(obj.GuiHandles.FireworksFig)
                delete(obj.GuiHandles.FireworksFig);
            end
            
            delete@handle(obj);
            
            warning('on', 'MATLAB:class:DestructorError');
        end
    end
    
    %% Static Methods
    methods (Static)
        function run()
            % run   Statically run the GUI (without creating a visible object)
            %
            % See also FireworksGUI.
            
            FireworksGUI();
        end
    end
    
    %% Protected Methods
    methods (Access = protected, Hidden)
        
        %% Demo Functions
        function demoToggleFcn(obj)
            if obj.DemoMode == false
                obj.DemoMode = true;
            else
                obj.DemoMode = false;
            end
        end
        
        function stopdemo(obj)
            set(obj.GuiHandles.DemoToggleButton, 'State', 'off', ...
                'TooltipString', 'Demo Mode: OFF');
            set(obj.GuiHandles.ComboFireworksButton, 'Enable', 'on');
            
            % Reset combo buffer
            obj.PresetFireworks = [];
            
        end
        
        function startdemo(obj)
            set(obj.GuiHandles.DemoToggleButton, 'State', 'on', ...
                'TooltipString', 'Demo Mode: ON');
            set(obj.GuiHandles.ComboFireworksButton, 'Enable', 'off');
            
            % This gets called before setting DemoMode to 'true', so only
            % start demo if it was NOT in DemoMode
            if obj.DemoMode == false
                if obj.FWAxes.isFireworksEmpty
                    obj.selectPresetFireworks();
                end
            end
        end
        
        function fireworksRepeater(obj)
            if obj.DemoMode
                obj.selectPresetFireworks();
            else
                if ~isempty(obj.PresetFireworks)
                    obj.selectPresetFireworks(obj.PresetFireworks(1));
                    obj.PresetFireworks(1) = [];
                end
            end
        end
        
        %% Recording Functions
        function movieTypeToggleFcn(obj)
            if strcmp(obj.MovieType, 'avi');
                obj.MovieType = 'gif';
            else
                obj.MovieType = 'avi';
            end
        end
        
        function changeMovieType(obj)
            
            if strcmp(obj.MovieType, 'avi')
                set(obj.GuiHandles.MovieTypeButton, ...
                    'CData', createCData('avi'), ...
                    'TooltipString', 'Movie type: AVI (click to change)');
            else
                set(obj.GuiHandles.MovieTypeButton, ...
                    'CData', createCData('gif'), ...
                    'TooltipString', 'Movie type: GIF (click to change)');
            end
            
        end
        
        function recordToggleFcn(obj)
            if obj.RecordMode == false
                obj.RecordMode = true;
            else
                obj.RecordMode = false;
            end
        end
        
        function startrecording(obj)
            set(obj.GuiHandles.MovieTypeButton, 'Enable', 'off');
            set(obj.GuiHandles.RecordToggleButton, 'State', 'on', ...
                'TooltipString', 'Record Mode: ON');
            set(obj.GuiHandles.FireworksFig, 'Resize', 'off');
            
            if strcmpi(obj.RecordTimer.Running, 'off')
                start(obj.RecordTimer);
            end
        end
        
        function stoprecording(obj)
            set(obj.GuiHandles.FireworksFig, 'Name', 'Fireworks');
            set(obj.GuiHandles.RecordToggleButton, 'State', 'off', ...
                'TooltipString', 'Record Mode: OFF');
            set(obj.GuiHandles.MovieTypeButton, 'Enable', 'on');
            set(obj.GuiHandles.FireworksFig, 'Resize', 'on');
            
            if strcmpi(obj.RecordTimer.Running, 'on')
                stop(obj.RecordTimer);
            end
        end
        
        function recordTimerFcn(obj, varargin)
            
            elapsedTime = round(toc(obj.Tic));
            
            if elapsedTime > obj.MaxRecordTime
                obj.RecordMode = false;
                msgbox({'You''ve been recording for an awfully long time.', ...
                    sprintf('Recording limited to %d seconds.', ...
                    round(obj.MaxRecordTime))}, 'Notice', 'modal');
                return;
            end
            
            set(obj.GuiHandles.FireworksFig, 'Name', ...
                sprintf('Fireworks (Recording... %d sec)', elapsedTime));
            
            f = getframe(obj.GuiHandles.FireworksFig);
            if strcmp(obj.MovieType, 'gif')
                imwrite(rgb2ind(f.cdata, helper.Fireworks.Colormap), helper.Fireworks.Colormap, ...
                    obj.GIFFileName, 'WriteMode', 'append', 'DelayTime', 0);
            else
                if verLessThan('matlab', '7.11.0')
                    obj.AVI = addframe(obj.AVI, f);
                else
                    writeVideo(obj.AVI, f);
                end
            end
            
        end
        
        function recordStartFcn(obj, varargin)
            
            if strcmp(obj.MovieType, 'gif')
                f = getframe(obj.GuiHandles.FireworksFig);
                
                obj.GIFFileName = sprintf('movie_%s.gif', datestr(now, 30));
                imwrite(rgb2ind(f.cdata, helper.Fireworks.Colormap), helper.Fireworks.Colormap, ...
                    obj.GIFFileName, 'DelayTime', 0, 'LoopCount', Inf);
            else
                if verLessThan('matlab', '7.11.0')
                    obj.AVI = avifile(sprintf('movie_%s.avi', datestr(now, 30)), ...
                        'fps', 10);
                else
                    obj.AVI = VideoWriter(sprintf('movie_%s.avi', datestr(now, 30)));
                    obj.AVI.FrameRate = 10;
                    open(obj.AVI);
                end
            end
            obj.Tic = tic;
        end
        
        function recordStopFcn(obj, varargin)
            
            disp('Finished Recording');
            
            if strcmp(obj.MovieType, 'avi')
                if verLessThan('matlab', '7.11.0')
                    obj.AVI = close(obj.AVI);
                else
                    close(obj.AVI);
                end
            end
            
        end
        
        %% GUI Functions
        function figureCloseFcn(obj)
            delete(obj);
            %delete(obj.GuiHandles.FireworksFig);
        end
        
        function figureResizeFcn(obj, varargin)
            pos = get(obj.GuiHandles.FireworksFig, 'Position');
            set(obj.FWAxes.AxH, ...
                'Position', [0, 0, pos(3:4)], ...
                'YLim', [0 3000], ...
                'XLimMode', 'auto', ...
                'ZLimMode', 'auto', ...
                'PlotBoxAspectRatio', [1, pos(4)/pos(3), 1]);
            set(obj.FWAxes.AxH, 'XLim', obj.FWAxes.XLim);
        end
        
        function windowButtonDownFcn(obj, varargin)
            if ~obj.DemoMode
                set(obj.GuiHandles.FireworksFig, ...
                    'WindowButtonMotionFcn', @obj.windowButtonMotionFcn);
                obj.TracePoints = [];
            end
        end
        
        function windowButtonMotionFcn(obj, varargin)
            if ~obj.DemoMode
                pt = get(obj.FWAxes.AxH, 'CurrentPoint');
                obj.TracePoints(end+1) = pt(1);
            end
        end
        
        function windowButtonUpFcn(obj, varargin)
            set(obj.GuiHandles.FireworksFig, 'WindowButtonMotionFcn', '');
            if ~obj.DemoMode
                if isempty(obj.TracePoints)
                    pt = get(obj.FWAxes.AxH, 'CurrentPoint');
                    obj.FWAxes.newFireworks('LaunchPos', pt(1));
                else
                    if length(obj.TracePoints) > 20
                        tp = obj.TracePoints(round(linspace(1, length(obj.TracePoints), 20)));
                    else
                        tp = obj.TracePoints;
                    end
                    sm = get(obj.GuiHandles.FireworksFig, 'SelectionType');
                    xl = obj.FWAxes.XLim80;
                    opts = cell(length(tp),1);
                    for id = 1:length(opts)
                        tpt = max(xl(1), min(xl(2), tp(id)));
                        switch sm
                            case {'normal', 'open'}
                                opts{id} = {'LaunchPos', tpt};
                            case 'alt'
                                opts{id} = {'LaunchPos', tpt, 'LaunchVel', [0 200], 'SpeedFactor', 1};
                        end
                    end
                    obj.setTimer(0.1, opts);
                    
                end
            end
        end
        
        function windowKeyPressFcn(obj, figObj, eventdata)
            
            %eventdata
            if ~obj.DemoMode
                if isequal(eventdata.Modifier, {'shift'})
                    switch eventdata.Character
                        case {'!', '?'}
                            obj.FWAxes.newFireworks('FireworksType', eventdata.Character, 'SpeedFactor', 1);
                    end
                else
                    switch eventdata.Key
                        case 'f1'
                            obj.FWAxes.newFireworks('FireworksType', 'plain');
                        case 'f2'
                            obj.FWAxes.newFireworks('FireworksType', 'glitter');
                        case {'1', '2', '3', '4', '5', '6', '7', '8', '9'}
                            obj.presetButtonFcn(str2double(eventdata.Key));
                        case '0'
                            obj.presetButtonFcn(10);
                        case 'space'
                            obj.FWAxes.newFireworks();
                        case  cellstr(('a':'z')')
                            obj.FWAxes.newFireworks('FireworksType', eventdata.Key, 'SpeedFactor', 1);
                        case 'f3'
                            obj.FWAxes.newFireworks('FireworksType', 'heart', 'SpeedFactor', 1);
                        case 'f4'
                            obj.FWAxes.newFireworks('FireworksType', 'matlab', 'SpeedFactor', 1);
                        case 'f10'
                            obj.recordToggleFcn();
                        case 'f12'
                            obj.demoToggleFcn();
                    end
                end
            else
                switch eventdata.Key
                    case 'f10'
                        obj.recordToggleFcn();
                    case 'f12'
                        obj.demoToggleFcn();
                end
            end
            
        end
        
        function windowScrollWheelFcn(obj, figObj, eventdata)
            if ~obj.DemoMode && eventdata.VerticalScrollCount < 0
                pt = get(obj.FWAxes.AxH, 'CurrentPoint');
                xl = obj.FWAxes.XLim80;
                obj.FWAxes.newFireworks('LaunchPos', max(xl(1), min(xl(2), pt(1))), ...
                    'LaunchVel', [10*rand-5 200]);
            end
        end
        
        %% Audio Function
        function soundToggleFcn(obj, varargin)
            if obj.SoundMode == false
                obj.SoundMode = true;
            else
                obj.SoundMode = false;
            end
        end
                
        %% Fireworks Functions        
        function presetButtonFcn(obj, id)
            if obj.FWAxes.isFireworksEmpty && isempty(obj.PresetFireworks)
                obj.selectPresetFireworks(id)
            else
                obj.PresetFireworks(end+1) = id;
            end
        end
        
        function selectPresetFireworks(obj, id)
            if nargin == 1
                id = round(9*rand())+1;
            end
            
            switch id
                case 1  % Random Timing
                    obj.setTimer([0.5 2], 15);
                    
                case 2  % Left to Right
                    xl = obj.FWAxes.XLim80;
                    opts = cell(9,1);
                    for id = 1:length(opts)
                        opts{id} = {'FireworksType', 'plain', 'LaunchPos', (id-5)*xl(2)/4, ...
                            'LaunchVel', [0 200], 'SpeedFactor', 1};
                    end
                    obj.setTimer(0.1, opts);
                    
                case 3  % Right to Left
                    xl = obj.FWAxes.XLim80;
                    opts = cell(9,1);
                    for id = 1:length(opts)
                        opts{id} = {'FireworksType', 'glitter', ...
                            'LaunchPos', (5-id)*xl(2)/4, ...
                            'LaunchVel', [0 200], ...
                            'SpeedFactor', 1};
                    end
                    obj.setTimer(0.1, opts);
                    
                case 4  % Flares
                    obj.FWAxes.newFireworks(20);
                    
                case 5  % Geyser
                    obj.FWAxes.newFireworks(20, 'LaunchPos', 0);
                    
                case 6  % Steady Stream
                    opts = cell(15,1);
                    for id = 1:length(opts)
                        opts{id} = {'LaunchPos', 0};
                    end
                    obj.setTimer(0.5, opts);
                    
                case 7  % Random Location
                    obj.setTimer(0.5, 15);
                    
                case 8  % Rapid Fire
                    opts = cell(30,1);
                    timedelay = nan(30, 1);
                    for id = 1:length(opts)
                        opts{id} = {'SpeedFactor', 1, 'LaunchPos', 0, ...
                            'LaunchVel', [10*rand-5 200], ...
                            'FireworksType', 'glitter'};
                    end
                    timedelay(1) = 0;
                    timedelay(2:3:end) = 0.1;
                    timedelay(3:3:end) = 0.1;
                    timedelay(4:3:end) = 1;
                    obj.setTimer(timedelay, opts);
                    
                case 9  % "Happy New Year!"
                    xl = obj.FWAxes.XLim80;
                    p0_1 = linspace(xl(1), xl(2), 5);
                    p0_2 = linspace(xl(1), xl(2), 3);
                    p0_3 = linspace(xl(1), xl(2), 5);
                    LaunchVel = [-5 200];
                    opts = cell(13,1);
                    timedelay = nan(13, 1);
                    opts{1}  = {'FireworksType', 'h', 'SpeedFactor', 1, 'LaunchPos', p0_1(1), 'LaunchVel', LaunchVel};
                    opts{2}  = {'FireworksType', 'a', 'SpeedFactor', 1, 'LaunchPos', p0_1(2), 'LaunchVel', LaunchVel};
                    opts{3}  = {'FireworksType', 'p', 'SpeedFactor', 1, 'LaunchPos', p0_1(3), 'LaunchVel', LaunchVel};
                    opts{4}  = {'FireworksType', 'p', 'SpeedFactor', 1, 'LaunchPos', p0_1(4), 'LaunchVel', LaunchVel};
                    opts{5}  = {'FireworksType', 'y', 'SpeedFactor', 1, 'LaunchPos', p0_1(5), 'LaunchVel', LaunchVel};
                    opts{6}  = {'FireworksType', 'n', 'SpeedFactor', 1, 'LaunchPos', p0_2(1), 'LaunchVel', LaunchVel};
                    opts{7}  = {'FireworksType', 'e', 'SpeedFactor', 1, 'LaunchPos', p0_2(2), 'LaunchVel', LaunchVel};
                    opts{8}  = {'FireworksType', 'w', 'SpeedFactor', 1, 'LaunchPos', p0_2(3), 'LaunchVel', LaunchVel};
                    opts{9}  = {'FireworksType', 'y', 'SpeedFactor', 1, 'LaunchPos', p0_3(1), 'LaunchVel', LaunchVel};
                    opts{10} = {'FireworksType', 'e', 'SpeedFactor', 1, 'LaunchPos', p0_3(2), 'LaunchVel', LaunchVel};
                    opts{11} = {'FireworksType', 'a', 'SpeedFactor', 1, 'LaunchPos', p0_3(3), 'LaunchVel', LaunchVel};
                    opts{12} = {'FireworksType', 'r', 'SpeedFactor', 1, 'LaunchPos', p0_3(4), 'LaunchVel', LaunchVel};
                    opts{13} = {'FireworksType', '!', 'SpeedFactor', 1, 'LaunchPos', p0_3(5), 'LaunchVel', LaunchVel};
                    timedelay(1) = 0;
                    timedelay([2 3 4 5 7 8 10 11 12 13]) = 0.3;
                    timedelay([6 9]) = 3;
                    obj.setTimer(timedelay, opts);
                case 10 % MATLAB
                    xl = obj.FWAxes.XLim80;
                    opts = cell(15,1);
                    for id = 1:length(opts)
                        opts{id} = {'FireworksType', 'matlab', 'LaunchPos', diff(xl)*rand-diff(xl)/2};
                    end
                    obj.setTimer(0.5, opts);
            end
        end
        
        function setTimer(obj, period, opts)
            if strcmpi(obj.DemoTimer.Running, 'on')
                return;
            end
            if length(period) == 1
                set(obj.DemoTimer, ...
                    'Period', period, ...
                    'StartDelay', 0, ...
                    'ExecutionMode', 'fixedSpacing');
                if iscell(opts)
                    set(obj.DemoTimer, ...
                        'TimerFcn', @(o,e) obj.delayedFireworksTimerFcn(opts), ...
                        'TasksToExecute', size(opts, 1));
                else
                    set(obj.DemoTimer, ...
                        'TimerFcn', @(o,e) obj.delayedFireworksTimerFcn(), ...
                        'TasksToExecute', opts);
                end
            else
                set(obj.DemoTimer, ...
                    'StartDelay', period(1), ...
                    'UserData', 1, ...
                    'ExecutionMode', 'singleShot');
                if iscell(opts)
                    set(obj.DemoTimer, ...
                        'TimerFcn', @(o,e) obj.delayedFireworksTimerFcn(opts), ...
                        'StopFcn', @(o,e) obj.changeDelayTimerFcn(period, size(opts, 1)));
                else
                    set(obj.DemoTimer, ...
                        'TimerFcn', @(o,e) obj.delayedFireworksTimerFcn(), ...
                        'StopFcn', @(o,e) obj.changeDelayTimerFcn(period, opts));
                end
            end
            
            start(obj.DemoTimer);
        end
        
        function delayedFireworksTimerFcn(obj, opts)
            if nargin == 2
                if strcmpi(get(obj.DemoTimer, 'ExecutionMode'), 'singleShot')
                    obj.FWAxes.newFireworks(opts{obj.DemoTimer.UserData}{:});
                else
                    obj.FWAxes.newFireworks(opts{obj.DemoTimer.TasksExecuted}{:});
                end
            else
                obj.FWAxes.newFireworks();
            end
        end
        
        function changeDelayTimerFcn(obj, delayRange, totalRep)
            obj.DemoTimer.UserData = obj.DemoTimer.UserData + 1;
            if obj.DemoTimer.UserData <= totalRep
                if length(delayRange) == totalRep
                    set(obj.DemoTimer, ...
                        'StartDelay', delayRange(obj.DemoTimer.UserData));
                else
                    set(obj.DemoTimer, ...
                        'StartDelay', ...
                        round((diff(delayRange)*rand+delayRange(1))*1000)/1000);
                end
                if isvalid(obj.DemoTimer)
                    start(obj.DemoTimer);
                end
            end
        end
        
    end
    
    %% Hidden Methods (overloading handle methods)
    methods (Hidden)
        
        function out = addlistener(varargin)
            out = addlistener@handle(varargin{:});
        end
        
        function notify(varargin)
            notify@handle(varargin{:})
        end
        
        function out = eq(varargin)
            out = eq@handle(varargin{:});
        end
        
        function out = ge(varargin)
            out = ge@handle(varargin{:});
        end
        
        function out = gt(varargin)
            out = gt@handle(varargin{:});
        end
        
        function out = le(varargin)
            out = le@handle(varargin{:});
        end
        
        function out = lt(varargin)
            out = lt@handle(varargin{:});
        end
        
        function out = ne(varargin)
            out = ne@handle(varargin{:});
        end
        
        function out = findprop(varargin)
            out = findprop@handle(varargin{:});
        end
        
        function findobj(varargin)
            findobj@handle(varargin{:});
        end
                
    end
    
end




%#ok<*INUSL>
%#ok<*INUSD>

Contact us