wesnoth/src/widgets/menu.hpp
Thomas Baumhauer c647a5b48c fix scrolling through the player list in the mp lobby:
...trying to preserve the selected player the viewport of the list
would always be reset to show the selected player
2009-01-10 11:37:02 +00:00

318 lines
8.5 KiB
C++

/* $Id$ */
/*
Copyright (C) 2003 - 2009 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 WIDGET_MENU_HPP_INCLUDED
#define WIDGET_MENU_HPP_INCLUDED
#include <map>
#include <set>
#include <string>
#include <vector>
#include "../image.hpp"
#include "../events.hpp"
#include "../sdl_utils.hpp"
#include "scrollarea.hpp"
#include "SDL.h"
namespace gui {
class menu;
extern menu *empty_menu;
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 size_t row_index, const SDL_Rect& rect, ROW_TYPE type);
virtual void draw_row(menu& menu_ref, const 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;
size_t get_font_size() const;
size_t get_cell_padding() const;
size_t get_thickness() const;
protected:
size_t font_size_;
size_t cell_padding_;
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 selction 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 size_t row_index, const SDL_Rect& rect, ROW_TYPE type);
virtual void draw_row(menu& menu_ref, const 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_;
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, size_t id)
: fields(fields), help(), id(id)
{}
std::vector<std::string> fields;
std::vector<std::string> help;
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_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_;
std::map<int,int> redirect_sort_;
std::map<int,std::vector<int> > pos_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=NULL, style *menu_style=NULL, const bool auto_join=true);
int selection() const;
void move_selection(size_t id);
void move_selection_keeping_viewport(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);
void erase_item(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.
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);
size_t nitems() 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);
void wrap_words();
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=NULL) const;
const std::vector<int>& column_widths() const;
virtual void draw_row(const size_t row_index, const SDL_Rect& rect, ROW_TYPE type);
style *style_;
bool silent_;
private:
size_t max_items_onscreen() const;
size_t heading_height() const;
int max_height_, max_width_;
mutable int max_items_, item_height_;
void adjust_viewport_to_selection();
void key_press(SDLKey key);
std::vector<item> items_;
std::vector<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_;
size_t selected_;
bool click_selects_;
bool out_;
bool previous_button_;
//std::set<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();
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;
mutable std::map<int,SDL_Rect> itemRects_;
SDL_Rect get_item_rect(int item) const;
SDL_Rect get_item_rect_internal(size_t pos) const;
size_t get_item_height_internal(const std::vector<std::string>& item) const;
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 wont 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(size_t pos, bool silent=false, SELECTION_MOVE_VIEWPORT move_viewport=MOVE_VIEWPORT);
void move_selection_to(size_t id, bool silent=false, SELECTION_MOVE_VIEWPORT move_viewport=MOVE_VIEWPORT);
void move_selection_up(size_t dep);
void move_selection_down(size_t dep);
void invalidate_row(size_t id);
void invalidate_row_pos(size_t pos);
void invalidate_heading();
std::set<int> invalid_;
};
}
#endif