classdef CrossGUI < matlab.apps.AppBase

    % Properties that correspond to app components
    properties (Access = public)
        CrossDialog    matlab.ui.Figure
        FileMenu       matlab.ui.container.Menu
        OpenFile       matlab.ui.container.Menu
        SaveFile       matlab.ui.container.Menu
        Exit           matlab.ui.container.Menu
        AboutMenu      matlab.ui.container.Menu
        MomentPanel    matlab.ui.container.Panel
        ax_moment      matlab.ui.control.UIAxes
        DeformedPanel  matlab.ui.container.Panel
        ax_deformed    matlab.ui.control.UIAxes
        ModelPanel     matlab.ui.container.Panel
        ax_model       matlab.ui.control.UIAxes
        MessagePanel   matlab.ui.container.Panel
        MessageText    matlab.ui.control.Label
        ControlRuler   matlab.ui.container.Panel
        DeleteSup      matlab.ui.control.StateButton
        InsertSup      matlab.ui.control.StateButton
        Precision      matlab.ui.control.DropDown
        GoThru         matlab.ui.control.Button
        Step           matlab.ui.control.Button
        Restart        matlab.ui.control.Button
        SupEnd         matlab.ui.control.Button
        SupInit        matlab.ui.control.Button
    end

    properties (Access = public)
        control       CrossControl
    end

    methods (Access = private)
        % Called when user attempts to close dialog
        function deleteCallback(app)
            choice = questdlg('Are you sure you want to exit?',...
            'Exit','Exit','Cancel','Cancel');
            switch choice
                case 'Cancel'
                    return
            end
            app.delete();
        end
    end

    methods (Access = public)

        function updateTextMessage(app)
            if app.control.solver.moreStepsToGo()
                app.MessageText.Text = 'Moments are not balanced yet.';
            else
                app.MessageText.Text = 'Cross iterative solution completed.';
            end
        end

        function setTextMessage(app,msg)
            app.MessageText.Text = msg;
        end

        function updateSupInit(app,supinit)
            if supinit == 0
                app.SupInit.Icon = 'images/supinitfix.gif';
                app.SupInit.Tooltip = 'Change initial support to clamped';
            else
                app.SupInit.Icon = 'images/supinitrel.gif';
                app.SupInit.Tooltip = 'Change initial support to released';
            end
        end

        function updateSupEnd(app,supend)
            if supend == 0
                app.SupEnd.Icon = 'images/supendfix.gif';
                app.SupEnd.Tooltip = 'Change end support to clamped';
            else
                app.SupEnd.Icon = 'images/supendrel.gif';
                app.SupEnd.Tooltip = 'Change end support to released';
            end
        end

        function resetInsertSup(app)
            if app.InsertSup.Value
                app.InsertSup.Value = false;
%                app.control.insertSupMode(false);
            end
        end

        function resetDeleteSup(app)
            if app.DeleteSup.Value
                app.DeleteSup.Value = false;
%                app.control.deleteSupMode(false);
            end
        end
    end


    % Callbacks that handle component events
    methods (Access = private)

        % Code that executes after component creation
        function startupFcn(app)
            % Create and initialize cross control object
            app.control = CrossControl(app);
            app.control.startup(app.CrossDialog,app.ax_model,app.ax_deformed,app.ax_moment);

            % Set close app callback function
            app.CrossDialog.CloseRequestFcn = app.createCallbackFcn(@deleteCallback, false);

            % Turn off toolbar of all axes
            app.ax_model.Toolbar.Visible = 'off';
            app.ax_model.Interactions = [];
            app.ax_deformed.Toolbar.Visible = 'off';
            app.ax_deformed.Interactions = [];
            app.ax_moment.Toolbar.Visible = 'off';
            app.ax_moment.Interactions = [];
        end

        % Button pushed function: SupInit
        function SupInitButtonPushed(app, event)
            app.resetInsertSup();
            app.resetDeleteSup();
            app.control.toggleSupInit();
            app.updateSupInit(app.control.solver.supinit);
            app.updateTextMessage();
        end

        % Button pushed function: SupEnd
        function SupEndButtonPushed(app, event)
            app.resetInsertSup();
            app.resetDeleteSup();
            app.control.toggleSupEnd();
            app.updateSupEnd(app.control.solver.supend);
            app.updateTextMessage();
        end

        % Button pushed function: Restart
        function RestartButtonPushed(app, event)
            app.resetInsertSup();
            app.resetDeleteSup();
            app.control.restart();
            app.updateTextMessage();
        end

        % Button pushed function: Step
        function StepButtonPushed(app, event)
            app.resetInsertSup();
            app.resetDeleteSup();
            app.control.autoStep();
            app.updateTextMessage();
        end

        % Button pushed function: GoThru
        function GoThruButtonPushed(app, event)
            app.resetInsertSup();
            app.resetDeleteSup();
            app.control.goThru();
            app.updateTextMessage();
        end

        % Value changed function: InsertSup
        function InsertSupValueChanged(app, event)
            app.resetDeleteSup();
            value = app.InsertSup.Value;
