Rotation and reflection should now work correctly;

Finished the symmetry editor

git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@538 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
twanvl
2007-07-10 02:47:27 +00:00
parent e678f834fc
commit 1a01ac55f2
23 changed files with 476 additions and 195 deletions
+23 -2
View File
@@ -23,7 +23,7 @@
SymbolControl::SymbolControl(SymbolWindow* parent, int id, const SymbolP& symbol)
: wxControl(parent, id)
, SymbolViewer(symbol)
, SymbolViewer(symbol, true)
, parent(parent)
{
onChangeSymbol();
@@ -66,7 +66,7 @@ void SymbolControl::onModeChange(wxCommandEvent& ev) {
switchEditor(new_intrusive1<SymbolBasicShapeEditor>(this));
break;
case ID_MODE_SYMMETRY:
switchEditor(new_intrusive1<SymbolSymmetryEditor>(this));
switchEditor(new_intrusive2<SymbolSymmetryEditor>(this, selected_parts.getASymmetry()));
break;
}
}
@@ -113,6 +113,24 @@ void SymbolControl::onUpdateSelection() {
Refresh(false);
}
break;
} case ID_MODE_SYMMETRY: {
// can only select a single part!
SymbolSymmetryP symmetry = selected_parts.getASymmetry();
if (!symmetry) {
if (selected_symmetry && selected_parts.select(selected_symmetry)) {
signalSelectionChange();
}
break;
}
if (symmetry != selected_symmetry) {
if (symmetry && selected_parts.select(symmetry)) {
signalSelectionChange();
}
// begin editing another part
selected_symmetry = symmetry;
Refresh(false);
}
break;
} case ID_MODE_SHAPES:
if (!selected_parts.empty()) {
// there can't be a selection
@@ -136,6 +154,9 @@ void SymbolControl::activatePart(const SymbolPartP& part) {
if (part->isSymbolShape()) {
selected_parts.select(part);
switchEditor(new_intrusive2<SymbolPointEditor>(this, static_pointer_cast<SymbolShape>(part)));
} else if (part->isSymbolSymmetry()) {
selected_parts.select(part);
switchEditor(new_intrusive2<SymbolSymmetryEditor>(this, static_pointer_cast<SymbolSymmetry>(part)));
}
}
+3 -2
View File
@@ -73,8 +73,9 @@ class SymbolControl : public wxControl, public SymbolViewer {
public:
/// What parts are selected?
SymbolPartsSelection selected_parts;
SymbolPartP highlight_part; ///< part the mouse cursor is over
SymbolShapeP selected_shape; ///< if there is a single selection
SymbolPartP highlight_part; ///< part the mouse cursor is over
SymbolShapeP selected_shape; ///< if there is a single selection
SymbolSymmetryP selected_symmetry; ///< if there is a single selection
/// Parent window
SymbolWindow* parent;
+3 -3
View File
@@ -486,13 +486,13 @@ const Image& SymbolPartList::itemPreview(int i, const SymbolPartP& part) {
if (s->combine == SYMBOL_COMBINE_SUBTRACT) {
// temporarily render using subtract instead, otherwise we don't see anything
s->combine = SYMBOL_COMBINE_BORDER;
img = render_symbol(sym, filter, 0.08, ITEM_HEIGHT * 4);
img = render_symbol(sym, filter, 0.08, ITEM_HEIGHT * 4, true);
s->combine = SYMBOL_COMBINE_SUBTRACT;
} else {
img = render_symbol(sym, filter, 0.08, ITEM_HEIGHT * 4);
img = render_symbol(sym, filter, 0.08, ITEM_HEIGHT * 4, true);
}
} else {
img = render_symbol(sym, filter, 0.08, ITEM_HEIGHT * 4);
img = render_symbol(sym, filter, 0.08, ITEM_HEIGHT * 4, true);
}
resample(img, p.image);
p.up_to_date = true;
+14 -7
View File
@@ -55,13 +55,6 @@ bool SymbolPartsSelection::select(const SymbolPartP& part, SelectMode mode) {
return true;
}
SymbolShapeP SymbolPartsSelection::getAShape() const {
FOR_EACH(s, selection) {
if (s->isSymbolShape()) return static_pointer_cast<SymbolShape>(s);
}
return SymbolShapeP();
}
void SymbolPartsSelection::clearChildren(SymbolPart* part) {
if (SymbolGroup* g = part->isSymbolGroup()) {
FOR_EACH(p, g->parts) {
@@ -71,6 +64,20 @@ void SymbolPartsSelection::clearChildren(SymbolPart* part) {
}
}
SymbolShapeP SymbolPartsSelection::getAShape() const {
FOR_EACH(s, selection) {
if (s->isSymbolShape()) return static_pointer_cast<SymbolShape>(s);
}
return SymbolShapeP();
}
SymbolSymmetryP SymbolPartsSelection::getASymmetry() const {
FOR_EACH(s, selection) {
if (s->isSymbolSymmetry()) return static_pointer_cast<SymbolSymmetry>(s);
}
return SymbolSymmetryP();
}
// ----------------------------------------------------------------------------- : Position based
+8
View File
@@ -15,6 +15,7 @@ class Vector2D;
DECLARE_POINTER_TYPE(Symbol);
DECLARE_POINTER_TYPE(SymbolPart);
DECLARE_POINTER_TYPE(SymbolShape);
DECLARE_POINTER_TYPE(SymbolSymmetry);
class SymbolGroup;
// ----------------------------------------------------------------------------- : Selection
@@ -61,6 +62,13 @@ class SymbolPartsSelection {
/// Get any SymbolShape if there is one selected
SymbolShapeP getAShape() const;
/// Get any SymbolSymmetry if there is one selected
SymbolSymmetryP getASymmetry() const;
/// Get the only selected thing
inline SymbolPartP getOnlyOne() const {
assert(selection.size() == 1);
return *selection.begin();
}
private:
Symbol* root;
+101 -62
View File
@@ -16,11 +16,13 @@
// ----------------------------------------------------------------------------- : SymbolSymmetryEditor
SymbolSymmetryEditor::SymbolSymmetryEditor(SymbolControl* control)
SymbolSymmetryEditor::SymbolSymmetryEditor(SymbolControl* control, const SymbolSymmetryP& sym)
: SymbolEditorBase(control)
, mode(ID_SYMMETRY_ROTATION)
, drawing(false)
, symmetry(control->selected_symmetry)
, symmetryMoveAction(nullptr)
{
symmetry = sym;
control->selected_symmetry = symmetry;
control->SetCursor(*wxCROSS_CURSOR);
}
@@ -28,7 +30,23 @@ SymbolSymmetryEditor::SymbolSymmetryEditor(SymbolControl* control)
void SymbolSymmetryEditor::draw(DC& dc) {
if (symmetry) {
control.highlightPart(dc, *symmetry);
control.highlightPart(dc, *symmetry, HIGHLIGHT_BORDER);
Color color(255,100,0);
Vector2D center = control.rotation.tr(symmetry->center);
Vector2D handle = control.rotation.tr(symmetry->center + symmetry->handle);
if (symmetry->kind == SYMMETRY_REFLECTION) {
// draw line to handle
dc.SetPen(wxPen(color,1,wxDOT));
dc.DrawLine(center.x, center.y, handle.x, handle.y);
// draw handle
dc.SetPen(*wxBLACK_PEN);
dc.SetBrush(color);
dc.DrawCircle(handle.x, handle.y, hovered == SELECTION_HANDLE ? 7 : 4);
}
// draw center
dc.SetPen(*wxBLACK_PEN);
dc.SetBrush(color);
dc.DrawCircle(center.x, center.y, hovered == SELECTION_CENTER ? 8 : 5);
}
}
@@ -39,29 +57,41 @@ void SymbolSymmetryEditor::initUI(wxToolBar* tb, wxMenuBar* mb) {
copies->SetHelpText(_HELP_("copies"));
copies->SetSize(50, -1);
tb->AddSeparator();
tb->AddTool(ID_ADD_SYMMETRY, _TOOL_("add symmetry"), load_resource_tool_image(_("symmetry_add")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("add symmetry"), _HELP_("add symmetry"));
tb->AddSeparator();
tb->AddTool(ID_SYMMETRY_ROTATION, _TOOL_("rotation"), load_resource_image(_("symmetry_rotation")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("rotation"), _HELP_("rotation"));
tb->AddTool(ID_SYMMETRY_REFLECTION, _TOOL_("reflection"), load_resource_image(_("symmetry_reflection")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("reflection"), _HELP_("reflection"));
tb->AddSeparator();
tb->AddControl(copies);
tb->Realize();
control.SetCursor(*wxCROSS_CURSOR);
stopActions(); // set status text
resetActions(); // set status text
}
void SymbolSymmetryEditor::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
tb->DeleteTool(ID_SYMMETRY_REFLECTION);
tb->DeleteTool(ID_SYMMETRY_ROTATION);
tb->DeleteTool(ID_ADD_SYMMETRY);
// HACK: hardcoded size of rest of toolbar
tb->DeleteToolByPos(7); // delete separator
tb->DeleteTool(ID_COPIES); // delete sides
tb->DeleteToolByPos(7); // delete separator
tb->DeleteToolByPos(7); // delete separator
tb->DeleteTool(ID_COPIES); // delete copies
#if wxVERSION_NUMBER < 2600
delete sides;
delete copies;
#endif
}
void SymbolSymmetryEditor::onUpdateUI(wxUpdateUIEvent& ev) {
if (ev.GetId() >= ID_SYMMETRY && ev.GetId() < ID_SYMMETRY_MAX) {
ev.Check(ev.GetId() == mode);
ev.Enable(symmetry);
ev.Check(symmetry && symmetry->kind == ev.GetId() - ID_SYMMETRY);
} else if (ev.GetId() == ID_COPIES) {
ev.Enable(symmetry);
if (symmetry) {
copies->SetValue(symmetry->copies);
}
} else if (ev.GetId() == ID_ADD_SYMMETRY) {
ev.Enable(true);
} else {
ev.Enable(false); // we don't know about this item
@@ -70,8 +100,28 @@ void SymbolSymmetryEditor::onUpdateUI(wxUpdateUIEvent& ev) {
void SymbolSymmetryEditor::onCommand(int id) {
if (id >= ID_SYMMETRY && id < ID_SYMMETRY_MAX) {
mode = id;
stopActions();
SymbolSymmetryType kind = id == ID_SYMMETRY_ROTATION ? SYMMETRY_ROTATION : SYMMETRY_REFLECTION;
if (symmetry && symmetry->kind != kind) {
getSymbol()->actions.add(new SymmetryTypeAction(*symmetry, kind));
control.Refresh(false);
}
resetActions();
} else if (id == ID_COPIES) {
if (symmetry && symmetry->copies != copies->GetValue()) {
getSymbol()->actions.add(new SymmetryCopiesAction(*symmetry, copies->GetValue()));
control.Refresh(false);
}
resetActions();
} else if (id == ID_ADD_SYMMETRY) {
symmetry = new_intrusive<SymbolSymmetry>();
symmetry->kind = SYMMETRY_ROTATION;
symmetry->copies = 2;
symmetry->center = Vector2D(0.5,0.5);
symmetry->handle = Vector2D(0.2,0);
symmetry->name = symmetry->expectedName();
getSymbol()->actions.add(new GroupSymbolPartsAction(*getSymbol(), control.selected_parts.get(), symmetry));
control.selected_parts.select(symmetry);
control.Refresh(false);
}
}
@@ -80,81 +130,70 @@ int SymbolSymmetryEditor::modeToolId() { return ID_MODE_SYMMETRY; }
// ----------------------------------------------------------------------------- : Mouse events
void SymbolSymmetryEditor::onLeftDown (const Vector2D& pos, wxMouseEvent& ev) {
// Start drawing
drawing = true;
center = handle = pos;
SetStatusText(_HELP_("drag to draw symmetry"));
if (!symmetry) return;
selection = findSelection(pos);
}
void SymbolSymmetryEditor::onLeftUp (const Vector2D& pos, wxMouseEvent& ev) {
if (drawing && symmetry) {
// Finalize the symmetry
getSymbol()->actions.add(new AddSymbolPartAction(*getSymbol(), symmetry));
// Select the part
control.selectPart(symmetry);
// No need to clean up, this editor gets destroyed
//stopActions();
if (!symmetry) return;
if (isEditing()) {
resetActions();
}
}
void SymbolSymmetryEditor::onMouseDrag (const Vector2D& from, const Vector2D& to, wxMouseEvent& ev) {
if (!symmetry) return;
// Resize the object
if (drawing) {
handle = to;
makePart(center, handle, ev.ControlDown(), settings.symbol_grid_snap != ev.ShiftDown());
control.Refresh(false);
if (selection == SELECTION_NONE) return;
if (!symmetryMoveAction) {
symmetryMoveAction = new SymmetryMoveAction(*symmetry, selection == SELECTION_HANDLE);
symmetryMoveAction->constrain = ev.ControlDown();
symmetryMoveAction->snap = ev.ShiftDown() != settings.symbol_grid_snap ? settings.symbol_grid_size : 0;
getSymbol()->actions.add(symmetryMoveAction);
}
symmetryMoveAction->move(to - from);
control.Refresh(false);
}
void SymbolSymmetryEditor::onMouseMove (const Vector2D& from, const Vector2D& to, wxMouseEvent& ev) {
Selection old_hovered = hovered;
hovered = findSelection(to);
if (hovered != old_hovered) control.Refresh(false);
// TODO: set status text
}
SymbolSymmetryEditor::Selection SymbolSymmetryEditor::findSelection(const Vector2D& pos) {
if (!symmetry) return SELECTION_NONE;
Vector2D pos_pixel = control.rotation.tr(pos);
Vector2D center = control.rotation.tr(symmetry->center);
if ((center - pos_pixel).lengthSqr() < 5*5) return SELECTION_CENTER;
if (symmetry->kind == SYMMETRY_REFLECTION) {
Vector2D handle = control.rotation.tr(symmetry->center + symmetry->handle);
if ((handle - pos_pixel).lengthSqr() < 5*5) return SELECTION_HANDLE;
}
return SELECTION_NONE;
}
// ----------------------------------------------------------------------------- : Other events
void SymbolSymmetryEditor::onKeyChange(wxKeyEvent& ev) {
if (drawing) {
if (symmetryMoveAction) {
if (ev.GetKeyCode() == WXK_CONTROL || ev.GetKeyCode() == WXK_SHIFT) {
// changed constrains
makePart(center, handle, ev.ControlDown(), settings.symbol_grid_snap != ev.ShiftDown());
symmetryMoveAction->constrain = ev.ControlDown();
symmetryMoveAction->snap = ev.ShiftDown() != settings.symbol_grid_snap ? settings.symbol_grid_size : 0;
control.Refresh(false);
} else if (ev.GetKeyCode() == WXK_ESCAPE) {
// cancel drawing
stopActions();
resetActions();
}
}
}
bool SymbolSymmetryEditor::isEditing() { return drawing; }
// ----------------------------------------------------------------------------- : Generating shapes
void SymbolSymmetryEditor::stopActions() {
symmetry = SymbolSymmetryP();
drawing = false;
SetStatusText(_HELP_("draw symmetry"));
control.Refresh(false);
bool SymbolSymmetryEditor::isEditing() {
return symmetryMoveAction;
}
void SymbolSymmetryEditor::makePart(Vector2D a, Vector2D b, bool constrained, bool snap) {
// snap
if (snap) {
a = snap_vector(a, settings.symbol_grid_size);
b = snap_vector(b, settings.symbol_grid_size);
}
// constrain
Vector2D dir = b - a;
if (constrained) {
double angle = atan2(dir.y, dir.x);
// multiples of 2pi/24 i.e. 24 stops
double mult = (2 * M_PI) / 24;
angle = floor(angle / mult + 0.5) * mult;
dir = Vector2D(cos(angle), sin(angle)) * dir.length();
}
// make part
if (!symmetry) {
symmetry = new_intrusive<SymbolSymmetry>();
}
symmetry->kind = mode == ID_SYMMETRY_ROTATION ? SYMMETRY_ROTATION : SYMMETRY_REFLECTION;
symmetry->copies = copies->GetValue();
symmetry->center = a;
symmetry->handle = dir;
symmetry->name = capitalize(mode == ID_SYMMETRY_ROTATION ? _TYPE_("rotation") : _TYPE_("reflection"))
+ String::Format(_(" (%d)"), symmetry->copies);
void SymbolSymmetryEditor::resetActions() {
symmetryMoveAction = nullptr;
}
+17 -10
View File
@@ -12,14 +12,15 @@
#include <util/prec.hpp>
#include <gui/symbol/editor.hpp>
class SymmetryMoveAction;
// ----------------------------------------------------------------------------- : SymbolSymmetryEditor
/// Editor for adding symmetries
class SymbolSymmetryEditor : public SymbolEditorBase {
public:
/** The symmetry parameter is optional, if it is not set, then only new ones can be created */
//%SymbolSymmetryEditor(SymbolControl* control, SymbolSymmetryP symmetry);
SymbolSymmetryEditor(SymbolControl* control);
SymbolSymmetryEditor(SymbolControl* control, const SymbolSymmetryP& symmetry);
// --------------------------------------------------- : Drawing
@@ -37,6 +38,7 @@ class SymbolSymmetryEditor : public SymbolEditorBase {
virtual void onLeftDown (const Vector2D& pos, wxMouseEvent& ev);
virtual void onLeftUp (const Vector2D& pos, wxMouseEvent& ev);
virtual void onMouseMove (const Vector2D& from, const Vector2D& to, wxMouseEvent& ev);
virtual void onMouseDrag (const Vector2D& from, const Vector2D& to, wxMouseEvent& ev);
// --------------------------------------------------- : Other events
@@ -47,18 +49,23 @@ class SymbolSymmetryEditor : public SymbolEditorBase {
// --------------------------------------------------- : Data
private:
int mode;
SymbolSymmetryP symmetry;
bool drawing;
Vector2D center, handle;
SymbolSymmetryP& symmetry;
// controls
wxSpinCtrl* copies;
// Actions
SymmetryMoveAction* symmetryMoveAction;
/// Cancel the drawing
void stopActions();
// What is selected?
enum Selection {
SELECTION_NONE,
SELECTION_HANDLE, // dragging a handle
SELECTION_CENTER, // dragging the rotation center
} selection, hovered;
/// Make the symmetry object
void makePart(Vector2D a, Vector2D b, bool constrained, bool snap);
Selection findSelection(const Vector2D& pos);
/// Done with dragging
void resetActions();
};
+5 -3
View File
@@ -297,14 +297,15 @@ void SymbolWindow::onUpdateUI(wxUpdateUIEvent& ev) {
void SymbolWindow::onSelectFromList(wxCommandEvent& ev) {
if (inSelectionEvent) return ;
if (inSelectionEvent) return;
inSelectionEvent = true;
control->onUpdateSelection();
inSelectionEvent = false;
}
void SymbolWindow::onActivateFromList(wxCommandEvent& ev) {
//% control->activatePart(control->getSymbol()->parts.at(ev.GetIndex()));
// TODO
if (control->selected_parts.size() == 1) {
control->activatePart(control->selected_parts.getOnlyOne());
}
}
void SymbolWindow::onSelectFromControl() {
@@ -329,6 +330,7 @@ BEGIN_EVENT_TABLE(SymbolWindow, wxFrame)
EVT_TOOL_RANGE (ID_MODE_MIN, ID_MODE_MAX, SymbolWindow::onModeChange)
EVT_TOOL_RANGE (ID_CHILD_MIN, ID_CHILD_MAX, SymbolWindow::onExtraTool)
EVT_UPDATE_UI (wxID_ANY, SymbolWindow::onUpdateUI)
EVT_COMMAND_RANGE(ID_CHILD_MIN, ID_CHILD_MAX, wxEVT_COMMAND_SPINCTRL_UPDATED, SymbolWindow::onExtraTool)
EVT_PART_SELECT (ID_PART_LIST, SymbolWindow::onSelectFromList)
EVT_PART_ACTIVATE (ID_PART_LIST, SymbolWindow::onActivateFromList)