Add a new tooltip implementation.

It's based on a new base class for popup windows. It also fixes the not
properly undrawing problem.
This commit is contained in:
Mark de Wever 2011-02-11 19:50:23 +00:00
parent 7725e75a07
commit 813f103b15
13 changed files with 552 additions and 57 deletions

View file

@ -8,6 +8,9 @@ Version 1.9.4+svn:
Portuguese (Brazil), Spanish, Vietnamese
* User interface:
* Added: circle to the gui2 canvas.
* Added: new tip class for tooltips and helptips.
* Reimplemented: the tooltips use the new tip class and look much better.
* Fixed: the tooltips no longer stack when the MP dialog is opened.
* WML engine:
* Allow [color_range] and [color_palette] nodes to be inserted at top-level
by add-ons to globally define custom ranges and palettes.

View file

@ -98,6 +98,7 @@
{_GUI_DEFINITION "default" "default label" DEFAULT () DEFAULT ({GUI__TEXT_VERTICALLY_CENTRED})}
{_GUI_DEFINITION "scroll_label" "scroll label" DEFAULT () DEFAULT 0}
{_GUI_DEFINITION "title" "label used for titles" TITLE "bold" TITLE ({GUI__TEXT_VERTICALLY_CENTRED})}
{_GUI_DEFINITION "default_large" "default, large font size" LARGE () DEFAULT ({GUI__TEXT_VERTICALLY_CENTRED})}
{_GUI_DEFINITION "default_small" "default, small font size" SMALL () DEFAULT ({GUI__TEXT_VERTICALLY_CENTRED})}
{_GUI_DEFINITION "default_tiny" "default, small font size" TINY () DEFAULT ({GUI__TEXT_VERTICALLY_CENTRED})}

View file

@ -0,0 +1,46 @@
#textdomain wesnoth-lib
###
### Defines all window styles used in the game.
### For now the definition for normal and tiny gui are the same, this might
### change later when tiny-gui will be tested.
###
[window_definition]
id = tooltip_large
description = "The window to show a large tooltip."
[resolution]
left_border = 7
right_border = 7
top_border = 7
bottom_border = 7
[background]
[draw]
[rectangle]
x1 = 0
y1 = 0
w = "(width)"
h = "(height)"
fill_color = "0, 0, 0, 192"
[/rectangle]
[/draw]
[/background]
[foreground]
[draw]
[/draw]
[/foreground]
[/resolution]
[/window_definition]

View file

@ -0,0 +1,38 @@
#textdomain wesnoth-lib
###
### Definition of the window used to show large tooltips.
###
[window]
id = "tooltip_large"
description = "The tooltip popup window with large tooltips, eg in the main menu."
[resolution]
definition = "tooltip_large"
automatic_placement = "true"
vertical_placement = "bottom"
horizontal_placement = "center"
[grid]
[row]
[column]
[label]
id = "label"
definition = "default_large"
wrap = "true"
[/label]
[/column]
[/row]
[/grid]
[/resolution]
[/window]

View file

@ -77,6 +77,7 @@ src/gui/dialogs/language_selection.cpp
src/gui/dialogs/lobby_main.cpp
src/gui/dialogs/message.cpp
src/gui/dialogs/mp_cmd_wrapper.cpp
src/gui/dialogs/popup.cpp
src/gui/dialogs/mp_connect.cpp
src/gui/dialogs/mp_create_game.cpp
src/gui/dialogs/mp_create_game_set_password.cpp
@ -84,6 +85,7 @@ src/gui/dialogs/mp_method_selection.cpp
src/gui/dialogs/simple_item_selector.cpp
src/gui/dialogs/title_screen.cpp
src/gui/dialogs/transient_message.cpp
src/gui/dialogs/tip.cpp
src/gui/dialogs/unit_attack.cpp
src/gui/dialogs/unit_create.cpp
src/gui/dialogs/wml_message.cpp

View file

@ -429,9 +429,11 @@ set(wesnoth-main_SRC
gui/dialogs/mp_create_game_set_password.cpp
gui/dialogs/mp_method_selection.cpp
gui/dialogs/mp_cmd_wrapper.cpp
gui/dialogs/popup.cpp
gui/dialogs/simple_item_selector.cpp
gui/dialogs/title_screen.cpp
gui/dialogs/transient_message.cpp
gui/dialogs/tip.cpp
gui/dialogs/unit_attack.cpp
gui/dialogs/unit_create.cpp
gui/dialogs/wml_message.cpp

View file

@ -368,9 +368,11 @@ wesnoth_sources = Split("""
gui/dialogs/mp_create_game_set_password.cpp
gui/dialogs/mp_method_selection.cpp
gui/dialogs/mp_cmd_wrapper.cpp
gui/dialogs/popup.cpp
gui/dialogs/simple_item_selector.cpp
gui/dialogs/title_screen.cpp
gui/dialogs/transient_message.cpp
gui/dialogs/tip.cpp
gui/dialogs/unit_attack.cpp
gui/dialogs/unit_create.cpp
gui/dialogs/wml_message.cpp

67
src/gui/dialogs/popup.cpp Normal file
View file

@ -0,0 +1,67 @@
/* $Id$ */
/*
Copyright (C) 2011 by Mark de Wever <koraq@xs4all.nl>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#define GETTEXT_DOMAIN "wesnoth-lib"
#include "gui/dialogs/popup.hpp"
#include "gui/widgets/window.hpp"
#include "video.hpp"
namespace gui2 {
tpopup::tpopup()
: window_(NULL)
{
}
tpopup::~tpopup()
{
hide();
}
void tpopup::show(CVideo& video, const unsigned /*auto_close_time*/)
{
if(video.faked()) {
return;
}
hide();
window_ = build_window(video);
post_build(video, *window_);
pre_show(video, *window_);
window_->show_tooltip(/*auto_close_time*/);
}
void tpopup::hide()
{
if(window_) {
window_->undraw();
delete window_;
window_ = NULL;
}
}
twindow* tpopup::build_window(CVideo& video) const
{
return build(video, window_id());
}
} // namespace gui2

103
src/gui/dialogs/popup.hpp Normal file
View file

@ -0,0 +1,103 @@
/* $Id$ */
/*
Copyright (C) 2011 by Mark de Wever <koraq@xs4all.nl>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#ifndef GUI_DIALOGS_POPUP_HPP_INCLUDED
#define GUI_DIALOGS_POPUP_HPP_INCLUDED
#include <string>
class CVideo;
namespace gui2 {
class twindow;
/**
* The popup class shows windows that are shown non-modal.
*
* At the moment these windows also don't capture the mouse and keyboard so can
* only be used for things like tooltips. This behaviour might change later.
*/
class tpopup
{
public:
tpopup();
virtual ~tpopup();
/**
* Shows the window.
*
* @param video The video which contains the surface to draw
* upon.
* @param auto_close_time The time in ms after which the dialog will
* automatically close, if 0 it doesn't close.
* @note the timeout is a minimum time and
* there's no quarantee about how fast it closes
* after the minimum.
*/
void show(CVideo& video, 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();
private:
/** The window, used in show. */
twindow* window_;
/** The id of the window to build. */
virtual const std::string& window_id() const = 0;
/**
* Builds the window.
*
* Every dialog shows it's own kind of window, this function should return
* the window to show.
*
* @param video The video which contains the surface to draw
* upon.
* @returns The window to show.
*/
twindow* build_window(CVideo& video) const;
/**
* Actions to be taken directly after the window is build.
*
* @param video The video which contains the surface to draw
* upon.
* @param window The window just created.
*/
virtual void post_build(CVideo& /*video*/, twindow& /*window*/) {}
/**
* Actions to be taken before showing the window.
*
* @param video The video which contains the surface to draw
* upon.
* @param window The window to be shown.
*/
virtual void pre_show(CVideo& /*video*/, twindow& /*window*/) {}
};
} // namespace gui2
#endif

156
src/gui/dialogs/tip.cpp Normal file
View file

@ -0,0 +1,156 @@
/* $Id$ */
/*
Copyright (C) 2011 by Mark de Wever <koraq@xs4all.nl>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#define GETTEXT_DOMAIN "wesnoth-lib"
#include "gui/dialogs/tip.hpp"
#include "gui/dialogs/dialog.hpp"
#include "gui/dialogs/popup.hpp"
#include "gui/widgets/settings.hpp"
#include "gui/widgets/window.hpp"
namespace gui2 {
/*WIKI
* @page = GUIWindowDefinitionWML
* @order = 2_tip
*
* == Tip float ==
*
* Generic window to show a floating tip window. The class has several
* subclasses using the same format. For example there will be tooltips and
* helptips, both using this class.
*
* @begin{table}{dialog_widgets}
*
* label & & control & m &
* This text contains the message to show in the tip. $
*
* @end{table}
*
* In the canvas of the windows used in this dialog the following variables are
* defined:
*
* @begin{table}{formula}
* mouse_x & unsigned & The x coordinate of the mouse pointer when
* the window was created. $
* mouse_y & unsigned & The y coordinate of the mouse pointer when
* the window was created. $
* @end{table}
*/
REGISTER_WND(tooltip_large)
/**
* Class to show the tips.
*
* At the moment two kinds of tips are known:
* * tooltip
* * helptip
*/
class ttip
: public tpopup
{
public:
ttip()
: tpopup()
, window_id_()
, message_()
, mouse_(tpoint(0, 0))
{
}
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 tpoint& mouse)
{
mouse_ = mouse;
}
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. */
tpoint mouse_;
/** Inherited from tpopup. */
virtual const std::string& window_id() const;
/** Inherited from tpopup. */
void pre_show(CVideo& video, twindow& window);
};
void ttip::pre_show(CVideo& /*video*/, twindow& window)
{
find_widget<tcontrol>(&window, "label", false).set_label(message_);
window.set_variable("mouse_x", variant(mouse_.x));
window.set_variable("mouse_y", variant(mouse_.y));
}
const std::string& ttip::window_id() const
{
return window_id_;
}
namespace tip {
static ttip& tip()
{
/*
* Allocating a static tip object causes a segmentation fault when Wesnoth
* termines. So instead create an object on the heap and never free it.
*/
static ttip *t = new ttip();
return *t;
}
void show(CVideo& video
, const std::string& window_id
, const t_string& message
, const tpoint& mouse)
{
ttip& t = tip();
t.set_window_id(window_id);
t.set_message(message);
t.set_mouse(mouse);
t.show(video);
}
void remove()
{
tip().hide();
}
} // namespace tip
} // namespace gui2

59
src/gui/dialogs/tip.hpp Normal file
View file

@ -0,0 +1,59 @@
/* $Id$ */
/*
Copyright (C) 2011 by Mark de Wever <koraq@xs4all.nl>
Part of the Battle for Wesnoth Project http://www.wesnoth.org/
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY.
See the COPYING file for more details.
*/
#ifndef GUI_DIALOGS_TIP_HPP_INCLUDED
#define GUI_DIALOGS_TIP_HPP_INCLUDED
#include <string>
class CVideo;
class t_string;
namespace gui2 {
class tpoint;
namespace tip {
/**
* Shows a tip.
*
* The tip is a tooltip or a helptip. One type of tip is shown at the same
* time, opening a second tip closes the first.
*
* @param video The video which contains the surface to draw
* upon.
* @param window_id The id of the window used to show the tip.
* @param message The message to show in the tip.
* @param mouse The position of the mouse.
*/
void show(CVideo& video
, const std::string& window_id
, const t_string& message
, const tpoint& mouse);
/**
* Removes a tip.
*
* It is safe to call this function when no tip is shown.
* */
void remove();
} // namespace tip
} // namespace gui2
#endif

View file

@ -32,6 +32,7 @@
#include "gui/auxiliary/layout_exception.hpp"
#include "gui/auxiliary/window_builder/control.hpp"
#include "gui/dialogs/title_screen.hpp"
#include "gui/dialogs/tip.hpp"
#include "gui/widgets/button.hpp"
#include "gui/widgets/settings.hpp"
#ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
@ -247,9 +248,11 @@ twindow::twindow(CVideo& video,
, cursor::setter(cursor::NORMAL)
, video_(video)
, status_(NEW)
, show_mode_(none)
, retval_(NONE)
, owner_(0)
, need_layout_(true)
, variables_()
, invalidate_layout_blocked_(false)
, suspend_drawing_(true)
, restorer_()
@ -340,6 +343,17 @@ twindow::~twindow()
}
}
/*
* The tip needs to be closed if the window closes and the window is
* not a tip. If we don't do that the tip will unrender in the next
* window and cause drawing glitches.
* Another issue is that on smallgui and an MP game the tooltip not
* unrendered properly can capture the mouse and make playing impossible.
*/
if(show_mode_ == modal) {
tip::remove();
}
tmanager::instance().remove(*this);
#ifdef DEBUG_WINDOW_LAYOUT_GRAPHS
@ -449,6 +463,8 @@ void twindow::show_tooltip(/*const unsigned auto_close_timeout*/)
assert(status_ == NEW);
show_mode_ = tooltip;
/*
* Before show has been called, some functions might have done some testing
* on the window and called layout, which can give glitches. So
@ -456,10 +472,19 @@ void twindow::show_tooltip(/*const unsigned auto_close_timeout*/)
*/
invalidate_layout();
suspend_drawing_ = false;
}
int twindow::show(const bool restore, const unsigned auto_close_timeout)
{
/*
* Removes the old tip if one shown. The show_tip doesn't remove
* the tip, since it's the tip.
*/
tip::remove();
show_mode_ = modal;
/**
* Helper class to set and restore the drawing interval.
*
@ -734,6 +759,17 @@ void twindow::draw()
update_rect(rect);
}
void twindow::undraw()
{
if(restorer_) {
SDL_Rect rect = get_rect();
sdl_blit(restorer_, 0, video_.getSurface(), &rect);
// Since the old area might be bigger as the new one, invalidate
// it.
update_rect(rect);
}
}
twindow::tinvalidate_layout_blocker::tinvalidate_layout_blocker(twindow& window)
: window_(window)
{
@ -809,20 +845,19 @@ void twindow::layout()
log_scope2(log_gui_layout, LOG_SCOPE_HEADER);
const game_logic::map_formula_callable variables =
get_screen_size_variables();
get_screen_size_variables(variables_);
const int maximum_width = automatic_placement_
? maximum_width_
? std::min(maximum_width_, settings::screen_width)
: settings::screen_width
: w_(variables);
: w_(variables_);
const int maximum_height = automatic_placement_
? maximum_height_
? std::min(maximum_height_, settings::screen_height)
: settings::screen_height
: h_(variables);
: h_(variables_);
/***** Handle click dismiss status. *****/
tbutton* click_dismiss_button = NULL;
@ -937,11 +972,11 @@ void twindow::layout()
assert(false);
}
} else {
origin.x = x_(variables);
origin.y = y_(variables);
origin.x = x_(variables_);
origin.y = y_(variables_);
size.x = w_(variables);
size.y = h_(variables);
size.x = w_(variables_);
size.y = h_(variables_);
}
/***** Set the window size *****/
@ -995,59 +1030,13 @@ void twindow::do_show_tooltip(const tpoint& location, const t_string& tooltip)
{
DBG_GUI_G << LOG_HEADER << " message: '" << tooltip << "'.\n";
assert(!tooltip.empty());
twidget* widget = find_at(location, true);
assert(widget);
#if 0
const SDL_Rect widget_rect = widget->get_rect();
const SDL_Rect client_rect = get_client_rect();
#endif
tooltip_.set_label(tooltip);
const tpoint size = tooltip_.get_best_size();
SDL_Rect tooltip_rect = ::create_rect(
(settings::screen_width - size.x) / 2
, settings::screen_height - size.y
, size.x
, size.y);
#if 0
// Find the best position to place the widget
if(widget_rect.y - size.y > 0) {
// put above
tooltip_rect.y = widget_rect.y - size.y;
} else {
//put below no test
tooltip_rect.y = widget_rect.y + widget_rect.h;
}
if(widget_rect.x + size.x < client_rect.w) {
// Directly above the mouse
tooltip_rect.x = widget_rect.x;
} else {
// shift left, no test
tooltip_rect.x = client_rect.w - size.x;
}
#endif
tooltip_.place(
tpoint(tooltip_rect.x, tooltip_rect.y),
tpoint(tooltip_rect.w, tooltip_rect.h));
tooltip_.set_visible(twidget::VISIBLE);
tooltip_restorer_= get_surface_portion(video_.getSurface(), tooltip_rect);
/** @todo Make not hard coded. */
tip::show(video_, "tooltip_large", tooltip, location);
}
void twindow::do_remove_tooltip()
{
SDL_Rect rect = tooltip_.get_rect();
sdl_blit(tooltip_restorer_, 0, video_.getSurface(), &rect);
update_rect(tooltip_.get_rect());
tooltip_.set_visible(twidget::HIDDEN);
tip::remove();
}
void twindow::do_show_help_popup(const tpoint& location, const t_string& help_popup)

View file

@ -167,6 +167,11 @@ public:
*/
void draw();
/**
* Undraws the window.
*/
void undraw();
/**
* Adds an item to the dirty_list_.
*
@ -378,6 +383,12 @@ public:
bool get_need_layout() const { return need_layout_; }
void set_variable(const std::string& key, const variant& value)
{
variables_.add(key, value);
set_dirty();
}
private:
/** Needed so we can change what's drawn on the screen. */
@ -386,6 +397,19 @@ private:
/** The status of the window. */
tstatus status_;
enum tshow_mode {
none
, modal
, tooltip
};
/**
* The mode in which the window is shown.
*
* This is used to determine whether or not to remove the tip.
*/
tshow_mode show_mode_;
// return value of the window, 0 default.
int retval_;
@ -400,6 +424,9 @@ private:
*/
bool need_layout_;
/** The variables of the canvas. */
game_logic::map_formula_callable variables_;
/** Is invalidate layout blocked see tinvalidate_layout_blocker. */
bool invalidate_layout_blocked_;