mirror of
https://github.com/wesnoth/wesnoth
synced 2025-05-07 14:54:21 +00:00
343 lines
10 KiB
C++
343 lines
10 KiB
C++
/* $Id$ */
|
|
/*
|
|
Copyright (C) 2006 - 2009 by Patrick Parker <patrick_x99@hotmail.com>
|
|
wesnoth widget 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 version 2
|
|
or at your option any later version.
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY.
|
|
|
|
See the COPYING file for more details.
|
|
*/
|
|
|
|
#ifndef CONSTRUCT_DIALOG_H_INCLUDED
|
|
#define CONSTRUCT_DIALOG_H_INCLUDED
|
|
|
|
#include "show_dialog.hpp"
|
|
|
|
#include "widgets/label.hpp"
|
|
#include "widgets/textbox.hpp"
|
|
#include "widgets/button.hpp"
|
|
#include "widgets/menu.hpp"
|
|
#include "key.hpp"
|
|
#include "sdl_utils.hpp"
|
|
|
|
namespace gui {
|
|
|
|
struct dialog_process_info
|
|
{
|
|
public:
|
|
dialog_process_info() :
|
|
key(),
|
|
left_button(true),
|
|
right_button(true),
|
|
key_down(true),
|
|
first_time(true),
|
|
double_clicked(false),
|
|
new_left_button(false),
|
|
new_right_button(false),
|
|
new_key_down(false),
|
|
selection(-1),
|
|
clear_buttons_(false)
|
|
{}
|
|
|
|
void clear_buttons() {
|
|
clear_buttons_ = true;
|
|
}
|
|
|
|
void cycle() {
|
|
if(clear_buttons_) {
|
|
left_button = true;
|
|
right_button = true;
|
|
key_down = true;
|
|
clear_buttons_ = false;
|
|
} else {
|
|
left_button = new_left_button;
|
|
right_button = new_right_button;
|
|
key_down = new_key_down;
|
|
}
|
|
}
|
|
CKey key;
|
|
bool left_button, right_button, key_down, first_time, double_clicked;
|
|
bool new_left_button, new_right_button, new_key_down;
|
|
int selection;
|
|
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();
|
|
|
|
handler_vector handler_members() {
|
|
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, double alpha = 0.4, double alpha_focus = 0.2)
|
|
: textbox(video, width, text, editable, max_size, alpha, alpha_focus, false),
|
|
label_(label_widget)
|
|
{}
|
|
virtual ~dialog_textbox();
|
|
|
|
label *get_label() const { return label_; }
|
|
|
|
handler_vector handler_members() {
|
|
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 wide_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=NULL)
|
|
: button(video,label,type,"",DEFAULT_SPACE,false), simple_result_(simple_result),
|
|
parent_(NULL), 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 };
|
|
struct dimension_measurements {
|
|
dimension_measurements();
|
|
int x, y;
|
|
SDL_Rect interior, message, textbox;
|
|
unsigned int menu_width;
|
|
std::map<preview_pane *const, 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 *const, 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 utils::invalid_utf8_exception() if message is invalid
|
|
dialog(display &disp,
|
|
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; }
|
|
void set_menu(const std::vector<std::string> & menu_items, menu::sorter* sorter=NULL);
|
|
void set_menu_items(const std::vector<std::string> &menu_items);
|
|
|
|
//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);
|
|
|
|
//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();
|
|
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);
|
|
display& get_display() { return disp_; }
|
|
|
|
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);
|
|
|
|
//Members
|
|
display &disp_;
|
|
dialog_image *image_;
|
|
std::string title_;
|
|
const style& style_;
|
|
label *title_widget_, *message_;
|
|
DIALOG_TYPE type_;
|
|
gui::menu *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<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;
|
|
const msecs three_blinks = 300; // 3 times the 0.1sec human reflex-arc time
|
|
|
|
class message_dialog : public gui::dialog
|
|
{
|
|
public:
|
|
message_dialog(display &disp, const std::string& title="", const std::string& message="", const gui::DIALOG_TYPE type=gui::MESSAGE)
|
|
: dialog(disp, title, message, type, message_style), prevent_misclick_until_(0)
|
|
{}
|
|
~message_dialog();
|
|
int show(msecs minimum_lifetime = three_blinks);
|
|
protected:
|
|
void action(gui::dialog_process_info &dp_info);
|
|
private:
|
|
msecs prevent_misclick_until_;
|
|
};
|
|
|
|
} //end namespace gui
|
|
#endif
|