From b18dea0f696779f16a59c57139bf74267905dc8a Mon Sep 17 00:00:00 2001 From: twanvl Date: Sun, 8 Jul 2007 13:48:53 +0000 Subject: [PATCH] Movement of objects with the arrow keys in symbol editor git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@527 0fc631ac-6414-0410-93d0-97cfa31319b6 --- src/data/action/symbol.cpp | 57 +++++++++++++++++++++- src/data/action/symbol.hpp | 35 ++++++++++++- src/data/symbol.cpp | 22 +++++++++ src/data/symbol.hpp | 29 +++++++++-- src/gui/symbol/point_editor.cpp | 28 ++++++++++- src/gui/symbol/select_editor.cpp | 13 ++++- src/render/symbol/viewer.cpp | 84 +++++++++++++++++++------------- src/render/symbol/viewer.hpp | 8 ++- src/util/window_id.hpp | 2 + 9 files changed, 232 insertions(+), 46 deletions(-) diff --git a/src/data/action/symbol.cpp b/src/data/action/symbol.cpp index c12b37f6..ca5b4ab1 100644 --- a/src/data/action/symbol.cpp +++ b/src/data/action/symbol.cpp @@ -23,8 +23,9 @@ String action_name_for(const set& parts, const String& action) { // ----------------------------------------------------------------------------- : Moving symbol parts -SymbolPartMoveAction::SymbolPartMoveAction(const set& parts) +SymbolPartMoveAction::SymbolPartMoveAction(const set& parts, const Vector2D& delta) : parts(parts) + , delta(delta), moved(-delta) , min_pos(Vector2D::infinity()), max_pos(-Vector2D::infinity()) , constrain(false) , snap(0) @@ -419,3 +420,57 @@ void ReorderSymbolPartsAction::perform(bool to_undo) { assert(part_id2 < symbol.parts.size()); swap(symbol.parts[part_id1], symbol.parts[part_id2]); } + +// ----------------------------------------------------------------------------- : Group symbol parts + +GroupSymbolPartsActionBase::GroupSymbolPartsActionBase(Symbol& symbol) + : symbol(symbol) +{} +void GroupSymbolPartsActionBase::perform(bool to_undo) { + swap(symbol.parts, old_part_list); +} + +GroupSymbolPartsAction::GroupSymbolPartsAction(Symbol& symbol, const set& parts) + : GroupSymbolPartsActionBase(symbol) +{ + // group parts in the old parts list + bool done = false; + SymbolGroupP group(new SymbolGroup); + group->name = _("Group"); + FOR_EACH(p, symbol.parts) { + if (parts.find(p) != parts.end()) { + group->parts.push_back(p); + if (!done) { + done = true; + old_part_list.push_back(group); + } + } else { + // not affected + old_part_list.push_back(p); + } + } +} +String GroupSymbolPartsAction::getName(bool to_undo) const { + return _ACTION_("group parts"); +} + +UngroupSymbolPartsAction::UngroupSymbolPartsAction(Symbol& symbol, const set& parts) + : GroupSymbolPartsActionBase(symbol) +{ + // break up the parts in the old parts list + FOR_EACH(p, symbol.parts) { + if (parts.find(p) != parts.end() && p->isSymbolGroup()) { + // break up the group + SymbolGroup* g = p->isSymbolGroup(); + FOR_EACH(p, g->parts) { + old_part_list.push_back(p); + } + } else { + // not affected + old_part_list.push_back(p); + } + } +} +String UngroupSymbolPartsAction::getName(bool to_undo) const { + return _ACTION_("ungroup parts"); +} diff --git a/src/data/action/symbol.hpp b/src/data/action/symbol.hpp index e7b0a102..89a21df8 100644 --- a/src/data/action/symbol.hpp +++ b/src/data/action/symbol.hpp @@ -31,7 +31,7 @@ class SymbolPartListAction : public SymbolPartAction {}; /// Move some symbol parts class SymbolPartMoveAction : public SymbolPartAction { public: - SymbolPartMoveAction(const set& parts); + SymbolPartMoveAction(const set& parts, const Vector2D& delta = Vector2D()); virtual String getName(bool to_undo) const; virtual void perform(bool to_undo); @@ -235,7 +235,38 @@ class ReorderSymbolPartsAction : public SymbolPartListAction { private: Symbol& symbol; ///< Symbol to swap the parts in public: - size_t part_id1, part_id2; ///< Indeces of parts to swap + size_t part_id1, part_id2; ///< Indices of parts to swap +}; + + +// ----------------------------------------------------------------------------- : Group symbol parts + +/// Group multiple symbol parts together +class GroupSymbolPartsActionBase : public SymbolPartListAction { + public: + GroupSymbolPartsActionBase(Symbol& symbol); + + virtual void perform(bool to_undo); + + protected: + Symbol& symbol; ///< Symbol to group stuff in + vector old_part_list; ///< Old part list of the symbol +}; + +/// Group multiple symbol parts together +class GroupSymbolPartsAction : public GroupSymbolPartsActionBase { + public: + GroupSymbolPartsAction(Symbol& symbol, const set& parts); + + virtual String getName(bool to_undo) const; +}; + +/// Break up one or more SymbolGroups +class UngroupSymbolPartsAction : public GroupSymbolPartsActionBase { + public: + UngroupSymbolPartsAction(Symbol& symbol, const set& groups); + + virtual String getName(bool to_undo) const; }; diff --git a/src/data/symbol.cpp b/src/data/symbol.cpp index 49f99fca..bea73f6e 100644 --- a/src/data/symbol.cpp +++ b/src/data/symbol.cpp @@ -11,6 +11,7 @@ #include DECLARE_TYPEOF_COLLECTION(ControlPointP); +DECLARE_TYPEOF_COLLECTION(SymbolPartP); // ----------------------------------------------------------------------------- : ControlPoint @@ -108,6 +109,7 @@ SymbolPartP read_new(Reader& reader) { reader.handle(_("type"), type); if (type == _("shape") || type.empty()) return new_intrusive(); else if (type == _("symmetry")) return new_intrusive(); + else if (type == _("group")) return new_intrusive(); else { throw ParseError(_("Unsupported symbol part type: '") + type + _("'")); } @@ -218,6 +220,26 @@ IMPLEMENT_REFLECTION(SymbolSymmetry) { } } +// ----------------------------------------------------------------------------- : SymbolGroup + +String SymbolGroup::typeName() const { + return _("group"); +} + +SymbolPartP SymbolGroup::clone() const { + SymbolGroupP part(new SymbolGroup(*this)); + // also clone the parts inside + FOR_EACH(p, part->parts) { + p = p->clone(); + } + return part; +} + +IMPLEMENT_REFLECTION(SymbolGroup) { + REFLECT_BASE(SymbolPart); + REFLECT(parts); +} + // ----------------------------------------------------------------------------- : Symbol IMPLEMENT_REFLECTION(Symbol) { diff --git a/src/data/symbol.hpp b/src/data/symbol.hpp index 6bb504f6..3ccde3d1 100644 --- a/src/data/symbol.hpp +++ b/src/data/symbol.hpp @@ -18,6 +18,7 @@ DECLARE_POINTER_TYPE(ControlPoint); DECLARE_POINTER_TYPE(SymbolPart); DECLARE_POINTER_TYPE(SymbolShape); DECLARE_POINTER_TYPE(SymbolSymmetry); +DECLARE_POINTER_TYPE(SymbolGroup); DECLARE_POINTER_TYPE(Symbol); // ----------------------------------------------------------------------------- : ControlPoint @@ -119,13 +120,16 @@ class SymbolPart : public IntrusivePtrVirtualBase { /// Icon for this part virtual int icon() const = 0; - /// Convert tot SymbolShape? + /// Convert to SymbolShape? virtual SymbolShape* isSymbolShape() { return nullptr; } virtual const SymbolShape* isSymbolShape() const { return nullptr; } - /// Convert tot SymbolSymmetry? + /// Convert to SymbolSymmetry? virtual SymbolSymmetry* isSymbolSymmetry() { return nullptr; } virtual const SymbolSymmetry* isSymbolSymmetry() const { return nullptr; } - + /// Convert to SymbolGroup? + virtual SymbolGroup* isSymbolGroup() { return nullptr; } + virtual const SymbolGroup* isSymbolGroup() const { return nullptr; } + DECLARE_REFLECTION_VIRTUAL(); }; @@ -184,7 +188,6 @@ class SymbolShape : public SymbolPart { DECLARE_REFLECTION(); }; - // ----------------------------------------------------------------------------- : SymbolSymmetry enum SymbolSymmetryType @@ -213,12 +216,28 @@ class SymbolSymmetry : public SymbolPart { DECLARE_REFLECTION(); }; +// ----------------------------------------------------------------------------- : SymbolGroup + +/// A group of symbol parts +class SymbolGroup : public SymbolPart { + public: + vector parts; ///< The parts in this group + + virtual String typeName() const; + virtual SymbolPartP clone() const; + virtual int icon() const { return SYMMETRY_REFLECTION + 1; } + virtual SymbolGroup* isSymbolGroup() { return this; } + virtual const SymbolGroup* isSymbolGroup() const { return this; } + + DECLARE_REFLECTION(); +}; + // ----------------------------------------------------------------------------- : Symbol /// An editable symbol, consists of any number of SymbolParts class Symbol : public IntrusivePtrBase { public: - /// The parts of this symbol + /// The parts of this symbol, first item is on top vector parts; /// Actions performed on this symbol and the parts in it ActionStack actions; diff --git a/src/gui/symbol/point_editor.cpp b/src/gui/symbol/point_editor.cpp index b0d8737b..9c5012db 100644 --- a/src/gui/symbol/point_editor.cpp +++ b/src/gui/symbol/point_editor.cpp @@ -352,7 +352,33 @@ void SymbolPointEditor::onChar(wxKeyEvent& ev) { if (ev.GetKeyCode() == WXK_DELETE) { deleteSelection(); } else { - ev.Skip(); + // move selection using arrow keys + double step = 1.0 / settings.symbol_grid_size; + Vector2D delta; + if (ev.GetKeyCode() == WXK_LEFT) delta = Vector2D(-step, 0); + else if (ev.GetKeyCode() == WXK_RIGHT) delta = Vector2D( step, 0); + else if (ev.GetKeyCode() == WXK_UP) delta = Vector2D(0, -step); + else if (ev.GetKeyCode() == WXK_DOWN) delta = Vector2D(0, step); + else { + ev.Skip(); + return; + } + // what to move + if (selection == SELECTED_POINTS || selection == SELECTED_LINE) { + // Move all selected points + controlPointMoveAction = new ControlPointMoveAction(selected_points); + getSymbol()->actions.add(controlPointMoveAction); + controlPointMoveAction->move(delta); + new_point += delta; + control.Refresh(false); + } else if (selection == SELECTED_HANDLE) { + // Move the selected handle + handleMoveAction = new HandleMoveAction(selected_handle); + getSymbol()->actions.add(handleMoveAction); + handleMoveAction->move(delta); + control.Refresh(false); + } + resetActions(); } } diff --git a/src/gui/symbol/select_editor.cpp b/src/gui/symbol/select_editor.cpp index 1aeaffec..fff39aea 100644 --- a/src/gui/symbol/select_editor.cpp +++ b/src/gui/symbol/select_editor.cpp @@ -387,7 +387,18 @@ void SymbolSelectEditor::onChar(wxKeyEvent& ev) { resetActions(); control.Refresh(false); } else { - ev.Skip(); + // move selection using arrow keys + double step = 1.0 / settings.symbol_grid_size; + Vector2D delta; + if (ev.GetKeyCode() == WXK_LEFT) delta = Vector2D(-step, 0); + else if (ev.GetKeyCode() == WXK_RIGHT) delta = Vector2D( step, 0); + else if (ev.GetKeyCode() == WXK_UP) delta = Vector2D(0, -step); + else if (ev.GetKeyCode() == WXK_DOWN) delta = Vector2D(0, step); + else { + ev.Skip(); + return; + } + getSymbol()->actions.add(new SymbolPartMoveAction(control.selected_parts, delta)); } } diff --git a/src/render/symbol/viewer.cpp b/src/render/symbol/viewer.cpp index 4b5e2961..56fa4877 100644 --- a/src/render/symbol/viewer.cpp +++ b/src/render/symbol/viewer.cpp @@ -74,41 +74,7 @@ void SymbolViewer::draw(DC& dc) { } // Draw all parts, in reverse order (bottom to top) FOR_EACH_REVERSE(p, symbol->parts) { - if (SymbolShape* s = p->isSymbolShape()) { - if (s->combine == SYMBOL_COMBINE_OVERLAP && buffersFilled) { - // We will be overlapping some previous parts, write them to the screen - combineBuffers(dc, borderDC.get(), interiorDC.get()); - // Clear the buffers - buffersFilled = false; - paintedSomething = true; - wxSize s = dc.GetSize(); - if (borderDC) { - borderDC->SetBrush(*wxBLACK_BRUSH); - borderDC->SetPen( *wxTRANSPARENT_PEN); - borderDC->DrawRectangle(0, 0, s.GetWidth(), s.GetHeight()); - } - interiorDC->SetBrush(*wxBLACK_BRUSH); - interiorDC->DrawRectangle(0, 0, s.GetWidth(), s.GetHeight()); - } - - // Paint the part itself - if (!paintedSomething) { - // No need to buffer - if (!interiorDC) interiorDC = getTempDC(dc); - combineSymbolShape(*s, dc, *interiorDC, true, false); - buffersFilled = true; - } else { - if (!borderDC) borderDC = getTempDC(dc); - if (!interiorDC) interiorDC = getTempDC(dc); - // Draw this shape to the buffer - combineSymbolShape(*s, *borderDC, *interiorDC, false, false); - buffersFilled = true; - } - // Paint symmetric versions of this part - // TODO - } else { - // symmetry, already handled above - } + combineSymbolPart(dc, *p, paintedSomething, buffersFilled, borderDC, interiorDC); } // Output the final parts from the buffer @@ -116,12 +82,55 @@ void SymbolViewer::draw(DC& dc) { combineBuffers(dc, borderDC.get(), interiorDC.get()); } } +void SymbolViewer::combineSymbolPart(DC& dc, const SymbolPart& part, bool& paintedSomething, bool& buffersFilled, MemoryDCP& borderDC, MemoryDCP& interiorDC) { + if (const SymbolShape* s = part.isSymbolShape()) { + if (s->combine == SYMBOL_COMBINE_OVERLAP && buffersFilled) { + // We will be overlapping some previous parts, write them to the screen + combineBuffers(dc, borderDC.get(), interiorDC.get()); + // Clear the buffers + buffersFilled = false; + paintedSomething = true; + wxSize s = dc.GetSize(); + if (borderDC) { + borderDC->SetBrush(*wxBLACK_BRUSH); + borderDC->SetPen( *wxTRANSPARENT_PEN); + borderDC->DrawRectangle(0, 0, s.GetWidth(), s.GetHeight()); + } + interiorDC->SetBrush(*wxBLACK_BRUSH); + interiorDC->DrawRectangle(0, 0, s.GetWidth(), s.GetHeight()); + } + + // Paint the part itself + if (!paintedSomething) { + // No need to buffer + if (!interiorDC) interiorDC = getTempDC(dc); + combineSymbolShape(*s, dc, *interiorDC, true, false); + buffersFilled = true; + } else { + if (!borderDC) borderDC = getTempDC(dc); + if (!interiorDC) interiorDC = getTempDC(dc); + // Draw this shape to the buffer + combineSymbolShape(*s, *borderDC, *interiorDC, false, false); + buffersFilled = true; + } + // Paint symmetric versions of this part + // TODO + } else if (const SymbolSymmetry* s = part.isSymbolSymmetry()) { + // symmetry, already handled above + } else if (const SymbolGroup* g = part.isSymbolGroup()) { + FOR_EACH_CONST(p, g->parts) { + combineSymbolPart(dc, *p, paintedSomething, buffersFilled, borderDC, interiorDC); + } + } +} void SymbolViewer::highlightPart(DC& dc, const SymbolPart& part, HighlightStyle style) { if (const SymbolShape* s = part.isSymbolShape()) { highlightPart(dc, *s, style); } else if (const SymbolSymmetry* s = part.isSymbolSymmetry()) { highlightPart(dc, *s); + } else if (const SymbolGroup* g = part.isSymbolGroup()) { + highlightPart(dc, *g, style); } else { throw InternalError(_("Invalid symbol part type")); } @@ -154,6 +163,11 @@ void SymbolViewer::highlightPart(DC& dc, const SymbolShape& shape, HighlightStyl void SymbolViewer::highlightPart(DC& dc, const SymbolSymmetry& sym) { // TODO } +void SymbolViewer::highlightPart(DC& dc, const SymbolGroup& group, HighlightStyle style) { + FOR_EACH_CONST(part, group.parts) { + highlightPart(dc, *part, style); + } +} void SymbolViewer::combineSymbolShape(const SymbolShape& shape, DC& border, DC& interior, bool directB, bool directI) { diff --git a/src/render/symbol/viewer.hpp b/src/render/symbol/viewer.hpp index dee1ac12..68a82e25 100644 --- a/src/render/symbol/viewer.hpp +++ b/src/render/symbol/viewer.hpp @@ -45,12 +45,18 @@ class SymbolViewer : public SymbolView { void draw(DC& dc); void highlightPart(DC& dc, const SymbolPart& part, HighlightStyle style); - void highlightPart(DC& dc, const SymbolShape& shap, HighlightStyle style); + void highlightPart(DC& dc, const SymbolShape& shape, HighlightStyle style); void highlightPart(DC& dc, const SymbolSymmetry& sym); + void highlightPart(DC& dc, const SymbolGroup& group, HighlightStyle style); void onAction(const Action&, bool) {} private: + typedef shared_ptr MemoryDCP; + + /// Combine a symbol part with the dc + void SymbolViewer::combineSymbolPart(DC& dc, const SymbolPart& part, bool& paintedSomething, bool& buffersFilled, MemoryDCP& borderDC, MemoryDCP& interiorDC); + /// Combines a symbol part with what is currently drawn, the border and interior are drawn separatly /** directB/directI are true if the border/interior is the screen dc, false if it * is a temporary 1 bit one diff --git a/src/util/window_id.hpp b/src/util/window_id.hpp index 0bb0cbda..f243f8d8 100644 --- a/src/util/window_id.hpp +++ b/src/util/window_id.hpp @@ -126,6 +126,8 @@ enum ChildMenuID { , ID_SYMBOL_COMBINE_BORDER = ID_SYMBOL_COMBINE + 5 //SYMBOL_COMBINE_BORDER , ID_SYMBOL_COMBINE_MAX , ID_EDIT_DUPLICATE // duplicating symbol parts +, ID_EDIT_GROUP +, ID_EDIT_UNGROUP , ID_VIEW_GRID , ID_VIEW_GRID_SNAP