GUI1 multi-selection menu widget.

This commit is contained in:
Lipka Boldizsár 2015-07-25 17:56:12 +02:00
parent 116991f618
commit daa214072b
5 changed files with 179 additions and 12 deletions

View file

@ -1092,6 +1092,7 @@ set(libwesnoth-game_STAT_SRC
widgets/label.cpp
widgets/menu.cpp
widgets/menu_style.cpp
widgets/multimenu.cpp
widgets/progressbar.cpp
widgets/scrollarea.cpp
widgets/scrollbar.cpp

View file

@ -137,6 +137,7 @@ libwesnoth_sources = Split("""
widgets/label.cpp
widgets/menu.cpp
widgets/menu_style.cpp
widgets/multimenu.cpp
widgets/progressbar.cpp
widgets/scrollarea.cpp
widgets/scrollbar.cpp

View file

@ -182,7 +182,7 @@ public:
// 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);
virtual void erase_item(size_t index);
void set_heading(const std::vector<std::string>& heading);
@ -190,7 +190,7 @@ public:
/// 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,
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
@ -228,6 +228,18 @@ protected:
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(size_t id);
void invalidate_row_pos(size_t pos);
void invalidate_heading();
private:
size_t max_items_onscreen() const;
@ -268,12 +280,6 @@ private:
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_;
@ -320,10 +326,6 @@ private:
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_;
};

80
src/widgets/multimenu.cpp Normal file
View file

@ -0,0 +1,80 @@
/*
Copyright (C) 2015 by Boldizsár Lipka <lipkab@zoho.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.
*/
#include "multimenu.hpp"
#include "image.hpp"
#include "video.hpp"
namespace gui {
multimenu::multimenu(CVideo &video, const std::vector<std::string> &items, bool click_selects, int max_height,
int max_width, const menu::sorter *sorter_obj, menu::style *menu_style, const bool auto_join) :
menu(video, items, click_selects, max_height, max_width, sorter_obj, menu_style, auto_join),
active_items_(items.size(), false) {}
void multimenu::draw_row(const size_t row_index, const SDL_Rect &rect, menu::ROW_TYPE type) {
surface img = image::get_image(active_items_[row_index]
? "buttons/checkbox-pressed.png"
: "buttons/checkbox.png");
blit_surface(img, NULL, video().getSurface(), &rect);
SDL_Rect newrect = {
(Sint16) (rect.x + img->w + 2),
rect.y,
(Uint16) (rect.w - img->w - 2),
rect.h
};
menu::draw_row(row_index, newrect, type);
}
void multimenu::handle_event(const SDL_Event &event) {
if (event.type == SDL_MOUSEBUTTONDOWN) {
int hit_box = hit_checkbox(event.button.x, event.button.y);
if (hit_box != -1) {
active_items_[hit_box] = !active_items_[hit_box];
invalidate_row_pos(hit_box);
last_changed_ = hit_box;
return;
}
}
menu::handle_event(event);
}
int multimenu::hit_checkbox(int x, int y) const {
int cb_width = image::get_image("buttons/checkbox-pressed.png")->w;
return x > inner_location().x + cb_width ? -1 : hit(x, y);
}
void multimenu::erase_item(size_t index) {
active_items_.erase(active_items_.begin() + index);
menu::erase_item(index);
last_changed_ = -1;
}
void multimenu::set_items(const std::vector<std::string> &items, bool strip_spaces, bool keep_viewport) {
active_items_.resize(items.size());
std::fill(active_items_.begin(), active_items_.end(), false);
last_changed_ = -1;
menu::set_items(items, strip_spaces, keep_viewport);
}
void multimenu::set_active(size_t index, bool active) {
active_items_[index] = active;
invalidate_row_pos(index);
}
int multimenu::last_changed() {
int result = last_changed_;
last_changed_ = -1;
return result;
}
}

83
src/widgets/multimenu.hpp Normal file
View file

@ -0,0 +1,83 @@
/*
Copyright (C) 2015 by Boldizsár Lipka <lipkab@zoho.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.
*/
#ifndef WIDGETS_MULTIMENU_HPP_INCLUDED
#define WIDGETS_MULTIMENU_HPP_INCLUDED
#include "menu.hpp"
namespace gui {
/**
* A widget that additionally to the normal menu contents also displays a
* checkbox in each row. An item is considered 'active' if its checkbox is checked,
* 'inactive' otherwise.
*/
class multimenu : public menu {
public:
multimenu(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);
void set_active(size_t index, bool active=true);
/**
* Tells if an item is activated.
*
* @param index the item's index
* @return true if the item is active, false if not
*/
bool is_active(size_t index) const { return active_items_[index]; }
/**
* Tell each items status
*
* @return a vector of bools. The n-th item is active if the vector's n-th item is true
*/
const std::vector<bool> &active_items() const { return active_items_; }
virtual void erase_item(size_t index);
virtual void set_items(const std::vector<std::string>& items, bool strip_spaces=true,
bool keep_viewport=false);
/**
* Returns the item last activated/deactivated. Items changed via set_active
* don't count, Invoking this function will set the last changed index to -1.
*
* @return the item's index, or -1 if no item was changed since the last
* invokation
*/
int last_changed();
protected:
virtual void draw_row(const size_t row_index, const SDL_Rect& rect, ROW_TYPE type);
virtual void handle_event(const SDL_Event& event);
/**
* Determine which checkbox was hit by a mouse click.
*
* @param x the x coordinate of the click
* @param y the y coordinate of the click
* @return the row whose checkbox was clicked on, or -1 if the click didn't hit a checkbox
*/
int hit_checkbox(int x, int y) const;
private:
std::vector<bool> active_items_;
int last_changed_;
};
}
#endif