editor2: followup to 2008-08-20T21:14:42Z!kailoran@gmail.com:

...fix issues with click-drag undo in paint and select operations
(separate fixes). Get rid of editor_action_select_xor. Some doc
comments that got caught in the way.
This commit is contained in:
Tomasz Śniatowski 2008-08-21 00:40:44 +01:00
parent 4eae029023
commit 3335b9c4a3
6 changed files with 107 additions and 50 deletions

View file

@ -96,6 +96,7 @@ void editor_action_area::extend(const editor_map& map, const std::set<gamemap::l
void editor_action_paste::extend(const editor_map& map, const std::set<gamemap::location>& locs)
{
LOG_ED << "Area extend\n";
paste_.add_tiles(map, locs);
}
editor_action_paste* editor_action_paste::perform(map_context& mc) const
@ -184,24 +185,17 @@ void editor_action_starting_position::perform_without_undo(map_context& mc) cons
mc.set_needs_labels_reset();
}
editor_action_select_xor* editor_action_select_xor::perform(map_context& mc) const
void editor_action_select::extend(const editor_map& map, const std::set<gamemap::location>& locs)
{
perform_without_undo(mc);
return new editor_action_select_xor(area_);
}
void editor_action_select_xor::perform_without_undo(map_context& mc) const
{
foreach (const gamemap::location& loc, area_) {
if (mc.get_map().in_selection(loc)) {
mc.get_map().remove_from_selection(loc);
} else {
mc.get_map().add_to_selection(loc);
foreach (const gamemap::location& loc, locs) {
LOG_ED << "Checking " << loc << "\n";
if (map.in_selection(loc)) {
LOG_ED << "Extending by " << loc << "\n";
area_.insert(loc);
}
mc.add_changed_location(loc);
}
}
editor_action_select_xor* editor_action_select::perform(map_context& mc) const
editor_action* editor_action_select::perform(map_context& mc) const
{
std::set<gamemap::location> undo_locs;
foreach (const gamemap::location& loc, area_) {
@ -211,7 +205,7 @@ editor_action_select_xor* editor_action_select::perform(map_context& mc) const
}
}
perform_without_undo(mc);
return new editor_action_select_xor(undo_locs);
return new editor_action_deselect(undo_locs);
}
void editor_action_select::perform_without_undo(map_context& mc) const
{
@ -221,7 +215,17 @@ void editor_action_select::perform_without_undo(map_context& mc) const
}
}
editor_action_select_xor* editor_action_deselect::perform(map_context& mc) const
void editor_action_deselect::extend(const editor_map& map, const std::set<gamemap::location>& locs)
{
foreach (const gamemap::location& loc, locs) {
LOG_ED << "Checking " << loc << "\n";
if (!map.in_selection(loc)) {
LOG_ED << "Extending by " << loc << "\n";
area_.insert(loc);
}
}
}
editor_action* editor_action_deselect::perform(map_context& mc) const
{
std::set<gamemap::location> undo_locs;
foreach (const gamemap::location& loc, area_) {
@ -231,7 +235,7 @@ editor_action_select_xor* editor_action_deselect::perform(map_context& mc) const
}
}
perform_without_undo(mc);
return new editor_action_select_xor(undo_locs);
return new editor_action_select(undo_locs);
}
void editor_action_deselect::perform_without_undo(map_context& mc) const
{
@ -241,7 +245,7 @@ void editor_action_deselect::perform_without_undo(map_context& mc) const
}
}
editor_action_select_xor* editor_action_select_all::perform(map_context& mc) const
editor_action_deselect* editor_action_select_all::perform(map_context& mc) const
{
std::set<gamemap::location> current = mc.get_map().selection();
@ -252,7 +256,7 @@ editor_action_select_xor* editor_action_select_all::perform(map_context& mc) con
current.begin(), current.end(),
std::inserter(undo_locs, undo_locs.begin()));
mc.set_everything_changed();
return new editor_action_select_xor(undo_locs);
return new editor_action_deselect(undo_locs);
}
void editor_action_select_all::perform_without_undo(map_context& mc) const
{
@ -260,13 +264,13 @@ void editor_action_select_all::perform_without_undo(map_context& mc) const
mc.set_everything_changed();
}
editor_action_select_xor* editor_action_select_none::perform(map_context& mc) const
editor_action_select* editor_action_select_none::perform(map_context& mc) const
{
std::set<gamemap::location> current = mc.get_map().selection();
mc.get_map().clear_selection();
mc.set_everything_changed();
return new editor_action_select_xor(current);
return new editor_action_select(current);
}
void editor_action_select_none::perform_without_undo(map_context& mc) const
{

View file

@ -44,12 +44,24 @@ class editor_action_whole_map : public editor_action
editor_map m_;
};
/**
* Base class for actions that:
* 1) operate on an area
* 2) can be used as undo for a click-drag operation
* 3) can be extended so one undo action undos several actual drag actions
*/
class editor_action_extendable : public editor_action
{
public:
editor_action_extendable()
{
}
/**
* The crux of the extendable contract. This member function must be
* implemented so that the undo behaviour is consistent, exactly the
* same as would be with separate undo actions for every part of
* the drag.
*/
virtual void extend(const editor_map& map, const std::set<gamemap::location>& locs) = 0;
};
@ -209,20 +221,6 @@ class editor_action_starting_position : public editor_action_location
int player_;
};
/**
* "xor" select action, used as undo in select/deselect
*/
class editor_action_select_xor : public editor_action_area
{
public:
editor_action_select_xor(const std::set<gamemap::location>& area)
: editor_action_area(area)
{
}
editor_action_select_xor* perform(map_context& mc) const;
void perform_without_undo(map_context& mc) const;
};
/**
* Select the given locations
*/
@ -233,7 +231,8 @@ class editor_action_select : public editor_action_area
: editor_action_area(area)
{
}
editor_action_select_xor* perform(map_context& mc) const;
void extend(const editor_map& map, const std::set<gamemap::location>& locs);
editor_action* perform(map_context& mc) const;
void perform_without_undo(map_context& mc) const;
};
@ -247,7 +246,8 @@ class editor_action_deselect : public editor_action_area
: editor_action_area(area)
{
}
editor_action_select_xor* perform(map_context& mc) const;
void extend(const editor_map& map, const std::set<gamemap::location>& locs);
editor_action* perform(map_context& mc) const;
void perform_without_undo(map_context& mc) const;
};
@ -260,7 +260,7 @@ class editor_action_select_all : public editor_action
editor_action_select_all()
{
}
editor_action_select_xor* perform(map_context& mc) const;
editor_action_deselect* perform(map_context& mc) const;
void perform_without_undo(map_context& mc) const;
};
@ -273,7 +273,7 @@ class editor_action_select_none : public editor_action
editor_action_select_none()
{
}
editor_action_select_xor* perform(map_context& mc) const;
editor_action_select* perform(map_context& mc) const;
void perform_without_undo(map_context& mc) const;
};

