mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
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
This commit is contained in:
@@ -23,8 +23,9 @@ String action_name_for(const set<SymbolPartP>& parts, const String& action) {
|
||||
|
||||
// ----------------------------------------------------------------------------- : Moving symbol parts
|
||||
|
||||
SymbolPartMoveAction::SymbolPartMoveAction(const set<SymbolPartP>& parts)
|
||||
SymbolPartMoveAction::SymbolPartMoveAction(const set<SymbolPartP>& 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<SymbolPartP>& 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<SymbolPartP>& 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");
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ class SymbolPartListAction : public SymbolPartAction {};
|
||||
/// Move some symbol parts
|
||||
class SymbolPartMoveAction : public SymbolPartAction {
|
||||
public:
|
||||
SymbolPartMoveAction(const set<SymbolPartP>& parts);
|
||||
SymbolPartMoveAction(const set<SymbolPartP>& 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<SymbolPartP> old_part_list; ///< Old part list of the symbol
|
||||
};
|
||||
|
||||
/// Group multiple symbol parts together
|
||||
class GroupSymbolPartsAction : public GroupSymbolPartsActionBase {
|
||||
public:
|
||||
GroupSymbolPartsAction(Symbol& symbol, const set<SymbolPartP>& parts);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
};
|
||||
|
||||
/// Break up one or more SymbolGroups
|
||||
class UngroupSymbolPartsAction : public GroupSymbolPartsActionBase {
|
||||
public:
|
||||
UngroupSymbolPartsAction(Symbol& symbol, const set<SymbolPartP>& groups);
|
||||
|
||||
virtual String getName(bool to_undo) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <gfx/bezier.hpp>
|
||||
|
||||
DECLARE_TYPEOF_COLLECTION(ControlPointP);
|
||||
DECLARE_TYPEOF_COLLECTION(SymbolPartP);
|
||||
|
||||
// ----------------------------------------------------------------------------- : ControlPoint
|
||||
|
||||
@@ -108,6 +109,7 @@ SymbolPartP read_new<SymbolPart>(Reader& reader) {
|
||||
reader.handle(_("type"), type);
|
||||
if (type == _("shape") || type.empty()) return new_intrusive<SymbolShape>();
|
||||
else if (type == _("symmetry")) return new_intrusive<SymbolSymmetry>();
|
||||
else if (type == _("group")) return new_intrusive<SymbolGroup>();
|
||||
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) {
|
||||
|
||||
+24
-5
@@ -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<SymbolPartP> 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<Symbol> {
|
||||
public:
|
||||
/// The parts of this symbol
|
||||
/// The parts of this symbol, first item is on top
|
||||
vector<SymbolPartP> parts;
|
||||
/// Actions performed on this symbol and the parts in it
|
||||
ActionStack actions;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<wxMemoryDC> 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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user