editor2: rotate clipboard 60 degrees cw/ccw feature, map_fragment doc comments
This commit is contained in:
parent
88cb10df99
commit
ebc01fba94
12 changed files with 226 additions and 28 deletions
|
@ -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:
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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_;
|
||||
};
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Add table
Reference in a new issue