Removed a whole bunch of GUI1 stuff

This almost completely removes GUI1, save for the button widget (will remove once I get
all the Theme handling sorted out) and the editor's own GUI1 widgets.

This includes the GUI1 textbox, scrollbar, scrollarea, and menu widgets, as well as the
dialog_frame and dialog_manager classes. I've also removed floating_textbox. It was only
kept around for reference (it's unused as of the inclusion of the GUI2 command console).

gui::in_dialog has been replaced by GUI2's is_in_dialog directly now that we have no more
GUI1 dialogs.

\o/
This commit is contained in:
Charles Dang 2018-03-20 21:07:59 +11:00
parent 6ea405174e
commit 28d2be4bec
22 changed files with 3 additions and 4166 deletions

View file

@ -997,7 +997,6 @@
<ClCompile Include="..\..\src\fake_unit_ptr.cpp" />
<ClCompile Include="..\..\src\filesystem_sdl.cpp" />
<ClCompile Include="..\..\src\floating_label.cpp" />
<ClCompile Include="..\..\src\floating_textbox.cpp" />
<ClCompile Include="..\..\src\font\font_config.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Font\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Font\</ObjectFileName>
@ -2835,7 +2834,6 @@
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Serialization\</ObjectFileName>
</ClCompile>
<ClCompile Include="..\..\src\settings.cpp" />
<ClCompile Include="..\..\src\show_dialog.cpp" />
<ClCompile Include="..\..\src\side_filter.cpp" />
<ClCompile Include="..\..\src\sound.cpp" />
<ClCompile Include="..\..\src\soundsource.cpp" />
@ -3466,41 +3464,6 @@
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Widgets\</ObjectFileName>
</ClCompile>
<ClCompile Include="..\..\src\widgets\menu.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Widgets\</ObjectFileName>
</ClCompile>
<ClCompile Include="..\..\src\widgets\menu_style.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Widgets\</ObjectFileName>
</ClCompile>
<ClCompile Include="..\..\src\widgets\scrollarea.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Widgets\</ObjectFileName>
</ClCompile>
<ClCompile Include="..\..\src\widgets\scrollbar.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Widgets\</ObjectFileName>
</ClCompile>
<ClCompile Include="..\..\src\widgets\textbox.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Debug|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Test_Release|Win32'">$(IntDir)Widgets\</ObjectFileName>
</ClCompile>
<ClCompile Include="..\..\src\widgets\widget.cpp">
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(IntDir)Widgets\</ObjectFileName>
<ObjectFileName Condition="'$(Configuration)|$(Platform)'=='ReleaseDEBUG|Win32'">$(IntDir)Widgets\</ObjectFileName>
@ -3640,7 +3603,6 @@
<ClInclude Include="..\..\src\fake_unit_ptr.hpp" />
<ClInclude Include="..\..\src\filesystem.hpp" />
<ClInclude Include="..\..\src\floating_label.hpp" />
<ClInclude Include="..\..\src\floating_textbox.hpp" />
<ClInclude Include="..\..\src\font\error.hpp" />
<ClInclude Include="..\..\src\font\font_config.hpp" />
<ClInclude Include="..\..\src\font\font_description.hpp" />
@ -3997,7 +3959,6 @@
<ClInclude Include="..\..\src\sdl\window.hpp" />
<ClInclude Include="..\..\src\seed_rng.hpp" />
<ClInclude Include="..\..\src\settings.hpp" />
<ClInclude Include="..\..\src\show_dialog.hpp" />
<ClInclude Include="..\..\src\side_filter.hpp" />
<ClInclude Include="..\..\src\sound.hpp" />
<ClInclude Include="..\..\src\soundsource.hpp" />
@ -4106,10 +4067,6 @@
<ClInclude Include="..\..\src\whiteboard\utility.hpp" />
<ClInclude Include="..\..\src\whiteboard\visitor.hpp" />
<ClInclude Include="..\..\src\widgets\button.hpp" />
<ClInclude Include="..\..\src\widgets\menu.hpp" />
<ClInclude Include="..\..\src\widgets\scrollarea.hpp" />
<ClInclude Include="..\..\src\widgets\scrollbar.hpp" />
<ClInclude Include="..\..\src\widgets\textbox.hpp" />
<ClInclude Include="..\..\src\widgets\widget.hpp" />
<ClInclude Include="..\..\src\wml_exception.hpp" />
<ClInclude Include="..\..\src\wml_separators.hpp" />

View file

@ -989,21 +989,6 @@
<ClCompile Include="..\..\src\widgets\button.cpp">
<Filter>Widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\src\widgets\menu.cpp">
<Filter>Widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\src\widgets\menu_style.cpp">
<Filter>Widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\src\widgets\scrollarea.cpp">
<Filter>Widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\src\widgets\scrollbar.cpp">
<Filter>Widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\src\widgets\textbox.cpp">
<Filter>Widgets</Filter>
</ClCompile>
<ClCompile Include="..\..\src\widgets\widget.cpp">
<Filter>Widgets</Filter>
</ClCompile>
@ -1442,7 +1427,6 @@
<ClCompile Include="..\..\src\fake_unit_ptr.cpp" />
<ClCompile Include="..\..\src\filesystem_sdl.cpp" />
<ClCompile Include="..\..\src\floating_label.cpp" />
<ClCompile Include="..\..\src\floating_textbox.cpp" />
<ClCompile Include="..\..\src\format_time_summary.cpp" />
<ClCompile Include="..\..\src\game_board.cpp" />
<ClCompile Include="..\..\src\game_classification.cpp" />
@ -1495,7 +1479,6 @@
<ClCompile Include="..\..\src\savegame.cpp" />
<ClCompile Include="..\..\src\seed_rng.cpp" />
<ClCompile Include="..\..\src\settings.cpp" />
<ClCompile Include="..\..\src\show_dialog.cpp" />
<ClCompile Include="..\..\src\side_filter.cpp" />
<ClCompile Include="..\..\src\sound.cpp" />
<ClCompile Include="..\..\src\sound_music_track.cpp" />
@ -2474,18 +2457,6 @@
<ClInclude Include="..\..\src\widgets\button.hpp">
<Filter>Widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\src\widgets\menu.hpp">
<Filter>Widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\src\widgets\scrollarea.hpp">
<Filter>Widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\src\widgets\scrollbar.hpp">
<Filter>Widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\src\widgets\textbox.hpp">
<Filter>Widgets</Filter>
</ClInclude>
<ClInclude Include="..\..\src\widgets\widget.hpp">
<Filter>Widgets</Filter>
</ClInclude>
@ -2878,7 +2849,6 @@
<ClInclude Include="..\..\src\fake_unit_ptr.hpp" />
<ClInclude Include="..\..\src\filesystem.hpp" />
<ClInclude Include="..\..\src\floating_label.hpp" />
<ClInclude Include="..\..\src\floating_textbox.hpp" />
<ClInclude Include="..\..\src\format_time_summary.hpp" />
<ClInclude Include="..\..\src\formatter.hpp" />
<ClInclude Include="..\..\src\game_board.hpp" />
@ -2938,7 +2908,6 @@
<ClInclude Include="..\..\src\savegame_config.hpp" />
<ClInclude Include="..\..\src\seed_rng.hpp" />
<ClInclude Include="..\..\src\settings.hpp" />
<ClInclude Include="..\..\src\show_dialog.hpp" />
<ClInclude Include="..\..\src\side_filter.hpp" />
<ClInclude Include="..\..\src\sound.hpp" />
<ClInclude Include="..\..\src\sound_music_track.hpp" />

View file

@ -42,7 +42,6 @@ pathfind/astarsearch.cpp
pathutils.cpp
quit_confirmation.cpp
reports.cpp
show_dialog.cpp
sound.cpp
sound_music_track.cpp
soundsource.cpp
@ -55,10 +54,5 @@ tooltips.cpp
utils/make_enum.cpp
video.cpp
widgets/button.cpp
widgets/menu.cpp
widgets/menu_style.cpp
widgets/scrollarea.cpp
widgets/scrollbar.cpp
widgets/textbox.cpp
widgets/widget.cpp
wml_exception.cpp

View file

@ -102,7 +102,6 @@ editor/toolkit/editor_toolkit.cpp
fake_unit_manager.cpp
fake_unit_ptr.cpp
filesystem_sdl.cpp
floating_textbox.cpp
formula/callable_objects.cpp
formula/debugger.cpp
formula/debugger_fwd.cpp

View file

@ -17,6 +17,7 @@
#include "display.hpp"
#include "events.hpp"
#include "gui/core/event/handler.hpp" // gui2::is_in_dialog
#include "gui/dialogs/loading_screen.hpp"
#include "hotkey/command_executor.hpp"
#include "hotkey/hotkey_command.hpp"
@ -25,7 +26,6 @@
#include "mouse_handler_base.hpp"
#include "preferences/game.hpp"
#include "scripting/plugins/context.hpp"
#include "show_dialog.hpp" //gui::in_dialog
#include "soundsource.hpp"
static lg::log_domain log_display("display");
@ -57,7 +57,7 @@ void controller_base::handle_event(const SDL_Event& event)
* first. have_keyboard_focus currently returns false if a dialog open, but this is just as stopgap
* measure. We need to figure out a better way to filter out events.
*/
//if(gui::in_dialog()) {
//if(gui2::is_in_dialog()) {
// return;
//}
@ -163,7 +163,7 @@ void controller_base::keyup_listener::handle_event(const SDL_Event& event)
bool controller_base::have_keyboard_focus()
{
return !gui::in_dialog();
return !gui2::is_in_dialog();
}
bool controller_base::handle_scroll(int mousex, int mousey, int mouse_flags, double x_axis, double y_axis)

View file

@ -49,7 +49,6 @@
#include "units/animation_component.hpp"
#include "units/drawer.hpp"
#include "whiteboard/manager.hpp"
#include "show_dialog.hpp"
#include "gui/dialogs/loading_screen.hpp"
#include "sdl/render_utils.hpp"
#include "sdl/texture.hpp"

View file

@ -1,145 +0,0 @@
/*
Copyright (C) 2006 - 2018 by Joerg Hinrichs <joerg.hinrichs@alice-dsl.de>
wesnoth playturn Copyright (C) 2003 by David White <dave@whitevine.net>
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.
*/
#include "floating_textbox.hpp"
#include "display_chat_manager.hpp"
#include "floating_label.hpp"
#include "font/standard_colors.hpp"
#include "game_display.hpp"
#include "preferences/game.hpp"
#include "log.hpp"
#include <ctime>
static lg::log_domain log_display("display");
#define ERR_DP LOG_STREAM(err, log_display)
namespace gui{
floating_textbox::floating_textbox() :
box_(nullptr),
check_(nullptr),
mode_(TEXTBOX_NONE),
label_string_(),
label_(0)
{}
void floating_textbox::close(game_display& /*gui*/)
{
if(!active()) {
return;
}
if(check_ != nullptr) {
if(mode_ == TEXTBOX_MESSAGE) {
preferences::set_message_private(check_->checked());
}
}
box_.reset(nullptr);
check_.reset(nullptr);
font::remove_floating_label(label_);
mode_ = TEXTBOX_NONE;
}
void floating_textbox::update_location(game_display& gui)
{
if (box_ == nullptr)
return;
const SDL_Rect& area = gui.map_outside_area();
const int border_size = 10;
const int ypos = area.y+area.h-30 - (check_ != nullptr ? check_->height() + border_size : 0);
if (label_ != 0)
font::remove_floating_label(label_);
font::floating_label flabel(label_string_);
flabel.set_color(font::YELLOW_COLOR);
flabel.set_position(area.x + border_size, ypos);
flabel.set_alignment(font::LEFT_ALIGN);
flabel.set_clip_rect(area);
label_ = font::add_floating_label(flabel);
if (label_ == 0)
return;
const SDL_Rect& label_area = font::get_floating_label_rect(label_);
const int textbox_width = area.w - label_area.w - border_size*3;
if(textbox_width <= 0) {
font::remove_floating_label(label_);
return;
}
if(box_ != nullptr) {
box_->set_volatile(true);
const SDL_Rect rect {
area.x + label_area.w + border_size * 2
, ypos
, textbox_width
, box_->height()
};
box_->set_location(rect);
}
if(check_ != nullptr) {
check_->set_volatile(true);
check_->set_location(box_->location().x,box_->location().y + box_->location().h + border_size);
}
}
void floating_textbox::show(gui::TEXTBOX_MODE mode, const std::string& label,
const std::string& check_label, bool checked, game_display& gui)
{
close(gui);
label_string_ = label;
mode_ = mode;
if(!check_label.empty()) {
check_.reset(new gui::button(gui.video(),check_label,gui::button::TYPE_CHECK));
check_->set_check(checked);
}
box_.reset(new gui::textbox(gui.video(),100,"",true,256,font::SIZE_PLUS,0.8,0.6));
update_location(gui);
}
void floating_textbox::tab(const std::set<std::string>& dictionary)
{
if(active() == false) {
return;
}
std::string text = box_->text();
std::vector<std::string> matches(dictionary.begin(), dictionary.end());
const bool line_start = utils::word_completion(text, matches);
if (matches.empty()) return;
if (matches.size() == 1 && mode_ == gui::TEXTBOX_MESSAGE) {
text.append(line_start ? ": " : " ");
} else if (matches.size() > 1) {
std::string completion_list = utils::join(matches, " ");
game_display::get_singleton()->get_chat_manager().add_chat_message(time(nullptr), "", 0, completion_list,
events::chat_handler::MESSAGE_PRIVATE, false);
}
box_->set_text(text);
}
}

View file

@ -1,57 +0,0 @@
/*
Copyright (C) 2006 - 2018 by Joerg Hinrichs <joerg.hinrichs@alice-dsl.de>
wesnoth playturn Copyright (C) 2003 by David White <dave@whitevine.net>
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.
*/
#pragma once
// Scoped_resource can't use a pointer to an incomplete pointer with MSVC.
#include "widgets/textbox.hpp"
#include <memory>
#include <set>
class game_display;
namespace gui{
class button;
enum TEXTBOX_MODE { TEXTBOX_NONE, TEXTBOX_SEARCH, TEXTBOX_MESSAGE,
TEXTBOX_COMMAND, TEXTBOX_AI };
class floating_textbox{
public:
floating_textbox();
TEXTBOX_MODE mode() const { return mode_; }
const std::unique_ptr<gui::button>& check() const { return check_; }
const std::unique_ptr<gui::textbox>& box() const { return box_; }
void close(game_display& gui);
void update_location(game_display& gui);
void show(gui::TEXTBOX_MODE mode, const std::string& label,
const std::string& check_label, bool checked, game_display& gui);
void tab(const std::set<std::string>& dictionary);
bool active() const { return box_.get() != nullptr; }
private:
std::unique_ptr<gui::textbox> box_;
std::unique_ptr<gui::button> check_;
TEXTBOX_MODE mode_;
std::string label_string_;
int label_;
};
}

View file

@ -33,7 +33,6 @@
#include "key.hpp" // for CKey
#include "log.hpp" // for LOG_STREAM, log_domain
#include "sdl/surface.hpp" // for surface
#include "show_dialog.hpp" // for dialog_frame, etc
#include "terrain/terrain.hpp" // for terrain_type
#include "units/unit.hpp" // for unit
#include "units/types.hpp" // for unit_type, unit_type_data, etc

View file

@ -29,7 +29,6 @@
#include "display.hpp"
#include "quit_confirmation.hpp"
#include "sdl/surface.hpp"
#include "show_dialog.hpp"
#include "../resources.hpp"
#include "../playmp_controller.hpp"

View file

@ -52,7 +52,6 @@
#include "save_blocker.hpp"
#include "scripting/game_lua_kernel.hpp"
#include "scripting/plugins/context.hpp"
#include "show_dialog.hpp" //gui::in_dialog
#include "sound.hpp"
#include "soundsource.hpp"
#include "statistics.hpp"

View file

@ -1,364 +0,0 @@
/*
Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
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 "show_dialog.hpp"
#include "floating_label.hpp"
#include "font/sdl_ttf.hpp"
#include "image.hpp"
#include "gettext.hpp"
#include "gui/core/event/handler.hpp"
#include "help/help.hpp"
#include "hotkey/command_executor.hpp"
#include "log.hpp"
#include "font/marked-up_text.hpp"
#include "font/standard_colors.hpp"
#include "sdl/rect.hpp"
static lg::log_domain log_display("display");
#define ERR_DP LOG_STREAM(err, log_display)
#define ERR_G LOG_STREAM(err, lg::general)
namespace {
bool is_in_dialog = false;
}
namespace gui {
//static initialization
const int ButtonHPadding = 10;
const int ButtonVPadding = 10;
//note: style names are directly related to the panel image file names
const dialog_frame::style dialog_frame::default_style("opaque", 0);
const dialog_frame::style dialog_frame::message_style("translucent65", 3);
const dialog_frame::style dialog_frame::preview_style("../dialogs/selection", 0);
const dialog_frame::style dialog_frame::titlescreen_style("translucent54", 1);
const int dialog_frame::title_border_w = 10;
const int dialog_frame::title_border_h = 5;
bool in_dialog()
{
return is_in_dialog || gui2::is_in_dialog();
}
dialog_manager::dialog_manager() : cursor::setter(cursor::NORMAL), reset_to(is_in_dialog)
{
is_in_dialog = true;
}
dialog_manager::~dialog_manager()
{
is_in_dialog = reset_to;
int mousex, mousey;
SDL_GetMouseState(&mousex, &mousey);
SDL_Event pb_event;
pb_event.type = SDL_MOUSEMOTION;
pb_event.motion.state = 0;
pb_event.motion.x = mousex;
pb_event.motion.y = mousey;
pb_event.motion.xrel = 0;
pb_event.motion.yrel = 0;
SDL_PushEvent(&pb_event);
}
dialog_frame::dialog_frame(CVideo& video, const std::string& title,
const style& style, bool auto_restore,
std::vector<button*>* buttons, button* help_button) :
title_(title),
video_(video),
dialog_style_(style),
buttons_(buttons),
help_button_(help_button),
restorer_(nullptr),
auto_restore_(auto_restore),
dim_(),
top_(image::get_image("dialogs/" + dialog_style_.panel + "-border-top.png")),
bot_(image::get_image("dialogs/" + dialog_style_.panel + "-border-bottom.png")),
left_(image::get_image("dialogs/" + dialog_style_.panel + "-border-left.png")),
right_(image::get_image("dialogs/" + dialog_style_.panel + "-border-right.png")),
top_left_(image::get_image("dialogs/" + dialog_style_.panel + "-border-topleft.png")),
bot_left_(image::get_image("dialogs/" + dialog_style_.panel + "-border-botleft.png")),
top_right_(image::get_image("dialogs/" + dialog_style_.panel + "-border-topright.png")),
bot_right_(image::get_image("dialogs/" + dialog_style_.panel + "-border-botright.png")),
bg_(image::get_image("dialogs/" + dialog_style_.panel + "-background.png")),
have_border_(top_ != nullptr && bot_ != nullptr && left_ != nullptr && right_ != nullptr),
dirty_(true)
{
}
dialog_frame::~dialog_frame()
{
delete restorer_;
}
dialog_frame::dimension_measurements::dimension_measurements() :
interior(sdl::empty_rect), exterior(sdl::empty_rect), title(sdl::empty_rect), button_row(sdl::empty_rect)
{}
dialog_frame::dimension_measurements dialog_frame::layout(const SDL_Rect& rect) {
return layout(rect.x, rect.y, rect.w, rect.h);
}
int dialog_frame::top_padding() const {
int padding = 0;
if(have_border_) {
padding += top_->h;
}
if(!title_.empty()) {
padding += font::get_max_height(font::SIZE_TITLE) + 2*dialog_frame::title_border_h;
}
return padding;
}
void dialog_frame::set_dirty(bool dirty) {
dirty_ = dirty;
}
void dialog_frame::handle_window_event(const SDL_Event& event) {
if (event.type == SDL_WINDOWEVENT) {
switch (event.window.event) {
case SDL_WINDOWEVENT_RESIZED:
case SDL_WINDOWEVENT_RESTORED:
case SDL_WINDOWEVENT_SHOWN:
case SDL_WINDOWEVENT_EXPOSED:
set_dirty();
}
}
}
void dialog_frame::handle_event(const SDL_Event& /*event*/) {
#if 0
if (event.type == DRAW_ALL_EVENT) {
set_dirty();
if (buttons_) {
for(std::vector<button *>::iterator it = buttons_->begin(); it != buttons_->end(); ++it) {
(*it)->set_dirty(true);
}
}
}
#endif
}
int dialog_frame::bottom_padding() const {
int padding = 0;
if(buttons_ != nullptr) {
for(std::vector<button*>::const_iterator b = buttons_->begin(); b != buttons_->end(); ++b) {
padding = std::max<int>((**b).height() + ButtonVPadding, padding);
}
}
if(have_border_) {
padding += bot_->h;
}
return padding;
}
dialog_frame::dimension_measurements dialog_frame::layout(int x, int y, int w, int h) {
dim_ = dimension_measurements();
if(!title_.empty()) {
dim_.title = draw_title(nullptr);
dim_.title.w += title_border_w;
}
if(buttons_ != nullptr) {
for(std::vector<button*>::const_iterator b = buttons_->begin(); b != buttons_->end(); ++b) {
dim_.button_row.w += (**b).width() + ButtonHPadding;
dim_.button_row.h = std::max<int>((**b).height() + ButtonVPadding,dim_.button_row.h);
}
dim_.button_row.x = -dim_.button_row.w;
dim_.button_row.y = y + h;
dim_.button_row.w += ButtonHPadding;
}
std::size_t buttons_width = dim_.button_row.w;
if(help_button_ != nullptr) {
buttons_width += help_button_->width() + ButtonHPadding*2;
dim_.button_row.y = y + h;
}
y -= dim_.title.h;
w = std::max(w, std::max(dim_.title.w, static_cast<int>(buttons_width)));
h += dim_.title.h + dim_.button_row.h;
dim_.button_row.x += x + w;
SDL_Rect bounds = video_.screen_area();
if(have_border_) {
bounds.x += left_->w;
bounds.y += top_->h;
bounds.w -= left_->w;
bounds.h -= top_->h;
}
if(x < bounds.x) {
w += x;
x = bounds.x;
}
if(y < bounds.y) {
h += y;
y = bounds.y;
}
if(x > bounds.w) {
w = 0;
} else if(x + w > bounds.w) {
w = bounds.w - x;
}
if(y > bounds.h) {
h = 0;
} else if(y + h > bounds.h) {
h = bounds.h - y;
}
dim_.interior.x = x;
dim_.interior.y = y;
dim_.interior.w = w;
dim_.interior.h = h;
if(have_border_) {
dim_.exterior.x = dim_.interior.x - left_->w;
dim_.exterior.y = dim_.interior.y - top_->h;
dim_.exterior.w = dim_.interior.w + left_->w + right_->w;
dim_.exterior.h = dim_.interior.h + top_->h + bot_->h;
} else {
dim_.exterior = dim_.interior;
}
dim_.title.x = dim_.interior.x + title_border_w;
dim_.title.y = dim_.interior.y + title_border_h;
return dim_;
}
void dialog_frame::draw_border()
{
if(have_border_ == false) {
return;
}
surface top_image(scale_surface(top_, dim_.interior.w, top_->h));
if(top_image != nullptr) {
video_.blit_surface(dim_.interior.x, dim_.exterior.y, top_image);
}
surface bot_image(scale_surface(bot_, dim_.interior.w, bot_->h));
if(bot_image != nullptr) {
video_.blit_surface(dim_.interior.x, dim_.interior.y + dim_.interior.h, bot_image);
}
surface left_image(scale_surface(left_, left_->w, dim_.interior.h));
if(left_image != nullptr) {
video_.blit_surface(dim_.exterior.x, dim_.interior.y, left_image);
}
surface right_image(scale_surface(right_, right_->w, dim_.interior.h));
if(right_image != nullptr) {
video_.blit_surface(dim_.interior.x + dim_.interior.w, dim_.interior.y, right_image);
}
if(top_left_ == nullptr || bot_left_ == nullptr || top_right_ == nullptr || bot_right_ == nullptr) {
return;
}
video_.blit_surface(dim_.interior.x - left_->w, dim_.interior.y - top_->h, top_left_);
video_.blit_surface(dim_.interior.x - left_->w, dim_.interior.y + dim_.interior.h + bot_->h - bot_left_->h, bot_left_);
video_.blit_surface(dim_.interior.x + dim_.interior.w + right_->w - top_right_->w, dim_.interior.y - top_->h, top_right_);
video_.blit_surface(dim_.interior.x + dim_.interior.w + right_->w - bot_right_->w, dim_.interior.y + dim_.interior.h + bot_->h - bot_right_->h, bot_right_);
}
void dialog_frame::clear_background()
{
delete restorer_;
restorer_ = nullptr;
}
void dialog_frame::draw_background()
{
if(auto_restore_) {
clear_background();
restorer_ = new surface_restorer(&video_, dim_.exterior);
}
if (dialog_style_.blur_radius) {
surface surf = ::get_surface_portion(video_.getSurface(), dim_.exterior);
surf = blur_surface(surf, dialog_style_.blur_radius);
sdl_blit(surf, nullptr, video_.getSurface(), &dim_.exterior);
}
if(bg_ == nullptr) {
ERR_DP << "could not find dialog background '" << dialog_style_.panel << "'" << std::endl;
return;
}
for(int i = 0; i < dim_.interior.w; i += bg_->w) {
for(int j = 0; j < dim_.interior.h; j += bg_->h) {
SDL_Rect src {0,0,0,0};
src.w = std::min(dim_.interior.w - i, bg_->w);
src.h = std::min(dim_.interior.h - j, bg_->h);
SDL_Rect dst = src;
dst.x = dim_.interior.x + i;
dst.y = dim_.interior.y + j;
sdl_blit(bg_, &src, video_.getSurface(), &dst);
}
}
}
SDL_Rect dialog_frame::draw_title(CVideo* video)
{
SDL_Rect rect = video->screen_area();
return font::draw_text(video, rect, font::SIZE_TITLE, font::TITLE_COLOR,
title_, dim_.title.x, dim_.title.y, false, TTF_STYLE_NORMAL);
}
void dialog_frame::draw()
{
if (!dirty_)
return;
//draw background
draw_background();
//draw frame border
draw_border();
//draw title
if (!title_.empty()) {
draw_title(&video_);
}
//draw buttons
SDL_Rect buttons_area = dim_.button_row;
if(buttons_ != nullptr) {
#ifdef OK_BUTTON_ON_RIGHT
std::reverse(buttons_->begin(),buttons_->end());
#endif
for(std::vector<button*>::const_iterator b = buttons_->begin(); b != buttons_->end(); ++b) {
(**b).set_location(buttons_area.x, buttons_area.y);
buttons_area.x += (**b).width() + ButtonHPadding;
}
}
if(help_button_ != nullptr) {
help_button_->set_location(dim_.interior.x+ButtonHPadding, buttons_area.y);
}
dirty_ = false;
}
}

