Removed as much GUI1 backend as is now possible
We're now maintaining the bare minimum to keep Help running.
This commit is contained in:
parent
8090a2f333
commit
d542e39762
5 changed files with 4 additions and 1308 deletions
|
@ -33,831 +33,13 @@
|
|||
|
||||
#include "utils/functional.hpp"
|
||||
|
||||
static lg::log_domain log_display("display");
|
||||
#define ERR_DP LOG_STREAM(err, log_display)
|
||||
#define LOG_DP LOG_STREAM(info, log_display)
|
||||
#define DBG_DP LOG_STREAM(debug, log_display)
|
||||
#define ERR_G LOG_STREAM(err, lg::general)
|
||||
|
||||
namespace gui {
|
||||
|
||||
//static initialization
|
||||
//note: style names are directly related to the panel image file names
|
||||
const dialog::style& dialog::default_style = dialog_frame::default_style;
|
||||
const dialog::style& dialog::message_style = dialog_frame::message_style;
|
||||
const dialog::style dialog::hotkeys_style("menu", 0);
|
||||
const int dialog::message_font_size = font::SIZE_PLUS;
|
||||
const int dialog::caption_font_size = font::SIZE_LARGE;
|
||||
const size_t dialog::left_padding = font::relative_size(10);
|
||||
const size_t dialog::right_padding = font::relative_size(10);
|
||||
const size_t dialog::image_h_pad = font::relative_size(/*image_ == nullptr ? 0 :*/ 10);
|
||||
const size_t dialog::top_padding = font::relative_size(10);
|
||||
const size_t dialog::bottom_padding = font::relative_size(10);
|
||||
|
||||
const int dialog::max_menu_width = -1;
|
||||
|
||||
menu * dialog::empty_menu = nullptr;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
std::vector<std::string> empty_string_vector;
|
||||
|
||||
} //end anonymous namespace
|
||||
|
||||
namespace gui {
|
||||
|
||||
dialog_textbox::~dialog_textbox()
|
||||
{
|
||||
delete label_;
|
||||
}
|
||||
|
||||
dialog::dimension_measurements::dimension_measurements() :
|
||||
x(-1),
|
||||
y(-1),
|
||||
interior(sdl::empty_rect),
|
||||
message(sdl::empty_rect),
|
||||
textbox(sdl::empty_rect),
|
||||
menu_width(0),
|
||||
panes(),
|
||||
label_x(-1),
|
||||
label_y(-1),
|
||||
menu_x(-1),
|
||||
menu_y(-1),
|
||||
menu_height(-1),
|
||||
image_x(-1),
|
||||
image_y(-1),
|
||||
caption_x(-1),
|
||||
caption_y(-1),
|
||||
buttons()
|
||||
{
|
||||
//note: this is not defined in the header file to C++ ODR (one-definition rule)
|
||||
//since each inclusion of the header file uses a different version of empty_rect
|
||||
//(unnamed namespace and/or const object defined at declaration time).
|
||||
}
|
||||
|
||||
dialog::dialog(CVideo& video, const std::string& title, const std::string& message,
|
||||
const DIALOG_TYPE type, const style& dialog_style) :
|
||||
video_(video),
|
||||
image_(nullptr),
|
||||
title_(title),
|
||||
style_(dialog_style),
|
||||
title_widget_(nullptr),
|
||||
message_(nullptr),
|
||||
type_(type),
|
||||
menu_(get_empty_menu(video)),
|
||||
preview_panes_(),
|
||||
button_pool_(),
|
||||
standard_buttons_(),
|
||||
extra_buttons_(),
|
||||
top_buttons_(),
|
||||
frame_buttons_(),
|
||||
topic_(),
|
||||
help_button_(nullptr),
|
||||
text_widget_(nullptr),
|
||||
frame_(nullptr),
|
||||
dim_(),
|
||||
result_(CONTINUE_DIALOG)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case MESSAGE:
|
||||
default:
|
||||
break;
|
||||
case OK_ONLY:
|
||||
add_button(new standard_dialog_button(video_,_("OK"),0,true), BUTTON_STANDARD);
|
||||
break;
|
||||
case YES_NO:
|
||||
add_button(new standard_dialog_button(video_,_("Yes"),0,false), BUTTON_STANDARD);
|
||||
add_button(new standard_dialog_button(video_,_("No"),1,true), BUTTON_STANDARD);
|
||||
break;
|
||||
case OK_CANCEL:
|
||||
add_button(new standard_dialog_button(video_,_("OK"),0,false), BUTTON_STANDARD);
|
||||
add_button(new standard_dialog_button(video_,_("Cancel"),1,true), BUTTON_STANDARD);
|
||||
break;
|
||||
case CANCEL_ONLY:
|
||||
add_button(new standard_dialog_button(video_,_("Cancel"),0,true), BUTTON_STANDARD);
|
||||
break;
|
||||
case CLOSE_ONLY:
|
||||
add_button(new standard_dialog_button(video_,_("Close"),0,true), BUTTON_STANDARD);
|
||||
break;
|
||||
}
|
||||
//dialog creator should catch(button::error&) ?
|
||||
|
||||
try {
|
||||
std::string msg = font::word_wrap_text(message, message_font_size, video_.getx() / 2, video_.gety() / 2);
|
||||
message_ = new label(video_, msg, message_font_size, font::NORMAL_COLOR, false);
|
||||
} catch(utf8::invalid_utf8_exception&) {
|
||||
ERR_DP << "Problem handling utf8 in message '" << message << "'" << std::endl;
|
||||
throw;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dialog::~dialog()
|
||||
{
|
||||
if(menu_ != empty_menu)
|
||||
{
|
||||
delete menu_;
|
||||
}
|
||||
delete title_widget_;
|
||||
delete message_;
|
||||
delete text_widget_;
|
||||
delete image_;
|
||||
delete frame_;
|
||||
|
||||
button_pool_iterator b;
|
||||
for (b = button_pool_.begin(); b != button_pool_.end(); ++b) {
|
||||
delete b->first;
|
||||
}
|
||||
// pp_iterator p;
|
||||
// for (p = preview_panes_.begin(); p != preview_panes_.end(); ++p) {
|
||||
// delete (*p);
|
||||
// }
|
||||
}
|
||||
|
||||
bool dialog::option_checked(unsigned int option_index)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
button_pool_iterator b;
|
||||
for (b = button_pool_.begin(); b != button_pool_.end(); ++b) {
|
||||
if(b->first->is_option()) {
|
||||
if(option_index == i++) {
|
||||
return b->first->checked();
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void dialog::add_button(dialog_button *const btn, BUTTON_LOCATION loc)
|
||||
{
|
||||
std::pair<dialog_button *, BUTTON_LOCATION> new_pair(btn,loc);
|
||||
button_pool_.push_back(new_pair);
|
||||
switch(loc)
|
||||
{
|
||||
case BUTTON_HELP:
|
||||
delete help_button_;
|
||||
help_button_ = btn;
|
||||
break;
|
||||
case BUTTON_EXTRA:
|
||||
case BUTTON_EXTRA_LEFT:
|
||||
case BUTTON_CHECKBOX:
|
||||
case BUTTON_CHECKBOX_LEFT:
|
||||
extra_buttons_.push_back(btn);
|
||||
break;
|
||||
case BUTTON_STANDARD:
|
||||
standard_buttons_.push_back(btn);
|
||||
break;
|
||||
case BUTTON_TOP:
|
||||
top_buttons_.push_back(btn);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
btn->set_parent(this);
|
||||
}
|
||||
|
||||
void dialog::add_button(dialog_button_info btn_info, BUTTON_LOCATION loc)
|
||||
{
|
||||
dialog_button *btn = new dialog_button(video_, btn_info.label, button::TYPE_PRESS, CONTINUE_DIALOG, btn_info.handler);
|
||||
add_button(btn, loc);
|
||||
}
|
||||
|
||||
void dialog::add_option(const std::string& label, bool checked, BUTTON_LOCATION loc, const std::string& help_string)
|
||||
{
|
||||
gui::dialog_button *btn = new dialog_button(video_, label, button::TYPE_CHECK);
|
||||
btn->set_check(checked);
|
||||
btn->set_help_string(help_string);
|
||||
add_button(btn, loc);
|
||||
}
|
||||
|
||||
void dialog::set_textbox(const std::string& text_widget_label,
|
||||
const std::string& text_widget_text,
|
||||
const int text_widget_max_chars, const unsigned int text_box_width)
|
||||
{
|
||||
label *label_ptr = new label(video_, text_widget_label, message_font_size, font::NORMAL_COLOR, false);
|
||||
const bool editable_textbox = std::find(text_widget_text.begin(),text_widget_text.end(),'\n') == text_widget_text.end();
|
||||
text_widget_ = new dialog_textbox(label_ptr, video_, text_box_width, text_widget_text, editable_textbox, text_widget_max_chars);
|
||||
text_widget_->set_wrap(!editable_textbox);
|
||||
}
|
||||
|
||||
void dialog::set_menu(const std::vector<std::string> &menu_items, menu::sorter* sorter)
|
||||
{
|
||||
set_menu(new gui::menu(video_, menu_items, (type_==MESSAGE),
|
||||
-1, dialog::max_menu_width, sorter, &menu::default_style, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes (or sets, if not previously set) the dialog's menu items to the
|
||||
* provided list. If @a keep_selected is true, the selection will remain at
|
||||
* the same index if possible (otherwise it gets reset to zero).
|
||||
*/
|
||||
void dialog::set_menu_items(const std::vector<std::string> &menu_items, bool keep_selection)
|
||||
{
|
||||
if(menu_ == empty_menu) {
|
||||
set_menu(menu_items);
|
||||
} else {
|
||||
menu_->set_items(menu_items, true, keep_selection);
|
||||
|
||||
for(pp_iterator i = preview_panes_.begin(); i != preview_panes_.end(); ++i) {
|
||||
(**i).set_selection(menu_->selection());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides create-on-use semantics for empty_menu.
|
||||
* This is called by dialog's constructor, so other code can use empty_menu directly.
|
||||
*/
|
||||
menu * dialog::get_empty_menu(CVideo& video)
|
||||
{
|
||||
if ( empty_menu == nullptr ) {
|
||||
empty_menu = new gui::menu(video, empty_string_vector, false, -1, -1, nullptr, &menu::simple_style);
|
||||
empty_menu->leave();
|
||||
}
|
||||
return empty_menu;
|
||||
}
|
||||
|
||||
int dialog::show(int xloc, int yloc)
|
||||
{
|
||||
layout(xloc, yloc);
|
||||
return show();
|
||||
}
|
||||
|
||||
int dialog::show()
|
||||
{
|
||||
if (video_.faked()) {
|
||||
plugins_manager * pm = plugins_manager::get();
|
||||
if (pm && pm->any_running()) {
|
||||
pm->notify_event("show_dialog", config(config_of
|
||||
("title", title_)
|
||||
("message", message_->get_text())
|
||||
));
|
||||
|
||||
plugins_context pc("Dialog");
|
||||
pc.set_callback("set_result", [this](const config& cfg) { set_result(cfg["result"].to_int(CLOSE_DIALOG)); }, false);
|
||||
|
||||
while (pm->any_running() && result() == CONTINUE_DIALOG) {
|
||||
pc.play_slice();
|
||||
}
|
||||
return result();
|
||||
}
|
||||
return CLOSE_DIALOG;
|
||||
}
|
||||
|
||||
if(video_.update_locked()) {
|
||||
ERR_DP << "display locked ignoring dialog '" << title_ << "' '" << message_->get_text() << "'" << std::endl;
|
||||
return CLOSE_DIALOG;
|
||||
}
|
||||
|
||||
LOG_DP << "showing dialog '" << title_ << "' '" << message_->get_text() << "'\n";
|
||||
if(dim_.interior == sdl::empty_rect) { layout(); }
|
||||
|
||||
//create the event context, remember to instruct any passed-in widgets to join it
|
||||
const events::event_context dialog_events_context;
|
||||
const dialog_manager manager;
|
||||
|
||||
get_frame().join();
|
||||
|
||||
//draw
|
||||
draw_frame();
|
||||
update_widget_positions();
|
||||
draw_contents();
|
||||
|
||||
//process
|
||||
plugins_manager::get()->notify_event("show_dialog", config(config_of
|
||||
("title", title_)
|
||||
("message", message_->get_text())
|
||||
));
|
||||
|
||||
plugins_context pc("Dialog");
|
||||
pc.set_callback("set_result", [this](const config& cfg) { set_result(cfg["result"].to_int(CLOSE_DIALOG)); }, false);
|
||||
|
||||
dialog_process_info dp_info;
|
||||
do
|
||||
{
|
||||
events::pump();
|
||||
set_result(process(dp_info));
|
||||
if(!done()) {
|
||||
refresh();
|
||||
}
|
||||
action(dp_info);
|
||||
dp_info.cycle();
|
||||
|
||||
pc.play_slice();
|
||||
} while(!done());
|
||||
|
||||
clear_background();
|
||||
return result();
|
||||
}
|
||||
|
||||
void dialog::draw_contents()
|
||||
{
|
||||
if(!preview_panes_.empty()) {
|
||||
for(pp_iterator i = preview_panes_.begin(); i != preview_panes_.end(); ++i) {
|
||||
preview_pane *pane = *i;
|
||||
if(!pane->handler_members().empty())
|
||||
{
|
||||
pane->draw();
|
||||
pane->needs_restore_ = false; //prevent panes from drawing over members
|
||||
}
|
||||
}
|
||||
}
|
||||
events::raise_draw_event(); //draw widgets
|
||||
|
||||
video_.flip();
|
||||
}
|
||||
|
||||
dialog_frame& dialog::get_frame()
|
||||
{
|
||||
if(frame_ == nullptr) {
|
||||
frame_buttons_.clear();
|
||||
for(button_iterator b = standard_buttons_.begin(); b != standard_buttons_.end(); ++b)
|
||||
{
|
||||
frame_buttons_.push_back(*b);
|
||||
}
|
||||
frame_ = new dialog_frame(video_, title_, style_, true, &frame_buttons_, help_button_);
|
||||
}
|
||||
return *frame_;
|
||||
}
|
||||
|
||||
void dialog::clear_background() {
|
||||
delete frame_;
|
||||
frame_ = nullptr;
|
||||
}
|
||||
|
||||
void dialog::draw_frame()
|
||||
{
|
||||
get_frame().draw();
|
||||
}
|
||||
|
||||
void dialog::update_widget_positions()
|
||||
{
|
||||
if(!preview_panes_.empty()) {
|
||||
for(pp_iterator i = preview_panes_.begin(); i != preview_panes_.end(); ++i) {
|
||||
preview_pane *pane = *i;
|
||||
pane->leave();
|
||||
pane->join();
|
||||
pane->set_location(dim_.panes.find(pane)->second);
|
||||
}
|
||||
}
|
||||
if(text_widget_) {
|
||||
text_widget_->leave();
|
||||
text_widget_->join();
|
||||
text_widget_->set_location(dim_.textbox);
|
||||
if(text_widget_->get_label()) {
|
||||
text_widget_->get_label()->set_location(dim_.label_x, dim_.label_y);
|
||||
}
|
||||
}
|
||||
if(get_menu().height() > 0) {
|
||||
menu_->leave();
|
||||
menu_->join();
|
||||
menu_->set_numeric_keypress_selection(text_widget_ == nullptr);
|
||||
menu_->set_width( dim_.menu_width );
|
||||
menu_->set_max_width( dim_.menu_width ); //lock the menu width
|
||||
if(dim_.menu_height >= 0) {
|
||||
menu_->set_max_height( dim_.menu_height );
|
||||
}
|
||||
menu_->set_location( dim_.menu_x, dim_.menu_y );
|
||||
}
|
||||
if(image_) {
|
||||
image_->leave();
|
||||
image_->join();
|
||||
image_->set_location(dim_.image_x, dim_.image_y);
|
||||
if(image_->caption()) {
|
||||
image_->caption()->set_location(dim_.caption_x, dim_.caption_y);
|
||||
}
|
||||
}
|
||||
button_iterator b;
|
||||
for(b = top_buttons_.begin(); b != top_buttons_.end(); ++b) {
|
||||
dialog_button *btn = *b;
|
||||
btn->leave();
|
||||
btn->join();
|
||||
std::pair<int,int> coords = dim_.buttons.find(btn)->second;
|
||||
btn->set_location(coords.first, coords.second);
|
||||
}
|
||||
for(b = extra_buttons_.begin(); b != extra_buttons_.end(); ++b) {
|
||||
dialog_button *btn = *b;
|
||||
btn->leave();
|
||||
btn->join();
|
||||
std::pair<int,int> coords = dim_.buttons.find(btn)->second;
|
||||
btn->set_location(coords.first, coords.second);
|
||||
}
|
||||
for(b = standard_buttons_.begin(); b != standard_buttons_.end(); ++b) {
|
||||
dialog_button *btn = *b;
|
||||
btn->leave();
|
||||
btn->join();
|
||||
}
|
||||
if(help_button_) {
|
||||
help_button_->leave();
|
||||
help_button_->join();
|
||||
}
|
||||
message_->set_location(dim_.message);
|
||||
message_->leave();
|
||||
message_->join();
|
||||
}
|
||||
|
||||
void dialog::refresh()
|
||||
{
|
||||
video_.flip();
|
||||
CVideo::delay(10);
|
||||
}
|
||||
|
||||
dialog::dimension_measurements dialog::layout(int xloc, int yloc)
|
||||
{
|
||||
CVideo& screen = video_;
|
||||
const surface& scr = screen.getSurface();
|
||||
|
||||
dimension_measurements dim;
|
||||
dim.x = xloc;
|
||||
dim.y = yloc;
|
||||
|
||||
const bool use_textbox = (text_widget_ != nullptr);
|
||||
int text_widget_width = 0;
|
||||
int text_widget_height = 0;
|
||||
if(use_textbox) {
|
||||
const SDL_Rect& area = font::text_area(text_widget_->text(),message_font_size);
|
||||
dim.textbox.w = std::min<size_t>(screen.getx()/2,std::max<size_t>(area.w,text_widget_->width()));
|
||||
dim.textbox.h = std::min<size_t>(screen.gety()/2,std::max<size_t>(area.h,text_widget_->height()));
|
||||
text_widget_width = dim.textbox.w;
|
||||
text_widget_width += (text_widget_->get_label() == nullptr) ? 0 : text_widget_->get_label()->width();
|
||||
text_widget_height = dim.textbox.h + message_font_size;
|
||||
}
|
||||
|
||||
const bool use_menu = (get_menu().height() > 0);
|
||||
if(!message_->get_text().empty()) {
|
||||
dim.message.w = message_->width();
|
||||
dim.message.h = message_->height();
|
||||
}
|
||||
unsigned int caption_width = 0;
|
||||
unsigned int caption_height = 0;
|
||||
if (image_ != nullptr && image_->caption() != nullptr) {
|
||||
caption_width = image_->caption()->width();
|
||||
caption_height = image_->caption()->height();
|
||||
}
|
||||
|
||||
int check_button_height = 0;
|
||||
int left_check_button_height = 0;
|
||||
int top_button_height = 0;
|
||||
const int button_height_padding = 5;
|
||||
|
||||
for(button_pool_const_iterator b = button_pool_.begin(); b != button_pool_.end(); ++b) {
|
||||
dialog_button const *const btn = b->first;
|
||||
switch(b->second)
|
||||
{
|
||||
case BUTTON_EXTRA:
|
||||
case BUTTON_CHECKBOX:
|
||||
check_button_height += btn->height() + button_height_padding;
|
||||
break;
|
||||
case BUTTON_EXTRA_LEFT:
|
||||
case BUTTON_CHECKBOX_LEFT:
|
||||
left_check_button_height += btn->height() + button_height_padding;
|
||||
break;
|
||||
case BUTTON_TOP:
|
||||
top_button_height += btn->height() + button_height_padding;
|
||||
break;
|
||||
case BUTTON_STANDARD:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
check_button_height = std::max<int>(check_button_height, left_check_button_height);
|
||||
|
||||
size_t above_preview_pane_height = 0, above_left_preview_pane_width = 0, above_right_preview_pane_width = 0;
|
||||
size_t preview_pane_height = 0, left_preview_pane_width = 0, right_preview_pane_width = 0;
|
||||
if(!preview_panes_.empty()) {
|
||||
for(pp_const_iterator i = preview_panes_.begin(); i != preview_panes_.end(); ++i) {
|
||||
preview_pane const *const pane = *i;
|
||||
const SDL_Rect& rect = pane->location();
|
||||
if(pane->show_above() == false) {
|
||||
preview_pane_height = std::max<size_t>(rect.h,preview_pane_height);
|
||||
if(pane->left_side()) {
|
||||
left_preview_pane_width += rect.w;
|
||||
} else {
|
||||
right_preview_pane_width += rect.w;
|
||||
}
|
||||
} else {
|
||||
above_preview_pane_height = std::max<size_t>(rect.h,above_preview_pane_height);
|
||||
if(pane->left_side()) {
|
||||
above_left_preview_pane_width += rect.w;
|
||||
} else {
|
||||
above_right_preview_pane_width += rect.w;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const int menu_hpadding = font::relative_size((dim.message.h > 0 && use_menu) ? 10 : 0);
|
||||
const size_t image_h_padding = (image_ == nullptr)? 0 : image_h_pad;
|
||||
const size_t padding_width = left_padding + right_padding + image_h_padding;
|
||||
const size_t padding_height = top_padding + bottom_padding + menu_hpadding;
|
||||
const size_t image_width = (image_ == nullptr) ? 0 : image_->width();
|
||||
const size_t image_height = (image_ == nullptr) ? 0 : image_->height();
|
||||
const size_t total_text_height = dim.message.h + caption_height;
|
||||
|
||||
size_t text_width = dim.message.w;
|
||||
if(caption_width > text_width)
|
||||
text_width = caption_width;
|
||||
|
||||
// Prevent the menu to be larger than the screen
|
||||
dim.menu_width = menu_->width();
|
||||
if(dim.menu_width + image_width + padding_width + left_preview_pane_width + right_preview_pane_width > static_cast<size_t>(scr->w))
|
||||
dim.menu_width = scr->w - image_width - padding_width - left_preview_pane_width - right_preview_pane_width;
|
||||
if(dim.menu_width > text_width)
|
||||
text_width = dim.menu_width;
|
||||
|
||||
|
||||
size_t total_width = image_width + text_width + padding_width;
|
||||
|
||||
if(text_widget_width+left_padding+right_padding > total_width)
|
||||
total_width = text_widget_width+left_padding+right_padding;
|
||||
|
||||
//Prevent the menu from being too skinny
|
||||
if(use_menu && preview_panes_.empty() &&
|
||||
total_width > dim.menu_width + image_width + padding_width) {
|
||||
dim.menu_width = total_width - image_width - padding_width;
|
||||
}
|
||||
|
||||
const size_t text_and_image_height = image_height > total_text_height ? image_height : total_text_height;
|
||||
|
||||
const int top_widgets_height = std::max<int>(text_widget_height, top_button_height);
|
||||
|
||||
const int total_height = text_and_image_height + padding_height + menu_->height() +
|
||||
top_widgets_height + check_button_height;
|
||||
|
||||
dim.interior.w = std::max<int>(total_width,above_left_preview_pane_width + above_right_preview_pane_width);
|
||||
dim.interior.h = std::max<int>(total_height,static_cast<int>(preview_pane_height));
|
||||
dim.interior.x = std::max<int>(0,dim.x >= 0 ? dim.x : scr->w/2 - (dim.interior.w + left_preview_pane_width + right_preview_pane_width)/2);
|
||||
dim.interior.y = std::max<int>(0,dim.y >= 0 ? dim.y : scr->h/2 - (dim.interior.h + above_preview_pane_height)/2);
|
||||
|
||||
DBG_DP << "above_preview_pane_height: " << above_preview_pane_height << "; "
|
||||
<< "dim.interior.y: " << scr->h/2 << " - " << (dim.interior.h + above_preview_pane_height)/2 << " = "
|
||||
<< dim.interior.y << "; " << "dim.interior.h: " << dim.interior.h << "\n";
|
||||
|
||||
if(dim.x <= -1 || dim.y <= -1) {
|
||||
dim.x = dim.interior.x + left_preview_pane_width;
|
||||
dim.y = dim.interior.y + above_preview_pane_height;
|
||||
}
|
||||
|
||||
if(dim.x + dim.interior.w > scr->w) {
|
||||
dim.x = scr->w - dim.interior.w;
|
||||
if(dim.x < dim.interior.x) {
|
||||
dim.interior.x = dim.x;
|
||||
}
|
||||
}
|
||||
|
||||
const int frame_top_pad = get_frame().top_padding();
|
||||
const int frame_bottom_pad = get_frame().bottom_padding();
|
||||
if(dim.y + dim.interior.h + frame_bottom_pad > scr->h) {
|
||||
dim.y = std::max<int>(frame_top_pad, scr->h - dim.interior.h - frame_bottom_pad);
|
||||
if(dim.y < dim.interior.y) {
|
||||
dim.interior.y = dim.y;
|
||||
}
|
||||
}
|
||||
|
||||
dim.interior.w += left_preview_pane_width + right_preview_pane_width;
|
||||
dim.interior.h += above_preview_pane_height;
|
||||
|
||||
const int max_height = scr->h - dim.interior.y - frame_bottom_pad;
|
||||
if(dim.interior.h > max_height) {
|
||||
//try to rein in the menu height a little bit
|
||||
const int menu_height = menu_->height();
|
||||
if(menu_height > 0) {
|
||||
dim.menu_height = std::max<int>(1, max_height - dim.interior.h + menu_height);
|
||||
dim.interior.h -= menu_height - dim.menu_height;
|
||||
}
|
||||
}
|
||||
|
||||
//calculate the positions of the preview panes to the sides of the dialog
|
||||
if(!preview_panes_.empty()) {
|
||||
|
||||
int left_preview_pane = dim.interior.x;
|
||||
int right_preview_pane = dim.interior.x + total_width + left_preview_pane_width;
|
||||
int above_left_preview_pane = dim.interior.x + dim.interior.w/2;
|
||||
int above_right_preview_pane = above_left_preview_pane;
|
||||
|
||||
for(pp_const_iterator i = preview_panes_.begin(); i != preview_panes_.end(); ++i) {
|
||||
preview_pane const *const pane = *i;
|
||||
SDL_Rect area = pane->location();
|
||||
|
||||
if(pane->show_above() == false) {
|
||||
area.y = dim.y;
|
||||
area.h = dim.interior.h;
|
||||
if(pane->left_side()) {
|
||||
area.x = left_preview_pane;
|
||||
left_preview_pane += area.w;
|
||||
} else {
|
||||
area.x = right_preview_pane;
|
||||
right_preview_pane += area.w;
|
||||
}
|
||||
} else {
|
||||
area.y = dim.interior.y;
|
||||
area.h = above_preview_pane_height;
|
||||
if(pane->left_side()) {
|
||||
area.x = above_left_preview_pane - area.w;
|
||||
above_left_preview_pane -= area.w;
|
||||
} else {
|
||||
area.x = above_right_preview_pane;
|
||||
above_right_preview_pane += area.w;
|
||||
}
|
||||
}
|
||||
dim.panes[*i] = area;
|
||||
}
|
||||
}
|
||||
|
||||
const int text_widget_y = dim.y + top_padding + text_and_image_height - 6 + menu_hpadding;
|
||||
|
||||
if(use_textbox) {
|
||||
dim.textbox.x = dim.x + left_padding + text_widget_width - dim.textbox.w;
|
||||
dim.textbox.y = text_widget_y + (text_widget_height - dim.textbox.h)/2;
|
||||
dim.label_x = dim.x+left_padding;
|
||||
dim.label_y = dim.textbox.y;
|
||||
}
|
||||
|
||||
if(top_buttons_.empty() == false) {
|
||||
int top_buttons_y = text_widget_y;
|
||||
|
||||
for(button_const_iterator b = top_buttons_.begin(); b != top_buttons_.end(); ++b) {
|
||||
const dialog_button& btn = **b;
|
||||
|
||||
std::pair<int, int> coords(0, 0);
|
||||
|
||||
coords.first = dim.x + total_width - btn.width() - ButtonHPadding;
|
||||
// As a special case, if there's only one button
|
||||
// and a text box, try to align the button to it
|
||||
if(top_buttons_.size() == 1 && use_textbox) {
|
||||
coords.second = text_widget_y + (text_widget_height - btn.height())/2;
|
||||
} else {
|
||||
coords.second = top_buttons_y;
|
||||
}
|
||||
|
||||
top_buttons_y += btn.height() + button_height_padding;
|
||||
|
||||
dim.buttons[*b] = coords;
|
||||
}
|
||||
}
|
||||
|
||||
dim.menu_x = dim.x+image_width+left_padding+image_h_padding;
|
||||
dim.menu_y = dim.y+top_padding+text_and_image_height+menu_hpadding+ std::max<int>(top_button_height - button_height_padding, (use_textbox ? text_widget_->location().h + top_padding : 0));
|
||||
|
||||
dim.message.x = dim.x + left_padding;
|
||||
dim.message.y = dim.y + top_padding + caption_height;
|
||||
|
||||
if(image_ != nullptr) {
|
||||
const int x = dim.x + left_padding;
|
||||
const int y = dim.y + top_padding;
|
||||
dim.message.x += image_width + image_h_padding;
|
||||
dim.image_x = x;
|
||||
dim.image_y = y;
|
||||
dim.caption_x = dim.x + image_width + left_padding + image_h_padding;
|
||||
dim.caption_y = dim.y + top_padding;
|
||||
}
|
||||
|
||||
//set the position of any tick boxes. by default, they go right below the menu,
|
||||
//slammed against the right side of the dialog
|
||||
if(extra_buttons_.empty() == false) {
|
||||
int options_y = dim.menu_y + menu_->height() + menu_hpadding + button_height_padding;
|
||||
int options_left_y = options_y;
|
||||
for(button_pool_const_iterator b = button_pool_.begin(); b != button_pool_.end(); ++b) {
|
||||
dialog_button const *const btn = b->first;
|
||||
std::pair<int,int> coords;
|
||||
switch(b->second)
|
||||
{
|
||||
case BUTTON_EXTRA:
|
||||
case BUTTON_CHECKBOX:
|
||||
coords.first = dim.x + total_width - btn->width() - ButtonHPadding;
|
||||
coords.second = options_y;
|
||||
dim.buttons[b->first] = coords;
|
||||
options_y += btn->height() + button_height_padding;
|
||||
break;
|
||||
case BUTTON_EXTRA_LEFT:
|
||||
case BUTTON_CHECKBOX_LEFT:
|
||||
coords.first = dim.x + ButtonHPadding;
|
||||
coords.second = options_left_y;
|
||||
dim.buttons[b->first] = coords;
|
||||
options_left_y += btn->height() + button_height_padding;
|
||||
break;
|
||||
case BUTTON_STANDARD:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
set_layout(dim);
|
||||
return dim;
|
||||
}
|
||||
|
||||
void dialog::set_layout(dimension_measurements &new_dim) {
|
||||
get_frame().layout(new_dim.interior);
|
||||
dim_ = new_dim;
|
||||
}
|
||||
|
||||
|
||||
int dialog::process(dialog_process_info &info)
|
||||
{
|
||||
|
||||
int mousex, mousey;
|
||||
int mouse_flags = SDL_GetMouseState(&mousex,&mousey);
|
||||
|
||||
info.new_right_button = (mouse_flags&SDL_BUTTON_RMASK) != 0;
|
||||
info.new_left_button = (mouse_flags&SDL_BUTTON_LMASK) != 0;
|
||||
info.new_key_down = info.key[SDLK_SPACE] || info.key[SDLK_RETURN] ||
|
||||
info.key[SDLK_ESCAPE] || info.key[SDLK_KP_ENTER];
|
||||
info.double_clicked = menu_->double_clicked();
|
||||
const bool use_menu = (menu_ != empty_menu);
|
||||
const bool use_text_input = (text_widget_!=nullptr);
|
||||
const bool has_input = (use_menu||use_text_input);//input of any sort has to be made
|
||||
|
||||
if((((!info.key_down && (info.key[SDLK_RETURN] || info.key[SDLK_KP_ENTER])) || info.double_clicked) &&
|
||||
(type_ == YES_NO || type_ == OK_CANCEL || type_ == OK_ONLY || type_ == CLOSE_ONLY))) {
|
||||
|
||||
return (use_menu ? menu_->selection() : 0);
|
||||
}
|
||||
|
||||
//escape quits from the dialog -- unless it's an "ok" dialog with input
|
||||
if(!info.key_down && info.key[SDLK_ESCAPE] && !(type_ == OK_ONLY && has_input)) {
|
||||
return (CLOSE_DIALOG);
|
||||
}
|
||||
|
||||
//inform preview panes when there is a new menu selection
|
||||
if((menu_->selection() != info.selection) || info.first_time) {
|
||||
info.selection = menu_->selection();
|
||||
int selection = info.selection;
|
||||
if(selection < 0) {
|
||||
selection = 0;
|
||||
}
|
||||
if(!preview_panes_.empty()) {
|
||||
for(pp_iterator i = preview_panes_.begin(); i != preview_panes_.end(); ++i) {
|
||||
(**i).set_selection(selection);
|
||||
if(info.first_time) {
|
||||
(**i).set_dirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
info.first_time = false;
|
||||
|
||||
if(use_menu) {
|
||||
//get any drop-down choice or context-menu click
|
||||
const int selection = menu_->process();
|
||||
if(selection != -1)
|
||||
{
|
||||
return (selection);
|
||||
}
|
||||
}
|
||||
|
||||
draw_frame();
|
||||
//draw_contents();
|
||||
|
||||
events::raise_process_event();
|
||||
events::raise_draw_event();
|
||||
|
||||
//left-clicking outside of a drop-down or context-menu should close it
|
||||
if (info.new_left_button && !info.left_button) {
|
||||
if (standard_buttons_.empty() && !sdl::point_in_rect(mousex,mousey, menu_->location())) {
|
||||
if (use_menu)
|
||||
sound::play_UI_sound(game_config::sounds::button_press);
|
||||
return CLOSE_DIALOG;
|
||||
}
|
||||
}
|
||||
|
||||
//right-clicking outside of a dialog should close it unless a choice is required
|
||||
//note: this will also close any context-menu or drop-down when it is right-clicked
|
||||
// but that may be changed to allow right-click selection instead.
|
||||
if (info.new_right_button && !info.right_button) {
|
||||
if( standard_buttons_.empty()
|
||||
|| (!sdl::point_in_rect(mousex,mousey,get_frame().get_layout().exterior)
|
||||
&& type_ != YES_NO && !(type_ == OK_ONLY && has_input))) {
|
||||
sound::play_UI_sound(game_config::sounds::button_press);
|
||||
return CLOSE_DIALOG;
|
||||
}
|
||||
}
|
||||
|
||||
//any keypress should close a dialog if it has one standard button (or less)
|
||||
//and no menu options.
|
||||
if (info.new_key_down && !info.key_down) {
|
||||
if (standard_buttons_.size() < 2 && !has_input)
|
||||
return CLOSE_DIALOG;
|
||||
}
|
||||
|
||||
//now handle any button presses
|
||||
for(button_pool_iterator b = button_pool_.begin(); b != button_pool_.end(); ++b) {
|
||||
if(b->first->pressed()) {
|
||||
return b->first->action(info);
|
||||
}
|
||||
}
|
||||
|
||||
return CONTINUE_DIALOG;
|
||||
}
|
||||
|
||||
int dialog_button::action(dialog_process_info &info) {
|
||||
if(handler_ != nullptr) {
|
||||
menu &menu_ref = parent_->get_menu();
|
||||
dialog_button_action::RESULT res = handler_->button_pressed(menu_ref.selection());
|
||||
dialog_button_action::RESULT res = handler_->button_pressed();
|
||||
|
||||
if(res == DELETE_ITEM || res == CLOSE_DIALOG) {
|
||||
if( res == CLOSE_DIALOG) {
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -871,122 +53,4 @@ int dialog_button::action(dialog_process_info &info) {
|
|||
return simple_result_;
|
||||
}
|
||||
|
||||
void dialog::action(dialog_process_info& info)
|
||||
{
|
||||
//default way of handling a "delete item" request
|
||||
if(result() == DELETE_ITEM) {
|
||||
const int selection = menu_->selection();
|
||||
if(selection >= 0) {
|
||||
menu_->erase_item(selection);
|
||||
}
|
||||
// was used before to auto close empty menu
|
||||
//if(menu_->number_of_items() == 0) {
|
||||
// set_result(CLOSE_DIALOG);
|
||||
//} else {
|
||||
|
||||
set_result(CONTINUE_DIALOG);
|
||||
info.first_time = true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int standard_dialog_button::action(dialog_process_info &/*info*/) {
|
||||
//if the menu is not used, then return the index of the
|
||||
//button pressed, otherwise return the index of the menu
|
||||
//item selected if the last button is not pressed, and
|
||||
//cancel (-1) otherwise
|
||||
if(dialog()->get_menu().height() <= 0) {
|
||||
return simple_result_;
|
||||
} else if((simple_result_ == 0 && is_last_) || !is_last_) {
|
||||
return (dialog()->get_menu().selection());
|
||||
}
|
||||
return CLOSE_DIALOG;
|
||||
}
|
||||
|
||||
void dialog::set_image(surface surf, const std::string &caption)
|
||||
{
|
||||
label *label_ptr = nullptr;
|
||||
if(!caption.empty()) {
|
||||
label_ptr = new label(video_, caption, caption_font_size, font::NORMAL_COLOR, false);
|
||||
}
|
||||
set_image( new dialog_image(label_ptr, video_, surf ));
|
||||
}
|
||||
|
||||
void dialog_image::draw_contents()
|
||||
{
|
||||
video().blit_surface(location().x, location().y, surf_);
|
||||
}
|
||||
|
||||
int filter_textbox::get_index(int selection) const {
|
||||
// don't translate special values
|
||||
if(selection < 0) {
|
||||
return selection;
|
||||
}
|
||||
//we must the header row value to the index to ignore this row and
|
||||
//then subtract it from the result to return the index not including
|
||||
//the possible header row.
|
||||
|
||||
if (selection + header_row_ >= index_map_.size()) {
|
||||
return -1; // bad index, cancel
|
||||
}
|
||||
|
||||
return index_map_[selection+header_row_]-header_row_;
|
||||
}
|
||||
|
||||
void filter_textbox::delete_item(int selection) {
|
||||
// use the real selection
|
||||
size_t adjusted_selection = selection + header_row_;
|
||||
|
||||
if (adjusted_selection >= index_map_.size())
|
||||
return;
|
||||
|
||||
filtered_items_.erase(filtered_items_.begin() + adjusted_selection);
|
||||
items_to_filter_.erase(items_to_filter_.begin() + index_map_[adjusted_selection]);
|
||||
items_.erase(items_.begin() + index_map_[adjusted_selection]);
|
||||
index_map_.erase(index_map_.begin() + adjusted_selection);
|
||||
|
||||
// don't forget to also shift the next index values
|
||||
// this assume that index_map_and items_ have the same order
|
||||
for(size_t i = adjusted_selection; i < index_map_.size(); ++i) {
|
||||
index_map_[i] = index_map_[i]-1;
|
||||
}
|
||||
|
||||
//for now, assume the dialog menu item is deleted using DELETE_ITEM
|
||||
/* dialog_.set_menu_items(filtered_items_); */
|
||||
}
|
||||
|
||||
void filter_textbox::handle_text_changed(const ucs4::string& text) {
|
||||
const std::vector<std::string> words = utils::split(unicode_cast<utf8::string>(text),' ');
|
||||
if (words == last_words)
|
||||
return;
|
||||
last_words = words;
|
||||
|
||||
filtered_items_.clear();
|
||||
index_map_.clear();
|
||||
|
||||
if(header_row_ == 1) {
|
||||
filtered_items_.push_back(items_[0]);
|
||||
index_map_.push_back(0);
|
||||
}
|
||||
|
||||
// we keep all items containing each word
|
||||
for(size_t n = header_row_; n < items_to_filter_.size(); ++n) {
|
||||
std::vector<std::string>::const_iterator w = words.begin();
|
||||
for(; w != words.end(); ++w)
|
||||
{
|
||||
if (std::search(items_to_filter_[n].begin(), items_to_filter_[n].end(),
|
||||
w->begin(), w->end(),
|
||||
chars_equal_insensitive) == items_to_filter_[n].end())
|
||||
break; // one word doesn't match, we don't reach words.end()
|
||||
}
|
||||
if (w == words.end()) {
|
||||
// all words have matched, keep the item
|
||||
filtered_items_.push_back(items_[n]);
|
||||
index_map_.push_back(n);
|
||||
}
|
||||
}
|
||||
|
||||
dialog_.set_menu_items(filtered_items_);
|
||||
}
|
||||
|
||||
}//end namespace gui
|
||||
|
|
|
@ -65,273 +65,22 @@ private:
|
|||
bool clear_buttons_;
|
||||
};
|
||||
|
||||
class dialog_image : public widget {
|
||||
public:
|
||||
dialog_image(label *const caption, CVideo &video, surface img) : widget(video, false),
|
||||
surf_(img), caption_(caption)
|
||||
{
|
||||
if(!img.null()) {
|
||||
set_measurements(img->w, img->h);
|
||||
}
|
||||
}
|
||||
~dialog_image() { delete caption_; }
|
||||
|
||||
//surface surface() const { return surf_; }
|
||||
label *caption() const { return caption_; }
|
||||
void draw_contents();
|
||||
|
||||
sdl_handler_vector handler_members() {
|
||||
sdl_handler_vector h;
|
||||
if(caption_) h.push_back(caption_);
|
||||
return h;
|
||||
}
|
||||
private:
|
||||
|
||||
surface surf_;
|
||||
label *caption_;
|
||||
};
|
||||
|
||||
class dialog_textbox : public textbox {
|
||||
public:
|
||||
dialog_textbox(label *const label_widget, CVideo &video, int width, const std::string& text="", bool editable=true, size_t max_size = 256, int font_size = font::SIZE_PLUS, double alpha = 0.4, double alpha_focus = 0.2)
|
||||
: textbox(video, width, text, editable, max_size, font_size, alpha, alpha_focus, false),
|
||||
label_(label_widget)
|
||||
{}
|
||||
virtual ~dialog_textbox();
|
||||
|
||||
label *get_label() const { return label_; }
|
||||
|
||||
sdl_handler_vector handler_members() {
|
||||
sdl_handler_vector h = textbox::handler_members();
|
||||
if(label_) h.push_back(label_);
|
||||
return h;
|
||||
}
|
||||
private:
|
||||
//forbidden operations
|
||||
dialog_textbox(const dialog_textbox&);
|
||||
void operator=(const dialog_textbox&);
|
||||
|
||||
label *label_;
|
||||
};
|
||||
|
||||
class dialog;
|
||||
|
||||
class filter_textbox : public gui::dialog_textbox {
|
||||
public:
|
||||
filter_textbox(CVideo& video, const std::string& header,
|
||||
const std::vector<std::string>& items,
|
||||
const std::vector<std::string>& items_to_filter, size_t header_row,
|
||||
dialog& dialog, int width = 250) :
|
||||
dialog_textbox(new label(video, header), video, width),
|
||||
items_(items),
|
||||
items_to_filter_(items_to_filter),
|
||||
filtered_items_(),
|
||||
index_map_(),
|
||||
last_words(1, ""), // dummy word to trigger an update
|
||||
header_row_(header_row),
|
||||
dialog_(dialog)
|
||||
{
|
||||
set_text("");
|
||||
}
|
||||
|
||||
// current menu selection is based on a possibly filtered view,
|
||||
// and thus may differ from the original, unfiltered index
|
||||
int get_index(int selection) const;
|
||||
void delete_item(int selection);
|
||||
|
||||
private:
|
||||
std::vector<std::string> items_, items_to_filter_, filtered_items_;
|
||||
std::vector<int> index_map_;
|
||||
std::vector<std::string> last_words;
|
||||
size_t header_row_;
|
||||
gui::dialog& dialog_;
|
||||
virtual void handle_text_changed(const ucs4::string& text);
|
||||
};
|
||||
|
||||
class dialog_button : public button {
|
||||
public:
|
||||
dialog_button(CVideo& video, const std::string& label, TYPE type=TYPE_PRESS,
|
||||
int simple_result=CONTINUE_DIALOG, dialog_button_action *handler=nullptr)
|
||||
: button(video,label,type,"",DEFAULT_SPACE,false), simple_result_(simple_result),
|
||||
parent_(nullptr), handler_(handler)
|
||||
handler_(handler)
|
||||
{}
|
||||
void set_parent(class dialog *parent) {
|
||||
parent_ = parent;
|
||||
}
|
||||
bool is_option() const {
|
||||
return (type_ == TYPE_CHECK);
|
||||
}
|
||||
virtual int action(dialog_process_info &info);
|
||||
protected:
|
||||
class dialog *dialog() const { return parent_; }
|
||||
const int simple_result_;
|
||||
private:
|
||||
class dialog *parent_;
|
||||
dialog_button_action *handler_;
|
||||
};
|
||||
|
||||
class standard_dialog_button : public dialog_button {
|
||||
public:
|
||||
standard_dialog_button(CVideo& video, const std::string& label, const int index, const bool is_last)
|
||||
: dialog_button(video,label,TYPE_PRESS,index), is_last_(is_last)
|
||||
{}
|
||||
int action(dialog_process_info &info);
|
||||
private:
|
||||
const bool is_last_;
|
||||
};
|
||||
|
||||
|
||||
class dialog {
|
||||
public:
|
||||
enum BUTTON_LOCATION { BUTTON_STANDARD, BUTTON_EXTRA, BUTTON_EXTRA_LEFT, BUTTON_CHECKBOX, BUTTON_CHECKBOX_LEFT, BUTTON_HELP, BUTTON_TOP };
|
||||
struct dimension_measurements {
|
||||
dimension_measurements();
|
||||
int x, y;
|
||||
SDL_Rect interior, message, textbox;
|
||||
unsigned int menu_width;
|
||||
std::map<preview_pane *, SDL_Rect > panes;
|
||||
int label_x, label_y;
|
||||
int menu_x, menu_y, menu_height;
|
||||
int image_x, image_y, caption_x, caption_y;
|
||||
std::map<dialog_button *, std::pair<int,int> > buttons;
|
||||
//use get_frame().get_layout() to check frame dimensions
|
||||
};
|
||||
typedef dialog_frame::style style;
|
||||
|
||||
private:
|
||||
typedef std::vector<preview_pane *>::iterator pp_iterator;
|
||||
typedef std::vector<preview_pane *>::const_iterator pp_const_iterator;
|
||||
typedef std::vector<dialog_button *>::iterator button_iterator;
|
||||
typedef std::vector<dialog_button *>::const_iterator button_const_iterator;
|
||||
typedef std::vector< std::pair<dialog_button *, BUTTON_LOCATION> >::iterator button_pool_iterator;
|
||||
typedef std::vector< std::pair<dialog_button *, BUTTON_LOCATION> >::const_iterator button_pool_const_iterator;
|
||||
|
||||
public:
|
||||
|
||||
//Static members
|
||||
static const style& default_style;
|
||||
static const style& message_style;
|
||||
static const style hotkeys_style;
|
||||
static const int message_font_size;
|
||||
static const int caption_font_size;
|
||||
static const int max_menu_width;
|
||||
static const size_t left_padding;
|
||||
static const size_t right_padding;
|
||||
static const size_t image_h_pad;
|
||||
static const size_t top_padding;
|
||||
static const size_t bottom_padding;
|
||||
|
||||
//Constructor & destructor
|
||||
//dialog - throws button::error() if standard buttons fail to initialize
|
||||
// throws utf8::invalid_utf8_exception() if message is invalid
|
||||
dialog(CVideo& video,
|
||||
const std::string& title="",
|
||||
const std::string& message="",
|
||||
const DIALOG_TYPE type=MESSAGE,
|
||||
const style& dialog_style=default_style);
|
||||
virtual ~dialog();
|
||||
|
||||
//Adding components - the dialog will manage the memory of
|
||||
//these widgets, therefore do not attempt to reference its
|
||||
//widgets after destroying it
|
||||
void set_image(dialog_image *const img) { delete image_; image_ = img; }
|
||||
void set_image(surface surf, const std::string &caption="");
|
||||
void set_menu(menu *const m) { if ( menu_ != empty_menu ) delete menu_;
|
||||
menu_ = m == nullptr ? empty_menu : m; }
|
||||
void set_menu(const std::vector<std::string> & menu_items, menu::sorter* sorter=nullptr);
|
||||
void set_menu_items(const std::vector<std::string> &menu_items, bool keep_selection=false);
|
||||
|
||||
//add_pane - preview panes are not currently memory managed
|
||||
//(for backwards compatibility)
|
||||
void add_pane(preview_pane *const pp) { preview_panes_.push_back(pp); }
|
||||
void set_panes(std::vector<preview_pane*> panes) { preview_panes_ = panes; }
|
||||
void set_textbox(dialog_textbox *const box) {
|
||||
delete text_widget_;
|
||||
text_widget_ = box;
|
||||
}
|
||||
void set_textbox(const std::string& text_widget_label="",
|
||||
const std::string &text_widget_text="",
|
||||
const int text_widget_max_chars = 256,
|
||||
const unsigned int text_box_width = font::relative_size(350));
|
||||
void add_button(dialog_button *const btn, BUTTON_LOCATION loc);
|
||||
void add_button(dialog_button_info btn_info, BUTTON_LOCATION loc=BUTTON_EXTRA);
|
||||
void add_option(const std::string& label, bool checked=false, BUTTON_LOCATION loc=BUTTON_CHECKBOX, const std::string& help_string = "");
|
||||
|
||||
//Specific preparations
|
||||
//layout - determines dialog measurements based on all components
|
||||
virtual dimension_measurements layout(int xloc=-1, int yloc=-1);
|
||||
void set_layout(dimension_measurements &new_dim);
|
||||
dimension_measurements get_layout() const { return dim_; }
|
||||
dialog_frame& get_frame();
|
||||
void set_basic_behavior(DIALOG_TYPE type) { type_ = type; }
|
||||
|
||||
//Launching the dialog
|
||||
//show - the return value of this method should be the same as result()
|
||||
int show(int xloc, int yloc);
|
||||
int show();
|
||||
|
||||
//Results
|
||||
int result() const { return result_; }
|
||||
menu &get_menu() { return *menu_; }
|
||||
bool done() const { return (result_ != CONTINUE_DIALOG); }
|
||||
std::string textbox_text() const { return text_widget_->text();}
|
||||
dialog_textbox& get_textbox() const { return *text_widget_; }
|
||||
bool option_checked(unsigned int option_index=0);
|
||||
CVideo& get_video() { return video_; }
|
||||
|
||||
/// Explicit freeing of class static resources.
|
||||
/// Must not be called if any instances of this class exist.
|
||||
/// Should be called if the display goes out of scope.
|
||||
/// (Currently called by ~game_launcher.)
|
||||
static void delete_empty_menu() { delete empty_menu; empty_menu = nullptr; }
|
||||
|
||||
protected:
|
||||
void set_result(const int result) { result_ = result; }
|
||||
|
||||
//action - invoked at the end of the dialog-processing loop
|
||||
virtual void action(dialog_process_info &dp_info);
|
||||
//refresh - forces the display to refresh
|
||||
void refresh();
|
||||
|
||||
label& get_message() const { return *message_; }
|
||||
|
||||
private:
|
||||
void clear_background();
|
||||
void draw_frame();
|
||||
void update_widget_positions();
|
||||
void draw_contents();
|
||||
|
||||
//process - execute a single dialog processing loop and return the result
|
||||
int process(dialog_process_info &info);
|
||||
|
||||
/// A pointer to this empty menu is used instead of nullptr (for menu_).
|
||||
static menu * empty_menu;
|
||||
/// Provides create-on-use semantics for empty_menu.
|
||||
static menu * get_empty_menu(CVideo& video);
|
||||
|
||||
//Members
|
||||
CVideo& video_;
|
||||
dialog_image *image_;
|
||||
std::string title_;
|
||||
const style& style_;
|
||||
label *title_widget_, *message_;
|
||||
DIALOG_TYPE type_;
|
||||
gui::menu *menu_; // Never nullptr; it equals empty_menu if there is currently no menu.
|
||||
std::vector<preview_pane*> preview_panes_;
|
||||
std::vector< std::pair<dialog_button*,BUTTON_LOCATION> > button_pool_;
|
||||
std::vector<dialog_button*> standard_buttons_;
|
||||
std::vector<dialog_button*> extra_buttons_;
|
||||
std::vector<dialog_button*> top_buttons_;
|
||||
std::vector<button*> frame_buttons_;
|
||||
std::string topic_;
|
||||
dialog_button *help_button_;
|
||||
dialog_textbox *text_widget_;
|
||||
dialog_frame *frame_;
|
||||
dimension_measurements dim_;
|
||||
int result_;
|
||||
};
|
||||
|
||||
typedef Uint32 msecs;
|
||||
|
||||
} //end namespace gui
|
||||
#endif
|
||||
|
|
|
@ -1007,7 +1007,6 @@ void game_launcher::clear_loaded_game()
|
|||
game_launcher::~game_launcher()
|
||||
{
|
||||
try {
|
||||
gui::dialog::delete_empty_menu();
|
||||
sound::close_sound();
|
||||
} catch (...) {}
|
||||
}
|
||||
|
|
|
@ -365,69 +365,5 @@ void dialog_frame::draw()
|
|||
dirty_ = false;
|
||||
}
|
||||
|
||||
int show_dialog(CVideo& video, surface image,
|
||||
const std::string& caption, const std::string& message,
|
||||
DIALOG_TYPE type,
|
||||
const std::vector<std::string>* menu_items,
|
||||
const std::vector<preview_pane*>* preview_panes,
|
||||
const std::string& text_widget_label,
|
||||
std::string* text_widget_text,
|
||||
const int text_widget_max_chars,
|
||||
std::vector<check_item>* options,
|
||||
int xloc,
|
||||
int yloc,
|
||||
const dialog_frame::style* dialog_style,
|
||||
std::vector<dialog_button_info>* action_buttons,
|
||||
const menu::sorter* sorter,
|
||||
menu::style* menu_style)
|
||||
{
|
||||
std::string title;
|
||||
if (image.null()) title = caption;
|
||||
const dialog::style& style = (dialog_style)? *dialog_style : dialog::default_style;
|
||||
|
||||
gui::dialog d(video, title, message, type, style);
|
||||
|
||||
//add the components
|
||||
if(!image.null()) {
|
||||
d.set_image(image, caption);
|
||||
}
|
||||
if(menu_items) {
|
||||
d.set_menu( new gui::menu(video,*menu_items,type == MESSAGE,-1,dialog::max_menu_width,sorter,menu_style,false));
|
||||
}
|
||||
if(preview_panes) {
|
||||
for(unsigned int i=0; i < preview_panes->size(); ++i) {
|
||||
d.add_pane((*preview_panes)[i]);
|
||||
}
|
||||
}
|
||||
if(text_widget_text) {
|
||||
d.set_textbox(text_widget_label,*text_widget_text, text_widget_max_chars);
|
||||
}
|
||||
if(options) {
|
||||
for(unsigned int i=0; i < options->size(); ++i) {
|
||||
check_item& item = (*options)[i];
|
||||
d.add_option(item.label, item.checked);
|
||||
}
|
||||
}
|
||||
if(action_buttons) {
|
||||
for(unsigned int i=0; i < action_buttons->size(); ++i) {
|
||||
d.add_button((*action_buttons)[i]);
|
||||
}
|
||||
}
|
||||
//enter the dialog loop
|
||||
d.show(xloc, yloc);
|
||||
|
||||
//send back results
|
||||
if(options) {
|
||||
for(unsigned int i=0; i < options->size(); ++i)
|
||||
{
|
||||
(*options)[i].checked = d.option_checked(i);
|
||||
}
|
||||
}
|
||||
if(text_widget_text) {
|
||||
*text_widget_text = d.textbox_text();
|
||||
}
|
||||
return d.result();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -146,61 +146,9 @@ public:
|
|||
|
||||
typedef DIALOG_RESULT RESULT;
|
||||
|
||||
virtual RESULT button_pressed(int menu_selection) = 0;
|
||||
virtual RESULT button_pressed() = 0;
|
||||
};
|
||||
|
||||
struct dialog_button_info
|
||||
{
|
||||
dialog_button_info(dialog_button_action* handler, const std::string& label) : handler(handler), label(label)
|
||||
{}
|
||||
|
||||
dialog_button_action* handler;
|
||||
std::string label;
|
||||
};
|
||||
|
||||
enum DIALOG_TYPE { MESSAGE, OK_ONLY, YES_NO, OK_CANCEL, CANCEL_ONLY, CLOSE_ONLY, NULL_DIALOG };
|
||||
|
||||
struct check_item {
|
||||
check_item(const std::string& label, bool checked) : label(label), checked(checked) {}
|
||||
std::string label;
|
||||
bool checked;
|
||||
};
|
||||
|
||||
//an interface for a 'preview pane'. A preview pane is shown beside a dialog created
|
||||
//by 'show_dialog' and shows information about the selection.
|
||||
class preview_pane : public widget {
|
||||
public:
|
||||
preview_pane(CVideo &video) : widget(video, false) {}
|
||||
virtual ~preview_pane() { tooltips::clear_tooltips(location()); }
|
||||
|
||||
virtual bool show_above() const { return false; }
|
||||
virtual bool left_side() const = 0;
|
||||
virtual void set_selection(int index) = 0;
|
||||
virtual sdl_handler_vector handler_members() { return widget::handler_members(); }
|
||||
};
|
||||
|
||||
//if a menu is given, then returns -1 if the dialog was canceled, and the
|
||||
//index of the selection otherwise. If no menu is given, returns the index
|
||||
//of the button that was pressed
|
||||
int show_dialog(CVideo& video, surface image,
|
||||
const std::string& caption, const std::string& message,
|
||||
DIALOG_TYPE type=MESSAGE,
|
||||
const std::vector<std::string>* menu_items=nullptr,
|
||||
const std::vector<preview_pane*>* preview_panes=nullptr,
|
||||
const std::string& text_widget_label="",
|
||||
std::string* text_widget_text=nullptr,
|
||||
const int text_widget_max_chars = 256,
|
||||
std::vector<check_item>* options=nullptr,
|
||||
int xloc=-1,
|
||||
int yloc=-1,
|
||||
const dialog_frame::style* dialog_style=nullptr,
|
||||
std::vector<dialog_button_info>* buttons=nullptr,
|
||||
const menu::sorter* sorter=nullptr,
|
||||
menu::style* menu_style=nullptr
|
||||
);
|
||||
|
||||
void check_quit(CVideo &video);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue