mirror of
https://github.com/wesnoth/wesnoth
synced 2025-04-29 17:21:57 +00:00
refactored menu class into its own source file
This commit is contained in:
parent
edb9436fa7
commit
839eac713c
2
Makefile
2
Makefile
@ -8,7 +8,7 @@ SDL_CFLAGS=`sdl-config --cflags` `freetype-config --cflags`
|
||||
SDL_LIBS=`sdl-config --libs` `freetype-config --libs` -lSDL_mixer -lSDL_ttf -lSDL_image -lSDL_net
|
||||
LIBS=${SDL_LIBS} -lstdc++
|
||||
INCLUDES=-I. -Isrc -Isrc/tools -Isrc/widgets
|
||||
OBJS=src/actions.o src/ai.o src/ai_attack.o src/ai_move.o src/config.o src/dialogs.o src/display.o src/filesystem.o src/font.o src/game.o src/game_config.o src/game_events.o src/gamestatus.o src/hotkeys.o src/intro.o src/key.o src/language.o src/log.o src/map.o src/menu.o src/multiplayer.o src/network.o src/pathfind.o src/playlevel.o src/playturn.o src/preferences.o src/replay.o src/sdl_utils.o src/sound.o src/team.o src/terrain.o src/tooltips.o src/unit.o src/unit_types.o src/video.o src/widgets/button.o src/widgets/slider.o src/widgets/textbox.o
|
||||
OBJS=src/actions.o src/ai.o src/ai_attack.o src/ai_move.o src/config.o src/dialogs.o src/display.o src/filesystem.o src/font.o src/game.o src/game_config.o src/game_events.o src/gamestatus.o src/hotkeys.o src/intro.o src/key.o src/language.o src/log.o src/map.o src/multiplayer.o src/network.o src/pathfind.o src/playlevel.o src/playturn.o src/preferences.o src/replay.o src/sdl_utils.o src/show_dialog.o src/sound.o src/team.o src/terrain.o src/tooltips.o src/unit.o src/unit_types.o src/video.o src/widgets/button.o src/widgets/menu.o src/widgets/slider.o src/widgets/textbox.o
|
||||
|
||||
MAKE_TRANS_OBJS=src/tools/make_translation.o src/config.o src/filesystem.o src/log.o
|
||||
MERGE_TRANS_OBJS=src/tools/merge_translations.o src/config.o src/filesystem.o src/log.o
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
@ -17,11 +17,11 @@
|
||||
#include "dialogs.hpp"
|
||||
#include "game_config.hpp"
|
||||
#include "log.hpp"
|
||||
#include "menu.hpp"
|
||||
#include "pathfind.hpp"
|
||||
#include "playlevel.hpp"
|
||||
#include "playturn.hpp"
|
||||
#include "replay.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
|
||||
#include "actions.hpp"
|
||||
#include "display.hpp"
|
||||
#include "menu.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
|
||||
namespace dialogs
|
||||
{
|
||||
|
@ -19,9 +19,9 @@
|
||||
#include "hotkeys.hpp"
|
||||
#include "language.hpp"
|
||||
#include "log.hpp"
|
||||
#include "menu.hpp"
|
||||
#include "preferences.hpp"
|
||||
#include "sdl_utils.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
#include "sound.hpp"
|
||||
#include "tooltips.hpp"
|
||||
#include "util.hpp"
|
||||
|
13
src/game.cpp
13
src/game.cpp
@ -25,13 +25,13 @@
|
||||
#include "gamestatus.hpp"
|
||||
#include "key.hpp"
|
||||
#include "language.hpp"
|
||||
#include "menu.hpp"
|
||||
#include "multiplayer.hpp"
|
||||
#include "network.hpp"
|
||||
#include "pathfind.hpp"
|
||||
#include "playlevel.hpp"
|
||||
#include "preferences.hpp"
|
||||
#include "replay.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
#include "sound.hpp"
|
||||
#include "team.hpp"
|
||||
#include "unit_types.hpp"
|
||||
@ -153,8 +153,14 @@ int play_game(int argc, char** argv)
|
||||
|
||||
for(int arg = 1; arg != argc; ++arg) {
|
||||
const std::string val(argv[arg]);
|
||||
if(val.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if(val == "--windowed" || val == "-w") {
|
||||
preferences::set_fullscreen(false);
|
||||
} else if(val == "--fullscreen" || val == "-f") {
|
||||
preferences::set_fullscreen(true);
|
||||
} else if(val == "--test" || val == "-t") {
|
||||
test_mode = true;
|
||||
} else if(val == "--debug" || val == "-d") {
|
||||
@ -162,9 +168,14 @@ int play_game(int argc, char** argv)
|
||||
} else if(val == "--help" || val == "-h") {
|
||||
std::cout << "usage: " << argv[0]
|
||||
<< " [options] [data-directory]\n";
|
||||
return 0;
|
||||
} else if(val == "--version" || val == "-v") {
|
||||
std::cout << "Battle for Wesnoth " << game_config::version
|
||||
<< "\n";
|
||||
return 0;
|
||||
} else if(val[0] == '-') {
|
||||
std::cerr << "unknown option: " << val << "\n";
|
||||
return 0;
|
||||
} else {
|
||||
if(!is_directory(val)) {
|
||||
std::cerr << "Could not find directory '" << val << "'\n";
|
||||
|
@ -11,10 +11,10 @@
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
#include "game_events.hpp"
|
||||
#include "menu.hpp"
|
||||
#include "language.hpp"
|
||||
#include "playlevel.hpp"
|
||||
#include "replay.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
#include "sound.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
|
@ -13,9 +13,9 @@
|
||||
#include "config.hpp"
|
||||
#include "hotkeys.hpp"
|
||||
#include "language.hpp"
|
||||
#include "menu.hpp"
|
||||
#include "playlevel.hpp"
|
||||
#include "preferences.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
#include "video.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
@ -14,7 +14,7 @@
|
||||
#include "intro.hpp"
|
||||
#include "key.hpp"
|
||||
#include "language.hpp"
|
||||
#include "menu.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
#include "widgets/button.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
|
@ -13,11 +13,11 @@
|
||||
|
||||
#include "language.hpp"
|
||||
#include "log.hpp"
|
||||
#include "menu.hpp"
|
||||
#include "multiplayer.hpp"
|
||||
#include "network.hpp"
|
||||
#include "playlevel.hpp"
|
||||
#include "replay.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
@ -21,8 +21,8 @@
|
||||
#include "game_config.hpp"
|
||||
#include "gamestatus.hpp"
|
||||
#include "key.hpp"
|
||||
#include "menu.hpp"
|
||||
#include "pathfind.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
#include "team.hpp"
|
||||
#include "unit_types.hpp"
|
||||
#include "unit.hpp"
|
||||
|
@ -22,8 +22,8 @@
|
||||
#include "game_events.hpp"
|
||||
#include "gamestatus.hpp"
|
||||
#include "key.hpp"
|
||||
#include "menu.hpp"
|
||||
#include "pathfind.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
#include "team.hpp"
|
||||
#include "unit_types.hpp"
|
||||
#include "unit.hpp"
|
||||
|
@ -14,8 +14,8 @@
|
||||
#include "font.hpp"
|
||||
#include "hotkeys.hpp"
|
||||
#include "language.hpp"
|
||||
#include "menu.hpp"
|
||||
#include "preferences.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
#include "sound.hpp"
|
||||
#include "util.hpp"
|
||||
#include "widgets/button.hpp"
|
||||
|
@ -17,11 +17,11 @@
|
||||
#include "dialogs.hpp"
|
||||
#include "game_config.hpp"
|
||||
#include "log.hpp"
|
||||
#include "menu.hpp"
|
||||
#include "pathfind.hpp"
|
||||
#include "playlevel.hpp"
|
||||
#include "playturn.hpp"
|
||||
#include "replay.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
@ -10,16 +10,18 @@
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "config.hpp"
|
||||
#include "font.hpp"
|
||||
#include "language.hpp"
|
||||
#include "menu.hpp"
|
||||
#include "playlevel.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
#include "language.hpp"
|
||||
#include "sdl_utils.hpp"
|
||||
#include "tooltips.hpp"
|
||||
#include "util.hpp"
|
||||
#include "widgets/button.hpp"
|
||||
#include "widgets/menu.hpp"
|
||||
#include "widgets/textbox.hpp"
|
||||
|
||||
#include <iostream>
|
||||
@ -171,336 +173,6 @@ void draw_solid_tinted_rectangle(int x, int y, int w, int h,
|
||||
|
||||
} //end namespace gui
|
||||
|
||||
namespace {
|
||||
const size_t max_menu_items = 18;
|
||||
const size_t menu_font_size = 16;
|
||||
const size_t menu_cell_padding = 10;
|
||||
|
||||
class menu
|
||||
{
|
||||
display* display_;
|
||||
int x_, y_;
|
||||
std::vector<std::vector<std::string> > items_;
|
||||
mutable std::vector<int> column_widths_;
|
||||
|
||||
scoped_sdl_surface buffer_;
|
||||
int selected_;
|
||||
bool click_selects_;
|
||||
bool previous_button_;
|
||||
bool drawn_;
|
||||
|
||||
mutable int height_;
|
||||
mutable int width_;
|
||||
|
||||
mutable int first_item_on_screen_;
|
||||
gui::button uparrow_, downarrow_;
|
||||
|
||||
const std::vector<int>& column_widths() const
|
||||
{
|
||||
if(column_widths_.empty()) {
|
||||
for(size_t row = 0; row != items_.size(); ++row) {
|
||||
for(size_t col = 0; col != items_[row].size(); ++col) {
|
||||
static const SDL_Rect area =
|
||||
{0,0,display_->x(),display_->y()};
|
||||
|
||||
const SDL_Rect res =
|
||||
font::draw_text(NULL,area,menu_font_size,
|
||||
font::NORMAL_COLOUR,items_[row][col],x_,y_);
|
||||
|
||||
if(col == column_widths_.size()) {
|
||||
column_widths_.push_back(res.w + menu_cell_padding);
|
||||
} else if(res.w > column_widths_[col] - menu_cell_padding) {
|
||||
column_widths_[col] = res.w + menu_cell_padding;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return column_widths_;
|
||||
}
|
||||
|
||||
void draw_item(int item) {
|
||||
SDL_Rect rect = get_item_rect(item);
|
||||
if(rect.w == 0)
|
||||
return;
|
||||
|
||||
if(buffer_.get() != NULL) {
|
||||
const int ypos = items_start()+(item-first_item_on_screen_)*rect.h;
|
||||
SDL_Rect srcrect = {0,ypos,rect.w,rect.h};
|
||||
SDL_BlitSurface(buffer_,&srcrect,
|
||||
display_->video().getSurface(),&rect);
|
||||
}
|
||||
|
||||
gui::draw_solid_tinted_rectangle(x_,rect.y,width(),rect.h,
|
||||
item == selected_ ? 150:0,0,0,
|
||||
item == selected_ ? 0.6 : 0.2,
|
||||
display_->video().getSurface());
|
||||
|
||||
SDL_Rect area = {0,0,display_->x(),display_->y()};
|
||||
|
||||
const std::vector<int>& widths = column_widths();
|
||||
|
||||
int xpos = rect.x;
|
||||
for(size_t i = 0; i != items_[item].size(); ++i) {
|
||||
font::draw_text(display_,area,menu_font_size,font::NORMAL_COLOUR,
|
||||
items_[item][i],xpos,rect.y);
|
||||
xpos += widths[i];
|
||||
}
|
||||
}
|
||||
|
||||
void draw() {
|
||||
drawn_ = true;
|
||||
|
||||
for(size_t i = 0; i != items_.size(); ++i)
|
||||
draw_item(i);
|
||||
|
||||
display_->video().flip();
|
||||
}
|
||||
|
||||
int hit(int x, int y) const {
|
||||
if(x > x_ && x < x_ + width() && y > y_ && y < y_ + height()){
|
||||
for(size_t i = 0; i != items_.size(); ++i) {
|
||||
const SDL_Rect& rect = get_item_rect(i);
|
||||
if(y > rect.y && y < rect.y + rect.h)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
mutable std::map<int,SDL_Rect> itemRects_;
|
||||
|
||||
SDL_Rect get_item_rect(int item) const
|
||||
{
|
||||
const SDL_Rect empty_rect = {0,0,0,0};
|
||||
if(item < first_item_on_screen_ ||
|
||||
size_t(item) >= first_item_on_screen_ + max_menu_items) {
|
||||
return empty_rect;
|
||||
}
|
||||
|
||||
const std::map<int,SDL_Rect>::const_iterator i = itemRects_.find(item);
|
||||
if(i != itemRects_.end())
|
||||
return i->second;
|
||||
|
||||
int y = y_ + items_start();
|
||||
if(item != first_item_on_screen_) {
|
||||
const SDL_Rect& prev = get_item_rect(item-1);
|
||||
y = prev.y + prev.h;
|
||||
}
|
||||
|
||||
static const SDL_Rect area = {0,0,display_->x(),display_->y()};
|
||||
|
||||
SDL_Rect res = font::draw_text(NULL,area,menu_font_size,
|
||||
font::NORMAL_COLOUR,items_[item][0],x_,y);
|
||||
|
||||
res.w = width();
|
||||
|
||||
//only insert into the cache if the menu's co-ordinates have
|
||||
//been initialized
|
||||
if(x_ > 0 && y_ > 0)
|
||||
itemRects_.insert(std::pair<int,SDL_Rect>(item,res));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int items_start() const
|
||||
{
|
||||
if(items_.size() > max_menu_items)
|
||||
return uparrow_.height();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int items_end() const
|
||||
{
|
||||
if(items_.size() > max_menu_items)
|
||||
return height() - downarrow_.height();
|
||||
else
|
||||
return height();
|
||||
}
|
||||
|
||||
int items_height() const
|
||||
{
|
||||
return items_end() - items_start();
|
||||
}
|
||||
|
||||
public:
|
||||
menu(display& disp, const std::vector<std::string>& items,
|
||||
bool click_selects=false)
|
||||
: display_(&disp), x_(0), y_(0), buffer_(NULL),
|
||||
selected_(-1), click_selects_(click_selects),
|
||||
previous_button_(true), drawn_(false), height_(-1), width_(-1),
|
||||
first_item_on_screen_(0),
|
||||
uparrow_(disp,"",gui::button::TYPE_PRESS,"uparrow"),
|
||||
downarrow_(disp,"",gui::button::TYPE_PRESS,"downarrow")
|
||||
{
|
||||
for(std::vector<std::string>::const_iterator item = items.begin();
|
||||
item != items.end(); ++item) {
|
||||
items_.push_back(config::split(*item));
|
||||
|
||||
//make sure there is always at least one item
|
||||
if(items_.back().empty())
|
||||
items_.back().push_back(" ");
|
||||
}
|
||||
}
|
||||
|
||||
int height() const {
|
||||
if(height_ == -1) {
|
||||
height_ = 0;
|
||||
for(size_t i = 0; i != items_.size() && i != max_menu_items; ++i) {
|
||||
height_ += get_item_rect(i).h;
|
||||
}
|
||||
|
||||
if(items_.size() > max_menu_items) {
|
||||
height_ += uparrow_.height() + downarrow_.height();
|
||||
}
|
||||
}
|
||||
|
||||
return height_;
|
||||
}
|
||||
|
||||
int width() const {
|
||||
if(width_ == -1) {
|
||||
const std::vector<int>& widths = column_widths();
|
||||
width_ = std::accumulate(widths.begin(),widths.end(),0);
|
||||
}
|
||||
|
||||
return width_;
|
||||
}
|
||||
|
||||
int selection() const { return selected_; }
|
||||
|
||||
void set_loc(int x, int y) {
|
||||
x_ = x;
|
||||
y_ = y;
|
||||
|
||||
const int w = width();
|
||||
|
||||
SDL_Rect portion = {x_,y_,w,height()};
|
||||
SDL_Surface* const screen = display_->video().getSurface();
|
||||
buffer_.assign(get_surface_portion(screen, portion));
|
||||
|
||||
if(items_.size() > max_menu_items) {
|
||||
uparrow_.set_x(x_);
|
||||
uparrow_.set_y(y_);
|
||||
downarrow_.set_x(x_);
|
||||
downarrow_.set_y(y_+items_end());
|
||||
}
|
||||
}
|
||||
|
||||
int process(int x, int y, bool button,bool up_arrow,bool down_arrow,
|
||||
bool page_up, bool page_down, int select_item) {
|
||||
if(items_.size() > size_t(max_menu_items)) {
|
||||
const bool up = uparrow_.process(x,y,button);
|
||||
if(up && first_item_on_screen_ > 0) {
|
||||
itemRects_.clear();
|
||||
--first_item_on_screen_;
|
||||
|
||||
draw();
|
||||
}
|
||||
|
||||
const bool down = downarrow_.process(x,y,button);
|
||||
if(down &&
|
||||
size_t(first_item_on_screen_+max_menu_items) < items_.size()) {
|
||||
itemRects_.clear();
|
||||
++first_item_on_screen_;
|
||||
draw();
|
||||
}
|
||||
}
|
||||
|
||||
if(select_item >= 0 && size_t(select_item) < items_.size()) {
|
||||
selected_ = select_item;
|
||||
if(selected_ < first_item_on_screen_) {
|
||||
itemRects_.clear();
|
||||
first_item_on_screen_ = selected_;
|
||||
}
|
||||
|
||||
if(size_t(selected_ - first_item_on_screen_) >= max_menu_items) {
|
||||
itemRects_.clear();
|
||||
first_item_on_screen_ = selected_ - max_menu_items - 1;
|
||||
}
|
||||
|
||||
draw();
|
||||
}
|
||||
|
||||
if(up_arrow && !click_selects_ && selected_ > 0) {
|
||||
--selected_;
|
||||
if(selected_ < first_item_on_screen_) {
|
||||
itemRects_.clear();
|
||||
first_item_on_screen_ = selected_;
|
||||
}
|
||||
|
||||
draw();
|
||||
}
|
||||
|
||||
if(down_arrow && !click_selects_ && selected_ < int(items_.size()-1)) {
|
||||
++selected_;
|
||||
if(size_t(selected_ - first_item_on_screen_) == max_menu_items) {
|
||||
itemRects_.clear();
|
||||
++first_item_on_screen_;
|
||||
}
|
||||
|
||||
draw();
|
||||
}
|
||||
|
||||
if(page_up && !click_selects_) {
|
||||
selected_ -= max_menu_items;
|
||||
if(selected_ < 0)
|
||||
selected_ = 0;
|
||||
|
||||
itemRects_.clear();
|
||||
first_item_on_screen_ = selected_;
|
||||
|
||||
draw();
|
||||
}
|
||||
|
||||
if(page_down && !click_selects_) {
|
||||
selected_ += max_menu_items;
|
||||
if(size_t(selected_) >= items_.size())
|
||||
selected_ = items_.size()-1;
|
||||
|
||||
first_item_on_screen_ = selected_ - (max_menu_items-1);
|
||||
if(first_item_on_screen_ < 0)
|
||||
first_item_on_screen_ = 0;
|
||||
|
||||
itemRects_.clear();
|
||||
|
||||
draw();
|
||||
}
|
||||
|
||||
const int starting_selected = selected_;
|
||||
|
||||
const int hit_item = hit(x,y);
|
||||
|
||||
if(click_selects_) {
|
||||
selected_ = hit_item;
|
||||
if(button && !previous_button_)
|
||||
return selected_;
|
||||
else {
|
||||
if(!drawn_ || selected_ != starting_selected)
|
||||
draw();
|
||||
previous_button_ = button;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(button && hit_item != -1){
|
||||
selected_ = hit_item;
|
||||
}
|
||||
|
||||
if(selected_ == -1)
|
||||
selected_ = 0;
|
||||
|
||||
if(selected_ != starting_selected)
|
||||
draw();
|
||||
|
||||
return -1;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace gui
|
||||
{
|
||||
|
@ -10,8 +10,9 @@
|
||||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
#ifndef MENU_HPP_INCLUDED
|
||||
#define MENU_HPP_INCLUDED
|
||||
|
||||
#ifndef SHOW_DIALOG_HPP_INCLUDED
|
||||
#define SHOW_DIALOG_HPP_INCLUDED
|
||||
|
||||
#include "display.hpp"
|
||||
#include "SDL.h"
|
@ -1,5 +1,5 @@
|
||||
#include "font.hpp"
|
||||
#include "menu.hpp"
|
||||
#include "show_dialog.hpp"
|
||||
#include "tooltips.hpp"
|
||||
#include "sdl_utils.hpp"
|
||||
|
||||
|
323
src/widgets/menu.cpp
Normal file
323
src/widgets/menu.cpp
Normal file
@ -0,0 +1,323 @@
|
||||
#include "menu.hpp"
|
||||
|
||||
#include "../font.hpp"
|
||||
#include "../show_dialog.hpp"
|
||||
|
||||
#include <numeric>
|
||||
|
||||
namespace {
|
||||
const size_t max_menu_items = 18;
|
||||
const size_t menu_font_size = 16;
|
||||
const size_t menu_cell_padding = 10;
|
||||
}
|
||||
|
||||
namespace gui {
|
||||
|
||||
menu::menu(display& disp, const std::vector<std::string>& items,
|
||||
bool click_selects)
|
||||
: display_(&disp), x_(0), y_(0), buffer_(NULL),
|
||||
selected_(-1), click_selects_(click_selects),
|
||||
previous_button_(true), drawn_(false), height_(-1), width_(-1),
|
||||
first_item_on_screen_(0),
|
||||
uparrow_(disp,"",gui::button::TYPE_PRESS,"uparrow"),
|
||||
downarrow_(disp,"",gui::button::TYPE_PRESS,"downarrow")
|
||||
{
|
||||
for(std::vector<std::string>::const_iterator item = items.begin();
|
||||
item != items.end(); ++item) {
|
||||
items_.push_back(config::split(*item));
|
||||
|
||||
//make sure there is always at least one item
|
||||
if(items_.back().empty())
|
||||
items_.back().push_back(" ");
|
||||
}
|
||||
}
|
||||
|
||||
int menu::height() const
|
||||
{
|
||||
if(height_ == -1) {
|
||||
height_ = 0;
|
||||
for(size_t i = 0; i != items_.size() && i != max_menu_items; ++i) {
|
||||
height_ += get_item_rect(i).h;
|
||||
}
|
||||
|
||||
if(items_.size() > max_menu_items) {
|
||||
height_ += uparrow_.height() + downarrow_.height();
|
||||
}
|
||||
}
|
||||
|
||||
return height_;
|
||||
}
|
||||
|
||||
int menu::width() const
|
||||
{
|
||||
if(width_ == -1) {
|
||||
const std::vector<int>& widths = column_widths();
|
||||
width_ = std::accumulate(widths.begin(),widths.end(),0);
|
||||
}
|
||||
|
||||
return width_;
|
||||
}
|
||||
|
||||
int menu::selection() const { return selected_; }
|
||||
|
||||
void menu::set_loc(int x, int y)
|
||||
{
|
||||
x_ = x;
|
||||
y_ = y;
|
||||
|
||||
const int w = width();
|
||||
|
||||
SDL_Rect portion = {x_,y_,w,height()};
|
||||
SDL_Surface* const screen = display_->video().getSurface();
|
||||
buffer_.assign(get_surface_portion(screen, portion));
|
||||
|
||||
if(items_.size() > max_menu_items) {
|
||||
uparrow_.set_x(x_);
|
||||
uparrow_.set_y(y_);
|
||||
downarrow_.set_x(x_);
|
||||
downarrow_.set_y(y_+items_end());
|
||||
}
|
||||
}
|
||||
|
||||
int menu::process(int x, int y, bool button,bool up_arrow,bool down_arrow,
|
||||
bool page_up, bool page_down, int select_item)
|
||||
{
|
||||
if(items_.size() > size_t(max_menu_items)) {
|
||||
const bool up = uparrow_.process(x,y,button);
|
||||
if(up && first_item_on_screen_ > 0) {
|
||||
itemRects_.clear();
|
||||
--first_item_on_screen_;
|
||||
|
||||
draw();
|
||||
}
|
||||
|
||||
const bool down = downarrow_.process(x,y,button);
|
||||
if(down &&
|
||||
size_t(first_item_on_screen_+max_menu_items) < items_.size()) {
|
||||
itemRects_.clear();
|
||||
++first_item_on_screen_;
|
||||
draw();
|
||||
}
|
||||
}
|
||||
|
||||
if(select_item >= 0 && size_t(select_item) < items_.size()) {
|
||||
selected_ = select_item;
|
||||
if(selected_ < first_item_on_screen_) {
|
||||
itemRects_.clear();
|
||||
first_item_on_screen_ = selected_;
|
||||
}
|
||||
|
||||
if(size_t(selected_ - first_item_on_screen_) >= max_menu_items) {
|
||||
itemRects_.clear();
|
||||
first_item_on_screen_ = selected_ - max_menu_items - 1;
|
||||
}
|
||||
|
||||
draw();
|
||||
}
|
||||
|
||||
if(up_arrow && !click_selects_ && selected_ > 0) {
|
||||
--selected_;
|
||||
if(selected_ < first_item_on_screen_) {
|
||||
itemRects_.clear();
|
||||
first_item_on_screen_ = selected_;
|
||||
}
|
||||
|
||||
draw();
|
||||
}
|
||||
|
||||
if(down_arrow && !click_selects_ && selected_ < int(items_.size()-1)) {
|
||||
++selected_;
|
||||
if(size_t(selected_ - first_item_on_screen_) == max_menu_items) {
|
||||
itemRects_.clear();
|
||||
++first_item_on_screen_;
|
||||
}
|
||||
|
||||
draw();
|
||||
}
|
||||
|
||||
if(page_up && !click_selects_) {
|
||||
selected_ -= max_menu_items;
|
||||
if(selected_ < 0)
|
||||
selected_ = 0;
|
||||
|
||||
itemRects_.clear();
|
||||
first_item_on_screen_ = selected_;
|
||||
|
||||
draw();
|
||||
}
|
||||
|
||||
if(page_down && !click_selects_) {
|
||||
selected_ += max_menu_items;
|
||||
if(size_t(selected_) >= items_.size())
|
||||
selected_ = items_.size()-1;
|
||||
|
||||
first_item_on_screen_ = selected_ - (max_menu_items-1);
|
||||
if(first_item_on_screen_ < 0)
|
||||
first_item_on_screen_ = 0;
|
||||
|
||||
itemRects_.clear();
|
||||
|
||||
draw();
|
||||
}
|
||||
|
||||
const int starting_selected = selected_;
|
||||
|
||||
const int hit_item = hit(x,y);
|
||||
|
||||
if(click_selects_) {
|
||||
selected_ = hit_item;
|
||||
if(button && !previous_button_)
|
||||
return selected_;
|
||||
else {
|
||||
if(!drawn_ || selected_ != starting_selected)
|
||||
draw();
|
||||
previous_button_ = button;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if(button && hit_item != -1){
|
||||
selected_ = hit_item;
|
||||
}
|
||||
|
||||
if(selected_ == -1)
|
||||
selected_ = 0;
|
||||
|
||||
if(selected_ != starting_selected)
|
||||
draw();
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
const std::vector<int>& menu::column_widths() const
|
||||
{
|
||||
if(column_widths_.empty()) {
|
||||
for(size_t row = 0; row != items_.size(); ++row) {
|
||||
for(size_t col = 0; col != items_[row].size(); ++col) {
|
||||
static const SDL_Rect area =
|
||||
{0,0,display_->x(),display_->y()};
|
||||
|
||||
const SDL_Rect res =
|
||||
font::draw_text(NULL,area,menu_font_size,
|
||||
font::NORMAL_COLOUR,items_[row][col],x_,y_);
|
||||
|
||||
if(col == column_widths_.size()) {
|
||||
column_widths_.push_back(res.w + menu_cell_padding);
|
||||
} else if(res.w > column_widths_[col] - menu_cell_padding) {
|
||||
column_widths_[col] = res.w + menu_cell_padding;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return column_widths_;
|
||||
}
|
||||
|
||||
void menu::draw_item(int item)
|
||||
{
|
||||
SDL_Rect rect = get_item_rect(item);
|
||||
if(rect.w == 0)
|
||||
return;
|
||||
|
||||
if(buffer_.get() != NULL) {
|
||||
const int ypos = items_start()+(item-first_item_on_screen_)*rect.h;
|
||||
SDL_Rect srcrect = {0,ypos,rect.w,rect.h};
|
||||
SDL_BlitSurface(buffer_,&srcrect,
|
||||
display_->video().getSurface(),&rect);
|
||||
}
|
||||
|
||||
gui::draw_solid_tinted_rectangle(x_,rect.y,width(),rect.h,
|
||||
item == selected_ ? 150:0,0,0,
|
||||
item == selected_ ? 0.6 : 0.2,
|
||||
display_->video().getSurface());
|
||||
|
||||
SDL_Rect area = {0,0,display_->x(),display_->y()};
|
||||
|
||||
const std::vector<int>& widths = column_widths();
|
||||
|
||||
int xpos = rect.x;
|
||||
for(size_t i = 0; i != items_[item].size(); ++i) {
|
||||
font::draw_text(display_,area,menu_font_size,font::NORMAL_COLOUR,
|
||||
items_[item][i],xpos,rect.y);
|
||||
xpos += widths[i];
|
||||
}
|
||||
}
|
||||
|
||||
void menu::draw()
|
||||
{
|
||||
drawn_ = true;
|
||||
|
||||
for(size_t i = 0; i != items_.size(); ++i)
|
||||
draw_item(i);
|
||||
|
||||
display_->video().flip();
|
||||
}
|
||||
|
||||
int menu::hit(int x, int y) const
|
||||
{
|
||||
if(x > x_ && x < x_ + width() && y > y_ && y < y_ + height()){
|
||||
for(size_t i = 0; i != items_.size(); ++i) {
|
||||
const SDL_Rect& rect = get_item_rect(i);
|
||||
if(y > rect.y && y < rect.y + rect.h)
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
SDL_Rect menu::get_item_rect(int item) const
|
||||
{
|
||||
const SDL_Rect empty_rect = {0,0,0,0};
|
||||
if(item < first_item_on_screen_ ||
|
||||
size_t(item) >= first_item_on_screen_ + max_menu_items) {
|
||||
return empty_rect;
|
||||
}
|
||||
|
||||
const std::map<int,SDL_Rect>::const_iterator i = itemRects_.find(item);
|
||||
if(i != itemRects_.end())
|
||||
return i->second;
|
||||
|
||||
int y = y_ + items_start();
|
||||
if(item != first_item_on_screen_) {
|
||||
const SDL_Rect& prev = get_item_rect(item-1);
|
||||
y = prev.y + prev.h;
|
||||
}
|
||||
|
||||
static const SDL_Rect area = {0,0,display_->x(),display_->y()};
|
||||
|
||||
SDL_Rect res = font::draw_text(NULL,area,menu_font_size,
|
||||
font::NORMAL_COLOUR,items_[item][0],x_,y);
|
||||
|
||||
res.w = width();
|
||||
|
||||
//only insert into the cache if the menu's co-ordinates have
|
||||
//been initialized
|
||||
if(x_ > 0 && y_ > 0)
|
||||
itemRects_.insert(std::pair<int,SDL_Rect>(item,res));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int menu::items_start() const
|
||||
{
|
||||
if(items_.size() > max_menu_items)
|
||||
return uparrow_.height();
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int menu::items_end() const
|
||||
{
|
||||
if(items_.size() > max_menu_items)
|
||||
return height() - downarrow_.height();
|
||||
else
|
||||
return height();
|
||||
}
|
||||
|
||||
int menu::items_height() const
|
||||
{
|
||||
return items_end() - items_start();
|
||||
}
|
||||
|
||||
}
|
66
src/widgets/menu.hpp
Normal file
66
src/widgets/menu.hpp
Normal file
@ -0,0 +1,66 @@
|
||||
#ifndef WIDGET_MENU_HPP_INCLUDED
|
||||
#define WIDGET_MENU_HPP_INCLUDED
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "../display.hpp"
|
||||
#include "../sdl_utils.hpp"
|
||||
|
||||
#include "button.hpp"
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
namespace gui {
|
||||
|
||||
class menu
|
||||
{
|
||||
public:
|
||||
menu(display& disp, const std::vector<std::string>& items,
|
||||
bool click_selects=false);
|
||||
|
||||
int height() const;
|
||||
int width() const;
|
||||
|
||||
int selection() const;
|
||||
|
||||
void set_loc(int x, int y);
|
||||
|
||||
int process(int x, int y, bool button,bool up_arrow,bool down_arrow,
|
||||
bool page_up, bool page_down, int select_item);
|
||||
|
||||
private:
|
||||
display* display_;
|
||||
int x_, y_;
|
||||
std::vector<std::vector<std::string> > items_;
|
||||
mutable std::vector<int> column_widths_;
|
||||
|
||||
scoped_sdl_surface buffer_;
|
||||
int selected_;
|
||||
bool click_selects_;
|
||||
bool previous_button_;
|
||||
bool drawn_;
|
||||
|
||||
mutable int height_;
|
||||
mutable int width_;
|
||||
|
||||
mutable int first_item_on_screen_;
|
||||
gui::button uparrow_, downarrow_;
|
||||
|
||||
const std::vector<int>& column_widths() const;
|
||||
void draw_item(int item);
|
||||
void draw();
|
||||
int hit(int x, int y) const;
|
||||
|
||||
mutable std::map<int,SDL_Rect> itemRects_;
|
||||
|
||||
SDL_Rect get_item_rect(int item) const;
|
||||
int items_start() const;
|
||||
|
||||
int items_end() const;
|
||||
int items_height() const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
Loading…
x
Reference in New Issue
Block a user