View file

@ -1,115 +0,0 @@
/*
Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
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.
*/
#pragma once
class surface;
#include "cursor.hpp"
#include "floating_label.hpp"
#include "tooltips.hpp"
#include "video.hpp"
#include "widgets/button.hpp"
namespace gui
{
extern const int ButtonHPadding;
extern const int ButtonVPadding;
enum DIALOG_RESULT {
DIALOG_BACK=-7,
DIALOG_FORWARD=-6,
CREATE_ITEM =-5,
DELETE_ITEM=-4,
ESCAPE_DIALOG=-3, //special return used by WML event dialogs
CONTINUE_DIALOG=-2,
CLOSE_DIALOG=-1
/* results (0..N) reserved for standard button indices */
};
bool in_dialog();
struct dialog_manager : private cursor::setter, private font::floating_label_context {
dialog_manager();
~dialog_manager();
private:
bool reset_to;
};
class dialog_frame :public events::sdl_handler {
public:
struct dimension_measurements {
dimension_measurements();
SDL_Rect interior, exterior, title, button_row;
};
class style {
public:
style(const std::string& p, int br) : panel(p), blur_radius(br) {}
std::string panel;
int blur_radius;
};
//Static members
static const int title_border_w, title_border_h;
static const style default_style;
static const style message_style;
static const style preview_style;
static const style titlescreen_style;
dialog_frame(CVideo &video, const std::string& title="",
const style& dialog_style=default_style,
bool auto_restore=true, std::vector<button*>* buttons=nullptr,
button* help_button=nullptr);
~dialog_frame();
dimension_measurements layout(int x, int y, int w, int h);
dimension_measurements layout(const SDL_Rect& frame_area);
void set_layout(dimension_measurements &new_dim) { dim_ = new_dim; }
dimension_measurements get_layout() const { return dim_; }
int top_padding() const;
int bottom_padding() const;
void draw();
//called by draw
void draw_border();
void draw_background();
//also called by layout with null param
SDL_Rect draw_title(CVideo *video);
void set_dirty(bool dirty = true);
virtual void handle_event(const SDL_Event&);
void handle_window_event(const SDL_Event& event);
private:
void clear_background();
std::string title_;
CVideo &video_;
const style& dialog_style_;
std::vector<button*>* buttons_;
button* help_button_;
surface_restorer* restorer_;
bool auto_restore_;
dimension_measurements dim_;
surface top_, bot_, left_, right_, top_left_, bot_left_, top_right_, bot_right_, bg_;
bool have_border_;
bool dirty_;
};
}

