Refactoring: the terrain palette now is a separate class.
Major speed enhancement: the palette is only redrawn when needed. The coordinates and terrain type of the hex the mouse is over are shown.
This commit is contained in:
parent
5616b044d2
commit
ed55b59702
3 changed files with 198 additions and 110 deletions
|
@ -164,6 +164,23 @@ height=600
|
|||
xanchor=right
|
||||
yanchor=fixed
|
||||
[/mini_map]
|
||||
|
||||
[status]
|
||||
[terrain]
|
||||
font_size=12
|
||||
rect=820,4,920,20
|
||||
xanchor=proportional
|
||||
yanchor=fixed
|
||||
[/terrain]
|
||||
|
||||
[position]
|
||||
font_size=12
|
||||
rect=925,4,1020,20
|
||||
xanchor=proportional
|
||||
yanchor=fixed
|
||||
[/position]
|
||||
[/status]
|
||||
|
||||
[/resolution]
|
||||
[/theme]
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (C) 2003 by David Whire <davidnwhite@optusnet.com.au>
|
||||
Copyright (C) 2003 by David White <davidnwhite@optusnet.com.au>
|
||||
Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
|
@ -9,6 +9,7 @@
|
|||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#include "SDL.h"
|
||||
#include "SDL_keysym.h"
|
||||
|
||||
|
@ -30,6 +31,7 @@
|
|||
#include "../playlevel.hpp"
|
||||
#include "../preferences.hpp"
|
||||
#include "../sdl_utils.hpp"
|
||||
#include "../tooltips.hpp"
|
||||
#include "../widgets/slider.hpp"
|
||||
#include "../team.hpp"
|
||||
#include "../unit_types.hpp"
|
||||
|
@ -56,18 +58,10 @@ namespace map_editor {
|
|||
map_editor::map_editor(display &gui, gamemap &map, config &theme, config &game_config)
|
||||
: gui_(gui), map_(map), tup_(gui, "", gui::button::TYPE_PRESS, "uparrow-button"),
|
||||
tdown_(gui, "", gui::button::TYPE_PRESS, "downarrow-button"), abort_(DONT_ABORT),
|
||||
tstart_(0), num_operations_since_save_(0), theme_(theme),
|
||||
game_config_(game_config), draw_terrain_(false),
|
||||
minimap_dirty_(false) {
|
||||
num_operations_since_save_(0), theme_(theme), game_config_(game_config),
|
||||
draw_terrain_(false), minimap_dirty_(false),
|
||||
palette_(gui, size_specs_, map) {
|
||||
|
||||
terrains_ = map_.get_terrain_precedence();
|
||||
terrains_.erase(std::remove_if(terrains_.begin(), terrains_.end(), is_invalid_terrain),
|
||||
terrains_.end());
|
||||
if(terrains_.empty()) {
|
||||
std::cerr << "No terrain found.\n";
|
||||
abort_ = ABORT_HARD;
|
||||
}
|
||||
selected_terrain_ = terrains_[0];
|
||||
|
||||
// Set size specs.
|
||||
adjust_sizes(gui_);
|
||||
|
@ -108,10 +102,10 @@ void map_editor::handle_mouse_button_event(const SDL_MouseButtonEvent &event,
|
|||
if (event.type == SDL_MOUSEBUTTONDOWN) {
|
||||
const Uint8 button = event.button;
|
||||
if (button == SDL_BUTTON_WHEELUP) {
|
||||
scroll_palette_up();
|
||||
palette_.scroll_up();
|
||||
}
|
||||
if (button == SDL_BUTTON_WHEELDOWN) {
|
||||
scroll_palette_down();
|
||||
palette_.scroll_down();
|
||||
}
|
||||
if (button == SDL_BUTTON_RIGHT) {
|
||||
selected_hex_ = gui_.hex_clicked_on(mousex, mousey);
|
||||
|
@ -120,12 +114,7 @@ void map_editor::handle_mouse_button_event(const SDL_MouseButtonEvent &event,
|
|||
}
|
||||
if (button == SDL_BUTTON_LEFT) {
|
||||
draw_terrain_ = true;
|
||||
int tselect = tile_selected(mousex, mousey, gui_, size_specs_);
|
||||
if(tselect >= 0) {
|
||||
// Was the click on a terrain item in the palette? If so, set
|
||||
// the selected terrain.
|
||||
selected_terrain_ = terrains_[tstart_+tselect];
|
||||
}
|
||||
palette_.left_mouse_click(mousex, mousey);
|
||||
}
|
||||
}
|
||||
if (event.type == SDL_MOUSEBUTTONUP) {
|
||||
|
@ -224,7 +213,7 @@ std::string map_editor::new_map_dialog(display& disp)
|
|||
std::stringstream str;
|
||||
std::stringstream map_str;
|
||||
for (i = 0; i < width_slider.value(); i++) {
|
||||
str << selected_terrain_;
|
||||
str << palette_.selected_terrain();
|
||||
}
|
||||
str << "\n";
|
||||
for (i = 0; i < height_slider.value(); i++) {
|
||||
|
@ -263,8 +252,10 @@ std::string map_editor::new_map_dialog(display& disp)
|
|||
title_rect = font::draw_text(&disp,disp.screen_area(),24,font::NORMAL_COLOUR,
|
||||
"Create New Map",xpos+(width-title_rect.w)/2,ypos+10);
|
||||
|
||||
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,width_label,width_rect.x,width_rect.y);
|
||||
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,height_label,height_rect.x,height_rect.y);
|
||||
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,
|
||||
width_label,width_rect.x,width_rect.y);
|
||||
font::draw_text(&disp,disp.screen_area(),14,font::NORMAL_COLOUR,
|
||||
height_label,height_rect.x,height_rect.y);
|
||||
|
||||
std::stringstream width_str;
|
||||
width_str << map_width;
|
||||
|
@ -387,7 +378,7 @@ void map_editor::adjust_sizes(const display &disp) {
|
|||
space_for_terrains = space_for_terrains / size_specs_.terrain_space % 2 == 0 ?
|
||||
space_for_terrains : space_for_terrains - size_specs_.terrain_space;
|
||||
size_specs_.nterrains = minimum((space_for_terrains / size_specs_.terrain_space) * 2,
|
||||
terrains_.size());
|
||||
palette_.num_terrains());
|
||||
size_specs_.bot_button_y = size_specs_.palette_y +
|
||||
(size_specs_.nterrains / 2) * size_specs_.terrain_space + button_palette_padding;
|
||||
}
|
||||
|
@ -458,12 +449,12 @@ void map_editor::left_button_down(const int mousex, const int mousey) {
|
|||
const gamemap::location hex = gui_.hex_clicked_on(mousex, mousey);
|
||||
if(map_.on_board(hex)) {
|
||||
const gamemap::TERRAIN terrain = map_[hex.x][hex.y];
|
||||
if(selected_terrain_ != terrain) {
|
||||
if(palette_.selected_terrain() != terrain) {
|
||||
if(key_[SDLK_RCTRL] || key_[SDLK_LCTRL]) {
|
||||
selected_terrain_ = terrain;
|
||||
palette_.select_terrain(terrain);
|
||||
}
|
||||
else {
|
||||
draw_terrain(selected_terrain_, hex);
|
||||
draw_terrain(palette_.selected_terrain(), hex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -507,25 +498,6 @@ void map_editor::right_button_down(const int mousex, const int mousey) {
|
|||
void map_editor::middle_button_down(const int mousex, const int mousey) {
|
||||
}
|
||||
|
||||
void map_editor::scroll_palette_down() {
|
||||
if(tstart_ + size_specs_.nterrains + 2 <= terrains_.size()) {
|
||||
tstart_ += 2;
|
||||
}
|
||||
else if (tstart_ + size_specs_.nterrains + 1 <= terrains_.size()) {
|
||||
tstart_ += 1;
|
||||
}
|
||||
}
|
||||
|
||||
void map_editor::scroll_palette_up() {
|
||||
int decrement = 2;
|
||||
if (tstart_ + size_specs_.nterrains == terrains_.size()
|
||||
&& terrains_.size() % 2 != 0) {
|
||||
decrement = 1;
|
||||
}
|
||||
if(tstart_ >= decrement) {
|
||||
tstart_ -= decrement;
|
||||
}
|
||||
}
|
||||
|
||||
bool map_editor::confirm_exit_and_save() {
|
||||
int exit_res = gui::show_dialog(gui_, NULL, "",
|
||||
|
@ -673,15 +645,16 @@ void map_editor::main_loop() {
|
|||
}
|
||||
|
||||
gui_.draw(false);
|
||||
if(drawterrainpalette(gui_, tstart_, selected_terrain_, map_, size_specs_) == false)
|
||||
scroll_palette_down();
|
||||
palette_.draw();
|
||||
//if(drawterrainpalette(gui_, tstart_, selected_terrain_, map_, size_specs_) == false)
|
||||
// scroll_palette_down();
|
||||
|
||||
if(tup_.process(mousex,mousey,l_button_down)) {
|
||||
scroll_palette_up();
|
||||
palette_.scroll_up();
|
||||
}
|
||||
|
||||
if(tdown_.process(mousex,mousey,l_button_down)) {
|
||||
scroll_palette_down();
|
||||
palette_.scroll_down();
|
||||
}
|
||||
|
||||
if (minimap_dirty_) {
|
||||
|
@ -778,75 +751,131 @@ void drawbar(display& disp)
|
|||
update_rect(dst);
|
||||
}
|
||||
|
||||
bool drawterrainpalette(display& disp, int start, gamemap::TERRAIN selected, gamemap map,
|
||||
size_specs specs)
|
||||
{
|
||||
size_t x = disp.mapx() + specs.palette_x;
|
||||
size_t y = specs.palette_y;
|
||||
|
||||
unsigned int starting = start;
|
||||
unsigned int ending = starting+specs.nterrains;
|
||||
terrain_palette::terrain_palette(display &gui, const size_specs &sizes,
|
||||
const gamemap &map)
|
||||
: size_specs_(sizes), gui_(gui), tstart_(0), map_(map), invalid_(true) {
|
||||
|
||||
terrains_ = map_.get_terrain_precedence();
|
||||
terrains_.erase(std::remove_if(terrains_.begin(), terrains_.end(), is_invalid_terrain),
|
||||
terrains_.end());
|
||||
if(terrains_.empty()) {
|
||||
std::cerr << "No terrain found.\n";
|
||||
}
|
||||
else {
|
||||
selected_terrain_ = terrains_[0];
|
||||
}
|
||||
}
|
||||
|
||||
void terrain_palette::scroll_down() {
|
||||
if(tstart_ + size_specs_.nterrains + 2 <= num_terrains()) {
|
||||
tstart_ += 2;
|
||||
invalid_ = true;
|
||||
}
|
||||
else if (tstart_ + size_specs_.nterrains + 1 <= num_terrains()) {
|
||||
tstart_ += 1;
|
||||
invalid_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
void terrain_palette::scroll_up() {
|
||||
unsigned int decrement = 2;
|
||||
if (tstart_ + size_specs_.nterrains == num_terrains()
|
||||
&& terrains_.size() % 2 != 0) {
|
||||
decrement = 1;
|
||||
}
|
||||
if(tstart_ >= decrement) {
|
||||
invalid_ = true;
|
||||
tstart_ -= decrement;
|
||||
}
|
||||
}
|
||||
|
||||
gamemap::TERRAIN terrain_palette::selected_terrain() const {
|
||||
return selected_terrain_;
|
||||
}
|
||||
|
||||
void terrain_palette::select_terrain(gamemap::TERRAIN terrain) {
|
||||
if (selected_terrain_ != terrain) {
|
||||
invalid_ = true;
|
||||
selected_terrain_ = terrain;
|
||||
}
|
||||
}
|
||||
|
||||
void terrain_palette::left_mouse_click(const int mousex, const int mousey) {
|
||||
int tselect = tile_selected(mousex, mousey);
|
||||
if(tselect >= 0) {
|
||||
select_terrain(terrains_[tstart_+tselect]);
|
||||
}
|
||||
}
|
||||
|
||||
size_t terrain_palette::num_terrains() const {
|
||||
return terrains_.size();
|
||||
}
|
||||
|
||||
|
||||
void terrain_palette::draw(bool force) {
|
||||
if (!invalid_ && !force) {
|
||||
return;
|
||||
}
|
||||
size_t x = gui_.mapx() + size_specs_.palette_x;
|
||||
size_t y = size_specs_.palette_y;
|
||||
|
||||
unsigned int starting = tstart_;
|
||||
unsigned int ending = starting + size_specs_.nterrains;
|
||||
|
||||
bool status = true;
|
||||
disp.redraw_everything();
|
||||
SDL_Rect invalid_rect;
|
||||
invalid_rect.x = x;
|
||||
invalid_rect.y = y;
|
||||
invalid_rect.w = 0;
|
||||
|
||||
SDL_Surface* const screen = disp.video().getSurface();
|
||||
|
||||
std::vector<gamemap::TERRAIN> terrains = map.get_terrain_precedence();
|
||||
terrains.erase(std::remove_if(terrains.begin(), terrains.end(), is_invalid_terrain),
|
||||
terrains.end());
|
||||
if(ending > terrains.size()){
|
||||
ending = terrains.size();
|
||||
invalid_rect.w = size_specs_.terrain_space * 2;
|
||||
invalid_rect.h = (size_specs_.nterrains / 2) * size_specs_.terrain_space;
|
||||
// Everything will be redrawn even though only one little part may
|
||||
// have changed, but that happens so seldom so we'll settle with
|
||||
// this.
|
||||
SDL_Surface* const screen = gui_.video().getSurface();
|
||||
SDL_BlitSurface(surf_, NULL, screen, &invalid_rect);
|
||||
surf_.assign(get_surface_portion(screen, invalid_rect));
|
||||
if(ending > num_terrains()){
|
||||
ending = num_terrains();
|
||||
}
|
||||
|
||||
for(unsigned int counter = starting; counter < ending; counter++){
|
||||
const gamemap::TERRAIN terrain = terrains[counter];
|
||||
const gamemap::TERRAIN terrain = terrains_[counter];
|
||||
const std::string filename = "terrain/" +
|
||||
map.get_terrain_info(terrain).default_image() + ".png";
|
||||
map_.get_terrain_info(terrain).default_image() + ".png";
|
||||
scoped_sdl_surface image(image::get_image(filename, image::UNSCALED));
|
||||
|
||||
if(image->w != specs.terrain_size || image->h != specs.terrain_size) {
|
||||
image.assign(scale_surface(image, specs.terrain_size, specs.terrain_size));
|
||||
if(image->w != size_specs_.terrain_size || image->h != size_specs_.terrain_size) {
|
||||
image.assign(scale_surface(image, size_specs_.terrain_size,
|
||||
size_specs_.terrain_size));
|
||||
}
|
||||
|
||||
if(image == NULL) {
|
||||
std::cerr << "image for terrain '" << counter << "' not found\n";
|
||||
return status;
|
||||
return;
|
||||
}
|
||||
const int counter_from_zero = counter - starting;
|
||||
SDL_Rect dstrect;
|
||||
dstrect.x = x + (counter_from_zero % 2 != 0 ? specs.terrain_space : 0);
|
||||
dstrect.x = x + (counter_from_zero % 2 != 0 ? size_specs_.terrain_space : 0);
|
||||
dstrect.y = y;
|
||||
dstrect.w = image->w;
|
||||
dstrect.h = image->h;
|
||||
|
||||
SDL_BlitSurface(image, NULL, screen, &dstrect);
|
||||
gui::draw_rectangle(dstrect.x, dstrect.y, image->w, image->h,
|
||||
terrain == selected ? 0xF000:0 , screen);
|
||||
terrain == selected_terrain() ? 0xF000:0 , screen);
|
||||
|
||||
if (counter_from_zero % 2 != 0)
|
||||
y += specs.terrain_space;
|
||||
y += size_specs_.terrain_space;
|
||||
}
|
||||
invalid_rect.w = specs.terrain_space * 2;
|
||||
|
||||
invalid_rect.h = y - invalid_rect.y;
|
||||
update_rect(invalid_rect);
|
||||
return status;
|
||||
invalid_ = false;
|
||||
}
|
||||
|
||||
int tile_selected(const unsigned int x, const unsigned int y,
|
||||
const display& disp, const size_specs specs)
|
||||
{
|
||||
for(unsigned int i = 0; i != specs.nterrains; i++) {
|
||||
const unsigned int px = disp.mapx() + specs.palette_x +
|
||||
(i % 2 != 0 ? specs.terrain_space : 0);
|
||||
const unsigned int py = specs.palette_y + (i / 2) * specs.terrain_space;
|
||||
const unsigned int pw = specs.terrain_space;
|
||||
const unsigned int ph = specs.terrain_space;
|
||||
int terrain_palette::tile_selected(const int x, const int y) const {
|
||||
for(unsigned int i = 0; i != size_specs_.nterrains; i++) {
|
||||
const int px = gui_.mapx() + size_specs_.palette_x +
|
||||
(i % 2 != 0 ? size_specs_.terrain_space : 0);
|
||||
const int py = size_specs_.palette_y + (i / 2) * size_specs_.terrain_space;
|
||||
const int pw = size_specs_.terrain_space;
|
||||
const int ph = size_specs_.terrain_space;
|
||||
|
||||
if(x > px && x < px + pw && y > py && y < py + ph) {
|
||||
return i;
|
||||
|
@ -859,8 +888,6 @@ bool is_invalid_terrain(char c) {
|
|||
return c == ' ' || c == '~';
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
|
@ -913,17 +940,20 @@ int main(int argc, char** argv)
|
|||
bool done = false;
|
||||
gamestatus status(cfg, 0);
|
||||
std::vector<team> teams;
|
||||
config* const theme_cfg = cfg.find_child("theme", "name", "editor");
|
||||
config dummy_theme;
|
||||
// Add a dummy team so the reports will be handled properly.
|
||||
teams.push_back(team(cfg));
|
||||
config* theme_cfg = cfg.find_child("theme", "name", "editor");
|
||||
config dummy_theme("");
|
||||
if (!theme_cfg) {
|
||||
std::cerr << "Editor theme could not be loaded." << std::endl;
|
||||
*theme_cfg = dummy_theme;
|
||||
theme_cfg = &dummy_theme;
|
||||
}
|
||||
std::map<gamemap::location,unit> units;
|
||||
while (! done) {
|
||||
try {
|
||||
gamemap map(cfg, mapdata);
|
||||
|
||||
std::cerr << "Using theme cfg: " << std::endl << theme_cfg->write() << std::endl;
|
||||
display gui(units, video, map, status, teams,
|
||||
*theme_cfg, cfg);
|
||||
gui.set_grid(preferences::grid());
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
|
||||
See the COPYING file for more details.
|
||||
*/
|
||||
|
||||
#ifndef EDITOR_H_INCLUDED
|
||||
#define EDITOR_H_INCLUDED
|
||||
|
||||
|
@ -54,9 +53,57 @@ struct size_specs {
|
|||
/// questions or saving.
|
||||
enum ABORT_MODE {DONT_ABORT, ABORT_NORMALLY, ABORT_HARD};
|
||||
|
||||
/// A palette where the terrain to be drawn can be selected.
|
||||
class terrain_palette {
|
||||
public:
|
||||
terrain_palette(display &gui, const size_specs &sizes,
|
||||
const gamemap &map);
|
||||
|
||||
/// Scroll the terrain palette up one step if possible.
|
||||
void scroll_up();
|
||||
|
||||
/// Scroll the terrain palette down one step if possible.
|
||||
void scroll_down();
|
||||
|
||||
/// Return the currently selected terrain.
|
||||
gamemap::TERRAIN selected_terrain() const;
|
||||
|
||||
/// Select a terrain.
|
||||
void select_terrain(gamemap::TERRAIN);
|
||||
|
||||
/// To be called when a mouse click occurs. Check if the coordinates
|
||||
/// is a terrain that may be chosen, select the terrain if that is
|
||||
/// the case.
|
||||
void left_mouse_click(const int mousex, const int mousey);
|
||||
|
||||
// Draw the palette. If force is true everything will be redrawn
|
||||
// even though it is not invalidated.
|
||||
void draw(bool force=false);
|
||||
|
||||
/// Return the number of terrains in the palette.
|
||||
size_t num_terrains() const;
|
||||
|
||||
|
||||
private:
|
||||
/// Return the number of the tile that is at coordinates (x, y) in the
|
||||
/// panel.
|
||||
int tile_selected(const int x, const int y) const;
|
||||
|
||||
const size_specs &size_specs_;
|
||||
scoped_sdl_surface surf_;
|
||||
display &gui_;
|
||||
unsigned int tstart_;
|
||||
std::vector<gamemap::TERRAIN> terrains_;
|
||||
gamemap::TERRAIN selected_terrain_;
|
||||
const gamemap &map_;
|
||||
// Set invalid_ to true if an operation that requires that the
|
||||
// palette is redrawn takes place.
|
||||
bool invalid_;
|
||||
};
|
||||
|
||||
/// A map editor. Receives SDL events and can execute hotkey commands.
|
||||
class map_editor : public events::handler,
|
||||
public hotkey::command_executor {
|
||||
public hotkey::command_executor {
|
||||
public:
|
||||
map_editor(display &gui, gamemap &map, config &theme, config &game_config);
|
||||
|
||||
|
@ -71,11 +118,6 @@ public:
|
|||
/// some way after the current iteration of the main loop.
|
||||
void set_abort(const ABORT_MODE abort=ABORT_NORMALLY);
|
||||
|
||||
/// Scroll the terrain palette down one step if possible.
|
||||
void scroll_palette_down();
|
||||
/// Scroll the terrain palette up one step if possible.
|
||||
void scroll_palette_up();
|
||||
|
||||
/// Save the current map. If filename is an empty string, use the
|
||||
/// filename that is set with set_file_to_save_as(). A message box
|
||||
/// that shows confirmation that the map was saved is shown if
|
||||
|
@ -169,16 +211,15 @@ private:
|
|||
/// dispose the modification.
|
||||
bool confirm_modification_disposal(display& disp, const std::string message);
|
||||
|
||||
void draw_terrain_name(display &disp, const gamemap::TERRAIN);
|
||||
|
||||
display &gui_;
|
||||
gamemap &map_;
|
||||
std::vector<gamemap::TERRAIN> terrains_;
|
||||
gui::button tup_, tdown_;
|
||||
gamemap::TERRAIN selected_terrain_;
|
||||
map_undo_list undo_stack_;
|
||||
map_undo_list redo_stack_;
|
||||
std::string filename_;
|
||||
ABORT_MODE abort_;
|
||||
unsigned int tstart_;
|
||||
// Keep track of the number of operations performed since the last
|
||||
// save. If this is zero when the editor is exited there is no need
|
||||
// to ask the user to save.
|
||||
|
@ -192,8 +233,12 @@ private:
|
|||
// When minimap_dirty_ is true a redraw of the minimap will be
|
||||
// scheduled.
|
||||
bool minimap_dirty_;
|
||||
terrain_palette palette_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/// Display a dialog with map filenames and return the chosen
|
||||
/// one. Create a temporary display to use.
|
||||
std::string get_filename_from_dialog(CVideo &video, config &cfg);
|
||||
|
@ -201,10 +246,6 @@ void drawbar(display& disp);
|
|||
bool drawterrainpalette(display& disp, int start, gamemap::TERRAIN selected,
|
||||
gamemap map, size_specs specs);
|
||||
|
||||
/// Return the number of the tile that is at coordinates (x, y) in the
|
||||
/// panel.
|
||||
int tile_selected(const unsigned int x, const unsigned int y,
|
||||
const display& disp, const size_specs specs);
|
||||
|
||||
bool is_invalid_terrain(char c);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue