[[Fixes for drag-move editing]]

- Fix a bug with the drag-move in editor (collision between read and
write if source and destination areas are not disjoint)

- Introduce a map_buffer type to handle this kind of operations and
simplify the clipboard functions

- Simplify the arithmetic operations about cartesian/hexagonal translations
This commit is contained in:
Ali El Gariani 2007-09-21 23:54:56 +00:00
parent 15fa492f92
commit c5dd72d4c5
2 changed files with 92 additions and 123 deletions

View File

@ -633,56 +633,23 @@ 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_terrain(map_.get_terrain(*it), palette_.selected_fg_terrain(), *it);
map_.set_terrain(*it, palette_.selected_fg_terrain());
}
}
terrain_changed(selected_hexes_);
perform_fill_selection(undo_action);
save_undo_action(undo_action);
}
void map_editor::edit_cut() {
clipboard_.clear();
insert_selection_in_clipboard();
edit_copy();
edit_fill_selection();
}
void map_editor::edit_copy() {
clipboard_.clear();
clear_buffer(clipboard_);
insert_selection_in_clipboard();
}
void map_editor::perform_paste() {
map_undo_action undo_action;
std::set<gamemap::location> filled;
gamemap::location start_hex = selected_hex_;
clear_highlighted_hexes_in_gui();
for (std::vector<clipboard_item>::const_iterator it = clipboard_.begin();
it != clipboard_.end(); it++) {
gamemap::location l(clipboard_offset_loc_.x + (*it).x_offset,
clipboard_offset_loc_.y + (*it).y_offset);
const int x_offset = start_hex.x - clipboard_offset_loc_.x;
const int y_offset = start_hex.y - clipboard_offset_loc_.y;
gamemap::location target = get_hex_with_offset(l, x_offset, y_offset);
if (map_.on_board(target)) {
undo_action.add_terrain(map_.get_terrain(target), (*it).terrain, target);
map_.set_terrain(target, (*it).terrain);
const int start_side = (*it).starting_side;
if (start_side != -1) {
undo_action.add_starting_location(start_side, start_side,
map_.starting_position(start_side), target);
map_.set_starting_position(start_side, target);
}
filled.insert(target);
gui_.add_highlighted_loc(target);
}
}
undo_action.set_selection(selected_hexes_, filled);
terrain_changed(filled);
selected_hexes_ = filled;
paste_buffer(clipboard_, selected_hex_, undo_action);
save_undo_action(undo_action);
}
@ -786,28 +753,76 @@ hotkey::ACTION_STATE map_editor::get_action_state(hotkey::HOTKEY_COMMAND command
return command_executor::get_action_state(command);
}
void map_editor::insert_selection_in_clipboard() {
if (selected_hexes_.empty()) {
return;
}
gamemap::location offset_hex = *(selected_hexes_.begin());
void map_editor::copy_buffer(map_buffer& buffer, const std::set<gamemap::location> &locs, const gamemap::location &origin)
{
std::set<gamemap::location>::const_iterator it;
// Find the hex that is closest to the selected one,
// use this as the one to calculate the offset from.
for (it = selected_hexes_.begin(); it != selected_hexes_.end(); it++) {
if (distance_between(selected_hex_, *it) <
distance_between(selected_hex_, offset_hex)) {
offset_hex = *it;
for (it = locs.begin(); it != locs.end(); it++) {
t_translation::t_letter terrain = map_.get_terrain(*it);
buffer.push_back(buffer_item(*it-origin, terrain, starting_side_at(map_, *it)));
}
}
void map_editor::paste_buffer(const map_buffer &buffer, const gamemap::location &loc, map_undo_action &undo_action)
{
std::set<gamemap::location> filled;
std::vector<buffer_item>::const_iterator it;
for (it = buffer.begin(); it != buffer.end(); it++) {
//the addition of locations is not commutative !
gamemap::location target = it->offset + loc;
if (map_.on_board(target)) {
undo_action.add_terrain(map_.get_terrain(target), it->terrain, target);
map_.set_terrain(target, it->terrain);
const int start_side = it->starting_side;
if (start_side != -1) {
undo_action.add_starting_location(start_side, start_side,
map_.starting_position(start_side), target);
map_.set_starting_position(start_side, target);
}
filled.insert(target);
}
}
clipboard_offset_loc_ = offset_hex;
terrain_changed(filled);
undo_action.set_selection(selected_hexes_, filled);
selected_hexes_ = filled;
highlight_selected_hexes(true);
}
void map_editor::insert_selection_in_clipboard() {
// Find the hex that is closest to the selected one,
// use this as origin
gamemap::location origin(1000,1000);
std::set<gamemap::location>::const_iterator it;
for (it = selected_hexes_.begin(); it != selected_hexes_.end(); it++) {
const int x_offset = (*it).x - offset_hex.x;
const int y_offset = (*it).y - offset_hex.y;
t_translation::t_letter terrain = map_.get_terrain(*it);
clipboard_.push_back(clipboard_item(x_offset, y_offset, terrain,
starting_side_at(map_, *it)));
if (distance_between(selected_hex_, *it) <
distance_between(selected_hex_, origin)) {
origin = *it;
}
}
copy_buffer(clipboard_, selected_hexes_, origin);
}
void map_editor::perform_fill_selection(map_undo_action &undo_action) {
std::set<gamemap::location>::const_iterator it;
for (it = selected_hexes_.begin(); it != selected_hexes_.end(); it++) {
if (map_.on_board(*it)) {
undo_action.add_terrain(map_.get_terrain(*it), palette_.selected_bg_terrain(), *it);
map_.set_terrain(*it, palette_.selected_bg_terrain());
}
}
terrain_changed(selected_hexes_);
}
void map_editor::perform_selection_move() {
map_undo_action undo_action;
map_buffer buf;
copy_buffer(buf, selected_hexes_, selection_move_start_);
perform_fill_selection(undo_action);
paste_buffer(buf,selected_hex_, undo_action);
save_undo_action(undo_action);
}
@ -1042,15 +1057,6 @@ void map_editor::set_file_to_save_as(const std::string filename, bool from_scena
from_scenario_ = from_scenario;
}
gamemap::location map_editor::get_hex_with_offset(const gamemap::location loc,
const int x_offset, const int y_offset) {
gamemap::location new_loc(loc.x + x_offset, loc.y + y_offset);
if (new_loc.x % 2 != loc.x % 2 && is_odd(new_loc.x)) {
new_loc.y--;
}
return new_loc;
}
void map_editor::left_button_down(const int mousex, const int mousey) {
const gamemap::location& minimap_loc = gui_.minimap_location_on(mousex,mousey);
const gamemap::location hex = gui_.hex_clicked_on(mousex, mousey);
@ -1101,14 +1107,12 @@ void map_editor::left_button_down(const int mousex, const int mousey) {
}
else if (l_button_held_func_ == MOVE_SELECTION) {
reset_mouseover_overlay();
const int x_diff = hex.x - selection_move_start_.x;
const int y_diff = hex.y - selection_move_start_.y;
//(*it-selection_move_start_) + hex
// No other selections should be active when doing this.
gui_.clear_highlighted_locs();
for (std::set<gamemap::location>::const_iterator it = selected_hexes_.begin();
it != selected_hexes_.end(); it++) {
const gamemap::location hl_loc =
get_hex_with_offset(*it, x_diff, y_diff);
std::set<gamemap::location>::const_iterator it;
for (it = selected_hexes_.begin(); it != selected_hexes_.end(); it++) {
const gamemap::location hl_loc = (*it-selection_move_start_) + hex;
if (map_.on_board(hl_loc)) {
gui_.add_highlighted_loc(hl_loc);
}
@ -1148,45 +1152,6 @@ void map_editor::draw_on_mouseover_hexes(const t_translation::t_letter terrain)
}
}
void map_editor::perform_selection_move() {
map_undo_action undo_action;
const int x_diff = selected_hex_.x - selection_move_start_.x;
const int y_diff = selected_hex_.y - selection_move_start_.y;
clear_highlighted_hexes_in_gui();
std::set<gamemap::location> new_selection;
// Transfer the terrain to the new position.
std::set<gamemap::location>::const_iterator it;
for(it = selected_hexes_.begin(); it != selected_hexes_.end(); it++) {
const gamemap::location hl_loc =
get_hex_with_offset(*it, x_diff, y_diff);
if (map_.on_board(hl_loc)) {
undo_action.add_terrain(map_.get_terrain(hl_loc), map_.get_terrain(*it), hl_loc);
gui_.add_highlighted_loc(hl_loc);
map_.set_terrain(hl_loc, map_.get_terrain(*it));
const int start_side = starting_side_at(map_, *it);
if (start_side != -1) {
// Starting side at the old location that needs transfering.
map_.set_starting_position(start_side, hl_loc);
undo_action.add_starting_location(start_side, start_side, *it, hl_loc);
}
new_selection.insert(hl_loc);
}
}
// Fill the selection with the selected terrain.
for (it = selected_hexes_.begin(); it != selected_hexes_.end(); it++) {
if (map_.on_board(*it) && new_selection.find(*it) == new_selection.end()) {
undo_action.add_terrain(map_.get_terrain(*it), palette_.selected_bg_terrain(), *it);
map_.set_terrain(*it, palette_.selected_bg_terrain());
}
}
undo_action.set_selection(selected_hexes_, new_selection);
terrain_changed(selected_hexes_);
selected_hexes_ = new_selection;
terrain_changed(selected_hexes_);
save_undo_action(undo_action);
}
void map_editor::draw_terrain(const t_translation::t_letter terrain,
const gamemap::location hex)
{

View File

@ -232,11 +232,8 @@ private:
/// Insert the currently selected locations in the clipboard.
void insert_selection_in_clipboard();
/// Return the hex with the given offset from loc. Make calculations
/// so the result with have the same _appearance_ as when the offset
/// was calculated ,not the same representation.
gamemap::location get_hex_with_offset(const gamemap::location loc,
const int x_offset, const int y_offset);
/// Commit a selection filling.
void perform_fill_selection(map_undo_action &undo_action);
/// Commit the movement of a selection.
void perform_selection_move();
@ -292,19 +289,26 @@ private:
// Load the tooltips for each button
void load_tooltips(void);
/// An item in the clipboard. Consists of the copied terrain and an
/// An item in the buffer. Consists of the copied terrain and an
/// offset. When pasting stuff, the offset is used to calculate
/// where to put the pasted hex when calculating from the one
/// selected when the paste takes place.
struct clipboard_item {
clipboard_item(int xo, int yo, t_translation::t_letter t, int start_side) :
x_offset(xo), y_offset(yo), terrain(t),
starting_side(start_side){}
int x_offset, y_offset;
/// where to put the pasted hex
struct buffer_item {
buffer_item(const gamemap::location &o, t_translation::t_letter t, int start_side) :
offset(o), terrain(t), starting_side(start_side) {}
gamemap::location offset;
t_translation::t_letter terrain;
int starting_side;
};
// map_buffer is used for clipboard and other map operations
typedef std::vector<buffer_item> map_buffer;
void copy_buffer(map_buffer& buffer, const std::set<gamemap::location> &locs,
const gamemap::location &origin);
void paste_buffer(const map_buffer& buffer, const gamemap::location &loc,
map_undo_action &undo_action);
void clear_buffer(map_buffer& buffer) {buffer.clear();};
editor_display &gui_;
editormap &map_;
std::string filename_, original_filename_;
@ -331,8 +335,8 @@ private:
std::vector<gamemap::location> starting_positions_;
std::set<gamemap::location> mouse_over_hexes_;
std::set<gamemap::location> selected_hexes_;
std::vector<clipboard_item> clipboard_;
gamemap::location clipboard_offset_loc_;
map_buffer clipboard_;
LEFT_BUTTON_HELD_FUNC l_button_held_func_;
gamemap::location selection_move_start_;