File diff suppressed because it is too large Load diff

View file

@ -1,317 +0,0 @@
/*
Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
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.
*/
#pragma once
#include <map>
#include <set>
#include "scrollarea.hpp"
namespace image{
class locator;
}
namespace gui {
class menu : public scrollarea
{
public:
enum ROW_TYPE { NORMAL_ROW, SELECTED_ROW, HEADING_ROW };
//basic menu style
class style
{
public:
style();
virtual ~style();
virtual void init() {}
virtual SDL_Rect item_size(const std::string& item) const;
virtual void draw_row_bg(menu& menu_ref, const std::size_t row_index, const SDL_Rect& rect, ROW_TYPE type);
virtual void draw_row(menu& menu_ref, const std::size_t row_index, const SDL_Rect& rect, ROW_TYPE type);
void scale_images(int max_width, int max_height);
surface get_item_image(const image::locator &i_locator) const;
std::size_t get_font_size() const;
std::size_t get_cell_padding() const;
std::size_t get_thickness() const;
protected:
std::size_t font_size_;
std::size_t cell_padding_;
std::size_t thickness_; //additional cell padding for style use only
int normal_rgb_, selected_rgb_, heading_rgb_;
double normal_alpha_, selected_alpha_, heading_alpha_;
int max_img_w_, max_img_h_;
};
//image-border selection style
class imgsel_style : public style
{
public:
imgsel_style(const std::string &img_base, bool has_bg,
int normal_rgb, int selected_rgb, int heading_rgb,
double normal_alpha, double selected_alpha, double heading_alpha);
virtual ~imgsel_style();
virtual SDL_Rect item_size(const std::string& item) const;
virtual void draw_row_bg(menu& menu_ref, const std::size_t row_index, const SDL_Rect& rect, ROW_TYPE type);
virtual void draw_row(menu& menu_ref, const std::size_t row_index, const SDL_Rect& rect, ROW_TYPE type);
virtual void init() { load_images(); }
bool load_images();
protected:
const std::string img_base_;
std::map<std::string,surface> img_map_;
private:
bool load_image(const std::string &img_sub);
bool has_background_;
bool initialized_;
bool load_failed_;
int normal_rgb2_, selected_rgb2_, heading_rgb2_;
double normal_alpha2_, selected_alpha2_, heading_alpha2_;
//FIXME: why is this better than a plain surface?
struct bg_cache
{
bg_cache() : surf(), width(-1), height(-1)
{}
surface surf;
int width, height;
};
bg_cache bg_cache_;
};
friend class style;
friend class imgsel_style;
static style &default_style;
static style simple_style;
static imgsel_style bluebg_style;
struct item
{
item() : fields(), help(), id(0)
{}
item(const std::vector<std::string>& fields, std::size_t id)
: fields(fields), help(), id(id)
{}
std::vector<std::string> fields;
std::vector<std::string> help;
std::size_t id;
};
class sorter
{
public:
virtual ~sorter() {}
virtual bool column_sortable(int column) const = 0;
virtual bool less(int column, const item& row1, const item& row2) const = 0;
};
class basic_sorter : public sorter
{
public:
basic_sorter();
virtual ~basic_sorter() {}
basic_sorter& set_alpha_sort(int column);
basic_sorter& set_numeric_sort(int column);
basic_sorter& set_xp_sort(int column);
basic_sorter& set_level_sort(int level_column, int xp_column);
basic_sorter& set_id_sort(int column);
basic_sorter& set_redirect_sort(int column, int to);
basic_sorter& set_position_sort(int column, const std::vector<int>& pos);
protected:
virtual bool column_sortable(int column) const;
virtual bool less(int column, const item& row1, const item& row2) const;
private:
std::set<int> alpha_sort_, numeric_sort_, id_sort_, xp_sort_, level_sort_;
std::map<int,int> redirect_sort_;
std::map<int,std::vector<int>> pos_sort_;
int xp_col_; //used by level sort
};
menu(CVideo& video, const std::vector<std::string>& items,
bool click_selects=false, int max_height=-1, int max_width=-1,
const sorter* sorter_obj=nullptr, style *menu_style=nullptr, const bool auto_join=true);
/** Default implementation, but defined out-of-line for efficiency reasons. */
~menu();
int selection() const;
void move_selection(std::size_t id);
void move_selection_keeping_viewport(std::size_t id);
void reset_selection();
// allows user to change_item while running (dangerous)
void change_item(int pos1,int pos2,const std::string& str);
virtual void erase_item(std::size_t index);
void set_heading(const std::vector<std::string>& heading);
/// Set new items to show and redraw/recalculate everything. If
/// strip_spaces is false, spaces will remain at the item edges. If
/// keep_viewport is true, the menu tries to keep the selection at
/// the same position as it were before the items were set.
virtual void set_items(const std::vector<std::string>& items, bool strip_spaces=true,
bool keep_viewport=false);
/// Set a new max height for this menu. Note that this does not take
/// effect immediately, only after certain operations that clear
/// everything, such as set_items().
void set_max_height(const int new_max_height);
void set_max_width(const int new_max_width);
int get_max_height() const { return max_height_; }
int get_max_width() const { return max_width_; }
std::size_t number_of_items() const { return items_.size(); }
int process();
bool double_clicked();
void set_click_selects(bool value);
void set_numeric_keypress_selection(bool value);
void scroll(unsigned int pos);
//currently, menus do not manage the memory of their sorter
//this should be changed to a more object-oriented approach
void set_sorter(sorter *s);
void sort_by(int column);
int get_sort_by() const {return sortby_;}
bool get_sort_reversed() const {return sortreversed_;}
protected:
bool item_ends_with_image(const std::string& item) const;
virtual void handle_event(const SDL_Event& event);
void set_inner_location(const SDL_Rect& rect);
bool requires_event_focus(const SDL_Event *event=nullptr) const;
const std::vector<int>& column_widths() const;
virtual void draw_row(const std::size_t row_index, const SDL_Rect& rect, ROW_TYPE type);
style *style_;
bool silent_;
int hit(int x, int y) const;
std::pair<int,int> hit_cell(int x, int y) const;
int hit_column(int x) const;
int hit_heading(int x, int y) const;
void invalidate_row(std::size_t id);
void invalidate_row_pos(std::size_t pos);
void invalidate_heading();
private:
std::size_t max_items_onscreen() const;
std::size_t heading_height() const;
int max_height_, max_width_;
mutable int max_items_, item_height_;
void adjust_viewport_to_selection();
void key_press(SDL_Keycode key);
std::vector<item> items_;
std::vector<std::size_t> item_pos_;
std::vector<std::string> heading_;
mutable int heading_height_;
void create_help_strings();
void process_help_string(int mousex, int mousey);
std::pair<int,int> cur_help_;
int help_string_;
mutable std::vector<int> column_widths_;
std::size_t selected_;
bool click_selects_;
bool out_;
bool previous_button_;
//std::set<std::size_t> undrawn_items_;
bool show_result_;
bool double_clicked_;
void column_widths_item(const std::vector<std::string>& row, std::vector<int>& widths) const;
void clear_item(int item);
void draw_contents();
void draw();
mutable std::map<int,SDL_Rect> itemRects_;
SDL_Rect get_item_rect(int item) const;
SDL_Rect get_item_rect_internal(std::size_t pos) const;
std::size_t get_item_height_internal(const std::vector<std::string>& item) const;
std::size_t get_item_height(int item) const;
int items_start() const;
int items_end() const;
int items_height() const;
void update_scrollbar_grip_height();
///variable which determines whether a numeric keypress should
///select an item on the dialog
bool num_selects_;
// These two variables are used to get the correct double click
// behavior so that a click that causes one double click won't be
// counted as a first click in the "next" double click.
bool ignore_next_doubleclick_;
bool last_was_doubleclick_;
//ellipsis calculation is slightly off, so default to false
bool use_ellipsis_;
const sorter* sorter_;
int sortby_;
bool sortreversed_;
int highlight_heading_;
/// Set new items to show. If strip_spaces is false, spaces will
/// remain at the item edges.
void fill_items(const std::vector<std::string>& items, bool strip_spaces);
void do_sort();
void recalculate_pos();
void assert_pos();
void update_size();
enum SELECTION_MOVE_VIEWPORT { MOVE_VIEWPORT, NO_MOVE_VIEWPORT };
void set_selection_pos(std::size_t pos, bool silent=false, SELECTION_MOVE_VIEWPORT move_viewport=MOVE_VIEWPORT);
void move_selection_to(std::size_t id, bool silent=false, SELECTION_MOVE_VIEWPORT move_viewport=MOVE_VIEWPORT);
void move_selection_up(std::size_t dep);
void move_selection_down(std::size_t dep);
std::set<int> invalid_;
};
}

