GUI2: A modeless_dialog is now a window

Which it should have been all along, as evidenced by the diff stats
here of +84, -246.
This commit is contained in:
Tommy 2022-07-29 23:42:17 +12:00
parent 6e357ea8b3
commit 247e5ff055
9 changed files with 87 additions and 254 deletions

View file

@ -41,31 +41,7 @@ std::unique_ptr<window> build(const builder_window::window_resolution& definitio
// best size (if needed) after all widgets have been placed.
auto win = std::make_unique<window>(definition);
assert(win);
for(const auto& lg : definition.linked_groups) {
if(win->has_linked_size_group(lg.id)) {
t_string msg = VGETTEXT("Linked '$id' group has multiple definitions.", {{"id", lg.id}});
FAIL(msg);
}
win->init_linked_size_group(lg.id, lg.fixed_width, lg.fixed_height);
}
win->set_click_dismiss(definition.click_dismiss);
const auto conf = win->cast_config_to<window_definition>();
assert(conf);
if(conf->grid) {
win->init_grid(*conf->grid);
win->finalize(*definition.grid);
} else {
win->init_grid(*definition.grid);
}
win->add_to_keyboard_chain(win.get());
win->finish_build(definition);
return win;
}

View file

@ -17,7 +17,6 @@
#include "gui/dialogs/debug_clock.hpp"
#include "draw_manager.hpp"
#include "gui/auxiliary/find_widget.hpp"
#include "gui/dialogs/modal_dialog.hpp"
#include "gui/widgets/integer_selector.hpp"
@ -35,57 +34,43 @@ namespace gui2::dialogs
REGISTER_DIALOG(debug_clock)
void debug_clock::pre_show(window& window)
debug_clock::debug_clock()
: modeless_dialog(window_id())
, signal_()
, time_()
{
hour_percentage_ = find_widget<progress_bar>(
&window, "hour_percentage", false, false);
this, "hour_percentage", false, false);
minute_percentage_ = find_widget<progress_bar>(
&window, "minute_percentage", false, false);
this, "minute_percentage", false, false);
second_percentage_ = find_widget<progress_bar>(
&window, "second_percentage", false, false);
this, "second_percentage", false, false);
hour_ = find_widget<integer_selector>(&window, "hour", false, false);
hour_ = find_widget<integer_selector>(this, "hour", false, false);
if(styled_widget *hour = dynamic_cast<styled_widget*>(hour_)) { //Note that the standard specifies that a dynamic cast of a null pointer is null
hour->set_active(false);
}
minute_ = find_widget<integer_selector>(&window, "minute", false, false);
minute_ = find_widget<integer_selector>(this, "minute", false, false);
if(styled_widget *minute = dynamic_cast<styled_widget*>(minute_)) {
minute->set_active(false);
}
second_ = find_widget<integer_selector>(&window, "second", false, false);
second_ = find_widget<integer_selector>(this, "second", false, false);
if(styled_widget *second = dynamic_cast<styled_widget*>(second_)) {
second->set_active(false);
}
pane_ = find_widget<pane>(&window, "pane", false, false);
pane_ = find_widget<pane>(this, "pane", false, false);
clock_ = find_widget<styled_widget>(&window, "clock", false, false);
draw_manager::register_drawable(this);
clock_ = find_widget<styled_widget>(this, "clock", false, false);
time_.set_current_time();
update_time(true);
}
void debug_clock::post_show()
{
draw_manager::deregister_drawable(this);
}
void debug_clock::layout()
void debug_clock::update()
{
update_time(false);
}
rect debug_clock::screen_location()
{
return get_window()->get_rectangle();
}
bool debug_clock::expose(const rect& /*region*/)
{
// Drawing is handled by the window that this should be, but is not.
return false;
window::update();
}
void debug_clock::update_time(const bool force)

View file

@ -47,23 +47,10 @@ namespace dialogs
* second | integer_selector |no |This shows the seconds since the beginning of the current minute. The control should have a minimum_value of 0 and a maximum_value of 59.
* clock | control |no |A control which will have set three variables in its canvas:<ul><li>hour - the same value as the hour integer_selector.</li><li>minute - the same value as the minute integer_selector.</li><li>second - the same value as the second integer_selector.</li></ul>The control can then show the time in its own preferred format(s).
*/
class debug_clock : public modeless_dialog, public top_level_drawable
class debug_clock : public modeless_dialog
{
public:
debug_clock()
: modeless_dialog()
, hour_percentage_(nullptr)
, minute_percentage_(nullptr)
, second_percentage_(nullptr)
, hour_(nullptr)
, minute_(nullptr)
, second_(nullptr)
, pane_(nullptr)
, clock_(nullptr)
, signal_()
, time_()
{
}
debug_clock();
private:
/** Progress bar for displaying the hours as a percentage. */
@ -139,12 +126,9 @@ private:
*/
time time_;
/** The type of window this is. */
virtual const std::string& window_id() const override;
virtual void pre_show(window& window) override;
virtual void post_show();
/**
* The callback for the drawing routine.
*
@ -156,11 +140,8 @@ private:
*/
void update_time(const bool force);
// TODO: draw_manager - modeless dialog should be a window, fix
/* top_level_drawable interface */
virtual void layout() override;
virtual bool expose(const rect& region) override;
virtual rect screen_location() override;
virtual void update() override;
};
} // namespace dialogs

View file

@ -17,19 +17,21 @@
#include "gui/dialogs/modeless_dialog.hpp"
#include "gui/widgets/window.hpp"
#include "gui/core/gui_definition.hpp" // get_window_builder
#include "video.hpp"
namespace gui2::dialogs
{
modeless_dialog::modeless_dialog() : window_(nullptr)
modeless_dialog::modeless_dialog(const std::string& window_id)
: window(get_window_builder(window_id))
{
window::finish_build(get_window_builder(window_id));
widget::set_id(window_id);
}
modeless_dialog::~modeless_dialog()
{
hide();
}
void modeless_dialog::show(const bool allow_interaction, const unsigned /*auto_close_time*/)
@ -38,47 +40,13 @@ void modeless_dialog::show(const bool allow_interaction, const unsigned /*auto_c
return;
}
hide();
window_ = build_window();
post_build(*window_);
pre_show(*window_);
if(allow_interaction) {
open_window_stack.push_back(window_.get());
window_->show_non_modal();
open_window_stack.push_back(this);
window::show_non_modal();
remove_from_window_stack(this);
} else {
window_->show_tooltip(/*auto_close_time*/);
window::show_tooltip(/*auto_close_time*/);
}
}
void modeless_dialog::hide()
{
if(window_) {
// Don't bother if show_mode_ == tooltip, because in that case we didn't add it anyway.
if(window_->mode() == window::show_mode::modeless) {
remove_from_window_stack(window_.get());
}
window_->undraw();
window_.reset(nullptr); }
}
std::unique_ptr<window> modeless_dialog::build_window() const
{
return build(window_id());
}
void modeless_dialog::post_build(window& /*window*/)
{
/* DO NOTHING */
}
void modeless_dialog::pre_show(window& /*window*/)
{
/* DO NOTHING */
}
} // namespace dialogs

View file