View file

@ -34,10 +34,21 @@ namespace editor2 {
class map_context : private boost::noncopyable
{
public:
/**
* A map context can only by created from an existing map
*/
map_context(const editor_map& map);
~map_context();
/**
* Map accesor
*/
editor_map& get_map() { return map_; };
/**
* Map accesor - const version
*/
const editor_map& get_map() const { return map_; }
/**
@ -54,13 +65,35 @@ public:
void draw_terrain(t_translation::t_terrain terrain, const std::set<gamemap::location>& locs,
bool one_layer_only = false);
/**
* Getter for the reload flag. Reload is the highest level of required refreshing,
* set when the map size has changed or the map was reassigned.
*/
bool needs_reload() const { return needs_reload_; }
/**
* Setter for the reload flag
*/
void set_needs_reload(bool value=true) { needs_reload_ = value; }
/**
* Getter for the terrain rebuild flag. Set whenever any terrain has changed.
*/
bool needs_terrain_rebuild() const { return needs_terrain_rebuild_; }
/**
* Setter for the terrain rebuild flag
*/
void set_needs_terrain_rebuild(bool value=true) { needs_terrain_rebuild_ = value; }
/**
* Getter fo the labels reset flag. Set when the labels need to be refreshed.
*/
bool needs_labels_reset() const { return needs_labels_reset_; }
/**
* Setter for the labels reset flag
*/
void set_needs_labels_reset(bool value=true) { needs_labels_reset_ = value; }
const std::set<gamemap::location> changed_locations() const { return changed_locations_; }
@ -78,6 +111,10 @@ public:
void set_filename(const std::string& fn) { filename_ = fn; }
/**
* Saves the map under the current filename. Filename must be valid.
* May throw an exception on failure.
*/
bool save();
/**
@ -87,6 +124,11 @@ public:
*/
void perform_action(const editor_action& action);
/**
* Performs a partial action, assumes that the top undo action has been modified to
* maintain coherent state of the undo stacks, and so a new undo action is not
* created.
*/
void perform_partial_action(const editor_action& action);
/** @return whether the map was modified since the last save */

View file

@ -31,7 +31,10 @@ map_fragment::map_fragment(const gamemap& map, const std::set<gamemap::location>
void map_fragment::add_tile(const gamemap& map, const gamemap::location& loc)
{
items_.push_back(tile_info(map, loc));
if (area_.find(loc) == area_.end()) {
items_.push_back(tile_info(map, loc));
area_.insert(loc);
}
}
void map_fragment::add_tiles(const gamemap& map, const std::set<gamemap::location>& locs)
@ -43,11 +46,7 @@ void map_fragment::add_tiles(const gamemap& map, const std::set<gamemap::locatio
std::set<gamemap::location> map_fragment::get_area() const
{
std::set<gamemap::location> result;
foreach (const tile_info& i, items_) {
result.insert(i.offset);
}
return result;
return area_;
}
std::set<gamemap::location> map_fragment::get_offset_area(const gamemap::location& loc) const
@ -113,6 +112,7 @@ void map_fragment::center_by_mass()
void map_fragment::rotate_60_cw()
{
area_.clear();
foreach (tile_info& ti, items_) {
gamemap::location l(0,0);
int x = ti.offset.x;
@ -123,6 +123,7 @@ void map_fragment::rotate_60_cw()
l = l.get_direction(gamemap::location::SOUTH_EAST, (x-is_odd(x))/2 );
l = l.get_direction(gamemap::location::SOUTH_WEST, y);
ti.offset = l;
area_.insert(l);
}
if (get_area().size() != items_.size()) {
throw editor_exception("Map fragment rotation resulted in duplicate entries");
@ -131,6 +132,7 @@ void map_fragment::rotate_60_cw()
void map_fragment::rotate_60_ccw()
{
area_.clear();
foreach (tile_info& ti, items_) {
gamemap::location l(0,0);
int x = ti.offset.x;
@ -141,6 +143,7 @@ void map_fragment::rotate_60_ccw()
l = l.get_direction(gamemap::location::NORTH_EAST, (x+is_odd(x))/2 );
l = l.get_direction(gamemap::location::SOUTH_EAST, y);
ti.offset = l;
area_.insert(l);
}
if (get_area().size() != items_.size()) {
throw editor_exception("Map fragment rotation resulted in duplicate entries");

View file

@ -127,8 +127,13 @@ class map_fragment
* Rotate the map fragment 60 degrees counter-clockwise around (0,0)
*/
void rotate_60_ccw();
protected:
/**
* The data of this map_fragment
*/
std::vector<tile_info> items_;
std::set<gamemap::location> area_;
};
} //end namespace editor2

View file

@ -177,9 +177,6 @@ public:
editor_action* drag_end(editor_display& disp, int x, int y);
protected:
template <editor_action_extendable* (brush_drag_mouse_action::*perform_func)(editor_display&, const std::set<gamemap::location>&)>
editor_action* drag_generic(editor_display& disp, int x, int y, bool& partial, editor_action* last_undo);
/** Brush accessor */
const brush& get_brush();
@ -189,9 +186,15 @@ protected:
*/
gamemap::location previous_drag_hex_;
editor_action* foo(editor_display&, const std::set<gamemap::location>&) {return NULL;}
editor_action* bar(editor_display&, const std::set<gamemap::location>&) {return NULL;}
private:
/**
* Template helper gathering actions common for both drag_right and drag_left.
* The drags differ only in the worker function called, which should be
* passed as the template parameter. This exists only to avoid copy-pasting code.
*/
template <editor_action_extendable* (brush_drag_mouse_action::*perform_func)(editor_display&, const std::set<gamemap::location>&)>
editor_action* drag_generic(editor_display& disp, int x, int y, bool& partial, editor_action* last_undo);
/**
* Current brush handle. Currently a pointer-to-pointer with full constness.
*/