View file

@ -1,243 +0,0 @@
/*
wesnoth menu styles Copyright (C) 2006 - 2018 by Patrick Parker <patrick_x99@hotmail.com>
wesnoth menu Copyright (C) 2003-5 by David White <dave@whitevine.net>
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 "widgets/menu.hpp"
#include "font/constants.hpp"
#include "image.hpp"
#include "lexical_cast.hpp"
#include "sdl/utils.hpp"
#include "video.hpp"
namespace gui {
//static initializations
menu::imgsel_style menu::bluebg_style("dialogs/selection", true,
0x000000, 0x000000, 0x333333,
0.35, 0.0, 0.3);
menu::style menu::simple_style;
menu::style &menu::default_style = menu::bluebg_style;
//constructors
menu::style::style() : font_size_(font::SIZE_NORMAL),
cell_padding_(font::SIZE_NORMAL * 3/5), thickness_(0),
normal_rgb_(0x000000), selected_rgb_(0x000099), heading_rgb_(0x333333),
normal_alpha_(0.2), selected_alpha_(0.6), heading_alpha_(0.3),
max_img_w_(-1), max_img_h_(-1)
{}
menu::style::~style()
{}
menu::imgsel_style::imgsel_style(const std::string &img_base, bool has_bg,
int normal_rgb, int selected_rgb, int heading_rgb,
double normal_alpha, double selected_alpha, double heading_alpha)
: img_base_(img_base), has_background_(has_bg), initialized_(false), load_failed_(false),
normal_rgb2_(normal_rgb), selected_rgb2_(selected_rgb), heading_rgb2_(heading_rgb),
normal_alpha2_(normal_alpha), selected_alpha2_(selected_alpha), heading_alpha2_(heading_alpha)
{}
menu::imgsel_style::~imgsel_style()
{}
std::size_t menu::style::get_font_size() const { return font_size_; }
std::size_t menu::style::get_cell_padding() const { return cell_padding_; }
std::size_t menu::style::get_thickness() const { return thickness_; }
void menu::style::scale_images(int max_width, int max_height)
{
max_img_w_ = max_width;
max_img_h_ = max_height;
}
surface menu::style::get_item_image(const image::locator& img_loc) const
{
surface surf = image::get_image(img_loc);
if(!surf.null())
{
int scale = 100;
if(max_img_w_ > 0 && surf->w > max_img_w_) {
scale = (max_img_w_ * 100) / surf->w;
}
if(max_img_h_ > 0 && surf->h > max_img_h_) {
scale = std::min<int>(scale, ((max_img_h_ * 100) / surf->h));
}
if(scale != 100)
{
return scale_surface(surf, (scale * surf->w)/100, (scale * surf->h)/100);
}
}
return surf;
}
bool menu::imgsel_style::load_image(const std::string &img_sub)
{
std::string path = img_base_ + "-" + img_sub + ".png";
const surface image = image::get_image(path);
img_map_[img_sub] = image;
return(!image.null());
}
bool menu::imgsel_style::load_images()
{
if(!initialized_)
{
if( load_image("border-botleft")
&& load_image("border-botright")
&& load_image("border-topleft")
&& load_image("border-topright")
&& load_image("border-left")
&& load_image("border-right")
&& load_image("border-top")
&& load_image("border-bottom") )
{
thickness_ = std::min(
img_map_["border-top"]->h,
img_map_["border-left"]->w);
if(has_background_ && !load_image("background"))
{
load_failed_ = true;
}
else
{
normal_rgb_ = normal_rgb2_;
normal_alpha_ = normal_alpha2_;
selected_rgb_ = selected_rgb2_;
selected_alpha_ = selected_alpha2_;
heading_rgb_ = heading_rgb2_;
heading_alpha_ = heading_alpha2_;
load_failed_ = false;
}
initialized_ = true;
}
else
{
thickness_ = 0;
initialized_ = true;
load_failed_ = true;
}
}
return (!load_failed_);
}
void menu::imgsel_style::draw_row_bg(menu& menu_ref, const std::size_t row_index, const SDL_Rect& rect, ROW_TYPE type)
{
if(type == SELECTED_ROW && has_background_ && !load_failed_) {
if(bg_cache_.width != rect.w || bg_cache_.height != rect.h)
{
//draw scaled background image
//scale image each time (to prevent loss of quality)
bg_cache_.surf = scale_surface(img_map_["background"], rect.w, rect.h);
bg_cache_.width = rect.w;
bg_cache_.height = rect.h;
}
SDL_Rect clip = rect;
menu_ref.video().blit_surface(rect.x,rect.y,bg_cache_.surf,nullptr,&clip);
}
else {
style::draw_row_bg(menu_ref, row_index, rect, type);
}
}
void menu::imgsel_style::draw_row(menu& menu_ref, const std::size_t row_index, const SDL_Rect& rect, ROW_TYPE type)
{
if(!load_failed_) {
//draw item inside
style::draw_row(menu_ref, row_index, rect, type);
if(type == SELECTED_ROW) {
// draw border
surface image;
SDL_Rect area;
SDL_Rect clip = rect;
area.x = rect.x;
area.y = rect.y;
image = img_map_["border-top"];
area.x = rect.x;
area.y = rect.y;
do {
menu_ref.video().blit_surface(area.x,area.y,image,nullptr,&clip);
area.x += image->w;
} while( area.x < rect.x + rect.w );
image = img_map_["border-left"];
area.x = rect.x;
area.y = rect.y;
do {
menu_ref.video().blit_surface(area.x,area.y,image,nullptr,&clip);
area.y += image->h;
} while( area.y < rect.y + rect.h );
image = img_map_["border-right"];
area.x = rect.x + rect.w - thickness_;
area.y = rect.y;
do {
menu_ref.video().blit_surface(area.x,area.y,image,nullptr,&clip);
area.y += image->h;
} while( area.y < rect.y + rect.h );
image = img_map_["border-bottom"];
area.x = rect.x;
area.y = rect.y + rect.h - thickness_;
do {
menu_ref.video().blit_surface(area.x,area.y,image,nullptr,&clip);
area.x += image->w;
} while( area.x < rect.x + rect.w );
image = img_map_["border-topleft"];
area.x = rect.x;
area.y = rect.y;
menu_ref.video().blit_surface(area.x,area.y,image);
image = img_map_["border-topright"];
area.x = rect.x + rect.w - image->w;
area.y = rect.y;
menu_ref.video().blit_surface(area.x,area.y,image);
image = img_map_["border-botleft"];
area.x = rect.x;
area.y = rect.y + rect.h - image->h;
menu_ref.video().blit_surface(area.x,area.y,image);
image = img_map_["border-botright"];
area.x = rect.x + rect.w - image->w;
area.y = rect.y + rect.h - image->h;
menu_ref.video().blit_surface(area.x,area.y,image);
}
}
else {
//default drawing
style::draw_row(menu_ref, row_index, rect, type);
}
}
SDL_Rect menu::imgsel_style::item_size(const std::string& item) const
{
SDL_Rect bounds = style::item_size(item);
bounds.w += 2 * thickness_;
bounds.h += 2 * thickness_;
return bounds;
}
} //namesapce gui

View file

@ -1,171 +0,0 @@
/*
Copyright (C) 2004 - 2018 by Guillaume Melquiond <guillaume.melquiond@gmail.com>
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.
*/
/** @file */
#define GETTEXT_DOMAIN "wesnoth-lib"
#include "widgets/scrollarea.hpp"
#include "sdl/rect.hpp"
namespace gui {
scrollarea::scrollarea(CVideo &video, const bool auto_join)
: widget(video, auto_join), scrollbar_(video),
old_position_(0), recursive_(false), shown_scrollbar_(false),
shown_size_(0), full_size_(0)
{
scrollbar_.hide(true);
}
bool scrollarea::has_scrollbar() const
{
return shown_size_ < full_size_ && scrollbar_.is_valid_height(location().h);
}
sdl_handler_vector scrollarea::handler_members()
{
sdl_handler_vector h;
h.push_back(&scrollbar_);
return h;
}
void scrollarea::update_location(const SDL_Rect& rect)
{
SDL_Rect r = rect;
shown_scrollbar_ = has_scrollbar();
if (shown_scrollbar_) {
int w = r.w - scrollbar_.width();
r.x += w;
r.w -= w;
scrollbar_.set_location(r);
r.x -= w;
r.w = w;
}
if (!hidden())
scrollbar_.hide(!shown_scrollbar_);
set_inner_location(r);
}
void scrollarea::test_scrollbar()
{
if (recursive_)
return;
recursive_ = true;
if (shown_scrollbar_ != has_scrollbar()) {
bg_restore();
bg_cancel();
update_location(location());
}
recursive_ = false;
}
void scrollarea::hide(bool value)
{
widget::hide(value);
if (shown_scrollbar_)
scrollbar_.hide(value);
}
unsigned scrollarea::get_position() const
{
return scrollbar_.get_position();
}
unsigned scrollarea::get_max_position() const
{
return scrollbar_.get_max_position();
}
void scrollarea::set_position(unsigned pos)
{
scrollbar_.set_position(pos);
}
void scrollarea::adjust_position(unsigned pos)
{
scrollbar_.adjust_position(pos);
}
void scrollarea::move_position(int dep)
{
scrollbar_.move_position(dep);
}
void scrollarea::set_shown_size(unsigned h)
{
scrollbar_.set_shown_size(h);
shown_size_ = h;
test_scrollbar();
}
void scrollarea::set_full_size(unsigned h)
{
scrollbar_.set_full_size(h);
full_size_ = h;
test_scrollbar();
}
void scrollarea::set_scroll_rate(unsigned r)
{
scrollbar_.set_scroll_rate(r);
}
void scrollarea::process_event()
{
int grip_position = scrollbar_.get_position();
if (grip_position == old_position_)
return;
old_position_ = grip_position;
scroll(grip_position);
}
SDL_Rect scrollarea::inner_location() const
{
SDL_Rect r = location();
if (shown_scrollbar_)
r.w -= scrollbar_.width();
return r;
}
unsigned scrollarea::scrollbar_width() const
{
return scrollbar_.width();
}
void scrollarea::handle_event(const SDL_Event& event)
{
gui::widget::handle_event(event);
if (mouse_locked() || hidden())
return;
if (event.type != SDL_MOUSEWHEEL)
return;
const SDL_MouseWheelEvent &ev = event.wheel;
int x, y;
SDL_GetMouseState(&x, &y);
if (sdl::point_in_rect(x, y, inner_location())) {
if (ev.y > 0) {
scrollbar_.scroll_up();
} else if (ev.y < 0) {
scrollbar_.scroll_down();
}
}
}
} // end namespace gui

