Sun, 06 Sep 2015 15:12:30 +0300
Refactor LDObject API
--- a/CMakeLists.txt Sun Sep 06 13:46:39 2015 +0300 +++ b/CMakeLists.txt Sun Sep 06 15:12:30 2015 +0300 @@ -105,6 +105,7 @@ src/hierarchyelement.h src/guiutilities.h src/documentloader.h + src/doublemap.h src/dialogs/colorselector.h src/dialogs/configdialog.h src/dialogs/ldrawpathdialog.h
--- a/src/addObjectDialog.cpp Sun Sep 06 13:46:39 2015 +0300 +++ b/src/addObjectDialog.cpp Sun Sep 06 15:12:30 2015 +0300 @@ -73,21 +73,21 @@ coordCount = 12; } break; - case OBJ_BFC: + case OBJ_Bfc: { rb_bfcType = new RadioGroup ("Statement", {}, 0, Qt::Vertical); - for_enum (BFCStatement, i) + for_enum (BfcStatement, i) { // Separate these in two columns - if (int (i) == int (BFCStatement::NumValues) / 2) + if (int (i) == int (BfcStatement::NumValues) / 2) rb_bfcType->rowBreak(); - rb_bfcType->addButton (LDBFC::StatementStrings[int (i)]); + rb_bfcType->addButton (LDBfc::statementToString (i)); } if (obj) - rb_bfcType->setValue ((int) static_cast<LDBFC*> (obj)->statement()); + rb_bfcType->setValue ((int) static_cast<LDBfc*> (obj)->statement()); } break; case OBJ_Subfile: @@ -168,7 +168,7 @@ layout->addWidget (le_comment, 0, 1); break; - case OBJ_BFC: + case OBJ_Bfc: layout->addWidget (rb_bfcType, 0, 1); break; @@ -348,12 +348,12 @@ } } break; - case OBJ_BFC: + case OBJ_Bfc: { - LDBFC* bfc = InitObject<LDBFC> (obj); + LDBfc* bfc = InitObject<LDBfc> (obj); int value = dlg.rb_bfcType->value(); - if (value == qBound (0, value, int (BFCStatement::NumValues) - 1)) - bfc->setStatement (BFCStatement (dlg.rb_bfcType->value())); + if (value == qBound (0, value, int (BfcStatement::NumValues) - 1)) + bfc->setStatement (BfcStatement (dlg.rb_bfcType->value())); } break; case OBJ_Subfile:
--- a/src/dialogs/newpartdialog.cpp Sun Sep 06 13:46:39 2015 +0300 +++ b/src/dialogs/newpartdialog.cpp Sun Sep 06 15:12:30 2015 +0300 @@ -40,15 +40,15 @@ ui.useCaLicense->setChecked (m_config->useCaLicense()); } -BFCStatement NewPartDialog::getWinding() const +BfcStatement NewPartDialog::getWinding() const { if (ui.windingCcw->isChecked()) - return BFCStatement::CertifyCCW; + return BfcStatement::CertifyCCW; if (ui.windingCw->isChecked()) - return BFCStatement::CertifyCW; + return BfcStatement::CertifyCW; - return BFCStatement::NoCertify; + return BfcStatement::NoCertify; } bool NewPartDialog::useCaLicense() const @@ -78,7 +78,7 @@ objs << new LDComment (CALicenseText); objs << new LDEmpty(); - objs << new LDBFC (getWinding()); + objs << new LDBfc (getWinding()); objs << new LDEmpty(); newdoc->addObjects (objs); }
--- a/src/dialogs/newpartdialog.h Sun Sep 06 13:46:39 2015 +0300 +++ b/src/dialogs/newpartdialog.h Sun Sep 06 15:12:30 2015 +0300 @@ -29,7 +29,7 @@ QString author() const; void fillHeader (LDDocument* newdoc) const; - BFCStatement getWinding() const; + BfcStatement getWinding() const; bool useCaLicense() const; QString title() const;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/doublemap.h Sun Sep 06 15:12:30 2015 +0300 @@ -0,0 +1,105 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013 - 2015 Teemu Piippo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#pragma once +#include <QMap> + +template<typename Key, typename Value> +class DoubleMap +{ +public: + void clear() + { + m_map.clear(); + m_reverseMap.clear(); + } + + void insert (const Key& key, const Value& value) + { + m_map[key] = value; + m_reverseMap[value] = key; + } + + bool containsKey (const Key& key) const + { + return m_map.contains (key); + } + + bool containsValue (const Value& value) const + { + return m_reverseMap.contains (value); + } + + void removeKey (const Key& key) + { + m_reverseMap.remove (m_map[key]); + m_map.remove (key); + } + + void removeValue (const Key& key) + { + m_reverseMap.remove (m_map[key]); + m_map.remove (key); + } + + Value& lookup (const Key& key) + { + return m_map[key]; + } + + const Value& lookup (const Key& key) const + { + return m_map[key]; + } + + Key& reverseLookup (const Value& key) + { + return m_reverseMap[key]; + } + + const Key& reverseLookup (const Value& key) const + { + return m_reverseMap[key]; + } + + Value* find (const Key& key) + { + auto iterator = m_map.find (key); + return iterator == m_map.end() ? NULL : &(*iterator); + } + + Key* reverseFind (const Value& value) + { + auto iterator = m_reverseMap.find (value); + return iterator == m_reverseMap.end() ? NULL : &(*iterator); + } + + Value& operator[] (const Key& key) + { + return lookup (key); + } + + const Value& operator[] (const Key& key) const + { + return lookup (key); + } + +private: + QMap<Key, Value> m_map; + QMap<Value, Key> m_reverseMap; +};
--- a/src/ldDocument.cpp Sun Sep 06 13:46:39 2015 +0300 +++ b/src/ldDocument.cpp Sun Sep 06 15:12:30 2015 +0300 @@ -761,24 +761,21 @@ // Handle BFC statements if (tokens.size() > 2 and tokens[1] == "BFC") { - for_enum (BFCStatement, i) + for_enum (BfcStatement, i) { - if (commentTextSimplified == format ("BFC %1", - LDBFC::StatementStrings[int (i)])) - { - return LDSpawn<LDBFC> (i); - } + if (commentTextSimplified == format ("BFC %1", LDBfc::statementToString (i))) + return LDSpawn<LDBfc> (i); } // MLCAD is notorious for stuffing these statements in parts it // creates. The above block only handles valid statements, so we // need to handle MLCAD-style invertnext, clip and noclip separately. if (commentTextSimplified == "BFC CERTIFY INVERTNEXT") - return LDSpawn<LDBFC> (BFCStatement::InvertNext); + return LDSpawn<LDBfc> (BfcStatement::InvertNext); else if (commentTextSimplified == "BFC CERTIFY CLIP") - return LDSpawn<LDBFC> (BFCStatement::Clip); + return LDSpawn<LDBfc> (BfcStatement::Clip); else if (commentTextSimplified == "BFC CERTIFY NOCLIP") - return LDSpawn<LDBFC> (BFCStatement::NoClip); + return LDSpawn<LDBfc> (BfcStatement::NoClip); } if (tokens.size() > 2 and tokens[1] == "!LDFORGE") @@ -1230,11 +1227,10 @@ // void LDDocument::addToSelection (LDObject* obj) // [protected] { - if (not obj->isSelected() and obj->document() == this) + if (obj->isSelected() and obj->document() == this) { m_sel << obj; m_window->renderer()->compileObject (obj); - obj->setSelected (true); } } @@ -1242,11 +1238,10 @@ // void LDDocument::removeFromSelection (LDObject* obj) // [protected] { - if (obj->isSelected() and obj->document() == this) + if (not obj->isSelected() and obj->document() == this) { m_sel.removeOne (obj); m_window->renderer()->compileObject (obj); - obj->setSelected (false); } } @@ -1256,8 +1251,8 @@ { for (LDObject* obj : m_sel) { + obj->deselect(); m_window->renderer()->compileObject (obj); - obj->setSelected (false); } m_sel.clear();
--- a/src/ldObject.cpp Sun Sep 06 13:46:39 2015 +0300 +++ b/src/ldObject.cpp Sun Sep 06 15:12:30 2015 +0300 @@ -33,7 +33,6 @@ // List of all LDObjects QMap<int32, LDObject*> g_allObjects; -static int32 g_idcursor = 1; // 0 shalt be null enum { MAX_LDOBJECT_IDS = (1 << 24) }; @@ -47,20 +46,25 @@ LDObject::LDObject (LDDocument* document) : m_isHidden (false), m_isSelected (false), - m_document (nullptr), - qObjListEntry (nullptr), - m_isDestroyed (false) + m_isDestroyed (false), + m_document (nullptr) { if (document) document->addObject (this); memset (m_coords, 0, sizeof m_coords); - chooseID(); - if (id() != 0) - g_allObjects[id()] = this; + // Let's hope that nobody goes to create 17 million objects anytime soon... + static int32 nextId = 1; // 0 shalt be null + if (nextId < MAX_LDOBJECT_IDS) + m_id = nextId++; + else + m_id = 0; - setRandomColor (QColor::fromHsv (rand() % 360, rand() % 256, rand() % 96 + 128)); + if (m_id != 0) + g_allObjects[m_id] = this; + + m_randomColor = QColor::fromHsv (rand() % 360, rand() % 256, rand() % 96 + 128); } LDSubfile::LDSubfile (LDDocument* document) : @@ -73,7 +77,7 @@ LDOBJ_DEFAULT_CTOR (LDCondLine, LDLine) LDOBJ_DEFAULT_CTOR (LDQuad, LDObject) LDOBJ_DEFAULT_CTOR (LDOverlay, LDObject) -LDOBJ_DEFAULT_CTOR (LDBFC, LDObject) +LDOBJ_DEFAULT_CTOR (LDBfc, LDObject) LDOBJ_DEFAULT_CTOR (LDComment, LDObject) LDObject::~LDObject() @@ -84,26 +88,6 @@ // ============================================================================= // -void LDObject::chooseID() -{ - // Let's hope that nobody goes to create 17 million objects anytime soon... - if (g_idcursor < MAX_LDOBJECT_IDS) - setID (g_idcursor++); - else - setID (0); -} - -// ============================================================================= -// -void LDObject::setVertexCoord (int i, Axis ax, double value) -{ - Vertex v = vertex (i); - v.setCoordinate (ax, value); - setVertex (i, v); -} - -// ============================================================================= -// QString LDComment::asText() const { return format ("0 %1", text()); @@ -185,23 +169,9 @@ // ============================================================================= // -const char* LDBFC::StatementStrings[] = +QString LDBfc::asText() const { - "CERTIFY CCW", - "CCW", - "CERTIFY CW", - "CW", - "NOCERTIFY", - "INVERTNEXT", - "CLIP", - "CLIP CCW", - "CLIP CW", - "NOCLIP", -}; - -QString LDBFC::asText() const -{ - return format ("0 BFC %1", StatementStrings[int (m_statement)]); + return format ("0 BFC %1", statementToString()); } // ============================================================================= @@ -226,6 +196,8 @@ // ============================================================================= // +// Replace this LDObject with another LDObject. Object is deleted in the process. +// void LDObject::replace (LDObject* other) { int idx = lineNumber(); @@ -242,6 +214,8 @@ // ============================================================================= // +// Swap this object with another. +// void LDObject::swap (LDObject* other) { if (document() == other->document()) @@ -291,6 +265,8 @@ // ============================================================================= // +// Deletes this object +// void LDObject::destroy() { deselect(); @@ -311,12 +287,12 @@ // ============================================================================= // -void LDObject::setDocument (LDDocument* const& a) +void LDObject::setDocument (LDDocument* document) { - m_document = a; + m_document = document; - if (a == nullptr) - setSelected (false); + if (document == nullptr) + m_isSelected = false; } // ============================================================================= @@ -414,8 +390,10 @@ } // ============================================================================= -// ----------------------------------------------------------------------------- -long LDObject::lineNumber() const +// +// Index (i.e. line number) of this object +// +int LDObject::lineNumber() const { if (document()) { @@ -474,6 +452,8 @@ // ============================================================================= // +// Get type name by enumerator +// QString LDObject::typeName (LDObjectType type) { return LDObject::getDefault (type)->typeName(); @@ -481,6 +461,8 @@ // ============================================================================= // +// Get a description of a list of LDObjects +// QString LDObject::describeObjects (const LDObjectList& objs) { QString text; @@ -513,6 +495,8 @@ // ============================================================================= // +// What object in the current file ultimately references this? +// LDObject* LDObject::topLevelParent() { LDObject* it; @@ -525,6 +509,8 @@ // ============================================================================= // +// Object after this in the current file +// LDObject* LDObject::next() const { int idx = lineNumber(); @@ -537,6 +523,8 @@ // ============================================================================= // +// Object prior to this in the current file +// LDObject* LDObject::previous() const { int idx = lineNumber(); @@ -549,13 +537,15 @@ // ============================================================================= // -bool LDObject::previousIsInvertnext (LDBFC*& ptr) +// Is the previous object INVERTNEXT? +// +bool LDObject::previousIsInvertnext (LDBfc*& ptr) { LDObject* prev = previous(); - if (prev and prev->type() == OBJ_BFC and static_cast<LDBFC*> (prev)->statement() == BFCStatement::InvertNext) + if (prev and prev->type() == OBJ_Bfc and static_cast<LDBfc*> (prev)->statement() == BfcStatement::InvertNext) { - ptr = static_cast<LDBFC*> (prev); + ptr = static_cast<LDBfc*> (prev); return true; } @@ -564,6 +554,8 @@ // ============================================================================= // +// Moves this object using the given vertex as a movement List +// void LDObject::move (Vertex vect) { if (hasMatrix()) @@ -578,14 +570,66 @@ } } +bool LDObject::isHidden() const +{ + return m_isHidden; +} + +void LDObject::setHidden (bool value) +{ + m_isHidden = value; +} + +LDObject* LDObject::parent() const +{ + return m_parent; +} + +void LDObject::setParent (LDObject* parent) +{ + m_parent = parent; +} + +bool LDObject::isSelected() const +{ + return m_isSelected; +} + +qint32 LDObject::id() const +{ + return m_id; +} + +LDColor LDObject::color() const +{ + return m_color; +} + +QColor LDObject::randomColor() const +{ + return m_randomColor; +} + +LDDocument* LDObject::document() const +{ + return m_document; +} + +bool LDObject::isDestroyed() const +{ + return m_isDestroyed; +} + // ============================================================================= // +// Returns a default-constructed LDObject by the given type +// LDObject* LDObject::getDefault (const LDObjectType type) { switch (type) { case OBJ_Comment: return LDSpawn<LDComment>(); - case OBJ_BFC: return LDSpawn<LDBFC>(); + case OBJ_Bfc: return LDSpawn<LDBfc>(); case OBJ_Line: return LDSpawn<LDLine>(); case OBJ_CondLine: return LDSpawn<LDCondLine>(); case OBJ_Subfile: return LDSpawn<LDSubfile>(); @@ -602,7 +646,7 @@ // ============================================================================= // void LDObject::invert() {} -void LDBFC::invert() {} +void LDBfc::invert() {} void LDEmpty::invert() {} void LDComment::invert() {} void LDError::invert() {} @@ -687,9 +731,9 @@ if (idx > 0) { - LDBFC* bfc = dynamic_cast<LDBFC*> (previous()); + LDBfc* bfc = dynamic_cast<LDBfc*> (previous()); - if (bfc and bfc->statement() == BFCStatement::InvertNext) + if (bfc and bfc->statement() == BfcStatement::InvertNext) { // This is prefixed with an invertnext, thus remove it. bfc->destroy(); @@ -698,7 +742,7 @@ } // Not inverted, thus prefix it with a new invertnext. - document()->insertObj (idx, new LDBFC (BFCStatement::InvertNext)); + document()->insertObj (idx, new LDBfc (BfcStatement::InvertNext)); } // ============================================================================= @@ -792,13 +836,15 @@ // ============================================================================= // -void LDObject::setColor (LDColor const& val) +void LDObject::setColor (LDColor color) { - changeProperty (this, &m_color, val); + changeProperty (this, &m_color, color); } // ============================================================================= // +// Get a vertex by index +// const Vertex& LDObject::vertex (int i) const { return m_coords[i]; @@ -806,11 +852,41 @@ // ============================================================================= // +// Set a vertex to the given value +// void LDObject::setVertex (int i, const Vertex& vert) { changeProperty (this, &m_coords[i], vert); } +LDMatrixObject::LDMatrixObject (LDDocument* document) : + LDObject (document), + m_position (Origin) {} + +LDMatrixObject::LDMatrixObject (const Matrix& transform, const Vertex& pos, LDDocument* document) : + LDObject (document), + m_position (pos), + m_transform (transform) {} + +void LDMatrixObject::setCoordinate (const Axis ax, double value) +{ + Vertex v = position(); + + switch (ax) + { + case X: v.setX (value); break; + case Y: v.setY (value); break; + case Z: v.setZ (value); break; + } + + setPosition (v); +} + +const Vertex& LDMatrixObject::position() const +{ + return m_position; +} + // ============================================================================= // void LDMatrixObject::setPosition (const Vertex& a) @@ -820,29 +896,182 @@ // ============================================================================= // +const Matrix& LDMatrixObject::transform() const +{ + return m_transform; +} + void LDMatrixObject::setTransform (const Matrix& val) { changeProperty (this, &m_transform, val); } +LDError::LDError (QString contents, QString reason, LDDocument* document) : + LDObject (document), + m_contents (contents), + m_reason (reason) {} + +QString LDError::reason() const +{ + return m_reason; +} + +QString LDError::contents() const +{ + return m_contents; +} + +QString LDError::fileReferenced() const +{ + return m_fileReferenced; +} + +void LDError::setFileReferenced (QString value) +{ + m_fileReferenced = value; +} + +LDComment::LDComment (QString text, LDDocument* document) : + LDObject (document), + m_text (text) {} + +QString LDComment::text() const +{ + return m_text; +} + +void LDComment::setText (QString value) +{ + changeProperty (this, &m_text, value); +} + +LDBfc::LDBfc (const BfcStatement type, LDDocument* document) : + LDObject (document), + m_statement (type) {} + +BfcStatement LDBfc::statement() const +{ + return m_statement; +} + +void LDBfc::setStatement (BfcStatement value) +{ + m_statement = value; +} + +QString LDBfc::statementToString() const +{ + return LDBfc::statementToString (statement()); +} + +QString LDBfc::statementToString (BfcStatement statement) +{ + static const char* statementStrings[] = + { + "CERTIFY CCW", + "CCW", + "CERTIFY CW", + "CW", + "NOCERTIFY", + "INVERTNEXT", + "CLIP", + "CLIP CCW", + "CLIP CW", + "NOCLIP", + }; + + if ((int) statement >= 0 and (int) statement < countof (statementStrings)) + return QString::fromLatin1 (statementStrings[(int) statement]); + else + return ""; +} + +int LDOverlay::camera() const +{ + return m_camera; +} + +void LDOverlay::setCamera (int value) +{ + m_camera = value; +} + +int LDOverlay::x() const +{ + return m_x; +} + +void LDOverlay::setX (int value) +{ + m_x = value; +} + +int LDOverlay::y() const +{ + return m_y; +} + +void LDOverlay::setY (int value) +{ + m_y = value; +} + +int LDOverlay::width() const +{ + return m_width; +} + +void LDOverlay::setWidth (int value) +{ + m_width = value; +} + +int LDOverlay::height() const +{ + return m_height; +} + +void LDOverlay::setHeight (int value) +{ + m_height = value; +} + +QString LDOverlay::fileName() const +{ + return m_fileName; +} + +void LDOverlay::setFileName (QString value) +{ + m_fileName = value; +} + // ============================================================================= // +// Selects this object. +// void LDObject::select() { - if (document()) + if (not isSelected() and document()) + { + m_isSelected = true; document()->addToSelection (this); + } } // ============================================================================= // +// Removes this object from selection +// void LDObject::deselect() { if (isSelected() and document()) { + m_isSelected = false; document()->removeFromSelection (this); // If this object is inverted with INVERTNEXT, deselect the INVERTNEXT as well. - LDBFC* invertnext; + LDBfc* invertnext; if (previousIsInvertnext (invertnext)) invertnext->deselect(); @@ -866,18 +1095,22 @@ // ============================================================================= // -void LDSubfile::setFileInfo (LDDocument* const& a) +LDDocument* LDSubfile::fileInfo() const { - changeProperty (this, &m_fileInfo, a); + return m_fileInfo; +} - // If it's an immediate subfile reference (i.e. this subfile belongs in an - // explicit file), we need to pre-compile the GL polygons for the document - // if they don't exist already. - if (a and - a->isCache() == false and - a->polygonData().isEmpty()) +void LDSubfile::setFileInfo (LDDocument* document) +{ + changeProperty (this, &m_fileInfo, document); + + // If it's an immediate subfile reference (i.e. this subfile is in an opened document), we need to pre-compile the + // GL polygons for the document if they don't exist already. + if (document and + document->isCache() == false and + document->polygonData().isEmpty()) { - a->initializeCachedData(); + document->initializeCachedData(); } };
--- a/src/ldObject.h Sun Sep 06 13:46:39 2015 +0300 +++ b/src/ldObject.h Sun Sep 06 15:12:30 2015 +0300 @@ -55,7 +55,7 @@ class LDSubfile; class LDDocument; -class LDBFC; +class LDBfc; // // Object type codes. @@ -67,7 +67,7 @@ OBJ_Triangle, // Object represents a triangle OBJ_Line, // Object represents a line OBJ_CondLine, // Object represents a conditional line - OBJ_BFC, // Object represents a BFC statement + OBJ_Bfc, // Object represents a BFC statement OBJ_Overlay, // Object contains meta-info about an overlay image. OBJ_Comment, // Object represents a comment OBJ_Error, // Object is the result of failed parsing @@ -89,123 +89,68 @@ // class LDObject { - PROPERTY (public, bool, isHidden, setHidden, STOCK_WRITE) - PROPERTY (public, bool, isSelected, setSelected, STOCK_WRITE) - PROPERTY (public, LDObject*, parent, setParent, STOCK_WRITE) - PROPERTY (public, LDDocument*, document, setDocument, CUSTOM_WRITE) - PROPERTY (private, int32, id, setID, STOCK_WRITE) - PROPERTY (public, LDColor, color, setColor, CUSTOM_WRITE) - PROPERTY (private, QColor, randomColor, setRandomColor, STOCK_WRITE) - public: LDObject (LDDocument* document = nullptr); - // This object as LDraw code - virtual QString asText() const = 0; - - // Makes a copy of this object - LDObject* createCopy() const; - - // What color does the object default to? - virtual LDColor defaultColor() const = 0; - - // Deletes this object - void destroy(); - - // Removes this object from selection - void deselect(); - - virtual void getVertices (QVector<Vertex>& verts) const; - - // Does this object have a matrix and position? (see LDMatrixObject) - virtual bool hasMatrix() const = 0; - - // Inverts this object (winding is reversed) - virtual void invert() = 0; - - // Is this object colored? - virtual bool isColored() const = 0; - - // Does this object have meaning in the part model? - virtual bool isScemantic() const = 0; - - // Index (i.e. line number) of this object - long lineNumber() const; - - // Moves this object using the given vertex as a movement List - void move (Vertex vect); - - // Object after this in the current file - LDObject* next() const; - - // Number of vertices this object has - virtual int numVertices() const = 0; + virtual QString asText() const = 0; // This object as LDraw code + LDColor color() const; + LDObject* createCopy() const; + virtual LDColor defaultColor() const = 0; // What color does the object default to? + void deselect(); + void destroy(); + LDDocument* document() const; + LDPolygon* getPolygon(); + virtual void getVertices (QVector<Vertex>& verts) const; + virtual bool hasMatrix() const = 0; // Does this object have a matrix and position? (see LDMatrixObject) + qint32 id() const; + virtual void invert() = 0; // Inverts this object (winding is reversed) + virtual bool isColored() const = 0; + bool isDestroyed() const; + bool isHidden() const; + virtual bool isScemantic() const = 0; // Does this object have meaning in the part model? + bool isSelected() const; + int lineNumber() const; + void move (Vertex vect); + LDObject* next() const; + virtual int numVertices() const = 0; + LDObject* parent() const; + LDObject* previous() const; + bool previousIsInvertnext (LDBfc*& ptr); + QColor randomColor() const; + void replace (LDObject* other); + void select(); + void setColor (LDColor color); + void setDocument (LDDocument* document); + void setHidden (bool value); + void setParent (LDObject* parent); + void setVertex (int i, const Vertex& vert); + void swap (LDObject* other); + LDObject* topLevelParent(); + virtual LDObjectType type() const = 0; + virtual QString typeName() const = 0; + const Vertex& vertex (int i) const; - // Object prior to this in the current file - LDObject* previous() const; - - // Is the previous object INVERTNEXT? - bool previousIsInvertnext (LDBFC*& ptr); - - // Replace this LDObject with another LDObject. Object is deleted in the process. - void replace (LDObject* other); - - // Selects this object. - void select(); - - // Set a vertex to the given value - void setVertex (int i, const Vertex& vert); - - // Set a single coordinate of a vertex - void setVertexCoord (int i, Axis ax, double value); - - // Swap this object with another. - void swap (LDObject* other); - - // What object in the current file ultimately references this? - LDObject* topLevelParent(); - - // Type enumerator of this object - virtual LDObjectType type() const = 0; - - // Type name of this object - virtual QString typeName() const = 0; - - // Get a vertex by index - const Vertex& vertex (int i) const; - - // Get type name by enumerator - static QString typeName (LDObjectType type); - - // Returns a default-constructed LDObject by the given type - static LDObject* getDefault (const LDObjectType type); - - // TODO: move this to LDDocument? - static void moveObjects (LDObjectList objs, const bool up); - - // Get a description of a list of LDObjects static QString describeObjects (const LDObjectList& objs); static LDObject* fromID (int id); - LDPolygon* getPolygon(); - bool isDestroyed() const { return m_isDestroyed; } - - // TODO: make this private! - QListWidgetItem* qObjListEntry; + static LDObject* getDefault (const LDObjectType type); + static void moveObjects (LDObjectList objs, const bool up); // TODO: move this to LDDocument? + static QString typeName (LDObjectType type); protected: virtual ~LDObject(); private: - Vertex m_coords[4]; + bool m_isHidden; + bool m_isSelected; bool m_isDestroyed; - - void chooseID(); + LDObject* m_parent; + LDDocument* m_document; + qint32 m_id; + LDColor m_color; + QColor m_randomColor; + Vertex m_coords[4]; }; -// -// Makes a new LDObject. This makes the shared pointer always use the custom -// deleter so that all deletions go through finalDelete(); -// template<typename T, typename... Args> T* LDSpawn (Args... args) { @@ -233,39 +178,20 @@ // class LDMatrixObject : public LDObject { - PROPERTY (public, Matrix, transform, setTransform, CUSTOM_WRITE) Vertex m_position; public: - LDMatrixObject (LDDocument* document = nullptr) : - LDObject (document), - m_position (Origin) {} - - LDMatrixObject (const Matrix& transform, const Vertex& pos, LDDocument* document = nullptr) : - LDObject (document), - m_transform (transform), - m_position (pos) {} - - inline const Vertex& position() const - { - return m_position; - } + LDMatrixObject (LDDocument* document = nullptr); + LDMatrixObject (const Matrix& transform, const Vertex& pos, LDDocument* document = nullptr); - void setCoordinate (const Axis ax, double value) - { - Vertex v = position(); + const Vertex& position() const; + void setCoordinate (const Axis ax, double value); + void setPosition (const Vertex& a); + const Matrix& transform() const; + void setTransform (const Matrix& value); - switch (ax) - { - case X: v.setX (value); break; - case Y: v.setY (value); break; - case Z: v.setZ (value); break; - } - - setPosition (v); - } - - void setPosition (const Vertex& a); +private: + Matrix m_transform; }; // @@ -282,15 +208,18 @@ LDOBJ_UNCOLORED LDOBJ_SCEMANTIC LDOBJ_NO_MATRIX - PROPERTY (public, QString, fileReferenced, setFileReferenced, STOCK_WRITE) - PROPERTY (private, QString, contents, setContents, STOCK_WRITE) - PROPERTY (private, QString, reason, setReason, STOCK_WRITE) public: - LDError (QString contents, QString reason, LDDocument* document = nullptr) : - LDObject (document), - m_contents (contents), - m_reason (reason) {} + LDError (QString contents, QString reason, LDDocument* document = nullptr); + QString reason() const; + QString contents() const; + QString fileReferenced() const; + void setFileReferenced (QString value); + +private: + QString m_fileReferenced; // If this error was caused by inability to open a file, what file was that? + QString m_contents; // The LDraw code that was being parsed + QString m_reason; }; // @@ -313,7 +242,6 @@ // class LDComment : public LDObject { - PROPERTY (public, QString, text, setText, STOCK_WRITE) LDOBJ (Comment) LDOBJ_NAME (comment) LDOBJ_VERTICES (0) @@ -322,16 +250,19 @@ LDOBJ_NO_MATRIX public: - LDComment (QString text, LDDocument* document = nullptr) : - LDObject (document), - m_text (text) {} + LDComment (QString text, LDDocument* document = nullptr); + QString text() const; + void setText (QString value); + +private: + QString m_text; }; // // // Represents a 0 BFC statement in the LDraw code. // -enum class BFCStatement +enum class BfcStatement { CertifyCCW, CCW, @@ -348,24 +279,27 @@ FirstValue = CertifyCCW }; -class LDBFC : public LDObject +class LDBfc : public LDObject { public: - LDOBJ (BFC) + LDOBJ (Bfc) LDOBJ_NAME (bfc) LDOBJ_VERTICES (0) LDOBJ_UNCOLORED - LDOBJ_CUSTOM_SCEMANTIC { return (statement() == BFCStatement::InvertNext); } + LDOBJ_CUSTOM_SCEMANTIC { return (statement() == BfcStatement::InvertNext); } LDOBJ_NO_MATRIX - PROPERTY (public, BFCStatement, statement, setStatement, STOCK_WRITE) public: - LDBFC (const BFCStatement type, LDDocument* document = nullptr) : - LDObject (document), - m_statement (type) {} + LDBfc (const BfcStatement type, LDDocument* document = nullptr); - // Statement strings - static const char* StatementStrings[]; + BfcStatement statement() const; + void setStatement (BfcStatement value); + QString statementToString() const; + + static QString statementToString (BfcStatement statement); + +private: + BfcStatement m_statement; }; // @@ -382,27 +316,19 @@ LDOBJ_DEFAULTCOLOR (MainColor) LDOBJ_SCEMANTIC LDOBJ_HAS_MATRIX - PROPERTY (public, LDDocument*, fileInfo, setFileInfo, CUSTOM_WRITE) public: - enum InlineFlag - { - DeepInline = (1 << 0), - CacheInline = (1 << 1), - RendererInline = (1 << 2), - DeepCacheInline = (DeepInline | CacheInline), - }; - - Q_DECLARE_FLAGS (InlineFlags, InlineFlag) - // Inlines this subfile. + LDDocument* fileInfo() const; + virtual void getVertices (QVector<Vertex>& verts) const override; LDObjectList inlineContents (bool deep, bool render); QList<LDPolygon> inlinePolygons(); - virtual void getVertices (QVector<Vertex>& verts) const override; + void setFileInfo (LDDocument* fileInfo); + +private: + LDDocument* m_fileInfo; }; -Q_DECLARE_OPERATORS_FOR_FLAGS (LDSubfile::InlineFlags) - // // LDLine // @@ -489,8 +415,7 @@ // // LDOverlay // -// Overlay image meta, stored in the header of parts so as to preserve overlay -// information. +// Overlay image meta, stored in the header of parts so as to preserve overlay information. // class LDOverlay : public LDObject { @@ -500,12 +425,28 @@ LDOBJ_UNCOLORED LDOBJ_NON_SCEMANTIC LDOBJ_NO_MATRIX - PROPERTY (public, int, camera, setCamera, STOCK_WRITE) - PROPERTY (public, int, x, setX, STOCK_WRITE) - PROPERTY (public, int, y, setY, STOCK_WRITE) - PROPERTY (public, int, width, setWidth, STOCK_WRITE) - PROPERTY (public, int, height, setHeight, STOCK_WRITE) - PROPERTY (public, QString, fileName, setFileName, STOCK_WRITE) + +public: + int camera() const; + QString fileName() const; + int height() const; + void setCamera (int value); + void setFileName (QString value); + void setHeight (int value); + void setWidth (int value); + void setX (int value); + void setY (int value); + int width() const; + int x() const; + int y() const; + +private: + int m_camera; + int m_x; + int m_y; + int m_width; + int m_height; + QString m_fileName; }; // Other common LDraw stuff
--- a/src/mainwindow.cpp Sun Sep 06 13:46:39 2015 +0300 +++ b/src/mainwindow.cpp Sun Sep 06 15:12:30 2015 +0300 @@ -376,6 +376,7 @@ // doesn't trigger selection updating so that the selection doesn't get lost // while this is done. g_isSelectionLocked = true; + m_objectsInList.clear(); for (int i = 0; i < ui.objectList->count(); ++i) delete ui.objectList->item (i); @@ -436,9 +437,9 @@ break; } - case OBJ_BFC: + case OBJ_Bfc: { - descr = LDBFC::StatementStrings[int (static_cast<LDBFC*> (obj)->statement())]; + descr = static_cast<LDBfc*> (obj)->statementToString(); break; } @@ -485,7 +486,7 @@ item->setForeground (obj->color().faceColor()); } - obj->qObjListEntry = item; + m_objectsInList.insert (obj, item); ui.objectList->insertItem (ui.objectList->count(), item); } @@ -504,7 +505,7 @@ return; LDObject* obj = selectedObjects().first(); - ui.objectList->scrollToItem (obj->qObjListEntry); + ui.objectList->scrollToItem (m_objectsInList[obj]); } // --------------------------------------------------------------------------------------------------------------------- @@ -524,7 +525,7 @@ { for (QListWidgetItem* item : items) { - if (item == obj->qObjListEntry) + if (item == m_objectsInList[obj]) { obj->select(); break; @@ -629,10 +630,12 @@ for (LDObject* obj : selectedObjects()) { - if (obj->qObjListEntry == nullptr) + QListWidgetItem** itempointer = m_objectsInList.find (obj); + + if (not itempointer) continue; - int row = ui.objectList->row (obj->qObjListEntry); + int row = ui.objectList->row (*itempointer); if (top == -1) { @@ -657,6 +660,7 @@ ui.objectList->model()->index (bottom, 0)); } + // Select multiple objects at once for performance reasons ui.objectList->selectionModel()->select (itemselect, QItemSelectionModel::ClearAndSelect); g_isSelectionLocked = false; } @@ -811,14 +815,8 @@ // void MainWindow::objectListDoubleClicked (QListWidgetItem* listitem) { - for (LDObject* it : m_currentDocument->objects()) - { - if (it->qObjListEntry == listitem) - { - AddObjectDialog::staticDialog (it->type(), it); - break; - } - } + LDObject* object = m_objectsInList.reverseLookup (listitem); + AddObjectDialog::staticDialog (object->type(), object); } // ---------------------------------------------------------------------------------------------------------------------
--- a/src/mainwindow.h Sun Sep 06 13:46:39 2015 +0300 +++ b/src/mainwindow.h Sun Sep 06 15:12:30 2015 +0300 @@ -27,6 +27,7 @@ #include "ldObject.h" #include "colors.h" #include "configurationvaluebag.h" +#include "doublemap.h" class MessageManager; class MainWindow; @@ -146,6 +147,7 @@ class QSettings* m_settings; QList<LDDocument*> m_documents; LDDocument* m_currentDocument; + DoubleMap<LDObject*, QListWidgetItem*> m_objectsInList; private slots: void selectionChanged();
--- a/src/primitives.cpp Sun Sep 06 13:46:39 2015 +0300 +++ b/src/primitives.cpp Sun Sep 06 15:12:30 2015 +0300 @@ -634,7 +634,7 @@ divs == HighResolution ? "48_" : "")) << LDSpawn<LDComment> (license) << LDSpawn<LDEmpty>() - << LDSpawn<LDBFC> (BFCStatement::CertifyCCW) + << LDSpawn<LDBfc> (BfcStatement::CertifyCCW) << LDSpawn<LDEmpty>(); document->openForEditing();
--- a/src/radioGroup.cpp Sun Sep 06 13:46:39 2015 +0300 +++ b/src/radioGroup.cpp Sun Sep 06 15:12:30 2015 +0300 @@ -95,7 +95,7 @@ // ============================================================================= // -void RadioGroup::addButton (const char* entry) +void RadioGroup::addButton (QString entry) { QRadioButton* button = new QRadioButton (entry); addButton (button);
--- a/src/radioGroup.h Sun Sep 06 13:46:39 2015 +0300 +++ b/src/radioGroup.h Sun Sep 06 15:12:30 2015 +0300 @@ -53,7 +53,7 @@ explicit RadioGroup (const QString& title, QList<char const*> entries, int const defaultId, const Qt::Orientation orient = Qt::Vertical, QWidget* parent = nullptr); - void addButton (const char* entry); + void addButton (QString entry); void addButton (QRadioButton* button); Iterator begin(); Iterator end();
--- a/src/toolsets/algorithmtoolset.cpp Sun Sep 06 13:46:39 2015 +0300 +++ b/src/toolsets/algorithmtoolset.cpp Sun Sep 06 15:12:30 2015 +0300 @@ -436,7 +436,7 @@ QString parentpath (currentDocument()->fullPath()); // BFC type of the new subfile - it shall inherit the BFC type of the parent document - BFCStatement bfctype (BFCStatement::NoCertify); + BfcStatement bfctype (BfcStatement::NoCertify); // Dirname of the new subfile QString subdirname (Dirname (parentpath)); @@ -521,9 +521,9 @@ // Determine the BFC winding type used in the main document - it is to // be carried over to the subfile. - for (LDObjectIterator<LDBFC> it (currentDocument()); it.isValid(); ++it) + for (LDObjectIterator<LDBfc> it (currentDocument()); it.isValid(); ++it) { - if (isOneOf (it->statement(), BFCStatement::CertifyCCW, BFCStatement::CertifyCW, BFCStatement::NoCertify)) + if (isOneOf (it->statement(), BfcStatement::CertifyCCW, BfcStatement::CertifyCW, BfcStatement::NoCertify)) { bfctype = it->statement(); break; @@ -550,7 +550,7 @@ objs << LDSpawn<LDComment> (license); objs << LDSpawn<LDEmpty>(); - objs << LDSpawn<LDBFC> (bfctype); + objs << LDSpawn<LDBfc> (bfctype); objs << LDSpawn<LDEmpty>(); doc->addObjects (objs);
--- a/src/toolsets/basictoolset.cpp Sun Sep 06 13:46:39 2015 +0300 +++ b/src/toolsets/basictoolset.cpp Sun Sep 06 15:12:30 2015 +0300 @@ -252,7 +252,7 @@ void BasicToolset::newBFC() { - AddObjectDialog::staticDialog (OBJ_BFC, nullptr); + AddObjectDialog::staticDialog (OBJ_Bfc, nullptr); } void BasicToolset::edit()