Added the ability to mark tiles in the editor.

The marked tiles may be filled with the selected terrain.
Added templates for cut and paste functionality.
This commit is contained in:
Kristoffer Erlandsson 2004-05-01 23:31:40 +00:00
parent 074e157400
commit d452ce1281
10 changed files with 192 additions and 39 deletions

View file

@ -114,6 +114,14 @@ alt=no
shift=no
[/hotkey]
[hotkey]
command="editfillselection"
key="f"
ctrl=yes
alt=no
shift=no
[/hotkey]
[resolution]
width=800
height=600
@ -135,7 +143,7 @@ height=600
[menu]
is_context_menu=true
items=undo,redo,editfloodfill,togglegrid,editsetstartpos
items=undo,redo,editfloodfill,editfillselection,togglegrid,editsetstartpos
[/menu]
# top panel

View file

@ -470,6 +470,10 @@ action_editsaveas="Save As"
action_editquit="Quit Editor"
action_editsetstartpos="Set Player Start Position"
action_editfloodfill="Flood Fill"
action_editfillselection="Fill Selection"
action_edit_cut="Cut"
action_edit_copy="Copy"
action_edit_paste="Paste"
save_hotkeys_button="Save Hotkeys"
change_hotkey_button="Change Hotkey"
hotkeys_dialog="Hotkey Settings"

View file

