editor2: rotate clipboard 60 degrees cw/ccw feature, map_fragment doc comments

This commit is contained in:
Tomasz Śniatowski 2008-08-20 10:33:51 +01:00
parent 88cb10df99
commit ebc01fba94
12 changed files with 226 additions and 28 deletions

View file

@ -1,5 +1,8 @@
Version 1.5.3+svn:
* Campaigns:
* Editor2:
* rotate clipboard 60 deg. cw/ccw, ctrl+r/ctrl+shift+r respectively
(cmd instead of ctrl on Mac). Active in the "paste" mode.
* Language and i18n:
* updated translations:

View file

@ -76,6 +76,19 @@
{IF_APPLE_CMD_ELSE_CTRL}
[/hotkey]
[hotkey]
command="editor-clipboard-rotate-cw"
key="r"
{IF_APPLE_CMD_ELSE_CTRL}
[/hotkey]
[hotkey]
command="editor-clipboard-rotate-ccw"
key="r"
shift=yes
{IF_APPLE_CMD_ELSE_CTRL}
[/hotkey]
[hotkey]
command="editor-tool-next"
key="n"

View file

@ -130,7 +130,7 @@
id=menu-editor-edit
title= _ "Edit"
image=lite
items=undo,redo,editor-cut,editor-copy,editor-paste,editor-select-all,editor-select-inverse,editor-select-none,editor-selection-fill,editor-selection-rotate,editor-selection-flip,editor-selection-generate,editor-selection-randomize
items=undo,redo,editor-cut,editor-copy,editor-paste,editor-select-all,editor-select-inverse,editor-select-none,editor-selection-fill,editor-selection-rotate,editor-selection-flip,editor-selection-generate,editor-selection-randomize,editor-clipboard-rotate-cw,editor-clipboard-rotate-ccw
rect="+2,=,+100,="
xanchor=fixed
yanchor=fixed

View file

@ -3,6 +3,11 @@ changes may be omitted). For a complete list of changes, see the main
changelog: http://svn.gna.org/viewcvs/*checkout*/wesnoth/trunk/changelog
Version 1.5.3:
* Editor2
* Rotate clipboard 60 degrees clockwise or counter-clockwise, ctrl+r
or ctrl+shift+r respectively (cmd instead of ctrl on Mac). Active
in the "paste" mode.
* Language and translations
* updated translations:

View file