@ -15,14 +15,12 @@
#pragma once
#include <memory>
#include "gui/widgets/window.hpp"
#include <string>
namespace gui2
{
class window;
namespace dialogs
{
@ -32,7 +30,7 @@ namespace dialogs
* At the moment these windows also don't capture the mouse and keyboard so can
* only be used for things like tooltips. This behavior might change later.
*/
class modeless_dialog
class modeless_dialog : public window
{
/**
* Special helper function to get the id of the window.
@ -51,7 +49,7 @@ class modeless_dialog
friend window* unit_test_window(const modeless_dialog& dialog);
public:
modeless_dialog();
explicit modeless_dialog(const std::string& window_id);
virtual ~modeless_dialog();
@ -70,52 +68,13 @@ public:
void show(const bool allow_interaction = false,
const unsigned auto_close_time = 0);
/**
* Hides the window.
*
* The hiding also destroys the window. It is save to call the function
* when the window is not shown.
*/
void hide();
/** Returns a pointer to the dialog's window. Will be null if it hasn't been built yet. */
window* get_window() const
{
return window_.get();
}
protected:
/** The window, used in show. */
std::unique_ptr<window> window_;
private:
/** The id of the window to build. */
virtual const std::string& window_id() const = 0;
/**
* Builds the window.
* The ID of the window to build. Usually defined by REGISTER_DIALOG.
*
* Every dialog shows it's own kind of window, this function should return
* the window to show.
*
* @returns The window to show.
* Falls back to widget::id(), which is set during construction.
*/
std::unique_ptr<window> build_window() const;
/**
* Actions to be taken directly after the window is build.
*
* @param window The window just created.
*/
virtual void post_build(window& window);
/**
* Actions to be taken before showing the window.
*
* @param window The window to be shown.
*/
virtual void pre_show(window& window);
virtual const std::string& window_id() const { return widget::id(); }
};
} // namespace dialogs

View file

@ -57,85 +57,26 @@ REGISTER_WINDOW(tooltip_large)
class tooltip : public modeless_dialog
{
public:
tooltip() : modeless_dialog(), window_id_(), message_(), mouse_()
tooltip(const std::string& window_id, const t_string& message,
const point& mouse, const SDL_Rect& source_rect)
: modeless_dialog(window_id)
{
// To make Coverity happy
source_rect_.x = 0;
source_rect_.y = 0;
source_rect_.w = 0;
source_rect_.h = 0;
find_widget<styled_widget>(this, "label", false).set_label(message);
set_variable("mouse_x", wfl::variant(mouse.x));
set_variable("mouse_y", wfl::variant(mouse.y));
set_variable("source_x", wfl::variant(source_rect.x));
set_variable("source_y", wfl::variant(source_rect.y));
set_variable("source_w", wfl::variant(source_rect.w));
set_variable("source_h", wfl::variant(source_rect.h));
}
void set_window_id(const std::string& window_id)
{
window_id_ = window_id;
}
void set_message(const t_string& message)
{
message_ = message;
}
void set_mouse(const point& mouse)
{
mouse_ = mouse;
}
void set_source_rect(const SDL_Rect& rect)
{
source_rect_ = rect;
}
private:
/** The id of the window to use to show the tip. */
std::string window_id_;
/** The message to show. */
t_string message_;
/** The position of the mouse. */
point mouse_;
/** The size of the requestor. */
SDL_Rect source_rect_;
/** Inherited from modeless_dialog. */
virtual const std::string& window_id() const override;
/** Inherited from modeless_dialog. */
virtual void pre_show(window& window) override;
};
void tooltip::pre_show(window& window)
{
find_widget<styled_widget>(&window, "label", false).set_label(message_);
window.set_variable("mouse_x", wfl::variant(mouse_.x));
window.set_variable("mouse_y", wfl::variant(mouse_.y));
window.set_variable("source_x", wfl::variant(source_rect_.x));
window.set_variable("source_y", wfl::variant(source_rect_.y));
window.set_variable("source_w", wfl::variant(source_rect_.w));
window.set_variable("source_h", wfl::variant(source_rect_.h));
}
const std::string& tooltip::window_id() const
{
return window_id_;
}
namespace tip
{
static tooltip& tip()
{
/*
* Allocating a static tip object causes a segmentation fault when Wesnoth
* terminates. So instead create an object on the heap and never free it.
*/
static tooltip* t = new tooltip();
return *t;
}
static std::unique_ptr<tooltip> tip;
void show(const std::string& window_id,
const t_string& message,
@ -146,23 +87,19 @@ void show(const std::string& window_id,
* For now allow invalid tip names, might turn them to invalid wml messages
* later on.
*/
tooltip& t = tip();
t.set_window_id(window_id);
t.set_message(message);
t.set_mouse(mouse);
t.set_source_rect(source_rect);
tip.reset(new tooltip(window_id, message, mouse, source_rect));
try
{
t.show();
tip->show();
}
catch(const window_builder_invalid_id&)
{
ERR_CFG << "Tip with the requested id '" << window_id
<< "' doesn't exist, fall back to the default.";
t.set_window_id("tooltip_large");
tip.reset(new tooltip("tooltip_large", message, mouse, source_rect));
try
{
t.show();
tip->show();
}
catch(const window_builder_invalid_id&)
{
@ -173,7 +110,7 @@ void show(const std::string& window_id,
void remove()
{
tip().hide();
tip.reset();
}
} // namespace tip

View file

@ -28,6 +28,7 @@
#include "events.hpp"
#include "floating_label.hpp"
#include "formula/callable.hpp"
#include "formula/string_utils.hpp"
#include "gettext.hpp"
#include "log.hpp"
#include "gui/auxiliary/typed_formula.hpp"
@ -392,6 +393,8 @@ window::~window()
manager::instance().remove(*this);
undraw();
#ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
delete debug_layout_;
@ -417,6 +420,33 @@ retval window::get_retval_by_id(const std::string& id)
}
}
void window::finish_build(const builder_window::window_resolution& definition)
{
for(const auto& lg : definition.linked_groups) {
if(has_linked_size_group(lg.id)) {
t_string msg = VGETTEXT("Linked '$id' group has multiple definitions.", {{"id", lg.id}});
FAIL(msg);
}
init_linked_size_group(lg.id, lg.fixed_width, lg.fixed_height);
}
set_click_dismiss(definition.click_dismiss);
const auto conf = cast_config_to<window_definition>();
assert(conf);
if(conf->grid) {
init_grid(*conf->grid);
finalize(*definition.grid);
} else {
init_grid(*definition.grid);
}
add_to_keyboard_chain(this);
}
void window::show_tooltip(/*const unsigned auto_close_timeout*/)
{
log_scope2(log_gui_draw, "Window: show as tooltip.");

View file

@ -74,7 +74,7 @@ class window : public panel, public top_level_drawable
public:
explicit window(const builder_window::window_resolution& definition);
~window();
virtual ~window();
/**
* Returns the instance of a window.
@ -88,6 +88,8 @@ public:
/** Gets the retval for the default buttons. */
static retval get_retval_by_id(const std::string& id);
void finish_build(const builder_window::window_resolution&);
/**
* Shows the window, running an event loop until it should close.
*

View file

@ -152,11 +152,6 @@ std::string unit_test_mark_popup_as_tested(const modeless_dialog& dialog)
return dialog.window_id();
}
window* unit_test_window(const modeless_dialog& dialog)
{
return dialog.window_.get();
}
} // namespace dialogs
} // namespace gui2
@ -235,7 +230,7 @@ namespace {
std::string exception;
try {
dlg->show(interact);
gui2::window* window = unit_test_window((*dlg.get()));
gui2::window* window = dlg.get();
BOOST_REQUIRE_NE(window, static_cast<void*>(nullptr));
window->draw();
} catch(const gui2::layout_exception_width_modified&) {