@ -2133,7 +2133,7 @@ void display::add_highlighted_loc(const gamemap::location &hex) {
}
}
void display::clear_highlighted_locs(const gamemap::location &hex) {
void display::clear_highlighted_locs() {
for (std::set<gamemap::location>::const_iterator it = highlighted_locations_.begin();
it != highlighted_locations_.end(); it++) {
invalidate(*it);

View file

@ -315,7 +315,7 @@ public:
//selecting hexes, it is pure highlighting.
void add_highlighted_loc(const gamemap::location &hex);
void clear_highlighted_locs(const gamemap::location &hex);
void clear_highlighted_locs();
void remove_highlighted_loc(const gamemap::location &hex);

View file

@ -69,7 +69,7 @@ map_editor::map_editor(display &gui, gamemap &map, config &theme, config &game_c
tdown_(gui, "", gui::button::TYPE_PRESS, "downarrow-button"), abort_(DONT_ABORT),
num_operations_since_save_(0), theme_(theme), game_config_(game_config),
draw_terrain_(false), map_dirty_(false),
palette_(gui, size_specs_, map), brush_(gui, size_specs_) {
palette_(gui, size_specs_, map), brush_(gui, size_specs_), add_selection_(false) {
// Set size specs.
@ -127,9 +127,30 @@ void map_editor::handle_mouse_button_event(const SDL_MouseButtonEvent &event,
show_menu(m->items(), mousex, mousey + 1, true);
}
if (button == SDL_BUTTON_LEFT) {
draw_terrain_ = true;
palette_.left_mouse_click(mousex, mousey);
brush_.left_mouse_click(mousex, mousey);
if (key_[SDLK_LSHIFT] || key_[SDLK_RSHIFT]) {
// Set a boolean to indicate wether to add or remove selected hexes.
if (selected_hexes_.find(gui_.hex_clicked_on(mousex, mousey))
== selected_hexes_.end()) {
add_selection_ = true;
}
else {
add_selection_ = false;
}
}
else if (!selected_hexes_.empty()
&& map_.on_board(gui_.hex_clicked_on(mousex, mousey))
&& !(key_[SDLK_LSHIFT] || key_[SDLK_RSHIFT])) {
// If hexes are selected, clear them and do not draw
// anything.
selected_hexes_.clear();
gui_.clear_highlighted_locs();
update_mouse_over_hexes(gui_.hex_clicked_on(mousex, mousey));
}
else {
draw_terrain_ = true;
palette_.left_mouse_click(mousex, mousey);
brush_.left_mouse_click(mousex, mousey);
}
}
}
if (event.type == SDL_MOUSEBUTTONUP) {
@ -222,6 +243,31 @@ void map_editor::edit_load_map() {
}
}
void map_editor::edit_fill_selection() {
map_undo_action undo_action;
for (std::set<gamemap::location>::const_iterator it = selected_hexes_.begin();
it != selected_hexes_.end(); it++) {
if (map_.on_board(*it)) {
undo_action.add(map_.get_terrain(*it), palette_.selected_terrain(), *it);
map_.set_terrain(*it, palette_.selected_terrain());
}
}
add_undo_action(undo_action);
invalidate_all_and_adjacent(selected_hexes_);
}
void map_editor::edit_cut() {
}
void map_editor::edit_copy() {
}
void map_editor::edit_paste() {
}
bool map_editor::can_execute_command(hotkey::HOTKEY_COMMAND command) const {
switch (command) {
case hotkey::HOTKEY_UNDO:
@ -238,6 +284,7 @@ bool map_editor::can_execute_command(hotkey::HOTKEY_COMMAND command) const {
case hotkey::HOTKEY_EDIT_NEW_MAP:
case hotkey::HOTKEY_EDIT_LOAD_MAP:
case hotkey::HOTKEY_EDIT_FLOOD_FILL:
case hotkey::HOTKEY_EDIT_FILL_SELECTION:
return true;
default:
return false;
@ -321,13 +368,49 @@ void map_editor::set_file_to_save_as(const std::string filename) {
void map_editor::left_button_down(const int mousex, const int mousey) {
const gamemap::location& loc = gui_.minimap_location_on(mousex,mousey);
const gamemap::location hex = gui_.hex_clicked_on(mousex, mousey);
if (loc.valid()) {
gui_.scroll_to_tile(loc.x,loc.y,display::WARP,false);
}
else if (key_[SDLK_RSHIFT] || key_[SDLK_LSHIFT]) {
if (key_[SDLK_RALT] || key_[SDLK_LALT]) {
// Select/deselect a component.
std::set<gamemap::location> selected;
selected = get_component(map_, selected_hex_);
for (std::set<gamemap::location>::const_iterator it = selected.begin();
it != selected.end(); it++) {
if (add_selection_) {
gui_.add_highlighted_loc(*it);
selected_hexes_.insert(*it);
}
else {
gui_.remove_highlighted_loc(*it);
selected_hexes_.erase(*it);
}
}
update_mouse_over_hexes(hex);
}
else {
// Select what the brush is over.
std::vector<gamemap::location> selected;
selected = get_tiles(map_, hex, brush_.selected_brush_size());
for (std::vector<gamemap::location>::const_iterator it = selected.begin();
it != selected.end(); it++) {
if (add_selection_) {
gui_.add_highlighted_loc(*it);
selected_hexes_.insert(*it);
}
else {
gui_.remove_highlighted_loc(*it);
selected_hexes_.erase(*it);
}
}
update_mouse_over_hexes(hex);
}
}
// If the left mouse button is down and we beforhand have registred
// a mouse down event, draw terrain at the current location.
else if (draw_terrain_) {
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(key_[SDLK_RCTRL] || key_[SDLK_LCTRL]) {
@ -400,8 +483,7 @@ void map_editor::invalidate_adjacent(const gamemap::location hex) {
}
void map_editor::invalidate_all_and_adjacent(const std::vector<gamemap::location> &hexes) {
/// XXX Change to use a set.
std::vector<gamemap::location> to_invalidate;
std::set<gamemap::location> to_invalidate;
std::vector<gamemap::location>::const_iterator it;
for (it = hexes.begin(); it != hexes.end(); it++) {
terrain_changed(map_, *it);
@ -409,27 +491,31 @@ void map_editor::invalidate_all_and_adjacent(const std::vector<gamemap::location
locs[0] = *it;
get_adjacent_tiles(*it, locs+1);
for(int i = 0; i != 7; ++i) {
to_invalidate.push_back(locs[i]);
to_invalidate.insert(locs[i]);
}
}
std::sort(to_invalidate.begin(), to_invalidate.end());;
std::vector<gamemap::location>::iterator end_of_unique =
std::unique(to_invalidate.begin(), to_invalidate.end());
for (it = to_invalidate.begin(); it != end_of_unique; it++) {
if (!map_.on_board(*it)) {
gamemap::TERRAIN terrain_before = map_.get_terrain(*it);
map_.remove_from_border_cache(*it);
gamemap::TERRAIN terrain_after = map_.get_terrain(*it);
std::set<gamemap::location>::const_iterator its;
for (its = to_invalidate.begin(); its != to_invalidate.end(); its++) {
if (!map_.on_board(*its)) {
gamemap::TERRAIN terrain_before = map_.get_terrain(*its);
map_.remove_from_border_cache(*its);
gamemap::TERRAIN terrain_after = map_.get_terrain(*its);
if (terrain_before != terrain_after) {
invalidate_adjacent(*it);
invalidate_adjacent(*its);
}
}
gui_.rebuild_terrain(*it);
gui_.invalidate(*it);
gui_.rebuild_terrain(*its);
gui_.invalidate(*its);
}
map_dirty_ = true;
}
void map_editor::invalidate_all_and_adjacent(const std::set<gamemap::location> &hexes) {
std::vector<gamemap::location> v;
std::copy(hexes.begin(), hexes.end(), std::back_inserter(v));
invalidate_all_and_adjacent(v);
}
void map_editor::right_button_down(const int mousex, const int mousey) {
}
void map_editor::middle_button_down(const int mousex, const int mousey) {

View file

@ -21,6 +21,8 @@
#include <map>
#include <queue>
#include <set>
#include <vector>
namespace map_editor {
@ -120,7 +122,11 @@ public:
/// position of the given player to the currently selected hex.
virtual void edit_set_start_pos();
virtual void edit_flood_fill();
virtual void edit_fill_selection();
virtual void edit_cut();
virtual void edit_copy();
virtual void edit_paste();
virtual bool can_execute_command(hotkey::HOTKEY_COMMAND command) const;
// Exception thrown when new map is to be loaded.
@ -182,6 +188,7 @@ private:
/// adjacent. Rebuild the terrain on the same hexes. Make sure that
/// the operations only happen once per hex for efficiency purposes.
void invalidate_all_and_adjacent(const std::vector<gamemap::location> &hexes);
void invalidate_all_and_adjacent(const std::set<gamemap::location> &hexes);
/// Re-set the labels for the starting positions of the
/// players. Should be called when the terrain has changed, which
@ -222,6 +229,7 @@ private:
std::vector<gamemap::location> starting_positions_;
std::set<gamemap::location> mouse_over_hexes_;
std::set<gamemap::location> selected_hexes_;
bool add_selection_;
};
}

View file

@ -17,6 +17,7 @@
#include <vector>
#include <map>
#include <algorithm>
#include <set>
namespace map_editor {
@ -56,34 +57,48 @@ void flood_fill(gamemap &map, const gamemap::location &start_loc,
if (fill_with == terrain_to_fill) {
return;
}
std::vector<gamemap::location> to_fill;
// First push the starting location onto a stack. Then, in every
// iteration, pop one element from the stack, fill this tile and add
// all adjacent tiles that have the terrain that should be
// filled. Continue until the stack is empty.
to_fill.push_back(start_loc);
while (!to_fill.empty()) {
gamemap::location loc = to_fill.back();
to_fill.pop_back();
std::set<gamemap::location> to_fill = get_component(map, start_loc);
std::set<gamemap::location>::iterator it;
for (it = to_fill.begin(); it != to_fill.end(); it++) {
gamemap::location loc = *it;
if (log != NULL) {
log->push_back(std::make_pair(loc, terrain_to_fill));
}
map.set_terrain(loc, fill_with);
}
}
std::set<gamemap::location>
get_component(const gamemap &map, const gamemap::location &start_loc) {
gamemap::TERRAIN terrain_to_fill = map.get_terrain(start_loc);
std::set<gamemap::location> to_fill;
std::set<gamemap::location> filled;
std::set<gamemap::location>::iterator it;
// Insert the start location in a set. Chose an element in the set,
// mark this element, and add all adjacent elements that are not
// marked. Continue until the set is empty.
to_fill.insert(start_loc);
while (!to_fill.empty()) {
it = to_fill.begin();
gamemap::location loc = *it;
to_fill.erase(it);
filled.insert(loc);
// Find all adjacent tiles with the terrain that should be
// filled and add these to the to_fill vector.
std::vector<gamemap::location> adj = get_tiles(map, loc, 2);
for (std::vector<gamemap::location>::iterator it2 = adj.begin();
it2 != adj.end(); it2++) {
if (map.get_terrain(*it2) == terrain_to_fill && map.on_board(*it2)) {
to_fill.push_back(*it2);
if (map.on_board(*it2) && map.get_terrain(*it2) == terrain_to_fill
&& filled.find(*it2) == filled.end()) {
to_fill.insert(*it2);
}
}
// Remove duplicates.
std::sort(to_fill.begin(), to_fill.end());
std::vector<gamemap::location>::iterator end_of_unique =
std::unique(to_fill.begin(), to_fill.end());
to_fill.erase(end_of_unique, to_fill.end());
}
return filled;
}
}

View file

@ -16,6 +16,7 @@
#include "../map.hpp"
#include <vector>
#include <set>
namespace map_editor {
@ -31,6 +32,10 @@ typedef std::vector<std::pair<gamemap::location, gamemap::TERRAIN> > terrain_log
/// started.
void flood_fill(gamemap &map, const gamemap::location &start_loc,
const gamemap::TERRAIN fill_with, terrain_log *log = NULL);
/// The the area that would be flood filled if a flood fill was requested.
std::set<gamemap::location>
get_component(const gamemap &map, const gamemap::location &start_loc);
}

View file

@ -74,6 +74,10 @@ HOTKEY_COMMAND string_to_command(const std::string& str)
m.insert(val("editsaveas",HOTKEY_EDIT_SAVE_AS));
m.insert(val("editsetstartpos",HOTKEY_EDIT_SET_START_POS));
m.insert(val("editfloodfill",HOTKEY_EDIT_FLOOD_FILL));
m.insert(val("editfillselection",HOTKEY_EDIT_FILL_SELECTION));
m.insert(val("editcut",HOTKEY_EDIT_CUT));
m.insert(val("editcopy",HOTKEY_EDIT_COPY));
m.insert(val("editpsate",HOTKEY_EDIT_COPY));
m.insert(val("toggleshroud",HOTKEY_TOGGLE_SHROUD));
m.insert(val("updateshroud",HOTKEY_UPDATE_SHROUD));
}
@ -423,6 +427,23 @@ void execute_command(display& disp, HOTKEY_COMMAND command, command_executor* ex
if(executor)
executor->edit_flood_fill();
break;
case HOTKEY_EDIT_FILL_SELECTION:
if(executor)
executor->edit_fill_selection();
break;
case HOTKEY_EDIT_CUT:
if(executor)
executor->edit_cut();
break;
case HOTKEY_EDIT_PASTE:
if(executor)
executor->edit_paste();
break;
case HOTKEY_EDIT_COPY:
if(executor)
executor->edit_copy();
break;
default:
break;
}

View file

@ -41,6 +41,8 @@ enum HOTKEY_COMMAND { HOTKEY_CYCLE_UNITS, HOTKEY_END_UNIT_TURN, HOTKEY_LEADER,
HOTKEY_EDIT_QUIT, HOTKEY_EDIT_SAVE_MAP,
HOTKEY_EDIT_SAVE_AS, HOTKEY_EDIT_SET_START_POS,
HOTKEY_EDIT_NEW_MAP, HOTKEY_EDIT_LOAD_MAP, HOTKEY_EDIT_FLOOD_FILL,
HOTKEY_EDIT_FILL_SELECTION, HOTKEY_EDIT_CUT, HOTKEY_EDIT_COPY,
HOTKEY_EDIT_PASTE,
HOTKEY_NULL };
struct hotkey_item {
@ -119,6 +121,10 @@ public:
virtual void edit_save_as() {}
virtual void edit_set_start_pos() {}
virtual void edit_flood_fill() {}
virtual void edit_fill_selection() {}
virtual void edit_cut() {}
virtual void edit_copy() {}
virtual void edit_paste() {}
virtual bool can_execute_command(HOTKEY_COMMAND command) const = 0;
};