View file

@ -1,67 +0,0 @@
/*
Copyright (C) 2004 - 2018 by Guillaume Melquiond <guillaume.melquiond@gmail.com>
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.
*/
/** @file */
#pragma once
#include "scrollbar.hpp"
namespace gui {
class scrollarea : public widget
{
public:
/**
* Create a zone with automatic handling of scrollbar.
* @todo FIXME: parameterlist ??
*/
//- \param d the display object
//- \param pane the widget where wheel events take place
scrollarea(CVideo &video, bool auto_join=true);
virtual void hide(bool value = true);
protected:
virtual sdl_handler_vector handler_members();
virtual void update_location(const SDL_Rect& rect);
virtual void handle_event(const SDL_Event& event);
virtual void process_event();
virtual void scroll(unsigned int pos) = 0;
virtual void set_inner_location(const SDL_Rect& rect) = 0;
SDL_Rect inner_location() const;
unsigned scrollbar_width() const;
unsigned get_position() const;
unsigned get_max_position() const;
void set_position(unsigned pos);
void adjust_position(unsigned pos);
void move_position(int dep);
void set_shown_size(unsigned h);
void set_full_size(unsigned h);
void set_scroll_rate(unsigned r);
bool has_scrollbar() const;
private:
scrollbar scrollbar_;
int old_position_;
bool recursive_, shown_scrollbar_;
unsigned shown_size_;
unsigned full_size_;
void test_scrollbar();
};
} // end namespace gui

View file

