Commit 67c0e51f authored by twanvl's avatar twanvl

Symbol editor now has constraints on selection, but part list allows selection inside groups.

Added logical 'xor' operator for scripting.
parent b4d89e6a
...@@ -105,6 +105,7 @@ void SymbolPartMatrixAction::transform(SymbolPart& part, const Matrix2D& m) { ...@@ -105,6 +105,7 @@ void SymbolPartMatrixAction::transform(SymbolPart& part, const Matrix2D& m) {
// bounds change after transforming // bounds change after transforming
s->calculateBounds(); s->calculateBounds();
} else if (SymbolSymmetry* s = part.isSymbolSymmetry()) { } else if (SymbolSymmetry* s = part.isSymbolSymmetry()) {
s->center = (s->center - center) * m + center;
s->handle = s->handle * m; s->handle = s->handle * m;
} else if (SymbolGroup* g = part.isSymbolGroup()) { } else if (SymbolGroup* g = part.isSymbolGroup()) {
FOR_EACH(p, g->parts) { FOR_EACH(p, g->parts) {
...@@ -280,7 +281,8 @@ void SymbolPartScaleAction::transformPart(SymbolPart& part) { ...@@ -280,7 +281,8 @@ void SymbolPartScaleAction::transformPart(SymbolPart& part) {
pnt->delta_after = pnt->delta_after .mul(scale); pnt->delta_after = pnt->delta_after .mul(scale);
} }
} else if (SymbolSymmetry* s = part.isSymbolSymmetry()) { } else if (SymbolSymmetry* s = part.isSymbolSymmetry()) {
throw "TODO"; transform(s->center);
s->handle.mul(new_size.div(old_size));
} else if (SymbolGroup* g = part.isSymbolGroup()) { } else if (SymbolGroup* g = part.isSymbolGroup()) {
FOR_EACH(p, g->parts) { FOR_EACH(p, g->parts) {
transformPart(*p); transformPart(*p);
...@@ -450,8 +452,9 @@ void DuplicateSymbolPartsAction::getParts(set<SymbolPartP>& parts) { ...@@ -450,8 +452,9 @@ void DuplicateSymbolPartsAction::getParts(set<SymbolPartP>& parts) {
// ----------------------------------------------------------------------------- : Reorder symbol parts // ----------------------------------------------------------------------------- : Reorder symbol parts
ReorderSymbolPartsAction::ReorderSymbolPartsAction(Symbol& symbol, size_t old_position, size_t new_position) ReorderSymbolPartsAction::ReorderSymbolPartsAction(SymbolGroup& old_parent, size_t old_position, SymbolGroup& new_parent, size_t new_position)
: symbol(symbol), old_position(old_position), new_position(new_position) : old_parent(&old_parent), new_parent(&new_parent)
, old_position(old_position), new_position(new_position)
{} {}
String ReorderSymbolPartsAction::getName(bool to_undo) const { String ReorderSymbolPartsAction::getName(bool to_undo) const {
...@@ -459,31 +462,58 @@ String ReorderSymbolPartsAction::getName(bool to_undo) const { ...@@ -459,31 +462,58 @@ String ReorderSymbolPartsAction::getName(bool to_undo) const {
} }
void ReorderSymbolPartsAction::perform(bool to_undo) { void ReorderSymbolPartsAction::perform(bool to_undo) {
assert(old_position < symbol.parts.size()); // remove from old
assert(new_position < symbol.parts.size()); assert(old_position < old_parent->parts.size());
SymbolPartP part = symbol.parts.at(old_position); SymbolPartP part = old_parent->parts.at(old_position);
symbol.parts.erase( symbol.parts.begin() + old_position); old_parent->parts.erase( old_parent->parts.begin() + old_position);
symbol.parts.insert(symbol.parts.begin() + new_position, part); // add to new
assert(new_position <= new_parent->parts.size());
new_parent->parts.insert(new_parent->parts.begin() + new_position, part);
// next time the other way around
swap(old_parent, new_parent);
swap(old_position, new_position); swap(old_position, new_position);
} }
UngroupReorderSymbolPartsAction::UngroupReorderSymbolPartsAction(SymbolGroup& group_parent, size_t group_pos, SymbolGroup& target_parent, size_t target_pos)
: group_parent(group_parent), group_pos(group_pos)
, target_parent(target_parent), target_pos(target_pos)
{
group = dynamic_pointer_cast<SymbolGroup>(group_parent.parts.at(group_pos));
assert(group);
}
String UngroupReorderSymbolPartsAction::getName(bool to_undo) const {
return _ACTION_("reorder parts");
}
void UngroupReorderSymbolPartsAction::perform(bool to_undo) {
if (!to_undo) {
group_parent.parts.erase(group_parent.parts.begin() + group_pos);
target_parent.parts.insert(target_parent.parts.begin() + target_pos, group->parts.begin(), group->parts.end());
} else {
target_parent.parts.erase(target_parent.parts.begin() + target_pos, target_parent.parts.begin() + target_pos + group->parts.size());
group_parent.parts.insert(group_parent.parts.begin() + group_pos, group);
}
}
// ----------------------------------------------------------------------------- : Group symbol parts // ----------------------------------------------------------------------------- : Group symbol parts
GroupSymbolPartsActionBase::GroupSymbolPartsActionBase(Symbol& symbol) GroupSymbolPartsActionBase::GroupSymbolPartsActionBase(SymbolGroup& root)
: symbol(symbol) : root(root)
{} {}
void GroupSymbolPartsActionBase::perform(bool to_undo) { void GroupSymbolPartsActionBase::perform(bool to_undo) {
swap(symbol.parts, old_part_list); swap(root.parts, old_part_list);
} }
GroupSymbolPartsAction::GroupSymbolPartsAction(Symbol& symbol, const set<SymbolPartP>& parts) GroupSymbolPartsAction::GroupSymbolPartsAction(SymbolGroup& root, const set<SymbolPartP>& parts, const SymbolGroupP& group)
: GroupSymbolPartsActionBase(symbol) : GroupSymbolPartsActionBase(root)
{ {
// group parts in the old parts list // group parts in the old parts list
bool done = false; bool done = false;
SymbolGroupP group(new SymbolGroup); FOR_EACH(p, root.parts) {
group->name = _("Group"); assert(p != group);
FOR_EACH(p, symbol.parts) {
if (parts.find(p) != parts.end()) { if (parts.find(p) != parts.end()) {
// add to group instead // add to group instead
group->parts.push_back(p); group->parts.push_back(p);
...@@ -502,11 +532,11 @@ String GroupSymbolPartsAction::getName(bool to_undo) const { ...@@ -502,11 +532,11 @@ String GroupSymbolPartsAction::getName(bool to_undo) const {
return _ACTION_("group parts"); return _ACTION_("group parts");
} }
UngroupSymbolPartsAction::UngroupSymbolPartsAction(Symbol& symbol, const set<SymbolPartP>& parts) UngroupSymbolPartsAction::UngroupSymbolPartsAction(SymbolGroup& root, const set<SymbolPartP>& parts)
: GroupSymbolPartsActionBase(symbol) : GroupSymbolPartsActionBase(root)
{ {
// break up the parts in the old parts list // break up the parts in the old parts list
FOR_EACH(p, symbol.parts) { FOR_EACH(p, root.parts) {
if (parts.find(p) != parts.end() && p->isSymbolGroup()) { if (parts.find(p) != parts.end() && p->isSymbolGroup()) {
// break up the group // break up the group
SymbolGroup* g = p->isSymbolGroup(); SymbolGroup* g = p->isSymbolGroup();
......
...@@ -240,36 +240,52 @@ class DuplicateSymbolPartsAction : public SymbolPartListAction { ...@@ -240,36 +240,52 @@ class DuplicateSymbolPartsAction : public SymbolPartListAction {
/// Change the position of a part in a symbol, by moving a part. /// Change the position of a part in a symbol, by moving a part.
class ReorderSymbolPartsAction : public SymbolPartListAction { class ReorderSymbolPartsAction : public SymbolPartListAction {
public: public:
ReorderSymbolPartsAction(Symbol& symbol, size_t old_position, size_t new_position); ReorderSymbolPartsAction(SymbolGroup& old_parent, size_t old_position, SymbolGroup& new_parent, size_t new_position);
virtual String getName(bool to_undo) const; virtual String getName(bool to_undo) const;
virtual void perform(bool to_undo); virtual void perform(bool to_undo);
private: private:
Symbol& symbol; ///< Symbol to swap the parts in SymbolGroup* old_parent, *new_parent;///< Parents to move from and to
public: public:
size_t old_position, new_position; ///< Positions to move from and to size_t old_position, new_position; ///< Positions to move from and to
}; };
/// Break up a single group, and put its contents at a specific position
class UngroupReorderSymbolPartsAction : public SymbolPartListAction {
public:
/// Remove all the given groups
UngroupReorderSymbolPartsAction(SymbolGroup& group_parent, size_t group_pos, SymbolGroup& target_parent, size_t target_pos);
virtual String getName(bool to_undo) const;
virtual void perform(bool to_undo);
private:
SymbolGroup& group_parent;
size_t group_pos;
SymbolGroupP group; ///< Group to destroy
SymbolGroup& target_parent;
size_t target_pos;
};
// ----------------------------------------------------------------------------- : Group symbol parts // ----------------------------------------------------------------------------- : Group symbol parts
/// Group multiple symbol parts together /// Group multiple symbol parts together
class GroupSymbolPartsActionBase : public SymbolPartListAction { class GroupSymbolPartsActionBase : public SymbolPartListAction {
public: public:
GroupSymbolPartsActionBase(Symbol& symbol); GroupSymbolPartsActionBase(SymbolGroup& root);
virtual void perform(bool to_undo); virtual void perform(bool to_undo);
protected: protected:
Symbol& symbol; ///< Symbol to group stuff in SymbolGroup& root; ///< Symbol or group to group stuff in
vector<SymbolPartP> old_part_list; ///< Old part list of the symbol vector<SymbolPartP> old_part_list; ///< Old part list of the symbol
}; };
/// Group multiple symbol parts together /// Group multiple symbol parts together
class GroupSymbolPartsAction : public GroupSymbolPartsActionBase { class GroupSymbolPartsAction : public GroupSymbolPartsActionBase {
public: public:
GroupSymbolPartsAction(Symbol& symbol, const set<SymbolPartP>& parts); GroupSymbolPartsAction(SymbolGroup& root, const set<SymbolPartP>& parts, const SymbolGroupP& group);
virtual String getName(bool to_undo) const; virtual String getName(bool to_undo) const;
}; };
...@@ -277,11 +293,11 @@ class GroupSymbolPartsAction : public GroupSymbolPartsActionBase { ...@@ -277,11 +293,11 @@ class GroupSymbolPartsAction : public GroupSymbolPartsActionBase {
/// Break up one or more SymbolGroups /// Break up one or more SymbolGroups
class UngroupSymbolPartsAction : public GroupSymbolPartsActionBase { class UngroupSymbolPartsAction : public GroupSymbolPartsActionBase {
public: public:
UngroupSymbolPartsAction(Symbol& symbol, const set<SymbolPartP>& groups); /// Remove all the given groups
UngroupSymbolPartsAction(SymbolGroup& root, const set<SymbolPartP>& groups);
virtual String getName(bool to_undo) const; virtual String getName(bool to_undo) const;
}; };
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
#endif #endif
...@@ -204,7 +204,12 @@ String SymbolSymmetry::typeName() const { ...@@ -204,7 +204,12 @@ String SymbolSymmetry::typeName() const {
} }
SymbolPartP SymbolSymmetry::clone() const { SymbolPartP SymbolSymmetry::clone() const {
return new_intrusive1<SymbolSymmetry>(*this); SymbolSymmetryP part(new SymbolSymmetry(*this));
// also clone the parts inside
FOR_EACH(p, part->parts) {
p = p->clone();
}
return part;
} }
IMPLEMENT_REFLECTION(SymbolSymmetry) { IMPLEMENT_REFLECTION(SymbolSymmetry) {
...@@ -213,20 +218,16 @@ IMPLEMENT_REFLECTION(SymbolSymmetry) { ...@@ -213,20 +218,16 @@ IMPLEMENT_REFLECTION(SymbolSymmetry) {
REFLECT(copies); REFLECT(copies);
REFLECT(center); REFLECT(center);
REFLECT(handle); REFLECT(handle);
// Fixes after reading REFLECT(parts);
REFLECT_IF_READING { REFLECT_IF_READING calculateBoundsNonRec();
if (name.empty()) {
if (kind == SYMMETRY_REFLECTION) {
name = _("Mirror");
} else {
name = _("Symmetry");
}
}
}
} }
// ----------------------------------------------------------------------------- : SymbolGroup // ----------------------------------------------------------------------------- : SymbolGroup
SymbolGroup::SymbolGroup() {
name = capitalize(_TYPE_("group"));
}
String SymbolGroup::typeName() const { String SymbolGroup::typeName() const {
return _("group"); return _("group");
} }
...@@ -240,6 +241,14 @@ SymbolPartP SymbolGroup::clone() const { ...@@ -240,6 +241,14 @@ SymbolPartP SymbolGroup::clone() const {
return part; return part;
} }
bool SymbolGroup::isAncestor(const SymbolPart& that) const {
if (this == &that) return true;
FOR_EACH_CONST(p, parts) {
if (p->isAncestor(that)) return true;
}
return false;
}
void SymbolGroup::calculateBounds() { void SymbolGroup::calculateBounds() {
FOR_EACH(p, parts) p->calculateBounds(); FOR_EACH(p, parts) p->calculateBounds();
calculateBoundsNonRec(); calculateBoundsNonRec();
...@@ -256,12 +265,14 @@ void SymbolGroup::calculateBoundsNonRec() { ...@@ -256,12 +265,14 @@ void SymbolGroup::calculateBoundsNonRec() {
IMPLEMENT_REFLECTION(SymbolGroup) { IMPLEMENT_REFLECTION(SymbolGroup) {
REFLECT_BASE(SymbolPart); REFLECT_BASE(SymbolPart);
REFLECT(parts); REFLECT(parts);
REFLECT_IF_READING calculateBoundsNonRec();
} }
// ----------------------------------------------------------------------------- : Symbol // ----------------------------------------------------------------------------- : Symbol
IMPLEMENT_REFLECTION(Symbol) { IMPLEMENT_REFLECTION(Symbol) {
REFLECT(parts); REFLECT(parts);
REFLECT_IF_READING calculateBoundsNonRec();
} }
// ----------------------------------------------------------------------------- : Default symbol // ----------------------------------------------------------------------------- : Default symbol
......
...@@ -133,6 +133,10 @@ class SymbolPart : public IntrusivePtrVirtualBase { ...@@ -133,6 +133,10 @@ class SymbolPart : public IntrusivePtrVirtualBase {
virtual SymbolGroup* isSymbolGroup() { return nullptr; } virtual SymbolGroup* isSymbolGroup() { return nullptr; }
virtual const SymbolGroup* isSymbolGroup() const { return nullptr; } virtual const SymbolGroup* isSymbolGroup() const { return nullptr; }
/// Does this part contain another?
/** also true if this==that*/
virtual bool isAncestor(const SymbolPart& that) const { return this == &that; }
/// Calculate the position and size of the part (min_pos and max_pos) /// Calculate the position and size of the part (min_pos and max_pos)
virtual void calculateBounds(); virtual void calculateBounds();
...@@ -191,6 +195,30 @@ class SymbolShape : public SymbolPart { ...@@ -191,6 +195,30 @@ class SymbolShape : public SymbolPart {
DECLARE_REFLECTION(); DECLARE_REFLECTION();
}; };
// ----------------------------------------------------------------------------- : SymbolGroup
/// A group of symbol parts
class SymbolGroup : public SymbolPart {
public:
vector<SymbolPartP> parts; ///< The parts in this group, first item is on top
SymbolGroup();
virtual String typeName() const;
virtual SymbolPartP clone() const;
virtual int icon() const { return SYMBOL_COMBINE_BORDER + 3; }
virtual SymbolGroup* isSymbolGroup() { return this; }
virtual const SymbolGroup* isSymbolGroup() const { return this; }
virtual bool isAncestor(const SymbolPart& that) const;
virtual void calculateBounds();
/// re-calculate the bounds, but not of the contained parts
void calculateBoundsNonRec();
DECLARE_REFLECTION();
};
// ----------------------------------------------------------------------------- : SymbolSymmetry // ----------------------------------------------------------------------------- : SymbolSymmetry
enum SymbolSymmetryType enum SymbolSymmetryType
...@@ -198,9 +226,9 @@ enum SymbolSymmetryType ...@@ -198,9 +226,9 @@ enum SymbolSymmetryType
, SYMMETRY_REFLECTION , SYMMETRY_REFLECTION
}; };
/// A mirror, reflecting part of the symbol /// A mirror, reflecting the part of the symbol in the group
/** Can handle rotation symmetry with any number of reflections */ /** Can handle rotation symmetry with any number of reflections */
class SymbolSymmetry : public SymbolPart { class SymbolSymmetry : public SymbolGroup {
public: public:
SymbolSymmetryType kind; ///< What kind of symmetry SymbolSymmetryType kind; ///< What kind of symmetry
int copies; ///< How many times is the orignal reflected (including the original itself) int copies; ///< How many times is the orignal reflected (including the original itself)
...@@ -219,26 +247,6 @@ class SymbolSymmetry : public SymbolPart { ...@@ -219,26 +247,6 @@ class SymbolSymmetry : public SymbolPart {
DECLARE_REFLECTION(); DECLARE_REFLECTION();
}; };
// ----------------------------------------------------------------------------- : SymbolGroup
/// A group of symbol parts
class SymbolGroup : public SymbolPart {
public:
vector<SymbolPartP> parts; ///< The parts in this group, first item is on top
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; }
virtual void calculateBounds();
/// re-calculate the bounds, but not of the contained parts
void calculateBoundsNonRec();
DECLARE_REFLECTION();
};
// ----------------------------------------------------------------------------- : Symbol // ----------------------------------------------------------------------------- : Symbol
/// An editable symbol, consists of any number of SymbolParts /// An editable symbol, consists of any number of SymbolParts
......
...@@ -28,7 +28,7 @@ SymbolBasicShapeEditor::SymbolBasicShapeEditor(SymbolControl* control) ...@@ -28,7 +28,7 @@ SymbolBasicShapeEditor::SymbolBasicShapeEditor(SymbolControl* control)
void SymbolBasicShapeEditor::draw(DC& dc) { void SymbolBasicShapeEditor::draw(DC& dc) {
// highlight the part we are drawing // highlight the part we are drawing
if (drawing) { if (shape) {
control.highlightPart(dc, *shape, HIGHLIGHT_BORDER); control.highlightPart(dc, *shape, HIGHLIGHT_BORDER);
} }
} }
...@@ -64,6 +64,7 @@ void SymbolBasicShapeEditor::destroyUI(wxToolBar* tb, wxMenuBar* mb) { ...@@ -64,6 +64,7 @@ void SymbolBasicShapeEditor::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
delete sides; delete sides;
delete sidesL; delete sidesL;
#endif #endif
stopActions(); // set status text
} }
void SymbolBasicShapeEditor::onUpdateUI(wxUpdateUIEvent& ev) { void SymbolBasicShapeEditor::onUpdateUI(wxUpdateUIEvent& ev) {
...@@ -80,6 +81,7 @@ void SymbolBasicShapeEditor::onCommand(int id) { ...@@ -80,6 +81,7 @@ void SymbolBasicShapeEditor::onCommand(int id) {
if (id >= ID_SHAPE && id < ID_SHAPE_MAX) { if (id >= ID_SHAPE && id < ID_SHAPE_MAX) {
// change shape mode // change shape mode
mode = id; mode = id;
stopActions();
} }
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <gui/symbol/select_editor.hpp> #include <gui/symbol/select_editor.hpp>
#include <gui/symbol/point_editor.hpp> #include <gui/symbol/point_editor.hpp>
#include <gui/symbol/basic_shape_editor.hpp> #include <gui/symbol/basic_shape_editor.hpp>
#include <gui/symbol/symmetry_editor.hpp>
#include <gui/util.hpp> #include <gui/util.hpp>
#include <data/action/symbol.hpp> #include <data/action/symbol.hpp>
#include <data/settings.hpp> #include <data/settings.hpp>
...@@ -36,7 +37,7 @@ void SymbolControl::switchEditor(const SymbolEditorBaseP& e) { ...@@ -36,7 +37,7 @@ void SymbolControl::switchEditor(const SymbolEditorBaseP& e) {
} }
void SymbolControl::onChangeSymbol() { void SymbolControl::onChangeSymbol() {
selected_parts.clear(); selected_parts.setSymbol(symbol);
switchEditor(new_intrusive2<SymbolSelectEditor>(this, false)); switchEditor(new_intrusive2<SymbolSelectEditor>(this, false));
Refresh(false); Refresh(false);
} }
...@@ -51,7 +52,7 @@ void SymbolControl::onModeChange(wxCommandEvent& ev) { ...@@ -51,7 +52,7 @@ void SymbolControl::onModeChange(wxCommandEvent& ev) {
break; break;
case ID_MODE_POINTS: case ID_MODE_POINTS:
if (selected_parts.size() == 1) { if (selected_parts.size() == 1) {
selected_shape = dynamic_pointer_cast<SymbolShape>(*selected_parts.begin()); selected_shape = selected_parts.getAShape();
if (selected_shape) { if (selected_shape) {
switchEditor(new_intrusive2<SymbolPointEditor>(this, selected_shape)); switchEditor(new_intrusive2<SymbolPointEditor>(this, selected_shape));
} }
...@@ -64,6 +65,9 @@ void SymbolControl::onModeChange(wxCommandEvent& ev) { ...@@ -64,6 +65,9 @@ void SymbolControl::onModeChange(wxCommandEvent& ev) {
} }
switchEditor(new_intrusive1<SymbolBasicShapeEditor>(this)); switchEditor(new_intrusive1<SymbolBasicShapeEditor>(this));
break; break;
case ID_MODE_SYMMETRY:
switchEditor(new_intrusive1<SymbolSymmetryEditor>(this));
break;
} }
} }
...@@ -92,25 +96,17 @@ void SymbolControl::onUpdateSelection() { ...@@ -92,25 +96,17 @@ void SymbolControl::onUpdateSelection() {
switch(editor->modeToolId()) { switch(editor->modeToolId()) {
case ID_MODE_POINTS: { case ID_MODE_POINTS: {
// can only select a single part! // can only select a single part!
if (selected_parts.size() > 1) { SymbolShapeP shape = selected_parts.getAShape();
// TODO: find a part that is a shape
SymbolPartP part = *selected_parts.begin();
selected_parts.clear();
selected_parts.insert(part);
signalSelectionChange();
} else if (selected_parts.empty()) {
selected_parts.insert(selected_shape);
signalSelectionChange();
break;
}
SymbolShapeP shape = dynamic_pointer_cast<SymbolShape>(*selected_parts.begin());
if (!shape) { if (!shape) {
selected_parts.clear(); if (selected_parts.select(selected_shape)) {
selected_parts.insert(selected_shape); signalSelectionChange();
signalSelectionChange(); }
break; break;
} }
if (shape != selected_shape) { if (shape != selected_shape) {
if (selected_parts.select(shape)) {
signalSelectionChange();
}
// begin editing another part // begin editing another part
selected_shape = shape; selected_shape = shape;
editor = new_intrusive2<SymbolPointEditor>(this, selected_shape); editor = new_intrusive2<SymbolPointEditor>(this, selected_shape);
...@@ -131,16 +127,14 @@ void SymbolControl::onUpdateSelection() { ...@@ -131,16 +127,14 @@ void SymbolControl::onUpdateSelection() {
} }
void SymbolControl::selectPart(const SymbolPartP& part) { void SymbolControl::selectPart(const SymbolPartP& part) {
selected_parts.clear(); selected_parts.select(part);
selected_parts.insert(part);
switchEditor(new_intrusive2<SymbolSelectEditor>(this, false)); switchEditor(new_intrusive2<SymbolSelectEditor>(this, false));
signalSelectionChange(); signalSelectionChange();
} }
void SymbolControl::activatePart(const SymbolPartP& part) { void SymbolControl::activatePart(const SymbolPartP& part) {
if (part->isSymbolShape()) { if (part->isSymbolShape()) {
selected_parts.clear(); selected_parts.select(part);
selected_parts.insert(part);
switchEditor(new_intrusive2<SymbolPointEditor>(this, static_pointer_cast<SymbolShape>(part))); switchEditor(new_intrusive2<SymbolPointEditor>(this, static_pointer_cast<SymbolShape>(part)));
} }
} }
...@@ -247,11 +241,12 @@ void SymbolControl::onSize(wxSizeEvent& ev) { ...@@ -247,11 +241,12 @@ void SymbolControl::onSize(wxSizeEvent& ev) {
void SymbolControl::onUpdateUI(wxUpdateUIEvent& ev) { void SymbolControl::onUpdateUI(wxUpdateUIEvent& ev) {
if (!editor) return; if (!editor) return;
switch (ev.GetId()) { switch (ev.GetId()) {
case ID_MODE_SELECT: case ID_MODE_ROTATE: case ID_MODE_POINTS: case ID_MODE_SHAPES: //case ID_MODE_PAINT: case ID_MODE_SELECT: case ID_MODE_ROTATE: case ID_MODE_POINTS:
case ID_MODE_SHAPES: case ID_MODE_SYMMETRY: //case ID_MODE_PAINT:
ev.Check(editor->modeToolId() == ev.GetId()); ev.Check(editor->modeToolId() == ev.GetId());
if (ev.GetId() == ID_MODE_POINTS) { if (ev.GetId() == ID_MODE_POINTS) {
// can only edit points when a single part is selected <TODO?> // can only edit points when a shape is available
ev.Enable(selected_parts.size() == 1 && (*selected_parts.begin())->isSymbolShape()); ev.Enable(selected_parts.getAShape());
} }
break; break;
case ID_MODE_PAINT: case ID_MODE_PAINT:
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <util/prec.hpp> #include <util/prec.hpp>
#include <data/symbol.hpp> #include <data/symbol.hpp>
#include <gui/symbol/selection.hpp>
#include <render/symbol/viewer.hpp> #include <render/symbol/viewer.hpp>
class SymbolWindow; class SymbolWindow;
...@@ -71,9 +72,9 @@ class SymbolControl : public wxControl, public SymbolViewer { ...@@ -71,9 +72,9 @@ class SymbolControl : public wxControl, public SymbolViewer {
public: public:
/// What parts are selected? /// What parts are selected?
set<SymbolPartP> selected_parts; SymbolPartsSelection selected_parts;
SymbolPartP highlight_part; ///< part the mouse cursor is over SymbolPartP highlight_part; ///< part the mouse cursor is over
SymbolShapeP selected_shape; ///< if there is a single selection SymbolShapeP selected_shape; ///< if there is a single selection
/// Parent window /// Parent window
SymbolWindow* parent; SymbolWindow* parent;
......
This diff is collapsed.
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#include <util/prec.hpp> #include <util/prec.hpp>
#include <data/symbol.hpp> #include <data/symbol.hpp>
class SymbolPartsSelection;
// ----------------------------------------------------------------------------- : Events // ----------------------------------------------------------------------------- : Events
DECLARE_EVENT_TYPE(EVENT_PART_SELECT, <not used>) DECLARE_EVENT_TYPE(EVENT_PART_SELECT, <not used>)
...@@ -26,7 +28,7 @@ DECLARE_EVENT_TYPE(EVENT_PART_ACTIVATE, <not used>) ...@@ -26,7 +28,7 @@ DECLARE_EVENT_TYPE(EVENT_PART_ACTIVATE, <not used>)
class SymbolPartList : public wxScrolledWindow, public SymbolView { class SymbolPartList : public wxScrolledWindow, public SymbolView {
public: public:
SymbolPartList(Window* parent, int id, set<SymbolPartP>& selection, SymbolP symbol = SymbolP()); SymbolPartList(Window* parent, int id, SymbolPartsSelection& selection, SymbolP symbol = SymbolP());
/// Another symbol is being viewed /// Another symbol is being viewed
virtual void onChangeSymbol(); virtual void onChangeSymbol();
...@@ -41,12 +43,14 @@ class SymbolPartList : public wxScrolledWindow, public SymbolView { ...@@ -41,12 +43,14 @@ class SymbolPartList : public wxScrolledWindow, public SymbolView {
protected: protected:
virtual wxSize DoGetBestSize() const; virtual wxSize DoGetBestSize() const;
private: private:
set<SymbolPartP>& selection; ///< Store selection here SymbolPartsSelection& selection; ///< Store selection here
SymbolPartP mouse_down_on;
int drop_position;
int number_of_items; int number_of_items;
SymbolPartP drag;
SymbolGroupP drag_parent, drop_parent;
size_t drag_position, drop_position;
bool drop_inside; // drop inside the drop parent, not at a specific position
SymbolPartP typing_in; SymbolPartP typing_in;
size_t cursor; size_t cursor;
...@@ -79,8 +83,20 @@ class SymbolPartList : public wxScrolledWindow, public SymbolView { ...@@ -79,8 +83,20 @@ class SymbolPartList : public wxScrolledWindow, public SymbolView {
const Image& symbolPreview(); const Image& symbolPreview();
void updatePart(const set<SymbolPartP>& parts, int& i, bool parent_updated, const SymbolPartP& part); void updatePart(const set<SymbolPartP>& parts, int& i, bool parent_updated, const SymbolPartP& part);
SymbolPartP findItem(int i) const; /// find item by position
static SymbolPartP findItem(int& i, const SymbolPartP& part); SymbolPartP findItem(int i, int x) const;
static SymbolPartP findItem(int& i, int x, const SymbolPartP& part);
/// parent of 'of' and the position of 'of' in that parent
void findParent(const SymbolPart& of, SymbolGroupP& parent_out, size_t& pos_out);
static bool findParent(const SymbolPart& of, const SymbolGroupP& in, SymbolGroupP& parent_out, size_t& pos_out);
/// Where is the drop position?
/** i = index before which the cursor is
* before = is the cursor before or after the separator line?
* Returns whether a drop position was found, sets drop_...
*/
bool findDropTarget(const SymbolPartP& parent, int& i, bool before);
static int childCount(const SymbolPartP& part); static int childCount(const SymbolPartP& part);
......
This diff is collapsed.
...@@ -74,6 +74,15 @@ class SymbolSelectEditor : public SymbolEditorBase { ...@@ -74,6 +74,15 @@ class SymbolSelectEditor : public SymbolEditorBase {
Vector2D minV, maxV; Vector2D minV, maxV;
// Where is the rotation center? // Where is the rotation center?
Vector2D center; Vector2D center;
// What kind of clicking/dragging are we doing
enum ClickMode {
CLICK_NONE,
CLICK_MOVE, // moving parts around
CLICK_HANDLE, // dragging a handle
CLICK_CENTER, // dragging the rotation center
CLICK_RECT, // selection rectangle
CLICK_TOGGLE, // same selection, not moved -> switch to rotate mode
} click_mode;
// At what angle is the handle we started draging for rotation // At what angle is the handle we started draging for rotation
double startAngle; double startAngle;
// what side are we dragging/rotating on? // what side are we dragging/rotating on?
...@@ -82,6 +91,8 @@ class SymbolSelectEditor : public SymbolEditorBase { ...@@ -82,6 +91,8 @@ class SymbolSelectEditor : public SymbolEditorBase {
bool have_dragged; bool have_dragged;
// Do we want to rotate? // Do we want to rotate?
bool rotate; bool rotate;
// selection rectangle
Vector2D selection_rect_a, selection_rect_b;
// Graphics assets // Graphics assets
wxCursor cursorRotate; wxCursor cursorRotate;
wxCursor cursorShearX; wxCursor cursorShearX;
...@@ -104,9 +115,6 @@ class SymbolSelectEditor : public SymbolEditorBase { ...@@ -104,9 +115,6 @@ class SymbolSelectEditor : public SymbolEditorBase {
/// Return the position of a handle, dx,dy in <-1, 0, 1> /// Return the position of a handle, dx,dy in <-1, 0, 1>
Vector2D handlePos(int dx, int dy); Vector2D handlePos(int dx, int dy);
/// Find the first part at the given position
SymbolPartP findPart(const Vector2D& pos);
/// Update minV and maxV to be the bounding box of the selected_parts /// Update minV and maxV to be the bounding box of the selected_parts
/// Updates center to be the rotation center of the parts /// Updates center to be the rotation center of the parts
void updateBoundingBox(); void updateBoundingBox();
......
...@@ -108,27 +108,27 @@ void SymbolWindow::init(Window* parent, SymbolP symbol) { ...@@ -108,27 +108,27 @@ void SymbolWindow::init(Window* parent, SymbolP symbol) {
// Edit mode toolbar // Edit mode toolbar
wxPanel* emp = new wxPanel(this, wxID_ANY); wxPanel* emp = new wxPanel(this, wxID_ANY);
wxToolBar* em = new wxToolBar(emp, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTB_FLAT | wxTB_VERTICAL | wxTB_TEXT | wxTB_HORZ_LAYOUT); wxToolBar* em = new wxToolBar(emp, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTB_FLAT | wxTB_VERTICAL | wxTB_HORZ_TEXT);
em->SetToolBitmapSize(wxSize(17,17));
em->AddTool(ID_MODE_SELECT, _TOOL_("select"), load_resource_tool_image(_("mode_select")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("select"), _HELP_("select")); em->AddTool(ID_MODE_SELECT, _TOOL_("select"), load_resource_tool_image(_("mode_select")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("select"), _HELP_("select"));
em->AddTool(ID_MODE_ROTATE, _TOOL_("rotate"), load_resource_tool_image(_("mode_rotate")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("rotate"), _HELP_("rotate")); em->AddTool(ID_MODE_ROTATE, _TOOL_("rotate"), load_resource_tool_image(_("mode_rotate")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("rotate"), _HELP_("rotate"));
em->AddSeparator(); em->AddSeparator();
em->AddTool(ID_MODE_POINTS, _TOOL_("points"), load_resource_tool_image(_("mode_curve")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("points"), _HELP_("points")); em->AddTool(ID_MODE_POINTS, _TOOL_("points"), load_resource_tool_image(_("mode_curve")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("points"), _HELP_("points"));
em->AddSeparator(); em->AddSeparator();
em->AddTool(ID_MODE_SHAPES, _TOOL_("basic shapes"), load_resource_tool_image(_("circle")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("basic shapes"), _HELP_("basic shapes")); em->AddTool(ID_MODE_SHAPES, _TOOL_("basic shapes"), load_resource_tool_image(_("circle")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("basic shapes"), _HELP_("basic shapes"));
em->AddSeparator(); em->AddTool(ID_MODE_SYMMETRY, _TOOL_("symmetry"), load_resource_tool_image(_("mode_symmetry")),wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("symmetry"), _HELP_("symmetry"));
em->AddTool(ID_MODE_PAINT, _TOOL_("paint"), load_resource_tool_image(_("mode_paint")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("paint"), _HELP_("paint")); //em->AddTool(ID_MODE_PAINT, _TOOL_("paint"), load_resource_tool_image(_("mode_paint")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("paint"), _HELP_("paint"));
em->AddSeparator();
em->Realize(); em->Realize();
// Lay out
wxSizer* es = new wxBoxSizer(wxVERTICAL);
es->Add(em, 1, wxEXPAND | wxBOTTOM | wxALIGN_CENTER, 5);
emp->SetSizer(es);
// Controls // Controls
control = new SymbolControl (this, ID_CONTROL, symbol); control = new SymbolControl (this, ID_CONTROL, symbol);
parts = new SymbolPartList(this, ID_PART_LIST, control->selected_parts, symbol); parts = new SymbolPartList(this, ID_PART_LIST, control->selected_parts, symbol);
// Lay out
wxSizer* es = new wxBoxSizer(wxHORIZONTAL);
es->Add(em, 1, wxEXPAND | wxTOP | wxBOTTOM | wxALIGN_CENTER, 1);
emp->SetSizer(es);
wxSizer* s = new wxBoxSizer(wxHORIZONTAL); wxSizer* s = new wxBoxSizer(wxHORIZONTAL);
wxSizer* v = new wxBoxSizer(wxVERTICAL); wxSizer* v = new wxBoxSizer(wxVERTICAL);
v->Add(emp, 0, wxEXPAND); v->Add(emp, 0, wxEXPAND);
...@@ -137,6 +137,52 @@ void SymbolWindow::init(Window* parent, SymbolP symbol) { ...@@ -137,6 +137,52 @@ void SymbolWindow::init(Window* parent, SymbolP symbol) {
s->Add(control, 1, wxEXPAND); s->Add(control, 1, wxEXPAND);
SetSizer(s); SetSizer(s);
#ifdef __WXMSW__
// only tested on msw, may not even be needed on other platforms
#define USE_HORRIBLE_HORRIBLE_HACK_TO_MAKE_TOOLBAR_THE_RIGHT_SIZE
#endif
#ifdef USE_HORRIBLE_HORRIBLE_HACK_TO_MAKE_TOOLBAR_THE_RIGHT_SIZE
// Welcome to HackWorld
// Prevent clipping of the bottom tool
Layout();
em->SetSize(emp->GetSize());
// HACK: force edit mode toolbar to be wide enough by adding spaces to tool names
int n = 0;
while (em->GetSize().x + 5 < emp->GetSize().x) {
++n;
for (int id = ID_MODE_SELECT ; id <= ID_MODE_SYMMETRY ; ++id) {
wxToolBarToolBase* tool = em->FindById(id);
tool->SetLabel(tool->GetLabel() + _(" "));
}
em->Realize();
}
// And now rebuild it, because the above meddling broke the toolbar for some unknown reason
em->Destroy();
em = new wxToolBar(emp, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTB_FLAT | wxTB_VERTICAL | wxTB_HORZ_TEXT);
em->SetToolBitmapSize(wxSize(17,17));
String spaces(max(0,n-1), _(' '));
em->AddTool(ID_MODE_SELECT, _TOOL_("select") + spaces, load_resource_tool_image(_("mode_select")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("select"), _HELP_("select"));
em->AddTool(ID_MODE_ROTATE, _TOOL_("rotate") + spaces, load_resource_tool_image(_("mode_rotate")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("rotate"), _HELP_("rotate"));
em->AddSeparator();
em->AddTool(ID_MODE_POINTS, _TOOL_("points") + spaces, load_resource_tool_image(_("mode_curve")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("points"), _HELP_("points"));
em->AddSeparator();
em->AddTool(ID_MODE_SHAPES, _TOOL_("basic shapes") + spaces, load_resource_tool_image(_("circle")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("basic shapes"),_HELP_("basic shapes"));
em->AddTool(ID_MODE_SYMMETRY, _TOOL_("symmetry") + spaces, load_resource_tool_image(_("mode_symmetry")),wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("symmetry"), _HELP_("symmetry"));
//em->AddTool(ID_MODE_PAINT, _TOOL_("paint") + spaces, load_resource_tool_image(_("mode_paint")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("paint"), _HELP_("paint"));
em->Realize();
es = new wxBoxSizer(wxVERTICAL);
es->Add(em, 1, wxEXPAND | wxBOTTOM | wxALIGN_CENTER, 5);
emp->SetSizer(es);
// Prevent clipping of the bottom tool
Layout();
em->SetSize(emp->GetSize());
#endif
// we want update ui events // we want update ui events
wxUpdateUIEvent::SetMode(wxUPDATE_UI_PROCESS_SPECIFIED); wxUpdateUIEvent::SetMode(wxUPDATE_UI_PROCESS_SPECIFIED);
SetExtraStyle(wxWS_EX_PROCESS_UI_UPDATES); SetExtraStyle(wxWS_EX_PROCESS_UI_UPDATES);
......
...@@ -877,6 +877,18 @@ ...@@ -877,6 +877,18 @@
<File <File
RelativePath=".\gui\symbol\select_editor.hpp"> RelativePath=".\gui\symbol\select_editor.hpp">
</File> </File>
<File
RelativePath=".\gui\symbol\selection.cpp">
</File>
<File
RelativePath=".\gui\symbol\selection.hpp">
</File>
<File
RelativePath=".\gui\symbol\symmetry_editor.cpp">
</File>
<File
RelativePath=".\gui\symbol\symmetry_editor.hpp">
</File>
<File <File
RelativePath=".\gui\symbol\window.cpp"> RelativePath=".\gui\symbol\window.cpp">
<FileConfiguration <FileConfiguration
......
...@@ -164,7 +164,25 @@ void SymbolViewer::highlightPart(DC& dc, const SymbolShape& shape, HighlightStyl ...@@ -164,7 +164,25 @@ void SymbolViewer::highlightPart(DC& dc, const SymbolShape& shape, HighlightStyl
} }
} }
void SymbolViewer::highlightPart(DC& dc, const SymbolSymmetry& sym) { void SymbolViewer::highlightPart(DC& dc, const SymbolSymmetry& sym) {
// TODO // center
RealPoint center = rotation.tr(sym.center);
// draw 'spokes'
double angle = atan2(sym.handle.y, sym.handle.x);
dc.SetPen(wxPen(Color(255,200,0),3));
for (int i = 0; i < sym.copies ; ++i) {
double a = angle + (i + 0.5) * 2 * M_PI / sym.copies;
Vector2D dir(cos(a), sin(a));
Vector2D dir2 = rotation.tr(sym.center + 2 * dir);
dc.DrawLine(center.x, center.y, dir2.x, dir2.y);
}
// draw center
dc.SetPen(*wxBLACK_PEN);
dc.SetBrush(Color(255,200,0));
dc.DrawCircle(center.x, center.y, 5);
// draw handle
Vector2D dir2 = rotation.tr(sym.center + sym.handle);
dc.SetPen(wxPen(Color(255,200,0),1,wxDOT));
dc.DrawLine(center.x, center.y, dir2.x, dir2.y);
} }
void SymbolViewer::highlightPart(DC& dc, const SymbolGroup& group, HighlightStyle style) { void SymbolViewer::highlightPart(DC& dc, const SymbolGroup& group, HighlightStyle style) {
if (style == HIGHLIGHT_BORDER) { if (style == HIGHLIGHT_BORDER) {
......
...@@ -352,6 +352,7 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP& ...@@ -352,6 +352,7 @@ void instrBinary (BinaryInstructionType i, ScriptValueP& a, const ScriptValueP&
break; break;
case I_AND: OPERATOR_I(&&); case I_AND: OPERATOR_I(&&);
case I_OR: OPERATOR_I(||); case I_OR: OPERATOR_I(||);
case I_XOR: a = to_script((bool)*a != (bool)*b); break;
case I_EQ: OPERATOR_SDI(==); case I_EQ: OPERATOR_SDI(==);
case I_NEQ: OPERATOR_SDI(!=); case I_NEQ: OPERATOR_SDI(!=);
case I_LT: OPERATOR_DI(<); case I_LT: OPERATOR_DI(<);
......
...@@ -582,6 +582,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc ...@@ -582,6 +582,7 @@ void parseOper(TokenIterator& input, Script& script, Precedence minPrec, Instruc
parseOper(input, script, PREC_CMP, I_BINARY, I_OR); parseOper(input, script, PREC_CMP, I_BINARY, I_OR);
} }
} }
else if (minPrec <= PREC_AND && token==_("xor")) parseOper(input, script, PREC_CMP, I_BINARY, I_XOR);
else if (minPrec <= PREC_CMP && token==_("=")) { else if (minPrec <= PREC_CMP && token==_("=")) {
if (minPrec <= PREC_SET) { if (minPrec <= PREC_SET) {
input.add_error(_("Use of '=', did you mean ':=' or '=='?")); input.add_error(_("Use of '=', did you mean ':=' or '=='?"));
......
...@@ -146,6 +146,7 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const { ...@@ -146,6 +146,7 @@ String Script::dumpInstr(unsigned int pos, Instruction i) const {
case I_MOD: ret += _("mod"); break; case I_MOD: ret += _("mod"); break;
case I_AND: ret += _("and"); break; case I_AND: ret += _("and"); break;
case I_OR: ret += _("or"); break; case I_OR: ret += _("or"); break;
case I_XOR: ret += _("xor"); break;
case I_EQ: ret += _("=="); break; case I_EQ: ret += _("=="); break;
case I_NEQ: ret += _("!="); break; case I_NEQ: ret += _("!="); break;
case I_LT: ret += _("<"); break; case I_LT: ret += _("<"); break;
......
...@@ -63,6 +63,7 @@ enum BinaryInstructionType ...@@ -63,6 +63,7 @@ enum BinaryInstructionType
// Logical // Logical
, I_AND ///< logical and , I_AND ///< logical and
, I_OR ///< logical or , I_OR ///< logical or
, I_XOR ///< logical xor
// Comparison // Comparison
, I_EQ ///< operator == , I_EQ ///< operator ==
, I_NEQ ///< operator != , I_NEQ ///< operator !=
......
...@@ -152,6 +152,13 @@ enum ChildMenuID { ...@@ -152,6 +152,13 @@ enum ChildMenuID {
, ID_SHAPE_MAX , ID_SHAPE_MAX
, ID_SIDES , ID_SIDES
// SymbolSymmetryEditor toolbar/menu
, ID_SYMMETRY = 2201
, ID_SYMMETRY_ROTATION = ID_SHAPE
, ID_SYMMETRY_REFLECTION
, ID_SYMMETRY_MAX
, ID_COPIES
// On cards panel // On cards panel
, ID_COLLAPSE_NOTES = 3001 , ID_COLLAPSE_NOTES = 3001
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment