2021-02-21 22:40:08 +11:00
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2021, Nick Vella <nick@nxk.io>
|
2022-02-26 10:50:04 -07:00
|
|
|
* Copyright (c) 2022, the SerenityOS developers.
|
2021-02-21 22:40:08 +11:00
|
|
|
*
|
2021-04-22 01:24:48 -07:00
|
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
2021-02-21 22:40:08 +11:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <LibGUI/BoxLayout.h>
|
|
|
|
|
#include <LibGUI/Button.h>
|
|
|
|
|
#include <LibGUI/SeparatorWidget.h>
|
|
|
|
|
#include <LibGUI/Widget.h>
|
|
|
|
|
#include <LibGUI/Wizards/AbstractWizardPage.h>
|
|
|
|
|
#include <LibGUI/Wizards/WizardDialog.h>
|
|
|
|
|
#include <LibGfx/Orientation.h>
|
|
|
|
|
#include <LibGfx/SystemTheme.h>
|
|
|
|
|
|
|
|
|
|
namespace GUI {
|
|
|
|
|
|
|
|
|
|
WizardDialog::WizardDialog(Window* parent_window)
|
|
|
|
|
: Dialog(parent_window)
|
|
|
|
|
, m_page_stack()
|
|
|
|
|
{
|
|
|
|
|
resize(500, 360);
|
|
|
|
|
set_title(String::formatted("Sample wizard"));
|
|
|
|
|
set_resizable(false);
|
|
|
|
|
|
|
|
|
|
if (parent_window)
|
|
|
|
|
set_icon(parent_window->icon());
|
|
|
|
|
|
|
|
|
|
auto& main_widget = set_main_widget<Widget>();
|
|
|
|
|
main_widget.set_fill_with_background_color(true);
|
|
|
|
|
main_widget.set_layout<VerticalBoxLayout>();
|
|
|
|
|
main_widget.layout()->set_spacing(0);
|
|
|
|
|
|
|
|
|
|
m_page_container_widget = main_widget.add<Widget>();
|
|
|
|
|
m_page_container_widget->set_fixed_size(500, 315);
|
|
|
|
|
m_page_container_widget->set_layout<VerticalBoxLayout>();
|
|
|
|
|
|
|
|
|
|
auto& separator = main_widget.add<SeparatorWidget>(Gfx::Orientation::Horizontal);
|
|
|
|
|
separator.set_fixed_height(2);
|
|
|
|
|
|
|
|
|
|
auto& nav_container_widget = main_widget.add<Widget>();
|
|
|
|
|
nav_container_widget.set_layout<HorizontalBoxLayout>();
|
|
|
|
|
nav_container_widget.set_fixed_height(42);
|
Userland+LibGUI: Add shorthand versions of the Margins constructor
This allows for typing [8] instead of [8, 8, 8, 8] to specify the same
margin on all edges, for example. The constructors follow CSS' style of
specifying margins. The added constructors are:
- Margins(int all): Sets the same margin on all edges.
- Margins(int vertical, int horizontal): Sets the first argument to top
and bottom margins, and the second argument to left and right margins.
- Margins(int top, int vertical, int bottom): Sets the first argument to
the top margin, the second argument to the left and right margins,
and the third argument to the bottom margin.
2021-08-17 00:11:38 +00:00
|
|
|
nav_container_widget.layout()->set_margins({ 0, 10 });
|
2021-02-21 22:40:08 +11:00
|
|
|
nav_container_widget.layout()->set_spacing(0);
|
|
|
|
|
nav_container_widget.layout()->add_spacer();
|
|
|
|
|
|
|
|
|
|
m_back_button = nav_container_widget.add<Button>("< Back");
|
|
|
|
|
m_back_button->set_fixed_width(75);
|
AK+Everywhere: Disallow constructing Functions from incompatible types
Previously, AK::Function would accept _any_ callable type, and try to
call it when called, first with the given set of arguments, then with
zero arguments, and if all of those failed, it would simply not call the
function and **return a value-constructed Out type**.
This lead to many, many, many hard to debug situations when someone
forgot a `const` in their lambda argument types, and many cases of
people taking zero arguments in their lambdas to ignore them.
This commit reworks the Function interface to not include any such
surprising behaviour, if your function instance is not callable with
the declared argument set of the Function, it can simply not be
assigned to that Function instance, end of story.
2021-06-05 23:04:31 +04:30
|
|
|
m_back_button->on_click = [&](auto) {
|
2021-02-21 22:40:08 +11:00
|
|
|
pop_page();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
m_next_button = nav_container_widget.add<Button>("Next >");
|
|
|
|
|
m_next_button->set_fixed_width(75);
|
AK+Everywhere: Disallow constructing Functions from incompatible types
Previously, AK::Function would accept _any_ callable type, and try to
call it when called, first with the given set of arguments, then with
zero arguments, and if all of those failed, it would simply not call the
function and **return a value-constructed Out type**.
This lead to many, many, many hard to debug situations when someone
forgot a `const` in their lambda argument types, and many cases of
people taking zero arguments in their lambdas to ignore them.
This commit reworks the Function interface to not include any such
surprising behaviour, if your function instance is not callable with
the declared argument set of the Function, it can simply not be
assigned to that Function instance, end of story.
2021-06-05 23:04:31 +04:30
|
|
|
m_next_button->on_click = [&](auto) {
|
2021-02-21 22:40:08 +11:00
|
|
|
VERIFY(has_pages());
|
|
|
|
|
|
|
|
|
|
if (!current_page().can_go_next())
|
|
|
|
|
return done(ExecOK);
|
|
|
|
|
|
2021-03-19 17:23:10 +03:30
|
|
|
auto next_page = current_page().next_page();
|
|
|
|
|
if (!next_page)
|
|
|
|
|
return done(ExecOK);
|
|
|
|
|
|
|
|
|
|
push_page(*next_page);
|
2021-02-21 22:40:08 +11:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto& button_spacer = nav_container_widget.add<Widget>();
|
|
|
|
|
button_spacer.set_fixed_width(10);
|
|
|
|
|
|
|
|
|
|
m_cancel_button = nav_container_widget.add<Button>("Cancel");
|
|
|
|
|
m_cancel_button->set_fixed_width(75);
|
AK+Everywhere: Disallow constructing Functions from incompatible types
Previously, AK::Function would accept _any_ callable type, and try to
call it when called, first with the given set of arguments, then with
zero arguments, and if all of those failed, it would simply not call the
function and **return a value-constructed Out type**.
This lead to many, many, many hard to debug situations when someone
forgot a `const` in their lambda argument types, and many cases of
people taking zero arguments in their lambdas to ignore them.
This commit reworks the Function interface to not include any such
surprising behaviour, if your function instance is not callable with
the declared argument set of the Function, it can simply not be
assigned to that Function instance, end of story.
2021-06-05 23:04:31 +04:30
|
|
|
m_cancel_button->on_click = [&](auto) {
|
2021-02-21 22:40:08 +11:00
|
|
|
handle_cancel();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
update_navigation();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WizardDialog::push_page(AbstractWizardPage& page)
|
|
|
|
|
{
|
|
|
|
|
if (!m_page_stack.is_empty())
|
|
|
|
|
m_page_stack.last().page_leave();
|
|
|
|
|
|
|
|
|
|
m_page_stack.append(page);
|
|
|
|
|
m_page_container_widget->remove_all_children();
|
|
|
|
|
m_page_container_widget->add_child(page);
|
|
|
|
|
|
|
|
|
|
update_navigation();
|
|
|
|
|
page.page_enter();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WizardDialog::replace_page(AbstractWizardPage& page)
|
|
|
|
|
{
|
|
|
|
|
if (!m_page_stack.is_empty())
|
|
|
|
|
m_page_stack.take_last()->page_leave();
|
|
|
|
|
|
|
|
|
|
m_page_stack.append(page);
|
|
|
|
|
m_page_container_widget->remove_all_children();
|
|
|
|
|
m_page_container_widget->add_child(page);
|
|
|
|
|
|
|
|
|
|
update_navigation();
|
|
|
|
|
page.page_enter();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WizardDialog::pop_page()
|
|
|
|
|
{
|
|
|
|
|
if (m_page_stack.size() <= 1)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
auto page = m_page_stack.take_last();
|
|
|
|
|
page->page_leave();
|
|
|
|
|
|
|
|
|
|
m_page_container_widget->remove_all_children();
|
|
|
|
|
m_page_container_widget->add_child(m_page_stack.last());
|
|
|
|
|
|
|
|
|
|
update_navigation();
|
|
|
|
|
m_page_stack.last().page_enter();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WizardDialog::update_navigation()
|
|
|
|
|
{
|
|
|
|
|
m_back_button->set_enabled(m_page_stack.size() > 1);
|
|
|
|
|
if (has_pages()) {
|
|
|
|
|
m_next_button->set_enabled(current_page().is_final_page() || current_page().can_go_next());
|
|
|
|
|
m_next_button->set_text(current_page().is_final_page() ? "Finish" : "Next >");
|
|
|
|
|
} else {
|
|
|
|
|
m_next_button->set_text("Next >");
|
|
|
|
|
m_next_button->set_enabled(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
AbstractWizardPage& WizardDialog::current_page()
|
|
|
|
|
{
|
|
|
|
|
VERIFY(has_pages());
|
|
|
|
|
return m_page_stack.last();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void WizardDialog::handle_cancel()
|
|
|
|
|
{
|
|
|
|
|
if (on_cancel)
|
|
|
|
|
return on_cancel();
|
|
|
|
|
|
|
|
|
|
done(ExecCancel);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|