@ -1,396 +0,0 @@
/*
Copyright (C) 2003 by David White <dave@whitevine.net>
2004 - 2015 by Guillaume Melquiond <guillaume.melquiond@gmail.com>
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.
*/
/** @file */
#define GETTEXT_DOMAIN "wesnoth-lib"
#include "widgets/scrollbar.hpp"
#include "image.hpp"
#include "sdl/rect.hpp"
#include "video.hpp"
#include <iostream>
namespace {
const std::string scrollbar_top = "buttons/scrollbars_large/scrolltop.png";
const std::string scrollbar_bottom = "buttons/scrollbars_large/scrollbottom.png";
const std::string scrollbar_mid = "buttons/scrollbars_large/scrollmid.png";
const std::string scrollbar_top_hl = "buttons/scrollbars_large/scrolltop-active.png";
const std::string scrollbar_bottom_hl = "buttons/scrollbars_large/scrollbottom-active.png";
const std::string scrollbar_mid_hl = "buttons/scrollbars_large/scrollmid-active.png";
const std::string scrollbar_top_pressed = "buttons/scrollbars_large/scrolltop-pressed.png";
const std::string scrollbar_bottom_pressed = "buttons/scrollbars_large/scrollbottom-pressed.png";
const std::string scrollbar_mid_pressed = "buttons/scrollbars_large/scrollmid-pressed.png";
const std::string groove_top = "buttons/scrollbars_large/scrollgroove-top.png";
const std::string groove_mid = "buttons/scrollbars_large/scrollgroove-mid.png";
const std::string groove_bottom = "buttons/scrollbars_large/scrollgroove-bottom.png";
}
namespace gui {
scrollbar::scrollbar(CVideo &video)
: widget(video)
, mid_scaled_(nullptr)
, groove_scaled_(nullptr)
, uparrow_(video, "", button::TYPE_TURBO, "button_square/button_square_25"
, gui::button::DEFAULT_SPACE, true,"icons/arrows/arrows_ornate_up_25")
, downarrow_(video, "", button::TYPE_TURBO, "button_square/button_square_25"
, gui::button::DEFAULT_SPACE, true,"icons/arrows/arrows_ornate_down_25")
, state_(NORMAL)
, minimum_grip_height_(0)
, mousey_on_grip_(0)
, grip_position_(0)
, grip_height_(0)
, full_height_(0)
, scroll_rate_(1)
{
uparrow_.enable(false);
downarrow_.enable(false);
static const surface img(image::get_image(scrollbar_mid));
if (img != nullptr) {
set_width(img->w);
// this is a bit rough maybe
minimum_grip_height_ = 2 * img->h;
}
}
sdl_handler_vector scrollbar::handler_members()
{
sdl_handler_vector h;
h.push_back(&uparrow_);
h.push_back(&downarrow_);
return h;
}
void scrollbar::update_location(const SDL_Rect& rect)
{
int uh = uparrow_.height(), dh = downarrow_.height();
uparrow_.set_location(rect.x, rect.y);
downarrow_.set_location(rect.x, rect.y + rect.h - dh);
SDL_Rect r = rect;
r.y += uh;
r.h -= uh + dh;
widget::update_location(r);
//TODO comment or remove
//bg_register(r);
}
void scrollbar::hide(bool value)
{
widget::hide(value);
uparrow_.hide(value);
downarrow_.hide(value);
}
unsigned scrollbar::get_position() const
{
return grip_position_;
}
unsigned scrollbar::get_max_position() const
{
return full_height_ - grip_height_;
}
void scrollbar::set_position(unsigned pos)
{
if (pos > full_height_ - grip_height_)
pos = full_height_ - grip_height_;
if (pos == grip_position_)
return;
grip_position_ = pos;
uparrow_.enable(grip_position_ != 0);
downarrow_.enable(grip_position_ < full_height_ - grip_height_);
set_dirty();
}
void scrollbar::adjust_position(unsigned pos)
{
if (pos < grip_position_)
set_position(pos);
else if (pos >= grip_position_ + grip_height_)
set_position(pos - (grip_height_ - 1));
}
void scrollbar::move_position(int dep)
{
int pos = grip_position_ + dep;
if (pos > 0)
set_position(pos);
else
set_position(0);
}
void scrollbar::set_shown_size(unsigned h)
{
if (h > full_height_)
h = full_height_;
if (h == grip_height_)
return;
bool at_bottom = get_position() == get_max_position() && get_max_position() > 0;
grip_height_ = h;
if (at_bottom)
grip_position_ = get_max_position();
set_position(grip_position_);
set_dirty(true);
}
void scrollbar::set_full_size(unsigned h)
{
if (h == full_height_)
return;
bool at_bottom = get_position() == get_max_position() && get_max_position() > 0;
full_height_ = h;
if (at_bottom)
grip_position_ = get_max_position();
downarrow_.enable(grip_position_ < full_height_ - grip_height_);
set_shown_size(grip_height_);
set_position(grip_position_);
set_dirty(true);
}
void scrollbar::set_scroll_rate(unsigned r)
{
scroll_rate_ = r;
}
bool scrollbar::is_valid_height(int height) const
{
int uh = uparrow_.height();
int dh = downarrow_.height();
if(uh + dh >= height) {
return false;
} else {
return true;
}
}
void scrollbar::scroll_down()
{
move_position(scroll_rate_);
}
void scrollbar::scroll_up()
{
move_position(-scroll_rate_);
}
void scrollbar::process_event()
{
if (uparrow_.pressed())
scroll_up();
if (downarrow_.pressed())
scroll_down();
}
SDL_Rect scrollbar::groove_area() const
{
SDL_Rect loc = location();
int uh = uparrow_.height();
int dh = downarrow_.height();
if(uh + dh >= loc.h) {
loc.h = 0;
} else {
loc.y += uh;
loc.h -= uh + dh;
}
return loc;
}
SDL_Rect scrollbar::grip_area() const
{
const SDL_Rect& loc = groove_area();
if (full_height_ == grip_height_)
return loc;
int h = static_cast<int>(loc.h) * grip_height_ / full_height_;
if (h < minimum_grip_height_)
h = minimum_grip_height_;
int y = loc.y + (static_cast<int>(loc.h) - h) * grip_position_ / (full_height_ - grip_height_);
return {loc.x, y, loc.w, h};
}
void scrollbar::draw_contents()
{
surface mid_img;
surface bottom_img;
surface top_img;
switch (state_) {
case NORMAL:
top_img.assign(image::get_image(scrollbar_top));
mid_img.assign(image::get_image(scrollbar_mid));
bottom_img.assign(image::get_image(scrollbar_bottom));
break;
case ACTIVE:
top_img.assign(image::get_image(scrollbar_top_hl));
mid_img.assign(image::get_image(scrollbar_mid_hl));
bottom_img.assign(image::get_image(scrollbar_bottom_hl));
break;
case DRAGGED:
top_img.assign(image::get_image(scrollbar_top_pressed));
mid_img.assign(image::get_image(scrollbar_mid_pressed));
bottom_img.assign(image::get_image(scrollbar_bottom_pressed));
break;
case UNINIT:
default:
break;
}
const surface top_grv(image::get_image(groove_top));
const surface mid_grv(image::get_image(groove_mid));
const surface bottom_grv(image::get_image(groove_bottom));
if (mid_img == nullptr || bottom_img == nullptr || top_img == nullptr
|| top_grv == nullptr || bottom_grv == nullptr || mid_grv == nullptr) {
std::cerr << "Failure to load scrollbar image.\n";
return;
}
SDL_Rect grip = grip_area();
int mid_height = grip.h - top_img->h - bottom_img->h;
if (mid_height <= 0) {
// For now, minimum size of the middle piece is 1.
// This should never really be encountered, and if it is,
// it's a symptom of a larger problem, I think.
mid_height = 1;
}
if(mid_scaled_.null() || mid_scaled_->h != mid_height) {
mid_scaled_.assign(scale_surface(mid_img, mid_img->w, mid_height));
}
SDL_Rect groove = groove_area();
int groove_height = groove.h - top_grv->h - bottom_grv->h;
if (groove_height <= 0) {
groove_height = 1;
}
if (groove_scaled_.null() || groove_scaled_->h != groove_height) {
groove_scaled_.assign(scale_surface(mid_grv, mid_grv->w, groove_height));
}
if (mid_scaled_.null() || groove_scaled_.null()) {
std::cerr << "Failure during scrollbar image scale.\n";
return;
}
if (grip.h > groove.h) {
std::cerr << "abort draw scrollbar: grip too large\n";
return;
}
// Draw scrollbar "groove"
video().blit_surface(groove.x, groove.y, top_grv);
video().blit_surface(groove.x, groove.y + top_grv->h, groove_scaled_);
video().blit_surface(groove.x, groove.y + top_grv->h + groove_height, bottom_grv);
// Draw scrollbar "grip"
video().blit_surface(grip.x, grip.y, top_img);
video().blit_surface(grip.x, grip.y + top_img->h, mid_scaled_);
video().blit_surface(grip.x, grip.y + top_img->h + mid_height, bottom_img);
}
void scrollbar::handle_event(const SDL_Event& event)
{
gui::widget::handle_event(event);
if (mouse_locked() || hidden())
return;
STATE new_state = state_;
const SDL_Rect& grip = grip_area();
const SDL_Rect& groove = groove_area();
switch (event.type) {
case SDL_MOUSEBUTTONUP:
{
const SDL_MouseButtonEvent& e = event.button;
bool on_grip = sdl::point_in_rect(e.x, e.y, grip);
new_state = on_grip ? ACTIVE : NORMAL;
break;
}
case SDL_MOUSEBUTTONDOWN:
{
const SDL_MouseButtonEvent& e = event.button;
bool on_grip = sdl::point_in_rect(e.x, e.y, grip);
bool on_groove = sdl::point_in_rect(e.x, e.y, groove);
if (on_grip && e.button == SDL_BUTTON_LEFT) {
mousey_on_grip_ = e.y - grip.y;
new_state = DRAGGED;
} else if (on_groove && e.button == SDL_BUTTON_LEFT && groove.h != grip.h) {
if (e.y < grip.y)
move_position(-static_cast<int>(grip_height_));
else
move_position(grip_height_);
} else if (on_groove && e.button == SDL_BUTTON_MIDDLE && groove.h != grip.h) {
int y_dep = e.y - grip.y - grip.h/2;
int dep = y_dep * int(full_height_ - grip_height_)/ (groove.h - grip.h);
move_position(dep);
}
break;
}
case SDL_MOUSEMOTION:
{
const SDL_MouseMotionEvent& e = event.motion;
if (state_ == NORMAL || state_ == ACTIVE) {
bool on_grip = sdl::point_in_rect(e.x, e.y, grip);
new_state = on_grip ? ACTIVE : NORMAL;
} else if (state_ == DRAGGED && groove.h != grip.h) {
int y_dep = e.y - grip.y - mousey_on_grip_;
int dep = y_dep * static_cast<int>(full_height_ - grip_height_) / (groove.h - grip.h);
move_position(dep);
}
break;
}
case SDL_MOUSEWHEEL:
{
const SDL_MouseWheelEvent& e = event.wheel;
int x, y;
SDL_GetMouseState(&x, &y);
bool on_groove = sdl::point_in_rect(x, y, groove);
if (on_groove && e.y < 0) {
move_position(scroll_rate_);
} else if (on_groove && e.y > 0) {
move_position(-scroll_rate_);
}
break;
}
default:
break;
}
if (new_state != state_) {
set_dirty();
mid_scaled_.assign(nullptr);
state_ = new_state;
}
}
} // end namespace gui

View file

@ -1,103 +0,0 @@
/*
Copyright (C) 2003 by David White <dave@whitevine.net>
2004 - 2015 by Guillaume Melquiond <guillaume.melquiond@gmail.com>
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.
*/
/** @file */
#pragma once
#include "button.hpp"
namespace gui {
class scrollarea;
/** Scrollbar */
class scrollbar : public widget
{
public:
/**
* Create a scrollbar.
* @todo FIXME: parameterlist ??
*/
//- @param d the display object
//- @param pane the widget where wheel events take place
//- @param callback a callback interface for warning that the grip has been moved
scrollbar(CVideo &video);
virtual void hide(bool value = true);
/**
* Determine where the scrollbar is.
*
* @return the position.
* @retval returns 0 if the scrollbar is at the top,
* @retval returns (full_size - shown_size) if it is at the bottom.
*/
unsigned get_position() const;
unsigned get_max_position() const;
/** Manually update the scrollbar. */
void set_position(unsigned pos);
/** Ensure the viewport contains the position. */
void adjust_position(unsigned pos);
/** Move the scrollbar. */
void move_position(int dep);
/** Set the relative size of the grip. */
void set_shown_size(unsigned h);
/** Set the relative size of the scrollbar. */
void set_full_size(unsigned h);
/** Set scroll rate. */
void set_scroll_rate(unsigned r);
/** Return true if the scrollbar has a valid size. */
bool is_valid_height(int height) const;
/** Scrolls down one step */
void scroll_down();
/** Scrolls up one step */
void scroll_up();
protected:
virtual sdl_handler_vector handler_members();
virtual void update_location(const SDL_Rect& rect);
virtual void handle_event(const SDL_Event& event);
virtual void process_event();
virtual void draw_contents();
private:
SDL_Rect grip_area() const;
SDL_Rect groove_area() const;
surface mid_scaled_, groove_scaled_;
button uparrow_, downarrow_;
enum STATE { UNINIT, NORMAL, ACTIVE, DRAGGED };
STATE state_;
int minimum_grip_height_, mousey_on_grip_;
// Relative data
unsigned int grip_position_, grip_height_, full_height_;
int scroll_rate_;
};
} // end namespace gui

View file

