From 2b9098f5400f40780096af1945ea34ab538a772a Mon Sep 17 00:00:00 2001 From: Nick Vella Date: Fri, 26 Feb 2021 18:17:28 +1100 Subject: [PATCH] WidgetGallery: add a simple Wizard demo :^) The sample Wizard subclasses WizardDialog and demonstrates a front and back cover, as well as extracting user input from a Wizard page to display in the interface which spawned the Wizard. --- Userland/Demos/WidgetGallery/CMakeLists.txt | 6 ++ .../Demos/WidgetGallery/DemoWizardDialog.cpp | 91 +++++++++++++++++++ .../Demos/WidgetGallery/DemoWizardDialog.h | 55 +++++++++++ .../Demos/WidgetGallery/DemoWizardPage1.gml | 37 ++++++++ .../Demos/WidgetGallery/DemoWizardPage2.gml | 21 +++++ Userland/Demos/WidgetGallery/main.cpp | 29 ++++++ 6 files changed, 239 insertions(+) create mode 100644 Userland/Demos/WidgetGallery/DemoWizardDialog.cpp create mode 100644 Userland/Demos/WidgetGallery/DemoWizardDialog.h diff --git a/Userland/Demos/WidgetGallery/CMakeLists.txt b/Userland/Demos/WidgetGallery/CMakeLists.txt index 2c4e42046dc..4fb67e32859 100644 --- a/Userland/Demos/WidgetGallery/CMakeLists.txt +++ b/Userland/Demos/WidgetGallery/CMakeLists.txt @@ -1,5 +1,11 @@ +compile_gml(DemoWizardPage1.gml DemoWizardPage1GML.h demo_wizard_page_1_gml) +compile_gml(DemoWizardPage2.gml DemoWizardPage2GML.h demo_wizard_page_2_gml) + set(SOURCES main.cpp + DemoWizardDialog.cpp + DemoWizardPage1GML.h + DemoWizardPage2GML.h ) serenity_app(WidgetGallery ICON app-widget-gallery) diff --git a/Userland/Demos/WidgetGallery/DemoWizardDialog.cpp b/Userland/Demos/WidgetGallery/DemoWizardDialog.cpp new file mode 100644 index 00000000000..96c8bdde564 --- /dev/null +++ b/Userland/Demos/WidgetGallery/DemoWizardDialog.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2021, Nick Vella + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "DemoWizardDialog.h" +#include +#include +#include +#include +#include +#include + +DemoWizardDialog::DemoWizardDialog(GUI::Window* parent_window) + : GUI::WizardDialog(parent_window) +{ + // Create the front cover + m_front_page = GUI::CoverWizardPage::construct(); + m_front_page->set_header_text("Welcome to the SerenityOS demo wizard!"); + m_front_page->set_body_text("This wizard demonstrates the amazing wizardry\ncapabilities of LibGUI :^)"); + m_front_page->on_next_page = [&]() { + return m_page_1; + }; + + // Create Page 1 + m_page_1 = GUI::WizardPage::construct( + "Installation location", + "Choose where Demo Application is installed on your computer."); + m_page_1->body_widget().load_from_gml(demo_wizard_page_1_gml); + m_page_1_location_text_box = m_page_1->body_widget().find_descendant_of_type_named("page_1_location_text_box"); + m_page_1->on_next_page = [&]() { + return m_page_2; + }; + + // Create Page 2 with a progress bar :^) + m_page_2 = GUI::WizardPage::construct( + "Installation in progress...", + "Please wait. Do not turn off your computer."); + m_page_2->body_widget().load_from_gml(demo_wizard_page_2_gml); + m_page_2_progress_bar = m_page_2->body_widget().find_descendant_of_type_named("page_2_progress_bar"); + m_page_2_timer = Core::Timer::construct(this); + m_page_2->on_page_enter = [&]() { + m_page_2_progress_value = 0; + m_page_2_timer->restart(100); + }; + m_page_2->on_page_leave = [&]() { + m_page_2_progress_value = 0; + m_page_2_timer->stop(); + }; + m_page_2_timer->on_timeout = [&]() { + if (m_page_2_progress_value < 100) + m_page_2_progress_value++; + m_page_2_progress_bar->set_value(m_page_2_progress_value); + + // Go to final page on progress completion + if (m_page_2_progress_value == 100) { + m_page_2_progress_value = 0; + replace_page(*m_back_page); + } + }; + // Don't set a on_next_page handler for page 2 as we automatically navigate to the final page on progress completion + + // Create the back cover + m_back_page = GUI::CoverWizardPage::construct(); + m_back_page->set_header_text("Wizard complete."); + m_back_page->set_body_text("That concludes the SerenityOS demo wizard :^)"); + m_back_page->set_is_final_page(true); + + push_page(*m_front_page); +} diff --git a/Userland/Demos/WidgetGallery/DemoWizardDialog.h b/Userland/Demos/WidgetGallery/DemoWizardDialog.h new file mode 100644 index 00000000000..430ec505c65 --- /dev/null +++ b/Userland/Demos/WidgetGallery/DemoWizardDialog.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021, Nick Vella + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include + +class DemoWizardDialog : public GUI::WizardDialog { + C_OBJECT(DemoWizardDialog); + +public: + String page_1_location() { return m_page_1_location_text_box->get_text(); } + +private: + DemoWizardDialog(GUI::Window* parent_window); + + RefPtr m_front_page; + RefPtr m_page_1; + RefPtr m_page_1_location_text_box; + + RefPtr m_page_2; + RefPtr m_page_2_progress_bar; + int m_page_2_progress_value { 0 }; + RefPtr m_page_2_timer; + + RefPtr m_back_page; +}; diff --git a/Userland/Demos/WidgetGallery/DemoWizardPage1.gml b/Userland/Demos/WidgetGallery/DemoWizardPage1.gml index e69de29bb2d..7840a4c92e7 100644 --- a/Userland/Demos/WidgetGallery/DemoWizardPage1.gml +++ b/Userland/Demos/WidgetGallery/DemoWizardPage1.gml @@ -0,0 +1,37 @@ +@GUI::Widget { + layout: @GUI::VerticalBoxLayout { + margins: [20, 20, 20, 20] + } + + @GUI::Label { + text: "Please select an installation directory." + text_alignment: "TopLeft" + fixed_height: 32 + } + + @GUI::Widget { + fixed_height: 25 + + layout: @GUI::HorizontalBoxLayout { + } + + @GUI::Label { + text: "Location: " + autosize: true + } + + @GUI::TextBox { + name: "page_1_location_text_box" + } + + @GUI::Button { + text: "Browse" + fixed_width: 75 + } + } + + // Spacer + @GUI::Widget { + + } +} diff --git a/Userland/Demos/WidgetGallery/DemoWizardPage2.gml b/Userland/Demos/WidgetGallery/DemoWizardPage2.gml index e69de29bb2d..1fd31f416da 100644 --- a/Userland/Demos/WidgetGallery/DemoWizardPage2.gml +++ b/Userland/Demos/WidgetGallery/DemoWizardPage2.gml @@ -0,0 +1,21 @@ +@GUI::Widget { + layout: @GUI::VerticalBoxLayout { + margins: [20, 20, 20, 20] + } + + @GUI::Label { + text: "Please wait..." + text_alignment: "TopLeft" + fixed_height: 32 + } + + @GUI::ProgressBar { + name: "page_2_progress_bar" + fixed_height: 28 + } + + // Spacer + @GUI::Widget { + + } +} diff --git a/Userland/Demos/WidgetGallery/main.cpp b/Userland/Demos/WidgetGallery/main.cpp index e0c129a21da..9bba628dbc7 100644 --- a/Userland/Demos/WidgetGallery/main.cpp +++ b/Userland/Demos/WidgetGallery/main.cpp @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -55,8 +56,12 @@ #include #include #include +#include +#include #include +#include "DemoWizardDialog.h" + template class ListViewModel final : public GUI::Model { public: @@ -466,6 +471,30 @@ int main(int argc, char** argv) input_label.set_text(value); }; + auto& tab_wizards = tab_widget.add_tab("Wizards"); + tab_wizards.set_layout(); + tab_wizards.layout()->set_margins({ 8, 8, 8, 8 }); + tab_wizards.layout()->set_spacing(8); + + auto& start_wizard_button = tab_wizards.add("Start wizard"); + auto& wizard_output_box = tab_wizards.add(); + wizard_output_box.set_text("Output from the demo wizard will appear here :^)"); + wizard_output_box.set_mode(GUI::TextEditor::DisplayOnly); + wizard_output_box.set_font(Gfx::FontDatabase::the().default_font()); + + start_wizard_button.on_click = [&]() { + wizard_output_box.set_text("Wizard started."); + + auto wizard = DemoWizardDialog::construct(window); + int result = wizard->exec(); + + StringBuilder sb; + sb.append(String::formatted("Wizard execution complete.\nDialog ExecResult code: {}", result)); + if (result == GUI::Dialog::ExecResult::ExecOK) + sb.append(String::formatted(" (ExecOK)\n'Installation' location: \"{}\"", wizard->page_1_location())); + wizard_output_box.set_text(sb.string_view()); + }; + auto& tab_image = tab_widget.add_tab("Images"); tab_image.set_layout(); tab_image.layout()->set_margins({ 8, 8, 8, 8 });