%            app.control.insertSupMode(value);
            app.MessageText.Text = 'Insert an internal support with mouse pointer.';
        end

        % Value changed function: DeleteSup
        function DeleteSupValueChanged(app, event)
            app.resetInsertSup();
            value = app.DeleteSup.Value;
%            app.control.deleteSupMode(value);
            app.MessageText.Text = 'Select an internal support for deletion with mouse pointer.';
        end

        % Value changed function: Precision
        function PrecisionValueChanged(app, event)
            app.resetInsertSup();
            app.resetDeleteSup();
            value = app.Precision.Value;
            if strcmp(value,'1 kNm')
                decplc = 0;
            elseif strcmp(value,'0.1 kNm')
                decplc = 1;
            else
                decplc = 2;
            end
            app.control.setPrecision(decplc);
            app.updateTextMessage();
        end

        % Menu selected function: Exit
        function ExitMenuSelected(app, event)
            app.deleteCallback();
        end

        % Menu selected function: OpenFile
        function OpenFileMenuSelected(app, event)
            app.resetInsertSup();
            app.resetDeleteSup();
            filterspec = {'*.crs'};
            [filename,pathname] = uigetfile(filterspec,'Cross Program - Input file');
            if ~isequal(filename,0)
                fullname = strcat(pathname,filename);
                app.control.openFile(fullname);
            end
            app.updateTextMessage();
        end

        % Menu selected function: SaveFile
        function SaveFileMenuSelected(app, event)
            app.resetInsertSup();
            app.resetDeleteSup();
            filterspec = {'*.crs'};
            [filename,pathname] = uiputfile(filterspec,'Cross Program - Output file');
            if ~isequal(filename,0)
                fullname = strcat(pathname,filename);
                app.control.saveFile(fullname);
            end
        end

        % Menu selected function: AboutMenu
        function AboutMenuSelected(app, event)
            msgbox({ 'PUC-Rio - CIV2801 - Fundamentos de Computação Gráfica Aplicada - 2022.2'; ' '; ...
                      'Program to demonstrate the Cross process applied to a continuous beam.' }, 'About Cross program');
        end

        % Size changed function: ModelPanel
        function ModelPanel_SizeChangedFcn(app, event)
            position = app.ModelPanel.Position;
            panel_width = position(3);
            panel_height = position(4);
            canvas_x = 1;
            canvas_y = 1;
            canvas_width = panel_width-1;
            canvas_height = panel_height-21;
            app.ax_model.Position = [canvas_x canvas_y canvas_width canvas_height];
            app.control.resizeCanvas(app.ax_model);
        end

        % Size changed function: DeformedPanel
        function DeformedPanel_SizeChangedFcn(app, event)
            position = app.DeformedPanel.Position;
            panel_width = position(3);
            panel_height = position(4);
            canvas_x = 1;
            canvas_y = 1;
            canvas_width = panel_width-1;
            canvas_height = panel_height-21;
            app.ax_deformed.Position = [canvas_x canvas_y canvas_width canvas_height];
            app.control.resizeCanvas(app.ax_deformed);
        end

        % Size changed function: MomentPanel
        function MomentPanel_SizeChangedFcn(app, event)
            position = app.MomentPanel.Position;
            panel_width = position(3);
            panel_height = position(4);
            canvas_x = 1;
            canvas_y = 1;
            canvas_width = panel_width-1;
            canvas_height = panel_height-21;
            app.ax_moment.Position = [canvas_x canvas_y canvas_width canvas_height];
            app.control.resizeCanvas(app.ax_moment);
        end
    end

    % Component initialization
    methods (Access = private)

        % Create UIFigure and components
        function createComponents(app)

            % Create CrossDialog and hide until all components are created
            app.CrossDialog = uifigure('Visible', 'off');
            app.CrossDialog.Position = [100 100 900 590];
            app.CrossDialog.Name = 'Cross process of continuous beam';
            app.CrossDialog.Scrollable = 'on';

            % Create FileMenu
            app.FileMenu = uimenu(app.CrossDialog);
            app.FileMenu.Text = 'File';

            % Create OpenFile
            app.OpenFile = uimenu(app.FileMenu);
            app.OpenFile.MenuSelectedFcn = createCallbackFcn(app, @OpenFileMenuSelected, true);
            app.OpenFile.Text = 'Open';

            % Create SaveFile
            app.SaveFile = uimenu(app.FileMenu);
            app.SaveFile.MenuSelectedFcn = createCallbackFcn(app, @SaveFileMenuSelected, true);
            app.SaveFile.Text = 'Save as ...';

            % Create Exit
            app.Exit = uimenu(app.FileMenu);
            app.Exit.MenuSelectedFcn = createCallbackFcn(app, @ExitMenuSelected, true);
            app.Exit.Text = 'Exit ...';

            % Create AboutMenu
            app.AboutMenu = uimenu(app.CrossDialog);
            app.AboutMenu.MenuSelectedFcn = createCallbackFcn(app, @AboutMenuSelected, true);
            app.AboutMenu.Text = 'About';

            % Create ControlRuler
            app.ControlRuler = uipanel(app.CrossDialog);
            app.ControlRuler.Position = [2 561 898 30];

            % Create SupInit
            app.SupInit = uibutton(app.ControlRuler, 'push');
            app.SupInit.ButtonPushedFcn = createCallbackFcn(app, @SupInitButtonPushed, true);
            app.SupInit.Icon = 'supinitfix.gif';
            app.SupInit.IconAlignment = 'center';
            app.SupInit.Tooltip = {'Change initial support to clamped'};
            app.SupInit.Position = [0 5 21 22];
            app.SupInit.Text = '';

            % Create SupEnd
            app.SupEnd = uibutton(app.ControlRuler, 'push');
            app.SupEnd.ButtonPushedFcn = createCallbackFcn(app, @SupEndButtonPushed, true);
            app.SupEnd.Icon = 'supendrel.gif';
            app.SupEnd.IconAlignment = 'center';
            app.SupEnd.Tooltip = {'Change initial support to released'};
            app.SupEnd.Position = [61 5 21 22];
            app.SupEnd.Text = '';

            % Create Restart
            app.Restart = uibutton(app.ControlRuler, 'push');
            app.Restart.ButtonPushedFcn = createCallbackFcn(app, @RestartButtonPushed, true);
            app.Restart.Icon = 'restart.gif';
            app.Restart.IconAlignment = 'center';
            app.Restart.Tooltip = {'Initialize interative solution of Cross process'};
            app.Restart.Position = [125 5 21 22];
            app.Restart.Text = '';

            % Create Step
            app.Step = uibutton(app.ControlRuler, 'push');
            app.Step.ButtonPushedFcn = createCallbackFcn(app, @StepButtonPushed, true);
            app.Step.Icon = 'step.gif';
            app.Step.IconAlignment = 'center';
            app.Step.Tooltip = {'Process one step of iterative solution '};
            app.Step.Position = [145 5 21 22];
            app.Step.Text = '';

            % Create GoThru
            app.GoThru = uibutton(app.ControlRuler, 'push');
            app.GoThru.ButtonPushedFcn = createCallbackFcn(app, @GoThruButtonPushed, true);
            app.GoThru.Icon = 'gothru.gif';
            app.GoThru.IconAlignment = 'center';
            app.GoThru.Tooltip = {'Go through: process all steps of iterative solution'};
            app.GoThru.Position = [165 5 21 22];
            app.GoThru.Text = '';

            % Create Precision
            app.Precision = uidropdown(app.ControlRuler);
            app.Precision.Items = {'1 kNm', '0.1 kNm', '0.01 kNm'};
            app.Precision.ValueChangedFcn = createCallbackFcn(app, @PrecisionValueChanged, true);
            app.Precision.Tooltip = {'Set bending moment precision of iterative solution'};
            app.Precision.Position = [185 5 84 22];
            app.Precision.Value = '0.1 kNm';

            % Create InsertSup
            app.InsertSup = uibutton(app.ControlRuler, 'state');
            app.InsertSup.ValueChangedFcn = createCallbackFcn(app, @InsertSupValueChanged, true);
            app.InsertSup.Tooltip = {'Insert internal support'};
            app.InsertSup.Icon = 'supinsert.gif';
            app.InsertSup.Text = '';
            app.InsertSup.Position = [21 5 21 22];

            % Create DeleteSup
            app.DeleteSup = uibutton(app.ControlRuler, 'state');
            app.DeleteSup.ValueChangedFcn = createCallbackFcn(app, @DeleteSupValueChanged, true);
            app.DeleteSup.Tooltip = {'Delete internal support'};
            app.DeleteSup.Icon = 'supdelete.gif';
            app.DeleteSup.Text = '';
            app.DeleteSup.Position = [41 5 21 22];

            % Create MessagePanel
            app.MessagePanel = uipanel(app.CrossDialog);
            app.MessagePanel.Position = [2 530 898 30];

            % Create MessageText
            app.MessageText = uilabel(app.MessagePanel);
            app.MessageText.Position = [4 4 893 22];
            app.MessageText.Text = 'Moments are not balanced yet.';

            % Create ModelPanel
            app.ModelPanel = uipanel(app.CrossDialog);
            app.ModelPanel.AutoResizeChildren = 'off';
            app.ModelPanel.Title = 'Continuous beam model';
            app.ModelPanel.SizeChangedFcn = createCallbackFcn(app, @ModelPanel_SizeChangedFcn, true);
            app.ModelPanel.Position = [2 357 898 172];

            % Create ax_model
            app.ax_model = uiaxes(app.ModelPanel);
            app.ax_model.XLim = [0 1];
            app.ax_model.YLim = [0 1];
            app.ax_model.ZLim = [0 1];
            app.ax_model.XColor = 'none';
            app.ax_model.XTick = [];
            app.ax_model.YColor = 'none';
            app.ax_model.YTick = [];
            app.ax_model.ZColor = 'none';
            app.ax_model.Position = [1 1 896 150];

            % Create DeformedPanel
            app.DeformedPanel = uipanel(app.CrossDialog);
            app.DeformedPanel.AutoResizeChildren = 'off';
            app.DeformedPanel.Title = 'Deformed configuration (displacements scale exaggerated)';
            app.DeformedPanel.SizeChangedFcn = createCallbackFcn(app, @DeformedPanel_SizeChangedFcn, true);
            app.DeformedPanel.Position = [3 187 898 172];

            % Create ax_deformed
            app.ax_deformed = uiaxes(app.DeformedPanel);
            app.ax_deformed.XLim = [0 1];
            app.ax_deformed.YLim = [0 1];
            app.ax_deformed.ZLim = [0 1];
            app.ax_deformed.XColor = 'none';
            app.ax_deformed.XTick = [];
            app.ax_deformed.YColor = 'none';
            app.ax_deformed.YTick = [];
            app.ax_deformed.ZColor = 'none';
            app.ax_deformed.Position = [1 0 896 150];

            % Create MomentPanel
            app.MomentPanel = uipanel(app.CrossDialog);
            app.MomentPanel.AutoResizeChildren = 'off';
            app.MomentPanel.Title = 'Bending moment diagram (kNm)';
            app.MomentPanel.SizeChangedFcn = createCallbackFcn(app, @MomentPanel_SizeChangedFcn, true);
            app.MomentPanel.Position = [3 16 898 172];

            % Create ax_moment
            app.ax_moment = uiaxes(app.MomentPanel);
            app.ax_moment.XLim = [0 1];
            app.ax_moment.YLim = [0 1];
            app.ax_moment.ZLim = [0 1];
            app.ax_moment.XColor = 'none';
            app.ax_moment.XTick = [];
            app.ax_moment.YColor = 'none';
            app.ax_moment.YTick = [];
            app.ax_moment.ZColor = 'none';
            app.ax_moment.Position = [1 0 896 150];

            % Show the figure after all components are created
            app.CrossDialog.Visible = 'on';
        end
    end

    % App creation and deletion
    methods (Access = public)

        % Construct app
        function app = CrossGUI

            % Create UIFigure and components
            createComponents(app)

            % Register the app with App Designer
            registerApp(app, app.CrossDialog)

            % Execute the startup function
            runStartupFcn(app, @startupFcn)

            if nargout == 0
                clear app
            end
        end

        % Code that executes before app deletion
        function delete(app)

            % Delete UIFigure when app is deleted
            delete(app.CrossDialog)
        end
    end
end