@ -1,730 +0,0 @@
/*
Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
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 "widgets/textbox.hpp"
#include "desktop/clipboard.hpp"
#include "font/sdl_ttf.hpp"
#include "log.hpp"
#include "sdl/rect.hpp"
#include "serialization/string_utils.hpp"
#include "video.hpp"
static lg::log_domain log_display("display");
#define WRN_DP LOG_STREAM(warn, log_display)
#define DBG_G LOG_STREAM(debug, lg::general())
namespace gui {
textbox::textbox(CVideo &video, int width, const std::string& text, bool editable, std::size_t max_size, int font_size, double alpha, double alpha_focus, const bool auto_join)
: scrollarea(video, auto_join), max_size_(max_size), font_size_(font_size), text_(unicode_cast<ucs4::string>(text)),
cursor_(text_.size()), selstart_(-1), selend_(-1),
grabmouse_(false), text_pos_(0), editable_(editable),
show_cursor_(true), show_cursor_at_(0), text_image_(nullptr),
wrap_(false), line_height_(0), yscroll_(0), alpha_(alpha),
alpha_focus_(alpha_focus),
edit_target_(nullptr)
,listening_(false)
{
// static const SDL_Rect area = video.screen_area();
// const int height = font::draw_text(nullptr,area,font_size,font::NORMAL_COLOR,"ABCD",0,0).h;
set_measurements(width, font::get_max_height(font_size_));
set_scroll_rate(font::get_max_height(font_size_) / 2);
update_text_cache(true);
}
textbox::~textbox()
{
}
void textbox::update_location(const SDL_Rect& rect)
{
scrollarea::update_location(rect);
update_text_cache(true);
set_dirty(true);
}
void textbox::set_inner_location(const SDL_Rect& rect)
{
bg_register(rect);
if (text_image_.null()) return;
text_pos_ = 0;
update_text_cache(false);
}
const std::string textbox::text() const
{
const std::string &ret = unicode_cast<utf8::string>(text_);
return ret;
}
// set_text does not respect max_size_
void textbox::set_text(const std::string& text, const color_t& color)
{
text_ = unicode_cast<ucs4::string>(text);
cursor_ = text_.size();
text_pos_ = 0;
selstart_ = -1;
selend_ = -1;
set_dirty(true);
update_text_cache(true, color);
handle_text_changed(text_);
}
void textbox::append_text(const std::string& text, bool auto_scroll, const color_t& color)
{
if(text_image_.get() == nullptr) {
set_text(text, color);
return;
}
//disallow adding multi-line text to a single-line text box
if(wrap_ == false && std::find_if(text.begin(),text.end(),utils::isnewline) != text.end()) {
return;
}
const bool is_at_bottom = get_position() == get_max_position();
const ucs4::string& wtext = unicode_cast<ucs4::string>(text);
surface new_text = add_text_line(wtext, color);
surface new_surface = create_compatible_surface(text_image_,std::max<std::size_t>(text_image_->w,new_text->w),text_image_->h+new_text->h);
adjust_surface_alpha(new_text, SDL_ALPHA_TRANSPARENT);
adjust_surface_alpha(text_image_, SDL_ALPHA_TRANSPARENT);
SDL_SetSurfaceBlendMode(text_image_, SDL_BLENDMODE_NONE);
sdl_blit(text_image_,nullptr,new_surface,nullptr);
SDL_SetSurfaceBlendMode(text_image_, SDL_BLENDMODE_BLEND);
SDL_Rect target {
0
, text_image_->h
, new_text->w
, new_text->h
};
SDL_SetSurfaceBlendMode(new_text, SDL_BLENDMODE_NONE);
sdl_blit(new_text,nullptr,new_surface,&target);
text_image_.assign(new_surface);
text_.insert(text_.end(), wtext.begin(), wtext.end());
set_dirty(true);
update_text_cache(false);
if(auto_scroll && is_at_bottom) scroll_to_bottom();
handle_text_changed(text_);
}
void textbox::clear()
{
text_.clear();
cursor_ = 0;
cursor_pos_ = 0;
text_pos_ = 0;
selstart_ = -1;
selend_ = -1;
set_dirty(true);
update_text_cache(true);
handle_text_changed(text_);
}
void textbox::set_selection(const int selstart, const int selend)
{
if (!editable_) {
return;
}
if (selstart < 0 || selend < 0 || std::size_t(selstart) > text_.size() ||
std::size_t(selend) > text_.size()) {
WRN_DP << "out-of-boundary selection" << std::endl;
return;
}
selstart_= selstart;
selend_ = selend;
set_dirty(true);
}
void textbox::set_cursor_pos(const int cursor_pos)
{
if (!editable_) {
return;
}
if (cursor_pos < 0 || std::size_t(cursor_pos) > text_.size()) {
WRN_DP << "out-of-boundary selection" << std::endl;
return;
}
cursor_ = cursor_pos;
update_text_cache(false);
set_dirty(true);
}
void textbox::draw_cursor(int pos) const
{
if(show_cursor_ && editable_ && enabled()) {
SDL_Rect rect {
location().x + pos
, location().y
, 1
, location().h
};
sdl::fill_rectangle(rect, {255, 255, 255, 255});
}
}
void textbox::draw_contents()
{
const SDL_Rect& loc = inner_location();
surface& surf = video().getSurface();
color_t c(0, 0, 0);
double& alpha = focus(nullptr) ? alpha_focus_ : alpha_;
c.a = 255 * alpha;
sdl::fill_rectangle(loc, c);
SDL_Rect src;
if(text_image_ == nullptr) {
update_text_cache(true);
}
if(text_image_ != nullptr) {
src.y = yscroll_;
src.w = std::min<std::size_t>(loc.w,text_image_->w);
src.h = std::min<std::size_t>(loc.h,text_image_->h);
src.x = text_pos_;
SDL_Rect dest = video().screen_area();
dest.x = loc.x;
dest.y = loc.y;
// Fills the selected area
if(enabled() && is_selection()) {
const int start = std::min<int>(selstart_,selend_);
const int end = std::max<int>(selstart_,selend_);
int startx = char_x_[start];
int starty = char_y_[start];
const int endx = char_x_[end];
const int endy = char_y_[end];
while(starty <= endy) {
const std::size_t right = starty == endy ? endx : text_image_->w;
if(right <= std::size_t(startx)) {
break;
}
SDL_Rect rect = sdl::create_rect(loc.x + startx
, loc.y + starty - src.y
, right - startx
, line_height_);
const clip_rect_setter clipper(surf, &loc);
color_t c2(0, 0, 160, 140);
sdl::fill_rectangle(rect, c2);
starty += int(line_height_);
startx = 0;
}
}
if(enabled()) {
sdl_blit(text_image_, &src, surf, &dest);
} else {
// HACK: using 30% opacity allows white text to look as though it is grayed out,
// while not changing any applicable non-grayscale AA. Actual colored text will
// not look as good, but this is not currently a concern since GUI1 textboxes
// are not used much nowadays, and they will eventually all go away.
adjust_surface_alpha(text_image_, ftofxp(0.3));
sdl_blit(text_image_, &src, surf, &dest);
}
}
draw_cursor(cursor_pos_ == 0 ? 0 : cursor_pos_ - 1);
}
void textbox::set_editable(bool value)
{
editable_ = value;
}
bool textbox::editable() const
{
return editable_;
}
int textbox::font_size() const
{
return font_size_;
}
void textbox::set_font_size(int fs)
{
font_size_ = fs;
}
void textbox::scroll_to_bottom()
{
set_position(get_max_position());
}
void textbox::set_wrap(bool val)
{
if(wrap_ != val) {
wrap_ = val;
update_text_cache(true);
set_dirty(true);
}
}
void textbox::scroll(unsigned int pos)
{
yscroll_ = pos;
set_dirty(true);
}
surface textbox::add_text_line(const ucs4::string& text, const color_t& color)
{
line_height_ = font::get_max_height(font_size_);
if(char_y_.empty()) {
char_y_.push_back(0);
} else {
char_y_.push_back(char_y_.back() + line_height_);
}
char_x_.push_back(0);
// Re-calculate the position of each glyph. We approximate this by asking the
// width of each substring, but this is a flawed assumption which won't work with
// some more complex scripts (that is, RTL languages). This part of the work should
// actually be done by the font-rendering system.
std::string visible_string;
ucs4::string wrapped_text;
ucs4::string::const_iterator backup_itor = text.end();
ucs4::string::const_iterator itor = text.begin();
while(itor != text.end()) {
//If this is a space, save copies of the current state so we can roll back
if(char(*itor) == ' ') {
backup_itor = itor;
}
visible_string.append(unicode_cast<utf8::string>(*itor));
if(char(*itor) == '\n') {
backup_itor = text.end();
visible_string = "";
}
int w = font::line_width(visible_string, font_size_);
if(wrap_ && w >= inner_location().w) {
if(backup_itor != text.end()) {
int backup = itor - backup_itor;
itor = backup_itor + 1;
if(backup > 0) {
char_x_.erase(char_x_.end()-backup, char_x_.end());
char_y_.erase(char_y_.end()-backup, char_y_.end());
wrapped_text.erase(wrapped_text.end()-backup, wrapped_text.end());
}
} else {
if (visible_string == std::string("").append(unicode_cast<utf8::string>(*itor))) {
break; //breaks infinite loop where when running with a fake display, we word wrap a single character infinitely.
}
}
backup_itor = text.end();
wrapped_text.push_back(ucs4::char_t('\n'));
char_x_.push_back(0);
char_y_.push_back(char_y_.back() + line_height_);
visible_string = "";
} else {
wrapped_text.push_back(*itor);
char_x_.push_back(w);
char_y_.push_back(char_y_.back() + (char(*itor) == '\n' ? line_height_ : 0));
++itor;
}
}
const std::string s = unicode_cast<utf8::string>(wrapped_text);
const surface res(font::get_rendered_text(s, font_size_, color));
return res;
}
void textbox::update_text_cache(bool changed, const color_t& color)
{
if(changed) {
char_x_.clear();
char_y_.clear();
text_image_.assign(add_text_line(text_, color));
}
int cursor_x = char_x_[cursor_];
if(cursor_x - text_pos_ > location().w) {
text_pos_ = cursor_x - location().w;
} else if(cursor_x - text_pos_ < 0) {
text_pos_ = cursor_x;
}
cursor_pos_ = cursor_x - text_pos_;
if (!text_image_.null()) {
set_full_size(text_image_->h);
set_shown_size(location().h);
}
}
bool textbox::is_selection()
{
return (selstart_ != -1) && (selend_ != -1) && (selstart_ != selend_);
}
void textbox::erase_selection()
{
if(!is_selection())
return;
ucs4::string::iterator itor = text_.begin() + std::min(selstart_, selend_);
text_.erase(itor, itor + std::abs(selend_ - selstart_));
cursor_ = std::min(selstart_, selend_);
selstart_ = selend_ = -1;
}
namespace {
const unsigned int copypaste_modifier =
#ifdef __APPLE__
KMOD_LGUI | KMOD_RGUI
#else
KMOD_CTRL
#endif
;
}
bool textbox::requires_event_focus(const SDL_Event* event) const
{
if(!focus_ || hidden() || !enabled()) {
return false;
}
if(event == nullptr) {
//when event is not specified, signal that focus may be desired later
return true;
}
if(event->type == SDL_KEYDOWN) {
SDL_Keycode key = event->key.keysym.sym;
switch(key) {
case SDLK_UP:
case SDLK_DOWN:
case SDLK_PAGEUP:
case SDLK_PAGEDOWN:
//in the future we may need to check for input history or multi-line support
//for now, just return false since these events are not handled.
return false;
default:
return true;
}
}
//mouse events are processed regardless of focus
return false;
}
void textbox::handle_event(const SDL_Event& event)
{
gui::widget::handle_event(event);
handle_event(event, false);
}
bool textbox::handle_text_input(const SDL_Event& event)
{
bool changed = false;
utf8::string str = event.text.text;
ucs4::string s = unicode_cast<ucs4::string>(str);
DBG_G << "Char: " << str << "\n";
if (editable_) {
changed = true;
if (is_selection())
erase_selection();
if (text_.size() + 1 <= max_size_) {
text_.insert(text_.begin() + cursor_, s.begin(), s.end());
cursor_ += s.size();
}
} else {
pass_event_to_target(event);
}
return changed;
}
bool textbox::handle_key_down(const SDL_Event &event)
{
bool changed = false;
const SDL_Keysym& key = reinterpret_cast<const SDL_KeyboardEvent&>(event).keysym;
const SDL_Keymod modifiers = SDL_GetModState();
const int c = key.sym;
const int old_cursor = cursor_;
listening_ = true;
if(editable_) {
if(c == SDLK_LEFT && cursor_ > 0)
--cursor_;
if(c == SDLK_RIGHT && cursor_ < static_cast<int>(text_.size()))
++cursor_;
// ctrl-a, ctrl-e and ctrl-u are readline style shortcuts, even on Macs
if(c == SDLK_END || (c == SDLK_e && (modifiers & KMOD_CTRL)))
cursor_ = text_.size();
if(c == SDLK_HOME || (c == SDLK_a && (modifiers & KMOD_CTRL)))
cursor_ = 0;
if((old_cursor != cursor_) && (modifiers & KMOD_SHIFT)) {
if(selstart_ == -1)
selstart_ = old_cursor;
selend_ = cursor_;
}
} else if(c == SDLK_LEFT || c == SDLK_RIGHT || c == SDLK_END || c == SDLK_HOME) {
pass_event_to_target(event);
}
if(editable_) {
if(c == SDLK_BACKSPACE) {
changed = true;
if(is_selection()) {
erase_selection();
} else if(cursor_ > 0) {
--cursor_;
text_.erase(text_.begin()+cursor_);
}
}
if(c == SDLK_u && (modifiers & KMOD_CTRL)) { // clear line
changed = true;
cursor_ = 0;
text_.resize(0);
}
if(c == SDLK_DELETE && !text_.empty()) {
changed = true;
if(is_selection()) {
erase_selection();
} else {
if(cursor_ < static_cast<int>(text_.size())) {
text_.erase(text_.begin()+cursor_);
}
}
}
} else if(c == SDLK_BACKSPACE || c == SDLK_DELETE || (c == SDLK_u && (modifiers & KMOD_CTRL))) {
pass_event_to_target(event);
}
//movement characters may have a "Unicode" field on some platforms, so ignore it.
if(!(c == SDLK_UP || c == SDLK_DOWN || c == SDLK_LEFT || c == SDLK_RIGHT ||
c == SDLK_DELETE || c == SDLK_BACKSPACE || c == SDLK_END || c == SDLK_HOME ||
c == SDLK_PAGEUP || c == SDLK_PAGEDOWN)) {
if((event.key.keysym.mod & copypaste_modifier)
//on windows SDL fires for AltGr lctrl+ralt (needed to access @ etc on certain keyboards)
#ifdef _WIN32
&& !(event.key.keysym.mod & KMOD_ALT)
#endif
) {
switch(c) {
case SDLK_v: // paste
{
if(!editable()) {
pass_event_to_target(event);
break;
}
changed = true;
if(is_selection())
erase_selection();
std::string str = desktop::clipboard::copy_from_clipboard(false);
//cut off anything after the first newline
str.erase(std::find_if(str.begin(),str.end(),utils::isnewline),str.end());
ucs4::string s = unicode_cast<ucs4::string>(str);
if(text_.size() < max_size_) {
if(s.size() + text_.size() > max_size_) {
s.resize(max_size_ - text_.size());
}
text_.insert(text_.begin()+cursor_, s.begin(), s.end());
cursor_ += s.size();
}
}
break;
case SDLK_c: // copy
{
if(is_selection())
{
const std::size_t beg = std::min<std::size_t>(std::size_t(selstart_),std::size_t(selend_));
const std::size_t end = std::max<std::size_t>(std::size_t(selstart_),std::size_t(selend_));
ucs4::string ws(text_.begin() + beg, text_.begin() + end);
std::string s = unicode_cast<utf8::string>(ws);
desktop::clipboard::copy_to_clipboard(s, false);
}
}
break;
}
}
else {
pass_event_to_target(event);
}
}
return changed;
}
void textbox::handle_event(const SDL_Event& event, bool was_forwarded)
{
if(!enabled())
return;
scrollarea::handle_event(event);
if(hidden())
return;
bool changed = false;
const int old_selstart = selstart_;
const int old_selend = selend_;
//Sanity check: verify that selection start and end are within text
//boundaries
if(is_selection() && !(std::size_t(selstart_) <= text_.size() && std::size_t(selend_) <= text_.size())) {
WRN_DP << "out-of-boundary selection" << std::endl;
selstart_ = selend_ = -1;
}
int mousex, mousey;
const uint8_t mousebuttons = SDL_GetMouseState(&mousex,&mousey);
if(!(mousebuttons & SDL_BUTTON(1))) {
grabmouse_ = false;
}
const SDL_Rect& loc = inner_location();
bool clicked_inside = !mouse_locked() && (event.type == SDL_MOUSEBUTTONDOWN
&& (mousebuttons & SDL_BUTTON(1))
&& sdl::point_in_rect(mousex, mousey, loc));
if(clicked_inside) {
set_focus(true);
}
if ((grabmouse_ && (!mouse_locked() && event.type == SDL_MOUSEMOTION)) || clicked_inside) {
const int x = mousex - loc.x + text_pos_;
const int y = mousey - loc.y;
int pos = 0;
int distance = x;
for(unsigned int i = 1; i < char_x_.size(); ++i) {
if(static_cast<int>(yscroll_) + y < char_y_[i]) {
break;
}
// Check individually each distance (if, one day, we support
// RTL languages, char_x_[c] may not be monotonous.)
if(std::abs(x - char_x_[i]) < distance && yscroll_ + y < char_y_[i] + line_height_) {
pos = i;
distance = std::abs(x - char_x_[i]);
}
}
cursor_ = pos;
if(grabmouse_)
selend_ = cursor_;
update_text_cache(false);
if(!grabmouse_ && (mousebuttons & SDL_BUTTON(1))) {
grabmouse_ = true;
selstart_ = selend_ = cursor_;
} else if (! (mousebuttons & SDL_BUTTON(1))) {
grabmouse_ = false;
}
set_dirty();
}
//if we don't have the focus, then see if we gain the focus,
//otherwise return
if(!was_forwarded && focus(&event) == false) {
if (!mouse_locked() && event.type == SDL_MOUSEMOTION && sdl::point_in_rect(mousex, mousey, loc))
events::focus_handler(this);
return;
}
const int old_cursor = cursor_;
if (event.type == SDL_TEXTINPUT && listening_) {
changed = handle_text_input(event);
} else
if (event.type == SDL_KEYDOWN) {
changed = handle_key_down(event);
}
else {
if(event.type != SDL_KEYDOWN || (!was_forwarded && focus(&event) != true)) {
draw();
return;
}
}
if(is_selection() && (selend_ != cursor_))
selstart_ = selend_ = -1;
//since there has been cursor activity, make the cursor appear for
//at least the next 500ms.
show_cursor_ = true;
show_cursor_at_ = SDL_GetTicks();
if(changed || old_cursor != cursor_ || old_selstart != selstart_ || old_selend != selend_) {
text_image_ = nullptr;
handle_text_changed(text_);
}
set_dirty(true);
}
void textbox::pass_event_to_target(const SDL_Event& event)
{
if(edit_target_ && edit_target_->editable()) {
edit_target_->handle_event(event, true);
}
}
void textbox::set_edit_target(textbox* target)
{
edit_target_ = target;
}
} //end namespace gui

View file

@ -1,122 +0,0 @@
/*
Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
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.
*/
#pragma once
#include "serialization/unicode.hpp"
#include "font/constants.hpp"
#include "font/standard_colors.hpp"
#include "scrollarea.hpp"
namespace gui {
class textbox : public scrollarea
{
public:
textbox(CVideo &video, int width, const std::string& text="", bool editable=true, std::size_t max_size = 256, int font_size = font::SIZE_PLUS, double alpha = 0.4, double alpha_focus = 0.2, const bool auto_join = true);
virtual ~textbox();
const std::string text() const;
void set_text(const std::string& text, const color_t& color =font::NORMAL_COLOR);
void append_text(const std::string& text,bool auto_scroll = false, const color_t& color =font::NORMAL_COLOR);
void clear();
void set_selection(const int selstart, const int selend);
void set_cursor_pos(const int cursor_pos);
void set_editable(bool value);
bool editable() const;
int font_size() const;
void set_font_size(int fs);
void scroll_to_bottom();
void set_wrap(bool val);
void set_edit_target(textbox* target);
protected:
virtual void draw_contents();
virtual void update_location(const SDL_Rect& rect);
virtual void set_inner_location(const SDL_Rect& );
virtual void scroll(unsigned int pos);
private:
virtual void handle_text_changed(const ucs4::string&) {}
std::size_t max_size_;
int font_size_;
ucs4::string text_;
// mutable unsigned int firstOnScreen_;
int cursor_;
int selstart_;
int selend_;
bool grabmouse_;
int text_pos_;
int cursor_pos_;
std::vector<int> char_x_, char_y_;
bool editable_;
bool show_cursor_;
//records the time the cursor was shown at last
//the cursor should be inverted every 500 ms.
//this will be reset when keyboard input events occur
int show_cursor_at_;
surface text_image_;
bool wrap_;
std::size_t line_height_, yscroll_;
double alpha_;
double alpha_focus_;
textbox* edit_target_;
/* This boolean is used to filter out any TextInput events that are received without
* the corresponding KeyPress events. This is needed to avoid a bug when creating a
* textbox using a hotkey.
* */
bool listening_;
void handle_event(const SDL_Event& event, bool was_forwarded);
void handle_event(const SDL_Event& event);
void pass_event_to_target(const SDL_Event& event);
void draw_cursor(int pos) const;
void update_text_cache(bool reset = false, const color_t& color =font::NORMAL_COLOR);
surface add_text_line(const ucs4::string& text, const color_t& color =font::NORMAL_COLOR);
bool is_selection();
void erase_selection();
//make it so that only one textbox object can be receiving
//events at a time.
bool requires_event_focus(const SDL_Event *event=nullptr) const;
bool show_scrollbar() const;
bool handle_text_input(const SDL_Event& event);
bool handle_key_down(const SDL_Event &event);
};
}