Commit 2593d447 authored by twanvl's avatar twanvl

Added the necessery classes to handle symmetry objects/mirrors in symbols;...

Added the necessery classes to handle symmetry objects/mirrors in symbols; What used to be SymbolPart is now SymbolShape, SymbolPart is a base class.
This should also pave the way for grouping.
parent 60b1f3c3
...@@ -413,6 +413,10 @@ label: ...@@ -413,6 +413,10 @@ label:
############################################################## Buttons/checkboxes/choices in the GUI ############################################################## Buttons/checkboxes/choices in the GUI
button: button:
# Editor
edit symbol: Edit
symbol gallery: Gallery
# Style panel # Style panel
use for all cards: Use for &all cards use for all cards: Use for &all cards
use custom styling options: Options &specific to this card use custom styling options: Options &specific to this card
...@@ -491,10 +495,35 @@ title: ...@@ -491,10 +495,35 @@ title:
############################################################## Action (undo/redo) names ############################################################## Action (undo/redo) names
action: action:
typing: Typing # Text editor
backspace: Backspace typing: Typing
delete: Delete backspace: Backspace
change: Change %s delete: Delete
# Choice/color editors
change: Change %s
# Symbol Actions
move: Move %s
rotate: Rotate %s
shear: Shear %s
scale: Resize %s
add part: Add %s
remove parts: Remove %s
duplicate: Duplicate %s
reorder parts: Reorder
change combine mode:Change combine mode
change shape name: Change shape name
# Symbol Part Actions
convert to line: Convert to line
convert to curve: Convert to curve
lock point: Lock point
move handle: Move handle
move curve: Move curve
add control point: Add control point
delete point: Delete point
delete points: Delete points
############################################################## Error messages ############################################################## Error messages
error: error:
...@@ -579,6 +608,10 @@ type: ...@@ -579,6 +608,10 @@ type:
polygon: polygon polygon: polygon
star: star star: star
point: point
points: points
handle: handle
############################################################## Magic ############################################################## Magic
game: game:
......
This diff is collapsed.
...@@ -63,7 +63,7 @@ class SymbolPartMatrixAction : public SymbolPartAction { ...@@ -63,7 +63,7 @@ class SymbolPartMatrixAction : public SymbolPartAction {
/// Perform the transformation using the given matrix /// Perform the transformation using the given matrix
void transform(const Vector2D& mx, const Vector2D& my); void transform(const Vector2D& mx, const Vector2D& my);
set<SymbolPartP> parts; ///< Parts to transform set<SymbolPartP> parts; ///< Parts to transform
Vector2D center; ///< Center to transform around Vector2D center; ///< Center to transform around
}; };
...@@ -122,22 +122,20 @@ class SymbolPartScaleAction : public SymbolPartAction { ...@@ -122,22 +122,20 @@ class SymbolPartScaleAction : public SymbolPartAction {
virtual void perform(bool to_undo); virtual void perform(bool to_undo);
/// Change min and max coordinates /// Change min and max coordinates
void move(const Vector2D& deltaMin, const Vector2D& deltaMax); void move(const Vector2D& delta_min, const Vector2D& delta_max);
/// Update the action's effect /// Update the action's effect
void update(); void update();
private: private:
set<SymbolPartP> parts; ///< Parts to scale set<SymbolPartP> parts; ///< Parts to scale
Vector2D oldMin, oldSize; ///< the original pos/size Vector2D old_min, old_size; ///< the original pos/size
Vector2D newRealMin, newRealSize; ///< the target pos/sizevoid shearBy(const Vector2D& shear) Vector2D new_real_min, new_real_size; ///< the target pos/sizevoid shearBy(const Vector2D& shear)
Vector2D newMin, newSize; ///< the target pos/size after applying constrains Vector2D new_min, new_size; ///< the target pos/size after applying constrains
int scaleX, scaleY; ///< to what corner are we attached? int scaleX, scaleY; ///< to what corner are we attached?
/// Transform everything in the parts /// Transform everything in the parts
void transformAll(); void transformAll();
/// Transform a single vector /// Transform a single vector
inline Vector2D transform(const Vector2D& v) { inline Vector2D transform(const Vector2D& v);
return (v - oldMin).div(oldSize).mul(newSize) + newMin;
}
public: public:
bool constrain; ///< Constrain movement? bool constrain; ///< Constrain movement?
int snap; ///< Snap to grid? int snap; ///< Snap to grid?
...@@ -148,13 +146,14 @@ class SymbolPartScaleAction : public SymbolPartAction { ...@@ -148,13 +146,14 @@ class SymbolPartScaleAction : public SymbolPartAction {
/// Change the name of a symbol part /// Change the name of a symbol part
class CombiningModeAction : public SymbolPartListAction { class CombiningModeAction : public SymbolPartListAction {
public: public:
CombiningModeAction(const set<SymbolPartP>& parts, SymbolPartCombine mode); // All parts must be SymbolParts
CombiningModeAction(const set<SymbolPartP>& parts, SymbolShapeCombine mode);
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:
vector<pair<SymbolPartP,SymbolPartCombine> > parts; ///< Affected parts with new combining modes vector<pair<SymbolShapeP,SymbolShapeCombine> > parts; ///< Affected parts with new combining modes
}; };
// ----------------------------------------------------------------------------- : Change name // ----------------------------------------------------------------------------- : Change name
...@@ -168,8 +167,8 @@ class SymbolPartNameAction : public SymbolPartListAction { ...@@ -168,8 +167,8 @@ class SymbolPartNameAction : public SymbolPartListAction {
virtual void perform(bool to_undo); virtual void perform(bool to_undo);
private: private:
SymbolPartP part; ///< Affected part SymbolPartP part; ///< Affected part
String partName; ///< New name String part_name; ///< New name
}; };
// ----------------------------------------------------------------------------- : Add symbol part // ----------------------------------------------------------------------------- : Add symbol part
...@@ -183,8 +182,8 @@ class AddSymbolPartAction : public SymbolPartListAction { ...@@ -183,8 +182,8 @@ class AddSymbolPartAction : public SymbolPartListAction {
virtual void perform(bool to_undo); virtual void perform(bool to_undo);
private: private:
Symbol& symbol; ///< Symbol to add the part to Symbol& symbol; ///< Symbol to add the part to
SymbolPartP part; ///< Part to add SymbolPartP part; ///< Part to add
}; };
// ----------------------------------------------------------------------------- : Remove symbol part // ----------------------------------------------------------------------------- : Remove symbol part
......
...@@ -80,6 +80,10 @@ Vector2D constrain_snap_vector_offset(const Vector2D& off1, const Vector2D& off2 ...@@ -80,6 +80,10 @@ Vector2D constrain_snap_vector_offset(const Vector2D& off1, const Vector2D& off2
return dd; return dd;
} }
String action_name_for(const set<ControlPointP>& points, const String& action) {
return format_string(action, points.size() == 1 ? _TYPE_("point") : _TYPE_("points"));
}
// ----------------------------------------------------------------------------- : Move control point // ----------------------------------------------------------------------------- : Move control point
...@@ -95,7 +99,7 @@ ControlPointMoveAction::ControlPointMoveAction(const set<ControlPointP>& points) ...@@ -95,7 +99,7 @@ ControlPointMoveAction::ControlPointMoveAction(const set<ControlPointP>& points)
} }
String ControlPointMoveAction::getName(bool to_undo) const { String ControlPointMoveAction::getName(bool to_undo) const {
return points.size() == 1 ? _("Move point") : _("Move points"); return action_name_for(points, _ACTION_("move"));
} }
void ControlPointMoveAction::perform(bool to_undo) { void ControlPointMoveAction::perform(bool to_undo) {
...@@ -126,7 +130,7 @@ HandleMoveAction::HandleMoveAction(const SelectedHandle& handle) ...@@ -126,7 +130,7 @@ HandleMoveAction::HandleMoveAction(const SelectedHandle& handle)
{} {}
String HandleMoveAction::getName(bool to_undo) const { String HandleMoveAction::getName(bool to_undo) const {
return _("Move handle"); return _ACTION_("move handle");
} }
void HandleMoveAction::perform(bool to_undo) { void HandleMoveAction::perform(bool to_undo) {
...@@ -171,8 +175,8 @@ SegmentModeAction::SegmentModeAction(const ControlPointP& p1, const ControlPoint ...@@ -171,8 +175,8 @@ SegmentModeAction::SegmentModeAction(const ControlPointP& p1, const ControlPoint
} }
String SegmentModeAction::getName(bool to_undo) const { String SegmentModeAction::getName(bool to_undo) const {
SegmentMode mode = to_undo ? point1.point->segment_after : point1.other.segment_after; SegmentMode mode = to_undo ? point1.point->segment_after : point1.other.segment_after;
if (mode == SEGMENT_LINE) return _("Convert to line"); if (mode == SEGMENT_LINE) return _ACTION_("convert to line");
else return _("Convert to curve"); else return _ACTION_("convert to curve");
} }
void SegmentModeAction::perform(bool to_undo) { void SegmentModeAction::perform(bool to_undo) {
...@@ -191,7 +195,7 @@ LockModeAction::LockModeAction(const ControlPointP& p, LockMode lock) ...@@ -191,7 +195,7 @@ LockModeAction::LockModeAction(const ControlPointP& p, LockMode lock)
} }
String LockModeAction::getName(bool to_undo) const { String LockModeAction::getName(bool to_undo) const {
return _("Lock point"); return _ACTION_("lock point");
} }
void LockModeAction::perform(bool to_undo) { void LockModeAction::perform(bool to_undo) {
...@@ -206,7 +210,7 @@ CurveDragAction::CurveDragAction(const ControlPointP& point1, const ControlPoint ...@@ -206,7 +210,7 @@ CurveDragAction::CurveDragAction(const ControlPointP& point1, const ControlPoint
{} {}
String CurveDragAction::getName(bool to_undo) const { String CurveDragAction::getName(bool to_undo) const {
return _("Move curve"); return _ACTION_("move curve");
} }
void CurveDragAction::perform(bool to_undo) { void CurveDragAction::perform(bool to_undo) {
...@@ -239,12 +243,12 @@ void CurveDragAction::move(const Vector2D& delta, double t) { ...@@ -239,12 +243,12 @@ void CurveDragAction::move(const Vector2D& delta, double t) {
// ----------------------------------------------------------------------------- : Add control point // ----------------------------------------------------------------------------- : Add control point
ControlPointAddAction::ControlPointAddAction(const SymbolPartP& part, UInt insert_after, double t) ControlPointAddAction::ControlPointAddAction(const SymbolShapeP& shape, UInt insert_after, double t)
: part(part) : shape(shape)
, new_point(new ControlPoint()) , new_point(new ControlPoint())
, insert_after(insert_after) , insert_after(insert_after)
, point1(part->getPoint(insert_after)) , point1(shape->getPoint(insert_after))
, point2(part->getPoint(insert_after + 1)) , point2(shape->getPoint(insert_after + 1))
{ {
// calculate new point // calculate new point
if (point1.other.segment_after == SEGMENT_CURVE) { if (point1.other.segment_after == SEGMENT_CURVE) {
...@@ -265,14 +269,14 @@ ControlPointAddAction::ControlPointAddAction(const SymbolPartP& part, UInt inser ...@@ -265,14 +269,14 @@ ControlPointAddAction::ControlPointAddAction(const SymbolPartP& part, UInt inser
} }
String ControlPointAddAction::getName(bool to_undo) const { String ControlPointAddAction::getName(bool to_undo) const {
return _("Add control point"); return _ACTION_("add control point");
} }
void ControlPointAddAction::perform(bool to_undo) { void ControlPointAddAction::perform(bool to_undo) {
if (to_undo) { // remove the point if (to_undo) { // remove the point
part->points.erase( part->points.begin() + insert_after + 1); shape->points.erase( shape->points.begin() + insert_after + 1);
} else { } else {
part->points.insert(part->points.begin() + insert_after + 1, new_point); shape->points.insert(shape->points.begin() + insert_after + 1, new_point);
} }
// update points before/after // update points before/after
point1.perform(); point1.perform();
...@@ -291,24 +295,24 @@ double ssqrt(double x) { ...@@ -291,24 +295,24 @@ double ssqrt(double x) {
// Remove a single control point // Remove a single control point
class SinglePointRemoveAction : public Action, public IntrusivePtrBase<SinglePointRemoveAction> { class SinglePointRemoveAction : public Action, public IntrusivePtrBase<SinglePointRemoveAction> {
public: public:
SinglePointRemoveAction(const SymbolPartP& part, UInt position); SinglePointRemoveAction(const SymbolShapeP& shape, UInt position);
virtual String getName(bool to_undo) const { return _("Delete point"); } virtual String getName(bool to_undo) const { return _("Delete point"); }
virtual void perform(bool to_undo); virtual void perform(bool to_undo);
private: private:
SymbolPartP part; SymbolShapeP shape;
UInt position; UInt position;
ControlPointP point; ///< Removed point ControlPointP point; ///< Removed point
ControlPointUpdate point1, point2; ///< Points before/after ControlPointUpdate point1, point2; ///< Points before/after
}; };
SinglePointRemoveAction::SinglePointRemoveAction(const SymbolPartP& part, UInt position) SinglePointRemoveAction::SinglePointRemoveAction(const SymbolShapeP& shape, UInt position)
: part(part) : shape(shape)
, position(position) , position(position)
, point (part->getPoint(position)) , point (shape->getPoint(position))
, point1(part->getPoint(position - 1)) , point1(shape->getPoint(position - 1))
, point2(part->getPoint(position + 1)) , point2(shape->getPoint(position + 1))
{ {
if (point1.other.segment_after == SEGMENT_CURVE || point2.other.segment_before == SEGMENT_CURVE) { if (point1.other.segment_after == SEGMENT_CURVE || point2.other.segment_before == SEGMENT_CURVE) {
// try to preserve curve // try to preserve curve
...@@ -359,10 +363,10 @@ SinglePointRemoveAction::SinglePointRemoveAction(const SymbolPartP& part, UInt p ...@@ -359,10 +363,10 @@ SinglePointRemoveAction::SinglePointRemoveAction(const SymbolPartP& part, UInt p
void SinglePointRemoveAction::perform(bool to_undo) { void SinglePointRemoveAction::perform(bool to_undo) {
if (to_undo) { if (to_undo) {
// reinsert the point // reinsert the point
part->points.insert(part->points.begin() + position, point); shape->points.insert(shape->points.begin() + position, point);
} else { } else {
// remove the point // remove the point
part->points.erase( part->points.begin() + position); shape->points.erase( shape->points.begin() + position);
} }
// update points around removed point // update points around removed point
point1.perform(); point1.perform();
...@@ -373,12 +377,12 @@ DECLARE_POINTER_TYPE(SinglePointRemoveAction); ...@@ -373,12 +377,12 @@ DECLARE_POINTER_TYPE(SinglePointRemoveAction);
DECLARE_TYPEOF_COLLECTION(SinglePointRemoveActionP); DECLARE_TYPEOF_COLLECTION(SinglePointRemoveActionP);
// Remove a set of points from a symbol part. // Remove a set of points from a symbol shape.
// Internally represented as a list of Single Point Remove Actions. // Internally represented as a list of Single Point Remove Actions.
// Not all points mat be removed, at least two points must remain. // Not all points mat be removed, at least two points must remain.
class ControlPointRemoveAction : public Action { class ControlPointRemoveAction : public Action {
public: public:
ControlPointRemoveAction(const SymbolPartP& part, const set<ControlPointP>& toDelete); ControlPointRemoveAction(const SymbolShapeP& shape, const set<ControlPointP>& to_delete);
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);
...@@ -387,20 +391,20 @@ class ControlPointRemoveAction : public Action { ...@@ -387,20 +391,20 @@ class ControlPointRemoveAction : public Action {
vector<SinglePointRemoveActionP> removals; vector<SinglePointRemoveActionP> removals;
}; };
ControlPointRemoveAction::ControlPointRemoveAction(const SymbolPartP& part, const set<ControlPointP>& toDelete) { ControlPointRemoveAction::ControlPointRemoveAction(const SymbolShapeP& shape, const set<ControlPointP>& to_delete) {
int index = 0; int index = 0;
// find points to remove, in reverse order // find points to remove, in reverse order
FOR_EACH(point, part->points) { FOR_EACH(point, shape->points) {
if (toDelete.find(point) != toDelete.end()) { if (to_delete.find(point) != to_delete.end()) {
// remove this point // remove this point
removals.push_back(new_intrusive2<SinglePointRemoveAction>(part, index)); removals.push_back(new_intrusive2<SinglePointRemoveAction>(shape, index));
} }
++index; ++index;
} }
} }
String ControlPointRemoveAction::getName(bool to_undo) const { String ControlPointRemoveAction::getName(bool to_undo) const {
return removals.size() == 1 ? _("Delete point") : _("Delete points"); return removals.size() == 1 ? _ACTION_("delete point") : _ACTION_("delete points");
} }
void ControlPointRemoveAction::perform(bool to_undo) { void ControlPointRemoveAction::perform(bool to_undo) {
...@@ -414,12 +418,12 @@ void ControlPointRemoveAction::perform(bool to_undo) { ...@@ -414,12 +418,12 @@ void ControlPointRemoveAction::perform(bool to_undo) {
} }
Action* controlPointRemoveAction(const SymbolPartP& part, const set<ControlPointP>& toDelete) { Action* control_point_remove_action(const SymbolShapeP& shape, const set<ControlPointP>& to_delete) {
if (part->points.size() - toDelete.size() < 2) { if (shape->points.size() - to_delete.size() < 2) {
// TODO : remove part? // TODO : remove part?
//new_intrusive<ControlPointRemoveAllAction>(part); //new_intrusive<ControlPointRemoveAllAction>(part);
return 0; // no action return 0; // no action
} else { } else {
return new ControlPointRemoveAction(part, toDelete); return new ControlPointRemoveAction(shape, to_delete);
} }
} }
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
/** @file data/action/symbol_part.hpp /** @file data/action/symbol_part.hpp
* *
* Actions operating on the insides of SymbolParts (ControlPoints and the like). * Actions operating on the insides of SymbolParts/SymbolShapes (ControlPoints and the like).
*/ */
// ----------------------------------------------------------------------------- : Includes // ----------------------------------------------------------------------------- : Includes
...@@ -147,11 +147,11 @@ class CurveDragAction : public SegmentModeAction { ...@@ -147,11 +147,11 @@ class CurveDragAction : public SegmentModeAction {
// ----------------------------------------------------------------------------- : Add control point // ----------------------------------------------------------------------------- : Add control point
/// Insert a new point in a symbol part /// Insert a new point in a symbol shape
class ControlPointAddAction : public Action { class ControlPointAddAction : public Action {
public: public:
/// Insert a new point in part, after position insertAfter_, at the time t on the segment /// Insert a new point in shape, after position insertAfter_, at the time t on the segment
ControlPointAddAction(const SymbolPartP& part, UInt insert_after, double t); ControlPointAddAction(const SymbolShapeP& shape, UInt insert_after, double t);
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);
...@@ -159,17 +159,17 @@ class ControlPointAddAction : public Action { ...@@ -159,17 +159,17 @@ class ControlPointAddAction : public Action {
inline ControlPointP getNewPoint() const { return new_point; } inline ControlPointP getNewPoint() const { return new_point; }
private: private:
SymbolPartP part; ///< SymbolPart we are in SymbolShapeP shape; ///< SymbolShape we are in
ControlPointP new_point; ///< The point to insert ControlPointP new_point; ///< The point to insert
UInt insert_after; ///< Insert after index .. in the array UInt insert_after; ///< Insert after index .. in the array
ControlPointUpdate point1, point2; ///< Update the points around the new point ControlPointUpdate point1, point2; ///< Update the points around the new point
}; };
// ----------------------------------------------------------------------------- : Remove control point // ----------------------------------------------------------------------------- : Remove control point
/// Action that removes any number of points from a symbol part /// Action that removes any number of points from a symbol shape
/// TODO: If less then 3 points are left removes the entire part? /// TODO: If less then 3 points are left removes the entire shape?
Action* controlPointRemoveAction(const SymbolPartP& part, const set<ControlPointP>& toDelete); Action* control_point_remove_action(const SymbolShapeP& shape, const set<ControlPointP>& to_delete);
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
......
This diff is collapsed.
...@@ -31,7 +31,7 @@ SymbolP image_to_symbol(Image& img); ...@@ -31,7 +31,7 @@ SymbolP image_to_symbol(Image& img);
void simplify_symbol(Symbol&); void simplify_symbol(Symbol&);
/// Simplify a symbol parts, i.e. use bezier curves instead of lots of lines /// Simplify a symbol parts, i.e. use bezier curves instead of lots of lines
void simplify_symbol_part(SymbolPart&); void simplify_symbol_shape(SymbolShape&);
// ----------------------------------------------------------------------------- : EOF // ----------------------------------------------------------------------------- : EOF
#endif #endif
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
#include <script/to_value.hpp> #include <script/to_value.hpp>
#include <gfx/bezier.hpp> #include <gfx/bezier.hpp>
DECLARE_TYPEOF_COLLECTION(SymbolPartP);
DECLARE_TYPEOF_COLLECTION(ControlPointP); DECLARE_TYPEOF_COLLECTION(ControlPointP);
// ----------------------------------------------------------------------------- : ControlPoint // ----------------------------------------------------------------------------- : ControlPoint
...@@ -94,17 +93,39 @@ Vector2D& ControlPoint::getOther(WhichHandle wh) { ...@@ -94,17 +93,39 @@ Vector2D& ControlPoint::getOther(WhichHandle wh) {
// ----------------------------------------------------------------------------- : SymbolPart // ----------------------------------------------------------------------------- : SymbolPart
IMPLEMENT_REFLECTION_ENUM(SymbolPartCombine) {
VALUE_N("overlap", PART_OVERLAP);
VALUE_N("merge", PART_MERGE);
VALUE_N("subtract", PART_SUBTRACT);
VALUE_N("intersection", PART_INTERSECTION);
VALUE_N("difference", PART_DIFFERENCE);
VALUE_N("border", PART_BORDER);
}
IMPLEMENT_REFLECTION(SymbolPart) { IMPLEMENT_REFLECTION(SymbolPart) {
REFLECT_IF_NOT_READING {
String type = typeName();
REFLECT(type);
}
REFLECT(name); REFLECT(name);
}
template <>
SymbolPartP read_new<SymbolPart>(Reader& reader) {
// there must be a type specified
String type;
reader.handle(_("type"), type);
if (type == _("shape") || type.empty()) return new_intrusive<SymbolShape>();
else if (type == _("symmetry")) return new_intrusive<SymbolSymmetry>();
else {
throw ParseError(_("Unsupported symbol part type: '") + type + _("'"));
}
}
// ----------------------------------------------------------------------------- : SymbolShape
IMPLEMENT_REFLECTION_ENUM(SymbolShapeCombine) {
VALUE_N("overlap", SYMBOL_COMBINE_OVERLAP);
VALUE_N("merge", SYMBOL_COMBINE_MERGE);
VALUE_N("subtract", SYMBOL_COMBINE_SUBTRACT);
VALUE_N("intersection", SYMBOL_COMBINE_INTERSECTION);
VALUE_N("difference", SYMBOL_COMBINE_DIFFERENCE);
VALUE_N("border", SYMBOL_COMBINE_BORDER);
}
IMPLEMENT_REFLECTION(SymbolShape) {
REFLECT_BASE(SymbolPart);
REFLECT(combine); REFLECT(combine);
REFLECT(points); REFLECT(points);
// Fixes after reading // Fixes after reading
...@@ -126,12 +147,16 @@ IMPLEMENT_REFLECTION(SymbolPart) { ...@@ -126,12 +147,16 @@ IMPLEMENT_REFLECTION(SymbolPart) {
} }
} }
SymbolPart::SymbolPart() SymbolShape::SymbolShape()
: combine(PART_OVERLAP), rotation_center(.5, .5) : combine(SYMBOL_COMBINE_OVERLAP), rotation_center(.5, .5)
{} {}
SymbolPartP SymbolPart::clone() const { String SymbolShape::typeName() const {
SymbolPartP part = new_intrusive1<SymbolPart>(*this); return _("shape");
}
SymbolPartP SymbolShape::clone() const {
SymbolShapeP part(new SymbolShape(*this));
// also clone the control points // also clone the control points
FOR_EACH(p, part->points) { FOR_EACH(p, part->points) {
p = new_intrusive1<ControlPoint>(*p); p = new_intrusive1<ControlPoint>(*p);
...@@ -139,7 +164,7 @@ SymbolPartP SymbolPart::clone() const { ...@@ -139,7 +164,7 @@ SymbolPartP SymbolPart::clone() const {
return part; return part;
} }
void SymbolPart::enforceConstraints() { void SymbolShape::enforceConstraints() {
for (int i = 0 ; i < (int)points.size() ; ++i) { for (int i = 0 ; i < (int)points.size() ; ++i) {
ControlPointP p1 = getPoint(i); ControlPointP p1 = getPoint(i);
ControlPointP p2 = getPoint(i + 1); ControlPointP p2 = getPoint(i + 1);
...@@ -148,7 +173,7 @@ void SymbolPart::enforceConstraints() { ...@@ -148,7 +173,7 @@ void SymbolPart::enforceConstraints() {
} }
} }
void SymbolPart::calculateBounds() { void SymbolShape::calculateBounds() {
min_pos = Vector2D::infinity(); min_pos = Vector2D::infinity();
max_pos = -Vector2D::infinity(); max_pos = -Vector2D::infinity();
for (int i = 0 ; i < (int)points.size() ; ++i) { for (int i = 0 ; i < (int)points.size() ; ++i) {
...@@ -156,6 +181,43 @@ void SymbolPart::calculateBounds() { ...@@ -156,6 +181,43 @@ void SymbolPart::calculateBounds() {
} }
} }
// ----------------------------------------------------------------------------- : SymbolSymmetry
IMPLEMENT_REFLECTION_ENUM(SymbolSymmetryType) {
VALUE_N("rotation", SYMMETRY_ROTATION);
VALUE_N("reflection", SYMMETRY_REFLECTION);
}
SymbolSymmetry::SymbolSymmetry()
: kind(SYMMETRY_ROTATION), copies(2)
{}
String SymbolSymmetry::typeName() const {
return _("symmetry");
}
SymbolPartP SymbolSymmetry::clone() const {
return new_intrusive1<SymbolSymmetry>(*this);
}
IMPLEMENT_REFLECTION(SymbolSymmetry) {
REFLECT_BASE(SymbolPart);
REFLECT(kind);
REFLECT(copies);
REFLECT(center);
REFLECT(handle);
// Fixes after reading
REFLECT_IF_READING {
if (name.empty()) {
if (kind == SYMMETRY_REFLECTION) {
name = _("Mirror");
} else {
name = _("Symmetry");
}
}
}
}
// ----------------------------------------------------------------------------- : Symbol // ----------------------------------------------------------------------------- : Symbol
IMPLEMENT_REFLECTION(Symbol) { IMPLEMENT_REFLECTION(Symbol) {
...@@ -165,8 +227,8 @@ IMPLEMENT_REFLECTION(Symbol) { ...@@ -165,8 +227,8 @@ IMPLEMENT_REFLECTION(Symbol) {
// ----------------------------------------------------------------------------- : Default symbol // ----------------------------------------------------------------------------- : Default symbol
// A default symbol part, a square, moved by d // A default symbol part, a square, moved by d
SymbolPartP default_symbol_part(double d) { SymbolShapeP default_symbol_part(double d) {
SymbolPartP part = new_intrusive<SymbolPart>(); SymbolShapeP part = new_intrusive<SymbolShape>();
part->points.push_back(new_intrusive2<ControlPoint>(d + .2, d + .2)); part->points.push_back(new_intrusive2<ControlPoint>(d + .2, d + .2));
part->points.push_back(new_intrusive2<ControlPoint>(d + .2, d + .8)); part->points.push_back(new_intrusive2<ControlPoint>(d + .2, d + .8));
part->points.push_back(new_intrusive2<ControlPoint>(d + .8, d + .8)); part->points.push_back(new_intrusive2<ControlPoint>(d + .8, d + .8));
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
DECLARE_POINTER_TYPE(ControlPoint); DECLARE_POINTER_TYPE(ControlPoint);
DECLARE_POINTER_TYPE(SymbolPart); DECLARE_POINTER_TYPE(SymbolPart);
DECLARE_POINTER_TYPE(SymbolShape);
DECLARE_POINTER_TYPE(SymbolSymmetry);
DECLARE_POINTER_TYPE(Symbol); DECLARE_POINTER_TYPE(Symbol);
// ----------------------------------------------------------------------------- : ControlPoint // ----------------------------------------------------------------------------- : ControlPoint
...@@ -43,7 +45,7 @@ enum WhichHandle ...@@ -43,7 +45,7 @@ enum WhichHandle
, HANDLE_AFTER , HANDLE_AFTER
}; };
/// A control point (corner) of a SymbolPart (polygon/bezier-gon) /// A control point (corner) of a SymbolShape (polygon/bezier-gon)
class ControlPoint : public IntrusivePtrBase<ControlPoint> { class ControlPoint : public IntrusivePtrBase<ControlPoint> {
public: public:
Vector2D pos; ///< position of the control point itself Vector2D pos; ///< position of the control point itself
...@@ -104,14 +106,41 @@ class SelectedHandle { ...@@ -104,14 +106,41 @@ class SelectedHandle {
// ----------------------------------------------------------------------------- : SymbolPart // ----------------------------------------------------------------------------- : SymbolPart
/// A part of a symbol, not necesserly a shape
class SymbolPart : public IntrusivePtrVirtualBase {
public:
/// Name/label for this part
String name;
/// Type of this part
virtual String typeName() const = 0;
/// Create a clone of this symbol part
virtual SymbolPartP clone() const = 0;
/// Icon for this part
virtual int icon() const = 0;
/// Convert tot SymbolShape?
virtual SymbolShape* isSymbolShape() { return nullptr; }
virtual const SymbolShape* isSymbolShape() const { return nullptr; }
/// Convert tot SymbolSymmetry?
virtual SymbolSymmetry* isSymbolSymmetry() { return nullptr; }
virtual const SymbolSymmetry* isSymbolSymmetry() const { return nullptr; }
DECLARE_REFLECTION_VIRTUAL();
};
template <> SymbolPartP read_new<SymbolPart>(Reader& reader);
// ----------------------------------------------------------------------------- : SymbolShape
/// How are symbol parts combined with parts below it? /// How are symbol parts combined with parts below it?
enum SymbolPartCombine enum SymbolShapeCombine
{ PART_MERGE { SYMBOL_COMBINE_MERGE
, PART_SUBTRACT , SYMBOL_COMBINE_SUBTRACT
, PART_INTERSECTION , SYMBOL_COMBINE_INTERSECTION
, PART_DIFFERENCE , SYMBOL_COMBINE_DIFFERENCE
, PART_OVERLAP , SYMBOL_COMBINE_OVERLAP
, PART_BORDER , SYMBOL_COMBINE_BORDER
}; };
/// A sane mod function, always returns a result in the range [0..size) /// A sane mod function, always returns a result in the range [0..size)
...@@ -120,25 +149,26 @@ inline size_t mod(int a, size_t size) { ...@@ -120,25 +149,26 @@ inline size_t mod(int a, size_t size) {
return m >= 0 ? m : m + size; return m >= 0 ? m : m + size;
} }
/// A single part (polygon/bezier-gon) in a Symbol /// A single shape (polygon/bezier-gon) in a Symbol
class SymbolPart : public IntrusivePtrBase<SymbolPart> { class SymbolShape : public SymbolPart {
public: public:
/// The points of this polygon /// The points of this polygon
vector<ControlPointP> points; vector<ControlPointP> points;
/// Name/label for this part
String name;
/// How is this part combined with parts below it? /// How is this part combined with parts below it?
SymbolPartCombine combine; SymbolShapeCombine combine;
// Center of rotation, relative to the part, when the part is scaled to [0..1] // Center of rotation, relative to the part, when the part is scaled to [0..1]
Vector2D rotation_center; Vector2D rotation_center;
/// Position and size of the part /// Position and size of the part
/// this is the smallest axis aligned bounding box that fits around the part /// this is the smallest axis aligned bounding box that fits around the part
Vector2D min_pos, max_pos; Vector2D min_pos, max_pos;
SymbolPart(); SymbolShape();
/// Create a clone of this symbol part virtual String typeName() const;
SymbolPartP clone() const; virtual SymbolPartP clone() const;
virtual int icon() const { return combine; }
virtual SymbolShape* isSymbolShape() { return this; }
virtual const SymbolShape* isSymbolShape() const { return this; }
/// Get a control point, wraps around /// Get a control point, wraps around
inline ControlPointP getPoint(int id) const { inline ControlPointP getPoint(int id) const {
...@@ -155,6 +185,34 @@ class SymbolPart : public IntrusivePtrBase<SymbolPart> { ...@@ -155,6 +185,34 @@ class SymbolPart : public IntrusivePtrBase<SymbolPart> {
}; };
// ----------------------------------------------------------------------------- : SymbolSymmetry
enum SymbolSymmetryType
{ SYMMETRY_ROTATION = SYMBOL_COMBINE_BORDER + 1 // for icons
, SYMMETRY_REFLECTION
};
/// A mirror, reflecting part of the symbol
/** Can handle rotation symmetry with any number of reflections */
class SymbolSymmetry : public SymbolPart {
public:
SymbolSymmetryType kind; ///< What kind of symmetry
int copies; ///< How many times is the orignal reflected (including the original itself)
bool clip; ///< Clip the orignal so it doesn't intersect the mirror(s)
Vector2D center; ///< Center point of the mirror
Vector2D handle; ///< A handle pointing in the direction of the original, relative to the center
SymbolSymmetry();
virtual String typeName() const;
virtual SymbolPartP clone() const;
virtual int icon() const { return kind; }
virtual SymbolSymmetry* isSymbolSymmetry() { return this; }
virtual const SymbolSymmetry* isSymbolSymmetry() const { return this; }
DECLARE_REFLECTION();
};
// ----------------------------------------------------------------------------- : Symbol // ----------------------------------------------------------------------------- : Symbol
/// An editable symbol, consists of any number of SymbolParts /// An editable symbol, consists of any number of SymbolParts
......
...@@ -141,17 +141,17 @@ bool point_in_bounds(const Vector2D& p, const Vector2D& min, const Vector2D& max ...@@ -141,17 +141,17 @@ bool point_in_bounds(const Vector2D& p, const Vector2D& min, const Vector2D& max
// ----------------------------------------------------------------------------- : Point tests // ----------------------------------------------------------------------------- : Point tests
// As a point inside a symbol part? // Is a point inside a symbol shape?
bool point_in_part(const Vector2D& pos, const SymbolPart& part) { bool point_in_shape(const Vector2D& pos, const SymbolShape& shape) {
// Step 1. compare bounding box of the part // Step 1. compare bounding box of the part
if (!point_in_bounds(pos, part.min_pos, part.max_pos)) return false; if (!point_in_bounds(pos, shape.min_pos, shape.max_pos)) return false;
// Step 2. trace ray outward, count intersections // Step 2. trace ray outward, count intersections
int count = 0; int count = 0;
size_t size = part.points.size(); size_t size = shape.points.size();
for(size_t i = 0 ; i < size ; ++i) { for(size_t i = 0 ; i < size ; ++i) {
ControlPointP p1 = part.getPoint((int) i); ControlPointP p1 = shape.getPoint((int) i);
ControlPointP p2 = part.getPoint((int) i + 1); ControlPointP p2 = shape.getPoint((int) i + 1);
if (p1->segment_after == SEGMENT_LINE) { if (p1->segment_after == SEGMENT_LINE) {
count += intersect_line_ray (p1->pos, p2->pos, pos); count += intersect_line_ray (p1->pos, p2->pos, pos);
} else { } else {
......
...@@ -98,8 +98,8 @@ void point_bounds(const Vector2D& p, Vector2D& min, Vector2D& max); ...@@ -98,8 +98,8 @@ void point_bounds(const Vector2D& p, Vector2D& min, Vector2D& max);
// ----------------------------------------------------------------------------- : Point tests // ----------------------------------------------------------------------------- : Point tests
/// Is a point inside the given symbol part? /// Is a point inside the given shape?
bool point_in_part(const Vector2D& p, const SymbolPart& part); bool point_in_shape(const Vector2D& p, const SymbolShape& part);
// ----------------------------------------------------------------------------- : Finding points // ----------------------------------------------------------------------------- : Finding points
......
...@@ -133,7 +133,7 @@ bool SymbolBasicShapeEditor::isEditing() { return drawing; } ...@@ -133,7 +133,7 @@ bool SymbolBasicShapeEditor::isEditing() { return drawing; }
// ----------------------------------------------------------------------------- : Generating shapes // ----------------------------------------------------------------------------- : Generating shapes
void SymbolBasicShapeEditor::stopActions() { void SymbolBasicShapeEditor::stopActions() {
shape = SymbolPartP(); shape = SymbolShapeP();
drawing = false; drawing = false;
switch (mode) { switch (mode) {
case ID_SHAPE_CIRCLE: case ID_SHAPE_CIRCLE:
...@@ -176,7 +176,7 @@ void SymbolBasicShapeEditor::makeShape(const Vector2D& a, const Vector2D& b, boo ...@@ -176,7 +176,7 @@ void SymbolBasicShapeEditor::makeShape(const Vector2D& a, const Vector2D& b, boo
// TODO : Move out of this class // TODO : Move out of this class
void SymbolBasicShapeEditor::makeCenteredShape(const Vector2D& c, Vector2D r, bool constrained) { void SymbolBasicShapeEditor::makeCenteredShape(const Vector2D& c, Vector2D r, bool constrained) {
shape = new_intrusive<SymbolPart>(); shape = new_intrusive<SymbolShape>();
// What shape to make? // What shape to make?
switch (mode) { switch (mode) {
case ID_SHAPE_CIRCLE: { case ID_SHAPE_CIRCLE: {
......
...@@ -48,7 +48,7 @@ class SymbolBasicShapeEditor : public SymbolEditorBase { ...@@ -48,7 +48,7 @@ class SymbolBasicShapeEditor : public SymbolEditorBase {
// --------------------------------------------------- : Data // --------------------------------------------------- : Data
private: private:
int mode; int mode;
SymbolPartP shape; SymbolShapeP shape;
Vector2D start; Vector2D start;
Vector2D end; Vector2D end;
bool drawing; bool drawing;
......
...@@ -51,8 +51,10 @@ void SymbolControl::onModeChange(wxCommandEvent& ev) { ...@@ -51,8 +51,10 @@ 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) {
single_selection = *selected_parts.begin(); selected_shape = dynamic_pointer_cast<SymbolShape>(*selected_parts.begin());
switchEditor(new_intrusive2<SymbolPointEditor>(this, single_selection)); if (selected_shape) {
switchEditor(new_intrusive2<SymbolPointEditor>(this, selected_shape));
}
} }
break; break;
case ID_MODE_SHAPES: case ID_MODE_SHAPES:
...@@ -88,25 +90,34 @@ void SymbolControl::onAction(const Action& action, bool undone) { ...@@ -88,25 +90,34 @@ void SymbolControl::onAction(const Action& action, bool undone) {
void SymbolControl::onUpdateSelection() { 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) { if (selected_parts.size() > 1) {
// TODO: find a part that is a shape
SymbolPartP part = *selected_parts.begin(); SymbolPartP part = *selected_parts.begin();
selected_parts.clear(); selected_parts.clear();
selected_parts.insert(part); selected_parts.insert(part);
signalSelectionChange(); signalSelectionChange();
} else if (selected_parts.empty()) { } else if (selected_parts.empty()) {
selected_parts.insert(single_selection); selected_parts.insert(selected_shape);
signalSelectionChange();
break;
}
SymbolShapeP shape = dynamic_pointer_cast<SymbolShape>(*selected_parts.begin());
if (!shape) {
selected_parts.clear();
selected_parts.insert(selected_shape);
signalSelectionChange(); signalSelectionChange();
break;
} }
if (single_selection != *selected_parts.begin()) { if (shape != selected_shape) {
// begin editing another part // begin editing another part
single_selection = *selected_parts.begin(); selected_shape = shape;
editor = new_intrusive2<SymbolPointEditor>(this, single_selection); editor = new_intrusive2<SymbolPointEditor>(this, selected_shape);
Refresh(false); Refresh(false);
} }
break; break;
case ID_MODE_SHAPES: } case ID_MODE_SHAPES:
if (!selected_parts.empty()) { if (!selected_parts.empty()) {
// there can't be a selection // there can't be a selection
selected_parts.clear(); selected_parts.clear();
...@@ -127,9 +138,11 @@ void SymbolControl::selectPart(const SymbolPartP& part) { ...@@ -127,9 +138,11 @@ void SymbolControl::selectPart(const SymbolPartP& part) {
} }
void SymbolControl::activatePart(const SymbolPartP& part) { void SymbolControl::activatePart(const SymbolPartP& part) {
selected_parts.clear(); if (part->isSymbolShape()) {
selected_parts.insert(part); selected_parts.clear();
switchEditor(new_intrusive2<SymbolPointEditor>(this, part)); selected_parts.insert(part);
switchEditor(new_intrusive2<SymbolPointEditor>(this, static_pointer_cast<SymbolShape>(part)));
}
} }
void SymbolControl::signalSelectionChange() { void SymbolControl::signalSelectionChange() {
......
...@@ -44,7 +44,7 @@ class SymbolControl : public wxControl, public SymbolViewer { ...@@ -44,7 +44,7 @@ class SymbolControl : public wxControl, public SymbolViewer {
/// The selection has changed, tell the part list /// The selection has changed, tell the part list
void signalSelectionChange(); void signalSelectionChange();
/// Activate a part, open it in the point editor /// Activate a part, open it in the point editor, if it is a shape
void activatePart(const SymbolPartP& part); void activatePart(const SymbolPartP& part);
/// Select a specific part from the symbol /// Select a specific part from the symbol
...@@ -70,9 +70,9 @@ class SymbolControl : public wxControl, public SymbolViewer { ...@@ -70,9 +70,9 @@ class SymbolControl : public wxControl, public SymbolViewer {
// --------------------------------------------------- : Data // --------------------------------------------------- : Data
public: public:
/// What parts are selected /// What parts are selected?
set<SymbolPartP> selected_parts; set<SymbolPartP> selected_parts;
SymbolPartP single_selection; SymbolShapeP selected_shape; // if there is a single selection
/// Parent window /// Parent window
SymbolWindow* parent; SymbolWindow* parent;
......
...@@ -19,13 +19,15 @@ SymbolPartList::SymbolPartList(Window* parent, int id, SymbolP symbol) ...@@ -19,13 +19,15 @@ SymbolPartList::SymbolPartList(Window* parent, int id, SymbolP symbol)
{ {
// Create image list // Create image list
wxImageList* images = new wxImageList(16,16); wxImageList* images = new wxImageList(16,16);
// NOTE: this is based on the order of the SymbolPartCombine enum! // NOTE: this is based on the order of the SymbolShapeCombine and SymbolSymmetryType enums!
images->Add(load_resource_image(_("combine_or"))); images->Add(load_resource_image(_("combine_or")));
images->Add(load_resource_image(_("combine_sub"))); images->Add(load_resource_image(_("combine_sub")));
images->Add(load_resource_image(_("combine_and"))); images->Add(load_resource_image(_("combine_and")));
images->Add(load_resource_image(_("combine_xor"))); images->Add(load_resource_image(_("combine_xor")));
images->Add(load_resource_image(_("combine_over"))); images->Add(load_resource_image(_("combine_over")));
images->Add(load_resource_image(_("combine_border"))); images->Add(load_resource_image(_("combine_border")));
images->Add(load_resource_image(_("symmetry_rotation")));
images->Add(load_resource_image(_("symmetry_reflection")));
AssignImageList(images, wxIMAGE_LIST_SMALL); AssignImageList(images, wxIMAGE_LIST_SMALL);
// create columns // create columns
InsertColumn(0, _("Name")); InsertColumn(0, _("Name"));
...@@ -59,7 +61,7 @@ String SymbolPartList::OnGetItemText(long item, long col) const { ...@@ -59,7 +61,7 @@ String SymbolPartList::OnGetItemText(long item, long col) const {
return getPart(item)->name; return getPart(item)->name;
} }
int SymbolPartList::OnGetItemImage(long item) const { int SymbolPartList::OnGetItemImage(long item) const {
return getPart(item)->combine; return getPart(item)->icon();
} }
SymbolPartP SymbolPartList::getPart(long item) const { SymbolPartP SymbolPartList::getPart(long item) const {
...@@ -74,14 +76,12 @@ void SymbolPartList::selectItem(long item) { ...@@ -74,14 +76,12 @@ void SymbolPartList::selectItem(long item) {
} }
} }
void SymbolPartList::getselected_parts(set<SymbolPartP>& sel) { void SymbolPartList::getSelectedParts(set<SymbolPartP>& sel) {
sel.clear(); sel.clear();
long count = GetItemCount(); long count = GetItemCount();
for (long i = 0 ; i < count ; ++ i) { for (long i = 0 ; i < count ; ++ i) {
bool selected = GetItemState(i, wxLIST_STATE_SELECTED); bool selected = GetItemState(i, wxLIST_STATE_SELECTED);
if (selected) { if (selected) sel.insert(symbol->parts.at(i));
sel.insert(symbol->parts.at(i));
}
} }
} }
...@@ -94,7 +94,7 @@ void SymbolPartList::selectParts(const set<SymbolPartP>& sel) { ...@@ -94,7 +94,7 @@ void SymbolPartList::selectParts(const set<SymbolPartP>& sel) {
wxLIST_STATE_SELECTED); wxLIST_STATE_SELECTED);
} }
} }
void SymbolPartList::update() { void SymbolPartList::update() {
if (symbol->parts.empty()) { if (symbol->parts.empty()) {
// deleting all items requires a full refresh on win32 // deleting all items requires a full refresh on win32
......
...@@ -31,7 +31,7 @@ class SymbolPartList : public wxListCtrl, public SymbolView { ...@@ -31,7 +31,7 @@ class SymbolPartList : public wxListCtrl, public SymbolView {
inline SymbolPartP getSelection() const { return getPart(selected); } inline SymbolPartP getSelection() const { return getPart(selected); }
/// Get a set of selected parts /// Get a set of selected parts
void getselected_parts(set<SymbolPartP>& sel); void getSelectedParts(set<SymbolPartP>& sel);
/// Select the specified parts, and nothing else /// Select the specified parts, and nothing else
void selectParts(const set<SymbolPartP>& sel); void selectParts(const set<SymbolPartP>& sel);
......
...@@ -19,7 +19,7 @@ DECLARE_TYPEOF_COLLECTION(ControlPointP); ...@@ -19,7 +19,7 @@ DECLARE_TYPEOF_COLLECTION(ControlPointP);
// ----------------------------------------------------------------------------- : SymbolPointEditor // ----------------------------------------------------------------------------- : SymbolPointEditor
SymbolPointEditor::SymbolPointEditor(SymbolControl* control, const SymbolPartP& part) SymbolPointEditor::SymbolPointEditor(SymbolControl* control, const SymbolShapeP& part)
: SymbolEditorBase(control) : SymbolEditorBase(control)
, part(part) , part(part)
, selection(SELECTED_NONE) , selection(SELECTED_NONE)
...@@ -261,7 +261,7 @@ void SymbolPointEditor::onLeftDClick(const Vector2D& pos, wxMouseEvent& ev) { ...@@ -261,7 +261,7 @@ void SymbolPointEditor::onLeftDClick(const Vector2D& pos, wxMouseEvent& ev) {
// Delete point // Delete point
selected_points.clear(); selected_points.clear();
selectPoint(hover_handle.point, false); selectPoint(hover_handle.point, false);
getSymbol()->actions.add(controlPointRemoveAction(part, selected_points)); getSymbol()->actions.add(control_point_remove_action(part, selected_points));
selected_points.clear(); selected_points.clear();
selection = SELECTED_NONE; selection = SELECTED_NONE;
} }
...@@ -439,7 +439,7 @@ void SymbolPointEditor::resetActions() { ...@@ -439,7 +439,7 @@ void SymbolPointEditor::resetActions() {
void SymbolPointEditor::deleteSelection() { void SymbolPointEditor::deleteSelection() {
if (!selected_points.empty()) { if (!selected_points.empty()) {
getSymbol()->actions.add(controlPointRemoveAction(part, selected_points)); getSymbol()->actions.add(control_point_remove_action(part, selected_points));
selected_points.clear(); selected_points.clear();
resetActions(); resetActions();
control.Refresh(false); control.Refresh(false);
......
...@@ -22,7 +22,7 @@ class CurveDragAction; ...@@ -22,7 +22,7 @@ class CurveDragAction;
// Symbol editor for editing control points and handles // Symbol editor for editing control points and handles
class SymbolPointEditor : public SymbolEditorBase { class SymbolPointEditor : public SymbolEditorBase {
public: public:
SymbolPointEditor(SymbolControl* control, const SymbolPartP& part); SymbolPointEditor(SymbolControl* control, const SymbolShapeP& part);
// --------------------------------------------------- : Drawing // --------------------------------------------------- : Drawing
...@@ -81,7 +81,7 @@ class SymbolPointEditor : public SymbolEditorBase { ...@@ -81,7 +81,7 @@ class SymbolPointEditor : public SymbolEditorBase {
// --------------------------------------------------- : Data // --------------------------------------------------- : Data
// The symbol part we are editing // The symbol part we are editing
SymbolPartP part; SymbolShapeP part;
// Actions in progress // Actions in progress
// All are owned by the action stack, or they are 0 // All are owned by the action stack, or they are 0
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <util/window_id.hpp> #include <util/window_id.hpp>
#include <data/action/symbol.hpp> #include <data/action/symbol.hpp>
#include <data/settings.hpp> #include <data/settings.hpp>
#include <util/error.hpp>
#include <gfx/gfx.hpp> #include <gfx/gfx.hpp>
DECLARE_TYPEOF_COLLECTION(SymbolPartP); DECLARE_TYPEOF_COLLECTION(SymbolPartP);
...@@ -37,7 +38,9 @@ SymbolSelectEditor::SymbolSelectEditor(SymbolControl* control, bool rotate) ...@@ -37,7 +38,9 @@ SymbolSelectEditor::SymbolSelectEditor(SymbolControl* control, bool rotate)
handleCenter = wxBitmap(load_resource_image(_("handle_center"))); handleCenter = wxBitmap(load_resource_image(_("handle_center")));
// Make sure all parts have updated bounds // Make sure all parts have updated bounds
FOR_EACH(p, getSymbol()->parts) { FOR_EACH(p, getSymbol()->parts) {
p->calculateBounds(); if (SymbolShape* s = p->isSymbolShape()) {
s->calculateBounds();
}
} }
resetActions(); resetActions();
} }
...@@ -108,27 +111,27 @@ void SymbolSelectEditor::drawRotationCenter(DC& dc, const Vector2D& pos) { ...@@ -108,27 +111,27 @@ void SymbolSelectEditor::drawRotationCenter(DC& dc, const Vector2D& pos) {
void SymbolSelectEditor::initUI(wxToolBar* tb, wxMenuBar* mb) { void SymbolSelectEditor::initUI(wxToolBar* tb, wxMenuBar* mb) {
tb->AddSeparator(); tb->AddSeparator();
tb->AddTool(ID_PART_MERGE, _TOOL_("merge"), load_resource_image(_("combine_or")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("merge"), _HELP_("merge")); tb->AddTool(ID_SYMBOL_COMBINE_MERGE, _TOOL_("merge"), load_resource_image(_("combine_or")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("merge"), _HELP_("merge"));
tb->AddTool(ID_PART_SUBTRACT, _TOOL_("subtract"), load_resource_image(_("combine_sub_dark")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("subtract"), _HELP_("subtract")); tb->AddTool(ID_SYMBOL_COMBINE_SUBTRACT, _TOOL_("subtract"), load_resource_image(_("combine_sub_dark")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("subtract"), _HELP_("subtract"));
tb->AddTool(ID_PART_INTERSECTION, _TOOL_("intersect"), load_resource_image(_("combine_and_dark")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("intersect"), _HELP_("intersect")); tb->AddTool(ID_SYMBOL_COMBINE_INTERSECTION, _TOOL_("intersect"), load_resource_image(_("combine_and_dark")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("intersect"), _HELP_("intersect"));
tb->AddTool(ID_PART_DIFFERENCE, _TOOL_("difference"),load_resource_image(_("combine_xor")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("difference"), _HELP_("difference")); tb->AddTool(ID_SYMBOL_COMBINE_DIFFERENCE, _TOOL_("difference"), load_resource_image(_("combine_xor")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("difference"), _HELP_("difference"));
tb->AddTool(ID_PART_OVERLAP, _TOOL_("overlap"), load_resource_image(_("combine_over")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("overlap"), _HELP_("overlap")); tb->AddTool(ID_SYMBOL_COMBINE_OVERLAP, _TOOL_("overlap"), load_resource_image(_("combine_over")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("overlap"), _HELP_("overlap"));
tb->AddTool(ID_PART_BORDER, _TOOL_("border"), load_resource_image(_("combine_border")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("border"), _HELP_("border")); tb->AddTool(ID_SYMBOL_COMBINE_BORDER, _TOOL_("border"), load_resource_image(_("combine_border")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("border"), _HELP_("border"));
tb->Realize(); tb->Realize();
} }
void SymbolSelectEditor::destroyUI(wxToolBar* tb, wxMenuBar* mb) { void SymbolSelectEditor::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
tb->DeleteTool(ID_PART_MERGE); tb->DeleteTool(ID_SYMBOL_COMBINE_MERGE);
tb->DeleteTool(ID_PART_SUBTRACT); tb->DeleteTool(ID_SYMBOL_COMBINE_SUBTRACT);
tb->DeleteTool(ID_PART_INTERSECTION); tb->DeleteTool(ID_SYMBOL_COMBINE_INTERSECTION);
tb->DeleteTool(ID_PART_DIFFERENCE); tb->DeleteTool(ID_SYMBOL_COMBINE_DIFFERENCE);
tb->DeleteTool(ID_PART_OVERLAP); tb->DeleteTool(ID_SYMBOL_COMBINE_OVERLAP);
tb->DeleteTool(ID_PART_BORDER); tb->DeleteTool(ID_SYMBOL_COMBINE_BORDER);
// HACK: hardcoded size of rest of toolbar // HACK: hardcoded size of rest of toolbar
tb->DeleteToolByPos(7); // delete separator tb->DeleteToolByPos(7); // delete separator
} }
void SymbolSelectEditor::onUpdateUI(wxUpdateUIEvent& ev) { void SymbolSelectEditor::onUpdateUI(wxUpdateUIEvent& ev) {
if (ev.GetId() >= ID_PART && ev.GetId() < ID_PART_MAX) { if (ev.GetId() >= ID_SYMBOL_COMBINE && ev.GetId() < ID_SYMBOL_COMBINE_MAX) {
if (control.selected_parts.empty()) { if (control.selected_parts.empty()) {
ev.Check(false); ev.Check(false);
ev.Enable(false); ev.Enable(false);
...@@ -136,10 +139,12 @@ void SymbolSelectEditor::onUpdateUI(wxUpdateUIEvent& ev) { ...@@ -136,10 +139,12 @@ void SymbolSelectEditor::onUpdateUI(wxUpdateUIEvent& ev) {
ev.Enable(true); ev.Enable(true);
bool check = true; bool check = true;
FOR_EACH(p, control.selected_parts) { FOR_EACH(p, control.selected_parts) {
if (p->combine != ev.GetId() - ID_PART) { if (SymbolShape* s = p->isSymbolShape()) {
check = false; if (s->combine != ev.GetId() - ID_SYMBOL_COMBINE) {
break; check = false;
} break;
}
} // disable when symmetries are selected?
} }
ev.Check(check); ev.Check(check);
} }
...@@ -151,11 +156,11 @@ void SymbolSelectEditor::onUpdateUI(wxUpdateUIEvent& ev) { ...@@ -151,11 +156,11 @@ void SymbolSelectEditor::onUpdateUI(wxUpdateUIEvent& ev) {
} }
void SymbolSelectEditor::onCommand(int id) { void SymbolSelectEditor::onCommand(int id) {
if (id >= ID_PART && id < ID_PART_MAX) { if (id >= ID_SYMBOL_COMBINE && id < ID_SYMBOL_COMBINE_MAX) {
// change combine mode // change combine mode
getSymbol()->actions.add(new CombiningModeAction( getSymbol()->actions.add(new CombiningModeAction(
control.selected_parts, control.selected_parts,
static_cast<SymbolPartCombine>(id - ID_PART) static_cast<SymbolShapeCombine>(id - ID_SYMBOL_COMBINE)
)); ));
control.Refresh(false); control.Refresh(false);
} else if (id == ID_EDIT_DUPLICATE && !isEditing()) { } else if (id == ID_EDIT_DUPLICATE && !isEditing()) {
...@@ -427,7 +432,13 @@ double SymbolSelectEditor::angleTo(const Vector2D& pos) { ...@@ -427,7 +432,13 @@ double SymbolSelectEditor::angleTo(const Vector2D& pos) {
SymbolPartP SymbolSelectEditor::findPart(const Vector2D& pos) { SymbolPartP SymbolSelectEditor::findPart(const Vector2D& pos) {
FOR_EACH(p, getSymbol()->parts) { FOR_EACH(p, getSymbol()->parts) {
if (point_in_part(pos, *p)) return p; if (SymbolShape* s = p->isSymbolShape()) {
if (point_in_shape(pos, *s)) return p;
} else if (SymbolSymmetry* s = p->isSymbolSymmetry()) {
// TODO
} else {
throw InternalError(_("Invalid symbol part type"));
}
} }
return SymbolPartP(); return SymbolPartP();
} }
...@@ -437,8 +448,10 @@ void SymbolSelectEditor::updateBoundingBox() { ...@@ -437,8 +448,10 @@ void SymbolSelectEditor::updateBoundingBox() {
minV = Vector2D::infinity(); minV = Vector2D::infinity();
maxV = -Vector2D::infinity(); maxV = -Vector2D::infinity();
FOR_EACH(p, control.selected_parts) { FOR_EACH(p, control.selected_parts) {
minV = piecewise_min(minV, p->min_pos); if (SymbolShape* s = p->isSymbolShape()) {
maxV = piecewise_max(maxV, p->max_pos); minV = piecewise_min(minV, s->min_pos);
maxV = piecewise_max(maxV, s->max_pos);
}
} }
/* // Find rotation center /* // Find rotation center
center = Vector2D(0,0); center = Vector2D(0,0);
......
...@@ -249,7 +249,7 @@ void SymbolWindow::onUpdateUI(wxUpdateUIEvent& ev) { ...@@ -249,7 +249,7 @@ void SymbolWindow::onUpdateUI(wxUpdateUIEvent& ev) {
void SymbolWindow::onSelectFromList(wxListEvent& ev) { void SymbolWindow::onSelectFromList(wxListEvent& ev) {
if (inSelectionEvent) return ; if (inSelectionEvent) return ;
inSelectionEvent = true; inSelectionEvent = true;
parts->getselected_parts(control->selected_parts); parts->getSelectedParts(control->selected_parts);
control->onUpdateSelection(); control->onUpdateSelection();
inSelectionEvent = false; inSelectionEvent = false;
} }
......
...@@ -36,31 +36,32 @@ void SymbolValueEditor::draw(RotatedDC& dc) { ...@@ -36,31 +36,32 @@ void SymbolValueEditor::draw(RotatedDC& dc) {
} }
void SymbolValueEditor::drawButton(RotatedDC& dc, int button, const String& text) { void SymbolValueEditor::drawButton(RotatedDC& dc, int button, const String& text) {
bool down = button == button_down; bool down = button == button_down;
double size = style().height; double height = style().height;
double x = style().right - size - (size + 1) * button; double width = style().height + 2;
double x = style().right - width - (width + 1) * button;
double y = style().top; double y = style().top;
// draw button // draw button
dc.SetPen(*wxTRANSPARENT_PEN); dc.SetPen(*wxTRANSPARENT_PEN);
dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)); dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
dc.DrawRectangle(RealRect(x, y, size, size)); dc.DrawRectangle(RealRect(x, y, width, height));
dc.SetPen(wxSystemSettings::GetColour(down ? wxSYS_COLOUR_BTNSHADOW : wxSYS_COLOUR_BTNHIGHLIGHT)); dc.SetPen(wxSystemSettings::GetColour(down ? wxSYS_COLOUR_BTNSHADOW : wxSYS_COLOUR_BTNHIGHLIGHT));
dc.DrawLine(RealPoint(x,y),RealPoint(x+size,y)); dc.DrawLine(RealPoint(x,y),RealPoint(x+width,y));
dc.DrawLine(RealPoint(x,y),RealPoint(x,y+size)); dc.DrawLine(RealPoint(x,y),RealPoint(x,y+height));
dc.SetPen(wxSystemSettings::GetColour(down ? wxSYS_COLOUR_BTNHIGHLIGHT : wxSYS_COLOUR_BTNSHADOW)); dc.SetPen(wxSystemSettings::GetColour(down ? wxSYS_COLOUR_BTNHIGHLIGHT : wxSYS_COLOUR_BTNSHADOW));
dc.DrawLine(RealPoint(x+size-1,y),RealPoint(x+size-1,y+size)); dc.DrawLine(RealPoint(x+width-1,y),RealPoint(x+width-1,y+height));
dc.DrawLine(RealPoint(x,y+size-1),RealPoint(x+size,y+size-1)); dc.DrawLine(RealPoint(x,y+height-1),RealPoint(x+width,y+height-1));
// draw text // draw text
RealSize text_size = dc.GetTextExtent(text); RealSize text_size = dc.GetTextExtent(text);
dc.DrawText(text, align_in_rect((Alignment)(ALIGN_BOTTOM | ALIGN_CENTER), text_size, RealRect(x, y, size,size*0.9))); dc.DrawText(text, align_in_rect((Alignment)(ALIGN_BOTTOM | ALIGN_CENTER), text_size, RealRect(x, y, width,height*0.9)));
// draw image // draw image
const Bitmap& bmp = button_images[button]; const Bitmap& bmp = button_images[button];
RealSize image_size(bmp.GetWidth(), bmp.GetHeight()); RealSize image_size(bmp.GetWidth(), bmp.GetHeight());
dc.DrawBitmap(bmp, align_in_rect(ALIGN_MIDDLE_CENTER, image_size, RealRect(x,y,size,size * 0.8))); dc.DrawBitmap(bmp, align_in_rect(ALIGN_MIDDLE_CENTER, image_size, RealRect(x,y,width,height * 0.8)));
} }
int SymbolValueEditor::findButton(const RealPoint& pos) { int SymbolValueEditor::findButton(const RealPoint& pos) {
if (pos.y < style().top || pos.y >= style().bottom) return -1; if (pos.y < style().top || pos.y >= style().bottom) return -1;
int button = (int)floor( (style().right - pos.x) / (style().height + 1) ); int button = (int)floor( (style().right - pos.x) / (style().height + 3) );
if (button >= 0 && button <= 1) return button; if (button >= 0 && button <= 1) return button;
return -1; return -1;
} }
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
// ----------------------------------------------------------------------------- : Includes // ----------------------------------------------------------------------------- : Includes
#include <render/symbol/viewer.hpp> #include <render/symbol/viewer.hpp>
#include <util/error.hpp> // clearDC_black
#include <gui/util.hpp> // clearDC_black #include <gui/util.hpp> // clearDC_black
DECLARE_TYPEOF_COLLECTION(SymbolPartP); DECLARE_TYPEOF_COLLECTION(SymbolPartP);
...@@ -64,41 +65,49 @@ void SymbolViewer::draw(DC& dc) { ...@@ -64,41 +65,49 @@ void SymbolViewer::draw(DC& dc) {
// Check if we can paint directly to the dc // Check if we can paint directly to the dc
// This will fail if there are parts with combine == intersection // This will fail if there are parts with combine == intersection
FOR_EACH(p, symbol->parts) { FOR_EACH(p, symbol->parts) {
if (p->combine == PART_INTERSECTION) { if (SymbolShape* s = p->isSymbolShape()) {
paintedSomething = true; if (s->combine == SYMBOL_COMBINE_INTERSECTION) {
break; paintedSomething = true;
break;
}
} }
} }
// Draw all parts, in reverse order (bottom to top) // Draw all parts, in reverse order (bottom to top)
FOR_EACH_REVERSE(p, symbol->parts) { FOR_EACH_REVERSE(p, symbol->parts) {
const SymbolPart& part = *p; if (SymbolShape* s = p->isSymbolShape()) {
if (part.combine == PART_OVERLAP && buffersFilled) { if (s->combine == SYMBOL_COMBINE_OVERLAP && buffersFilled) {
// We will be overlapping some previous parts, write them to the screen // We will be overlapping some previous parts, write them to the screen
combineBuffers(dc, borderDC.get(), interiorDC.get()); combineBuffers(dc, borderDC.get(), interiorDC.get());
// Clear the buffers // Clear the buffers
buffersFilled = false; buffersFilled = false;
paintedSomething = true; paintedSomething = true;
wxSize s = dc.GetSize(); wxSize s = dc.GetSize();
if (borderDC) { if (borderDC) {
borderDC->SetBrush(*wxBLACK_BRUSH); borderDC->SetBrush(*wxBLACK_BRUSH);
borderDC->SetPen( *wxTRANSPARENT_PEN); borderDC->SetPen( *wxTRANSPARENT_PEN);
borderDC->DrawRectangle(0, 0, s.GetWidth(), s.GetHeight()); borderDC->DrawRectangle(0, 0, s.GetWidth(), s.GetHeight());
}
interiorDC->SetBrush(*wxBLACK_BRUSH);
interiorDC->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 (!paintedSomething) { if (!interiorDC) interiorDC = getTempDC(dc);
// No need to buffer combineSymbolShape(*s, dc, *interiorDC, true, false);
if (!interiorDC) interiorDC = getTempDC(dc); buffersFilled = true;
combineSymbolPart(part, dc, *interiorDC, true, false); } else {
buffersFilled = true; 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 { } else {
if (!borderDC) borderDC = getTempDC(dc); // symmetry, already handled above
if (!interiorDC) interiorDC = getTempDC(dc);
// Draw this part to the buffer
combineSymbolPart(part, *borderDC, *interiorDC, false, false);
buffersFilled = true;
} }
} }
...@@ -109,11 +118,20 @@ void SymbolViewer::draw(DC& dc) { ...@@ -109,11 +118,20 @@ void SymbolViewer::draw(DC& dc) {
} }
void SymbolViewer::highlightPart(DC& dc, const SymbolPart& part, HighlightStyle style) { 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 {
throw InternalError(_("Invalid symbol part type"));
}
}
void SymbolViewer::highlightPart(DC& dc, const SymbolShape& shape, HighlightStyle style) {
// create point list // create point list
vector<wxPoint> points; vector<wxPoint> points;
size_t size = part.points.size(); size_t size = shape.points.size();
for(size_t i = 0 ; i < size ; ++i) { for(size_t i = 0 ; i < size ; ++i) {
segment_subdivide(*part.getPoint((int)i), *part.getPoint((int)i+1), rotation, points); segment_subdivide(*shape.getPoint((int)i), *shape.getPoint((int)i+1), rotation, points);
} }
// draw // draw
if (style == HIGHLIGHT_BORDER) { if (style == HIGHLIGHT_BORDER) {
...@@ -125,7 +143,7 @@ void SymbolViewer::highlightPart(DC& dc, const SymbolPart& part, HighlightStyle ...@@ -125,7 +143,7 @@ void SymbolViewer::highlightPart(DC& dc, const SymbolPart& part, HighlightStyle
dc.SetBrush(Color(0,0,64)); dc.SetBrush(Color(0,0,64));
dc.SetPen (*wxTRANSPARENT_PEN); dc.SetPen (*wxTRANSPARENT_PEN);
dc.DrawPolygon((int)points.size(), &points[0]); dc.DrawPolygon((int)points.size(), &points[0]);
if (part.combine == PART_SUBTRACT || part.combine == PART_BORDER) { if (shape.combine == SYMBOL_COMBINE_SUBTRACT || shape.combine == SYMBOL_COMBINE_BORDER) {
dc.SetLogicalFunction(wxAND); dc.SetLogicalFunction(wxAND);
dc.SetBrush(Color(191,191,255)); dc.SetBrush(Color(191,191,255));
dc.DrawPolygon((int)points.size(), &points[0]); dc.DrawPolygon((int)points.size(), &points[0]);
...@@ -133,51 +151,54 @@ void SymbolViewer::highlightPart(DC& dc, const SymbolPart& part, HighlightStyle ...@@ -133,51 +151,54 @@ void SymbolViewer::highlightPart(DC& dc, const SymbolPart& part, HighlightStyle
dc.SetLogicalFunction(wxCOPY); dc.SetLogicalFunction(wxCOPY);
} }
} }
void SymbolViewer::highlightPart(DC& dc, const SymbolSymmetry& sym) {
// TODO
}
void SymbolViewer::combineSymbolPart(const SymbolPart& part, DC& border, DC& interior, bool directB, bool directI) { void SymbolViewer::combineSymbolShape(const SymbolShape& shape, DC& border, DC& interior, bool directB, bool directI) {
// what color should the interior be? // what color should the interior be?
// use black when drawing to the screen // use black when drawing to the screen
Byte interiorCol = directI ? 0 : 255; Byte interiorCol = directI ? 0 : 255;
// how to draw depends on combining mode // how to draw depends on combining mode
switch(part.combine) { switch(shape.combine) {
case PART_OVERLAP: case SYMBOL_COMBINE_OVERLAP:
case PART_MERGE: { case SYMBOL_COMBINE_MERGE: {
drawSymbolPart(part, &border, &interior, 255, interiorCol, directB, false); drawSymbolShape(shape, &border, &interior, 255, interiorCol, directB, false);
break; break;
} case PART_SUBTRACT: { } case SYMBOL_COMBINE_SUBTRACT: {
border.SetLogicalFunction(wxAND); border.SetLogicalFunction(wxAND);
drawSymbolPart(part, &border, &interior, 0, ~interiorCol, directB, false); drawSymbolShape(shape, &border, &interior, 0, ~interiorCol, directB, false);
border.SetLogicalFunction(wxCOPY); border.SetLogicalFunction(wxCOPY);
break; break;
} case PART_INTERSECTION: { } case SYMBOL_COMBINE_INTERSECTION: {
MemoryDCP keepBorder = getTempDC(border); MemoryDCP keepBorder = getTempDC(border);
MemoryDCP keepInterior = getTempDC(interior); MemoryDCP keepInterior = getTempDC(interior);
drawSymbolPart(part, keepBorder.get(), keepInterior.get(), 255, 255, false, false); drawSymbolShape(shape, keepBorder.get(), keepInterior.get(), 255, 255, false, false);
// combine the temporary dcs with the result using the AND operator // combine the temporary dcs with the result using the AND operator
wxSize s = border.GetSize(); wxSize s = border.GetSize();
border .Blit(0, 0, s.GetWidth(), s.GetHeight(), &*keepBorder , 0, 0, wxAND); border .Blit(0, 0, s.GetWidth(), s.GetHeight(), &*keepBorder , 0, 0, wxAND);
interior.Blit(0, 0, s.GetWidth(), s.GetHeight(), &*keepInterior, 0, 0, wxAND); interior.Blit(0, 0, s.GetWidth(), s.GetHeight(), &*keepInterior, 0, 0, wxAND);
break; break;
} case PART_DIFFERENCE: { } case SYMBOL_COMBINE_DIFFERENCE: {
interior.SetLogicalFunction(wxXOR); interior.SetLogicalFunction(wxXOR);
drawSymbolPart(part, &border, &interior, 0, ~interiorCol, directB, true); drawSymbolShape(shape, &border, &interior, 0, ~interiorCol, directB, true);
interior.SetLogicalFunction(wxCOPY); interior.SetLogicalFunction(wxCOPY);
break; break;
} case PART_BORDER: { } case SYMBOL_COMBINE_BORDER: {
// draw border as interior // draw border as interior
drawSymbolPart(part, nullptr, &border, 0, 255, false, false); drawSymbolShape(shape, nullptr, &border, 0, 255, false, false);
break; break;
} }
} }
} }
void SymbolViewer::drawSymbolPart(const SymbolPart& part, DC* border, DC* interior, Byte borderCol, Byte interiorCol, bool directB, bool clear) { void SymbolViewer::drawSymbolShape(const SymbolShape& shape, DC* border, DC* interior, Byte borderCol, Byte interiorCol, bool directB, bool clear) {
// create point list // create point list
vector<wxPoint> points; vector<wxPoint> points;
size_t size = part.points.size(); size_t size = shape.points.size();
for(size_t i = 0 ; i < size ; ++i) { for(size_t i = 0 ; i < size ; ++i) {
segment_subdivide(*part.getPoint((int)i), *part.getPoint((int)i+1), rotation, points); segment_subdivide(*shape.getPoint((int)i), *shape.getPoint((int)i+1), rotation, points);
} }
// draw border // draw border
if (border && border_radius > 0) { if (border && border_radius > 0) {
......
...@@ -45,6 +45,8 @@ class SymbolViewer : public SymbolView { ...@@ -45,6 +45,8 @@ class SymbolViewer : public SymbolView {
void draw(DC& dc); void draw(DC& dc);
void highlightPart(DC& dc, const SymbolPart& part, HighlightStyle style); void highlightPart(DC& dc, const SymbolPart& part, HighlightStyle style);
void highlightPart(DC& dc, const SymbolShape& shap, HighlightStyle style);
void highlightPart(DC& dc, const SymbolSymmetry& sym);
void onAction(const Action&, bool) {} void onAction(const Action&, bool) {}
...@@ -53,14 +55,14 @@ class SymbolViewer : public SymbolView { ...@@ -53,14 +55,14 @@ class SymbolViewer : public SymbolView {
/** directB/directI are true if the border/interior is the screen dc, false if it /** directB/directI are true if the border/interior is the screen dc, false if it
* is a temporary 1 bit one * is a temporary 1 bit one
*/ */
void combineSymbolPart(const SymbolPart& part, DC& border, DC& interior, bool directB, bool directI); void combineSymbolShape(const SymbolShape& part, DC& border, DC& interior, bool directB, bool directI);
/// Draw a symbol part, draws the border and the interior to separate DCs /// Draw a symbol part, draws the border and the interior to separate DCs
/** The DCs may be null. directB should be true when drawing the border directly to the screen. /** The DCs may be null. directB should be true when drawing the border directly to the screen.
* The **Col parameters give the color to use for the (interior of) the border and the interior * The **Col parameters give the color to use for the (interior of) the border and the interior
* default should be white (255) border and black (0) interior. * default should be white (255) border and black (0) interior.
*/ */
void drawSymbolPart(const SymbolPart& part, DC* border, DC* interior, unsigned char borderCol, unsigned char interiorCol, bool directB, bool oppB); void drawSymbolShape(const SymbolShape& shape, DC* border, DC* interior, unsigned char borderCol, unsigned char interiorCol, bool directB, bool oppB);
/* /*
// ------------------- Bezier curve calculation // ------------------- Bezier curve calculation
......
...@@ -100,6 +100,8 @@ combine_and_dark IMAGE "../common/combine_and_dark.png" ...@@ -100,6 +100,8 @@ combine_and_dark IMAGE "../common/combine_and_dark.png"
combine_xor IMAGE "../common/combine_xor.png" combine_xor IMAGE "../common/combine_xor.png"
combine_over IMAGE "../common/combine_over.png" combine_over IMAGE "../common/combine_over.png"
combine_border IMAGE "../common/combine_border.png" combine_border IMAGE "../common/combine_border.png"
symmetry_rotation IMAGE "../common/symmetry_rotation.png"
symmetry_reflection IMAGE "../common/symmetry_reflection.png"
handle_rotate IMAGE "../common/handle_rotate.png" handle_rotate IMAGE "../common/handle_rotate.png"
handle_shear_x IMAGE "../common/handle_shear_x.png" handle_shear_x IMAGE "../common/handle_shear_x.png"
......
src/resource/msw/tool/window_keywords.png

657 Bytes | W: | H:

src/resource/msw/tool/window_keywords.png

551 Bytes | W: | H:

src/resource/msw/tool/window_keywords.png
src/resource/msw/tool/window_keywords.png
src/resource/msw/tool/window_keywords.png
src/resource/msw/tool/window_keywords.png
  • 2-up
  • Swipe
  • Onion skin
src/resource/msw/tool/window_set_info.png

354 Bytes | W: | H:

src/resource/msw/tool/window_set_info.png

520 Bytes | W: | H:

src/resource/msw/tool/window_set_info.png
src/resource/msw/tool/window_set_info.png
src/resource/msw/tool/window_set_info.png
src/resource/msw/tool/window_set_info.png
  • 2-up
  • Swipe
  • Onion skin
src/resource/msw/tool/window_style.png

568 Bytes | W: | H:

src/resource/msw/tool/window_style.png

380 Bytes | W: | H:

src/resource/msw/tool/window_style.png
src/resource/msw/tool/window_style.png
src/resource/msw/tool/window_style.png
src/resource/msw/tool/window_style.png
  • 2-up
  • Swipe
  • Onion skin
...@@ -117,14 +117,14 @@ enum ChildMenuID { ...@@ -117,14 +117,14 @@ enum ChildMenuID {
, ID_INSERT_SYMBOL , ID_INSERT_SYMBOL
// SymbolSelectEditor toolbar/menu // SymbolSelectEditor toolbar/menu
, ID_PART = 2001 , ID_SYMBOL_COMBINE = 2001
, ID_PART_MERGE = ID_PART + 0//PART_MERGE , ID_SYMBOL_COMBINE_MERGE = ID_SYMBOL_COMBINE + 0 //SYMBOL_COMBINE_MERGE
, ID_PART_SUBTRACT = ID_PART + 1//PART_SUBTRACT , ID_SYMBOL_COMBINE_SUBTRACT = ID_SYMBOL_COMBINE + 1 //SYMBOL_COMBINE_SUBTRACT
, ID_PART_INTERSECTION = ID_PART + 2//PART_INTERSECTION , ID_SYMBOL_COMBINE_INTERSECTION = ID_SYMBOL_COMBINE + 2 //SYMBOL_COMBINE_INTERSECTION
, ID_PART_DIFFERENCE = ID_PART + 3//PART_DIFFERENCE , ID_SYMBOL_COMBINE_DIFFERENCE = ID_SYMBOL_COMBINE + 3 //SYMBOL_COMBINE_DIFFERENCE
, ID_PART_OVERLAP = ID_PART + 4//PART_OVERLAP , ID_SYMBOL_COMBINE_OVERLAP = ID_SYMBOL_COMBINE + 4 //SYMBOL_COMBINE_OVERLAP
, ID_PART_BORDER = ID_PART + 5//PART_BORDER , ID_SYMBOL_COMBINE_BORDER = ID_SYMBOL_COMBINE + 5 //SYMBOL_COMBINE_BORDER
, ID_PART_MAX , ID_SYMBOL_COMBINE_MAX
, ID_EDIT_DUPLICATE // duplicating symbol parts , ID_EDIT_DUPLICATE // duplicating symbol parts
, ID_VIEW_GRID , ID_VIEW_GRID
, ID_VIEW_GRID_SNAP , ID_VIEW_GRID_SNAP
......
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