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.

git-svn-id: svn://svn.code.sf.net/p/magicseteditor/code/trunk@526 0fc631ac-6414-0410-93d0-97cfa31319b6
This commit is contained in:
twanvl
2007-07-08 01:12:55 +00:00
parent 0deb8513fd
commit b46d979f9e
31 changed files with 616 additions and 375 deletions
+2 -2
View File
@@ -133,7 +133,7 @@ bool SymbolBasicShapeEditor::isEditing() { return drawing; }
// ----------------------------------------------------------------------------- : Generating shapes
void SymbolBasicShapeEditor::stopActions() {
shape = SymbolPartP();
shape = SymbolShapeP();
drawing = false;
switch (mode) {
case ID_SHAPE_CIRCLE:
@@ -176,7 +176,7 @@ void SymbolBasicShapeEditor::makeShape(const Vector2D& a, const Vector2D& b, boo
// TODO : Move out of this class
void SymbolBasicShapeEditor::makeCenteredShape(const Vector2D& c, Vector2D r, bool constrained) {
shape = new_intrusive<SymbolPart>();
shape = new_intrusive<SymbolShape>();
// What shape to make?
switch (mode) {
case ID_SHAPE_CIRCLE: {
+1 -1
View File
@@ -48,7 +48,7 @@ class SymbolBasicShapeEditor : public SymbolEditorBase {
// --------------------------------------------------- : Data
private:
int mode;
SymbolPartP shape;
SymbolShapeP shape;
Vector2D start;
Vector2D end;
bool drawing;
+24 -11
View File
@@ -51,8 +51,10 @@ void SymbolControl::onModeChange(wxCommandEvent& ev) {
break;
case ID_MODE_POINTS:
if (selected_parts.size() == 1) {
single_selection = *selected_parts.begin();
switchEditor(new_intrusive2<SymbolPointEditor>(this, single_selection));
selected_shape = dynamic_pointer_cast<SymbolShape>(*selected_parts.begin());
if (selected_shape) {
switchEditor(new_intrusive2<SymbolPointEditor>(this, selected_shape));
}
}
break;
case ID_MODE_SHAPES:
@@ -88,25 +90,34 @@ void SymbolControl::onAction(const Action& action, bool undone) {
void SymbolControl::onUpdateSelection() {
switch(editor->modeToolId()) {
case ID_MODE_POINTS:
case ID_MODE_POINTS: {
// can only select a single part!
if (selected_parts.size() > 1) {
// 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(single_selection);
selected_parts.insert(selected_shape);
signalSelectionChange();
break;
}
if (single_selection != *selected_parts.begin()) {
SymbolShapeP shape = dynamic_pointer_cast<SymbolShape>(*selected_parts.begin());
if (!shape) {
selected_parts.clear();
selected_parts.insert(selected_shape);
signalSelectionChange();
break;
}
if (shape != selected_shape) {
// begin editing another part
single_selection = *selected_parts.begin();
editor = new_intrusive2<SymbolPointEditor>(this, single_selection);
selected_shape = shape;
editor = new_intrusive2<SymbolPointEditor>(this, selected_shape);
Refresh(false);
}
break;
case ID_MODE_SHAPES:
} case ID_MODE_SHAPES:
if (!selected_parts.empty()) {
// there can't be a selection
selected_parts.clear();
@@ -127,9 +138,11 @@ void SymbolControl::selectPart(const SymbolPartP& part) {
}
void SymbolControl::activatePart(const SymbolPartP& part) {
selected_parts.clear();
selected_parts.insert(part);
switchEditor(new_intrusive2<SymbolPointEditor>(this, part));
if (part->isSymbolShape()) {
selected_parts.clear();
selected_parts.insert(part);
switchEditor(new_intrusive2<SymbolPointEditor>(this, static_pointer_cast<SymbolShape>(part)));
}
}
void SymbolControl::signalSelectionChange() {
+3 -3
View File
@@ -44,7 +44,7 @@ class SymbolControl : public wxControl, public SymbolViewer {
/// The selection has changed, tell the part list
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);
/// Select a specific part from the symbol
@@ -70,9 +70,9 @@ class SymbolControl : public wxControl, public SymbolViewer {
// --------------------------------------------------- : Data
public:
/// What parts are selected
/// What parts are selected?
set<SymbolPartP> selected_parts;
SymbolPartP single_selection;
SymbolShapeP selected_shape; // if there is a single selection
/// Parent window
SymbolWindow* parent;
+7 -7
View File
@@ -19,13 +19,15 @@ SymbolPartList::SymbolPartList(Window* parent, int id, SymbolP symbol)
{
// Create image list
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_sub")));
images->Add(load_resource_image(_("combine_and")));
images->Add(load_resource_image(_("combine_xor")));
images->Add(load_resource_image(_("combine_over")));
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);
// create columns
InsertColumn(0, _("Name"));
@@ -59,7 +61,7 @@ String SymbolPartList::OnGetItemText(long item, long col) const {
return getPart(item)->name;
}
int SymbolPartList::OnGetItemImage(long item) const {
return getPart(item)->combine;
return getPart(item)->icon();
}
SymbolPartP SymbolPartList::getPart(long item) const {
@@ -74,14 +76,12 @@ void SymbolPartList::selectItem(long item) {
}
}
void SymbolPartList::getselected_parts(set<SymbolPartP>& sel) {
void SymbolPartList::getSelectedParts(set<SymbolPartP>& sel) {
sel.clear();
long count = GetItemCount();
for (long i = 0 ; i < count ; ++ i) {
bool selected = GetItemState(i, wxLIST_STATE_SELECTED);
if (selected) {
sel.insert(symbol->parts.at(i));
}
if (selected) sel.insert(symbol->parts.at(i));
}
}
@@ -94,7 +94,7 @@ void SymbolPartList::selectParts(const set<SymbolPartP>& sel) {
wxLIST_STATE_SELECTED);
}
}
void SymbolPartList::update() {
if (symbol->parts.empty()) {
// deleting all items requires a full refresh on win32
+1 -1
View File
@@ -31,7 +31,7 @@ class SymbolPartList : public wxListCtrl, public SymbolView {
inline SymbolPartP getSelection() const { return getPart(selected); }
/// Get a set of selected parts
void getselected_parts(set<SymbolPartP>& sel);
void getSelectedParts(set<SymbolPartP>& sel);
/// Select the specified parts, and nothing else
void selectParts(const set<SymbolPartP>& sel);
+3 -3
View File
@@ -19,7 +19,7 @@ DECLARE_TYPEOF_COLLECTION(ControlPointP);
// ----------------------------------------------------------------------------- : SymbolPointEditor
SymbolPointEditor::SymbolPointEditor(SymbolControl* control, const SymbolPartP& part)
SymbolPointEditor::SymbolPointEditor(SymbolControl* control, const SymbolShapeP& part)
: SymbolEditorBase(control)
, part(part)
, selection(SELECTED_NONE)
@@ -261,7 +261,7 @@ void SymbolPointEditor::onLeftDClick(const Vector2D& pos, wxMouseEvent& ev) {
// Delete point
selected_points.clear();
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();
selection = SELECTED_NONE;
}
@@ -439,7 +439,7 @@ void SymbolPointEditor::resetActions() {
void SymbolPointEditor::deleteSelection() {
if (!selected_points.empty()) {
getSymbol()->actions.add(controlPointRemoveAction(part, selected_points));
getSymbol()->actions.add(control_point_remove_action(part, selected_points));
selected_points.clear();
resetActions();
control.Refresh(false);
+2 -2
View File
@@ -22,7 +22,7 @@ class CurveDragAction;
// Symbol editor for editing control points and handles
class SymbolPointEditor : public SymbolEditorBase {
public:
SymbolPointEditor(SymbolControl* control, const SymbolPartP& part);
SymbolPointEditor(SymbolControl* control, const SymbolShapeP& part);
// --------------------------------------------------- : Drawing
@@ -81,7 +81,7 @@ class SymbolPointEditor : public SymbolEditorBase {
// --------------------------------------------------- : Data
// The symbol part we are editing
SymbolPartP part;
SymbolShapeP part;
// Actions in progress
// All are owned by the action stack, or they are 0
+36 -23
View File
@@ -12,6 +12,7 @@
#include <util/window_id.hpp>
#include <data/action/symbol.hpp>
#include <data/settings.hpp>
#include <util/error.hpp>
#include <gfx/gfx.hpp>
DECLARE_TYPEOF_COLLECTION(SymbolPartP);
@@ -37,7 +38,9 @@ SymbolSelectEditor::SymbolSelectEditor(SymbolControl* control, bool rotate)
handleCenter = wxBitmap(load_resource_image(_("handle_center")));
// Make sure all parts have updated bounds
FOR_EACH(p, getSymbol()->parts) {
p->calculateBounds();
if (SymbolShape* s = p->isSymbolShape()) {
s->calculateBounds();
}
}
resetActions();
}
@@ -108,27 +111,27 @@ void SymbolSelectEditor::drawRotationCenter(DC& dc, const Vector2D& pos) {
void SymbolSelectEditor::initUI(wxToolBar* tb, wxMenuBar* mb) {
tb->AddSeparator();
tb->AddTool(ID_PART_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_PART_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_PART_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_MERGE, _TOOL_("merge"), load_resource_image(_("combine_or")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("merge"), _HELP_("merge"));
tb->AddTool(ID_SYMBOL_COMBINE_SUBTRACT, _TOOL_("subtract"), load_resource_image(_("combine_sub_dark")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("subtract"), _HELP_("subtract"));
tb->AddTool(ID_SYMBOL_COMBINE_INTERSECTION, _TOOL_("intersect"), load_resource_image(_("combine_and_dark")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("intersect"), _HELP_("intersect"));
tb->AddTool(ID_SYMBOL_COMBINE_DIFFERENCE, _TOOL_("difference"), load_resource_image(_("combine_xor")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("difference"), _HELP_("difference"));
tb->AddTool(ID_SYMBOL_COMBINE_OVERLAP, _TOOL_("overlap"), load_resource_image(_("combine_over")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("overlap"), _HELP_("overlap"));
tb->AddTool(ID_SYMBOL_COMBINE_BORDER, _TOOL_("border"), load_resource_image(_("combine_border")), wxNullBitmap, wxITEM_CHECK, _TOOLTIP_("border"), _HELP_("border"));
tb->Realize();
}
void SymbolSelectEditor::destroyUI(wxToolBar* tb, wxMenuBar* mb) {
tb->DeleteTool(ID_PART_MERGE);
tb->DeleteTool(ID_PART_SUBTRACT);
tb->DeleteTool(ID_PART_INTERSECTION);
tb->DeleteTool(ID_PART_DIFFERENCE);
tb->DeleteTool(ID_PART_OVERLAP);
tb->DeleteTool(ID_PART_BORDER);
tb->DeleteTool(ID_SYMBOL_COMBINE_MERGE);
tb->DeleteTool(ID_SYMBOL_COMBINE_SUBTRACT);
tb->DeleteTool(ID_SYMBOL_COMBINE_INTERSECTION);
tb->DeleteTool(ID_SYMBOL_COMBINE_DIFFERENCE);
tb->DeleteTool(ID_SYMBOL_COMBINE_OVERLAP);
tb->DeleteTool(ID_SYMBOL_COMBINE_BORDER);
// HACK: hardcoded size of rest of toolbar
tb->DeleteToolByPos(7); // delete separator
}
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()) {
ev.Check(false);
ev.Enable(false);
@@ -136,10 +139,12 @@ void SymbolSelectEditor::onUpdateUI(wxUpdateUIEvent& ev) {
ev.Enable(true);
bool check = true;
FOR_EACH(p, control.selected_parts) {
if (p->combine != ev.GetId() - ID_PART) {
check = false;
break;
}
if (SymbolShape* s = p->isSymbolShape()) {
if (s->combine != ev.GetId() - ID_SYMBOL_COMBINE) {
check = false;
break;
}
} // disable when symmetries are selected?
}
ev.Check(check);
}
@@ -151,11 +156,11 @@ void SymbolSelectEditor::onUpdateUI(wxUpdateUIEvent& ev) {
}
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
getSymbol()->actions.add(new CombiningModeAction(
control.selected_parts,
static_cast<SymbolPartCombine>(id - ID_PART)
static_cast<SymbolShapeCombine>(id - ID_SYMBOL_COMBINE)
));
control.Refresh(false);
} else if (id == ID_EDIT_DUPLICATE && !isEditing()) {
@@ -427,7 +432,13 @@ double SymbolSelectEditor::angleTo(const Vector2D& pos) {
SymbolPartP SymbolSelectEditor::findPart(const Vector2D& pos) {
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();
}
@@ -437,8 +448,10 @@ void SymbolSelectEditor::updateBoundingBox() {
minV = Vector2D::infinity();
maxV = -Vector2D::infinity();
FOR_EACH(p, control.selected_parts) {
minV = piecewise_min(minV, p->min_pos);
maxV = piecewise_max(maxV, p->max_pos);
if (SymbolShape* s = p->isSymbolShape()) {
minV = piecewise_min(minV, s->min_pos);
maxV = piecewise_max(maxV, s->max_pos);
}
}
/* // Find rotation center
center = Vector2D(0,0);
+1 -1
View File
@@ -249,7 +249,7 @@ void SymbolWindow::onUpdateUI(wxUpdateUIEvent& ev) {
void SymbolWindow::onSelectFromList(wxListEvent& ev) {
if (inSelectionEvent) return ;
inSelectionEvent = true;
parts->getselected_parts(control->selected_parts);
parts->getSelectedParts(control->selected_parts);
control->onUpdateSelection();
inSelectionEvent = false;
}
+11 -10
View File
@@ -36,31 +36,32 @@ void SymbolValueEditor::draw(RotatedDC& dc) {
}
void SymbolValueEditor::drawButton(RotatedDC& dc, int button, const String& text) {
bool down = button == button_down;
double size = style().height;
double x = style().right - size - (size + 1) * button;
double height = style().height;
double width = style().height + 2;
double x = style().right - width - (width + 1) * button;
double y = style().top;
// draw button
dc.SetPen(*wxTRANSPARENT_PEN);
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.DrawLine(RealPoint(x,y),RealPoint(x+size,y));
dc.DrawLine(RealPoint(x,y),RealPoint(x,y+size));
dc.DrawLine(RealPoint(x,y),RealPoint(x+width,y));
dc.DrawLine(RealPoint(x,y),RealPoint(x,y+height));
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,y+size-1),RealPoint(x+size,y+size-1));
dc.DrawLine(RealPoint(x+width-1,y),RealPoint(x+width-1,y+height));
dc.DrawLine(RealPoint(x,y+height-1),RealPoint(x+width,y+height-1));
// draw 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
const Bitmap& bmp = button_images[button];
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) {
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;
return -1;
}