@ -485,6 +485,9 @@ bool editor_controller::can_execute_command(hotkey::HOTKEY_COMMAND command, int
return false; //not implemented
case HOTKEY_EDITOR_PASTE:
return !clipboard_.empty();
case HOTKEY_EDITOR_CLIPBOARD_ROTATE_CW:
case HOTKEY_EDITOR_CLIPBOARD_ROTATE_CCW:
return !clipboard_.empty() && is_mouse_action_set(HOTKEY_EDITOR_PASTE);
case HOTKEY_EDITOR_SELECT_ALL:
case HOTKEY_EDITOR_SELECT_INVERSE:
case HOTKEY_EDITOR_SELECT_NONE:
@ -543,6 +546,14 @@ bool editor_controller::execute_command(hotkey::HOTKEY_COMMAND command, int inde
case HOTKEY_EDITOR_PASTE: //paste is somewhat different as it might be "one action then revert to previous mode"
hotkey_set_mouse_action(command);
return true;
case HOTKEY_EDITOR_CLIPBOARD_ROTATE_CW:
clipboard_.rotate_60_cw();
update_mouse_action_highlights();
return true;
case HOTKEY_EDITOR_CLIPBOARD_ROTATE_CCW:
clipboard_.rotate_60_ccw();
update_mouse_action_highlights();
return true;
case HOTKEY_EDITOR_BRUSH_NEXT:
cycle_brush();
return true;
@ -672,18 +683,15 @@ void editor_controller::show_menu(const std::vector<std::string>& items_arg, int
void editor_controller::cycle_brush()
{
int x, y;
SDL_GetMouseState(&x, &y);
gamemap::location hex_clicked = gui().hex_clicked_on(x,y);
gui().invalidate(get_brush()->project(hex_clicked));
DBG_ED << __FUNCTION__ << "\n";
if (brush_ == &brushes_.back()) {
brush_ = &brushes_.front();
} else {
++brush_;
}
std::set<gamemap::location> new_brush_locs = get_brush()->project(hex_clicked);
gui().set_brush_locs(new_brush_locs);
gui().invalidate(new_brush_locs);
DBG_ED << &brushes_.front() << " " << brush_ << " " << &brushes_.back() << "\n";
update_mouse_action_highlights();
DBG_ED << "END\n";
}
void editor_controller::preferences()
@ -702,7 +710,7 @@ void editor_controller::copy_selection()
{
if (!get_map().selection().empty()) {
clipboard_ = map_fragment(get_map(), get_map().selection());
clipboard_.center();
clipboard_.center_by_mass();
}
}
@ -746,6 +754,15 @@ bool editor_controller::is_mouse_action_set(hotkey::HOTKEY_COMMAND command) cons
return (i != mouse_actions_.end()) && (i->second == mouse_action_);
}
void editor_controller::update_mouse_action_highlights()
{
DBG_ED << __FUNCTION__ << "\n";
int x, y;
SDL_GetMouseState(&x, &y);
gamemap::location hex_clicked = gui().hex_clicked_on(x,y);
get_mouse_action()->update_brush_highlights(gui(), hex_clicked);
}
events::mouse_handler_base& editor_controller::get_mouse_handler_base()
{

View file

@ -191,6 +191,8 @@ class editor_controller : public controller_base,
* @return true if the mouse action identified by the hotkey is active
*/
bool is_mouse_action_set(hotkey::HOTKEY_COMMAND command) const;
void update_mouse_action_highlights();
/* mouse_handler_base overrides */
void mouse_motion(int x, int y, const bool browse, bool update);

View file

@ -33,7 +33,7 @@ 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(loc, map.get_terrain(loc)));
items_.push_back(tile_info(map, loc));
}
std::set<gamemap::location> map_fragment::get_area() const
@ -61,20 +61,88 @@ void map_fragment::paste_into(gamemap& map, const gamemap::location& loc) const
}
}
void map_fragment::center()
void map_fragment::shift(const gamemap::location& offset)
{
foreach (tile_info& ti, items_) {
ti.offset.vector_sum_assign(offset);
}
}
gamemap::location map_fragment::center_of_bounds() const
{
if (empty()) return gamemap::location();
gamemap::location top_left = items_[0].offset;
gamemap::location bottom_right = items_[0].offset;
for (size_t i = 1; i < items_.size(); ++i) {
const gamemap::location& loc = items_[i].offset;
if (loc.x < top_left.x) top_left.x = loc.x;
else if (loc.x > bottom_right.x) bottom_right.x = loc.x;
if (loc.y < top_left.y) top_left.y = loc.y;
else if (loc.y > bottom_right.y) bottom_right.y = loc.y;
}
gamemap::location c((top_left.x + bottom_right.x) / 2,
(top_left.y + bottom_right.y) / 2);
return c;
}
gamemap::location map_fragment::center_of_mass() const
{
gamemap::location sum(0, 0);
foreach (tile_info& ti, items_) {
sum.x += ti.offset.x;
sum.y += ti.offset.y;
foreach (const tile_info& ti, items_) {
sum.vector_sum_assign(ti.offset);
}
sum.x /= items_.size();
sum.y /= items_.size();
foreach (tile_info& ti, items_) {
ti.offset.vector_difference_assign(sum);
}
return sum;
}
void map_fragment::center_by_bounds()
{
shift(center_of_bounds().vector_negation());
}
void map_fragment::center_by_mass()
{
shift(center_of_mass().vector_negation());
}
void map_fragment::rotate_60_cw()
{
foreach (tile_info& ti, items_) {
gamemap::location l(0,0);
int x = ti.offset.x;
int y = ti.offset.y;
// rotate the X-Y axes to SOUTH/SOUTH_EAST - SOUTH_WEST axes
// but if x is odd, simply using x/2 + x/2 will lack a step
l = l.get_direction(gamemap::location::SOUTH, (x+is_odd(x))/2);
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;
}
if (get_area().size() != items_.size()) {
throw editor_exception("Map fragment rotation resulted in duplicate entries");
}
}
void map_fragment::rotate_60_ccw()
{
foreach (tile_info& ti, items_) {
gamemap::location l(0,0);
int x = ti.offset.x;
int y = ti.offset.y;
// rotate the X-Y axes to SOUTH/SOUTH_EAST - SOUTH_WEST axes
// but if x is odd, simply using x/2 + x/2 will lack a step
l = l.get_direction(gamemap::location::NORTH, (x-is_odd(x))/2);
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;
}
if (get_area().size() != items_.size()) {
throw editor_exception("Map fragment rotation resulted in duplicate entries");
}
}
bool map_fragment::empty() const
{
return items_.empty();

View file

@ -23,28 +23,105 @@
namespace editor2 {
/**
* This represents a tile along with information about it, namely the terrain,
* possibly other information. It is a less compact representation that what
* is used in the map, but is more convenient in some situations.
*/
struct tile_info
{
tile_info(const gamemap::location& offset, t_translation::t_terrain terrain)
: offset(offset), terrain(terrain)
/**
* Create a tile info -- the constructor grabs required data from the map
*/
tile_info(const gamemap& map, const gamemap::location& offset)
: offset(offset), terrain(map.get_terrain(offset))
{
}
gamemap::location offset;
t_translation::t_terrain terrain;
};
/**
* A map fragment -- a collection of locations and information abut them.
*/
class map_fragment
{
public:
/**
* Create an empty map fragment.
*/
map_fragment();
/**
* Create a map fragment from the specified locations on the map.
*/
map_fragment(const gamemap& map, const std::set<gamemap::location>& area);
/**
* Add a single location and pull its info from the map.
*/
void add_tile(const gamemap& map, const gamemap::location& loc);
/**
* Get the tile_info vector.
*/
const std::vector<tile_info>& get_items() const { return items_; }
/**
* Get the area covered by this map fragment.
*/
std::set<gamemap::location> get_area() const;
std::set<gamemap::location> get_offset_area(const gamemap::location& loc) const;
/**
* Get the area covered by this map fragment, shifted by an offset.
*/
std::set<gamemap::location> get_offset_area(const gamemap::location& offset) const;
/**
* Paste the map fragment into the map, treating loc as the (0,0) point (offset).
*/
void paste_into(gamemap& map, const gamemap::location& loc) const;
void center();
/**
* Shift all tiles in the map fragment by the specified offset.
*/
void shift(const gamemap::location& offset);
/**
* Get the center of the map fragment, bounds-wise.
*/
gamemap::location center_of_bounds() const;
/**
* Get the center of the map fragment, mass-wise.
*/
gamemap::location center_of_mass() const;
/**
* Shift the map fragment so it is roughly centered around the (0,0) point, bounds-wise.
*/
void center_by_bounds();
/**
* Shift the map fragment so it is roughly centered around the (0,0) point, mass-wise.
*/
void center_by_mass();
/**
* @return true if the map_fragment is empty
*/
bool empty() const;
/**
* Rotate the map fragment 60 degrees clockwise around (0,0)
*/
void rotate_60_cw();
/**
* Rotate the map fragment 60 degrees counter-clockwise around (0,0)
*/
void rotate_60_ccw();
protected:
std::vector<tile_info> items_;
};

View file

@ -28,11 +28,16 @@ namespace editor2 {
void mouse_action::move(editor_display& disp, const gamemap::location& hex)
{
if (hex != previous_move_hex_) {
disp.set_brush_locs(affected_hexes(disp, hex));
update_brush_highlights(disp, hex);
previous_move_hex_ = hex;
}
}
void mouse_action::update_brush_highlights(editor_display& disp, const gamemap::location& hex)
{
disp.set_brush_locs(affected_hexes(disp, hex));
}
std::set<gamemap::location> mouse_action::affected_hexes(
editor_display& /*disp*/, const gamemap::location& hex)
{
@ -188,11 +193,9 @@ std::set<gamemap::location> mouse_action_select::affected_hexes(
editor_action* mouse_action_select::key_event(
editor_display& disp, const SDL_Event& event)
{
// Force an actual move event to update the brush
gamemap::location tmp = previous_move_hex_;
previous_move_hex_ = gamemap::location();
move(disp, tmp);
return mouse_action::key_event(disp, event);
editor_action* ret = mouse_action::key_event(disp, event);
update_brush_highlights(disp, previous_move_hex_);
return ret;
}
editor_action* mouse_action_select::click_perform_left(

View file

@ -45,6 +45,11 @@ public:
* Mouse move (not a drag). Never changes anything (other than temporary highlihts and similar)
*/
void move(editor_display& disp, const gamemap::location& hex);
/**
* Unconditionally update the brush highlights for the current tool when hex is the center location
*/
void update_brush_highlights(editor_display& disp, const gamemap::location& hex);
/**
* Locations that would be affected by a click, used by move to update highlights. Defauts to higlight the mouseover hex.

View file

@ -157,6 +157,10 @@ const struct {
N_("Select Inverse"), false, hotkey::SCOPE_EDITOR },
{ hotkey::HOTKEY_EDITOR_SELECT_NONE, "editor-select-none",
N_("Select None"), false, hotkey::SCOPE_EDITOR },
{ hotkey::HOTKEY_EDITOR_CLIPBOARD_ROTATE_CW, "editor-clipboard-rotate-cw",
N_("Rotate Clipboard Clockwise"), false, hotkey::SCOPE_EDITOR },
{ hotkey::HOTKEY_EDITOR_CLIPBOARD_ROTATE_CCW, "editor-clipboard-rotate-ccw",
N_("Rotate Clipboard Counter-Clockwise"), false, hotkey::SCOPE_EDITOR },
{ hotkey::HOTKEY_EDITOR_SELECTION_ROTATE, "editor-selection-rotate",
N_("Rotate Selection"), false, hotkey::SCOPE_EDITOR },
{ hotkey::HOTKEY_EDITOR_SELECTION_FLIP, "editor-selection-flip",

View file

@ -81,6 +81,7 @@ enum HOTKEY_COMMAND {
HOTKEY_EDITOR_CUT, HOTKEY_EDITOR_COPY, HOTKEY_EDITOR_PASTE,
HOTKEY_EDITOR_SELECT_ALL, HOTKEY_EDITOR_SELECT_INVERSE,
HOTKEY_EDITOR_SELECT_NONE,
HOTKEY_EDITOR_CLIPBOARD_ROTATE_CW, HOTKEY_EDITOR_CLIPBOARD_ROTATE_CCW,
HOTKEY_EDITOR_SELECTION_ROTATE, HOTKEY_EDITOR_SELECTION_FLIP,
HOTKEY_EDITOR_SELECTION_FILL,
HOTKEY_EDITOR_SELECTION_GENERATE, HOTKEY_EDITOR_SELECTION_RANDOMIZE,