Wed, 23 Oct 2013 12:46:10 +0300
Merge branch 'master' into gl
Conflicts:
src/file.cpp
src/gldraw.cpp
src/gldraw.h
src/gui.cpp
src/ldtypes.cpp
src/src.pro
src/types.h
icons/visibility.png | file | annotate | diff | comparison | revisions | |
ldforge.pro | file | annotate | diff | comparison | revisions | |
legacy/checkboxgroup.cpp | file | annotate | diff | comparison | revisions | |
src/file.cpp | file | annotate | diff | comparison | revisions | |
src/gldraw.cpp | file | annotate | diff | comparison | revisions | |
src/gldraw.h | file | annotate | diff | comparison | revisions | |
src/gui.cpp | file | annotate | diff | comparison | revisions | |
src/ldtypes.cpp | file | annotate | diff | comparison | revisions | |
src/src.pro | file | annotate | diff | comparison | revisions | |
src/types.h | file | annotate | diff | comparison | revisions |
--- a/.gitignore Wed Sep 25 11:02:44 2013 +0300 +++ b/.gitignore Wed Oct 23 12:46:10 2013 +0300 @@ -1,8 +1,11 @@ build +build_debug +build_release ldforge.kdev4 -src/ui_*.h Makefile +Makefile.* ldforge +ldforge_debug *.dat debug_lastOutput .kdev_include_paths \ No newline at end of file
--- a/changelog.txt Wed Sep 25 11:02:44 2013 +0300 +++ b/changelog.txt Wed Oct 23 12:46:10 2013 +0300 @@ -1,5 +1,5 @@ ================================================= -== Changes in version 0.2.999-internal +== Changes in version 0.3-alpha ================================================= - Multiple files can now be kept open at the same time. A new list widget is on the left to contain the list of currently open files. @@ -9,6 +9,7 @@ - Converted the configuration code to use QSettings, in practice this means the configuration file moved to the registry under Windows and into ~/.config/LDForge under Linux. Unfortunately this means settings get lost during transition from version 0.2 and 0.3. +- Added a new editing mode for drawing circles. - Corrections to the primitive generator: - Fixed: "Hi-Res" was not prepended to the names of 48/ primitives. - Fixed: Checking the Hi-Res option would not allow segment values over 16. @@ -21,18 +22,25 @@ gives the opportunity to see the other config fields) - Added new action "Add History Line" for quickly inserting 0 !HISTORY lines to headers - Added new action "Go to line", default shortcut Ctrl-G. It should be obvious what it does. +- Added new actions "Hide" and "Reveal" which allow direct setting of objects' visibility setting instead of + toggling it. - Added support for logoed studs, this should satisfy Steffen. :p - Added support for '0 BFC CLIP' and '0 BFC NOCLIP' and added auto-correction from errorneous MLCAD syntax ('0 BFC CERTIFY CLIP'). +- The viewport now uses 7 sets of rotation/pan/zoom values, one for each camera. Changing these values + in one camera no longer affects other cameras. - When an external program is attempted to be used without a binary path defined, one will be asked with an input dialog instead of being told to go to configuration to set the path. - When adding edges with Intersector (which is done with Isecalc), the user is prompted for Isecalc's path now as well if necessary instead of just ignoring it and not adding the edgelines. +- Added a configuration option for line anti-aliasing. - BFC red/green view and black edges no longer default to true. - If the vertex snapper finds a vertex closer than 4 pixels, it likely is the vertex being looked for and the algorithm can terminate early, hopefully this will save a few cycles on large parts. - The camera icons now draw real tooltips instead of emulated ones. - Color icon border now reflects the color's edge color. +- Fixed: File loading would skip every 300th line. +- Fixed: LDForge would sometimes crash during startup over uninitialized data in the GL renderer. - Fixed: The message log was still written with black text with dark backgrounds. =================================================
--- a/ldforge.pro Wed Sep 25 11:02:44 2013 +0300 +++ b/ldforge.pro Wed Oct 23 12:46:10 2013 +0300 @@ -12,7 +12,6 @@ RC_FILE = ldforge.rc RESOURCES = ldforge.qrc RCC_DIR = ./build/ -OBJECTS_DIR = ./build/ MOC_DIR = ./build/ RCC_DIR = ./build/ UI_DIR = ./build/ @@ -21,7 +20,18 @@ FORMS = ui/*.ui QT += opengl network QMAKE_CXXFLAGS += -std=c++0x +CONFIG += debug_and_release + +CONFIG (debug, debug|release) { + TARGET = ldforge_debug + DEFINES += DEBUG + OBJECTS_DIR = ./build_debug/ +} else { + TARGET = ldforge + DEFINES += RELEASE + OBJECTS_DIR = ./build_release/ +} unix { LIBS += -lGLU -} \ No newline at end of file +}
--- a/ldforge.qrc Wed Sep 25 11:02:44 2013 +0300 +++ b/ldforge.qrc Wed Oct 23 12:46:10 2013 +0300 @@ -66,6 +66,7 @@ <file>./icons/line.png</file> <file>./icons/mail.png</file> <file>./icons/make-borders.png</file> + <file>./icons/mode-circle.png</file> <file>./icons/mode-draw.png</file> <file>./icons/mode-select.png</file> <file>./icons/move-x-neg.png</file> @@ -98,7 +99,9 @@ <file>./icons/uncolorize.png</file> <file>./icons/undo.png</file> <file>./icons/vertex.png</file> - <file>./icons/visibility.png</file> + <file>./icons/visibility-hide.png</file> + <file>./icons/visibility-show.png</file> + <file>./icons/visibility-toggle.png</file> <file>./icons/wireframe.png</file> <file>./icons/ytruder.png</file> <file>data/primitive-categories.cfg</file>
--- a/legacy/checkboxgroup.cpp Wed Sep 25 11:02:44 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -// ============================================================================= -// CheckBoxGroup -// ============================================================================= -class CheckBoxGroup : public QGroupBox { - Q_OBJECT - -public: - CheckBoxGroup (const char* label, Qt::Orientation orient = Qt::Horizontal, QWidget* parent = null); - - void addCheckBox (const char* label, int key, bool checked = false); - vector<int> checkedValues () const; - QCheckBox* getCheckBox (int key); - bool buttonChecked (int key); - -signals: - void selectionChanged (); - -private: - QBoxLayout* m_layout; - std::map<int, QCheckBox*> m_vals; - -private slots: - void buttonChanged (); -}; - -CheckBoxGroup::CheckBoxGroup (const char* label, Qt::Orientation orient, QWidget* parent) : QGroupBox (parent) { - m_layout = new QBoxLayout (makeDirection (orient)); - setTitle (label); - setLayout (m_layout); -} - -void CheckBoxGroup::addCheckBox (const char* label, int key, bool checked) { - if (m_vals.find (key) != m_vals.end ()) - return; - - QCheckBox* box = new QCheckBox (label); - box->setChecked (checked); - - m_vals[key] = box; - m_layout->addWidget (box); - - connect (box, SIGNAL (stateChanged (int)), this, SLOT (buttonChanged ())); -} - -vector<int> CheckBoxGroup::checkedValues () const { - vector<int> vals; - - for (const auto& kv : m_vals) - if (kv.second->isChecked ()) - vals << kv.first; - - return vals; -} - -QCheckBox* CheckBoxGroup::getCheckBox (int key) { - return m_vals[key]; -} - -void CheckBoxGroup::buttonChanged () { - emit selectionChanged (); -} - -bool CheckBoxGroup::buttonChecked (int key) { - return m_vals[key]->isChecked (); -} - -CheckBoxGroup* makeAxesBox() { - CheckBoxGroup* cbg_axes = new CheckBoxGroup ("Axes", Qt::Horizontal); - cbg_axes->addCheckBox ("X", X); - cbg_axes->addCheckBox ("Y", Y); - cbg_axes->addCheckBox ("Z", Z); - return cbg_axes; -} \ No newline at end of file
--- a/src/actions.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/actions.h Wed Oct 23 12:46:10 2013 +0300 @@ -58,6 +58,7 @@ act (SelectByType) act (ModeDraw) act (ModeSelect) +act (ModeCircle) act (SetDrawDepth) act (SetColor) act (Autocolor) @@ -71,7 +72,9 @@ act (Borders) act (CornerVerts) act (RoundCoordinates) -act (Visibility) +act (VisibilityHide) +act (VisibilityReveal) +act (VisibilityToggle) act (ReplaceCoords) act (Flip) act (Demote)
--- a/src/addObjectDialog.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/addObjectDialog.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -34,374 +34,379 @@ #include "widgets.h" #include "misc.h" #include "primitives.h" +#include "moc_addObjectDialog.cpp" // ============================================================================= // ----------------------------------------------------------------------------- -class SubfileListItem : public QTreeWidgetItem { - PROPERTY (Primitive*, primInfo, setPrimInfo) - -public: - SubfileListItem (QTreeWidgetItem* parent, Primitive* info) : - QTreeWidgetItem (parent), m_primInfo (info) {} - SubfileListItem (QTreeWidget* parent, Primitive* info) : - QTreeWidgetItem (parent), m_primInfo (info) {} +class SubfileListItem : public QTreeWidgetItem +{ PROPERTY (Primitive*, primInfo, setPrimInfo) + + public: + SubfileListItem (QTreeWidgetItem* parent, Primitive* info) : + QTreeWidgetItem (parent), m_primInfo (info) {} + SubfileListItem (QTreeWidget* parent, Primitive* info) : + QTreeWidgetItem (parent), m_primInfo (info) {} }; // ============================================================================= // ----------------------------------------------------------------------------- -AddObjectDialog::AddObjectDialog (const LDObject::Type type, LDObject* obj, QWidget* parent) : QDialog (parent) { - setlocale (LC_ALL, "C"); - +AddObjectDialog::AddObjectDialog (const LDObject::Type type, LDObject* obj, QWidget* parent) : QDialog (parent) +{ setlocale (LC_ALL, "C"); + short coordCount = 0; str typeName = LDObject::typeName (type); - - switch (type) { - case LDObject::Comment: - le_comment = new QLineEdit; - if (obj) - le_comment->setText (static_cast<LDComment*> (obj)->text); - - le_comment->setMinimumWidth (384); - break; - - case LDObject::Line: - coordCount = 6; - break; - - case LDObject::Triangle: - coordCount = 9; - break; - - case LDObject::Quad: - case LDObject::CndLine: - coordCount = 12; - break; - - case LDObject::Vertex: - coordCount = 3; - break; - - case LDObject::BFC: - rb_bfcType = new RadioGroup ("Statement", {}, 0, Qt::Vertical); - - for (int i = 0; i < LDBFC::NumStatements; ++i) { - // Separate these in two columns - if (i == LDBFC::NumStatements / 2) - rb_bfcType->rowBreak(); - - rb_bfcType->addButton (LDBFC::statements[i]); - } - - if (obj) - rb_bfcType->setValue ((int) static_cast<LDBFC*> (obj)->type); - break; - - case LDObject::Subfile: - coordCount = 3; - - // If the primitive lister is busy writing data, we have to wait - // for that to happen first. This should be quite considerably rare. - while (primitiveLoaderBusy()) - ; - - tw_subfileList = new QTreeWidget(); - tw_subfileList->setHeaderLabel (tr ("Primitives")); - - for (PrimitiveCategory& cat : g_PrimitiveCategories) { - SubfileListItem* parentItem = new SubfileListItem (tw_subfileList, null); - parentItem->setText (0, cat.name()); - QList<QTreeWidgetItem*> subfileItems; - - for (Primitive& prim : cat.prims) { - SubfileListItem* item = new SubfileListItem (parentItem, &prim); - item->setText (0, fmt ("%1 - %2", prim.name, prim.title)); - subfileItems << item; - - // If this primitive is the one the current object points to, - // select it by default - if (obj && static_cast<LDSubfile*> (obj)->fileInfo()->name() == prim.name) - tw_subfileList->setCurrentItem (item); + + switch (type) + { case LDObject::Comment: + le_comment = new QLineEdit; + + if (obj) + le_comment->setText (static_cast<LDComment*> (obj)->text); + + le_comment->setMinimumWidth (384); + break; + + case LDObject::Line: + coordCount = 6; + break; + + case LDObject::Triangle: + coordCount = 9; + break; + + case LDObject::Quad: + case LDObject::CndLine: + coordCount = 12; + break; + + case LDObject::Vertex: + coordCount = 3; + break; + + case LDObject::BFC: + rb_bfcType = new RadioGroup ("Statement", {}, 0, Qt::Vertical); + + for (int i = 0; i < LDBFC::NumStatements; ++i) + { // Separate these in two columns + if (i == LDBFC::NumStatements / 2) + rb_bfcType->rowBreak(); + + rb_bfcType->addButton (LDBFC::statements[i]); } - - tw_subfileList->addTopLevelItem (parentItem); - } - - connect (tw_subfileList, SIGNAL (itemSelectionChanged()), this, SLOT (slot_subfileTypeChanged())); - lb_subfileName = new QLabel ("File:"); - le_subfileName = new QLineEdit; - le_subfileName->setFocus(); - - if (obj) { - LDSubfile* ref = static_cast<LDSubfile*> (obj); - le_subfileName->setText (ref->fileInfo()->name()); - } - break; - - default: - critical (fmt ("Unhandled LDObject type %1 (%2) in AddObjectDialog", (int) type, typeName)); - return; + + if (obj) + rb_bfcType->setValue ( (int) static_cast<LDBFC*> (obj)->type); + + break; + + case LDObject::Subfile: + coordCount = 3; + + // If the primitive lister is busy writing data, we have to wait + // for that to happen first. This should be quite considerably rare. + while (primitiveLoaderBusy()) + ; + + tw_subfileList = new QTreeWidget(); + tw_subfileList->setHeaderLabel (tr ("Primitives")); + + for (PrimitiveCategory & cat : g_PrimitiveCategories) + { SubfileListItem* parentItem = new SubfileListItem (tw_subfileList, null); + parentItem->setText (0, cat.name()); + QList<QTreeWidgetItem*> subfileItems; + + for (Primitive & prim : cat.prims) + { SubfileListItem* item = new SubfileListItem (parentItem, &prim); + item->setText (0, fmt ("%1 - %2", prim.name, prim.title)); + subfileItems << item; + + // If this primitive is the one the current object points to, + // select it by default + if (obj && static_cast<LDSubfile*> (obj)->fileInfo()->name() == prim.name) + tw_subfileList->setCurrentItem (item); + } + + tw_subfileList->addTopLevelItem (parentItem); + } + + connect (tw_subfileList, SIGNAL (itemSelectionChanged()), this, SLOT (slot_subfileTypeChanged())); + lb_subfileName = new QLabel ("File:"); + le_subfileName = new QLineEdit; + le_subfileName->setFocus(); + + if (obj) + { LDSubfile* ref = static_cast<LDSubfile*> (obj); + le_subfileName->setText (ref->fileInfo()->name()); + } + + break; + + default: + critical (fmt ("Unhandled LDObject type %1 (%2) in AddObjectDialog", (int) type, typeName)); + return; } - + QPixmap icon = getIcon (fmt ("add-%1", typeName)); LDObject* defaults = LDObject::getDefault (type); - + lb_typeIcon = new QLabel; lb_typeIcon->setPixmap (icon); - + // Show a color edit dialog for the types that actually use the color - if (defaults->isColored()) { - if (obj != null) + if (defaults->isColored()) + { if (obj != null) colnum = obj->color(); else colnum = (type == LDObject::CndLine || type == LDObject::Line) ? edgecolor : maincolor; - + pb_color = new QPushButton; setButtonBackground (pb_color, colnum); connect (pb_color, SIGNAL (clicked()), this, SLOT (slot_colorButtonClicked())); } - - for (short i = 0; i < coordCount; ++i) { - dsb_coords[i] = new QDoubleSpinBox; + + for (short i = 0; i < coordCount; ++i) + { dsb_coords[i] = new QDoubleSpinBox; dsb_coords[i]->setDecimals (5); dsb_coords[i]->setMinimum (-10000.0); dsb_coords[i]->setMaximum (10000.0); } - + QGridLayout* const layout = new QGridLayout; layout->addWidget (lb_typeIcon, 0, 0); - - switch (type) { - case LDObject::Line: - case LDObject::CndLine: - case LDObject::Triangle: - case LDObject::Quad: - // Apply coordinates - if (obj) { - for (short i = 0; i < coordCount / 3; ++i) - for (short j = 0; j < 3; ++j) - dsb_coords[(i * 3) + j]->setValue (obj->getVertex (i).coord (j)); - } - break; - - case LDObject::Comment: - layout->addWidget (le_comment, 0, 1); - break; - - case LDObject::BFC: - layout->addWidget (rb_bfcType, 0, 1); - break; - - case LDObject::Subfile: - layout->addWidget (tw_subfileList, 1, 1, 1, 2); - layout->addWidget (lb_subfileName, 2, 1); - layout->addWidget (le_subfileName, 2, 2); - break; - - default: - break; + + switch (type) + { case LDObject::Line: + case LDObject::CndLine: + case LDObject::Triangle: + case LDObject::Quad: + + // Apply coordinates + if (obj) + { for (short i = 0; i < coordCount / 3; ++i) + for (short j = 0; j < 3; ++j) + dsb_coords[ (i * 3) + j]->setValue (obj->getVertex (i).coord (j)); + } + + break; + + case LDObject::Comment: + layout->addWidget (le_comment, 0, 1); + break; + + case LDObject::BFC: + layout->addWidget (rb_bfcType, 0, 1); + break; + + case LDObject::Subfile: + layout->addWidget (tw_subfileList, 1, 1, 1, 2); + layout->addWidget (lb_subfileName, 2, 1); + layout->addWidget (le_subfileName, 2, 2); + break; + + default: + break; } - - if (defaults->hasMatrix()) { - LDMatrixObject* mo = obj ? dynamic_cast<LDMatrixObject*> (obj) : null; - + + if (defaults->hasMatrix()) + { LDMatrixObject* mo = dynamic_cast<LDMatrixObject*> (obj); + QLabel* lb_matrix = new QLabel ("Matrix:"); le_matrix = new QLineEdit; // le_matrix->setValidator (new QDoubleValidator); matrix defaultMatrix = g_identity; - - if (mo) { - for (const Axis ax : g_Axes) - dsb_coords[ax]->setValue (mo->position()[ax]); - + + if (mo) + { for (const Axis ax : g_Axes) + dsb_coords[ax]->setValue (mo->position() [ax]); + defaultMatrix = mo->transform(); } - + le_matrix->setText (defaultMatrix.stringRep()); layout->addWidget (lb_matrix, 4, 1); layout->addWidget (le_matrix, 4, 2, 1, 3); } - + if (defaults->isColored()) layout->addWidget (pb_color, 1, 0); - - if (coordCount > 0) { - QGridLayout* const qCoordLayout = new QGridLayout; - + + if (coordCount > 0) + { QGridLayout* const qCoordLayout = new QGridLayout; + for (short i = 0; i < coordCount; ++i) qCoordLayout->addWidget (dsb_coords[i], (i / 3), (i % 3)); - + layout->addLayout (qCoordLayout, 0, 1, (coordCount / 3), 3); } - + QDialogButtonBox* bbx_buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QWidget::connect (bbx_buttons, SIGNAL (accepted()), this, SLOT (accept())); QWidget::connect (bbx_buttons, SIGNAL (rejected()), this, SLOT (reject())); layout->addWidget (bbx_buttons, 5, 0, 1, 4); setLayout (layout); setWindowTitle (fmt (tr ("Edit %1"), typeName)); - + setWindowIcon (icon); delete defaults; } // ============================================================================= // ----------------------------------------------------------------------------- -void AddObjectDialog::setButtonBackground (QPushButton* button, short colnum) { - LDColor* col = getColor (colnum); - +void AddObjectDialog::setButtonBackground (QPushButton* button, short colnum) +{ LDColor* col = getColor (colnum); + button->setIcon (getIcon ("palette")); button->setAutoFillBackground (true); - + if (col) button->setStyleSheet (fmt ("background-color: %1", col->hexcode)); } // ============================================================================= // ----------------------------------------------------------------------------- -str AddObjectDialog::currentSubfileName() { - SubfileListItem* item = static_cast<SubfileListItem*> (tw_subfileList->currentItem()); - +str AddObjectDialog::currentSubfileName() +{ SubfileListItem* item = static_cast<SubfileListItem*> (tw_subfileList->currentItem()); + if (item->primInfo() == null) return ""; // selected a heading - + return item->primInfo()->name; } // ============================================================================= // ----------------------------------------------------------------------------- -void AddObjectDialog::slot_colorButtonClicked() { - ColorSelector::getColor (colnum, colnum, this); +void AddObjectDialog::slot_colorButtonClicked() +{ ColorSelector::getColor (colnum, colnum, this); setButtonBackground (pb_color, colnum); } // ============================================================================= // ----------------------------------------------------------------------------- -void AddObjectDialog::slot_subfileTypeChanged() { - str name = currentSubfileName(); - +void AddObjectDialog::slot_subfileTypeChanged() +{ str name = currentSubfileName(); + if (name.length() > 0) le_subfileName->setText (name); } // ============================================================================= // ----------------------------------------------------------------------------- -template<class T> static T* initObj (LDObject*& obj) { - if (obj == null) +template<class T> static T* initObj (LDObject*& obj) +{ if (obj == null) obj = new T; - + return static_cast<T*> (obj); } // ============================================================================= // ----------------------------------------------------------------------------- -void AddObjectDialog::staticDialog (const LDObject::Type type, LDObject* obj) { - setlocale (LC_ALL, "C"); - +void AddObjectDialog::staticDialog (const LDObject::Type type, LDObject* obj) +{ setlocale (LC_ALL, "C"); + // FIXME: Redirect to Edit Raw if (obj && obj->getType() == LDObject::Error) return; - + if (type == LDObject::Empty) return; // Nothing to edit with empties - + const bool newObject = (obj == null); matrix transform = g_identity; AddObjectDialog dlg (type, obj); - - if (obj) - assert (obj->getType() == type); - + + assert (!obj || obj->getType() == type); + if (dlg.exec() == false) return; - - if (type == LDObject::Subfile) { - QStringList matrixstrvals = dlg.le_matrix->text().split (" "); - - if (matrixstrvals.size() == 9) { - double matrixvals[9]; + + if (type == LDObject::Subfile) + { QStringList matrixstrvals = dlg.le_matrix->text().split (" ", QString::SkipEmptyParts); + + if (matrixstrvals.size() == 9) + { double matrixvals[9]; int i = 0; - + for (str val : matrixstrvals) matrixvals[i++] = val.toFloat(); - + transform = matrix (matrixvals); } } - - switch (type) { - case LDObject::Comment: - { - LDComment* comm = initObj<LDComment> (obj); + + switch (type) + { case LDObject::Comment: + { LDComment* comm = initObj<LDComment> (obj); comm->text = dlg.le_comment->text(); } break; - - case LDObject::Line: - case LDObject::Triangle: - case LDObject::Quad: - case LDObject::CndLine: - if (!obj) - obj = LDObject::getDefault (type); - - for (short i = 0; i < obj->vertices(); ++i) { - vertex v; + + case LDObject::Line: + case LDObject::Triangle: + case LDObject::Quad: + case LDObject::CndLine: + + if (!obj) + obj = LDObject::getDefault (type); + + for (short i = 0; i < obj->vertices(); ++i) + { vertex v; + for (const Axis ax : g_Axes) - v[ax] = dlg.dsb_coords[(i * 3) + ax]->value(); - - obj->setVertex (i, v); - } - break; - - case LDObject::BFC: - { - LDBFC* bfc = initObj<LDBFC> (obj); + v[ax] = dlg.dsb_coords[ (i * 3) + ax]->value(); + + obj->setVertex (i, v); + } + + break; + + case LDObject::BFC: + { LDBFC* bfc = initObj<LDBFC> (obj); bfc->type = (LDBFC::Type) dlg.rb_bfcType->value(); } break; - - case LDObject::Vertex: - { - LDVertex* vert = initObj<LDVertex> (obj); - - for (const Axis ax : g_Axes) + + case LDObject::Vertex: + { LDVertex* vert = initObj<LDVertex> (obj); + + for (const Axis ax : g_Axes) vert->pos[ax] = dlg.dsb_coords[ax]->value(); } break; - - case LDObject::Subfile: - { - str name = dlg.le_subfileName->text(); + + case LDObject::Subfile: + { str name = dlg.le_subfileName->text(); + if (name.length() == 0) return; // no subfile filename - + LDFile* file = getFile (name); - if (!file) { - critical (fmt ("Couldn't open `%1': %2", name, strerror (errno))); + + if (!file) + { critical (fmt ("Couldn't open `%1': %2", name, strerror (errno))); return; } - + LDSubfile* ref = initObj<LDSubfile> (obj); - + for (const Axis ax : g_Axes) ref->setCoordinate (ax, dlg.dsb_coords[ax]->value()); - + ref->setTransform (transform); ref->setFileInfo (file); } break; - - default: - break; + + default: + break; } - + if (obj->isColored()) obj->setColor (dlg.colnum); - - if (newObject) { - ulong idx = g_win->getInsertionPoint(); + + if (newObject) + { int idx = g_win->getInsertionPoint(); LDFile::current()->insertObj (idx, obj); } - + g_win->fullRefresh(); } -#include "moc_addObjectDialog.cpp"
--- a/src/addObjectDialog.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/addObjectDialog.h Wed Oct 23 12:46:10 2013 +0300 @@ -16,8 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef ZZ_ADDOBJECTDIALOG_H -#define ZZ_ADDOBJECTDIALOG_H +#ifndef LDFORGE_ADDOBJECTDIALOG_H +#define LDFORGE_ADDOBJECTDIALOG_H #include <QDialog> #include "ldtypes.h" @@ -31,42 +31,42 @@ class QTreeWidget; class QDoubleSpinBox; -class AddObjectDialog : public QDialog { - Q_OBJECT - -public: - AddObjectDialog (const LDObject::Type type, LDObject* obj, QWidget* parent = null); - static void staticDialog (const LDObject::Type type, LDObject* obj); - - QLabel* lb_typeIcon; - - // Comment line edit - QLineEdit* le_comment; - - // Coordinate edits for.. anything with coordinates, really. - QDoubleSpinBox* dsb_coords[12]; - - // Color selection dialog button - QPushButton* pb_color; - - // BFC-related widgets - RadioGroup* rb_bfcType; - - // Subfile stuff - QTreeWidget* tw_subfileList; - QLineEdit* le_subfileName; - QLabel* lb_subfileName; - QLineEdit* le_matrix; - -private: - void setButtonBackground (QPushButton* button, short color); - str currentSubfileName(); - - short colnum; - -private slots: - void slot_colorButtonClicked(); - void slot_subfileTypeChanged(); +class AddObjectDialog : public QDialog +{ Q_OBJECT + + public: + AddObjectDialog (const LDObject::Type type, LDObject* obj, QWidget* parent = null); + static void staticDialog (const LDObject::Type type, LDObject* obj); + + QLabel* lb_typeIcon; + + // Comment line edit + QLineEdit* le_comment; + + // Coordinate edits for.. anything with coordinates, really. + QDoubleSpinBox* dsb_coords[12]; + + // Color selection dialog button + QPushButton* pb_color; + + // BFC-related widgets + RadioGroup* rb_bfcType; + + // Subfile stuff + QTreeWidget* tw_subfileList; + QLineEdit* le_subfileName; + QLabel* lb_subfileName; + QLineEdit* le_matrix; + + private: + void setButtonBackground (QPushButton* button, short color); + str currentSubfileName(); + + short colnum; + + private slots: + void slot_colorButtonClicked(); + void slot_subfileTypeChanged(); }; -#endif // ZZ_ADDOBJECTDIALOG_H \ No newline at end of file +#endif // LDFORGE_ADDOBJECTDIALOG_H
--- a/src/colorSelectDialog.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/colorSelectDialog.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -31,6 +31,7 @@ #include "config.h" #include "misc.h" #include "ui_colorsel.h" +#include "moc_colorSelectDialog.cpp" static const int g_numColumns = 16; static const short g_squareSize = 32; @@ -40,78 +41,78 @@ // ============================================================================= // ----------------------------------------------------------------------------- -ColorSelector::ColorSelector (short defval, QWidget* parent) : QDialog (parent) { - // Remove the default color if it's invalid +ColorSelector::ColorSelector (short defval, QWidget* parent) : QDialog (parent) +{ // Remove the default color if it's invalid if (!::getColor (defval)) defval = -1; - + m_firstResize = true; ui = new Ui_ColorSelUI; ui->setupUi (this); - + m_scene = new QGraphicsScene; ui->viewport->setScene (m_scene); setSelection (::getColor (defval)); - + // not really an icon but eh m_scene->setBackgroundBrush (getIcon ("checkerboard")); drawScene(); - + int width = viewportWidth(); ui->viewport->setMinimumWidth (width); ui->viewport->setMaximumWidth (width); - + drawColorInfo(); } // ============================================================================= // ----------------------------------------------------------------------------- -ColorSelector::~ColorSelector() { - delete ui; +ColorSelector::~ColorSelector() +{ delete ui; } // ============================================================================= // ----------------------------------------------------------------------------- -void ColorSelector::drawScene() { - const int numCols = g_numColumns; +void ColorSelector::drawScene() +{ const int numCols = g_numColumns; const int square = g_squareSize; const int g_maxHeight = (numRows() * square); QRect sceneRect (0, 0, viewportWidth(), g_maxHeight); - + m_scene->setSceneRect (sceneRect); ui->viewport->setSceneRect (sceneRect); - + const double penWidth = 1.0f; - + // Draw the color rectangles. m_scene->clear(); - - for (short i = 0; i < MAX_COLORS; ++i) { - LDColor* info = ::getColor (i); - + + for (short i = 0; i < MAX_COLORS; ++i) + { LDColor* info = ::getColor (i); + if (!info) continue; - + const double x = (i % numCols) * square; const double y = (i / numCols) * square; const double w = square - (penWidth / 2); - + QColor col = info->faceColor; - - if (i == maincolor) { - // Use the user preferences for main color here + + if (i == maincolor) + { // Use the user preferences for main color here col = QColor (gl_maincolor); col.setAlpha (gl_maincolor_alpha * 255.0f); } - + QPen pen (info->edgeColor, penWidth, Qt::SolidLine, Qt::FlatCap, Qt::MiterJoin); m_scene->addRect (x, y, w, w, pen, col); QGraphicsTextItem* numtext = m_scene->addText (fmt ("%1", i)); - numtext->setDefaultTextColor ((luma (col) < 80) ? Qt::white : Qt::black); + numtext->setDefaultTextColor ( (luma (col) < 80) ? Qt::white : Qt::black); numtext->setPos (x, y); - - if (sel() && i == sel()->index) { - auto curspic = m_scene->addPixmap (getIcon ("colorcursor")); + + if (sel() && i == sel()->index) + { auto curspic = m_scene->addPixmap (getIcon ("colorcursor")); curspic->setPos (x, y); } } @@ -119,62 +120,62 @@ // ============================================================================= // ----------------------------------------------------------------------------- -int ColorSelector::numRows() const { - return (MAX_COLORS / g_numColumns); +int ColorSelector::numRows() const +{ return (MAX_COLORS / g_numColumns); } // ============================================================================= // ----------------------------------------------------------------------------- -int ColorSelector::viewportWidth() const { - return g_numColumns * g_squareSize + 21; +int ColorSelector::viewportWidth() const +{ return g_numColumns * g_squareSize + 21; } // ============================================================================= // ----------------------------------------------------------------------------- -void ColorSelector::drawColorInfo() { - if (!sel()) { - ui->colorLabel->setText ("---"); +void ColorSelector::drawColorInfo() +{ if (!sel()) + { ui->colorLabel->setText ("---"); return; } - + ui->colorLabel->setText (fmt ("%1 - %2", sel()->index, sel()->name)); } // ============================================================================= // ----------------------------------------------------------------------------- -void ColorSelector::resizeEvent (QResizeEvent* ev) { - // If this is the first resize, check if we need to scroll down to see the +void ColorSelector::resizeEvent (QResizeEvent* ev) +{ // If this is the first resize, check if we need to scroll down to see the // currently selected color. We cannot do this in the constructor because the // height is not set properly there. - if (m_firstResize) { - int visibleColors = (ui->viewport->height() / g_squareSize) * g_numColumns; - - if (sel() && sel()->index >= visibleColors) { - int y = (sel()->index / g_numColumns) * g_squareSize; + if (m_firstResize) + { int visibleColors = (ui->viewport->height() / g_squareSize) * g_numColumns; + + if (sel() && sel()->index >= visibleColors) + { int y = (sel()->index / g_numColumns) * g_squareSize; ui->viewport->verticalScrollBar()->setValue (y); } - + m_firstResize = false; } - + (void) ev; drawScene(); } // ============================================================================= // ----------------------------------------------------------------------------- -void ColorSelector::mousePressEvent (QMouseEvent* event) { - QPointF scenepos = ui->viewport->mapToScene (event->pos()); - - ulong x = ((ulong) scenepos.x() - (g_squareSize / 2)) / g_squareSize; - ulong y = ((ulong) scenepos.y() - (g_squareSize / 2)) / g_squareSize; - ulong idx = (y * g_numColumns) + x; - +void ColorSelector::mousePressEvent (QMouseEvent* event) +{ QPointF scenepos = ui->viewport->mapToScene (event->pos()); + + int x = (scenepos.x() - (g_squareSize / 2)) / g_squareSize; + int y = (scenepos.y() - (g_squareSize / 2)) / g_squareSize; + int idx = (y * g_numColumns) + x; + LDColor* col = ::getColor (idx); - + if (!col) return; - + setSelection (col); drawScene(); drawColorInfo(); @@ -182,14 +183,13 @@ // ============================================================================= // ----------------------------------------------------------------------------- -bool ColorSelector::getColor (short& val, short int defval, QWidget* parent) { - ColorSelector dlg (defval, parent); - - if (dlg.exec() && dlg.sel() != null) { - val = dlg.sel()->index; +bool ColorSelector::getColor (short& val, short int defval, QWidget* parent) +{ ColorSelector dlg (defval, parent); + + if (dlg.exec() && dlg.sel() != null) + { val = dlg.sel()->index; return true; } - + return false; -} -#include "moc_colorSelectDialog.cpp" +} \ No newline at end of file
--- a/src/colorSelectDialog.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/colorSelectDialog.h Wed Oct 23 12:46:10 2013 +0300 @@ -16,8 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef COLORSELECTOR_H -#define COLORSELECTOR_H +#ifndef LDFORGE_COLORSELECTOR_H +#define LDFORGE_COLORSELECTOR_H #include <QDialog> #include "common.h" @@ -26,28 +26,28 @@ class Ui_ColorSelUI; class QGraphicsScene; -class ColorSelector : public QDialog { - Q_OBJECT +class ColorSelector : public QDialog +{ Q_OBJECT READ_PROPERTY (LDColor*, sel, setSelection) - -public: - explicit ColorSelector (short defval = -1, QWidget* parent = null); - virtual ~ColorSelector(); - static bool getColor (short& val, short defval = -1, QWidget* parent = null); - -protected: - void mousePressEvent (QMouseEvent* event); - void resizeEvent (QResizeEvent* ev); - -private: - Ui_ColorSelUI* ui; - QGraphicsScene* m_scene; - bool m_firstResize; - - int numRows() const; - int viewportWidth() const; - void drawScene(); - void drawColorInfo(); + + public: + explicit ColorSelector (short defval = -1, QWidget* parent = null); + virtual ~ColorSelector(); + static bool getColor (short& val, short defval = -1, QWidget* parent = null); + + protected: + void mousePressEvent (QMouseEvent* event); + void resizeEvent (QResizeEvent* ev); + + private: + Ui_ColorSelUI* ui; + QGraphicsScene* m_scene; + bool m_firstResize; + + int numRows() const; + int viewportWidth() const; + void drawScene(); + void drawColorInfo(); }; -#endif // COLORSELECTOR_H \ No newline at end of file +#endif // LDFORGE_COLORSELECTOR_H
--- a/src/colors.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/colors.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -33,49 +33,46 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void initColors() { - LDColor* col; - print ("%1: initializing color information.\n", __func__); - +void initColors() +{ LDColor* col; + log ("%1: initializing color information.\n", __func__); + // Always make sure there's 16 and 24 available. They're special like that. col = new LDColor; - col->faceColor = - col->hexcode = "#AAAAAA"; + col->faceColor = col->hexcode = "#AAAAAA"; col->edgeColor = Qt::black; g_LDColors[maincolor] = col; - + col = new LDColor; - col->faceColor = - col->edgeColor = - col->hexcode = "#000000"; + col->faceColor = col->edgeColor = col->hexcode = "#000000"; g_LDColors[edgecolor] = col; - + parseLDConfig(); } // ============================================================================= // ----------------------------------------------------------------------------- -LDColor* getColor (short colnum) { - // Check bounds +LDColor* getColor (short colnum) +{ // Check bounds if (colnum < 0 || colnum >= MAX_COLORS) return null; - + return g_LDColors[colnum]; } // ============================================================================= // ----------------------------------------------------------------------------- -void setColor (short colnum, LDColor* col) { - if (colnum < 0 || colnum >= MAX_COLORS) +void setColor (short colnum, LDColor* col) +{ if (colnum < 0 || colnum >= MAX_COLORS) return; - + g_LDColors[colnum] = col; } // ============================================================================= // ----------------------------------------------------------------------------- -int luma (QColor& col) { - return (0.2126f * col.red()) + - (0.7152f * col.green()) + - (0.0722f * col.blue()); -} \ No newline at end of file +int luma (QColor& col) +{ return (0.2126f * col.red()) + + (0.7152f * col.green()) + + (0.0722f * col.blue()); +}
--- a/src/colors.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/colors.h Wed Oct 23 12:46:10 2013 +0300 @@ -16,19 +16,19 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef COLORS_H -#define COLORS_H +#ifndef LDFORGE_COLORS_H +#define LDFORGE_COLORS_H #include <QColor> #include "common.h" #define MAX_COLORS 512 -class LDColor { -public: - str name, hexcode; - QColor faceColor, edgeColor; - short index; +class LDColor +{ public: + str name, hexcode; + QColor faceColor, edgeColor; + short index; }; void initColors(); @@ -42,4 +42,4 @@ static const short maincolor = 16; static const short edgecolor = 24; -#endif // COLORS_H \ No newline at end of file +#endif // LDFORGE_COLORS_H
--- a/src/common.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/common.h Wed Oct 23 12:46:10 2013 +0300 @@ -20,12 +20,11 @@ // This file is included one way or another in every source file of LDForge. // Stuff defined and included here is universally included. -#ifndef COMMON_H -#define COMMON_H +#ifndef LDFORGE_COMMON_H +#define LDFORGE_COMMON_H #include <stdio.h> #include <stdlib.h> -#include <assert.h> #include <stdint.h> #include <stdarg.h> #include <QString> @@ -48,40 +47,30 @@ // RC Number for BUILD_RC #define RC_NUMBER 0 -// Uncomment for portable build... maybe it's time to move to cmake? -// #define PORTABLE +// ============================================= +#ifdef DEBUG +# undef RELEASE +#endif // DEBUG + +#ifdef RELEASE +# undef DEBUG +#endif // RELEASE // ============================================= -#if (BUILD_ID != BUILD_INTERNAL) -#define RELEASE -#endif // BUILD_ID - #define alias auto& -#define elif else if +#define elif(A) else if (A) // Null pointer static const std::nullptr_t null = nullptr; -#ifdef __GNUC__ -# define FORMAT_PRINTF(M,N) __attribute__ ((format (printf, M, N))) -# define ATTR(N) __attribute__ ((N)) -#else -# define FORMAT_PRINTF(M,N) -# define ATTR(N) -#endif // __GNUC__ - #ifdef WIN32 -#define DIRSLASH "\\" -#define DIRSLASH_CHAR '\\' +# define DIRSLASH "\\" +# define DIRSLASH_CHAR '\\' #else // WIN32 -#define DIRSLASH "/" -#define DIRSLASH_CHAR '/' +# define DIRSLASH "/" +# define DIRSLASH_CHAR '/' #endif // WIN32 -#ifdef RELEASE -#define NDEBUG // remove asserts -#endif // RELEASE - #define PROP_NAME(GET) m_##GET #define READ_ACCESSOR(T, GET) \ @@ -145,27 +134,24 @@ #define FUNCNAME __func__ #endif // __GNUC__ -// Replace assert with a version that shows a GUI dialog if possible +// Replace assert with a version that shows a GUI dialog if possible. +// On Windows I just can't get the actual error messages otherwise. +void assertionFailure (const char* file, int line, const char* funcname, const char* expr); + #ifdef assert -#undef assert +# undef assert #endif // assert -class QString; -typedef QString str; - -void assertionFailure (const char* file, const ulong line, const char* funcname, const char* expr); -void fatalError (const char* file, const ulong line, const char* funcname, str errmsg); +#ifdef DEBUG +# define assert(N) { ((N) ? (void) 0 : assertionFailure (__FILE__, __LINE__, FUNCNAME, #N)); } +#else +# define assert(N) {} +#endif // DEBUG // Version string identifier -str versionString(); -str versionMoniker(); -str fullVersionString(); - -#define assert(N) \ - ((N) ? (void) 0 : assertionFailure (__FILE__, __LINE__, FUNCNAME, #N)) - -#define fatal(MSG) \ - fatalError (__FILE__, __LINE__, FUNCNAME, MSG) +QString versionString(); +QString versionMoniker(); +QString fullVersionString(); // ----------------------------------------------------------------------------- #ifdef IN_IDE_PARSER // KDevelop workarounds: @@ -183,4 +169,4 @@ typedef void FILE; // :| #endif // IN_IDE_PARSER -#endif // COMMON_H \ No newline at end of file +#endif // LDFORGE_COMMON_H
--- a/src/config.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/config.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -33,13 +33,14 @@ #include "file.h" Config* g_configPointers[MAX_CONFIG]; -static ushort g_cfgPointerCursor = 0; +static int g_cfgPointerCursor = 0; // ============================================================================= // Get the QSettings object. A portable build refers to a file in the current // directory, a non-portable build to ~/.config/LDForge or to registry. // ----------------------------------------------------------------------------- -static QSettings* getSettingsObject() { +static QSettings* getSettingsObject() +{ #ifdef PORTABLE # ifdef _WIN32 # define EXTENSION ".ini" @@ -58,18 +59,18 @@ // ============================================================================= // Load the configuration from file // ----------------------------------------------------------------------------- -bool Config::load() { - QSettings* settings = getSettingsObject(); - print ("config::load: Loading configuration file from %1\n", settings->fileName()); - - for (Config* cfg : g_configPointers) { - if (!cfg) +bool Config::load() +{ QSettings* settings = getSettingsObject(); + log ("config::load: Loading configuration file from %1\n", settings->fileName()); + + for (Config* cfg : g_configPointers) + { if (!cfg) break; - + QVariant val = settings->value (cfg->name, cfg->defaultVariant()); cfg->loadFromVariant (val); } - + settings->deleteLater(); return true; } @@ -77,20 +78,20 @@ // ============================================================================= // Save the configuration to disk // ----------------------------------------------------------------------------- -bool Config::save() { - QSettings* settings = getSettingsObject(); - print ("Saving configuration to %1...\n", settings->fileName()); - - for (Config* cfg : g_configPointers) { - if (!cfg) +bool Config::save() +{ QSettings* settings = getSettingsObject(); + log ("Saving configuration to %1...\n", settings->fileName()); + + for (Config* cfg : g_configPointers) + { if (!cfg) break; - + if (cfg->isDefault()) continue; - + settings->setValue (cfg->name, cfg->toVariant()); } - + settings->sync(); settings->deleteLater(); return true; @@ -99,11 +100,11 @@ // ============================================================================= // Reset configuration defaults. // ----------------------------------------------------------------------------- -void Config::reset() { - for (Config* cfg : g_configPointers) { - if (!cfg) +void Config::reset() +{ for (Config * cfg : g_configPointers) + { if (!cfg) break; - + cfg->resetValue(); } } @@ -112,15 +113,15 @@ // Where is the configuration file located at? Note that the Windows build uses // the registry so only use this with PORTABLE code. // ----------------------------------------------------------------------------- -str Config::filepath (str file) { - return Config::dirpath() + DIRSLASH + file; +str Config::filepath (str file) +{ return Config::dirpath() + DIRSLASH + file; } // ============================================================================= // Directory of the configuration file. PORTABLE code here as well. // ----------------------------------------------------------------------------- -str Config::dirpath() { - QSettings* cfg = getSettingsObject(); +str Config::dirpath() +{ QSettings* cfg = getSettingsObject(); return dirname (cfg->fileName()); } @@ -129,10 +130,10 @@ // on the vector's c-tor being called before the configs' c-tors. With global // variables we cannot assume that!! Therefore we need to use a C-style array here. // ----------------------------------------------------------------------------- -void Config::addToArray (Config* ptr) { - if (g_cfgPointerCursor == 0) +void Config::addToArray (Config* ptr) +{ if (g_cfgPointerCursor == 0) memset (g_configPointers, 0, sizeof g_configPointers); - + assert (g_cfgPointerCursor < MAX_CONFIG); g_configPointers[g_cfgPointerCursor++] = ptr; -} \ No newline at end of file +}
--- a/src/config.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/config.h Wed Oct 23 12:46:10 2013 +0300 @@ -16,8 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef CONFIG_H -#define CONFIG_H +#ifndef LDFORGE_CONFIG_H +#define LDFORGE_CONFIG_H #include "common.h" @@ -37,42 +37,53 @@ #define extern_cfg(T, NAME) extern T##Config NAME // ========================================================= -class Config { -public: - enum Type { - Int, - String, - Float, - Bool, - KeySequence, - List, - }; +class Config +{ public: + enum Type + { Int, + String, + Float, + Bool, + KeySequence, + List, + }; - Config (const char* name, const char* defstring); - const char* name; + Config (const char* name, const char* defstring); + const char* name; + + virtual Type getType() const + { return (Type) 0; + } + + virtual void resetValue() {} + virtual void loadFromVariant (const QVariant& val) + { (void) val; + } - virtual Type getType() const { - return (Type) 0; - } - - virtual void resetValue() {} - virtual void loadFromVariant (const QVariant& val) { (void) val; } - virtual bool isDefault() const { return false; } - virtual QVariant toVariant() const { return QVariant(); } - virtual QVariant defaultVariant() const { return QVariant(); } - - // ------------------------------------------ - static bool load(); - static bool save(); - static void reset(); - static str dirpath(); - static str filepath (str file); - -protected: - static void addToArray (Config* ptr); - -private: - const char* m_defstring; + virtual bool isDefault() const + { return false; + } + + virtual QVariant toVariant() const + { return QVariant(); + } + + virtual QVariant defaultVariant() const + { return QVariant(); + } + + // ------------------------------------------ + static bool load(); + static bool save(); + static void reset(); + static str dirpath(); + static str filepath (str file); + + protected: + static void addToArray (Config* ptr); + + private: + const char* m_defstring; }; // ============================================================================= @@ -130,106 +141,106 @@ T operator--(int) { return value--; } // ============================================================================= -class IntConfig : public Config { -public: - IMPLEMENT_CONFIG (Int, int) - DEFINE_ALL_COMPARE_OPERATORS (int) - DEFINE_INCREMENT_OPERATORS (int) - DEFINE_BINARY_OPERATOR (int, +) - DEFINE_BINARY_OPERATOR (int, -) - DEFINE_BINARY_OPERATOR (int, *) - DEFINE_BINARY_OPERATOR (int, /) - DEFINE_BINARY_OPERATOR (int, %) - DEFINE_BINARY_OPERATOR (int, ^) - DEFINE_BINARY_OPERATOR (int, |) - DEFINE_BINARY_OPERATOR (int, &) - DEFINE_BINARY_OPERATOR (int, >>) - DEFINE_BINARY_OPERATOR (int, <<) - DEFINE_UNARY_OPERATOR (int, !) - DEFINE_UNARY_OPERATOR (int, ~) - DEFINE_UNARY_OPERATOR (int, -) - DEFINE_UNARY_OPERATOR (int, +) - DEFINE_ASSIGN_OPERATOR (int, =) - DEFINE_ASSIGN_OPERATOR (int, +=) - DEFINE_ASSIGN_OPERATOR (int, -=) - DEFINE_ASSIGN_OPERATOR (int, *=) - DEFINE_ASSIGN_OPERATOR (int, /=) - DEFINE_ASSIGN_OPERATOR (int, %=) - DEFINE_ASSIGN_OPERATOR (int, >>=) - DEFINE_ASSIGN_OPERATOR (int, <<=) +class IntConfig : public Config +{ public: + IMPLEMENT_CONFIG (Int, int) + DEFINE_ALL_COMPARE_OPERATORS (int) + DEFINE_INCREMENT_OPERATORS (int) + DEFINE_BINARY_OPERATOR (int, +) + DEFINE_BINARY_OPERATOR (int, -) + DEFINE_BINARY_OPERATOR (int, *) + DEFINE_BINARY_OPERATOR (int, /) + DEFINE_BINARY_OPERATOR (int, %) + DEFINE_BINARY_OPERATOR (int, ^) + DEFINE_BINARY_OPERATOR (int, |) + DEFINE_BINARY_OPERATOR (int, &) + DEFINE_BINARY_OPERATOR (int, >>) + DEFINE_BINARY_OPERATOR (int, <<) + DEFINE_UNARY_OPERATOR (int, !) + DEFINE_UNARY_OPERATOR (int, ~) + DEFINE_UNARY_OPERATOR (int, -) + DEFINE_UNARY_OPERATOR (int, +) + DEFINE_ASSIGN_OPERATOR (int, =) + DEFINE_ASSIGN_OPERATOR (int, +=) + DEFINE_ASSIGN_OPERATOR (int, -=) + DEFINE_ASSIGN_OPERATOR (int, *=) + DEFINE_ASSIGN_OPERATOR (int, /=) + DEFINE_ASSIGN_OPERATOR (int, %=) + DEFINE_ASSIGN_OPERATOR (int, >>=) + DEFINE_ASSIGN_OPERATOR (int, <<=) }; // ============================================================================= -class StringConfig : public Config { -public: - IMPLEMENT_CONFIG (String, str) - - DEFINE_COMPARE_OPERATOR (str, ==) - DEFINE_COMPARE_OPERATOR (str, !=) - DEFINE_ASSIGN_OPERATOR (str, =) - DEFINE_ASSIGN_OPERATOR (str, +=) - - QChar operator[] (int n) { - return value[n]; - } +class StringConfig : public Config +{ public: + IMPLEMENT_CONFIG (String, str) + + DEFINE_COMPARE_OPERATOR (str, ==) + DEFINE_COMPARE_OPERATOR (str, !=) + DEFINE_ASSIGN_OPERATOR (str, =) + DEFINE_ASSIGN_OPERATOR (str, +=) + + QChar operator[] (int n) + { return value[n]; + } }; // ============================================================================= -class FloatConfig : public Config { -public: - IMPLEMENT_CONFIG (Float, float) - DEFINE_ALL_COMPARE_OPERATORS (float) - DEFINE_INCREMENT_OPERATORS (float) - DEFINE_BINARY_OPERATOR (float, +) - DEFINE_BINARY_OPERATOR (float, -) - DEFINE_BINARY_OPERATOR (float, *) - DEFINE_UNARY_OPERATOR (float, !) - DEFINE_ASSIGN_OPERATOR (float, =) - DEFINE_ASSIGN_OPERATOR (float, +=) - DEFINE_ASSIGN_OPERATOR (float, -=) - DEFINE_ASSIGN_OPERATOR (float, *=) +class FloatConfig : public Config +{ public: + IMPLEMENT_CONFIG (Float, float) + DEFINE_ALL_COMPARE_OPERATORS (float) + DEFINE_INCREMENT_OPERATORS (float) + DEFINE_BINARY_OPERATOR (float, +) + DEFINE_BINARY_OPERATOR (float, -) + DEFINE_BINARY_OPERATOR (float, *) + DEFINE_UNARY_OPERATOR (float, !) + DEFINE_ASSIGN_OPERATOR (float, =) + DEFINE_ASSIGN_OPERATOR (float, +=) + DEFINE_ASSIGN_OPERATOR (float, -=) + DEFINE_ASSIGN_OPERATOR (float, *=) }; // ============================================================================= -class BoolConfig : public Config { -public: - IMPLEMENT_CONFIG (Bool, bool) - DEFINE_ALL_COMPARE_OPERATORS (bool) - DEFINE_ASSIGN_OPERATOR (bool, =) +class BoolConfig : public Config +{ public: + IMPLEMENT_CONFIG (Bool, bool) + DEFINE_ALL_COMPARE_OPERATORS (bool) + DEFINE_ASSIGN_OPERATOR (bool, =) }; // ============================================================================= -class KeySequenceConfig : public Config { -public: - IMPLEMENT_CONFIG (KeySequence, QKeySequence) - DEFINE_ALL_COMPARE_OPERATORS (QKeySequence) - DEFINE_ASSIGN_OPERATOR (QKeySequence, =) +class KeySequenceConfig : public Config +{ public: + IMPLEMENT_CONFIG (KeySequence, QKeySequence) + DEFINE_ALL_COMPARE_OPERATORS (QKeySequence) + DEFINE_ASSIGN_OPERATOR (QKeySequence, =) }; // ============================================================================= -class ListConfig : public Config { -public: - IMPLEMENT_CONFIG (List, QList<QVariant>) - DEFINE_ASSIGN_OPERATOR (QList<QVariant>, =) - - typedef QList<QVariant>::iterator it; - typedef QList<QVariant>::const_iterator c_it; - - it begin() { - return value.begin(); - } - - c_it begin() const { - return value.constBegin(); - } - - it end() { - return value.end(); - } - - c_it end() const { - return value.constEnd(); - } +class ListConfig : public Config +{ public: + IMPLEMENT_CONFIG (List, QList<QVariant>) + DEFINE_ASSIGN_OPERATOR (QList<QVariant>, =) + + typedef QList<QVariant>::iterator it; + typedef QList<QVariant>::const_iterator c_it; + + it begin() + { return value.begin(); + } + + c_it begin() const + { return value.constBegin(); + } + + it end() + { return value.end(); + } + + c_it end() const + { return value.constEnd(); + } }; -#endif // CONFIG_H \ No newline at end of file +#endif // LDFORGE_CONFIG_H
--- a/src/configDialog.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/configDialog.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -38,6 +38,7 @@ #include "colorSelectDialog.h" #include "gldraw.h" #include "ui_config.h" +#include "moc_configDialog.cpp" extern_cfg (String, gl_bgcolor); extern_cfg (String, gl_maincolor); @@ -48,6 +49,7 @@ extern_cfg (String, gui_colortoolbar); extern_cfg (Bool, edit_schemanticinline); extern_cfg (Bool, gl_blackedges); +extern_cfg (Bool, gl_aa); extern_cfg (Bool, gui_implicitfiles); extern_cfg (String, net_downloadpath); extern_cfg (Bool, net_guesspaths); @@ -84,41 +86,42 @@ ConfigDialog::ConfigDialog (ConfigDialog::Tab deftab, QWidget* parent, Qt::WindowFlags f) : QDialog (parent, f) { - assert (g_win); + assert (g_win != null); ui = new Ui_ConfigUI; ui->setupUi (this); - + // Interface tab setButtonBackground (ui->backgroundColorButton, gl_bgcolor); connect (ui->backgroundColorButton, SIGNAL (clicked()), - this, SLOT (slot_setGLBackground())); - + this, SLOT (slot_setGLBackground())); + setButtonBackground (ui->mainColorButton, gl_maincolor); connect (ui->mainColorButton, SIGNAL (clicked()), - this, SLOT (slot_setGLForeground())); - + this, SLOT (slot_setGLForeground())); + ui->mainColorAlpha->setValue (gl_maincolor_alpha * 10.0f); ui->lineThickness->setValue (gl_linethickness); ui->colorizeObjects->setChecked (lv_colorize); ui->colorBFC->setChecked (gl_colorbfc); ui->blackEdges->setChecked (gl_blackedges); + ui->m_aa->setChecked (gl_aa); ui->implicitFiles->setChecked (gui_implicitfiles); ui->m_logostuds->setChecked (gl_logostuds); - - ulong i = 0; + + int i = 0; #define act(N) addShortcut (key_##N, ACTION(N), i); #include "actions.h" - + ui->shortcutsList->setSortingEnabled (true); ui->shortcutsList->sortItems(); - + connect (ui->shortcut_set, SIGNAL (clicked()), this, SLOT (slot_setShortcut())); connect (ui->shortcut_reset, SIGNAL (clicked()), this, SLOT (slot_resetShortcut())); connect (ui->shortcut_clear, SIGNAL (clicked()), this, SLOT (slot_clearShortcut())); - + quickColors = quickColorsFromConfig(); updateQuickColorList(); - + connect (ui->quickColor_add, SIGNAL (clicked()), this, SLOT (slot_setColor())); connect (ui->quickColor_remove, SIGNAL (clicked()), this, SLOT (slot_delColor())); connect (ui->quickColor_edit, SIGNAL (clicked()), this, SLOT (slot_setColor())); @@ -126,92 +129,105 @@ connect (ui->quickColor_moveUp, SIGNAL (clicked()), this, SLOT (slot_moveColor())); connect (ui->quickColor_moveDown, SIGNAL (clicked()), this, SLOT (slot_moveColor())); connect (ui->quickColor_clear, SIGNAL (clicked()), this, SLOT (slot_clearColors())); - + ui->downloadPath->setText (net_downloadpath); ui->guessNetPaths->setChecked (net_guesspaths); ui->autoCloseNetPrompt->setChecked (net_autoclose); - connect (ui->findDownloadPath, SIGNAL (clicked(bool)), this, SLOT (slot_findDownloadFolder())); - + connect (ui->findDownloadPath, SIGNAL (clicked (bool)), this, SLOT (slot_findDownloadFolder())); + ui->m_profileName->setText (ld_defaultname); ui->m_profileUsername->setText (ld_defaultuser); ui->m_profileLicense->setCurrentIndex (ld_defaultlicense); - ui->tabs->setCurrentIndex (deftab); - + initGrids(); initExtProgs(); - + selectPage (deftab); + connect (ui->buttonBox, SIGNAL (clicked (QAbstractButton*)), - this, SLOT (buttonClicked(QAbstractButton*))); + this, SLOT (buttonClicked (QAbstractButton*))); + + connect (ui->m_pages, SIGNAL (currentChanged (int)), + this, SLOT (selectPage (int))); + + connect (ui->m_pagelist, SIGNAL (currentRowChanged (int)), + this, SLOT (selectPage (int))); } // ============================================================================= // ----------------------------------------------------------------------------- -ConfigDialog::~ConfigDialog() { - delete ui; +ConfigDialog::~ConfigDialog() +{ delete ui; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void ConfigDialog::selectPage (int row) +{ ui->m_pagelist->setCurrentRow (row); + ui->m_pages->setCurrentIndex (row); } // ============================================================================= // Adds a shortcut entry to the list of shortcuts. // ----------------------------------------------------------------------------- -void ConfigDialog::addShortcut (KeySequenceConfig& cfg, QAction* act, ulong& i) { - ShortcutListItem* item = new ShortcutListItem; +void ConfigDialog::addShortcut (KeySequenceConfig& cfg, QAction* act, int& i) +{ ShortcutListItem* item = new ShortcutListItem; item->setIcon (act->icon()); item->setKeyConfig (&cfg); item->setAction (act); setShortcutText (item); - + // If the action doesn't have a valid icon, use an empty one // so that the list is kept aligned. if (act->icon().isNull()) item->setIcon (getIcon ("empty")); - + ui->shortcutsList->insertItem (i++, item); } // ============================================================================= // Initializes the table of grid stuff // ----------------------------------------------------------------------------- -void ConfigDialog::initGrids() { - QGridLayout* gridlayout = new QGridLayout; +void ConfigDialog::initGrids() +{ QGridLayout* gridlayout = new QGridLayout; QLabel* xlabel = new QLabel ("X"), - *ylabel = new QLabel ("Y"), - *zlabel = new QLabel ("Z"), - *anglabel = new QLabel ("Angle"); + *ylabel = new QLabel ("Y"), + *zlabel = new QLabel ("Z"), + *anglabel = new QLabel ("Angle"); short i = 1; - - for (QLabel* label : initlist<QLabel*> ({ xlabel, ylabel, zlabel, anglabel })) { - label->setAlignment (Qt::AlignCenter); + + for (QLabel* label : initlist<QLabel*> ({xlabel, ylabel, zlabel, anglabel})) + { label->setAlignment (Qt::AlignCenter); gridlayout->addWidget (label, 0, i++); } - - for (int i = 0; i < g_NumGrids; ++i) { - // Icon + + for (int i = 0; i < g_NumGrids; ++i) + { // Icon lb_gridIcons[i] = new QLabel; lb_gridIcons[i]->setPixmap (getIcon (fmt ("grid-%1", str (g_GridInfo[i].name).toLower()))); - + // Text label lb_gridLabels[i] = new QLabel (fmt ("%1:", g_GridInfo[i].name)); - + QHBoxLayout* labellayout = new QHBoxLayout; labellayout->addWidget (lb_gridIcons[i]); labellayout->addWidget (lb_gridLabels[i]); gridlayout->addLayout (labellayout, i + 1, 0); - + // Add the widgets - for (int j = 0; j < 4; ++j) { - dsb_gridData[i][j] = new QDoubleSpinBox; + for (int j = 0; j < 4; ++j) + { dsb_gridData[i][j] = new QDoubleSpinBox; dsb_gridData[i][j]->setValue (g_GridInfo[i].confs[j]->value); gridlayout->addWidget (dsb_gridData[i][j], i + 1, j + 1); } } - + ui->grids->setLayout (gridlayout); } // ============================================================================= // ----------------------------------------------------------------------------- -static const struct extProgInfo { - const str name, iconname; +static const struct LDExtProgInfo +{ const str name, iconname; StringConfig* const path; mutable QLineEdit* input; mutable QPushButton* setPathButton; @@ -219,7 +235,8 @@ BoolConfig* const wine; mutable QCheckBox* wineBox; #endif // _WIN32 -} g_extProgInfo[] = { +} g_LDExtProgInfo[] = +{ #ifndef _WIN32 # define EXTPROG(NAME, LOWNAME) { #NAME, #LOWNAME, &prog_##LOWNAME, null, null, &prog_##LOWNAME##_wine, null }, #else @@ -237,51 +254,51 @@ // ============================================================================= // Initializes the stuff in the ext programs tab // ----------------------------------------------------------------------------- -void ConfigDialog::initExtProgs() { - QGridLayout* pathsLayout = new QGridLayout; - ulong row = 0; - - for (const extProgInfo & info : g_extProgInfo) { - QLabel* icon = new QLabel, +void ConfigDialog::initExtProgs() +{ QGridLayout* pathsLayout = new QGridLayout; + int row = 0; + + for (const LDExtProgInfo& info : g_LDExtProgInfo) + { QLabel* icon = new QLabel, *progLabel = new QLabel (info.name); QLineEdit* input = new QLineEdit; QPushButton* setPathButton = new QPushButton; - + icon->setPixmap (getIcon (info.iconname)); input->setText (info.path->value); setPathButton->setIcon (getIcon ("folder")); info.input = input; info.setPathButton = setPathButton; - + connect (setPathButton, SIGNAL (clicked()), this, SLOT (slot_setExtProgPath())); - + pathsLayout->addWidget (icon, row, 0); pathsLayout->addWidget (progLabel, row, 1); pathsLayout->addWidget (input, row, 2); pathsLayout->addWidget (setPathButton, row, 3); - + #ifndef _WIN32 QCheckBox* wineBox = new QCheckBox ("Wine"); wineBox->setChecked (*info.wine); info.wineBox = wineBox; pathsLayout->addWidget (wineBox, row, 4); #endif - + ++row; } - + ui->extProgs->setLayout (pathsLayout); } // ============================================================================= // Set the settings based on widget data. // ----------------------------------------------------------------------------- -void ConfigDialog::applySettings() { - // Apply configuration +void ConfigDialog::applySettings() +{ // Apply configuration lv_colorize = ui->colorizeObjects->isChecked(); gl_colorbfc = ui->colorBFC->isChecked(); gl_blackedges = ui->blackEdges->isChecked(); - gl_maincolor_alpha = ((double) ui->mainColorAlpha->value()) / 10.0f; + gl_maincolor_alpha = ( (double) ui->mainColorAlpha->value()) / 10.0f; gl_linethickness = ui->lineThickness->value(); gui_implicitfiles = ui->implicitFiles->isChecked(); net_downloadpath = ui->downloadPath->text(); @@ -291,29 +308,30 @@ ld_defaultuser = ui->m_profileUsername->text(); ld_defaultname = ui->m_profileName->text(); ld_defaultlicense = ui->m_profileLicense->currentIndex(); - + gl_aa = ui->m_aa->isChecked(); + // Rebuild the quick color toolbar g_win->setQuickColors (quickColors); gui_colortoolbar = quickColorString(); - + // Set the grid settings for (int i = 0; i < g_NumGrids; ++i) for (int j = 0; j < 4; ++j) g_GridInfo[i].confs[j]->value = dsb_gridData[i][j]->value(); - + // Apply key shortcuts #define act(N) ACTION(N)->setShortcut (key_##N); #include "actions.h" - + // Ext program settings - for (const extProgInfo & info : g_extProgInfo) { - *info.path = info.input->text(); - + for (const LDExtProgInfo& info : g_LDExtProgInfo) + { *info.path = info.input->text(); + #ifndef _WIN32 *info.wine = info.wineBox->isChecked(); #endif // _WIN32 } - + Config::save(); reloadAllSubfiles(); loadLogoedStuds(); @@ -326,53 +344,55 @@ // ============================================================================= // A dialog button was clicked // ----------------------------------------------------------------------------- -void ConfigDialog::buttonClicked (QAbstractButton* button) { - typedef QDialogButtonBox QDDB; +void ConfigDialog::buttonClicked (QAbstractButton* button) +{ typedef QDialogButtonBox QDDB; QDialogButtonBox* dbb = ui->buttonBox; - - if (button == dbb->button (QDDB::Ok)) { - applySettings(); + + if (button == dbb->button (QDDB::Ok)) + { applySettings(); accept(); - } elif (button == dbb->button (QDDB::Apply)) { - applySettings(); - } elif (button == dbb->button (QDDB::Cancel)) { - reject(); + } elif (button == dbb->button (QDDB::Apply)) + { applySettings(); + } elif (button == dbb->button (QDDB::Cancel)) + { reject(); } } // ============================================================================= // Update the list of color toolbar items in the quick color tab. // ----------------------------------------------------------------------------- -void ConfigDialog::updateQuickColorList (LDQuickColor* sel) { - for (QListWidgetItem* item : quickColorItems) +void ConfigDialog::updateQuickColorList (LDQuickColor* sel) +{ for (QListWidgetItem * item : quickColorItems) delete item; - + quickColorItems.clear(); - + // Init table items - for (LDQuickColor& entry : quickColors) { - QListWidgetItem* item = new QListWidgetItem; - - if (entry.isSeparator()) { - item->setText ("--------"); + for (LDQuickColor& entry : quickColors) + { QListWidgetItem* item = new QListWidgetItem; + + if (entry.isSeparator()) + { item->setText ("--------"); item->setIcon (getIcon ("empty")); - } else { - LDColor* col = entry.color(); - - if (col == null) { - item->setText ("[[unknown color]]"); + } + else + { LDColor* col = entry.color(); + + if (col == null) + { item->setText ("[[unknown color]]"); item->setIcon (getIcon ("error")); - } else { - item->setText (col->name); + } + else + { item->setText (col->name); item->setIcon (makeColorIcon (col, 16)); } } - + ui->quickColorList->addItem (item); quickColorItems << item; - - if (sel && &entry == sel) { - ui->quickColorList->setCurrentItem (item); + + if (sel && &entry == sel) + { ui->quickColorList->setCurrentItem (item); ui->quickColorList->scrollToItem (item); } } @@ -381,43 +401,38 @@ // ============================================================================= // Quick colors: add or edit button was clicked. // ----------------------------------------------------------------------------- -void ConfigDialog::slot_setColor() { - LDQuickColor* entry = null; +void ConfigDialog::slot_setColor() +{ LDQuickColor* entry = null; QListWidgetItem* item = null; const bool isNew = static_cast<QPushButton*> (sender()) == ui->quickColor_add; - - if (isNew == false) { - item = getSelectedQuickColor(); - + + if (isNew == false) + { item = getSelectedQuickColor(); + if (!item) return; - - ulong i = getItemRow (item, quickColorItems); + + int i = getItemRow (item, quickColorItems); entry = &quickColors[i]; - + if (entry->isSeparator() == true) return; // don't color separators } - + short defval = entry ? entry->color()->index : -1; short val; - + if (ColorSelector::getColor (val, defval, this) == false) return; - + if (entry) entry->setColor (getColor (val)); - else { - LDQuickColor entry (getColor (val), null); - + else + { LDQuickColor entry (getColor (val), null); + item = getSelectedQuickColor(); - ulong idx; - - if (item) - idx = getItemRow (item, quickColorItems) + 1; - else - idx = quickColorItems.size(); - + int idx = (item) ? getItemRow (item, quickColorItems) + 1 : quickColorItems.size(); + quickColors.insert (idx, entry); entry = quickColors[idx]; } @@ -428,64 +443,64 @@ // ============================================================================= // Remove a quick color // ----------------------------------------------------------------------------- -void ConfigDialog::slot_delColor() { - if (ui->quickColorList->selectedItems().size() == 0) +void ConfigDialog::slot_delColor() +{ if (ui->quickColorList->selectedItems().isEmpty()) return; - + QListWidgetItem* item = ui->quickColorList->selectedItems() [0]; - quickColors.erase (getItemRow (item, quickColorItems)); + quickColors.removeAt (getItemRow (item, quickColorItems)); updateQuickColorList(); } // ============================================================================= // Move a quick color up/down // ----------------------------------------------------------------------------- -void ConfigDialog::slot_moveColor() { - const bool up = (static_cast<QPushButton*> (sender()) == ui->quickColor_moveUp); - - if (ui->quickColorList->selectedItems().size() == 0) +void ConfigDialog::slot_moveColor() +{ const bool up = (static_cast<QPushButton*> (sender()) == ui->quickColor_moveUp); + + if (ui->quickColorList->selectedItems().isEmpty()) return; - + QListWidgetItem* item = ui->quickColorList->selectedItems() [0]; int idx = getItemRow (item, quickColorItems); int dest = up ? (idx - 1) : (idx + 1); - - if (dest < 0 || (ulong) dest >= quickColorItems.size()) + + if (dest < 0 || dest >= quickColorItems.size()) return; // destination out of bounds - + LDQuickColor tmp = quickColors[dest]; quickColors[dest] = quickColors[idx]; quickColors[idx] = tmp; - + updateQuickColorList (&quickColors[dest]); } // ============================================================================= // Add a separator to quick colors // ----------------------------------------------------------------------------- -void ConfigDialog::slot_addColorSeparator() { - quickColors << LDQuickColor::getSeparator(); +void ConfigDialog::slot_addColorSeparator() +{ quickColors << LDQuickColor::getSeparator(); updateQuickColorList (&quickColors[quickColors.size() - 1]); } // ============================================================================= // Clear all quick colors // ----------------------------------------------------------------------------- -void ConfigDialog::slot_clearColors() { - quickColors.clear(); +void ConfigDialog::slot_clearColors() +{ quickColors.clear(); updateQuickColorList(); } // ============================================================================= // Pick a color and set the appropriate configuration option. // ----------------------------------------------------------------------------- -void ConfigDialog::pickColor (StringConfig& conf, QPushButton* button) { - QColor col = QColorDialog::getColor (QColor (conf)); - - if (col.isValid()) { - uchar r = col.red(), - g = col.green(), - b = col.blue(); +void ConfigDialog::pickColor (StringConfig& conf, QPushButton* button) +{ QColor col = QColorDialog::getColor (QColor (conf)); + + if (col.isValid()) + { uchar r = col.red(), + g = col.green(), + b = col.blue(); conf.value.sprintf ("#%.2X%.2X%.2X", r, g, b); setButtonBackground (button, conf.value); } @@ -493,21 +508,21 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void ConfigDialog::slot_setGLBackground() { - pickColor (gl_bgcolor, ui->backgroundColorButton); +void ConfigDialog::slot_setGLBackground() +{ pickColor (gl_bgcolor, ui->backgroundColorButton); } // ============================================================================= // ----------------------------------------------------------------------------- -void ConfigDialog::slot_setGLForeground() { - pickColor (gl_maincolor, ui->mainColorButton); +void ConfigDialog::slot_setGLForeground() +{ pickColor (gl_maincolor, ui->mainColorButton); } // ============================================================================= // Sets background color of a given button. // ----------------------------------------------------------------------------- -void ConfigDialog::setButtonBackground (QPushButton* button, str value) { - button->setIcon (getIcon ("colorselect")); +void ConfigDialog::setButtonBackground (QPushButton* button, str value) +{ button->setIcon (getIcon ("colorselect")); button->setAutoFillBackground (true); button->setStyleSheet (fmt ("background-color: %1", value)); } @@ -515,51 +530,52 @@ // ============================================================================= // Finds the given list widget item in the list of widget items given. // ----------------------------------------------------------------------------- -int ConfigDialog::getItemRow (QListWidgetItem* item, List<QListWidgetItem*>& haystack) { - int i = 0; - - for (QListWidgetItem* it : haystack) { - if (it == item) +int ConfigDialog::getItemRow (QListWidgetItem* item, QList<QListWidgetItem*>& haystack) +{ int i = 0; + + for (QListWidgetItem* it : haystack) + { if (it == item) return i; - + ++i; } + return -1; } // ============================================================================= // Which quick color is currently selected? // ----------------------------------------------------------------------------- -QListWidgetItem* ConfigDialog::getSelectedQuickColor() { - if (ui->quickColorList->selectedItems().size() == 0) +QListWidgetItem* ConfigDialog::getSelectedQuickColor() +{ if (ui->quickColorList->selectedItems().isEmpty()) return null; - - return ui->quickColorList->selectedItems()[0]; + + return ui->quickColorList->selectedItems() [0]; } // ============================================================================= // Get the list of shortcuts selected // ----------------------------------------------------------------------------- -QList<ShortcutListItem*> ConfigDialog::getShortcutSelection() { - QList<ShortcutListItem*> out; - +QList<ShortcutListItem*> ConfigDialog::getShortcutSelection() +{ QList<ShortcutListItem*> out; + for (QListWidgetItem* entry : ui->shortcutsList->selectedItems()) out << static_cast<ShortcutListItem*> (entry); - + return out; } // ============================================================================= // Edit the shortcut of a given action. // ----------------------------------------------------------------------------- -void ConfigDialog::slot_setShortcut() { - QList<ShortcutListItem*> sel = getShortcutSelection(); - +void ConfigDialog::slot_setShortcut() +{ QList<ShortcutListItem*> sel = getShortcutSelection(); + if (sel.size() < 1) return; - + ShortcutListItem* item = sel[0]; - + if (KeySequenceDialog::staticDialog (item->keyConfig(), this)) setShortcutText (item); } @@ -567,11 +583,11 @@ // ============================================================================= // Reset a shortcut to defaults // ----------------------------------------------------------------------------- -void ConfigDialog::slot_resetShortcut() { - QList<ShortcutListItem*> sel = getShortcutSelection(); - - for (ShortcutListItem* item : sel) { - item->keyConfig()->reset(); +void ConfigDialog::slot_resetShortcut() +{ QList<ShortcutListItem*> sel = getShortcutSelection(); + + for (ShortcutListItem* item : sel) + { item->keyConfig()->reset(); setShortcutText (item); } } @@ -579,11 +595,11 @@ // ============================================================================= // Remove the shortcut of an action. // ----------------------------------------------------------------------------- -void ConfigDialog::slot_clearShortcut() { - QList<ShortcutListItem*> sel = getShortcutSelection(); - - for (ShortcutListItem* item : sel) { - item->keyConfig()->value = QKeySequence(); +void ConfigDialog::slot_clearShortcut() +{ QList<ShortcutListItem*> sel = getShortcutSelection(); + + for (ShortcutListItem* item : sel) + { item->keyConfig()->value = QKeySequence(); setShortcutText (item); } } @@ -591,38 +607,38 @@ // ============================================================================= // Set the path of an external program // ----------------------------------------------------------------------------- -void ConfigDialog::slot_setExtProgPath() { - const extProgInfo* info = null; - - for (const extProgInfo& it : g_extProgInfo) { - if (it.setPathButton == sender()) { - info = ⁢ +void ConfigDialog::slot_setExtProgPath() +{ const LDExtProgInfo* info = null; + + for (const LDExtProgInfo& it : g_LDExtProgInfo) + { if (it.setPathButton == sender()) + { info = ⁢ break; } } - + assert (info != null); str fpath = QFileDialog::getOpenFileName (this, fmt ("Path to %1", info->name), *info->path, g_extProgPathFilter); - + if (fpath.isEmpty()) return; - + info->input->setText (fpath); } // ============================================================================= // '...' button pressed for the download path // ----------------------------------------------------------------------------- -void ConfigDialog::slot_findDownloadFolder() { - str dpath = QFileDialog::getExistingDirectory(); +void ConfigDialog::slot_findDownloadFolder() +{ str dpath = QFileDialog::getExistingDirectory(); ui->downloadPath->setText (dpath); } // ============================================================================= // Updates the text string for a given shortcut list item // ----------------------------------------------------------------------------- -void ConfigDialog::setShortcutText (ShortcutListItem* item) { - QAction* act = item->action(); +void ConfigDialog::setShortcutText (ShortcutListItem* item) +{ QAction* act = item->action(); str label = act->iconText(); str keybind = item->keyConfig()->value.toString(); item->setText (fmt ("%1 (%2)", label, keybind)); @@ -631,19 +647,19 @@ // ============================================================================= // Gets the configuration string of the quick color toolbar // ----------------------------------------------------------------------------- -str ConfigDialog::quickColorString() { - str val; - - for (const LDQuickColor& entry : quickColors) { - if (val.length() > 0) +str ConfigDialog::quickColorString() +{ str val; + + for (const LDQuickColor& entry : quickColors) + { if (val.length() > 0) val += ':'; - + if (entry.isSeparator()) val += '|'; else val += fmt ("%1", entry.color()->index); } - + return val; } @@ -655,14 +671,14 @@ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ========================================================================================================================= KeySequenceDialog::KeySequenceDialog (QKeySequence seq, QWidget* parent, Qt::WindowFlags f) : - QDialog (parent, f), seq (seq) { - lb_output = new QLabel; + QDialog (parent, f), seq (seq) +{ lb_output = new QLabel; IMPLEMENT_DIALOG_BUTTONS - + setWhatsThis ("Into this dialog you can input a key sequence for use as a " - "shortcut in LDForge. Use OK to confirm the new shortcut and Cancel to " - "dismiss."); - + "shortcut in LDForge. Use OK to confirm the new shortcut and Cancel to " + "dismiss."); + QVBoxLayout* layout = new QVBoxLayout; layout->addWidget (lb_output); layout->addWidget (bbx_buttons); @@ -673,32 +689,31 @@ // ============================================================================= // ----------------------------------------------------------------------------- -bool KeySequenceDialog::staticDialog (KeySequenceConfig* cfg, QWidget* parent) { - KeySequenceDialog dlg (cfg->value, parent); - +bool KeySequenceDialog::staticDialog (KeySequenceConfig* cfg, QWidget* parent) +{ KeySequenceDialog dlg (cfg->value, parent); + if (dlg.exec() == false) return false; - + cfg->value = dlg.seq; return true; } // ============================================================================= // ----------------------------------------------------------------------------- -void KeySequenceDialog::updateOutput() { - str shortcut = seq.toString(); - +void KeySequenceDialog::updateOutput() +{ str shortcut = seq.toString(); + if (seq == QKeySequence()) shortcut = "<empty>"; - + str text = fmt ("<center><b>%1</b></center>", shortcut); lb_output->setText (text); } // ============================================================================= // ----------------------------------------------------------------------------- -void KeySequenceDialog::keyPressEvent (QKeyEvent* ev) { - seq = ev->key() + ev->modifiers(); +void KeySequenceDialog::keyPressEvent (QKeyEvent* ev) +{ seq = ev->key() + ev->modifiers(); updateOutput(); } -#include "moc_configDialog.cpp"
--- a/src/configDialog.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/configDialog.h Wed Oct 23 12:46:10 2013 +0300 @@ -16,8 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef CONFIGDIALOG_H -#define CONFIGDIALOG_H +#ifndef LDFORGE_CONFIGDIALOG_H +#define LDFORGE_CONFIGDIALOG_H #include "gui.h" #include <QDialog> @@ -27,91 +27,92 @@ class QDoubleSpinBox; // ============================================================================= -class ShortcutListItem : public QListWidgetItem { - PROPERTY (KeySequenceConfig*, keyConfig, setKeyConfig) +class ShortcutListItem : public QListWidgetItem +{ PROPERTY (KeySequenceConfig*, keyConfig, setKeyConfig) PROPERTY (QAction*, action, setAction) - -public: - explicit ShortcutListItem (QListWidget* view = null, int type = Type) : - QListWidgetItem (view, type) {} + + public: + explicit ShortcutListItem (QListWidget* view = null, int type = Type) : + QListWidgetItem (view, type) {} }; // ============================================================================= -class ConfigDialog : public QDialog { - Q_OBJECT - -public: - enum Tab { - InterfaceTab, - ProfileTab, - ShortcutsTab, - QuickColorsTab, - GridsTab, - ExtProgsTab, - DownloadTab - }; - - explicit ConfigDialog (Tab deftab = InterfaceTab, QWidget* parent = null, Qt::WindowFlags f = 0); - virtual ~ConfigDialog(); - float getGridValue (int i, int j) const; - - List<LDQuickColor> quickColors; - QDoubleSpinBox* dsb_gridData[3][4]; - -private: - Ui_ConfigUI* ui; - QLabel* lb_gridLabels[3]; - QLabel* lb_gridIcons[3]; - List<QListWidgetItem*> quickColorItems; - - void applySettings(); - void addShortcut (KeySequenceConfig& cfg, QAction* act, ulong& i); - void setButtonBackground (QPushButton* button, str value); - void pickColor (StringConfig& cfg, QPushButton* button); - void updateQuickColorList (LDQuickColor* sel = null); - void setShortcutText (ShortcutListItem* item); - int getItemRow (QListWidgetItem* item, List<QListWidgetItem*>& haystack); - str quickColorString(); - QListWidgetItem* getSelectedQuickColor(); - QList<ShortcutListItem*> getShortcutSelection(); - void initGrids(); - void initExtProgs(); - -private slots: - void slot_setGLBackground(); - void slot_setGLForeground(); - void slot_setShortcut(); - void slot_resetShortcut(); - void slot_clearShortcut(); - void slot_setColor(); - void slot_delColor(); - void slot_addColorSeparator(); - void slot_moveColor(); - void slot_clearColors(); - void slot_setExtProgPath(); - void slot_findDownloadFolder(); - void buttonClicked (QAbstractButton* button); +class ConfigDialog : public QDialog +{ Q_OBJECT + + public: + enum Tab + { InterfaceTab, + ProfileTab, + ShortcutsTab, + QuickColorsTab, + GridsTab, + ExtProgsTab, + DownloadTab + }; + + explicit ConfigDialog (Tab deftab = InterfaceTab, QWidget* parent = null, Qt::WindowFlags f = 0); + virtual ~ConfigDialog(); + float getGridValue (int i, int j) const; + + QList<LDQuickColor> quickColors; + QDoubleSpinBox* dsb_gridData[3][4]; + + private: + Ui_ConfigUI* ui; + QLabel* lb_gridLabels[3]; + QLabel* lb_gridIcons[3]; + QList<QListWidgetItem*> quickColorItems; + + void applySettings(); + void addShortcut (KeySequenceConfig& cfg, QAction* act, int& i); + void setButtonBackground (QPushButton* button, str value); + void pickColor (StringConfig& cfg, QPushButton* button); + void updateQuickColorList (LDQuickColor* sel = null); + void setShortcutText (ShortcutListItem* item); + int getItemRow (QListWidgetItem* item, QList<QListWidgetItem*>& haystack); + str quickColorString(); + QListWidgetItem* getSelectedQuickColor(); + QList<ShortcutListItem*> getShortcutSelection(); + void initGrids(); + void initExtProgs(); + + private slots: + void slot_setGLBackground(); + void slot_setGLForeground(); + void slot_setShortcut(); + void slot_resetShortcut(); + void slot_clearShortcut(); + void slot_setColor(); + void slot_delColor(); + void slot_addColorSeparator(); + void slot_moveColor(); + void slot_clearColors(); + void slot_setExtProgPath(); + void slot_findDownloadFolder(); + void buttonClicked (QAbstractButton* button); + void selectPage (int row); }; // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= -class KeySequenceDialog : public QDialog { - Q_OBJECT +class KeySequenceDialog : public QDialog +{ Q_OBJECT + + public: + explicit KeySequenceDialog (QKeySequence seq, QWidget* parent = null, Qt::WindowFlags f = 0); + static bool staticDialog (KeySequenceConfig* cfg, QWidget* parent = null); -public: - explicit KeySequenceDialog (QKeySequence seq, QWidget* parent = null, Qt::WindowFlags f = 0); - static bool staticDialog (KeySequenceConfig* cfg, QWidget* parent = null); - - QLabel* lb_output; - QDialogButtonBox* bbx_buttons; - QKeySequence seq; - -private: - void updateOutput(); - -private slots: - virtual void keyPressEvent (QKeyEvent* ev) override; + QLabel* lb_output; + QDialogButtonBox* bbx_buttons; + QKeySequence seq; + + private: + void updateOutput(); + + private slots: + virtual void keyPressEvent (QKeyEvent* ev) override; }; -#endif // CONFIGDIALOG_H \ No newline at end of file +#endif // LDFORGE_CONFIGDIALOG_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/crashcatcher.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -0,0 +1,109 @@ +#ifdef __unix__ + +#include <QString> +#include <QProcess> +#include <QTemporaryFile> +#include <QMessageBox> +#include <unistd.h> +#include <signal.h> +#include <sys/prctl.h> +#include "crashcatcher.h" +#include "types.h" +#include "dialogs.h" + +// Is the crash catcher active now? +static bool g_crashCatcherActive = false; + +// If an assertion failed, what was it? +static str g_assertionFailure; + +// List of signals to catch and crash on +static QList<int> g_signalsToCatch ({ + SIGSEGV, // segmentation fault + SIGABRT, // abort() calls + SIGFPE, // floating point exceptions (e.g. division by zero) + SIGILL, // illegal instructions +}); + +// ============================================================================= +// ----------------------------------------------------------------------------- +static void handleCrash (int sig) +{ printf ("%s: crashed with signal %d, launching gdb\n", __func__, sig); + + if (g_crashCatcherActive) + { printf ("caught signal while crash catcher is active!\n"); + exit (149); + } + + const pid_t pid = getpid(); + QProcess proc; + QTemporaryFile commandsFile; + + g_crashCatcherActive = true; + + if (commandsFile.open()) + { commandsFile.write (fmt ("attach %1\n", pid).toLocal8Bit()); + commandsFile.write (str ("backtrace full\n").toLocal8Bit()); + commandsFile.write (str ("detach\n").toLocal8Bit()); + commandsFile.write (str ("quit").toLocal8Bit()); + commandsFile.flush(); + commandsFile.close(); + } + + QStringList args ({"-x", commandsFile.fileName()}); + + proc.start ("gdb", args); + + // Linux doesn't allow ptrace to be used on anything but direct child processes + // so we need to use prctl to register an exception to this to allow GDB attach to us. + // We need to do this now and no earlier because only now we actually know GDB's PID. + prctl (PR_SET_PTRACER, proc.pid(), 0, 0, 0); + + proc.waitForFinished (1000); + str output = QString (proc.readAllStandardOutput()); + str err = QString (proc.readAllStandardError()); + + bombBox (fmt ("<h3>Program crashed with signal %1</h3>\n\n" + "%2" + "<p><b>GDB <tt>stdout</tt>:</b></p><pre>%3</pre>\n" + "<p><b>GDB <tt>stderr</tt>:</b></p><pre>%4</pre>", + sig, (!g_assertionFailure.isEmpty()) ? g_assertionFailure : "", output, err)); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void initCrashCatcher() +{ struct sigaction sighandler; + sighandler.sa_handler = &handleCrash; + sighandler.sa_flags = 0; + sigemptyset (&sighandler.sa_mask); + + for (int sig : g_signalsToCatch) + sigaction (sig, &sighandler, null); + + log ("%1: crash catcher hooked to signals: %2\n", __func__, g_signalsToCatch); +} +#endif // #ifdef __unix__ + +// ============================================================================= +// This function must be readily available in both Windows and Linux. We display +// the bomb box straight in Windows while in Linux we let abort() trigger the +// signal handler, which will cause the usual bomb box with GDB diagnostics. +// Said prompt will embed the assertion failure information. +// ----------------------------------------------------------------------------- +void assertionFailure (const char* file, int line, const char* funcname, const char* expr) +{ str errmsg = fmt ( + "<p><b>File</b>: <tt>%1</tt><br />" + "<b>Line</b>: <tt>%2</tt><br />" + "<b>Function:</b> <tt>%3</tt></p>" + "<p>Assertion <b><tt>`%4'</tt></b> failed.</p>", + file, line, funcname, expr); + + g_assertionFailure = errmsg; + +#ifndef __unix__ + bombBox (errmsg); +#endif + + abort(); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/crashcatcher.h Wed Oct 23 12:46:10 2013 +0300 @@ -0,0 +1,11 @@ +#ifndef LDFORGE_CRASHCATCHER_H +#define LDFORGE_CRASHCATCHER_H + +#ifdef __unix__ + +void initCrashCatcher(); + +#else // ifdef __unix__ +#define initCrashCatcher() +#endif // ifdef __unix__ +#endif // ifndef LDFORGE_CRASHCATCHER_H \ No newline at end of file
--- a/src/dialogs.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/dialogs.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -28,8 +28,8 @@ #include <QProgressBar> #include <QCheckBox> #include <QDesktopServices> +#include <QMessageBox> #include <QUrl> - #include "dialogs.h" #include "widgets.h" #include "gui.h" @@ -42,59 +42,62 @@ #include "ui_openprogress.h" #include "ui_extprogpath.h" #include "ui_about.h" +#include "ui_bombbox.h" +#include "moc_dialogs.cpp" extern const char* g_extProgPathFilter; extern_cfg (String, io_ldpath); // ============================================================================= // ----------------------------------------------------------------------------- -OverlayDialog::OverlayDialog (QWidget* parent, Qt::WindowFlags f) : QDialog (parent, f) { - ui = new Ui_OverlayUI; +OverlayDialog::OverlayDialog (QWidget* parent, Qt::WindowFlags f) : QDialog (parent, f) +{ ui = new Ui_OverlayUI; ui->setupUi (this); - - m_cameraArgs = { - { ui->top, GL::Top }, + + m_cameraArgs = + { { ui->top, GL::Top }, { ui->bottom, GL::Bottom }, { ui->front, GL::Front }, { ui->back, GL::Back }, { ui->left, GL::Left }, { ui->right, GL::Right } }; - + GL::Camera cam = g_win->R()->camera(); - + if (cam == GL::Free) cam = GL::Top; - + connect (ui->width, SIGNAL (valueChanged (double)), this, SLOT (slot_dimensionsChanged())); connect (ui->height, SIGNAL (valueChanged (double)), this, SLOT (slot_dimensionsChanged())); connect (ui->buttonBox, SIGNAL (helpRequested()), this, SLOT (slot_help())); connect (ui->fileSearchButton, SIGNAL (clicked (bool)), this, SLOT (slot_fpath())); - + slot_dimensionsChanged(); fillDefaults (cam); } // ============================================================================= // ----------------------------------------------------------------------------- -OverlayDialog::~OverlayDialog() { - delete ui; +OverlayDialog::~OverlayDialog() +{ delete ui; } // ============================================================================= // ----------------------------------------------------------------------------- -void OverlayDialog::fillDefaults (int newcam) { - overlayMeta& info = g_win->R()->getOverlay (newcam); +void OverlayDialog::fillDefaults (int newcam) +{ LDGLOverlay& info = g_win->R()->getOverlay (newcam); radioDefault<int> (newcam, m_cameraArgs); - - if (info.img != null) { - ui->filename->setText (info.fname); + + if (info.img != null) + { ui->filename->setText (info.fname); ui->originX->setValue (info.ox); ui->originY->setValue (info.oy); ui->width->setValue (info.lw); ui->height->setValue (info.lh); - } else { - ui->filename->setText (""); + } + else + { ui->filename->setText (""); ui->originX->setValue (0); ui->originY->setValue (0); ui->width->setValue (0.0f); @@ -104,40 +107,40 @@ // ============================================================================= // ----------------------------------------------------------------------------- -str OverlayDialog::fpath() const { - return ui->filename->text(); +str OverlayDialog::fpath() const +{ return ui->filename->text(); } -ushort OverlayDialog::ofsx() const { - return ui->originX->value(); +int OverlayDialog::ofsx() const +{ return ui->originX->value(); } -ushort OverlayDialog::ofsy() const { - return ui->originY->value(); +int OverlayDialog::ofsy() const +{ return ui->originY->value(); } -double OverlayDialog::lwidth() const { - return ui->width->value(); +double OverlayDialog::lwidth() const +{ return ui->width->value(); } -double OverlayDialog::lheight() const { - return ui->height->value(); +double OverlayDialog::lheight() const +{ return ui->height->value(); } -int OverlayDialog::camera() const { - return radioSwitch<int> (GL::Top, m_cameraArgs); +int OverlayDialog::camera() const +{ return radioSwitch<int> (GL::Top, m_cameraArgs); } -void OverlayDialog::slot_fpath() { - ui->filename->setText (QFileDialog::getOpenFileName (null, "Overlay image")); +void OverlayDialog::slot_fpath() +{ ui->filename->setText (QFileDialog::getOpenFileName (null, "Overlay image")); } -void OverlayDialog::slot_help() { - showDocumentation (g_docs_overlays); +void OverlayDialog::slot_help() +{ showDocumentation (g_docs_overlays); } -void OverlayDialog::slot_dimensionsChanged() { - bool enable = (ui->width->value() != 0) || (ui->height->value() != 0); +void OverlayDialog::slot_dimensionsChanged() +{ bool enable = (ui->width->value() != 0) || (ui->height->value() != 0); ui->buttonBox->button (QDialogButtonBox::Ok)->setEnabled (enable); } @@ -146,132 +149,130 @@ LDrawPathDialog::LDrawPathDialog (const bool validDefault, QWidget* parent, Qt::WindowFlags f) : QDialog (parent, f), m_validDefault (validDefault) -{ - ui = new Ui_LDPathUI; +{ ui = new Ui_LDPathUI; ui->setupUi (this); ui->status->setText ("---"); - + if (validDefault) ui->heading->hide(); - else { - cancelButton()->setText ("Exit"); + else + { cancelButton()->setText ("Exit"); cancelButton()->setIcon (getIcon ("exit")); } - + okButton()->setEnabled (false); - + connect (ui->path, SIGNAL (textEdited (QString)), this, SLOT (slot_tryConfigure())); connect (ui->searchButton, SIGNAL (clicked()), this, SLOT (slot_findPath())); connect (ui->buttonBox, SIGNAL (rejected()), this, validDefault ? SLOT (reject()) : SLOT (slot_exit())); connect (ui->buttonBox, SIGNAL (accepted()), this, SLOT (slot_accept())); - + setPath (io_ldpath); - + if (validDefault) slot_tryConfigure(); } // ============================================================================= // ----------------------------------------------------------------------------- -LDrawPathDialog::~LDrawPathDialog() { - delete ui; +LDrawPathDialog::~LDrawPathDialog() +{ delete ui; } -QPushButton* LDrawPathDialog::okButton() { - return ui->buttonBox->button (QDialogButtonBox::Ok); +QPushButton* LDrawPathDialog::okButton() +{ return ui->buttonBox->button (QDialogButtonBox::Ok); } -QPushButton* LDrawPathDialog::cancelButton() { - return ui->buttonBox->button (QDialogButtonBox::Cancel); +QPushButton* LDrawPathDialog::cancelButton() +{ return ui->buttonBox->button (QDialogButtonBox::Cancel); } -void LDrawPathDialog::setPath (str path) { - ui->path->setText (path); +void LDrawPathDialog::setPath (str path) +{ ui->path->setText (path); } -str LDrawPathDialog::filename() const { - return ui->path->text(); +str LDrawPathDialog::filename() const +{ return ui->path->text(); } // ============================================================================= // ----------------------------------------------------------------------------- -void LDrawPathDialog::slot_findPath() { - str newpath = QFileDialog::getExistingDirectory (this, "Find LDraw Path"); - - if (newpath.length() > 0 && newpath != filename()) { - setPath (newpath); +void LDrawPathDialog::slot_findPath() +{ str newpath = QFileDialog::getExistingDirectory (this, "Find LDraw Path"); + + if (newpath.length() > 0 && newpath != filename()) + { setPath (newpath); slot_tryConfigure(); } } // ============================================================================= // ----------------------------------------------------------------------------- -void LDrawPathDialog::slot_exit() { - exit (1); +void LDrawPathDialog::slot_exit() +{ exit (0); } // ============================================================================= // ----------------------------------------------------------------------------- -void LDrawPathDialog::slot_tryConfigure() { - if (LDPaths::tryConfigure (filename()) == false) { - ui->status->setText (fmt ("<span style=\"color:#700; \">%1</span>", LDPaths::getError())); +void LDrawPathDialog::slot_tryConfigure() +{ if (LDPaths::tryConfigure (filename()) == false) + { ui->status->setText (fmt ("<span style=\"color:#700; \">%1</span>", LDPaths::getError())); okButton()->setEnabled (false); return; } - + ui->status->setText ("<span style=\"color: #270; \">OK!</span>"); okButton()->setEnabled (true); } // ============================================================================= // ----------------------------------------------------------------------------- -void LDrawPathDialog::slot_accept() { - Config::save(); +void LDrawPathDialog::slot_accept() +{ Config::save(); accept(); } // ============================================================================= // ----------------------------------------------------------------------------- -OpenProgressDialog::OpenProgressDialog (QWidget* parent, Qt::WindowFlags f) : QDialog (parent, f) { - ui = new Ui_OpenProgressUI; +OpenProgressDialog::OpenProgressDialog (QWidget* parent, Qt::WindowFlags f) : QDialog (parent, f) +{ ui = new Ui_OpenProgressUI; ui->setupUi (this); ui->progressText->setText ("Parsing..."); - setNumLines (0); m_progress = 0; } // ============================================================================= // ----------------------------------------------------------------------------- -OpenProgressDialog::~OpenProgressDialog() { - delete ui; +OpenProgressDialog::~OpenProgressDialog() +{ delete ui; } // ============================================================================= // ----------------------------------------------------------------------------- -READ_ACCESSOR (ulong, OpenProgressDialog::numLines) { - return m_numLines; +READ_ACCESSOR (int, OpenProgressDialog::numLines) +{ return m_numLines; } // ============================================================================= // ----------------------------------------------------------------------------- -SET_ACCESSOR (ulong, OpenProgressDialog::setNumLines) { - m_numLines = val; +SET_ACCESSOR (int, OpenProgressDialog::setNumLines) +{ m_numLines = val; ui->progressBar->setRange (0, numLines()); updateValues(); } // ============================================================================= // ----------------------------------------------------------------------------- -void OpenProgressDialog::updateValues() { - ui->progressText->setText (fmt ("Parsing... %1 / %2", progress(), numLines())); +void OpenProgressDialog::updateValues() +{ ui->progressText->setText (fmt ("Parsing... %1 / %2", progress(), numLines())); ui->progressBar->setValue (progress()); } // ============================================================================= // ----------------------------------------------------------------------------- -void OpenProgressDialog::updateProgress (int progress) { - m_progress = progress; +void OpenProgressDialog::updateProgress (int progress) +{ m_progress = progress; updateValues(); } @@ -282,56 +283,64 @@ ui (new Ui_ExtProgPath) { ui->setupUi (this); - str labelText = ui->m_label->text(); labelText.replace ("<PROGRAM>", progName); ui->m_label->setText (labelText); - connect (ui->m_findPath, SIGNAL (clicked (bool)), this, SLOT (findPath())); } // ============================================================================= // ----------------------------------------------------------------------------- -ExtProgPathPrompt::~ExtProgPathPrompt() { - delete ui; +ExtProgPathPrompt::~ExtProgPathPrompt() +{ delete ui; } // ============================================================================= // ----------------------------------------------------------------------------- -void ExtProgPathPrompt::findPath() { - str path = QFileDialog::getOpenFileName (null, "", "", g_extProgPathFilter); - +void ExtProgPathPrompt::findPath() +{ str path = QFileDialog::getOpenFileName (null, "", "", g_extProgPathFilter); + if (!path.isEmpty()) ui->m_path->setText (path); } // ============================================================================= // ----------------------------------------------------------------------------- -str ExtProgPathPrompt::getPath() const { - return ui->m_path->text(); +str ExtProgPathPrompt::getPath() const +{ return ui->m_path->text(); } // ============================================================================= // ----------------------------------------------------------------------------- AboutDialog::AboutDialog (QWidget* parent, Qt::WindowFlags f) : QDialog (parent, f) -{ - Ui::AboutUI ui; +{ Ui::AboutUI ui; ui.setupUi (this); ui.versionInfo->setText (fmt (tr ("LDForge %1"), fullVersionString())); - + QPushButton* mailButton = new QPushButton; mailButton->setText ("Contact"); mailButton->setIcon (getIcon ("mail")); ui.buttonBox->addButton (static_cast<QAbstractButton*> (mailButton), QDialogButtonBox::HelpRole); connect (ui.buttonBox, SIGNAL (helpRequested()), this, SLOT (slot_mail())); - + setWindowTitle ("About " APPNAME); } // ============================================================================= // ----------------------------------------------------------------------------- -void AboutDialog::slot_mail() { - QDesktopServices::openUrl (QUrl ("mailto:Santeri Piippo <slatenails64@gmail.com>?subject=LDForge")); +void AboutDialog::slot_mail() +{ QDesktopServices::openUrl (QUrl ("mailto:Santeri Piippo <slatenails64@gmail.com>?subject=LDForge")); } -#include "moc_dialogs.cpp" + +// ============================================================================= +// ----------------------------------------------------------------------------- +void bombBox (const str& message) +{ QDialog dlg (g_win); + Ui_BombBox ui; + + ui.setupUi (&dlg); + ui.m_text->setText (message); + ui.buttonBox->button (QDialogButtonBox::Close)->setText (QObject::tr ("Damn it")); + dlg.exec(); +}
--- a/src/dialogs.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/dialogs.h Wed Oct 23 12:46:10 2013 +0300 @@ -16,8 +16,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef DIALOGS_H -#define DIALOGS_H +#ifndef LDFORGE_DIALOGS_H +#define LDFORGE_DIALOGS_H #include <QDialog> #include "common.h" @@ -40,99 +40,101 @@ class Ui_LDPathUI; class Ui_OpenProgressUI; -class OverlayDialog : public QDialog { - Q_OBJECT - -public: - explicit OverlayDialog (QWidget* parent = null, Qt::WindowFlags f = 0); - virtual ~OverlayDialog(); - - str fpath() const; - ushort ofsx() const; - ushort ofsy() const; - double lwidth() const; - double lheight() const; - int camera() const; - -private: - Ui_OverlayUI* ui; - List<pair<QRadioButton*, int>> m_cameraArgs; - -private slots: - void slot_fpath(); - void slot_help(); - void slot_dimensionsChanged(); - void fillDefaults (int newcam); +class OverlayDialog : public QDialog +{ Q_OBJECT + + public: + explicit OverlayDialog (QWidget* parent = null, Qt::WindowFlags f = 0); + virtual ~OverlayDialog(); + + str fpath() const; + int ofsx() const; + int ofsy() const; + double lwidth() const; + double lheight() const; + int camera() const; + + private: + Ui_OverlayUI* ui; + QList<pair<QRadioButton*, int>> m_cameraArgs; + + private slots: + void slot_fpath(); + void slot_help(); + void slot_dimensionsChanged(); + void fillDefaults (int newcam); }; // ============================================================================= -class LDrawPathDialog : public QDialog { - Q_OBJECT - -public: - explicit LDrawPathDialog (const bool validDefault, QWidget* parent = null, Qt::WindowFlags f = 0); - virtual ~LDrawPathDialog(); - str filename() const; - void setPath (str path); - -private: - Q_DISABLE_COPY (LDrawPathDialog) - const bool m_validDefault; - Ui_LDPathUI* ui; - QPushButton* okButton(); - QPushButton* cancelButton(); - -private slots: - void slot_findPath(); - void slot_tryConfigure(); - void slot_exit(); - void slot_accept(); +class LDrawPathDialog : public QDialog +{ Q_OBJECT + + public: + explicit LDrawPathDialog (const bool validDefault, QWidget* parent = null, Qt::WindowFlags f = 0); + virtual ~LDrawPathDialog(); + str filename() const; + void setPath (str path); + + private: + Q_DISABLE_COPY (LDrawPathDialog) + const bool m_validDefault; + Ui_LDPathUI* ui; + QPushButton* okButton(); + QPushButton* cancelButton(); + + private slots: + void slot_findPath(); + void slot_tryConfigure(); + void slot_exit(); + void slot_accept(); }; // ============================================================================= -class OpenProgressDialog : public QDialog { - Q_OBJECT - READ_PROPERTY (ulong, progress, setProgress) - DECLARE_PROPERTY (ulong, numLines, setNumLines) +class OpenProgressDialog : public QDialog +{ Q_OBJECT + READ_PROPERTY (int, progress, setProgress) + DECLARE_PROPERTY (int, numLines, setNumLines) -public: - explicit OpenProgressDialog (QWidget* parent = null, Qt::WindowFlags f = 0); - virtual ~OpenProgressDialog(); + public: + explicit OpenProgressDialog (QWidget* parent = null, Qt::WindowFlags f = 0); + virtual ~OpenProgressDialog(); -public slots: - void updateProgress (int progress); + public slots: + void updateProgress (int progress); -private: - Ui_OpenProgressUI* ui; + private: + Ui_OpenProgressUI* ui; - void updateValues(); + void updateValues(); }; // ============================================================================= -class ExtProgPathPrompt : public QDialog { - Q_OBJECT - -public: - explicit ExtProgPathPrompt (str progName, QWidget* parent = 0, Qt::WindowFlags f = 0); - virtual ~ExtProgPathPrompt(); - str getPath() const; - -public slots: - void findPath(); - -private: - Ui_ExtProgPath* ui; +class ExtProgPathPrompt : public QDialog +{ Q_OBJECT + + public: + explicit ExtProgPathPrompt (str progName, QWidget* parent = 0, Qt::WindowFlags f = 0); + virtual ~ExtProgPathPrompt(); + str getPath() const; + + public slots: + void findPath(); + + private: + Ui_ExtProgPath* ui; }; // ============================================================================= -class AboutDialog : public QDialog { - Q_OBJECT - -public: - AboutDialog (QWidget* parent = null, Qt::WindowFlags f = 0); - -private slots: - void slot_mail(); +class AboutDialog : public QDialog +{ Q_OBJECT + + public: + AboutDialog (QWidget* parent = null, Qt::WindowFlags f = 0); + + private slots: + void slot_mail(); }; -#endif // DIALOGS_H \ No newline at end of file +void bombBox (const str& message); + +#endif // LDFORGE_DIALOGS_H
--- a/src/docs.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/docs.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -25,27 +25,27 @@ // ============================================================================= // ----------------------------------------------------------------------------- -class DocumentViewer : public QDialog { -public: - explicit DocumentViewer (QWidget* parent = null, Qt::WindowFlags f = 0) : QDialog (parent, f) { - te_text = new QTextEdit (this); - te_text->setMinimumSize (QSize (400, 300)); - te_text->setReadOnly (true); - - QDialogButtonBox* bbx_buttons = new QDialogButtonBox (QDialogButtonBox::Close); - QVBoxLayout* layout = new QVBoxLayout (this); - layout->addWidget (te_text); - layout->addWidget (bbx_buttons); - - connect (bbx_buttons, SIGNAL (rejected()), this, SLOT (reject())); - } - - void setText (const char* text) { - te_text->setText (text); - } - -private: - QTextEdit* te_text; +class DocumentViewer : public QDialog +{ public: + explicit DocumentViewer (QWidget* parent = null, Qt::WindowFlags f = 0) : QDialog (parent, f) + { te_text = new QTextEdit (this); + te_text->setMinimumSize (QSize (400, 300)); + te_text->setReadOnly (true); + + QDialogButtonBox* bbx_buttons = new QDialogButtonBox (QDialogButtonBox::Close); + QVBoxLayout* layout = new QVBoxLayout (this); + layout->addWidget (te_text); + layout->addWidget (bbx_buttons); + + connect (bbx_buttons, SIGNAL (rejected()), this, SLOT (reject())); + } + + void setText (const char* text) + { te_text->setText (text); + } + + private: + QTextEdit* te_text; }; const char* g_docs_overlays = @@ -65,8 +65,8 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void showDocumentation (const char* text) { - DocumentViewer dlg; +void showDocumentation (const char* text) +{ DocumentViewer dlg; dlg.setText (text); dlg.exec(); -} \ No newline at end of file +}
--- a/src/download.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/download.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -29,114 +29,117 @@ #include "file.h" #include "gldraw.h" #include "configDialog.h" +#include "moc_download.cpp" cfg (String, net_downloadpath, ""); cfg (Bool, net_guesspaths, true); cfg (Bool, net_autoclose, false); -constexpr const char* PartDownloader::k_OfficialURL, - *PartDownloader::k_UnofficialURL; +constexpr const char *PartDownloader::k_UnofficialURL; // ============================================================================= // ----------------------------------------------------------------------------- -void PartDownloader::k_download() { - str path = getDownloadPath(); - if (path == "" || QDir (path).exists() == false) { - critical (PartDownloader::tr ("You need to specify a valid path for " +void PartDownloader::k_download() +{ str path = getDownloadPath(); + + if (path == "" || QDir (path).exists() == false) + { critical (PartDownloader::tr ("You need to specify a valid path for " "downloaded files in the configuration to download paths.")); - + (new ConfigDialog (ConfigDialog::DownloadTab, null))->exec(); return; } - + PartDownloader* dlg = new PartDownloader; dlg->exec(); } // ============================================================================= // ----------------------------------------------------------------------------- -str PartDownloader::getDownloadPath() { - str path = net_downloadpath; - +str PartDownloader::getDownloadPath() +{ str path = net_downloadpath; + #if DIRSLASH_CHAR != '/' path.replace (DIRSLASH, "/"); #endif - + return path; } // ============================================================================= // ----------------------------------------------------------------------------- -PartDownloader::PartDownloader (QWidget* parent) : QDialog (parent) { - ui = new Ui_DownloadFrom; +PartDownloader::PartDownloader (QWidget* parent) : QDialog (parent) +{ ui = new Ui_DownloadFrom; ui->setupUi (this); ui->fname->setFocus(); ui->progress->horizontalHeader()->setResizeMode (PartLabelColumn, QHeaderView::Stretch); - + m_downloadButton = new QPushButton (tr ("Download")); ui->buttonBox->addButton (m_downloadButton, QDialogButtonBox::ActionRole); getButton (Abort)->setEnabled (false); - + connect (ui->source, SIGNAL (currentIndexChanged (int)), this, SLOT (sourceChanged (int))); connect (ui->buttonBox, SIGNAL (clicked (QAbstractButton*)), this, SLOT (buttonClicked (QAbstractButton*))); } // ============================================================================= // ----------------------------------------------------------------------------- -PartDownloader::~PartDownloader() { - delete ui; +PartDownloader::~PartDownloader() +{ delete ui; } // ============================================================================= // ----------------------------------------------------------------------------- -str PartDownloader::getURL() const { - const Source src = getSource(); +str PartDownloader::getURL() const +{ const Source src = getSource(); str dest; - - switch (src) { - case PartsTracker: - dest = ui->fname->text(); - modifyDest (dest); - return str (k_UnofficialURL) + dest; - - case CustomURL: - return ui->fname->text(); + + switch (src) + { case PartsTracker: + dest = ui->fname->text(); + modifyDest (dest); + return str (k_UnofficialURL) + dest; + + case CustomURL: + return ui->fname->text(); } - + // Shouldn't happen return ""; } // ============================================================================= // ----------------------------------------------------------------------------- -void PartDownloader::modifyDest (str& dest) const { - dest = dest.simplified(); - +void PartDownloader::modifyDest (str& dest) const +{ dest = dest.simplified(); + // If the user doesn't want us to guess, stop right here. if (net_guesspaths == false) return; - + // Ensure .dat extension - if (dest.right (4) != ".dat") { - /* Remove the existing extension, if any. It may be we're here over a - typo in the .dat extension. */ + if (dest.right (4) != ".dat") + { // Remove the existing extension, if any. It may be we're here over a + // typo in the .dat extension. const int dotpos = dest.lastIndexOf ("."); + if (dotpos != -1 && dotpos >= dest.length() - 4) dest.chop (dest.length() - dotpos); - + dest += ".dat"; } - - /* If the part starts with s\ or s/, then use parts/s/. Same goes with - 48\ and p/48/. */ - if (dest.left (2) == "s\\" || dest.left (2) == "s/") { - dest.remove (0, 2); + + // If the part starts with s\ or s/, then use parts/s/. Same goes with + // 48\ and p/48/. + if (dest.left (2) == "s\\" || dest.left (2) == "s/") + { dest.remove (0, 2); dest.prepend ("parts/s/"); - } elif (dest.left (3) == "48\\" || dest.left (3) == "48/") { - dest.remove (0, 3); + } elif (dest.left (3) == "48\\" || dest.left (3) == "48/") + + { dest.remove (0, 3); dest.prepend ("p/48/"); } - + /* Try determine where to put this part. We have four directories: parts/, parts/s/, p/, and p/48/. If we haven't already specified either parts/ or p/, we need to add it automatically. Part files @@ -146,16 +149,16 @@ - d** (formed stickers) - p** (patterns) - a lowercase alphabetic letter for variants - + Subfiles (usually) have an s** prefix, in which case we use parts/s/. Note that the regex starts with a '^' so it won't catch already fully given part file names. */ str partRegex = "^u?[0-9]+(c[0-9][0-9]+)*(d[0-9][0-9]+)*[a-z]?(p[0-9a-z][0-9a-z]+)*"; str subpartRegex = partRegex + "s[0-9][0-9]+"; - + partRegex += "\\.dat$"; subpartRegex += "\\.dat$"; - + if (QRegExp (subpartRegex).exactMatch (dest)) dest.prepend ("parts/s/"); elif (QRegExp (partRegex).exactMatch (dest)) @@ -166,14 +169,14 @@ // ============================================================================= // ----------------------------------------------------------------------------- -PartDownloader::Source PartDownloader::getSource() const { - return (Source) ui->source->currentIndex(); +PartDownloader::Source PartDownloader::getSource() const +{ return (Source) ui->source->currentIndex(); } // ============================================================================= // ----------------------------------------------------------------------------- -void PartDownloader::sourceChanged (int i) { - if (i == CustomURL) +void PartDownloader::sourceChanged (int i) +{ if (i == CustomURL) ui->fileNameLabel->setText (tr ("URL:")); else ui->fileNameLabel->setText (tr ("File name:")); @@ -181,31 +184,32 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void PartDownloader::buttonClicked (QAbstractButton* btn) { - if (btn == getButton (Close)) { - reject(); - } elif (btn == getButton (Abort)) { - setAborted (true); - +void PartDownloader::buttonClicked (QAbstractButton* btn) +{ if (btn == getButton (Close)) + { reject(); + } + elif (btn == getButton (Abort)) + { setAborted (true); + for (PartDownloadRequest* req : m_requests) req->abort(); - } elif (btn == getButton (Download)) { - str dest = ui->fname->text(); + } + elif (btn == getButton (Download)) + { str dest = ui->fname->text(); setPrimaryFile (null); setAborted (false); - + if (getSource() == CustomURL) dest = basename (getURL()); - + modifyDest (dest); - - if (QFile::exists (PartDownloader::getDownloadPath() + DIRSLASH + dest)) { - const str overwritemsg = fmt (tr ("%1 already exists in download directory. Overwrite?"), dest); - + + if (QFile::exists (PartDownloader::getDownloadPath() + DIRSLASH + dest)) + { const str overwritemsg = fmt (tr ("%1 already exists in download directory. Overwrite?"), dest); if (!confirm (tr ("Overwrite?"), overwritemsg)) return; } - + m_downloadButton->setEnabled (false); ui->progress->setEnabled (true); ui->fname->setEnabled (false); @@ -219,17 +223,17 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void PartDownloader::downloadFile (str dest, str url, bool primary) { - const int row = ui->progress->rowCount(); - +void PartDownloader::downloadFile (str dest, str url, bool primary) +{ const int row = ui->progress->rowCount(); + // Don't download files repeadetly. - if (m_filesToDownload.find (dest) != -1u) + if (m_filesToDownload.indexOf (dest) != -1) return; - + modifyDest (dest); - print ("DOWNLOAD: %1 -> %2\n", url, PartDownloader::getDownloadPath() + DIRSLASH + dest); + log ("DOWNLOAD: %1 -> %2\n", url, PartDownloader::getDownloadPath() + DIRSLASH + dest); PartDownloadRequest* req = new PartDownloadRequest (url, dest, primary, this); - + m_filesToDownload << dest; m_requests << req; ui->progress->insertRow (row); @@ -239,36 +243,37 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void PartDownloader::checkIfFinished() { - bool failed = aborted(); - +void PartDownloader::checkIfFinished() +{ bool failed = aborted(); + // If there is some download still working, we're not finished. - for (PartDownloadRequest* req : m_requests) { - if (!req->isFinished()) + for (PartDownloadRequest* req : m_requests) + { if (!req->isFinished()) return; - + if (req->state() == PartDownloadRequest::Failed) failed = true; } - + for (PartDownloadRequest* req : m_requests) delete req; - + m_requests.clear(); - + // Update everything now - if (primaryFile()) { - LDFile::setCurrent (primaryFile()); + if (primaryFile()) + { LDFile::setCurrent (primaryFile()); reloadAllSubfiles(); g_win->fullRefresh(); g_win->R()->resetAngles(); } - - if (net_autoclose && !failed) { - // Close automatically if desired. + + if (net_autoclose && !failed) + { // Close automatically if desired. accept(); - } else { - // Allow the prompt be closed now. + } + else + { // Allow the prompt be closed now. getButton (Abort)->setEnabled (false); getButton (Close)->setEnabled (true); } @@ -276,21 +281,24 @@ // ============================================================================= // ----------------------------------------------------------------------------- -QPushButton* PartDownloader::getButton (PartDownloader::Button i) { - typedef QDialogButtonBox QDBB; +QPushButton* PartDownloader::getButton (PartDownloader::Button i) +{ typedef QDialogButtonBox QDBB; alias btnbox = ui->buttonBox; - - switch (i) { - case Download: - return m_downloadButton; - - case Abort: - return qobject_cast<QPushButton*> (btnbox->button (QDBB::Abort)); - - case Close: - return qobject_cast<QPushButton*> (btnbox->button (QDBB::Close)); + + switch (i) + { case Download: + { return m_downloadButton; + } + + case Abort: + { return qobject_cast<QPushButton*> (btnbox->button (QDBB::Abort)); + } + + case Close: + { return qobject_cast<QPushButton*> (btnbox->button (QDBB::Close)); + } } - + return null; } @@ -310,14 +318,16 @@ { // Make sure that we have a valid destination. str dirpath = dirname (m_fpath); - + QDir dir (dirpath); - if (!dir.exists()) { - print ("Creating %1...\n", dirpath); + + if (!dir.exists()) + { log ("Creating %1...\n", dirpath); + if (!dir.mkpath (dirpath)) critical (fmt (tr ("Couldn't create the directory %1!"), dirpath)); } - + m_reply = m_nam->get (QNetworkRequest (QUrl (url))); connect (m_reply, SIGNAL (finished()), this, SLOT (downloadFinished())); connect (m_reply, SIGNAL (readyRead()), this, SLOT (readyRead())); @@ -330,111 +340,112 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void PartDownloadRequest::updateToTable() { - const int labelcol = PartDownloader::PartLabelColumn, - progcol = PartDownloader::ProgressColumn; +void PartDownloadRequest::updateToTable() +{ const int labelcol = PartDownloader::PartLabelColumn, + progcol = PartDownloader::ProgressColumn; QTableWidget* table = m_prompt->ui->progress; QProgressBar* prog; - - switch (m_state) { - case Requesting: - case Downloading: - prog = qobject_cast<QProgressBar*> (table->cellWidget (tableRow(), progcol)); - - if (!prog) { - prog = new QProgressBar; - table->setCellWidget (tableRow(), progcol, prog); - } - - prog->setRange (0, m_bytesTotal); - prog->setValue (m_bytesRead); - break; - - case Finished: - case Failed: - { - QLabel* lb = new QLabel ((m_state == Finished) ? "<b><span style=\"color: #080\">FINISHED</span></b>" : - "<b><span style=\"color: #800\">FAILED</span></b>"); + + switch (m_state) + { case Requesting: + case Downloading: + { prog = qobject_cast<QProgressBar*> (table->cellWidget (tableRow(), progcol)); + + if (!prog) + { prog = new QProgressBar; + table->setCellWidget (tableRow(), progcol, prog); + } + + prog->setRange (0, m_bytesTotal); + prog->setValue (m_bytesRead); + } break; + + case Finished: + case Failed: + { QLabel* lb = new QLabel ((m_state == Finished) ? "<b><span style=\"color: #080\">FINISHED</span></b>" : + "<b><span style=\"color: #800\">FAILED</span></b>"); lb->setAlignment (Qt::AlignCenter); table->setCellWidget (tableRow(), progcol, lb); - } - break; + } break; } - + QLabel* lb = qobject_cast<QLabel*> (table->cellWidget (tableRow(), labelcol)); - if (m_firstUpdate) { - lb = new QLabel (fmt ("<b>%1</b>", m_dest), table); + + if (m_firstUpdate) + { lb = new QLabel (fmt ("<b>%1</b>", m_dest), table); table->setCellWidget (tableRow(), labelcol, lb); } - + // Make sure that the cell is big enough to contain the label if (table->columnWidth (labelcol) < lb->width()) table->setColumnWidth (labelcol, lb->width()); - + m_firstUpdate = false; } // ============================================================================= // ----------------------------------------------------------------------------- -void PartDownloadRequest::downloadFinished() { - if (m_reply->error() != QNetworkReply::NoError) { - if (m_primary && !m_prompt->aborted()) +void PartDownloadRequest::downloadFinished() +{ if (m_reply->error() != QNetworkReply::NoError) + { if (m_primary && !m_prompt->aborted()) critical (m_reply->errorString()); - + m_state = Failed; } elif (state() != Failed) m_state = Finished; - + m_bytesRead = m_bytesTotal; updateToTable(); - - if (m_fp) { - m_fp->close(); + + if (m_fp) + { m_fp->close(); delete m_fp; m_fp = null; - + if (m_state == Failed) QFile::remove (m_fpath); } - - if (m_state != Finished) { - m_prompt->checkIfFinished(); + + if (m_state != Finished) + { m_prompt->checkIfFinished(); return; } - + // Try to load this file now. LDFile* f = openDATFile (m_fpath, false); + if (!f) return; - + f->setImplicit (!m_primary); - + // Iterate through this file and check for errors. If there's any that stems // from unknown file references, try resolve that by downloading the reference. // This is why downloading a part may end up downloading multiple files, as // it resolves dependencies. - for (LDObject* obj : f->objects()) { - LDError* err = dynamic_cast<LDError*> (obj); + for (LDObject* obj : f->objects()) + { LDError* err = dynamic_cast<LDError*> (obj); + if (!err || err->fileRef().isEmpty()) continue; - + str dest = err->fileRef(); m_prompt->modifyDest (dest); m_prompt->downloadFile (dest, str (PartDownloader::k_UnofficialURL) + dest, false); } - - if (m_primary) { - addRecentFile (m_fpath); + + if (m_primary) + { addRecentFile (m_fpath); m_prompt->setPrimaryFile (f); } - + m_prompt->checkIfFinished(); } // ============================================================================= // ----------------------------------------------------------------------------- -void PartDownloadRequest::downloadProgress (int64 recv, int64 total) { - m_bytesRead = recv; +void PartDownloadRequest::downloadProgress (int64 recv, int64 total) +{ m_bytesRead = recv; m_bytesTotal = total; m_state = Downloading; updateToTable(); @@ -442,18 +453,19 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void PartDownloadRequest::readyRead() { - if (state() == Failed) +void PartDownloadRequest::readyRead() +{ if (state() == Failed) return; - - if (m_fp == null) { - m_fpath.replace ("\\", "/"); - + + if (m_fp == null) + { m_fpath.replace ("\\", "/"); + // We have already asked the user whether we can overwrite so we're good // to go here. m_fp = new QFile (m_fpath.toLocal8Bit()); - if (!m_fp->open (QIODevice::WriteOnly)) { - critical (fmt (tr ("Couldn't open %1 for writing: %2"), m_fpath, strerror (errno))); + + if (!m_fp->open (QIODevice::WriteOnly)) + { critical (fmt (tr ("Couldn't open %1 for writing: %2"), m_fpath, strerror (errno))); m_state = Failed; m_reply->abort(); updateToTable(); @@ -461,31 +473,30 @@ return; } } - + m_fp->write (m_reply->readAll()); } // ============================================================================= // ----------------------------------------------------------------------------- -bool PartDownloadRequest::isFinished() const { - return m_state == Finished || m_state == Failed; +bool PartDownloadRequest::isFinished() const +{ return m_state == Finished || m_state == Failed; } // ============================================================================= // ----------------------------------------------------------------------------- -const PartDownloadRequest::State& PartDownloadRequest::state() const { - return m_state; +const PartDownloadRequest::State& PartDownloadRequest::state() const +{ return m_state; } // ============================================================================= // ----------------------------------------------------------------------------- -void PartDownloadRequest::abort() { - m_reply->abort(); +void PartDownloadRequest::abort() +{ m_reply->abort(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (DownloadFrom, 0) { - PartDownloader::k_download(); +DEFINE_ACTION (DownloadFrom, 0) +{ PartDownloader::k_download(); } -#include "moc_download.cpp"
--- a/src/download.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/download.h Wed Oct 23 12:46:10 2013 +0300 @@ -34,95 +34,94 @@ // ============================================================================= // ----------------------------------------------------------------------------- -class PartDownloader : public QDialog { - Q_OBJECT - PROPERTY (LDFile*, primaryFile, setPrimaryFile) - PROPERTY (bool, aborted, setAborted) - -public: - constexpr static const char* k_OfficialURL = "http://ldraw.org/library/official/", - *k_UnofficialURL = "http://ldraw.org/library/unofficial/"; - - enum Source { - PartsTracker, - CustomURL, - }; - - enum Button { - Download, - Abort, - Close - }; - - enum TableColumn { - PartLabelColumn, - ProgressColumn, - }; - - explicit PartDownloader (QWidget* parent = null); - virtual ~PartDownloader(); - str getURL() const; - static str getDownloadPath(); - Source getSource() const; - void downloadFile (str dest, str url, bool primary); - void modifyDest (str& dest) const; - QPushButton* getButton (Button i); - static void k_download(); - -public slots: - void sourceChanged (int i); - void checkIfFinished(); - void buttonClicked (QAbstractButton* btn); - -protected: - Ui_DownloadFrom* ui; - friend class PartDownloadRequest; - -private: - List<str> m_filesToDownload; - List<PartDownloadRequest*> m_requests; - QPushButton* m_downloadButton; +class PartDownloader : public QDialog +{ Q_OBJECT + PROPERTY (LDFile*, primaryFile, setPrimaryFile) + PROPERTY (bool, aborted, setAborted) + + public: + constexpr static const char* k_UnofficialURL = "http://ldraw.org/library/unofficial/"; + + enum Source + { PartsTracker, + CustomURL, + }; + + enum Button + { Download, + Abort, + Close + }; + + enum TableColumn + { PartLabelColumn, + ProgressColumn, + }; + + explicit PartDownloader (QWidget* parent = null); + virtual ~PartDownloader(); + str getURL() const; + static str getDownloadPath(); + Source getSource() const; + void downloadFile (str dest, str url, bool primary); + void modifyDest (str& dest) const; + QPushButton* getButton (Button i); + static void k_download(); + + public slots: + void sourceChanged (int i); + void checkIfFinished(); + void buttonClicked (QAbstractButton* btn); + + protected: + Ui_DownloadFrom* ui; + friend class PartDownloadRequest; + + private: + QList<str> m_filesToDownload; + QList<PartDownloadRequest*> m_requests; + QPushButton* m_downloadButton; }; // ============================================================================= // ----------------------------------------------------------------------------- -class PartDownloadRequest : public QObject { - Q_OBJECT +class PartDownloadRequest : public QObject +{ Q_OBJECT PROPERTY (int, tableRow, setTableRow) - -public: - enum State { - Requesting, - Downloading, - Finished, - Failed, - }; - - explicit PartDownloadRequest (str url, str dest, bool primary, PartDownloader* parent); - PartDownloadRequest (const PartDownloadRequest&) = delete; - virtual ~PartDownloadRequest(); - void updateToTable(); - bool isFinished() const; - const State& state() const; - - void operator= (const PartDownloadRequest&) = delete; - -public slots: - void downloadFinished(); - void readyRead(); - void downloadProgress (qint64 recv, qint64 total); - void abort(); - -private: - PartDownloader* m_prompt; - str m_url, m_dest, m_fpath; - QNetworkAccessManager* m_nam; - QNetworkReply* m_reply; - bool m_firstUpdate; - State m_state; - int64 m_bytesRead, m_bytesTotal; - bool m_primary; - QFile* m_fp; + + public: + enum State + { Requesting, + Downloading, + Finished, + Failed, + }; + + explicit PartDownloadRequest (str url, str dest, bool primary, PartDownloader* parent); + PartDownloadRequest (const PartDownloadRequest&) = delete; + virtual ~PartDownloadRequest(); + void updateToTable(); + bool isFinished() const; + const State& state() const; + + void operator= (const PartDownloadRequest&) = delete; + + public slots: + void downloadFinished(); + void readyRead(); + void downloadProgress (qint64 recv, qint64 total); + void abort(); + + private: + PartDownloader* m_prompt; + str m_url, m_dest, m_fpath; + QNetworkAccessManager* m_nam; + QNetworkReply* m_reply; + bool m_firstUpdate; + State m_state; + int64 m_bytesRead, m_bytesTotal; + bool m_primary; + QFile* m_fp; }; -#endif // LDFORGE_DOWNLOAD_H \ No newline at end of file +#endif // LDFORGE_DOWNLOAD_H
--- a/src/extprogs.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/extprogs.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -39,8 +39,8 @@ #include "ui_edger2.h" #include "dialogs.h" -enum extprog { - Isecalc, +enum extprog +{ Isecalc, Intersector, Coverer, Ytruder, @@ -57,8 +57,8 @@ cfg (String, prog_rectifier, ""); cfg (String, prog_edger2, ""); -StringConfig* const g_extProgPaths[] = { - &prog_isecalc, +StringConfig* const g_extProgPaths[] = +{ &prog_isecalc, &prog_intersector, &prog_coverer, &prog_ytruder, @@ -74,8 +74,8 @@ cfg (Bool, prog_rectifier_wine, false); cfg (Bool, prog_edger2_wine, false); -BoolConfig* const g_extProgWine[] = { - &prog_isecalc_wine, +BoolConfig* const g_extProgWine[] = +{ &prog_isecalc_wine, &prog_intersector_wine, &prog_coverer_wine, &prog_ytruder_wine, @@ -84,8 +84,8 @@ }; #endif // _WIN32 -const char* g_extProgNames[] = { - "Isecalc", +const char* g_extProgNames[] = +{ "Isecalc", "Intersector", "Coverer", "Ytruder", @@ -95,51 +95,52 @@ // ============================================================================= // ----------------------------------------------------------------------------- -static bool checkProgPath (const extprog prog) { - alias path = g_extProgPaths[prog]->value; - +static bool checkProgPath (const extprog prog) +{ alias path = g_extProgPaths[prog]->value; + if (path.length() > 0) return true; - + ExtProgPathPrompt* dlg = new ExtProgPathPrompt (g_extProgNames[prog]); - if (dlg->exec() && !dlg->getPath().isEmpty()) { - path = dlg->getPath(); + + if (dlg->exec() && !dlg->getPath().isEmpty()) + { path = dlg->getPath(); return true; } - + return false; } // ============================================================================= // ----------------------------------------------------------------------------- -static str processErrorString (QProcess& proc) { - switch (proc.error()) { - case QProcess::FailedToStart: - return "Failed to start (check your permissions)"; - - case QProcess::Crashed: - return "Crashed."; - - case QProcess::WriteError: - case QProcess::ReadError: - return "I/O error."; - - case QProcess::UnknownError: - return "Unknown error"; - - case QProcess::Timedout: - return fmt ("Timed out (30 seconds)"); +static str processErrorString (QProcess& proc) +{ switch (proc.error()) + { case QProcess::FailedToStart: + return "Failed to start (check your permissions)"; + + case QProcess::Crashed: + return "Crashed."; + + case QProcess::WriteError: + case QProcess::ReadError: + return "I/O error."; + + case QProcess::UnknownError: + return "Unknown error"; + + case QProcess::Timedout: + return fmt ("Timed out (30 seconds)"); } - + return ""; } // ============================================================================= // ----------------------------------------------------------------------------- -static bool mkTempFile (QTemporaryFile& tmp, str& fname) { - if (!tmp.open()) +static bool mkTempFile (QTemporaryFile& tmp, str& fname) +{ if (!tmp.open()) return false; - + fname = tmp.fileName(); tmp.close(); return true; @@ -147,192 +148,190 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void writeObjects (List<LDObject*>& objects, File& f) { - for (LDObject* obj : objects) { - if (obj->getType() == LDObject::Subfile) { - LDSubfile* ref = static_cast<LDSubfile*> (obj); - List<LDObject*> objs = ref->inlineContents (LDSubfile::DeepInline); - +static void writeObjects (const QList<LDObject*>& objects, File& f) +{ for (LDObject* obj : objects) + { if (obj->getType() == LDObject::Subfile) + { LDSubfile* ref = static_cast<LDSubfile*> (obj); + QList<LDObject*> objs = ref->inlineContents (LDSubfile::DeepInline); + writeObjects (objs, f); - + for (LDObject* obj : objs) delete obj; - } else + } + else f.write (obj->raw() + "\r\n"); } } // ============================================================================= // ----------------------------------------------------------------------------- -void writeObjects (List<LDObject*>& objects, str fname) { - // Write the input file +static void writeObjects (const QList<LDObject*>& objects, str fname) +{ // Write the input file File f (fname, File::Write); - - if (!f) { - critical (fmt ("Couldn't open temporary file %1 for writing.\n", fname)); + + if (!f) + { critical (fmt ("Couldn't open temporary file %1 for writing.\n", fname)); return; } - + writeObjects (objects, f); f.close(); } // ============================================================================= // ----------------------------------------------------------------------------- -void writeSelection (str fname) { - writeObjects (g_win->sel(), fname); +void writeSelection (str fname) +{ writeObjects (selection(), fname); } // ============================================================================= // ----------------------------------------------------------------------------- -void writeColorGroup (const short colnum, str fname) { - List<LDObject*> objects; - - for (LDObject* obj : LDFile::current()->objects()) { - if (obj->isColored() == false || obj->color() != colnum) +void writeColorGroup (const short colnum, str fname) +{ QList<LDObject*> objects; + + for (LDObject* obj : LDFile::current()->objects()) + { if (obj->isColored() == false || obj->color() != colnum) continue; - + objects << obj; } - + writeObjects (objects, fname); } // ============================================================================= // ----------------------------------------------------------------------------- -bool runUtilityProcess (extprog prog, str path, str argvstr) { - QTemporaryFile input, output; +bool runUtilityProcess (extprog prog, str path, str argvstr) +{ QTemporaryFile input, output; str inputname, outputname; QStringList argv = argvstr.split (" ", QString::SkipEmptyParts); - + #ifndef _WIN32 - if (*g_extProgWine[prog]) { - argv.insert (0, path); + if (*g_extProgWine[prog]) + { argv.insert (0, path); path = "wine"; } #endif // _WIN32 - - print ("cmdline: %1 %2\n", path, argv.join (" ")); - + + log ("cmdline: %1 %2\n", path, argv.join (" ")); + // Temporary files for stdin and stdout if (!mkTempFile (input, inputname) || !mkTempFile (output, outputname)) return false; - + QProcess proc; - + // Init stdin File stdinfp (inputname, File::Write); - + // Begin! proc.setStandardInputFile (inputname); proc.start (path, argv); - + // Write an enter, the utility tools all expect one stdinfp.write ("\n"); - + // Wait while it runs proc.waitForFinished(); - -#ifndef RELEASE - print ("%1", str (proc.readAllStandardOutput())); -#endif // RELEASE - + str err = ""; - + if (proc.exitStatus() != QProcess::NormalExit) err = processErrorString (proc); - + // Check the return code if (proc.exitCode() != 0) err = fmt ("Program exited abnormally (return code %1).", proc.exitCode()); - - if (err.length() > 0) { - critical (fmt ("%1 failed: %2\n", g_extProgNames[prog], err)); + + if (err.length() > 0) + { critical (fmt ("%1 failed: %2\n", g_extProgNames[prog], err)); return false; } - + return true; } // ============================================================================= // ----------------------------------------------------------------------------- -static void insertOutput (str fname, bool replace, List<short> colorsToReplace) { +static void insertOutput (str fname, bool replace, QList<short> colorsToReplace) +{ #ifndef RELEASE QFile::copy (fname, "./debug_lastOutput"); #endif // RELEASE - + // Read the output file File f (fname, File::Read); - - if (!f) { - critical (fmt ("Couldn't open temporary file %1 for reading.\n", fname)); + + if (!f) + { critical (fmt ("Couldn't open temporary file %1 for reading.\n", fname)); return; } - - List<LDObject*> objs = loadFileContents (&f, null); - + + QList<LDObject*> objs = loadFileContents (&f, null); + // If we replace the objects, delete the selection now. if (replace) g_win->deleteSelection(); - + for (const short colnum : colorsToReplace) g_win->deleteByColor (colnum); - + // Insert the new objects - g_win->sel().clear(); - - for (LDObject * obj : objs) { - if (!obj->isScemantic()) { - delete obj; + LDFile::current()->clearSelection(); + + for (LDObject * obj : objs) + { if (!obj->isScemantic()) + { delete obj; continue; } - + LDFile::current()->addObject (obj); - g_win->sel() << obj; + obj->select(); } - + g_win->fullRefresh(); } // ============================================================================= // Interface for Ytruder // ----------------------------------------------------------------------------- -DEFINE_ACTION (Ytruder, 0) { - setlocale (LC_ALL, "C"); - +DEFINE_ACTION (Ytruder, 0) +{ setlocale (LC_ALL, "C"); + if (!checkProgPath (Ytruder)) return; - + QDialog* dlg = new QDialog; Ui::YtruderUI ui; ui.setupUi (dlg); - + if (!dlg->exec()) return; - + // Read the user's choices const enum { Distance, Symmetry, Projection, Radial } mode = ui.mode_distance->isChecked() ? Distance : ui.mode_symmetry->isChecked() ? Symmetry : ui.mode_projection->isChecked() ? Projection : Radial; - + const Axis axis = ui.axis_x->isChecked() ? X : ui.axis_y->isChecked() ? Y : Z; - + const double depth = ui.planeDepth->value(), - condAngle = ui.condAngle->value(); - + condAngle = ui.condAngle->value(); + QTemporaryFile indat, outdat; str inDATName, outDATName; - + // Make temp files for the input and output files if (!mkTempFile (indat, inDATName) || !mkTempFile (outdat, outDATName)) return; - + // Compose the command-line arguments - str argv = join ({ - (axis == X) ? "-x" : (axis == Y) ? "-y" : "-z", + str argv = join ( + { (axis == X) ? "-x" : (axis == Y) ? "-y" : "-z", (mode == Distance) ? "-d" : (mode == Symmetry) ? "-s" : (mode == Projection) ? "-p" : "-r", depth, "-a", @@ -340,41 +339,41 @@ inDATName, outDATName }); - + writeSelection (inDATName); - + if (!runUtilityProcess (Ytruder, prog_ytruder, argv)) return; - + insertOutput (outDATName, false, {}); } // ============================================================================= // Rectifier interface // ----------------------------------------------------------------------------- -DEFINE_ACTION (Rectifier, 0){ - setlocale (LC_ALL, "C"); - +DEFINE_ACTION (Rectifier, 0) +{ setlocale (LC_ALL, "C"); + if (!checkProgPath (Rectifier)) return; - + QDialog* dlg = new QDialog; Ui::RectifierUI ui; ui.setupUi (dlg); - + if (!dlg->exec()) return; - + QTemporaryFile indat, outdat; str inDATName, outDATName; - + // Make temp files for the input and output files if (!mkTempFile (indat, inDATName) || !mkTempFile (outdat, outDATName)) return; - + // Compose arguments - str argv = join ({ - (!ui.cb_condense->isChecked()) ? "-q" : "", + str argv = join ( + { (!ui.cb_condense->isChecked()) ? "-q" : "", (!ui.cb_subst->isChecked()) ? "-r" : "", (ui.cb_condlineCheck->isChecked()) ? "-a" : "", (ui.cb_colorize->isChecked()) ? "-c" : "", @@ -383,52 +382,52 @@ inDATName, outDATName }); - + writeSelection (inDATName); - + if (!runUtilityProcess (Rectifier, prog_rectifier, argv)) return; - + insertOutput (outDATName, true, {}); } // ============================================================================= // Intersector interface // ----------------------------------------------------------------------------- -DEFINE_ACTION (Intersector, 0) { - setlocale (LC_ALL, "C"); - +DEFINE_ACTION (Intersector, 0) +{ setlocale (LC_ALL, "C"); + if (!checkProgPath (Intersector)) return; - + QDialog* dlg = new QDialog; Ui::IntersectorUI ui; ui.setupUi (dlg); - + makeColorSelector (ui.cmb_incol); makeColorSelector (ui.cmb_cutcol); ui.cb_repeat->setWhatsThis ("If this is set, " APPNAME " runs Intersector a second time with inverse files to cut the " - " cutter group with the input group. Both groups are cut by the intersection."); + " cutter group with the input group. Both groups are cut by the intersection."); ui.cb_edges->setWhatsThis ("Makes " APPNAME " try run Isecalc to create edgelines for the intersection."); - + short inCol, cutCol; const bool repeatInverse = ui.cb_repeat->isChecked(); - - for (;;) { - if (!dlg->exec()) + + forever + { if (!dlg->exec()) return; - + inCol = ui.cmb_incol->itemData (ui.cmb_incol->currentIndex()).toInt(); cutCol = ui.cmb_cutcol->itemData (ui.cmb_cutcol->currentIndex()).toInt(); - - if (inCol == cutCol) { - critical ("Cannot use the same color group for both input and cutter!"); + + if (inCol == cutCol) + { critical ("Cannot use the same color group for both input and cutter!"); continue; } - + break; } - + // Five temporary files! // indat = input group file // cutdat = cutter group file @@ -437,91 +436,92 @@ // edgesdat = edges output (isecalc) QTemporaryFile indat, cutdat, outdat, outdat2, edgesdat; str inDATName, cutDATName, outDATName, outDAT2Name, edgesDATName; - + if (!mkTempFile (indat, inDATName) || !mkTempFile (cutdat, cutDATName) || !mkTempFile (outdat, outDATName) || !mkTempFile (outdat2, outDAT2Name) || - !mkTempFile (edgesdat, edgesDATName)) { - return; + !mkTempFile (edgesdat, edgesDATName)) + { return; } - - str parms = join ({ - (ui.cb_colorize->isChecked()) ? "-c" : "", + + str parms = join ( + { (ui.cb_colorize->isChecked()) ? "-c" : "", (ui.cb_nocondense->isChecked()) ? "-t" : "", "-s", ui.dsb_prescale->value() }); - - str argv_normal = join ({ - parms, + + str argv_normal = join ( + { parms, inDATName, cutDATName, outDATName }); - - str argv_inverse = join ({ - parms, + + str argv_inverse = join ( + { parms, cutDATName, inDATName, outDAT2Name }); - + writeColorGroup (inCol, inDATName); writeColorGroup (cutCol, cutDATName); - + if (!runUtilityProcess (Intersector, prog_intersector, argv_normal)) return; - + insertOutput (outDATName, false, {inCol}); - + if (repeatInverse && runUtilityProcess (Intersector, prog_intersector, argv_inverse)) insertOutput (outDAT2Name, false, {cutCol}); - + if ( ui.cb_edges->isChecked() && checkProgPath (Isecalc) && - runUtilityProcess (Isecalc, prog_isecalc, join ({inDATName, cutDATName, edgesDATName})) + runUtilityProcess (Isecalc, prog_isecalc, join ( {inDATName, cutDATName, edgesDATName})) ) insertOutput (edgesDATName, false, {}); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Coverer, 0) { - setlocale (LC_ALL, "C"); - +DEFINE_ACTION (Coverer, 0) +{ setlocale (LC_ALL, "C"); + if (!checkProgPath (Coverer)) return; - + QDialog* dlg = new QDialog; Ui::CovererUI ui; ui.setupUi (dlg); makeColorSelector (ui.cmb_col1); makeColorSelector (ui.cmb_col2); - + short in1Col, in2Col; - - for (;;) { - if (!dlg->exec()) + + forever + { if (!dlg->exec()) return; - + in1Col = ui.cmb_col1->itemData (ui.cmb_col1->currentIndex()).toInt(); in2Col = ui.cmb_col2->itemData (ui.cmb_col2->currentIndex()).toInt(); - - if (in1Col == in2Col) { - critical ("Cannot use the same color group for both input and cutter!"); + + if (in1Col == in2Col) + { critical ("Cannot use the same color group for both input and cutter!"); continue; } + break; } - + QTemporaryFile in1dat, in2dat, outdat; str in1DATName, in2DATName, outDATName; - + if (!mkTempFile (in1dat, in1DATName) || !mkTempFile (in2dat, in2DATName) || !mkTempFile (outdat, outDATName)) return; - - str argv = join ({ - (ui.cb_oldsweep->isChecked() ? "-s" : ""), + + str argv = join ( + { (ui.cb_oldsweep->isChecked() ? "-s" : ""), (ui.cb_reverse->isChecked() ? "-r" : ""), (ui.dsb_segsplit->value() != 0 ? fmt ("-l %1", ui.dsb_segsplit->value()) : ""), (ui.sb_bias->value() != 0 ? fmt ("-s %1", ui.sb_bias->value()) : ""), @@ -529,61 +529,61 @@ in2DATName, outDATName }); - + writeColorGroup (in1Col, in1DATName); writeColorGroup (in2Col, in2DATName); - + if (!runUtilityProcess (Coverer, prog_coverer, argv)) return; - + insertOutput (outDATName, false, {}); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Isecalc, 0) { - setlocale (LC_ALL, "C"); - +DEFINE_ACTION (Isecalc, 0) +{ setlocale (LC_ALL, "C"); + if (!checkProgPath (Isecalc)) return; - + Ui::IsecalcUI ui; QDialog* dlg = new QDialog; ui.setupUi (dlg); - + makeColorSelector (ui.cmb_col1); makeColorSelector (ui.cmb_col2); - + short in1Col, in2Col; - + // Run the dialog and validate input - for (;;) { - if (!dlg->exec()) + forever + { if (!dlg->exec()) return; - + in1Col = ui.cmb_col1->itemData (ui.cmb_col1->currentIndex()).toInt(), in2Col = ui.cmb_col1->itemData (ui.cmb_col2->currentIndex()).toInt(); - - if (in1Col == in2Col) { - critical ("Cannot use the same color group for both input and cutter!"); + + if (in1Col == in2Col) + { critical ("Cannot use the same color group for both input and cutter!"); continue; } - + break; } - + QTemporaryFile in1dat, in2dat, outdat; str in1DATName, in2DATName, outDATName; - + if (!mkTempFile (in1dat, in1DATName) || !mkTempFile (in2dat, in2DATName) || !mkTempFile (outdat, outDATName)) return; - - str argv = join ({ - in1DATName, + + str argv = join ( + { in1DATName, in2DATName, outDATName }); - + writeColorGroup (in1Col, in1DATName); writeColorGroup (in2Col, in2DATName); runUtilityProcess (Isecalc, prog_isecalc, argv); @@ -592,29 +592,29 @@ // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Edger2, 0) { - setlocale (LC_ALL, "C"); - +DEFINE_ACTION (Edger2, 0) +{ setlocale (LC_ALL, "C"); + if (!checkProgPath (Edger2)) return; - + QDialog* dlg = new QDialog; Ui::Edger2Dialog ui; ui.setupUi (dlg); - + if (!dlg->exec()) return; - + QTemporaryFile in, out; str inName, outName; - + if (!mkTempFile (in, inName) || !mkTempFile (out, outName)) return; - + int unmatched = ui.unmatched->currentIndex(); - - str argv = join ({ - fmt ("-p %1", ui.precision->value()), + + str argv = join ( + { fmt ("-p %1", ui.precision->value()), fmt ("-af %1", ui.flatAngle->value()), fmt ("-ac %1", ui.condAngle->value()), fmt ("-ae %1", ui.edgeAngle->value()), @@ -628,11 +628,11 @@ inName, outName, }); - + writeSelection (inName); - + if (!runUtilityProcess (Edger2, prog_edger2, argv)) return; - + insertOutput (outName, true, {}); -} \ No newline at end of file +}
--- a/src/file.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/file.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -34,6 +34,7 @@ #include "dialogs.h" #include "gldraw.h" #include "gldata.h" +#include "moc_file.cpp" cfg (String, io_ldpath, ""); cfg (List, io_recentfiles, {}); @@ -52,59 +53,70 @@ // ============================================================================= // ----------------------------------------------------------------------------- -namespace LDPaths { - static str pathError; - - struct { - str LDConfigPath; +namespace LDPaths +{ static str pathError; + + struct + { str LDConfigPath; str partsPath, primsPath; } pathInfo; - - void initPaths() { - if (!tryConfigure (io_ldpath)) { - LDrawPathDialog dlg (false); - + + void initPaths() + { if (!tryConfigure (io_ldpath)) + { LDrawPathDialog dlg (false); + if (!dlg.exec()) exit (0); - + io_ldpath = dlg.filename(); } } - - bool tryConfigure (str path) { - QDir dir; - - if (!dir.cd (path)) { - pathError = "Directory does not exist."; + + bool tryConfigure (str path) + { QDir dir; + + if (!dir.cd (path)) + { pathError = "Directory does not exist."; return false; } - + QStringList mustHave = { "LDConfig.ldr", "parts", "p" }; QStringList contents = dir.entryList (mustHave); - - if (contents.size() != mustHave.size()) { - pathError = "Not an LDraw directory! Must<br />have LDConfig.ldr, parts/ and p/."; + + if (contents.size() != mustHave.size()) + { pathError = "Not an LDraw directory! Must<br />have LDConfig.ldr, parts/ and p/."; return false; } - + pathInfo.partsPath = fmt ("%1" DIRSLASH "parts", path); pathInfo.LDConfigPath = fmt ("%1" DIRSLASH "LDConfig.ldr", path); pathInfo.primsPath = fmt ("%1" DIRSLASH "p", path); - + return true; } - + // Accessors - str getError() { return pathError; } - str ldconfig() { return pathInfo.LDConfigPath; } - str prims() { return pathInfo.primsPath; } - str parts() { return pathInfo.partsPath; } + str getError() + { return pathError; + } + + str ldconfig() + { return pathInfo.LDConfigPath; + } + + str prims() + { return pathInfo.primsPath; + } + + str parts() + { return pathInfo.partsPath; + } } // ============================================================================= // ----------------------------------------------------------------------------- -LDFile::LDFile() { - setImplicit (true); +LDFile::LDFile() +{ setImplicit (true); setSavePos (-1); setListItem (null); m_history.setFile (this); @@ -112,136 +124,139 @@ // ============================================================================= // ----------------------------------------------------------------------------- -LDFile::~LDFile() { - // Clear everything from the model +LDFile::~LDFile() +{ // Clear everything from the model for (LDObject* obj : objects()) delete obj; - + // Clear the cache as well for (LDObject* obj : cache()) delete obj; - + // Remove this file from the list of files - for (ulong i = 0; i < g_loadedFiles.size(); ++i) { - if (g_loadedFiles[i] == this) { - g_loadedFiles.erase (i); - break; - } - } - + g_loadedFiles.removeOne (this); + // If we just closed the current file, we need to set the current // file as something else. - if (this == LDFile::current()) { - // If we closed the last file, create a blank one. - if (countExplicitFiles() == 0) + if (this == LDFile::current()) + { bool found = false; + + // Try find an explicitly loaded file - if we can't find one, + // we need to create a new file to switch to. + for (LDFile* file : g_loadedFiles) + { if (!file->implicit()) + { LDFile::setCurrent (file); + found = true; + break; + } + } + + if (!found) newFile(); - else { - // Find the first explicit file loaded - int idx = 0; - while (g_loadedFiles[idx]->implicit()) - idx++; - - LDFile::setCurrent (g_loadedFiles[idx]); - } } - + g_win->updateFileList(); } // ============================================================================= // ----------------------------------------------------------------------------- -LDFile* findLoadedFile (str name) { - for (LDFile* file : g_loadedFiles) +LDFile* findLoadedFile (str name) +{ for (LDFile * file : g_loadedFiles) if (!file->name().isEmpty() && file->getShortName() == name) return file; - + return null; } // ============================================================================= // ----------------------------------------------------------------------------- -str dirname (str path) { - long lastpos = path.lastIndexOf (DIRSLASH); - +str dirname (str path) +{ long lastpos = path.lastIndexOf (DIRSLASH); + if (lastpos > 0) return path.left (lastpos); - + #ifndef _WIN32 + if (path[0] == DIRSLASH_CHAR) return DIRSLASH; + #endif // _WIN32 - + return ""; } // ============================================================================= // ----------------------------------------------------------------------------- -str basename (str path) { - long lastpos = path.lastIndexOf (DIRSLASH); - +str basename (str path) +{ long lastpos = path.lastIndexOf (DIRSLASH); + if (lastpos != -1) return path.mid (lastpos + 1); - + return path; } // ============================================================================= // ----------------------------------------------------------------------------- -File* openLDrawFile (str relpath, bool subdirs) { - print ("%1: Try to open %2\n", __func__, relpath); +File* openLDrawFile (str relpath, bool subdirs) +{ log ("Opening %1...\n", relpath); File* f = new File; str fullPath; - + // LDraw models use Windows-style path separators. If we're not on Windows, // replace the path separator now before opening any files. #ifndef WIN32 relpath.replace ("\\", "/"); #endif // WIN32 - - if (LDFile::current()) { - // First, try find the file in the current model's file path. We want a file + + if (LDFile::current()) + { // First, try find the file in the current model's file path. We want a file // in the immediate vicinity of the current model to override stock LDraw stuff. str partpath = fmt ("%1" DIRSLASH "%2", dirname (LDFile::current()->name()), relpath); - + if (f->open (partpath, File::Read)) return f; } - + if (f->open (relpath, File::Read)) return f; - + // Try with just the LDraw path first fullPath = fmt ("%1" DIRSLASH "%2", io_ldpath, relpath); - + if (f->open (fullPath, File::Read)) return f; - - if (subdirs) { - // Look in sub-directories: parts and p. Also look in net_downloadpath. + + if (subdirs) + { // Look in sub-directories: parts and p. Also look in net_downloadpath, since that's + // where we download parts from the PT to. for (const str& topdir : initlist<str> ({ io_ldpath, net_downloadpath })) - for (const str& subdir : initlist<str> ({ "parts", "p" })) { - fullPath = fmt ("%1" DIRSLASH "%2" DIRSLASH "%3", topdir, subdir, relpath); - if (f->open (fullPath, File::Read)) - return f; + { for (const str& subdir : initlist<str> ({ "parts", "p" })) + { fullPath = fmt ("%1" DIRSLASH "%2" DIRSLASH "%3", topdir, subdir, relpath); + + if (f->open (fullPath, File::Read)) + return f; + } } } - + // Did not find the file. - print ("could not find %1\n", relpath); + log ("Could not find %1.\n", relpath); delete f; return null; } // ============================================================================= // ----------------------------------------------------------------------------- -void FileLoader::start() { - setDone (false); +void FileLoader::start() +{ setDone (false); setProgress (0); setAborted (false); - - if (concurrent()) { - g_aborted = false; - + + if (concurrent()) + { g_aborted = false; + // Show a progress dialog if we're loading the main file here so we can // show progress updates and keep the WM posted that we're still here. // Of course we cannot exec() the dialog because then the dialog would @@ -250,70 +265,70 @@ dlg->setNumLines (lines().size()); dlg->setModal (true); dlg->show(); - + // Connect the loader in so we can show updates connect (this, SIGNAL (workDone()), dlg, SLOT (accept())); connect (dlg, SIGNAL (rejected()), this, SLOT (abort())); - } else + } + else dlg = null; - + // Begin working work (0); } // ============================================================================= // ----------------------------------------------------------------------------- -void FileLoader::work (int i) { - // User wishes to abort, so stop here now. - if (aborted()) { - for (LDObject* obj : m_objs) +void FileLoader::work (int i) +{ // User wishes to abort, so stop here now. + if (aborted()) + { for (LDObject* obj : m_objs) delete obj; - + m_objs.clear(); setDone (true); return; } - + // Parse up to 300 lines per iteration int max = i + 300; - - for (; i < max && i < (int) lines().size(); ++i) { - str line = lines()[i]; - + + for (; i < max && i < (int) lines().size(); ++i) + { str line = lines() [i]; + // Trim the trailing newline qchar c; - - while (line.length() > 0 && ((c = line[line.length() - 1]) == '\n' || c == '\r')) + while (!line.isEmpty() && ((c = line[line.length() - 1]) == '\n' || c == '\r')) line.chop (1); - + LDObject* obj = parseLine (line); - + // Check for parse errors and warn about tthem - if (obj->getType() == LDObject::Error) { - log ("Couldn't parse line #%1: %2", m_progress + 1, static_cast<LDError*> (obj)->reason); - + if (obj->getType() == LDObject::Error) + { log ("Couldn't parse line #%1: %2", m_progress + 1, static_cast<LDError*> (obj)->reason); + if (m_warningsPointer) (*m_warningsPointer)++; } - + m_objs << obj; setProgress (i); - + // If we have a dialog pointer, update the progress now if (concurrent()) dlg->updateProgress (i); } - + // If we're done now, tell the environment we're done and stop. - if (i >= ((int) lines().size()) - 1) { - emit workDone(); + if (i >= ((int) lines().size()) - 1) + { emit workDone(); setDone (true); return; } - + // Otherwise, continue, by recursing back. - if (!done()) { - // If we have a dialog to show progress output to, we cannot just call + if (!done()) + { // If we have a dialog to show progress output to, we cannot just call // work() again immediately as the dialog needs some processor cycles as // well. Thus, take a detour through the event loop by using the // meta-object system. @@ -324,7 +339,7 @@ // eventually catch the invokation we throw here and send us back. Though // it's not technically recursion anymore, more like a for loop. :P if (concurrent()) - QMetaObject::invokeMethod (this, "work", Qt::QueuedConnection, Q_ARG (int, i + 1)); + QMetaObject::invokeMethod (this, "work", Qt::QueuedConnection, Q_ARG (int, i)); else work (i + 1); } @@ -332,166 +347,169 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void FileLoader::abort() { - setAborted (true); - +void FileLoader::abort() +{ setAborted (true); + if (concurrent()) g_aborted = true; } // ============================================================================= // ----------------------------------------------------------------------------- -List<LDObject*> loadFileContents (File* f, ulong* numWarnings, bool* ok) { - List<str> lines; - List<LDObject*> objs; - +QList<LDObject*> loadFileContents (File* f, int* numWarnings, bool* ok) +{ QList<str> lines; + QList<LDObject*> objs; + if (numWarnings) *numWarnings = 0; - + // Calculate the amount of lines for (str line : *f) lines << line; - + f->rewind(); - + FileLoader* loader = new FileLoader; loader->setWarningsPointer (numWarnings); loader->setLines (lines); loader->setConcurrent (g_loadingMainFile); loader->start(); - + // After start() returns, if the loader isn't done yet, it's delaying // its next iteration through the event loop. We need to catch this here // by telling the event loop to tick, which will tick the file loader again. // We keep doing this until the file loader is ready. while (loader->done() == false) qApp->processEvents(); - + // If we wanted the success value, supply that now if (ok) *ok = !loader->aborted(); - + objs = loader->objs(); return objs; } // ============================================================================= // ----------------------------------------------------------------------------- -LDFile* openDATFile (str path, bool search) { - // Convert the file name to lowercase since some parts contain uppercase +LDFile* openDATFile (str path, bool search) +{ // Convert the file name to lowercase since some parts contain uppercase // file names. I'll assume here that the library will always use lowercase // file names for the actual parts.. File* f; - + if (search) f = openLDrawFile (path.toLower(), true); - else { - f = new File (path, File::Read); - - if (!*f) { - delete f; + else + { f = new File (path, File::Read); + + if (!*f) + { delete f; return null; } } - + if (!f) return null; - + LDFile* load = new LDFile; load->setName (path); - - ulong numWarnings; + + int numWarnings; bool ok; - List<LDObject*> objs = loadFileContents (f, &numWarnings, &ok); - + QList<LDObject*> objs = loadFileContents (f, &numWarnings, &ok); + if (!ok) return null; - + for (LDObject* obj : objs) load->addObject (obj); - + delete f; g_loadedFiles << load; - - if (g_loadingMainFile) { - LDFile::setCurrent (load); + + if (g_loadingMainFile) + { LDFile::setCurrent (load); g_win->R()->setFile (load); log (QObject::tr ("File %1 parsed successfully (%2 errors)."), path, numWarnings); } - + return load; } // ============================================================================= // ----------------------------------------------------------------------------- -bool LDFile::safeToClose() { - typedef QMessageBox msgbox; +bool LDFile::safeToClose() +{ typedef QMessageBox msgbox; setlocale (LC_ALL, "C"); - + // If we have unsaved changes, warn and give the option of saving. - if (hasUnsavedChanges()) { - str message = fmt ("There are unsaved changes to %1. Should it be saved?", + if (hasUnsavedChanges()) + { str message = fmt ("There are unsaved changes to %1. Should it be saved?", (name().length() > 0) ? name() : "<anonymous>"); - + int button = msgbox::question (g_win, "Unsaved Changes", message, - (msgbox::Yes | msgbox::No | msgbox::Cancel), msgbox::Cancel); - - switch (button) { - case msgbox::Yes: - // If we don't have a file path yet, we have to ask the user for one. - if (name().length() == 0) { - str newpath = QFileDialog::getSaveFileName (g_win, "Save As", - LDFile::current()->name(), "LDraw files (*.dat *.ldr)"); - - if (newpath.length() == 0) - return false; - - setName (newpath); - } - - if (!save()) { - message = fmt (QObject::tr ("Failed to save %1: %2\nDo you still want to close?"), - name(), strerror (errno)); - - if (msgbox::critical (g_win, "Save Failure", message, - (msgbox::Yes | msgbox::No), msgbox::No) == msgbox::No) { - return false; + (msgbox::Yes | msgbox::No | msgbox::Cancel), msgbox::Cancel); + + switch (button) + { case msgbox::Yes: + + // If we don't have a file path yet, we have to ask the user for one. + if (name().length() == 0) + { str newpath = QFileDialog::getSaveFileName (g_win, "Save As", + LDFile::current()->name(), "LDraw files (*.dat *.ldr)"); + + if (newpath.length() == 0) + return false; + + setName (newpath); } - } - break; - - case msgbox::Cancel: - return false; - - default: - break; + + if (!save()) + { message = fmt (QObject::tr ("Failed to save %1: %2\nDo you still want to close?"), + name(), strerror (errno)); + + if (msgbox::critical (g_win, "Save Failure", message, + (msgbox::Yes | msgbox::No), msgbox::No) == msgbox::No) + { return false; + } + } + + break; + + case msgbox::Cancel: + return false; + + default: + break; } } - + return true; } // ============================================================================= // ----------------------------------------------------------------------------- -void closeAll() { - // Remove all loaded files and the objects they contain - List<LDFile*> files = g_loadedFiles; - for (LDFile* file : files) +void closeAll() +{ // Remove all loaded files and the objects they contain + QList<LDFile*> files = g_loadedFiles; + +for (LDFile * file : files) delete file; } // ============================================================================= // ----------------------------------------------------------------------------- -void newFile() { - // Create a new anonymous file and set it to our current +void newFile() +{ // Create a new anonymous file and set it to our current LDFile* f = new LDFile; f->setName (""); f->setImplicit (false); g_loadedFiles << f; LDFile::setCurrent (f); - + LDFile::closeInitialFile(); - + g_win->R()->setFile (f); g_win->fullRefresh(); g_win->updateTitle(); @@ -500,26 +518,26 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void addRecentFile (str path) { - alias rfiles = io_recentfiles.value; +void addRecentFile (str path) +{ alias rfiles = io_recentfiles.value; int idx = rfiles.indexOf (path); - + // If this file already is in the list, pop it out. - if (idx != -1) { - if (rfiles.size() == 1) + if (idx != -1) + { if (rfiles.size() == 1) return; // only recent file - abort and do nothing - + // Pop it out. rfiles.removeAt (idx); } - + // If there's too many recent files, drop one out. while (rfiles.size() > (g_MaxRecentFiles - 1)) rfiles.removeAt (0); - + // Add the file rfiles << path; - + Config::save(); g_win->updateRecentFilesMenu(); } @@ -527,35 +545,35 @@ // ============================================================================= // Open an LDraw file and set it as the main model // ----------------------------------------------------------------------------- -void openMainFile (str path) { - g_loadingMainFile = true; +void openMainFile (str path) +{ g_loadingMainFile = true; LDFile* file = openDATFile (path, false); - - if (!file) { - // Loading failed, thus drop down to a new file since we + + if (!file) + { // Loading failed, thus drop down to a new file since we // closed everything prior. newFile(); - - if (!g_aborted) { - // Tell the user loading failed. + + if (!g_aborted) + { // Tell the user loading failed. setlocale (LC_ALL, "C"); critical (fmt (QObject::tr ("Failed to open %1: %2"), path, strerror (errno))); } - + g_loadingMainFile = false; return; } - + file->setImplicit (false); - + // If we have an anonymous, unchanged file open as the only open file // (aside of the one we just opened), close it now. LDFile::closeInitialFile(); - + // Rebuild the object tree view now. LDFile::setCurrent (file); g_win->fullRefresh(); - + // Add it to the recent files list. addRecentFile (path); g_loadingMainFile = false; @@ -563,49 +581,49 @@ // ============================================================================= // ----------------------------------------------------------------------------- -bool LDFile::save (str savepath) { - if (!savepath.length()) +bool LDFile::save (str savepath) +{ if (!savepath.length()) savepath = name(); - + File f (savepath, File::Write); - + if (!f) return false; - + // If the second object in the list holds the file name, update that now. // Only do this if the file is explicitly open. If it's saved into a directory // called "s" or "48", prepend that into the name. LDComment* fpathComment = null; LDObject* first = object (1); - - if (!implicit() && first != null && first->getType() == LDObject::Comment) { - fpathComment = static_cast<LDComment*> (first); - - if (fpathComment->text.left (6) == "Name: ") { - str newname; + + if (!implicit() && first != null && first->getType() == LDObject::Comment) + { fpathComment = static_cast<LDComment*> (first); + + if (fpathComment->text.left (6) == "Name: ") + { str newname; str dir = basename (dirname (savepath)); - + if (dir == "s" || dir == "48") newname = dir + "\\"; - + newname += basename (savepath); fpathComment->text = fmt ("Name: %1", newname); g_win->buildObjList(); } } - + // File is open, now save the model to it. Note that LDraw requires files to // have DOS line endings, so we terminate the lines with \r\n. for (LDObject* obj : objects()) f.write (obj->raw() + "\r\n"); - + // File is saved, now clean up. f.close(); - + // We have successfully saved, update the save position now. setSavePos (history().pos()); setName (savepath); - + g_win->updateFileListItem (this); g_win->updateTitle(); return true; @@ -618,18 +636,18 @@ return new LDError (line, "Bad amount of tokens"); #define CHECK_TOKEN_NUMBERS(MIN, MAX) \ - for (ushort i = MIN; i <= MAX; ++i) \ - if (!isNumber (tokens[i])) \ + for (int i = MIN; i <= MAX; ++i) \ + if (!numeric (tokens[i])) \ return new LDError (line, fmt ("Token #%1 was `%2`, expected a number", (i + 1), tokens[i])); // ============================================================================= // ----------------------------------------------------------------------------- -static vertex parseVertex (QStringList& s, const ushort n) { - vertex v; - +static vertex parseVertex (QStringList& s, const int n) +{ vertex v; + for (const Axis ax : g_Axes) - v[ax] = atof (s[n + ax]); - + v[ax] = s[n + ax].toDouble(); + return v; } @@ -638,432 +656,439 @@ // code and returns the object parsed from it. parseLine never returns null, // the object will be LDError if it could not be parsed properly. // ----------------------------------------------------------------------------- -LDObject* parseLine (str line) { - QStringList tokens = line.split (" ", str::SkipEmptyParts); - - if (tokens.size() <= 0) { - // Line was empty, or only consisted of whitespace +LDObject* parseLine (str line) +{ QStringList tokens = line.split (" ", str::SkipEmptyParts); + + if (tokens.size() <= 0) + { // Line was empty, or only consisted of whitespace return new LDEmpty; } - + if (tokens[0].length() != 1 || tokens[0][0].isDigit() == false) return new LDError (line, "Illogical line code"); - + int num = tokens[0][0].digitValue(); - - switch (num) { - case 0: { - // Comment - str comm = line.mid (line.indexOf ("0") + 1); - - // Remove any leading whitespace - while (comm[0] == ' ') - comm.remove (0, 1); - - // Handle BFC statements - if (tokens.size() > 2 && tokens[1] == "BFC") { - for (short i = 0; i < LDBFC::NumStatements; ++i) - if (comm == fmt ("BFC %1", LDBFC::statements [i])) - return new LDBFC ((LDBFC::Type) 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. - struct { - const char* a; - LDBFC::Type b; - } BFCData[] = { - { "INVERTNEXT", LDBFC::InvertNext }, - { "NOCLIP", LDBFC::NoClip }, - { "CLIP", LDBFC::Clip } - }; - - for (const auto& i : BFCData) - if (comm == fmt ("BFC CERTIFY %1", i.a)) - return new LDBFC (i.b); + + switch (num) + { case 0: + { // Comment + str comm = line.mid (line.indexOf ("0") + 1); + + // Remove any leading whitespace + while (comm[0] == ' ') + comm.remove (0, 1); + + // Handle BFC statements + if (tokens.size() > 2 && tokens[1] == "BFC") + { for (short i = 0; i < LDBFC::NumStatements; ++i) + if (comm == fmt ("BFC %1", LDBFC::statements [i])) + return new LDBFC ( (LDBFC::Type) 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. + struct + { const char* a; + LDBFC::Type b; + } BFCData[] = + { { "INVERTNEXT", LDBFC::InvertNext }, + { "NOCLIP", LDBFC::NoClip }, + { "CLIP", LDBFC::Clip } + }; + + for (const auto & i : BFCData) + if (comm == fmt ("BFC CERTIFY %1", i.a)) + return new LDBFC (i.b); + } + + if (tokens.size() > 2 && tokens[1] == "!LDFORGE") + { // Handle LDForge-specific types, they're embedded into comments too + if (tokens[2] == "VERTEX") + { // Vertex (0 !LDFORGE VERTEX) + CHECK_TOKEN_COUNT (7) + CHECK_TOKEN_NUMBERS (3, 6) + + LDVertex* obj = new LDVertex; + obj->setColor (tokens[3].toLong()); + + for (const Axis ax : g_Axes) + obj->pos[ax] = tokens[4 + ax].toDouble(); // 4 - 6 + + return obj; + } elif (tokens[2] == "OVERLAY") + + { CHECK_TOKEN_COUNT (9); + CHECK_TOKEN_NUMBERS (5, 8) + + LDOverlay* obj = new LDOverlay; + obj->setFilename (tokens[3]); + obj->setCamera (tokens[4].toLong()); + obj->setX (tokens[5].toLong()); + obj->setY (tokens[6].toLong()); + obj->setWidth (tokens[7].toLong()); + obj->setHeight (tokens[8].toLong()); + return obj; + } + } + + // Just a regular comment: + LDComment* obj = new LDComment; + obj->text = comm; + return obj; } - - if (tokens.size() > 2 && tokens[1] == "!LDFORGE") { - // Handle LDForge-specific types, they're embedded into comments too - if (tokens[2] == "VERTEX") { - // Vertex (0 !LDFORGE VERTEX) - CHECK_TOKEN_COUNT (7) - CHECK_TOKEN_NUMBERS (3, 6) - - LDVertex* obj = new LDVertex; - obj->setColor (tokens[3].toLong()); - - for (const Axis ax : g_Axes) - obj->pos[ax] = tokens[4 + ax].toDouble(); // 4 - 6 - - return obj; - } elif (tokens[2] == "OVERLAY") { - CHECK_TOKEN_COUNT (9); - CHECK_TOKEN_NUMBERS (5, 8) - - LDOverlay* obj = new LDOverlay; - obj->setFilename (tokens[3]); - obj->setCamera (tokens[4].toLong()); - obj->setX (tokens[5].toLong()); - obj->setY (tokens[6].toLong()); - obj->setWidth (tokens[7].toLong()); - obj->setHeight (tokens[8].toLong()); + + case 1: + { // Subfile + CHECK_TOKEN_COUNT (15) + CHECK_TOKEN_NUMBERS (1, 13) + + // Try open the file. Disable g_loadingMainFile temporarily since we're + // not loading the main file now, but the subfile in question. + bool tmp = g_loadingMainFile; + g_loadingMainFile = false; + LDFile* load = getFile (tokens[14]); + g_loadingMainFile = tmp; + + // If we cannot open the file, mark it an error + if (!load) + { LDError* obj = new LDError (line, fmt ("Could not open %1", tokens[14])); + obj->setFileRef (tokens[14]); return obj; } + + LDSubfile* obj = new LDSubfile; + obj->setColor (tokens[1].toLong()); + obj->setPosition (parseVertex (tokens, 2)); // 2 - 4 + + matrix transform; + + for (short i = 0; i < 9; ++i) + transform[i] = tokens[i + 5].toDouble(); // 5 - 13 + + obj->setTransform (transform); + obj->setFileInfo (load); + return obj; } - - // Just a regular comment: - LDComment* obj = new LDComment; - obj->text = comm; - return obj; - } - - case 1: { - // Subfile - CHECK_TOKEN_COUNT (15) - CHECK_TOKEN_NUMBERS (1, 13) - - // Try open the file. Disable g_loadingMainFile temporarily since we're - // not loading the main file now, but the subfile in question. - bool tmp = g_loadingMainFile; - g_loadingMainFile = false; - LDFile* load = getFile (tokens[14]); - g_loadingMainFile = tmp; - - // If we cannot open the file, mark it an error - if (!load) { - LDError* obj = new LDError (line, fmt ("Could not open %1", tokens[14])); - obj->setFileRef (tokens[14]); + + case 2: + { CHECK_TOKEN_COUNT (8) + CHECK_TOKEN_NUMBERS (1, 7) + + // Line + LDLine* obj = new LDLine; + obj->setColor (tokens[1].toLong()); + + for (short i = 0; i < 2; ++i) + obj->setVertex (i, parseVertex (tokens, 2 + (i * 3))); // 2 - 7 + return obj; } - - LDSubfile* obj = new LDSubfile; - obj->setColor (tokens[1].toLong()); - obj->setPosition (parseVertex (tokens, 2)); // 2 - 4 - - matrix transform; - - for (short i = 0; i < 9; ++i) - transform[i] = tokens[i + 5].toDouble(); // 5 - 13 - - obj->setTransform (transform); - obj->setFileInfo (load); - return obj; - } - - case 2: { - CHECK_TOKEN_COUNT (8) - CHECK_TOKEN_NUMBERS (1, 7) - - // Line - LDLine* obj = new LDLine; - obj->setColor (tokens[1].toLong()); - - for (short i = 0; i < 2; ++i) - obj->setVertex (i, parseVertex (tokens, 2 + (i * 3))); // 2 - 7 - - return obj; - } - - case 3: { - CHECK_TOKEN_COUNT (11) - CHECK_TOKEN_NUMBERS (1, 10) - - // Triangle - LDTriangle* obj = new LDTriangle; - obj->setColor (tokens[1].toLong()); - - for (short i = 0; i < 3; ++i) - obj->setVertex (i, parseVertex (tokens, 2 + (i * 3))); // 2 - 10 - - return obj; - } - - case 4: - case 5: { - CHECK_TOKEN_COUNT (14) - CHECK_TOKEN_NUMBERS (1, 13) - - // Quadrilateral / Conditional line - LDObject* obj; - - if (num == 4) - obj = new LDQuad; - else - obj = new LDCndLine; - - obj->setColor (tokens[1].toLong()); - - for (short i = 0; i < 4; ++i) - obj->setVertex (i, parseVertex (tokens, 2 + (i * 3))); // 2 - 13 - - return obj; - } - - default: // Strange line we couldn't parse - return new LDError (line, "Unknown line code number"); + + case 3: + { CHECK_TOKEN_COUNT (11) + CHECK_TOKEN_NUMBERS (1, 10) + + // Triangle + LDTriangle* obj = new LDTriangle; + obj->setColor (tokens[1].toLong()); + + for (short i = 0; i < 3; ++i) + obj->setVertex (i, parseVertex (tokens, 2 + (i * 3))); // 2 - 10 + + return obj; + } + + case 4: + case 5: + { CHECK_TOKEN_COUNT (14) + CHECK_TOKEN_NUMBERS (1, 13) + + // Quadrilateral / Conditional line + LDObject* obj; + + if (num == 4) + obj = new LDQuad; + else + obj = new LDCndLine; + + obj->setColor (tokens[1].toLong()); + + for (short i = 0; i < 4; ++i) + obj->setVertex (i, parseVertex (tokens, 2 + (i * 3))); // 2 - 13 + + return obj; + } + + default: // Strange line we couldn't parse + return new LDError (line, "Unknown line code number"); } } // ============================================================================= // ----------------------------------------------------------------------------- -LDFile* getFile (str filename) { - // Try find the file in the list of loaded files +LDFile* getFile (str filename) +{ // Try find the file in the list of loaded files LDFile* load = findLoadedFile (filename); - + // If it's not loaded, try open it if (!load) load = openDATFile (filename, true); - + return load; } // ============================================================================= // ----------------------------------------------------------------------------- -void reloadAllSubfiles() { - if (!LDFile::current()) +void reloadAllSubfiles() +{ if (!LDFile::current()) return; - + g_loadedFiles.clear(); g_loadedFiles << LDFile::current(); - + // Go through all objects in the current file and reload the subfiles - for (LDObject* obj : LDFile::current()->objects()) { - if (obj->getType() == LDObject::Subfile) { - LDSubfile* ref = static_cast<LDSubfile*> (obj); +for (LDObject * obj : LDFile::current()->objects()) + { if (obj->getType() == LDObject::Subfile) + { LDSubfile* ref = static_cast<LDSubfile*> (obj); LDFile* fileInfo = getFile (ref->fileInfo()->name()); - + if (fileInfo) ref->setFileInfo (fileInfo); else ref->replace (new LDError (ref->raw(), "Could not open referred file")); } - + // Reparse gibberish files. It could be that they are invalid because // of loading errors. Circumstances may be different now. if (obj->getType() == LDObject::Error) obj->replace (parseLine (static_cast<LDError*> (obj)->contents)); } - + // Close all files left unused LDFile::closeUnused(); } // ============================================================================= // ----------------------------------------------------------------------------- -ulong LDFile::addObject (LDObject* obj) { - m_history.add (new AddHistory (objects().size(), obj)); +int LDFile::addObject (LDObject* obj) +{ m_history.add (new AddHistory (objects().size(), obj)); m_objects << obj; - + if (obj->getType() == LDObject::Vertex) m_vertices << obj; - + obj->setFile (this); return numObjs() - 1; } // ============================================================================= // ----------------------------------------------------------------------------- -void LDFile::addObjects (const List<LDObject*> objs) { - for (LDObject* obj : objs) +void LDFile::addObjects (const QList<LDObject*> objs) +{ for (LDObject * obj : objs) if (obj) addObject (obj); } // ============================================================================= // ----------------------------------------------------------------------------- -void LDFile::insertObj (const ulong pos, LDObject* obj) { - m_history.add (new AddHistory (pos, obj)); +void LDFile::insertObj (int pos, LDObject* obj) +{ m_history.add (new AddHistory (pos, obj)); m_objects.insert (pos, obj); obj->setFile (this); } // ============================================================================= // ----------------------------------------------------------------------------- -void LDFile::forgetObject (LDObject* obj) { - ulong idx = obj->getIndex(); +void LDFile::forgetObject (LDObject* obj) +{ int idx = obj->getIndex(); m_history.add (new DelHistory (idx, obj)); - m_objects.erase (idx); + m_objects.removeAt (idx); obj->setFile (null); } // ============================================================================= // ----------------------------------------------------------------------------- -bool safeToCloseAll() { - for (LDFile* f : g_loadedFiles) +bool safeToCloseAll() +{ for (LDFile* f : g_loadedFiles) if (!f->safeToClose()) return false; - + return true; } // ============================================================================= // ----------------------------------------------------------------------------- -void LDFile::setObject (ulong idx, LDObject* obj) { - assert (idx < numObjs()); - +void LDFile::setObject (int idx, LDObject* obj) +{ assert (idx < numObjs()); + // Mark this change to history str oldcode = object (idx)->raw(); str newcode = obj->raw(); m_history << new EditHistory (idx, oldcode, newcode); - + obj->setFile (this); m_objects[idx] = obj; } // ============================================================================= // ----------------------------------------------------------------------------- -static List<LDFile*> getFilesUsed (LDFile* node) { - List<LDFile*> filesUsed; - - for (LDObject* obj : node->objects()) { - if (obj->getType() != LDObject::Subfile) +static QList<LDFile*> getFilesUsed (LDFile* node) +{ QList<LDFile*> filesUsed; + +for (LDObject * obj : node->objects()) + { if (obj->getType() != LDObject::Subfile) continue; - + LDSubfile* ref = static_cast<LDSubfile*> (obj); filesUsed << ref->fileInfo(); filesUsed << getFilesUsed (ref->fileInfo()); } - + return filesUsed; } // ============================================================================= // Find out which files are unused and close them. // ----------------------------------------------------------------------------- -void LDFile::closeUnused() { - List<LDFile*> filesUsed = getFilesUsed (LDFile::current()); - +void LDFile::closeUnused() +{ QList<LDFile*> filesUsed = getFilesUsed (LDFile::current()); + // Anything that's explicitly opened must not be closed for (LDFile* file : g_loadedFiles) if (!file->implicit()) filesUsed << file; - + // Remove duplicated entries - filesUsed.makeUnique(); - + removeDuplicates (filesUsed); + // Close all open files that aren't in filesUsed - for (LDFile* file : g_loadedFiles) { - bool isused = false; - - for (LDFile* usedFile : filesUsed) { - if (file == usedFile) { - isused = true; + for (LDFile* file : g_loadedFiles) + { bool isused = false; + + for (LDFile* usedFile : filesUsed) + { if (file == usedFile) + { isused = true; break; } } - + if (!isused) delete file; } - + g_loadedFiles.clear(); g_loadedFiles << filesUsed; } // ============================================================================= // ----------------------------------------------------------------------------- -LDObject* LDFile::object (ulong pos) const { - if (m_objects.size() <= pos) +LDObject* LDFile::object (int pos) const +{ if (m_objects.size() <= pos) return null; - + return m_objects[pos]; } // ============================================================================= // ----------------------------------------------------------------------------- -LDObject* LDFile::obj (ulong pos) const { - return object (pos); +LDObject* LDFile::obj (int pos) const +{ return object (pos); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +int LDFile::numObjs() const +{ return objects().size(); } // ============================================================================= // ----------------------------------------------------------------------------- -ulong LDFile::numObjs() const { - return objects().size(); +bool LDFile::hasUnsavedChanges() const +{ return !implicit() && history().pos() != savePos(); } // ============================================================================= // ----------------------------------------------------------------------------- -bool LDFile::hasUnsavedChanges() const { - return !implicit() && history().pos() != savePos(); -} +str LDFile::getShortName() +{ if (!name().isEmpty()) + return basename (name()); -// ============================================================================= -// ----------------------------------------------------------------------------- -str LDFile::getShortName() { - if (name().length() > 0) - return basename (name()); - + if (!defaultName().isEmpty()) + return defaultName(); + return tr ("<anonymous>"); } // ============================================================================= // ----------------------------------------------------------------------------- -List<LDObject*> LDFile::inlineContents (LDSubfile::InlineFlags flags) { - // Possibly substitute with logoed studs: +QList<LDObject*> LDFile::inlineContents (LDSubfile::InlineFlags flags) +{ // Possibly substitute with logoed studs: // stud.dat -> stud-logo.dat // stud2.dat -> stud-logo2.dat - if (gl_logostuds && (flags & LDSubfile::RendererInline)) { - if (name() == "stud.dat" && g_logoedStud) + if (gl_logostuds && (flags & LDSubfile::RendererInline)) + { if (name() == "stud.dat" && g_logoedStud) return g_logoedStud->inlineContents (flags); + elif (name() == "stud2.dat" && g_logoedStud2) - return g_logoedStud2->inlineContents (flags); + return g_logoedStud2->inlineContents (flags); } - - List<LDObject*> objs, objcache; - + + QList<LDObject*> objs, objcache; + bool deep = flags & LDSubfile::DeepInline, - doCache = flags & LDSubfile::CacheInline; - + doCache = flags & LDSubfile::CacheInline; + // If we have this cached, just clone that - if (deep && cache().size()) { - for (LDObject* obj : cache()) + if (deep && cache().size()) +{ for (LDObject * obj : cache()) objs << obj->clone(); - } else { - if (!deep) + } + else + { if (!deep) doCache = false; - - for (LDObject* obj : objects()) { - // Skip those without scemantic meaning + + for (LDObject * obj : objects()) + { // Skip those without scemantic meaning if (!obj->isScemantic()) continue; - + // Got another sub-file reference, inline it if we're deep-inlining. If not, // just add it into the objects normally. Also, we only cache immediate // subfiles and this is not one. Yay, recursion! - if (deep && obj->getType() == LDObject::Subfile) { - LDSubfile* ref = static_cast<LDSubfile*> (obj); - + if (deep && obj->getType() == LDObject::Subfile) + { LDSubfile* ref = static_cast<LDSubfile*> (obj); + // We only want to cache immediate subfiles, so shed the caching // flag when recursing deeper in hierarchy. - List<LDObject*> otherobjs = ref->inlineContents (flags & ~(LDSubfile::CacheInline)); - - for (LDObject* otherobj : otherobjs) { - // Cache this object, if desired + QList<LDObject*> otherobjs = ref->inlineContents (flags & ~ (LDSubfile::CacheInline)); + + for (LDObject * otherobj : otherobjs) + { // Cache this object, if desired if (doCache) objcache << otherobj->clone(); - + objs << otherobj; } - } else { - if (doCache) + } + else + { if (doCache) objcache << obj->clone(); - + objs << obj->clone(); } } - + if (doCache) setCache (objcache); } - + return objs; } // ============================================================================= // ----------------------------------------------------------------------------- -LDFile* LDFile::current() { - return m_curfile; +LDFile* LDFile::current() +{ return m_curfile; } // ============================================================================= @@ -1072,38 +1097,37 @@ // // FIXME: f can be temporarily null. This probably should not be the case. // ----------------------------------------------------------------------------- -void LDFile::setCurrent (LDFile* f) { - // Implicit files were loaded for caching purposes and must never be set +void LDFile::setCurrent (LDFile* f) +{ // Implicit files were loaded for caching purposes and must never be set // current. if (f && f->implicit()) return; - + m_curfile = f; - - if (g_win && f) { - // A ton of stuff needs to be updated - g_win->clearSelection(); + + if (g_win && f) + { // A ton of stuff needs to be updated g_win->updateFileListItem (f); g_win->buildObjList(); g_win->updateTitle(); g_vertexCompiler.needMerge(); g_win->R()->setFile (f); - g_win->R()->resetAngles(); + g_win->R()->resetAllAngles(); g_win->R()->repaint(); - + log ("Changed file to %1", f->getShortName()); } } // ============================================================================= // ----------------------------------------------------------------------------- -int LDFile::countExplicitFiles() { - int count = 0; - +int LDFile::countExplicitFiles() +{ int count = 0; + for (LDFile* f : g_loadedFiles) if (f->implicit() == false) count++; - + return count; } @@ -1111,8 +1135,8 @@ // This little beauty closes the initial file that was open at first when opening // a new file over it. // ----------------------------------------------------------------------------- -void LDFile::closeInitialFile() { - if ( +void LDFile::closeInitialFile() +{ if ( countExplicitFiles() == 2 && g_loadedFiles[0]->name() == "" && !g_loadedFiles[0]->hasUnsavedChanges() @@ -1122,13 +1146,49 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void loadLogoedStuds() { - print ("Loading logoed studs...\n"); - +void loadLogoedStuds() +{ log ("Loading logoed studs...\n"); + delete g_logoedStud; delete g_logoedStud2; - + g_logoedStud = openDATFile ("stud-logo.dat", true); g_logoedStud2 = openDATFile ("stud2-logo.dat", true); } -#include "moc_file.cpp" + +// ============================================================================= +// ----------------------------------------------------------------------------- +void LDFile::addToSelection (LDObject* obj) // [protected] +{ if (obj->selected()) + return; + + assert (obj->file() == this); + m_sel << obj; + obj->setSelected (true); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void LDFile::removeFromSelection (LDObject* obj) // [protected] +{ if (!obj->selected()) + return; + + assert (obj->file() == this); + m_sel.removeOne (obj); + obj->setSelected (false); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void LDFile::clearSelection() +{ for (LDObject* obj : m_sel) + removeFromSelection (obj); + + assert (m_sel.isEmpty()); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +const QList<LDObject*>& LDFile::selection() const +{ return m_sel; +}
--- a/src/file.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/file.h Wed Oct 23 12:46:10 2013 +0300 @@ -29,10 +29,10 @@ class History; class OpenProgressDialog; -namespace LDPaths { - void initPaths(); +namespace LDPaths +{ void initPaths(); bool tryConfigure (str path); - + str ldconfig(); str prims(); str parts(); @@ -47,55 +47,86 @@ // // A file is implicit when they are opened automatically for caching purposes // and are hidden from the user. User-opened files are explicit (not implicit). +// +// The default name is a placeholder, initially suggested name for a file. The +// primitive generator uses this to give initial names to primitives. // ============================================================================= -class LDFile : public QObject { - Q_OBJECT - READ_PROPERTY (List<LDObject*>, objects, setObjects) - READ_PROPERTY (History, history, setHistory) - READ_PROPERTY (List<LDObject*>, vertices, setVertices) - PROPERTY (str, name, setName) - PROPERTY (bool, implicit, setImplicit) - PROPERTY (List<LDObject*>, cache, setCache) - PROPERTY (long, savePos, setSavePos) - DECLARE_PROPERTY (QListWidgetItem*, listItem, setListItem) - -public: - typedef List<LDObject*>::it it; - typedef List<LDObject*>::c_it c_it; - - LDFile(); - ~LDFile(); - - ulong addObject (LDObject* obj); // Adds an object to this file at the end of the file. - void addObjects (const List<LDObject*> objs); - void forgetObject (LDObject* obj); // Deletes the given object from the object chain. - str getShortName(); - bool hasUnsavedChanges() const; // Does this file have unsaved changes? - List<LDObject*> inlineContents (LDSubfile::InlineFlags flags); - void insertObj (const ulong pos, LDObject* obj); - ulong numObjs() const; - LDObject* object (ulong pos) const; - LDObject* obj (ulong pos) const; - bool save (str path = ""); // Saves this file to disk. - bool safeToClose(); // Perform safety checks. Do this before closing any files! - void setObject (ulong idx, LDObject* obj); +class LDFile : public QObject +{ Q_OBJECT + READ_PROPERTY (QList<LDObject*>, objects, setObjects) + READ_PROPERTY (History, history, setHistory) + READ_PROPERTY (QList<LDObject*>, vertices, setVertices) + PROPERTY (str, name, setName) + PROPERTY (str, defaultName, setDefaultName) + PROPERTY (bool, implicit, setImplicit) + PROPERTY (QList<LDObject*>, cache, setCache) + PROPERTY (long, savePos, setSavePos) + DECLARE_PROPERTY (QListWidgetItem*, listItem, setListItem) + + public: + LDFile(); + ~LDFile(); + + int addObject (LDObject* obj); // Adds an object to this file at the end of the file. + void addObjects (const QList<LDObject*> objs); + void clearSelection(); + void forgetObject (LDObject* obj); // Deletes the given object from the object chain. + str getShortName(); + const QList<LDObject*>& selection() const; + bool hasUnsavedChanges() const; // Does this file have unsaved changes? + QList<LDObject*> inlineContents (LDSubfile::InlineFlags flags); + void insertObj (int pos, LDObject* obj); + int numObjs() const; + LDObject* object (int pos) const; + LDObject* obj (int pos) const; + bool save (str path = ""); // Saves this file to disk. + bool safeToClose(); // Perform safety checks. Do this before closing any files! + void setObject (int idx, LDObject* obj); + + inline LDFile& operator<< (LDObject* obj) + { addObject (obj); + return *this; + } - inline LDFile& operator<< (LDObject* obj) { addObject (obj); return *this; } - inline void openHistory() { m_history.open(); } - inline void closeHistory() { m_history.close(); } - inline void undo() { m_history.undo(); } - inline void redo() { m_history.redo(); } - inline void clearHistory() { m_history.clear(); } - inline void addToHistory (AbstractHistoryEntry* entry) { m_history << entry; } - - static void closeUnused(); - static LDFile* current(); - static void setCurrent (LDFile* f); - static void closeInitialFile(); - static int countExplicitFiles(); - -private: - static LDFile* m_curfile; + inline void openHistory() + { m_history.open(); + } + + inline void closeHistory() + { m_history.close(); + } + + inline void undo() + { m_history.undo(); + } + + inline void redo() + { m_history.redo(); + } + + inline void clearHistory() + { m_history.clear(); + } + + inline void addToHistory (AbstractHistoryEntry* entry) + { m_history << entry; + } + + static void closeUnused(); + static LDFile* current(); + static void setCurrent (LDFile* f); + static void closeInitialFile(); + static int countExplicitFiles(); + + protected: + void addToSelection (LDObject* obj); + void removeFromSelection (LDObject* obj); + friend class LDObject; + + private: + QList<LDObject*> m_sel; + + static LDFile* m_curfile; }; // Close all current loaded files and start off blank. @@ -129,16 +160,20 @@ // Is it safe to close all files? bool safeToCloseAll(); -List<LDObject*> loadFileContents (File* f, ulong* numWarnings, bool* ok = null); +QList<LDObject*> loadFileContents (File* f, int* numWarnings, bool* ok = null); + +extern QList<LDFile*> g_loadedFiles; -extern List<LDFile*> g_loadedFiles; +inline const QList<LDObject*>& selection() +{ return LDFile::current()->selection(); +} void addRecentFile (str path); void loadLogoedStuds(); str basename (str path); str dirname (str path); -extern List<LDFile*> g_loadedFiles; // Vector of all currently opened files. +extern QList<LDFile*> g_loadedFiles; // Vector of all currently opened files. // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * @@ -146,31 +181,32 @@ // FileLoader // // Loads the given file and parses it to LDObjects using parseLine. It's a -// separate class so as to be able to do the work in a separate thread. +// separate class so as to be able to do the work progressively through the +// event loop, allowing the program to maintain responsivity during loading. // ============================================================================= -class FileLoader : public QObject { - Q_OBJECT - READ_PROPERTY (List<LDObject*>, objs, setObjects) - READ_PROPERTY (bool, done, setDone) - READ_PROPERTY (ulong, progress, setProgress) - READ_PROPERTY (bool, aborted, setAborted) - PROPERTY (List<str>, lines, setLines) - PROPERTY (ulong*, warningsPointer, setWarningsPointer) - PROPERTY (bool, concurrent, setConcurrent) - -public slots: - void start(); - void abort(); - -private: - OpenProgressDialog* dlg; - -private slots: - void work (int i); - -signals: - void progressUpdate (int progress); - void workDone(); +class FileLoader : public QObject +{ Q_OBJECT + READ_PROPERTY (QList<LDObject*>, objs, setObjects) + READ_PROPERTY (bool, done, setDone) + READ_PROPERTY (int, progress, setProgress) + READ_PROPERTY (bool, aborted, setAborted) + PROPERTY (QList<str>, lines, setLines) + PROPERTY (int*, warningsPointer, setWarningsPointer) + PROPERTY (bool, concurrent, setConcurrent) + + public slots: + void start(); + void abort(); + + private: + OpenProgressDialog* dlg; + + private slots: + void work (int i); + + signals: + void progressUpdate (int progress); + void workDone(); }; -#endif // FILE_H \ No newline at end of file +#endif // FILE_H
--- a/src/gldraw.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/gldraw.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -36,14 +36,11 @@ #include "addObjectDialog.h" #include "messagelog.h" #include "gldata.h" -#include "build/moc_gldraw.cpp" +#include "primitives.h" +#include "moc_gldraw.cpp" -static const struct staticCameraMeta { - const int8 glrotate[3]; - const Axis axisX, axisY; - const bool negX, negY; -} g_staticCameras[6] = { - {{ 1, 0, 0 }, X, Z, false, false }, +static const LDFixedCameraInfo g_FixedCameras[6] = +{ {{ 1, 0, 0 }, X, Z, false, false }, {{ 0, 0, 0 }, X, Y, false, true }, {{ 0, 1, 0 }, Z, Y, true, true }, {{ -1, 0, 0 }, X, Z, false, true }, @@ -51,6 +48,12 @@ {{ 0, -1, 0 }, Z, Y, false, true }, }; +static const matrix g_circleDrawTransforms[3] = +{ { 2, 0, 0, 0, 1, 0, 0, 0, 2 }, + { 2, 0, 0, 0, 0, 2, 0, 1, 0 }, + { 0, 1, 0, 2, 0, 0, 0, 0, 2 }, +}; + cfg (String, gl_bgcolor, "#CCCCD9"); cfg (String, gl_maincolor, "#707078"); cfg (Float, gl_maincolor_alpha, 1.0); @@ -60,20 +63,21 @@ cfg (Bool, gl_axes, false); cfg (Bool, gl_wireframe, false); cfg (Bool, gl_logostuds, false); +cfg (Bool, gl_aa, true); // argh -const char* g_CameraNames[7] = { - QT_TRANSLATE_NOOP ("GLRenderer", "Top"), - QT_TRANSLATE_NOOP ("GLRenderer", "Front"), - QT_TRANSLATE_NOOP ("GLRenderer", "Left"), - QT_TRANSLATE_NOOP ("GLRenderer", "Bottom"), - QT_TRANSLATE_NOOP ("GLRenderer", "Back"), - QT_TRANSLATE_NOOP ("GLRenderer", "Right"), - QT_TRANSLATE_NOOP ("GLRenderer", "Free") +const char* g_CameraNames[7] = +{ QT_TRANSLATE_NOOP ("GLRenderer", "Top"), + QT_TRANSLATE_NOOP ("GLRenderer", "Front"), + QT_TRANSLATE_NOOP ("GLRenderer", "Left"), + QT_TRANSLATE_NOOP ("GLRenderer", "Bottom"), + QT_TRANSLATE_NOOP ("GLRenderer", "Back"), + QT_TRANSLATE_NOOP ("GLRenderer", "Right"), + QT_TRANSLATE_NOOP ("GLRenderer", "Free") }; -const GL::Camera g_Cameras[7] = { - GL::Top, +const GL::Camera g_Cameras[7] = +{ GL::Top, GL::Front, GL::Left, GL::Bottom, @@ -82,19 +86,19 @@ GL::Free }; -const struct GLAxis { - const QColor col; +const struct LDGLAxis +{ const QColor col; const vertex vert; -} g_GLAxes[3] = { - { QColor (255, 0, 0), vertex (10000, 0, 0) }, +} g_GLAxes[3] = +{ { QColor (255, 0, 0), vertex (10000, 0, 0) }, { QColor (80, 192, 0), vertex (0, 10000, 0) }, { QColor (0, 160, 192), vertex (0, 0, 10000) }, }; // ============================================================================= // ----------------------------------------------------------------------------- -GLRenderer::GLRenderer (QWidget* parent) : QGLWidget (parent) { - m_picking = m_rangepick = false; +GLRenderer::GLRenderer (QWidget* parent) : QGLWidget (parent) +{ m_picking = m_rangepick = false; m_camera = (GL::Camera) gl_camera.value; m_drawToolTip = false; m_editMode = Select; @@ -102,94 +106,123 @@ m_panning = false; setFile (null); setDrawOnly (false); - resetAngles(); setMessageLog (null); - + m_width = m_height = -1; + m_hoverpos = g_origin; + m_toolTipTimer = new QTimer (this); m_toolTipTimer->setSingleShot (true); connect (m_toolTipTimer, SIGNAL (timeout()), this, SLOT (slot_toolTipTimer())); - + m_thickBorderPen = QPen (QColor (0, 0, 0, 208), 2, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin); m_thinBorderPen = m_thickBorderPen; m_thinBorderPen.setWidth (1); - + // Init camera icons - for (const GL::Camera cam : g_Cameras) { - str iconname = fmt ("camera-%1", tr (g_CameraNames[cam]).toLower()); - + for (const GL::Camera cam : g_Cameras) + { str iconname = fmt ("camera-%1", tr (g_CameraNames[cam]).toLower()); + CameraIcon* info = &m_cameraIcons[cam]; info->img = new QPixmap (getIcon (iconname)); info->cam = cam; } - - for (int i = 0; i < 6; ++i) { - m_overlays[i].img = null; + + for (int i = 0; i < 6; ++i) + { m_overlays[i].img = null; m_depthValues[i] = 0.0f; } - + calcCameraIcons(); } // ============================================================================= // ----------------------------------------------------------------------------- -GLRenderer::~GLRenderer() { - for (int i = 0; i < 6; ++i) +GLRenderer::~GLRenderer() +{ for (int i = 0; i < 6; ++i) delete m_overlays[i].img; - + for (CameraIcon& info : m_cameraIcons) delete info.img; } // ============================================================================= +// Calculates the "hitboxes" of the camera icons so that we can tell when the +// cursor is pointing at the camera icon. // ----------------------------------------------------------------------------- -void GLRenderer::calcCameraIcons() { - ushort i = 0; - - for (CameraIcon& info : m_cameraIcons) { +void GLRenderer::calcCameraIcons() +{ int i = 0; + + for (CameraIcon& info : m_cameraIcons) + { // MATH const long x1 = (m_width - (info.cam != Free ? 48 : 16)) + ((i % 3) * 16) - 1, y1 = ((i / 3) * 16) + 1; - + info.srcRect = QRect (0, 0, 16, 16); info.destRect = QRect (x1, y1, 16, 16); - info.selRect = QRect (info.destRect.x(), info.destRect.y(), - info.destRect.width() + 1, info.destRect.height() + 1); + info.selRect = QRect ( + info.destRect.x(), + info.destRect.y(), + info.destRect.width() + 1, + info.destRect.height() + 1 + ); + ++i; } } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::initGLData() { - glEnable (GL_BLEND); +void GLRenderer::initGLData() +{ glEnable (GL_BLEND); glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable (GL_POLYGON_OFFSET_FILL); glPolygonOffset (1.0f, 1.0f); - + glEnable (GL_DEPTH_TEST); glShadeModel (GL_SMOOTH); glEnable (GL_MULTISAMPLE); - - glEnable (GL_LINE_SMOOTH); - glHint (GL_LINE_SMOOTH_HINT, GL_NICEST); + + if (gl_aa) + { glEnable (GL_LINE_SMOOTH); + glEnable (GL_POLYGON_SMOOTH); + glHint (GL_LINE_SMOOTH_HINT, GL_NICEST); + glHint (GL_POLYGON_SMOOTH_HINT, GL_NICEST); + } else + { glDisable (GL_LINE_SMOOTH); + glDisable (GL_POLYGON_SMOOTH); + } } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::resetAngles() { - m_rotX = 30.0f; - m_rotY = 325.f; - m_panX = m_panY = m_rotZ = 0.0f; +void GLRenderer::resetAngles() +{ rot (X) = 30.0f; + rot (Y) = 325.f; + pan (X) = pan (Y) = rot (Z) = 0.0f; zoomToFit(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::initializeGL() { - setBackground(); - +void GLRenderer::resetAllAngles() +{ Camera oldcam = camera(); + + for (int i = 0; i < 7; ++i) + { setCamera ((Camera) i); + resetAngles(); + } + + setCamera (oldcam); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void GLRenderer::initializeGL() +{ setBackground(); + glLineWidth (gl_linethickness); glLineStipple (1, 0x6666); - + setAutoFillBackground (false); setMouseTracking (true); setFocusPolicy (Qt::WheelFocus); @@ -199,26 +232,26 @@ // ============================================================================= // ----------------------------------------------------------------------------- -QColor GLRenderer::getMainColor() { - QColor col (gl_maincolor); - +QColor GLRenderer::getMainColor() +{ QColor col (gl_maincolor); + if (!col.isValid()) return QColor (0, 0, 0); - + col.setAlpha (gl_maincolor_alpha * 255.f); return col; } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::setBackground() { - QColor col (gl_bgcolor); - +void GLRenderer::setBackground() +{ QColor col (gl_bgcolor); + if (!col.isValid()) return; - + col.setAlpha (255); - + m_darkbg = luma (col) < 80; m_bgcolor = col; qglClearColor (col); @@ -236,18 +269,18 @@ void GLRenderer::hardRefresh() { g_vertexCompiler.compileFile(); refresh(); - + glLineWidth (gl_linethickness); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::resizeGL (int w, int h) { - m_width = w; +void GLRenderer::resizeGL (int w, int h) +{ m_width = w; m_height = h; - + calcCameraIcons(); - + glViewport (0, 0, w, h); glMatrixMode (GL_PROJECTION); glLoadIdentity(); @@ -257,61 +290,62 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::drawGLScene() { - if (file() == null) +void GLRenderer::drawGLScene() +{ if (file() == null) return; - + if (gl_wireframe && !picking()) glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); - + glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable (GL_DEPTH_TEST); - - if (m_camera != Free) { - glMatrixMode (GL_PROJECTION); + + if (m_camera != Free) + { glMatrixMode (GL_PROJECTION); glPushMatrix(); - + glLoadIdentity(); glOrtho (-m_virtWidth, m_virtWidth, -m_virtHeight, m_virtHeight, -100.0f, 100.0f); - glTranslatef (m_panX, m_panY, 0.0f); - - if (m_camera != Front && m_camera != Back) { - glRotatef (90.0f, g_staticCameras[m_camera].glrotate[0], - g_staticCameras[m_camera].glrotate[1], - g_staticCameras[m_camera].glrotate[2]); + glTranslatef (pan (X), pan (Y), 0.0f); + + if (m_camera != Front && m_camera != Back) + { glRotatef (90.0f, g_FixedCameras[camera()].glrotate[0], + g_FixedCameras[camera()].glrotate[1], + g_FixedCameras[camera()].glrotate[2]); } - + // Back camera needs to be handled differently - if (m_camera == GL::Back) { - glRotatef (180.0f, 1.0f, 0.0f, 0.0f); + if (m_camera == GL::Back) + { glRotatef (180.0f, 1.0f, 0.0f, 0.0f); glRotatef (180.0f, 0.0f, 0.0f, 1.0f); } - } else { - glMatrixMode (GL_MODELVIEW); + } + else + { glMatrixMode (GL_MODELVIEW); glPushMatrix(); glLoadIdentity(); - + glTranslatef (0.0f, 0.0f, -2.0f); - glTranslatef (m_panX, m_panY, -zoom()); - glRotatef (m_rotX, 1.0f, 0.0f, 0.0f); - glRotatef (m_rotY, 0.0f, 1.0f, 0.0f); - glRotatef (m_rotZ, 0.0f, 0.0f, 1.0f); + glTranslatef (pan (X), pan (Y), -zoom()); + glRotatef (rot (X), 1.0f, 0.0f, 0.0f); + glRotatef (rot (Y), 0.0f, 1.0f, 0.0f); + glRotatef (rot (Z), 0.0f, 0.0f, 1.0f); } // Draw the VAOs now glEnableClientState (GL_VERTEX_ARRAY); glEnableClientState (GL_COLOR_ARRAY); glDisableClientState (GL_NORMAL_ARRAY); - + if (gl_colorbfc) { glEnable (GL_CULL_FACE); glCullFace (GL_CCW); } else glDisable (GL_CULL_FACE); - + drawVAOs ((m_picking ? PickArray : gl_colorbfc ? BFCArray : MainArray), GL_TRIANGLES); drawVAOs ((m_picking ? EdgePickArray : EdgeArray), GL_LINES); - + // Draw conditional lines. Note that conditional lines are drawn into // EdgePickArray in the picking scene, so when picking, don't do anything // here. @@ -320,7 +354,7 @@ drawVAOs (CondEdgeArray, GL_LINES); glDisable (GL_LINE_STIPPLE); } - + glPopMatrix(); glMatrixMode (GL_MODELVIEW); glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); @@ -339,28 +373,28 @@ // This converts a 2D point on the screen to a 3D point in the model. If 'snap' // is true, the 3D point will snap to the current grid. // ----------------------------------------------------------------------------- -vertex GLRenderer::coordconv2_3 (const QPoint& pos2d, bool snap) const { - assert (camera() != Free); - +vertex GLRenderer::coordconv2_3 (const QPoint& pos2d, bool snap) const +{ assert (camera() != Free); + vertex pos3d; - const staticCameraMeta* cam = &g_staticCameras[m_camera]; + const LDFixedCameraInfo* cam = &g_FixedCameras[m_camera]; const Axis axisX = cam->axisX; const Axis axisY = cam->axisY; const short negXFac = cam->negX ? -1 : 1, - negYFac = cam->negY ? -1 : 1; - + negYFac = cam->negY ? -1 : 1; + // Calculate cx and cy - these are the LDraw unit coords the cursor is at. - double cx = (-m_virtWidth + ((2 * pos2d.x() * m_virtWidth) / m_width) - m_panX); - double cy = (m_virtHeight - ((2 * pos2d.y() * m_virtHeight) / m_height) - m_panY); - - if (snap) { - cx = Grid::snap (cx, (Grid::Config) axisX); + double cx = (-m_virtWidth + ((2 * pos2d.x() * m_virtWidth) / m_width) - pan (X)); + double cy = (m_virtHeight - ((2 * pos2d.y() * m_virtHeight) / m_height) - pan (Y)); + + if (snap) + { cx = Grid::snap (cx, (Grid::Config) axisX); cy = Grid::snap (cy, (Grid::Config) axisY); } - + cx *= negXFac; cy *= negYFac; - + str tmp; // Create the vertex from the coordinates pos3d[axisX] = tmp.sprintf ("%.3f", cx).toDouble(); @@ -374,203 +408,286 @@ // Inverse operation for the above - convert a 3D position to a 2D screen // position // ----------------------------------------------------------------------------- -QPoint GLRenderer::coordconv3_2 (const vertex& pos3d) const { - GLfloat m[16]; - const staticCameraMeta* cam = &g_staticCameras[m_camera]; +QPoint GLRenderer::coordconv3_2 (const vertex& pos3d) const +{ GLfloat m[16]; + const LDFixedCameraInfo* cam = &g_FixedCameras[m_camera]; const Axis axisX = cam->axisX; const Axis axisY = cam->axisY; const short negXFac = cam->negX ? -1 : 1, - negYFac = cam->negY ? -1 : 1; - + negYFac = cam->negY ? -1 : 1; + glGetFloatv (GL_MODELVIEW_MATRIX, m); - + const double x = pos3d.x(); const double y = pos3d.y(); const double z = pos3d.z(); - + vertex transformed; transformed[X] = (m[0] * x) + (m[1] * y) + (m[2] * z) + m[3]; transformed[Y] = (m[4] * x) + (m[5] * y) + (m[6] * z) + m[7]; transformed[Z] = (m[8] * x) + (m[9] * y) + (m[10] * z) + m[11]; - - double rx = (((transformed[axisX] * negXFac) + m_virtWidth + m_panX) * m_width) / (2 * m_virtWidth); - double ry = (((transformed[axisY] * negYFac) - m_virtHeight + m_panY) * m_height) / (2 * m_virtHeight); - + + double rx = (((transformed[axisX] * negXFac) + m_virtWidth + pan (X)) * m_width) / (2 * m_virtWidth); + double ry = (((transformed[axisY] * negYFac) - m_virtHeight + pan (Y)) * m_height) / (2 * m_virtHeight); + return QPoint (rx, -ry); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::paintEvent (QPaintEvent* ev) { - Q_UNUSED (ev) - +void GLRenderer::paintEvent (QPaintEvent* ev) +{ Q_UNUSED (ev) + makeCurrent(); m_virtWidth = zoom(); m_virtHeight = (m_height * m_virtWidth) / m_width; - + initGLData(); drawGLScene(); - + + const QPen textpen = getTextPen(); + const QBrush polybrush (QColor (64, 192, 0, 128)); QPainter paint (this); QFontMetrics metrics = QFontMetrics (QFont()); paint.setRenderHint (QPainter::HighQualityAntialiasing); - + // If we wish to only draw the brick, stop here if (drawOnly()) return; - - if (m_camera != Free && !picking()) { - // Paint the overlay image if we have one - const overlayMeta& overlay = m_overlays[m_camera]; - if (overlay.img != null) { - QPoint v0 = coordconv3_2 (m_overlays[m_camera].v0), - v1 = coordconv3_2 (m_overlays[m_camera].v1); - + + if (m_camera != Free && !picking()) + { // Paint the overlay image if we have one + const LDGLOverlay& overlay = m_overlays[m_camera]; + + if (overlay.img != null) + { QPoint v0 = coordconv3_2 (m_overlays[m_camera].v0), + v1 = coordconv3_2 (m_overlays[m_camera].v1); + QRect targRect (v0.x(), v0.y(), abs (v1.x() - v0.x()), abs (v1.y() - v0.y())), - srcRect (0, 0, overlay.img->width(), overlay.img->height()); + srcRect (0, 0, overlay.img->width(), overlay.img->height()); paint.drawImage (targRect, *overlay.img, srcRect); } - + // Paint the coordinates onto the screen. str text = fmt (tr ("X: %1, Y: %2, Z: %3"), m_hoverpos[X], m_hoverpos[Y], m_hoverpos[Z]); - + QFontMetrics metrics = QFontMetrics (font()); QRect textSize = metrics.boundingRect (0, 0, m_width, m_height, Qt::AlignCenter, text); - + paint.setPen (getTextPen()); paint.drawText (m_width - textSize.width(), m_height - 16, textSize.width(), textSize.height(), Qt::AlignCenter, text); - + + QPen linepen = m_thinBorderPen; + linepen.setWidth (2); + linepen.setColor (luma (m_bgcolor) < 40 ? Qt::white : Qt::black); + // If we're drawing, draw the vertices onto the screen. - if (editMode() == Draw) { - const short blipsize = 8; - int numverts = 4; - + if (editMode() == Draw) + { int numverts = 4; + if (!m_rectdraw) numverts = m_drawedVerts.size() + 1; - - if (numverts > 0) { - QPoint poly[4]; + + if (numverts > 0) + { QPoint poly[4]; vertex polyverts[4]; - - if (!m_rectdraw) { - uchar i = 0; - for (vertex& vert : m_drawedVerts) { - poly[i] = coordconv3_2 (vert); + + if (!m_rectdraw) + { uchar i = 0; + + for (vertex& vert : m_drawedVerts) + { poly[i] = coordconv3_2 (vert); polyverts[i] = vert; ++i; } - + // Draw the cursor vertex as the last one in the list. - if (numverts <= 4) { - poly[i] = coordconv3_2 (m_hoverpos); + if (numverts <= 4) + { poly[i] = coordconv3_2 (m_hoverpos); polyverts[i] = m_hoverpos; - } else { - numverts = 4; + } + else + { numverts = 4; } - } else { - if (m_drawedVerts.size() > 0) { - // Get vertex information from m_rectverts - for (int i = 0; i < numverts; ++i) { - polyverts[i] = m_rectverts[i]; + } + else + { if (m_drawedVerts.size() > 0) + { // Get vertex information from m_rectverts + for (int i = 0; i < numverts; ++i) + { polyverts[i] = m_rectverts[i]; poly[i] = coordconv3_2 (polyverts[i]); } - } else { - poly[0] = coordconv3_2 (m_hoverpos); + } + else + { poly[0] = coordconv3_2 (m_hoverpos); polyverts[0] = m_hoverpos; } } - + // Draw the polygon-to-be - QPen pen = m_thinBorderPen; - pen.setWidth (2); - pen.setColor (luma (m_bgcolor) < 40 ? Qt::white : Qt::black); - paint.setPen (pen); - paint.setBrush (QColor (64, 192, 0, 128)); + paint.setPen (linepen); + paint.setBrush (polybrush); paint.drawPolygon (poly, numverts); - + // Draw vertex blips - pen = m_thinBorderPen; - pen.setWidth (1); - paint.setPen (pen); - paint.setBrush (QColor (64, 192, 0)); - - for (ushort i = 0; i < numverts; ++i) { - QPoint& blip = poly[i]; - paint.drawEllipse (blip.x() - blipsize / 2, blip.y() - blipsize / 2, - blipsize, blipsize); - + for (int i = 0; i < numverts; ++i) + { QPoint& blip = poly[i]; + drawBlip (paint, blip); + // Draw their coordinates paint.drawText (blip.x(), blip.y() - 8, polyverts[i].stringRep (true)); } } } + elif (editMode() == CircleMode) + { // If we have not specified the center point of the circle yet, preview it on the screen. + if (m_drawedVerts.isEmpty()) + drawBlip (paint, coordconv3_2 (m_hoverpos)); + else + { QVector<vertex> verts, verts2; + const double dist0 = circleDrawDist (0), + dist1 = (m_drawedVerts.size() >= 2) ? circleDrawDist (1) : -1; + const int segs = lores; + const double angleUnit = (2 * pi) / segs; + Axis relX, relY; + QVector<QPoint> ringpoints, circlepoints, circle2points; + + getRelativeAxes (relX, relY); + + // Calculate the preview positions of vertices + for (int i = 0; i < segs; ++i) + { vertex v = g_origin; + v[relX] = m_drawedVerts[0][relX] + (cos (i * angleUnit) * dist0); + v[relY] = m_drawedVerts[0][relY] + (sin (i * angleUnit) * dist0); + verts << v; + + if (dist1 != -1) + { v[relX] = m_drawedVerts[0][relX] + (cos (i * angleUnit) * dist1); + v[relY] = m_drawedVerts[0][relY] + (sin (i * angleUnit) * dist1); + verts2 << v; + } + } + + int i = 0; + for (const vertex& v : verts + verts2) + { // Calculate the 2D point of the vertex + QPoint point = coordconv3_2 (v); + + // Draw a green blip at where it is + drawBlip (paint, point); + + // Add it to the list of points for the green ring fill. + ringpoints << point; + + // Also add the circle points to separate lists + if (i < verts.size()) + circlepoints << point; + else + circle2points << point; + + ++i; + } + + // Insert the first point as the seventeenth one so that + // the ring polygon is closed properly. + if (ringpoints.size() >= 16) + ringpoints.insert (16, ringpoints[0]); + + // Same for the outer ring. Note that the indices are offset by 1 + // because of the insertion done above bumps the values. + if (ringpoints.size() >= 33) + ringpoints.insert (33, ringpoints[17]); + + // Draw the ring + paint.setBrush ((m_drawedVerts.size() >= 2) ? polybrush : Qt::NoBrush); + paint.setPen (Qt::NoPen); + paint.drawPolygon (QPolygon (ringpoints)); + + // Draw the circles + paint.setBrush (Qt::NoBrush); + paint.setPen (linepen); + paint.drawPolygon (QPolygon (circlepoints)); + paint.drawPolygon (QPolygon (circle2points)); + + { // Draw the current radius in the middle of the circle. + QPoint origin = coordconv3_2 (m_drawedVerts[0]); + str label = str::number (dist0); + paint.setPen (textpen); + paint.drawText (origin.x() - (metrics.width (label) / 2), origin.y(), label); + + if (m_drawedVerts.size() >= 2) + { label = str::number (dist1); + paint.drawText (origin.x() - (metrics.width (label) / 2), origin.y() + metrics.height(), label); + } + } + } + } } - + // Camera icons - if (!m_picking) { - // Draw a background for the selected camera + if (!m_picking) + { // Draw a background for the selected camera paint.setPen (m_thinBorderPen); paint.setBrush (QBrush (QColor (0, 128, 160, 128))); paint.drawRect (m_cameraIcons[camera()].selRect); - + // Draw the actual icons - for (CameraIcon& info : m_cameraIcons) { - // Don't draw the free camera icon when in draw mode + for (CameraIcon& info : m_cameraIcons) + { // Don't draw the free camera icon when in draw mode if (&info == &m_cameraIcons[GL::Free] && editMode() != Select) continue; - + paint.drawPixmap (info.destRect, *info.img, info.srcRect); } - + str fmtstr = tr ("%1 Camera"); - + // Draw a label for the current camera in the bottom left corner - { - const ushort margin = 4; - + { const int margin = 4; + str label; label = fmt (fmtstr, tr (g_CameraNames[camera()])); - paint.setPen (getTextPen()); - paint.drawText (QPoint (margin, height() - (margin + metrics.descent())), label); + paint.setPen (textpen); + paint.drawText (QPoint (margin, height() - (margin + metrics.descent())), label); } - + // Tool tips - if (m_drawToolTip) { - if (m_cameraIcons[m_toolTipCamera].destRect.contains (m_pos) == false) + if (m_drawToolTip) + { if (m_cameraIcons[m_toolTipCamera].destRect.contains (m_pos) == false) m_drawToolTip = false; - else { - str label = fmt (fmtstr, tr (g_CameraNames[m_toolTipCamera])); + else + { str label = fmt (fmtstr, tr (g_CameraNames[m_toolTipCamera])); QToolTip::showText (m_globalpos, label); } } } - + // Message log - if (msglog()) { - int y = 0; + if (msglog()) + { int y = 0; const int margin = 2; QColor penColor = getTextPen(); - - for (const MessageManager::Line& line : msglog()->getLines()) { - penColor.setAlphaF (line.alpha); + + for (const MessageManager::Line& line : msglog()->getLines()) + { penColor.setAlphaF (line.alpha); paint.setPen (penColor); paint.drawText (QPoint (margin, y + margin + metrics.ascent()), line.text); y += metrics.height(); } } - + // If we're range-picking, draw a rectangle encompassing the selection area. - if (m_rangepick && !m_picking && m_totalmove >= 10) { - const short x0 = m_rangeStart.x(), + if (m_rangepick && !m_picking && m_totalmove >= 10) + { int x0 = m_rangeStart.x(), y0 = m_rangeStart.y(), x1 = m_pos.x(), y1 = m_pos.y(); - + QRect rect (x0, y0, x1 - x0, y1 - y0); QColor fillColor = (m_addpick ? "#40FF00" : "#00CCFF"); fillColor.setAlphaF (0.2f); - + paint.setPen (m_thickBorderPen); paint.setBrush (QBrush (fillColor)); paint.drawRect (rect); @@ -579,143 +696,161 @@ // ============================================================================= // ----------------------------------------------------------------------------- -QColor GLRenderer::getTextPen () const { - return m_darkbg ? Qt::white : Qt::black; +void GLRenderer::drawBlip (QPainter& paint, QPoint pos) const +{ QPen pen = m_thinBorderPen; + const int blipsize = 8; + pen.setWidth (1); + paint.setPen (pen); + paint.setBrush (QColor (64, 192, 0)); + paint.drawEllipse (pos.x() - blipsize / 2, pos.y() - blipsize / 2, blipsize, blipsize); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::compileAllObjects() { - g_vertexCompiler.compileFile(); +void GLRenderer::compileAllObjects() +{ g_vertexCompiler.compileFile(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::clampAngle (double& angle) const { - while (angle < 0) +void GLRenderer::clampAngle (double& angle) const +{ while (angle < 0) angle += 360.0; + while (angle > 360.0) angle -= 360.0; } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::addDrawnVertex (vertex pos) { - // If we picked an already-existing vertex, stop drawing - for (vertex& vert : m_drawedVerts) { - if (vert == pos) { - endDraw (true); - return; +void GLRenderer::addDrawnVertex (vertex pos) +{ // If we picked an already-existing vertex, stop drawing + if (editMode() != CircleMode) + { for (vertex& vert : m_drawedVerts) + { if (vert == pos) + { endDraw (true); + return; + } } } - + m_drawedVerts << pos; } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::mouseReleaseEvent (QMouseEvent* ev) { - const bool wasLeft = (m_lastButtons & Qt::LeftButton) && !(ev->buttons() & Qt::LeftButton), - wasRight = (m_lastButtons & Qt::RightButton) && !(ev->buttons() & Qt::RightButton), - wasMid = (m_lastButtons & Qt::MidButton) && !(ev->buttons() & Qt::MidButton); - +void GLRenderer::mouseReleaseEvent (QMouseEvent* ev) +{ const bool wasLeft = (m_lastButtons & Qt::LeftButton) && ! (ev->buttons() & Qt::LeftButton), + wasRight = (m_lastButtons & Qt::RightButton) && ! (ev->buttons() & Qt::RightButton), + wasMid = (m_lastButtons & Qt::MidButton) && ! (ev->buttons() & Qt::MidButton); + if (m_panning) m_panning = false; - - if (wasLeft) { - // Check if we selected a camera icon - if (!m_rangepick) { - for (CameraIcon& info : m_cameraIcons) { - if (info.destRect.contains (ev->pos())) { - setCamera (info.cam); + + if (wasLeft) + { // Check if we selected a camera icon + if (!m_rangepick) + { for (CameraIcon & info : m_cameraIcons) + { if (info.destRect.contains (ev->pos())) + { setCamera (info.cam); goto end; } } } - - switch (editMode()) { - case Draw: - if (m_rectdraw) { - if (m_drawedVerts.size() == 2) { - endDraw (true); - return; + + switch (editMode()) + { + case Draw: + { if (m_rectdraw) + { if (m_drawedVerts.size() == 2) + { endDraw (true); + return; + } } - } else { - // If we have 4 verts, stop drawing. - if (m_drawedVerts.size() >= 4) { - endDraw (true); + else + { // If we have 4 verts, stop drawing. + if (m_drawedVerts.size() >= 4) + { endDraw (true); + return; + } + + if (m_drawedVerts.isEmpty() && ev->modifiers() & Qt::ShiftModifier) + { m_rectdraw = true; + updateRectVerts(); + } + } + + addDrawnVertex (m_hoverpos); + } break; + + case CircleMode: + { if (m_drawedVerts.size() == 3) + { endDraw (true); return; } - - if (m_drawedVerts.size() == 0 && ev->modifiers() & Qt::ShiftModifier) { - m_rectdraw = true; - updateRectVerts(); + + addDrawnVertex (m_hoverpos); + } break; + + case Select: + { if (!drawOnly()) + { if (m_totalmove < 10) + m_rangepick = false; + + if (!m_rangepick) + m_addpick = (m_keymods & Qt::ControlModifier); + + if (m_totalmove < 10 || m_rangepick) + pick (ev->x(), ev->y()); } - } - - addDrawnVertex (m_hoverpos); - break; - - case Select: - if (!drawOnly()) { - if (m_totalmove < 10) - m_rangepick = false; - - if (!m_rangepick) - m_addpick = (m_keymods & Qt::ControlModifier); - - if (m_totalmove < 10 || m_rangepick) - pick (ev->x(), ev->y()); - } - - break; + } break; } - + m_rangepick = false; } - - if (wasMid && editMode() == Draw && m_drawedVerts.size() < 4 && m_totalmove < 10) { - // Find the closest vertex to our cursor + + if (wasMid && editMode() != Select && m_drawedVerts.size() < 4 && m_totalmove < 10) + { // Find the closest vertex to our cursor double mindist = 1024.0f; vertex closest; bool valid = false; - + QPoint curspos = coordconv3_2 (m_hoverpos); - - for (const vertex& pos3d: m_knownVerts) { - QPoint pos2d = coordconv3_2 (pos3d); - + + for (const vertex& pos3d: m_knownVerts) + { QPoint pos2d = coordconv3_2 (pos3d); + // Measure squared distance const double dx = abs (pos2d.x() - curspos.x()), - dy = abs (pos2d.y() - curspos.y()), - distsq = (dx * dx) + (dy * dy); - + dy = abs (pos2d.y() - curspos.y()), + distsq = (dx * dx) + (dy * dy); + if (distsq >= 1024.0f) // 32.0f ** 2 continue; // too far away - - if (distsq < mindist) { - mindist = distsq; + + if (distsq < mindist) + { mindist = distsq; closest = pos3d; valid = true; - - /* If it's only 4 pixels away, I think we found our vertex now. */ + + // If it's only 4 pixels away, I think we found our vertex now. if (distsq <= 16.0f) // 4.0f ** 2 break; } } - + if (valid) addDrawnVertex (closest); } - - if (wasRight && m_drawedVerts.size() > 0) { - // Remove the last vertex - m_drawedVerts.erase (m_drawedVerts.size() - 1); - - if (m_drawedVerts.size() == 0) + + if (wasRight && !m_drawedVerts.isEmpty()) + { // Remove the last vertex + m_drawedVerts.removeLast(); + + if (m_drawedVerts.isEmpty()) m_rectdraw = false; } - + end: update(); m_totalmove = 0; @@ -723,89 +858,89 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::mousePressEvent (QMouseEvent* ev) { - m_totalmove = 0; - - if (ev->modifiers() & Qt::ControlModifier) { - m_rangepick = true; +void GLRenderer::mousePressEvent (QMouseEvent* ev) +{ m_totalmove = 0; + + if (ev->modifiers() & Qt::ControlModifier) + { m_rangepick = true; m_rangeStart.setX (ev->x()); m_rangeStart.setY (ev->y()); m_addpick = (m_keymods & Qt::AltModifier); ev->accept(); } - + m_lastButtons = ev->buttons(); } // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= -void GLRenderer::mouseMoveEvent (QMouseEvent* ev) { - int dx = ev->x() - m_pos.x(); +void GLRenderer::mouseMoveEvent (QMouseEvent* ev) +{ int dx = ev->x() - m_pos.x(); int dy = ev->y() - m_pos.y(); m_totalmove += abs (dx) + abs (dy); - + const bool left = ev->buttons() & Qt::LeftButton, - mid = ev->buttons() & Qt::MidButton, - shift = ev->modifiers() & Qt::ShiftModifier; - - if (mid || (left && shift)) { - m_panX += 0.03f * dx * (zoom() / 7.5f); - m_panY -= 0.03f * dy * (zoom() / 7.5f); + mid = ev->buttons() & Qt::MidButton, + shift = ev->modifiers() & Qt::ShiftModifier; + + if (mid || (left && shift)) + { pan (X) += 0.03f * dx * (zoom() / 7.5f); + pan (Y) -= 0.03f * dy * (zoom() / 7.5f); m_panning = true; - } elif (left && !m_rangepick && camera() == Free) { - m_rotX = m_rotX + (dy); - m_rotY = m_rotY + (dx); - - clampAngle (m_rotX); - clampAngle (m_rotY); + } elif (left && !m_rangepick && camera() == Free) + { rot (X) = rot (X) + dy; + rot (Y) = rot (Y) + dx; + + clampAngle (rot (X)); + clampAngle (rot (Y)); } - + // Start the tool tip timer if (!m_drawToolTip) m_toolTipTimer->start (500); - + // Update 2d position m_pos = ev->pos(); m_globalpos = ev->globalPos(); - + // Calculate 3d position of the cursor m_hoverpos = (camera() != Free) ? coordconv2_3 (m_pos, true) : g_origin; - + // Update rect vertices since m_hoverpos may have changed updateRectVerts(); - + update(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::keyPressEvent (QKeyEvent* ev) { - m_keymods = ev->modifiers(); +void GLRenderer::keyPressEvent (QKeyEvent* ev) +{ m_keymods = ev->modifiers(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::keyReleaseEvent (QKeyEvent* ev) { - m_keymods = ev->modifiers(); +void GLRenderer::keyReleaseEvent (QKeyEvent* ev) +{ m_keymods = ev->modifiers(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::wheelEvent (QWheelEvent* ev) { - makeCurrent(); - +void GLRenderer::wheelEvent (QWheelEvent* ev) +{ makeCurrent(); + zoomNotch (ev->delta() > 0); - setZoom (clamp<double> (zoom(), 0.01f, 10000.0f)); - + zoom() = clamp (zoom(), 0.01, 10000.0); + update(); ev->accept(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::leaveEvent (QEvent* ev) { - (void) ev; +void GLRenderer::leaveEvent (QEvent* ev) +{ (void) ev; m_drawToolTip = false; m_toolTipTimer->stop(); update(); @@ -813,203 +948,188 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::contextMenuEvent (QContextMenuEvent* ev) { - g_win->spawnContextMenu (ev->globalPos()); +void GLRenderer::contextMenuEvent (QContextMenuEvent* ev) +{ g_win->spawnContextMenu (ev->globalPos()); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::setCamera (const GL::Camera cam) { - m_camera = cam; +void GLRenderer::setCamera (const GL::Camera cam) +{ m_camera = cam; gl_camera = (int) cam; g_win->updateEditModeActions(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::pick (uint mouseX, uint mouseY) { - GLint viewport[4]; +void GLRenderer::pick (int mouseX, int mouseY) +{ GLint viewport[4]; makeCurrent(); - + // Use particularly thick lines while picking ease up selecting lines. glLineWidth (max<double> (gl_linethickness, 6.5f)); - + // Clear the selection if we do not wish to add to it. - if (!m_addpick) { - List<LDObject*> oldsel = g_win->sel(); - g_win->sel().clear(); - - for (LDObject* obj : oldsel) { - obj->setSelected (false); + if (!m_addpick) + { QList<LDObject*> oldsel = selection(); + LDFile::current()->clearSelection(); + + for (LDObject* obj : oldsel) compileObject (obj); - } } - + m_picking = true; - + // Paint the picking scene glDisable (GL_DITHER); glClearColor (1.0f, 1.0f, 1.0f, 1.0f); - + drawGLScene(); - + glGetIntegerv (GL_VIEWPORT, viewport); - - int x0 = mouseX, - y0 = mouseY, - x1, y1; - + + short x0 = mouseX, + y0 = mouseY; + short x1, y1; + // Determine how big an area to read - with range picking, we pick by // the area given, with single pixel picking, we use an 1 x 1 area. - if (m_rangepick) { - x1 = m_rangeStart.x(); + if (m_rangepick) + { x1 = m_rangeStart.x(); y1 = m_rangeStart.y(); - } else { - x1 = x0 + 1; + } + else + { x1 = x0 + 1; y1 = y0 + 1; } - + // x0 and y0 must be less than x1 and y1, respectively. if (x0 > x1) dataswap (x0, x1); - + if (y0 > y1) dataswap (y0, y1); - + // Clamp the values to ensure they're within bounds - x0 = max (0, x0); - y0 = max (0, y0); - x1 = min (x1, m_width); - y1 = min (y1, m_height); - - const int areawidth = (x1 - x0); - const int areaheight = (y1 - y0); - const int64 numpixels = areawidth * areaheight; - + x0 = max<short> (0, x0); + y0 = max<short> (0, y0); + x1 = min<short> (x1, m_width); + y1 = min<short> (y1, m_height); + + const short areawidth = (x1 - x0); + const short areaheight = (y1 - y0); + const long numpixels = areawidth * areaheight; + // Allocate space for the pixel data. uchar* const pixeldata = new uchar[4 * numpixels]; uchar* pixelptr = &pixeldata[0]; - + assert (viewport[3] == m_height); - + // Read pixels from the color buffer. glReadPixels (x0, viewport[3] - y1, areawidth, areaheight, GL_RGBA, GL_UNSIGNED_BYTE, pixeldata); - + LDObject* removedObj = null; - + // Go through each pixel read and add them to the selection. - for (int64 i = 0; i < numpixels; ++i) { - printf ("Color: #%X%X%X\n", pixelptr[0], pixelptr[1], pixelptr[2]); - - int32 idx = - (*(pixelptr + 0) * 0x00001) + - (*(pixelptr + 1) * 0x00100) + - (*(pixelptr + 2) * 0x10000); - + for (long i = 0; i < numpixels; ++i) + { long idx = + (* (pixelptr + 0) * 0x10000) + + (* (pixelptr + 1) * 0x00100) + + (* (pixelptr + 2) * 0x00001); pixelptr += 4; - + if (idx == 0xFFFFFF) continue; // White is background; skip - + LDObject* obj = LDObject::fromID (idx); - if (!obj) { - log ("WARNING: Object #%1 doesn't exist!", idx); - continue; - } - + // If this is an additive single pick and the object is currently selected, // we remove it from selection instead. - if (!m_rangepick && m_addpick) { - bool removed = false; - - for (ulong i = 0; i < g_win->sel().size(); ++i) { - if (g_win->sel()[i] == obj) { - g_win->sel().erase (i); - obj->setSelected (false); - removed = true; - removedObj = obj; - } + if (!m_rangepick && m_addpick) + { if (obj->selected()) + { obj->unselect(); + removedObj = obj; + break; } - - if (removed) - break; } - - g_win->sel() << obj; + + obj->select(); } - + delete[] pixeldata; - - // Remove duplicated entries - g_win->sel().makeUnique(); - + // Update everything now. g_win->updateSelection(); - + // Recompile the objects now to update their color - for (LDObject* obj : g_win->sel()) + for (LDObject* obj : selection()) compileObject (obj); - + if (removedObj) compileObject (removedObj); - + // Restore line thickness glLineWidth (gl_linethickness); - + m_picking = false; m_rangepick = false; glEnable (GL_DITHER); - + setBackground(); repaint(); } // ============================================================================= // ----------------------------------------------------------------------------- -READ_ACCESSOR (EditMode, GLRenderer::editMode) { - return m_editMode; +READ_ACCESSOR (EditMode, GLRenderer::editMode) +{ return m_editMode; } // ============================================================================= // ----------------------------------------------------------------------------- -SET_ACCESSOR (EditMode, GLRenderer::setEditMode) { - m_editMode = val; - - switch (editMode()) { - case Select: - unsetCursor(); - setContextMenuPolicy (Qt::DefaultContextMenu); - break; - - case Draw: - // Cannot draw into the free camera - use top instead. - if (m_camera == Free) - setCamera (Top); - - // Disable the context menu - we need the right mouse button - // for removing vertices. - setContextMenuPolicy (Qt::NoContextMenu); - - // Use the crosshair cursor when drawing. - setCursor (Qt::CrossCursor); - - // Clear the selection when beginning to draw. - // FIXME: make the selection clearing stuff in ::pick a method and use it - // here! This code doesn't update the GL lists. - g_win->sel().clear(); - g_win->updateSelection(); - m_drawedVerts.clear(); - break; +SET_ACCESSOR (EditMode, GLRenderer::setEditMode) +{ m_editMode = val; + + switch (editMode()) + { case Select: + { unsetCursor(); + setContextMenuPolicy (Qt::DefaultContextMenu); + } break; + + case Draw: + case CircleMode: + { // Cannot draw into the free camera - use top instead. + if (m_camera == Free) + setCamera (Top); + + // Disable the context menu - we need the right mouse button + // for removing vertices. + setContextMenuPolicy (Qt::NoContextMenu); + + // Use the crosshair cursor when drawing. + setCursor (Qt::CrossCursor); + + // Clear the selection when beginning to draw. + QList<LDObject*> priorsel = selection(); + LDFile::current()->clearSelection(); + + for (LDObject* obj : priorsel) + compileObject (obj); + + g_win->updateSelection(); + m_drawedVerts.clear(); + } break; } - + g_win->updateEditModeActions(); update(); } // ============================================================================= // ----------------------------------------------------------------------------- -READ_ACCESSOR (LDFile*, GLRenderer::file) { - return m_file; +READ_ACCESSOR (LDFile*, GLRenderer::file) +{ return m_file; } // ============================================================================= @@ -1017,89 +1137,234 @@ SET_ACCESSOR (LDFile*, GLRenderer::setFile) { m_file = val; g_vertexCompiler.setFile (val); - + if (val != null) overlaysFromObjects(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::endDraw (bool accept) { - (void) accept; - +matrix GLRenderer::getCircleDrawMatrix (double scale) +{ matrix transform = g_circleDrawTransforms[camera() % 3]; + + for (int i = 0; i < 9; ++i) + { if (transform[i] == 2) + transform[i] = scale; + elif (transform[i] == 1 && camera() >= 3) + transform[i] = -1; + } + + return transform; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void GLRenderer::endDraw (bool accept) +{ (void) accept; + // Clean the selection and create the object - List<vertex>& verts = m_drawedVerts; - LDObject* obj = null; - - if (m_rectdraw) { - LDQuad* quad = new LDQuad; - - // Copy the vertices from m_rectverts - updateRectVerts(); - - for (int i = 0; i < quad->vertices(); ++i) - quad->setVertex (i, m_rectverts[i]); - - quad->setColor (maincolor); - obj = quad; - } else { - switch (verts.size()) { - case 1: - // 1 vertex - add a vertex object - obj = new LDVertex; - static_cast<LDVertex*> (obj)->pos = verts[0]; - obj->setColor (maincolor); - break; - - case 2: - // 2 verts - make a line - obj = new LDLine (verts[0], verts[1]); - obj->setColor (edgecolor); - break; - - case 3: - case 4: - obj = (verts.size() == 3) ? - static_cast<LDObject*> (new LDTriangle) : - static_cast<LDObject*> (new LDQuad); - - obj->setColor (maincolor); - for (ushort i = 0; i < obj->vertices(); ++i) - obj->setVertex (i, verts[i]); - break; + QList<vertex>& verts = m_drawedVerts; + QList<LDObject*> objs; + + switch (editMode()) + { case Draw: + { if (m_rectdraw) + { LDQuad* quad = new LDQuad; + + // Copy the vertices from m_rectverts + updateRectVerts(); + + for (int i = 0; i < quad->vertices(); ++i) + quad->setVertex (i, m_rectverts[i]); + + quad->setColor (maincolor); + objs << quad; + } + else + { switch (verts.size()) + { case 1: + { // 1 vertex - add a vertex object + LDVertex* obj = new LDVertex; + obj->pos = verts[0]; + obj->setColor (maincolor); + objs << obj; + } break; + + case 2: + { // 2 verts - make a line + LDLine* obj = new LDLine (verts[0], verts[1]); + obj->setColor (edgecolor); + objs << obj; + } break; + + case 3: + case 4: + { LDObject* obj = (verts.size() == 3) ? + static_cast<LDObject*> (new LDTriangle) : + static_cast<LDObject*> (new LDQuad); + + obj->setColor (maincolor); + + for (int i = 0; i < obj->vertices(); ++i) + obj->setVertex (i, verts[i]); + + objs << obj; + } break; + } + } + } break; + + case CircleMode: + { const int segs = lores, divs = lores; // TODO: make customizable + double dist0 = circleDrawDist (0), + dist1 = circleDrawDist (1); + LDFile* refFile = null; + matrix transform; + bool circleOrDisc = false; + + if (dist1 < dist0) + std::swap<double> (dist0, dist1); + + if (dist0 == dist1) + { // If the radii are the same, there's no ring space to fill. Use a circle. + refFile = getFile ("4-4edge.dat"); + transform = getCircleDrawMatrix (dist0); + circleOrDisc = true; + } + elif (dist0 == 0 || dist1 == 0) + { // If either radii is 0, use a disc. + refFile = getFile ("4-4disc.dat"); + transform = getCircleDrawMatrix ((dist0 != 0) ? dist0 : dist1); + circleOrDisc = true; + } + elif (g_RingFinder (dist0, dist1)) + { // The ring finder found a solution, use that. Add the component rings to the file. + for (const RingFinder::Component& cmp : g_RingFinder.bestSolution()->components()) + { if ((refFile = getFile (radialFileName (::Ring, lores, lores, cmp.num))) == null) + { refFile = generatePrimitive (::Ring, lores, lores, cmp.num); + refFile->setImplicit (false); + } + + LDSubfile* ref = new LDSubfile; + ref->setFileInfo (refFile); + ref->setTransform (getCircleDrawMatrix (cmp.scale)); + ref->setPosition (m_drawedVerts[0]); + ref->setColor (maincolor); + objs << ref; + } + } + else + { // Last resort: draw the ring with quads + QList<QLineF> c0, c1; + Axis relX, relY, relZ; + getRelativeAxes (relX, relY); + relZ = (Axis) (3 - relX - relY); + double x0 = m_drawedVerts[0][relX], + y0 = m_drawedVerts[0][relY]; + + vertex templ; + templ[relX] = x0; + templ[relY] = y0; + templ[relZ] = depthValue(); + + // Calculate circle coords + makeCircle (segs, divs, dist0, c0); + makeCircle (segs, divs, dist1, c1); + + for (int i = 0; i < segs; ++i) + { vertex v0, v1, v2, v3; + v0 = v1 = v2 = v3 = templ; + v0[relX] += c0[i].x1(); + v0[relY] += c0[i].y1(); + v1[relX] += c0[i].x2(); + v1[relY] += c0[i].y2(); + v2[relX] += c1[i].x2(); + v2[relY] += c1[i].y2(); + v3[relX] += c1[i].x1(); + v3[relY] += c1[i].y1(); + + LDQuad* q = new LDQuad (v0, v1, v2, v3); + q->setColor (maincolor); + + // Ensure the quads always are BFC-front towards the camera + if (camera() % 3 <= 0) + q->invert(); + + objs << q; + } + } + + if (circleOrDisc) + { LDSubfile* ref = new LDSubfile; + ref->setFileInfo (refFile); + ref->setTransform (transform); + ref->setPosition (m_drawedVerts[0]); + ref->setColor (maincolor); + objs << ref; + } + } break; + + case Select: + { assert (false); + return; + } break; + } + + if (objs.size() > 0) + { g_win->beginAction (null); + + for (LDObject* obj : objs) + { file()->addObject (obj); + compileObject (obj); } - } - - if (obj) { - g_win->beginAction (null); - file()->addObject (obj); - compileObject (obj); - g_win->fullRefresh(); + + g_win->refresh(); g_win->endAction(); } - + m_drawedVerts.clear(); m_rectdraw = false; } // ============================================================================= // ----------------------------------------------------------------------------- -static List<vertex> getVertices (LDObject* obj) { - List<vertex> verts; - - if (obj->vertices() >= 2) { - for (int i = 0; i < obj->vertices(); ++i) +double GLRenderer::circleDrawDist (int pos) const +{ assert (m_drawedVerts.size() >= pos + 1); + const vertex& v1 = (m_drawedVerts.size() >= pos + 2) ? m_drawedVerts[pos + 1] : m_hoverpos; + Axis relX, relY; + getRelativeAxes (relX, relY); + + const double dx = m_drawedVerts[0][relX] - v1[relX]; + const double dy = m_drawedVerts[0][relY] - v1[relY]; + return sqrt ((dx * dx) + (dy * dy)); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void GLRenderer::getRelativeAxes (Axis& relX, Axis& relY) const +{ const LDFixedCameraInfo* cam = &g_FixedCameras[m_camera]; + relX = cam->axisX; + relY = cam->axisY; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +static QList<vertex> getVertices (LDObject* obj) +{ QList<vertex> verts; + + if (obj->vertices() >= 2) + { for (int i = 0; i < obj->vertices(); ++i) verts << obj->getVertex (i); - } elif (obj->getType() == LDObject::Subfile) { - LDSubfile* ref = static_cast<LDSubfile*> (obj); - List<LDObject*> objs = ref->inlineContents (LDSubfile::DeepCacheInline); - - for(LDObject* obj : objs) { - verts << getVertices (obj); + } elif (obj->getType() == LDObject::Subfile) + { LDSubfile* ref = static_cast<LDSubfile*> (obj); + QList<LDObject*> objs = ref->inlineContents (LDSubfile::DeepCacheInline); + + for (LDObject* obj : objs) + { verts << getVertices (obj); delete obj; } } - + return verts; } @@ -1112,30 +1377,30 @@ // ============================================================================= // ----------------------------------------------------------------------------- -uchar* GLRenderer::screencap (ushort& w, ushort& h) { - w = m_width; +uchar* GLRenderer::screencap (int& w, int& h) +{ w = m_width; h = m_height; uchar* cap = new uchar[4 * w * h]; - + m_screencap = true; update(); m_screencap = false; - + // Capture the pixels glReadPixels (0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, cap); - + return cap; } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::slot_toolTipTimer() { - // We come here if the cursor has stayed in one place for longer than a +void GLRenderer::slot_toolTipTimer() +{ // We come here if the cursor has stayed in one place for longer than a // a second. Check if we're holding it over a camera icon - if so, draw // a tooltip. - for (CameraIcon& icon : m_cameraIcons) { - if (icon.destRect.contains (m_pos)) { - m_toolTipCamera = icon.cam; +for (CameraIcon & icon : m_cameraIcons) + { if (icon.destRect.contains (m_pos)) + { m_toolTipCamera = icon.cam; m_drawToolTip = true; update(); break; @@ -1145,226 +1410,238 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::deleteLists (LDObject* obj) { - // Delete the lists but only if they have been initialized +void GLRenderer::deleteLists (LDObject* obj) +{ // Delete the lists but only if they have been initialized if (!obj->m_glinit) return; - - for (const GL::ListType listType : g_glListTypes) + +for (const GL::ListType listType : g_glListTypes) glDeleteLists (obj->glLists[listType], 1); - + obj->m_glinit = false; } // ============================================================================= // ----------------------------------------------------------------------------- -Axis GLRenderer::cameraAxis (bool y, GL::Camera camid) { - if (camid == (GL::Camera) -1) +Axis GLRenderer::cameraAxis (bool y, GL::Camera camid) +{ if (camid == (GL::Camera) - 1) camid = m_camera; - - const staticCameraMeta* cam = &g_staticCameras[camid]; + + const LDFixedCameraInfo* cam = &g_FixedCameras[camid]; return (y) ? cam->axisY : cam->axisX; } // ============================================================================= // ----------------------------------------------------------------------------- -bool GLRenderer::setupOverlay (GL::Camera cam, str file, int x, int y, int w, int h) { - QImage* img = new QImage (file); - overlayMeta& info = getOverlay (cam); - - if (img->isNull()) { - critical (tr ("Failed to load overlay image!")); +bool GLRenderer::setupOverlay (GL::Camera cam, str file, int x, int y, int w, int h) +{ QImage* img = new QImage (file); + LDGLOverlay& info = getOverlay (cam); + + if (img->isNull()) + { critical (tr ("Failed to load overlay image!")); delete img; return false; } - + delete info.img; // delete the old image - + info.fname = file; info.lw = w; info.lh = h; info.ox = x; info.oy = y; info.img = img; - + if (info.lw == 0) info.lw = (info.lh * img->width()) / img->height(); elif (info.lh == 0) info.lh = (info.lw * img->height()) / img->width(); - + const Axis x2d = cameraAxis (false, cam), y2d = cameraAxis (true, cam); - - double negXFac = g_staticCameras[cam].negX ? -1 : 1, - negYFac = g_staticCameras[cam].negY ? -1 : 1; - + const double negXFac = g_FixedCameras[cam].negX ? -1 : 1, + negYFac = g_FixedCameras[cam].negY ? -1 : 1; + info.v0 = info.v1 = g_origin; info.v0[x2d] = - (info.ox * info.lw * negXFac) / img->width(); info.v0[y2d] = (info.oy * info.lh * negYFac) / img->height(); info.v1[x2d] = info.v0[x2d] + info.lw; info.v1[y2d] = info.v0[y2d] + info.lh; - + // Set alpha of all pixels to 0.5 for (long i = 0; i < img->width(); ++i) - for (long j = 0; j < img->height(); ++j) { - uint32 pixel = img->pixel (i, j); - img->setPixel (i, j, 0x80000000 | (pixel & 0x00FFFFFF)); - } - + for (long j = 0; j < img->height(); ++j) + { uint32 pixel = img->pixel (i, j); + img->setPixel (i, j, 0x80000000 | (pixel & 0x00FFFFFF)); + } + updateOverlayObjects(); return true; } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::clearOverlay() { - if (camera() == Free) +void GLRenderer::clearOverlay() +{ if (camera() == Free) return; - - overlayMeta& info = m_overlays[camera()]; + + LDGLOverlay& info = m_overlays[camera()]; delete info.img; info.img = null; - + updateOverlayObjects(); } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::setDepthValue (double depth) { - assert (camera() < Free); +void GLRenderer::setDepthValue (double depth) +{ assert (camera() < Free); m_depthValues[camera()] = depth; } // ============================================================================= // ----------------------------------------------------------------------------- -double GLRenderer::depthValue() const { - assert (camera() < Free); +double GLRenderer::depthValue() const +{ assert (camera() < Free); return m_depthValues[camera()]; } // ============================================================================= // ----------------------------------------------------------------------------- -const char* GLRenderer::cameraName() const { - return g_CameraNames[camera()]; +const char* GLRenderer::cameraName() const +{ return g_CameraNames[camera()]; } // ============================================================================= // ----------------------------------------------------------------------------- -overlayMeta& GLRenderer::getOverlay (int newcam) { - return m_overlays[newcam]; +LDGLOverlay& GLRenderer::getOverlay (int newcam) +{ return m_overlays[newcam]; } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::zoomNotch (bool inward) { - if (zoom() > 15) - setZoom (zoom() * (inward ? 0.833f : 1.2f)); +void GLRenderer::zoomNotch (bool inward) +{ if (zoom() > 15) + zoom() *= inward ? 0.833f : 1.2f; else - setZoom (zoom() + (inward ? -1.2f : 1.2f)); + zoom() += inward ? -1.2f : 1.2f; } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::zoomToFit() { - if (file() == null) { - setZoom (30.0f); +void GLRenderer::zoomToFit() +{ if (file() == null || m_width == -1 || m_height == -1) + { zoom() = 30.0f; return; } - + bool lastfilled = false; bool firstrun = true; const uint32 white = 0xFFFFFFFF; bool inward = true; - ulong run = 0; - const ushort w = m_width, h = m_height; - + const int w = m_width, h = m_height; + glClearColor (1.0, 1.0, 1.0, 1.0); glDisable (GL_DITHER); - + // Use the pick list while drawing the scene, this way we can tell whether borders // are background or not. m_picking = true; - - for (;;) { - if (zoom() > 10000.0f || zoom() < 0.0f) { - // Obviously, there's nothing to draw if we get here. + + for (;;) + { if (zoom() > 10000.0 || zoom() < 0.0) + { // Obviously, there's nothing to draw if we get here. // Default to 30.0f and break out. - setZoom (30.0f); + zoom() = 30.0; break; } - + zoomNotch (inward); - + uchar* cap = new uchar[4 * w * h]; drawGLScene(); glReadPixels (0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, cap); uint32* imgdata = reinterpret_cast<uint32*> (cap); bool filled = false; - + // Check the top and bottom rows - for (ushort i = 0; i < w && !filled; ++i) + for (int i = 0; i < w && !filled; ++i) if (imgdata[i] != white || imgdata[((h - 1) * w) + i] != white) filled = true; - + // Left and right edges - for (ushort i = 0; i < h && !filled; ++i) - if (imgdata[i * w] != white || imgdata[(i * w) + (w - 1)] != white) + for (int i = 0; i < h && !filled; ++i) + if (imgdata[i * w] != white || imgdata[(i * w) + w - 1] != white) filled = true; - - if (firstrun) { - // If this is the first run, we don't know enough to determine + + delete[] cap; + + if (firstrun) + { // If this is the first run, we don't know enough to determine // whether the zoom was to fit, so we mark in our knowledge so // far and start over. inward = !filled; firstrun = false; - } else { - // If this run filled the screen and the last one did not, the + } + else + { // If this run filled the screen and the last one did not, the // last run had ideal zoom - zoom a bit back and we should reach it. - if (filled && !lastfilled) { - zoomNotch (false); + if (filled && !lastfilled) + { zoomNotch (false); break; } - + // If this run did not fill the screen and the last one did, we've // now reached ideal zoom so we're done here. if (!filled && lastfilled) break; - + inward = !filled; } - - delete[] cap; + lastfilled = filled; - ++run; } - + setBackground(); m_picking = false; } // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::updateRectVerts() { - if (!m_rectdraw) +void GLRenderer::zoomAllToFit() +{ Camera oldcam = camera(); + + for (int i = 0; i < 7; ++i) + { setCamera ((Camera) i); + zoomToFit(); + } + + setCamera (oldcam); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void GLRenderer::updateRectVerts() +{ if (!m_rectdraw) return; - - if (m_drawedVerts.size() == 0) { - for (int i = 0; i < 4; ++i) + + if (m_drawedVerts.isEmpty()) + { for (int i = 0; i < 4; ++i) m_rectverts[i] = m_hoverpos; - + return; } - + vertex v0 = m_drawedVerts[0], - v1 = (m_drawedVerts.size() >= 2) ? m_drawedVerts[1] : m_hoverpos; - + v1 = (m_drawedVerts.size() >= 2) ? m_drawedVerts[1] : m_hoverpos; + const Axis ax = cameraAxis (false), - ay = cameraAxis (true), - az = (Axis) (3 - ax - ay); - + ay = cameraAxis (true), + az = (Axis) (3 - ax - ay); + for (int i = 0; i < 4; ++i) m_rectverts[i][az] = depthValue(); - + m_rectverts[0][ax] = v0[ax]; m_rectverts[0][ay] = v0[ay]; m_rectverts[1][ax] = v1[ax]; @@ -1377,17 +1654,17 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::mouseDoubleClickEvent (QMouseEvent* ev) { - if (!(ev->buttons() & Qt::LeftButton) || editMode() != Select) +void GLRenderer::mouseDoubleClickEvent (QMouseEvent* ev) +{ if (! (ev->buttons() & Qt::LeftButton) || editMode() != Select) return; - + pick (ev->x(), ev->y()); - - if (g_win->sel().size() == 0) + + if (selection().isEmpty()) return; - + g_win->beginAction (null); - LDObject* obj = g_win->sel()[0]; + LDObject* obj = selection().first(); AddObjectDialog::staticDialog (obj->getType(), obj); g_win->endAction(); ev->accept(); @@ -1395,16 +1672,16 @@ // ============================================================================= // ----------------------------------------------------------------------------- -LDOverlay* GLRenderer::findOverlayObject (GLRenderer::Camera cam) { - LDOverlay* ovlobj = null; - - for (LDObject * obj : file()->objects()) { - if (obj->getType() == LDObject::Overlay && static_cast<LDOverlay*> (obj)->camera() == cam) { - ovlobj = static_cast<LDOverlay*> (obj); +LDOverlay* GLRenderer::findOverlayObject (GLRenderer::Camera cam) +{ LDOverlay* ovlobj = null; + + for (LDObject * obj : file()->objects()) + { if (obj->getType() == LDObject::Overlay && static_cast<LDOverlay*> (obj)->camera() == cam) + { ovlobj = static_cast<LDOverlay*> (obj); break; } } - + return ovlobj; } @@ -1412,16 +1689,16 @@ // ----------------------------------------------------------------------------- // Read in overlays from the current file and update overlay info accordingly. // ----------------------------------------------------------------------------- -void GLRenderer::overlaysFromObjects() { - for (Camera cam : g_Cameras) { - if (cam == Free) +void GLRenderer::overlaysFromObjects() +{ for (Camera cam : g_Cameras) + { if (cam == Free) continue; - - overlayMeta& meta = m_overlays[cam]; + + LDGLOverlay& meta = m_overlays[cam]; LDOverlay* ovlobj = findOverlayObject (cam); - - if (!ovlobj && meta.img) { - delete meta.img; + + if (!ovlobj && meta.img) + { delete meta.img; meta.img = null; } elif (ovlobj && (!meta.img || meta.fname != ovlobj->filename())) setupOverlay (cam, ovlobj->filename(), ovlobj->x(), ovlobj->y(), ovlobj->width(), ovlobj->height()); @@ -1430,65 +1707,65 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void GLRenderer::updateOverlayObjects() { - for (Camera cam : g_Cameras) { - if (cam == Free) +void GLRenderer::updateOverlayObjects() +{ for (Camera cam : g_Cameras) + { if (cam == Free) continue; - - overlayMeta& meta = m_overlays[cam]; + + LDGLOverlay& meta = m_overlays[cam]; LDOverlay* ovlobj = findOverlayObject (cam); - - if (!meta.img && ovlobj) { - // If this is the last overlay image, we need to remove the empty space after it as well. + + if (!meta.img && ovlobj) + { // If this is the last overlay image, we need to remove the empty space after it as well. LDObject* nextobj = ovlobj->next(); - - if (nextobj && nextobj->getType() == LDObject::Empty) { - m_file->forgetObject (nextobj); + + if (nextobj && nextobj->getType() == LDObject::Empty) + { m_file->forgetObject (nextobj); delete nextobj; } - + // If the overlay object was there and the overlay itself is // not, remove the object. m_file->forgetObject (ovlobj); delete ovlobj; - } elif (meta.img && !ovlobj) { - // Inverse case: image is there but the overlay object is + } elif (meta.img && !ovlobj) + { // Inverse case: image is there but the overlay object is // not, thus create the object. ovlobj = new LDOverlay; - + // Find a suitable position to place this object. We want to place // this into the header, which is everything up to the first scemantic // object. If we find another overlay object, place this object after // the last one found. Otherwise, place it before the first schemantic // object and put an empty object after it (though don't do this if // there was no schemantic elements at all) - ulong i, lastOverlay = -1u; + int i, lastOverlay = -1; bool found = false; - - for (i = 0; i < file()->numObjs(); ++i) { - LDObject* obj = file()->obj (i); - - if (obj->isScemantic()) { - found = true; + + for (i = 0; i < file()->numObjs(); ++i) + { LDObject* obj = file()->obj (i); + + if (obj->isScemantic()) + { found = true; break; } - + if (obj->getType() == LDObject::Overlay) lastOverlay = i; } - - if (lastOverlay != -1u) + + if (lastOverlay != -1) file()->insertObj (lastOverlay + 1, ovlobj); - else { - file()->insertObj (i, ovlobj); - + else + { file()->insertObj (i, ovlobj); + if (found) file()->insertObj (i + 1, new LDEmpty); } } - - if (meta.img && ovlobj) { - ovlobj->setCamera (cam); + + if (meta.img && ovlobj) + { ovlobj->setCamera (cam); ovlobj->setFilename (meta.fname); ovlobj->setX (meta.ox); ovlobj->setY (meta.oy); @@ -1496,8 +1773,7 @@ ovlobj->setHeight (meta.lh); } } - + if (g_win->R() == this) g_win->refresh(); } -#include "moc_gldraw.cpp"
--- a/src/gldraw.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/gldraw.h Wed Oct 23 12:46:10 2013 +0300 @@ -32,146 +32,219 @@ class LDFile; class QTimer; -enum EditMode { - Select, - Draw +enum EditMode +{ Select, + Draw, + CircleMode, }; // Meta for overlays -struct overlayMeta { - vertex v0, v1; - ushort ox, oy; +struct LDGLOverlay +{ vertex v0, v1; + int ox, oy; double lw, lh; str fname; QImage* img; }; +struct LDFixedCameraInfo +{ const char glrotate[3]; + const Axis axisX, axisY; + const bool negX, negY; +}; + // ============================================================================= // GLRenderer -// +// // The main renderer object, draws the brick on the screen, manages the camera // and selection picking. The instance of GLRenderer is accessible as // g_win->R() // ============================================================================= -class GLRenderer : public QGLWidget { - Q_OBJECT - +class GLRenderer : public QGLWidget +{ Q_OBJECT + PROPERTY (bool, drawOnly, setDrawOnly) - PROPERTY (double, zoom, setZoom) PROPERTY (MessageManager*, msglog, setMessageLog) READ_PROPERTY (bool, picking, setPicking) DECLARE_PROPERTY (LDFile*, file, setFile) DECLARE_PROPERTY (EditMode, editMode, setEditMode) - -public: - enum Camera { Top, Front, Left, Bottom, Back, Right, Free }; - enum ListType { NormalList, PickList, BFCFrontList, BFCBackList }; - - enum VAOType { - MainArray, - EdgeArray, - CondEdgeArray, - BFCArray, - PickArray, - EdgePickArray, - NumArrays - }; - - GLRenderer (QWidget* parent = null); - ~GLRenderer(); - - Camera camera() const { return m_camera; } - Axis cameraAxis (bool y, Camera camid = (Camera) -1); - const char* cameraName() const; - void clearOverlay(); - void compileObject (LDObject* obj); - void compileAllObjects(); - double depthValue() const; - void drawGLScene(); - void endDraw (bool accept); - static QColor getMainColor(); - overlayMeta& getOverlay (int newcam); - void hardRefresh(); - void initGLData(); - void overlaysFromObjects(); - void refresh(); - void resetAngles(); - uchar* screencap (ushort& w, ushort& h); - void setBackground(); - void setCamera (const Camera cam); - void setDepthValue (double depth); - bool setupOverlay (GLRenderer::Camera cam, str file, int x, int y, int w, int h); - void updateOverlayObjects(); - void zoomNotch (bool inward); - void zoomToFit(); - - static void deleteLists (LDObject* obj); + + public: + enum Camera { Top, Front, Left, Bottom, Back, Right, Free }; + enum ListType { NormalList, PickList, BFCFrontList, BFCBackList }; + + GLRenderer (QWidget* parent = null); + ~GLRenderer(); + + inline Camera camera() const + { return m_camera; + } + + Axis cameraAxis (bool y, Camera camid = (Camera) - 1); + const char* cameraName() const; + void clearOverlay(); + void compileObject (LDObject* obj); + void compileAllObjects(); + double depthValue() const; + void drawGLScene(); + void endDraw (bool accept); + QColor getMainColor(); + LDGLOverlay& getOverlay (int newcam); + void hardRefresh(); + void initGLData(); + void overlaysFromObjects(); + void refresh(); + void resetAngles(); + void resetAllAngles(); + uchar* screencap (int& w, int& h); + void setBackground(); + void setCamera (const Camera cam); + void setDepthValue (double depth); + bool setupOverlay (GLRenderer::Camera cam, str file, int x, int y, int w, int h); + void updateOverlayObjects(); + void zoomNotch (bool inward); + void zoomToFit(); + void zoomAllToFit(); + + static void deleteLists (LDObject* obj); + + protected: + void contextMenuEvent (QContextMenuEvent* ev); + void initializeGL(); + void keyPressEvent (QKeyEvent* ev); + void keyReleaseEvent (QKeyEvent* ev); + void leaveEvent (QEvent* ev); + void mouseDoubleClickEvent (QMouseEvent* ev); + void mousePressEvent (QMouseEvent* ev); + void mouseMoveEvent (QMouseEvent* ev); + void mouseReleaseEvent (QMouseEvent* ev); + void paintEvent (QPaintEvent* ev); + void resizeGL (int w, int h); + void wheelEvent (QWheelEvent* ev); + + private: + // CameraIcon::img is a heap-allocated QPixmap because otherwise it gets + // initialized before program gets to main() and constructs a QApplication + // and Qt doesn't like that. + struct CameraIcon + { QPixmap* img; + QRect srcRect, destRect, selRect; + Camera cam; + }; -protected: - void contextMenuEvent (QContextMenuEvent* ev); - void initializeGL(); - void keyPressEvent (QKeyEvent* ev); - void keyReleaseEvent (QKeyEvent* ev); - void leaveEvent (QEvent* ev); - void mouseDoubleClickEvent (QMouseEvent* ev); - void mousePressEvent (QMouseEvent* ev); - void mouseMoveEvent (QMouseEvent* ev); - void mouseReleaseEvent (QMouseEvent* ev); - void paintEvent (QPaintEvent* ev); - void resizeGL (int w, int h); - void wheelEvent (QWheelEvent* ev); + CameraIcon m_cameraIcons[7]; + QTimer* m_toolTipTimer; + Qt::MouseButtons m_lastButtons; + Qt::KeyboardModifiers m_keymods; + vertex m_hoverpos; + double m_virtWidth, + m_virtHeight, + m_rotX[7], + m_rotY[7], + m_rotZ[7], + m_panX[7], + m_panY[7], + m_zoom[7]; + bool m_darkbg, + m_rangepick, + m_addpick, + m_drawToolTip, + m_screencap, + m_panning; + QPoint m_pos, + m_globalpos, + m_rangeStart; + QPen m_thickBorderPen, + m_thinBorderPen; + Camera m_camera, + m_toolTipCamera; + GLuint m_axeslist; + int m_width, + m_height, + m_totalmove; + QList<vertex> m_drawedVerts; + bool m_rectdraw; + vertex m_rectverts[4]; + QColor m_bgcolor; + double m_depthValues[6]; + LDGLOverlay m_overlays[6]; + QList<vertex> m_knownVerts; -private: - // CameraIcon::img is a heap-allocated QPixmap because otherwise it gets - // initialized before program gets to main() and constructs a QApplication - // and Qt doesn't like that. - struct CameraIcon { - QPixmap* img; - QRect srcRect, destRect, selRect; - Camera cam; - } m_cameraIcons[7]; - - QTimer* m_toolTipTimer; - Qt::MouseButtons m_lastButtons; - Qt::KeyboardModifiers m_keymods; - ulong m_totalmove; - vertex m_hoverpos; - double m_virtWidth, m_virtHeight, m_rotX, m_rotY, m_rotZ, m_panX, m_panY; - bool m_darkbg, m_rangepick, m_addpick, m_drawToolTip, m_screencap; - QPoint m_pos, m_globalpos, m_rangeStart; - QPen m_thickBorderPen, m_thinBorderPen; - Camera m_camera, m_toolTipCamera; - GLuint m_axeslist; - int m_width, m_height; - List<vertex> m_drawedVerts; - bool m_rectdraw; - vertex m_rectverts[4]; - QColor m_bgcolor; - double m_depthValues[6]; - overlayMeta m_overlays[6]; - List<vertex> m_knownVerts; - bool m_panning; - - void addDrawnVertex (vertex m_hoverpos); - void calcCameraIcons(); // Compute geometry for camera icons - void clampAngle (double& angle) const; // Clamps an angle to [0, 360] - vertex coordconv2_3 (const QPoint& pos2d, bool snap) const; // Convert a 2D point to a 3D point - QPoint coordconv3_2 (const vertex& pos3d) const; // Convert a 3D point to a 2D point - void drawVAOs (VAOType arrayType, GLenum type); // Draw a VAO array - LDOverlay* findOverlayObject (Camera cam); - void updateRectVerts(); - void pick (uint mouseX, uint mouseY); // Perform object selection - QColor getTextPen() const; // Determine which color to draw text with - -private slots: - void slot_toolTipTimer(); + void addDrawnVertex (vertex m_hoverpos); + LDOverlay* findOverlayObject (Camera cam); + void updateRectVerts(); + void getRelativeAxes (Axis& relX, Axis& relY) const; + matrix getCircleDrawMatrix (double scale); + void drawBlip (QPainter& paint, QPoint pos) const; + + // Compute geometry for camera icons + void calcCameraIcons(); + + // How large is the circle we're drawing right now? + double circleDrawDist (int pos) const; + + // Clamps an angle to [0, 360] + void clampAngle (double& angle) const; + + // Compile one of the lists of an object + void compileList (LDObject* obj, const ListType list); + + // Sub-routine for object compiling + void compileSubObject (LDObject* obj, const GLenum gltype); + + // Compile a single vertex to a list + void compileVertex (const vertex& vrt); + + // Convert a 2D point to a 3D point + vertex coordconv2_3 (const QPoint& pos2d, bool snap) const; + + // Convert a 3D point to a 2D point + QPoint coordconv3_2 (const vertex& pos3d) const; + + // Draw a VAO array + void drawVAOs (VAOType arrayType, GLenum type); + + // Determine which color to draw text with + QColor getTextPen() const; + + // Perform object selection + void pick (int mouseX, int mouseY); + + // Set the color to an object list + void setObjectColor (LDObject* obj, const ListType list); + + // Get a rotation value + inline double& rot (Axis ax) + { return + (ax == X) ? m_rotX[camera()] : + (ax == Y) ? m_rotY[camera()] : + m_rotZ[camera()]; + } + + // Get a panning value + inline double& pan (Axis ax) + { return (ax == X) ? m_panX[camera()] : m_panY[camera()]; + } + + // Same except const (can be used in const methods) + inline const double& pan (Axis ax) const + { return (ax == X) ? m_panX[camera()] : m_panY[camera()]; + } + + // Get the zoom value + inline double& zoom() + { return m_zoom[camera()]; + } + + private slots: + void slot_toolTipTimer(); }; // Alias for short namespaces typedef GLRenderer GL; -static const GLRenderer::ListType g_glListTypes[] = { - GL::NormalList, +static const GLRenderer::ListType g_glListTypes[] = +{ GL::NormalList, GL::PickList, GL::BFCFrontList, GL::BFCBackList, @@ -180,4 +253,4 @@ extern const GL::Camera g_Cameras[7]; extern const char* g_CameraNames[7]; -#endif // GLDRAW_H \ No newline at end of file +#endif // GLDRAW_H
--- a/src/gui.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/gui.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -48,6 +48,7 @@ #include "messagelog.h" #include "config.h" #include "ui_ldforge.h" +#include "moc_gui.cpp" static bool g_bSelectionLocked = false; @@ -64,28 +65,23 @@ #define act(N) extern_cfg (KeySequence, key_##N); #include "actions.h" -const char* g_modeActionNames[] = { - "modeSelect", - "modeDraw", -}; - // ============================================================================= // ----------------------------------------------------------------------------- -ForgeWindow::ForgeWindow() { - g_win = this; +ForgeWindow::ForgeWindow() +{ g_win = this; m_renderer = new GLRenderer; - + ui = new Ui_LDForgeUI; ui->setupUi (this); - + // Stuff the renderer into its frame QVBoxLayout* rendererLayout = new QVBoxLayout (ui->rendererFrame); rendererLayout->addWidget (R()); - + connect (ui->objectList, SIGNAL (itemSelectionChanged()), this, SLOT (slot_selectionChanged())); connect (ui->objectList, SIGNAL (itemDoubleClicked (QListWidgetItem*)), this, SLOT (slot_editObject (QListWidgetItem*))); connect (ui->fileList, SIGNAL (currentItemChanged (QListWidgetItem*, QListWidgetItem*)), this, SLOT (changeCurrentFile())); - + // Init message log manager m_msglog = new MessageManager; m_msglog->setRenderer (R()); @@ -93,7 +89,7 @@ m_quickColors = quickColorsFromConfig(); slot_selectionChanged(); setStatusBar (new QStatusBar); - + // Init primitive loader task stuff m_primLoaderBar = new QProgressBar; m_primLoaderWidget = new QWidget; @@ -102,7 +98,7 @@ primLoaderLayout->addWidget (m_primLoaderBar); statusBar()->addPermanentWidget (m_primLoaderWidget); m_primLoaderWidget->hide(); - + // Make certain actions checkable ui->actionAxes->setChecked (gl_axes); ui->actionWireframe->setChecked (gl_wireframe); @@ -112,11 +108,11 @@ updateRecentFilesMenu(); updateToolBars(); updateTitle(); - + setMinimumSize (300, 200); - + connect (qApp, SIGNAL (aboutToQuit()), this, SLOT (slot_lastSecondCleanup())); - + // Connect all actions and set shortcuts #define act(N) \ connect (ui->action##N, SIGNAL (triggered()), this, SLOT (slot_action())); \ @@ -126,41 +122,42 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::slot_action() { - // Find out which action triggered this +void ForgeWindow::slot_action() +{ // Find out which action triggered this #define act(N) if (sender() == ui->action##N) invokeAction (ui->action##N, &actiondef_##N); #include "actions.h" } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::invokeAction (QAction* act, void (*func)()) { - beginAction (act); - (*func)(); +void ForgeWindow::invokeAction (QAction* act, void (*func) ()) +{ beginAction (act); + (*func) (); endAction(); } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::slot_lastSecondCleanup() { - delete m_renderer; +void ForgeWindow::slot_lastSecondCleanup() +{ delete m_renderer; delete ui; } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::updateRecentFilesMenu() { - // First, clear any items in the recent files menu - for (QAction* recent : m_recentFiles) +void ForgeWindow::updateRecentFilesMenu() +{ // First, clear any items in the recent files menu +for (QAction * recent : m_recentFiles) delete recent; + m_recentFiles.clear(); - + QAction* first = null; - - for (const QVariant& it : io_recentfiles) { - str file = it.toString(); + +for (const QVariant & it : io_recentfiles) + { str file = it.toString(); QAction* recent = new QAction (getIcon ("open-recent"), file, this); - + connect (recent, SIGNAL (triggered()), this, SLOT (slot_recentFile())); ui->menuOpenRecent->insertAction (first, recent); m_recentFiles << recent; @@ -170,53 +167,53 @@ // ============================================================================= // ----------------------------------------------------------------------------- -List<LDQuickColor> quickColorsFromConfig() { - List<LDQuickColor> colors; - - for (str colorname : gui_colortoolbar.value.split (":")) { - if (colorname == "|") +QList<LDQuickColor> quickColorsFromConfig() +{ QList<LDQuickColor> colors; + +for (str colorname : gui_colortoolbar.value.split (":")) + { if (colorname == "|") colors << LDQuickColor::getSeparator(); - else { - LDColor* col = getColor (colorname.toLong()); - + else + { LDColor* col = getColor (colorname.toLong()); + if (col != null) colors << LDQuickColor (col, null); } } - + return colors; } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::updateToolBars() { - m_colorButtons.clear(); +void ForgeWindow::updateToolBars() +{ m_colorButtons.clear(); ui->colorToolbar->clear(); - - for (LDQuickColor& entry : m_quickColors) { - if (entry.isSeparator()) + +for (LDQuickColor & entry : m_quickColors) + { if (entry.isSeparator()) ui->colorToolbar->addSeparator(); - else { - QToolButton* colorButton = new QToolButton; + else + { QToolButton* colorButton = new QToolButton; colorButton->setIcon (makeColorIcon (entry.color(), 22)); colorButton->setIconSize (QSize (22, 22)); colorButton->setToolTip (entry.color()->name); - + connect (colorButton, SIGNAL (clicked()), this, SLOT (slot_quickColor())); ui->colorToolbar->addWidget (colorButton); m_colorButtons << colorButton; - + entry.setToolButton (colorButton); } } - + updateGridToolBar(); } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::updateGridToolBar() { - // Ensure that the current grid - and only the current grid - is selected. +void ForgeWindow::updateGridToolBar() +{ // Ensure that the current grid - and only the current grid - is selected. ui->actionGridCoarse->setChecked (grid == Grid::Coarse); ui->actionGridMedium->setChecked (grid == Grid::Medium); ui->actionGridFine->setChecked (grid == Grid::Fine); @@ -224,159 +221,158 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::updateTitle() { - str title = fmt (APPNAME " %1", fullVersionString()); - +void ForgeWindow::updateTitle() +{ str title = fmt (APPNAME " %1", fullVersionString()); + // Append our current file if we have one - if (LDFile::current()) { - if (LDFile::current()->name().length() > 0) + if (LDFile::current()) + { if (LDFile::current()->name().length() > 0) title += fmt (": %1", basename (LDFile::current()->name())); else title += fmt (": <anonymous>"); - + if (LDFile::current()->numObjs() > 0 && - LDFile::current()->obj (0)->getType() == LDObject::Comment) - { - // Append title + LDFile::current()->obj (0)->getType() == LDObject::Comment) + { // Append title LDComment* comm = static_cast<LDComment*> (LDFile::current()->obj (0)); title += fmt (": %1", comm->text); } - + if (LDFile::current()->history().pos() != LDFile::current()->savePos()) title += '*'; } - + +#ifdef DEBUG + title += " [debug build]"; +#elif BUILD_ID != BUILD_RELEASE + title += " [release build]"; +#endif // DEBUG + setWindowTitle (title); } // ============================================================================= // ----------------------------------------------------------------------------- -int ForgeWindow::deleteSelection() { - if (m_sel.size() == 0) +int ForgeWindow::deleteSelection() +{ if (selection().isEmpty()) return 0; - - List<LDObject*> selCopy = m_sel; - int num = 0; - + + QList<LDObject*> selCopy = selection(); + // Delete the objects that were being selected - for (LDObject* obj : selCopy) { - LDFile::current()->forgetObject (obj); - ++num; + for (LDObject* obj : selCopy) delete obj; - } - + refresh(); - return num; + return selCopy.size(); } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::buildObjList() { - if (!LDFile::current()) +void ForgeWindow::buildObjList() +{ if (!LDFile::current()) return; - + // Lock the selection while we do this so that refreshing the object list // doesn't trigger selection updating so that the selection doesn't get lost // while this is done. g_bSelectionLocked = true; - + for (int i = 0; i < ui->objectList->count(); ++i) delete ui->objectList->item (i); - + ui->objectList->clear(); - - for (LDObject* obj : LDFile::current()->objects()) { - str descr; - - switch (obj->getType()) { - case LDObject::Comment: - descr = static_cast<LDComment*> (obj)->text; - - // Remove leading whitespace - while (descr[0] == ' ') - descr.remove (0, 1); - break; - - case LDObject::Empty: - break; // leave it empty - - case LDObject::Line: - case LDObject::Triangle: - case LDObject::Quad: - case LDObject::CndLine: - for (short i = 0; i < obj->vertices(); ++i) { - if (i != 0) - descr += ", "; - - descr += obj->getVertex (i).stringRep (true); + + for (LDObject* obj : LDFile::current()->objects()) + { str descr; + + switch (obj->getType()) + { case LDObject::Comment: + { descr = static_cast<LDComment*> (obj)->text; + + // Remove leading whitespace + while (descr[0] == ' ') + descr.remove (0, 1); + } break; + + case LDObject::Empty: + break; // leave it empty + + case LDObject::Line: + case LDObject::Triangle: + case LDObject::Quad: + case LDObject::CndLine: + { for (short i = 0; i < obj->vertices(); ++i) + { if (i != 0) + descr += ", "; + + descr += obj->getVertex (i).stringRep (true); + } + } break; + + case LDObject::Error: + { descr = fmt ("ERROR: %1", obj->raw()); + } break; + + case LDObject::Vertex: + { descr = static_cast<LDVertex*> (obj)->pos.stringRep (true); + } break; + + case LDObject::Subfile: + { LDSubfile* ref = static_cast<LDSubfile*> (obj); + + descr = fmt ("%1 %2, (", ref->fileInfo()->name(), ref->position().stringRep (true)); + + for (int i = 0; i < 9; ++i) + descr += fmt ("%1%2", ref->transform()[i], (i != 8) ? " " : ""); + + descr += ')'; + } break; + + case LDObject::BFC: + { descr = LDBFC::statements[static_cast<LDBFC*> (obj)->type]; + } break; + + case LDObject::Overlay: + { LDOverlay* ovl = static_cast<LDOverlay*> (obj); + descr = fmt ("[%1] %2 (%3, %4), %5 x %6", g_CameraNames[ovl->camera()], + basename (ovl->filename()), ovl->x(), ovl->y(), ovl->width(), ovl->height()); } break; - - case LDObject::Error: - descr = fmt ("ERROR: %1", obj->raw()); - break; - - case LDObject::Vertex: - descr = static_cast<LDVertex*> (obj)->pos.stringRep (true); - break; - - case LDObject::Subfile: - { - LDSubfile* ref = static_cast<LDSubfile*> (obj); - - descr = fmt ("%1 %2, (", ref->fileInfo()->name(), - ref->position().stringRep (true)); - - for (short i = 0; i < 9; ++i) - descr += fmt ("%1%2", ftoa (ref->transform()[i]), - (i != 8) ? " " : ""); - - descr += ')'; - } - break; - - case LDObject::BFC: - descr = LDBFC::statements[static_cast<LDBFC*> (obj)->type]; - break; - - case LDObject::Overlay: - { - LDOverlay* ovl = static_cast<LDOverlay*> (obj); - descr = fmt ("[%1] %2 (%3, %4), %5 x %6", g_CameraNames[ovl->camera()], - basename (ovl->filename()), ovl->x(), ovl->y(), ovl->width(), ovl->height()); - } - break; - - default: - descr = obj->typeName(); - break; + + default: + { descr = obj->typeName(); + } break; } - - // Put it into brackets if it's hidden - if (obj->hidden()) - descr = fmt ("[[ %1 ]]", descr); - + QListWidgetItem* item = new QListWidgetItem (descr); item->setIcon (getIcon (obj->typeName())); + // Use italic font if hidden + if (obj->hidden()) + { QFont font = item->font(); + font.setItalic (true); + item->setFont (font); + } + // Color gibberish orange on red so it stands out. - if (obj->getType() == LDObject::Error) { - item->setBackground (QColor ("#AA0000")); + if (obj->getType() == LDObject::Error) + { item->setBackground (QColor ("#AA0000")); item->setForeground (QColor ("#FFAA00")); - } elif (lv_colorize && obj->isColored() && - obj->color() != maincolor && obj->color() != edgecolor) - { - // If the object isn't in the main or edge color, draw this + } + elif (lv_colorize && obj->isColored() && obj->color() != maincolor && obj->color() != edgecolor) + { // If the object isn't in the main or edge color, draw this // list entry in said color. LDColor* col = getColor (obj->color()); + if (col) item->setForeground (col->faceColor); } - + obj->qObjListEntry = item; ui->objectList->insertItem (ui->objectList->count(), item); } - + g_bSelectionLocked = false; updateSelection(); scrollToSelection(); @@ -384,291 +380,277 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::scrollToSelection() { - if (m_sel.size() == 0) +void ForgeWindow::scrollToSelection() +{ if (selection().isEmpty()) return; - - LDObject* obj = m_sel[m_sel.size() - 1]; + + LDObject* obj = selection().last(); ui->objectList->scrollToItem (obj->qObjListEntry); } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::slot_selectionChanged() { - if (g_bSelectionLocked == true || LDFile::current() == null) +void ForgeWindow::slot_selectionChanged() +{ if (g_bSelectionLocked == true || LDFile::current() == null) return; - + // Update the shared selection array, though don't do this if this was // called during GL picking, in which case the GL renderer takes care // of the selection. if (m_renderer->picking()) return; - - List<LDObject*> priorSelection = m_sel; - + + QList<LDObject*> priorSelection = selection(); + // Get the objects from the object list selection - m_sel.clear(); + LDFile::current()->clearSelection(); const QList<QListWidgetItem*> items = ui->objectList->selectedItems(); - + for (LDObject* obj : LDFile::current()->objects()) - for (QListWidgetItem* item : items) { - if (item == obj->qObjListEntry) { - m_sel << obj; - break; + { for (QListWidgetItem* item : items) + { if (item == obj->qObjListEntry) + { obj->select(); + break; + } } } - + // Update the GL renderer - for (LDObject* obj : priorSelection) { - obj->setSelected (false); + QList<LDObject*> compound = priorSelection + selection(); + removeDuplicates (compound); + + for (LDObject* obj : compound) m_renderer->compileObject (obj); - } - - for (LDObject* obj : m_sel) { - obj->setSelected (true); - m_renderer->compileObject (obj); - } - + m_renderer->update(); } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::slot_recentFile() { - QAction* qAct = static_cast<QAction*> (sender()); +void ForgeWindow::slot_recentFile() +{ QAction* qAct = static_cast<QAction*> (sender()); openMainFile (qAct->text()); } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::slot_quickColor() { - beginAction (null); +void ForgeWindow::slot_quickColor() +{ beginAction (null); QToolButton* button = static_cast<QToolButton*> (sender()); LDColor* col = null; - - for (const LDQuickColor& entry : m_quickColors) { - if (entry.toolButton() == button) { - col = entry.color(); + + for (const LDQuickColor & entry : m_quickColors) + { if (entry.toolButton() == button) + { col = entry.color(); break; } } - + if (col == null) return; - + short newColor = col->index; - - for (LDObject* obj : m_sel) { - if (obj->isColored() == false) + + for (LDObject* obj : selection()) + { if (obj->isColored() == false) continue; // uncolored object - + obj->setColor (newColor); R()->compileObject (obj); } - + refresh(); endAction(); } // ============================================================================= // ----------------------------------------------------------------------------- -ulong ForgeWindow::getInsertionPoint() { - if (m_sel.size() > 0) { - // If we have a selection, put the item after it. - return (m_sel[m_sel.size() - 1]->getIndex()) + 1; - } - +int ForgeWindow::getInsertionPoint() +{ // If we have a selection, put the item after it. + if (!selection().isEmpty()) + return selection().last()->getIndex() + 1; + // Otherwise place the object at the end. return LDFile::current()->numObjs(); } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::fullRefresh() { - buildObjList(); +void ForgeWindow::fullRefresh() +{ buildObjList(); m_renderer->hardRefresh(); } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::refresh() { - buildObjList(); +void ForgeWindow::refresh() +{ buildObjList(); m_renderer->update(); } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::updateSelection() { - g_bSelectionLocked = true; - - print ("1\n"); +void ForgeWindow::updateSelection() +{ g_bSelectionLocked = true; + for (LDObject* obj : LDFile::current()->objects()) obj->setSelected (false); - - print ("2\n"); + ui->objectList->clearSelection(); - - print ("3\n"); - for (LDObject* obj : m_sel) { - if (obj->qObjListEntry == null) + + for (LDObject* obj : selection()) + { if (obj->qObjListEntry == null) continue; - + obj->qObjListEntry->setSelected (true); obj->setSelected (true); } - - print ("4\n"); + g_bSelectionLocked = false; slot_selectionChanged(); } // ============================================================================= // ----------------------------------------------------------------------------- -bool ForgeWindow::isSelected (LDObject* obj) { - LDObject* needle = obj->topLevelParent(); - - for (LDObject* hay : m_sel) - if (hay == needle) - return true; - - return false; -} +short ForgeWindow::getSelectedColor() +{ short result = -1; -short ForgeWindow::getSelectedColor() { - short result = -1; - - for (LDObject* obj : m_sel) { - if (obj->isColored() == false) + for (LDObject* obj : selection()) + { if (obj->isColored() == false) continue; // doesn't use color - + if (result != -1 && obj->color() != result) return -1; // No consensus in object color - + if (result == -1) result = obj->color(); } - + return result; } // ============================================================================= // ----------------------------------------------------------------------------- -LDObject::Type ForgeWindow::uniformSelectedType() { - LDObject::Type result = LDObject::Unidentified; - - for (LDObject* obj : m_sel) { - if (result != LDObject::Unidentified && obj->color() != result) +LDObject::Type ForgeWindow::uniformSelectedType() +{ LDObject::Type result = LDObject::Unidentified; + + for (LDObject * obj : selection()) + { if (result != LDObject::Unidentified && obj->color() != result) return LDObject::Unidentified; - + if (result == LDObject::Unidentified) result = obj->getType(); } - + return result; } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::closeEvent (QCloseEvent* ev) { - // Check whether it's safe to close all files. - if (!safeToCloseAll()) { - ev->ignore(); +void ForgeWindow::closeEvent (QCloseEvent* ev) +{ // Check whether it's safe to close all files. + if (!safeToCloseAll()) + { ev->ignore(); return; } - + // Save the configuration before leaving so that, for instance, grid choice // is preserved across instances. Config::save(); - + ev->accept(); } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::spawnContextMenu (const QPoint pos) { - const bool single = (g_win->sel().size() == 1); - LDObject* singleObj = (single) ? g_win->sel()[0] : null; - +void ForgeWindow::spawnContextMenu (const QPoint pos) +{ const bool single = (selection().size() == 1); + LDObject* singleObj = (single) ? selection()[0] : null; + QMenu* contextMenu = new QMenu; - - if (single && singleObj->getType() != LDObject::Empty) { - contextMenu->addAction (ACTION (Edit)); + + if (single && singleObj->getType() != LDObject::Empty) + { contextMenu->addAction (ACTION (Edit)); contextMenu->addSeparator(); } - + contextMenu->addAction (ACTION (Cut)); contextMenu->addAction (ACTION (Copy)); contextMenu->addAction (ACTION (Paste)); contextMenu->addAction (ACTION (Delete)); contextMenu->addSeparator(); contextMenu->addAction (ACTION (SetColor)); - + if (single) contextMenu->addAction (ACTION (EditRaw)); - + contextMenu->addAction (ACTION (Borders)); contextMenu->addAction (ACTION (SetOverlay)); contextMenu->addAction (ACTION (ClearOverlay)); contextMenu->addAction (ACTION (ModeSelect)); contextMenu->addAction (ACTION (ModeDraw)); - - if (R()->camera() != GL::Free) { - contextMenu->addSeparator(); + contextMenu->addAction (ACTION (ModeCircle)); + + if (R()->camera() != GL::Free) + { contextMenu->addSeparator(); contextMenu->addAction (ACTION (SetDrawDepth)); } - + contextMenu->exec (pos); } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::deleteObjVector (List<LDObject*> objs) { - for (LDObject* obj : objs) { - LDFile::current()->forgetObject (obj); +void ForgeWindow::deleteObjVector (QList<LDObject*> objs) +{ for (LDObject * obj : objs) + { LDFile::current()->forgetObject (obj); delete obj; } } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::deleteByColor (const short colnum) { - List<LDObject*> objs; - for (LDObject* obj : LDFile::current()->objects()) { - if (!obj->isColored() || obj->color() != colnum) +void ForgeWindow::deleteByColor (const short colnum) +{ QList<LDObject*> objs; + +for (LDObject * obj : LDFile::current()->objects()) + { if (!obj->isColored() || obj->color() != colnum) continue; - + objs << obj; } - + deleteObjVector (objs); } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::updateEditModeActions() { - const EditMode mode = R()->editMode(); +void ForgeWindow::updateEditModeActions() +{ const EditMode mode = R()->editMode(); ACTION (ModeSelect)->setChecked (mode == Select); ACTION (ModeDraw)->setChecked (mode == Draw); + ACTION (ModeCircle)->setChecked (mode == CircleMode); } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::slot_editObject (QListWidgetItem* listitem) { - LDObject* obj = null; - for (LDObject* it : LDFile::current()->objects()) { - if (it->qObjListEntry == listitem) { - obj = it; +void ForgeWindow::slot_editObject (QListWidgetItem* listitem) +{ LDObject* obj = null; + + for (LDObject* it : LDFile::current()->objects()) + { if (it->qObjListEntry == listitem) + { obj = it; break; } } - + AddObjectDialog::staticDialog (obj->getType(), obj); } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::primitiveLoaderStart (ulong max) { - m_primLoaderWidget->show(); +void ForgeWindow::primitiveLoaderStart (int max) +{ m_primLoaderWidget->show(); m_primLoaderBar->setRange (0, max); m_primLoaderBar->setValue (0); m_primLoaderBar->setFormat ("%p%"); @@ -676,14 +658,14 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::primitiveLoaderUpdate (ulong prog) { - m_primLoaderBar->setValue (prog); +void ForgeWindow::primitiveLoaderUpdate (int prog) +{ m_primLoaderBar->setValue (prog); } // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::primitiveLoaderEnd() { - QTimer* hidetimer = new QTimer; +void ForgeWindow::primitiveLoaderEnd() +{ QTimer* hidetimer = new QTimer; connect (hidetimer, SIGNAL (timeout()), m_primLoaderWidget, SLOT (hide())); hidetimer->setSingleShot (true); hidetimer->start (1500); @@ -693,92 +675,93 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void ForgeWindow::save (LDFile* f, bool saveAs) { - str path = f->name(); - - if (path.length() == 0 || saveAs) { - path = QFileDialog::getSaveFileName (g_win, tr ("Save As"), - LDFile::current()->name(), tr ("LDraw files (*.dat *.ldr)")); - - if (path.length() == 0) { - // User didn't give a file name. This happens if the user cancelled - // saving in the save file dialog. Abort. +void ForgeWindow::save (LDFile* f, bool saveAs) +{ str path = f->name(); + + if (saveAs || path.isEmpty()) + { path = QFileDialog::getSaveFileName (g_win, tr ("Save As"), + (f->name().isEmpty()) ? f->name() : f->defaultName(), tr ("LDraw files (*.dat *.ldr)")); + + if (path.isEmpty()) + { // User didn't give a file name, abort. return; } } - - if (f->save (path)) { - f->setName (path); - + + if (f->save (path)) + { f->setName (path); + if (f == LDFile::current()) g_win->updateTitle(); - + log ("Saved to %1.", path); - + // Add it to recent files addRecentFile (path); - } else { - str message = fmt (tr ("Failed to save to %1: %2"), path, strerror (errno)); - + } + else + { str message = fmt (tr ("Failed to save to %1: %2"), path, strerror (errno)); + // Tell the user the save failed, and give the option for saving as with it. QMessageBox dlg (QMessageBox::Critical, tr ("Save Failure"), message, QMessageBox::Close, g_win); - + // Add a save-as button QPushButton* saveAsBtn = new QPushButton (tr ("Save As")); saveAsBtn->setIcon (getIcon ("file-save-as")); dlg.addButton (saveAsBtn, QMessageBox::ActionRole); dlg.setDefaultButton (QMessageBox::Close); dlg.exec(); - + if (dlg.clickedButton() == saveAsBtn) save (f, true); // yay recursion! } } -void ForgeWindow::addMessage (str msg) { - m_msglog->addLine (msg); +void ForgeWindow::addMessage (str msg) +{ m_msglog->addLine (msg); } // ============================================================================ -void ObjectList::contextMenuEvent (QContextMenuEvent* ev) { - g_win->spawnContextMenu (ev->globalPos()); +void ObjectList::contextMenuEvent (QContextMenuEvent* ev) +{ g_win->spawnContextMenu (ev->globalPos()); } // ============================================================================= // ----------------------------------------------------------------------------- -QPixmap getIcon (str iconName) { - return (QPixmap (fmt (":/icons/%1.png", iconName))); +QPixmap getIcon (str iconName) +{ return (QPixmap (fmt (":/icons/%1.png", iconName))); } // ============================================================================= -bool confirm (str msg) { - return confirm (ForgeWindow::tr ("Confirm"), msg); +bool confirm (str msg) +{ return confirm (ForgeWindow::tr ("Confirm"), msg); } -bool confirm (str title, str msg) { - return QMessageBox::question (g_win, title, msg, +bool confirm (str title, str msg) +{ return QMessageBox::question (g_win, title, msg, (QMessageBox::Yes | QMessageBox::No), QMessageBox::No) == QMessageBox::Yes; } // ============================================================================= -void critical (str msg) { - QMessageBox::critical (g_win, ForgeWindow::tr("Error"), msg, +void critical (str msg) +{ QMessageBox::critical (g_win, ForgeWindow::tr ("Error"), msg, (QMessageBox::Close), QMessageBox::Close); } // ============================================================================= -QIcon makeColorIcon (LDColor* colinfo, const ushort size) { - // Create an image object and link a painter to it. +QIcon makeColorIcon (LDColor* colinfo, const int size) +{ // Create an image object and link a painter to it. QImage img (size, size, QImage::Format_ARGB32); QPainter paint (&img); - + QColor col = colinfo->faceColor; - if (colinfo->index == maincolor) { - // Use the user preferences for main color here + + if (colinfo->index == maincolor) + { // Use the user preferences for main color here col = gl_maincolor.value; col.setAlphaF (gl_maincolor_alpha); } - + // Paint the icon paint.fillRect (QRect (0, 0, size, size), colinfo->edgeColor); paint.drawPixmap (QRect (1, 1, size - 2, size - 2), getIcon ("checkerboard"), QRect (0, 0, 8, 8)); @@ -787,101 +770,98 @@ } // ============================================================================= -void makeColorSelector (QComboBox* box) { - std::map<short, ulong> counts; - - for (LDObject* obj : LDFile::current()->objects()) { - if (!obj->isColored()) +void makeColorSelector (QComboBox* box) +{ std::map<int, int> counts; + + for (LDObject * obj : LDFile::current()->objects()) + { if (!obj->isColored()) continue; - + if (counts.find (obj->color()) == counts.end()) counts[obj->color()] = 1; else counts[obj->color()]++; } - + box->clear(); - ulong row = 0; - for (const auto& pair : counts) { - LDColor* col = getColor (pair.first); + int row = 0; + + for (const auto & pair : counts) + { LDColor* col = getColor (pair.first); assert (col != null); - + QIcon ico = makeColorIcon (col, 16); box->addItem (ico, fmt ("[%1] %2 (%3 object%4)", - pair.first, col->name, pair.second, plural (pair.second))); + pair.first, col->name, pair.second, plural (pair.second))); box->setItemData (row, pair.first); - + ++row; } } -void ForgeWindow::setStatusBarText (str text) { - statusBar()->showMessage (text); +void ForgeWindow::setStatusBarText (str text) +{ statusBar()->showMessage (text); } -void ForgeWindow::clearSelection() { - m_sel.clear(); -} - -Ui_LDForgeUI* ForgeWindow::interface() const { - return ui; +Ui_LDForgeUI* ForgeWindow::interface() const +{ return ui; } #define act(N) QAction* ForgeWindow::action##N() { return ui->action##N; } #include "actions.h" -void ForgeWindow::updateFileList() { - ui->fileList->clear(); - - for (LDFile* f : g_loadedFiles) { - // Don't list implicit files unless explicitly desired. +void ForgeWindow::updateFileList() +{ ui->fileList->clear(); + + for (LDFile* f : g_loadedFiles) + { // Don't list implicit files unless explicitly desired. if (f->implicit() && !gui_implicitfiles) continue; - + // Add an item to the list for this file and store a pointer to it in // the file, so we can find files by the list item. ui->fileList->addItem (""); QListWidgetItem* item = ui->fileList->item (ui->fileList->count() - 1); f->setListItem (item); - + updateFileListItem (f); } } -void ForgeWindow::updateFileListItem (LDFile* f) { - if (f->listItem() == null) { - // We don't have a list item for this file, so the list either doesn't +void ForgeWindow::updateFileListItem (LDFile* f) +{ if (f->listItem() == null) + { // We don't have a list item for this file, so the list either doesn't // exist yet or is out of date. Build the list now. updateFileList(); return; } - + // If this is the current file, it also needs to be the selected item on // the list. if (f == LDFile::current()) ui->fileList->setCurrentItem (f->listItem()); - + // If we list implicit files, draw them with a shade of gray to make them // distinct. if (f->implicit()) f->listItem()->setForeground (QColor (96, 96, 96)); - + f->listItem()->setText (f->getShortName()); - + // If the file has unsaved changes, draw a little icon next to it to mark that. f->listItem()->setIcon (f->hasUnsavedChanges() ? getIcon ("file-save") : QIcon()); } -void ForgeWindow::beginAction (QAction* act) { - // Open the history so we can record the edits done during this action. +void ForgeWindow::beginAction (QAction* act) +{ // Open the history so we can record the edits done during this action. if (act != ACTION (Undo) && act != ACTION (Redo) && act != ACTION (Open)) LDFile::current()->openHistory(); } -void ForgeWindow::endAction() { - // Close the history now. +void ForgeWindow::endAction() +{ // Close the history now. LDFile::current()->closeHistory(); - + // Update the list item of the current file - we may need to draw an icon // now that marks it as having unsaved changes. updateFileListItem (LDFile::current()); @@ -890,40 +870,42 @@ // ============================================================================= // A file is selected from the list of files on the left of the screen. Find out // which file was picked and change to it. -void ForgeWindow::changeCurrentFile() { - LDFile* f = null; +void ForgeWindow::changeCurrentFile() +{ LDFile* f = null; QListWidgetItem* item = ui->fileList->currentItem(); - + // Find the file pointer of the item that was selected. - for (LDFile* it : g_loadedFiles) { - if (it->listItem() == item) { - f = it; +for (LDFile * it : g_loadedFiles) + { if (it->listItem() == item) + { f = it; break; } } - + // If we picked the same file we're currently on, we don't need to do // anything. if (!f || f == LDFile::current()) return; - + LDFile::setCurrent (f); } -void ForgeWindow::refreshObjectList() { +void ForgeWindow::refreshObjectList() +{ #if 0 ui->objectList->clear(); LDFile* f = LDFile::current(); - - for (LDObject* obj : *f) + +for (LDObject * obj : *f) ui->objectList->addItem (obj->qObjListEntry); + #endif - + buildObjList(); } -QImage imageFromScreencap (uchar* data, ushort w, ushort h) { - // GL and Qt formats have R and B swapped. Also, GL flips Y - correct it as well. +QImage imageFromScreencap (uchar* data, int w, int h) +{ // GL and Qt formats have R and B swapped. Also, GL flips Y - correct it as well. return QImage (data, w, h, QImage::Format_ARGB32).rgbSwapped().mirrored(); } @@ -933,11 +915,10 @@ m_color (color), m_toolButton (toolButton) {} -LDQuickColor LDQuickColor::getSeparator() { - return LDQuickColor (null, null); +LDQuickColor LDQuickColor::getSeparator() +{ return LDQuickColor (null, null); } -bool LDQuickColor::isSeparator() const { - return color() == null; +bool LDQuickColor::isSeparator() const +{ return color() == null; } -#include "moc_gui.cpp"
--- a/src/gui.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/gui.h Wed Oct 23 12:46:10 2013 +0300 @@ -41,7 +41,7 @@ bbx_buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel); \ connect (bbx_buttons, SIGNAL (accepted()), this, SLOT (accept())); \ connect (bbx_buttons, SIGNAL (rejected()), this, SLOT (reject())); \ - + // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= @@ -58,106 +58,110 @@ #define CTRL_SHIFT(N) (Qt::CTRL | Qt::SHIFT | Qt::Key_##N) // ============================================================================= -class LDQuickColor { - PROPERTY (LDColor*, color, setColor) +class LDQuickColor +{ PROPERTY (LDColor*, color, setColor) PROPERTY (QToolButton*, toolButton, setToolButton) - -public: - LDQuickColor (LDColor* color, QToolButton* toolButton); - bool isSeparator() const; - - static LDQuickColor getSeparator(); + + public: + LDQuickColor (LDColor* color, QToolButton* toolButton); + bool isSeparator() const; + + static LDQuickColor getSeparator(); }; // ============================================================================= // ObjectList -// +// // Object list class for ForgeWindow // ============================================================================= -class ObjectList : public QListWidget { - Q_OBJECT - -protected: - void contextMenuEvent (QContextMenuEvent* ev); +class ObjectList : public QListWidget +{ Q_OBJECT + + protected: + void contextMenuEvent (QContextMenuEvent* ev); }; // ============================================================================= // ForgeWindow -// +// // The one main GUI class. Hosts the renderer, object list, message log. Contains // slot_action, which is what all actions connect to. Manages menus and toolbars. // Large and in charge. // ============================================================================= -class ForgeWindow : public QMainWindow { - Q_OBJECT - -public: - ForgeWindow(); - void buildObjList(); - void updateTitle(); - void fullRefresh(); - void refresh(); - ulong getInsertionPoint(); - void updateToolBars(); - void updateRecentFilesMenu(); - void updateSelection(); - void updateGridToolBar(); - void updateEditModeActions(); - void updateFileList(); - void updateFileListItem (LDFile* f); - bool isSelected (LDObject* obj); - short getSelectedColor(); - LDObject::Type uniformSelectedType(); - void scrollToSelection(); - void spawnContextMenu (const QPoint pos); - void deleteObjVector (List< LDObject* > objs); - int deleteSelection(); - void deleteByColor (const short int colnum); - void save (LDFile* f, bool saveAs); - GLRenderer* R() { return m_renderer; } - List<LDObject*>& sel() { return m_sel; } - void setQuickColors (List<LDQuickColor>& colors) { m_quickColors = colors; } - void setStatusBarText (str text); - void addMessage (str msg); - Ui_LDForgeUI* interface() const; - void refreshObjectList(); - void beginAction(QAction* act); - void endAction(); - +class ForgeWindow : public QMainWindow +{ Q_OBJECT + + public: + ForgeWindow(); + void buildObjList(); + void updateTitle(); + void fullRefresh(); + void refresh(); + int getInsertionPoint(); + void updateToolBars(); + void updateRecentFilesMenu(); + void updateSelection(); + void updateGridToolBar(); + void updateEditModeActions(); + void updateFileList(); + void updateFileListItem (LDFile* f); + short getSelectedColor(); + LDObject::Type uniformSelectedType(); + void scrollToSelection(); + void spawnContextMenu (const QPoint pos); + void deleteObjVector (QList< LDObject* > objs); + int deleteSelection(); + void deleteByColor (const short int colnum); + void save (LDFile* f, bool saveAs); + + inline GLRenderer* R() + { return m_renderer; + } + + inline void setQuickColors (QList<LDQuickColor>& colors) + { m_quickColors = colors; + } + + void setStatusBarText (str text); + void addMessage (str msg); + Ui_LDForgeUI* interface() const; + void refreshObjectList(); + void beginAction (QAction* act); + void endAction(); + #define act(N) QAction* action##N(); #include "actions.h" - -public slots: - void primitiveLoaderStart (ulong max); - void primitiveLoaderUpdate (ulong prog); - void primitiveLoaderEnd(); - void clearSelection(); - void slot_action(); - void changeCurrentFile(); - -protected: - void closeEvent (QCloseEvent* ev); - -private: - GLRenderer* m_renderer; - QProgressBar* m_primLoaderBar; - QWidget* m_primLoaderWidget; - List<LDObject*> m_sel; - List<LDQuickColor> m_quickColors; - List<QToolButton*> m_colorButtons; - List<QAction*> m_recentFiles; - MessageManager* m_msglog; - Ui_LDForgeUI* ui; - - void invokeAction (QAction* act, void (*func)()); - + + public slots: + void primitiveLoaderStart (int max); + void primitiveLoaderUpdate (int prog); + void primitiveLoaderEnd(); + void slot_action(); + void changeCurrentFile(); + + protected: + void closeEvent (QCloseEvent* ev); -private slots: - void slot_selectionChanged(); - void slot_recentFile(); - void slot_quickColor(); - void slot_lastSecondCleanup(); - void slot_editObject (QListWidgetItem* listitem); + private: + GLRenderer* m_renderer; + QProgressBar* m_primLoaderBar; + QWidget* m_primLoaderWidget; + QList<LDObject*> m_sel; + QList<LDQuickColor> m_quickColors; + QList<QToolButton*> m_colorButtons; + QList<QAction*> m_recentFiles; + MessageManager* m_msglog; + Ui_LDForgeUI* ui; + + void invokeAction (QAction* act, void (*func)()); + + + private slots: + void slot_selectionChanged(); + void slot_recentFile(); + void slot_quickColor(); + void slot_lastSecondCleanup(); + void slot_editObject (QListWidgetItem* listitem); }; #define INVOKE_ACTION(N) actiondef_##N(); @@ -171,24 +175,24 @@ // ----------------------------------------------------------------------------- // Other GUI-related stuff not directly part of ForgeWindow: QPixmap getIcon (str iconName); // Get an icon from the resource dir -List<LDQuickColor> quickColorsFromConfig(); // Make a list of quick colors based on config +QList<LDQuickColor> quickColorsFromConfig(); // Make a list of quick colors based on config bool confirm (str title, str msg); // Generic confirm prompt bool confirm (str msg); // Generic confirm prompt void critical (str msg); // Generic error prompt -QIcon makeColorIcon (LDColor* colinfo, const ushort size); // Makes an icon for the given color +QIcon makeColorIcon (LDColor* colinfo, const int size); // Makes an icon for the given color void makeColorSelector (QComboBox* box); // Fills the given combo-box with color information -QImage imageFromScreencap (uchar* data, ushort w, ushort h); +QImage imageFromScreencap (uchar* data, int w, int h); // ============================================================================= // ----------------------------------------------------------------------------- // Takes in pairs of radio buttons and respective values and returns the value of // the first found radio button that was checked. // ============================================================================= -template<class T> T radioSwitch (const T& defval, List<pair<QRadioButton*, T>> haystack) { - for (pair<QRadioButton*, const T&> i : haystack) +template<class T> T radioSwitch (const T& defval, QList<pair<QRadioButton*, T>> haystack) +{ for (pair<QRadioButton*, const T&> i : haystack) if (i.first->isChecked()) return i.second; - + return defval; } @@ -197,13 +201,13 @@ // Takes in pairs of radio buttons and respective values and checks the first // found radio button to have the given value. // ============================================================================= -template<class T> void radioDefault (const T& expr, List<pair<QRadioButton*, T>> haystack) { - for (pair<QRadioButton*, const T&> i : haystack) { - if (i.second == expr) { - i.first->setChecked (true); +template<class T> void radioDefault (const T& expr, QList<pair<QRadioButton*, T>> haystack) +{ for (pair<QRadioButton*, const T&> i : haystack) + { if (i.second == expr) + { i.first->setChecked (true); return; } } } -#endif // GUI_H \ No newline at end of file +#endif // GUI_H
--- a/src/gui_actions.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/gui_actions.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -44,361 +44,358 @@ // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (New, CTRL_SHIFT (N)) { - QDialog* dlg = new QDialog (g_win); +DEFINE_ACTION (New, CTRL_SHIFT (N)) +{ QDialog* dlg = new QDialog (g_win); Ui::NewPartUI ui; ui.setupUi (dlg); - + str authortext = ld_defaultname; - + if (!ld_defaultuser.value.isEmpty()) authortext.append (fmt (" [%1]", ld_defaultuser)); - + ui.le_author->setText (authortext); - - switch (ld_defaultlicense) { - case 0: - ui.rb_license_ca->setChecked (true); - break; - - case 1: - ui.rb_license_nonca->setChecked (true); - break; - - case 2: - ui.rb_license_none->setChecked (true); - break; - - default: - QMessageBox::warning (null, "Warning", - fmt ("Unknown ld_defaultlicense value %1!", ld_defaultlicense)); - break; + + switch (ld_defaultlicense) + { case 0: + ui.rb_license_ca->setChecked (true); + break; + + case 1: + ui.rb_license_nonca->setChecked (true); + break; + + case 2: + ui.rb_license_none->setChecked (true); + break; + + default: + QMessageBox::warning (null, "Warning", + fmt ("Unknown ld_defaultlicense value %1!", ld_defaultlicense)); + break; } - + if (dlg->exec() == false) return; - + newFile(); - + const LDBFC::Type BFCType = ui.rb_bfc_ccw->isChecked() ? LDBFC::CertifyCCW : ui.rb_bfc_cw->isChecked() ? LDBFC::CertifyCW : LDBFC::NoCertify; - + const str license = ui.rb_license_ca->isChecked() ? CALicense : ui.rb_license_nonca->isChecked() ? NonCALicense : ""; - - LDFile::current()->addObjects ({ - new LDComment (ui.le_title->text()), - new LDComment ("Name: <untitled>.dat" ), + + LDFile::current()->addObjects ( + { new LDComment (ui.le_title->text()), + new LDComment ("Name: <untitled>.dat"), new LDComment (fmt ("Author: %1", ui.le_author->text())), new LDComment (fmt ("!LDRAW_ORG Unofficial_Part")), (license != "" ? - new LDComment (license) : - null), + new LDComment (license) : + null), new LDEmpty, new LDBFC (BFCType), new LDEmpty, }); - + g_win->fullRefresh(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (NewFile, CTRL (N)) { - newFile(); +DEFINE_ACTION (NewFile, CTRL (N)) +{ newFile(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Open, CTRL (O)) { - str name = QFileDialog::getOpenFileName (g_win, "Open File", "", "LDraw files (*.dat *.ldr)"); - +DEFINE_ACTION (Open, CTRL (O)) +{ str name = QFileDialog::getOpenFileName (g_win, "Open File", "", "LDraw files (*.dat *.ldr)"); + if (name.length() == 0) return; - + openMainFile (name); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Save, CTRL (S)) { - g_win->save (LDFile::current(), false); +DEFINE_ACTION (Save, CTRL (S)) +{ g_win->save (LDFile::current(), false); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (SaveAs, CTRL_SHIFT (S)) { - g_win->save (LDFile::current(), true); +DEFINE_ACTION (SaveAs, CTRL_SHIFT (S)) +{ g_win->save (LDFile::current(), true); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (SaveAll, CTRL (L)) { - for (LDFile* file : g_loadedFiles) { - if (file->implicit()) +DEFINE_ACTION (SaveAll, CTRL (L)) +{ for (LDFile* file : g_loadedFiles) + { if (file->implicit()) continue; - + g_win->save (file, false); } } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Close, CTRL (W)) { - if (!LDFile::current()->safeToClose()) +DEFINE_ACTION (Close, CTRL (W)) +{ if (!LDFile::current()->safeToClose()) return; - + delete LDFile::current(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (CloseAll, 0) { - if (!safeToCloseAll()) +DEFINE_ACTION (CloseAll, 0) +{ if (!safeToCloseAll()) return; - + closeAll(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Settings, 0) { - (new ConfigDialog)->exec(); +DEFINE_ACTION (Settings, 0) +{ (new ConfigDialog)->exec(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (SetLDrawPath, 0) { - (new LDrawPathDialog (true))->exec(); +DEFINE_ACTION (SetLDrawPath, 0) +{ (new LDrawPathDialog (true))->exec(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Exit, CTRL (Q)) { - exit (0); +DEFINE_ACTION (Exit, CTRL (Q)) +{ exit (0); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (NewSubfile, 0) { - AddObjectDialog::staticDialog (LDObject::Subfile, null); +DEFINE_ACTION (NewSubfile, 0) +{ AddObjectDialog::staticDialog (LDObject::Subfile, null); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (NewLine, 0) { - AddObjectDialog::staticDialog (LDObject::Line, null); +DEFINE_ACTION (NewLine, 0) +{ AddObjectDialog::staticDialog (LDObject::Line, null); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (NewTriangle, 0) { - AddObjectDialog::staticDialog (LDObject::Triangle, null); +DEFINE_ACTION (NewTriangle, 0) +{ AddObjectDialog::staticDialog (LDObject::Triangle, null); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (NewQuad, 0) { - AddObjectDialog::staticDialog (LDObject::Quad, null); +DEFINE_ACTION (NewQuad, 0) +{ AddObjectDialog::staticDialog (LDObject::Quad, null); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (NewCLine, 0) { - AddObjectDialog::staticDialog (LDObject::CndLine, null); +DEFINE_ACTION (NewCLine, 0) +{ AddObjectDialog::staticDialog (LDObject::CndLine, null); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (NewComment, 0) { - AddObjectDialog::staticDialog (LDObject::Comment, null); +DEFINE_ACTION (NewComment, 0) +{ AddObjectDialog::staticDialog (LDObject::Comment, null); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (NewBFC, 0) { - AddObjectDialog::staticDialog (LDObject::BFC, null); -} - -// ============================================================================= -// ----------------------------------------------------------------------------- -DEFINE_ACTION (NewVertex, 0) { - AddObjectDialog::staticDialog (LDObject::Vertex, null); +DEFINE_ACTION (NewBFC, 0) +{ AddObjectDialog::staticDialog (LDObject::BFC, null); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (MakePrimitive, 0) { - generatePrimitive(); +DEFINE_ACTION (NewVertex, 0) +{ AddObjectDialog::staticDialog (LDObject::Vertex, null); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Edit, 0) { - if (g_win->sel().size() != 1) +DEFINE_ACTION (Edit, 0) +{ if (selection().size() != 1) return; - - LDObject* obj = g_win->sel()[0]; + + LDObject* obj = selection() [0]; AddObjectDialog::staticDialog (obj->getType(), obj); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Help, KEY (F1)) { - -} - -// ============================================================================= -// ----------------------------------------------------------------------------- -DEFINE_ACTION (About, 0) { - AboutDialog().exec(); +DEFINE_ACTION (Help, KEY (F1)) +{ } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (AboutQt, 0) { - QMessageBox::aboutQt (g_win); +DEFINE_ACTION (About, 0) +{ AboutDialog().exec(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (SelectAll, CTRL (A)) { - g_win->sel().clear(); - - for (LDObject* obj : LDFile::current()->objects()) - g_win->sel() << obj; - +DEFINE_ACTION (AboutQt, 0) +{ QMessageBox::aboutQt (g_win); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +DEFINE_ACTION (SelectAll, CTRL (A)) +{ for (LDObject* obj : LDFile::current()->objects()) + obj->select(); + g_win->updateSelection(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (SelectByColor, CTRL_SHIFT (A)) { - short colnum = g_win->getSelectedColor(); - +DEFINE_ACTION (SelectByColor, CTRL_SHIFT (A)) +{ short colnum = g_win->getSelectedColor(); + if (colnum == -1) return; // no consensus on color - - g_win->sel().clear(); + + LDFile::current()->clearSelection(); + for (LDObject* obj : LDFile::current()->objects()) if (obj->color() == colnum) - g_win->sel() << obj; - + obj->select(); + g_win->updateSelection(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (SelectByType, 0) { - if (g_win->sel().size() == 0) +DEFINE_ACTION (SelectByType, 0) +{ if (selection().isEmpty()) return; - + LDObject::Type type = g_win->uniformSelectedType(); - + if (type == LDObject::Unidentified) return; - + // If we're selecting subfile references, the reference filename must also // be uniform. str refName; - - if (type == LDObject::Subfile) { - refName = static_cast<LDSubfile*> (g_win->sel()[0])->fileInfo()->name(); - - for (LDObject* obj : g_win->sel()) + + if (type == LDObject::Subfile) + { refName = static_cast<LDSubfile*> (selection()[0])->fileInfo()->name(); + + for (LDObject* obj : selection()) if (static_cast<LDSubfile*> (obj)->fileInfo()->name() != refName) return; } - - g_win->sel().clear(); - for (LDObject* obj : LDFile::current()->objects()) { - if (obj->getType() != type) + + LDFile::current()->clearSelection(); + + for (LDObject* obj : LDFile::current()->objects()) + { if (obj->getType() != type) continue; - + if (type == LDObject::Subfile && static_cast<LDSubfile*> (obj)->fileInfo()->name() != refName) continue; - - g_win->sel() << obj; + + obj->select(); } - + g_win->updateSelection(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (GridCoarse, 0) { - grid = Grid::Coarse; +DEFINE_ACTION (GridCoarse, 0) +{ grid = Grid::Coarse; g_win->updateGridToolBar(); } -DEFINE_ACTION (GridMedium, 0) { - grid = Grid::Medium; +DEFINE_ACTION (GridMedium, 0) +{ grid = Grid::Medium; g_win->updateGridToolBar(); } -DEFINE_ACTION (GridFine, 0) { - grid = Grid::Fine; +DEFINE_ACTION (GridFine, 0) +{ grid = Grid::Fine; g_win->updateGridToolBar(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (ResetView, CTRL (0)) { - g_win->R()->resetAngles(); +DEFINE_ACTION (ResetView, CTRL (0)) +{ g_win->R()->resetAngles(); g_win->R()->update(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (InsertFrom, 0) { - str fname = QFileDialog::getOpenFileName(); - ulong idx = g_win->getInsertionPoint(); - +DEFINE_ACTION (InsertFrom, 0) +{ str fname = QFileDialog::getOpenFileName(); + int idx = g_win->getInsertionPoint(); + if (!fname.length()) return; - + File f (fname, File::Read); - if (!f) { - critical (fmt ("Couldn't open %1 (%2)", fname, strerror (errno))); + + if (!f) + { critical (fmt ("Couldn't open %1 (%2)", fname, strerror (errno))); return; } - - List<LDObject*> objs = loadFileContents (&f, null); - - g_win->sel().clear(); - - for (LDObject* obj : objs) { - LDFile::current()->insertObj (idx, obj); - g_win->sel() << obj; + + QList<LDObject*> objs = loadFileContents (&f, null); + + LDFile::current()->clearSelection(); + + for (LDObject* obj : objs) + { LDFile::current()->insertObj (idx, obj); + obj->select(); g_win->R()->compileObject (obj); - + idx++; } - + g_win->refresh(); g_win->scrollToSelection(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (ExportTo, 0) { - if (g_win->sel().size() == 0) +DEFINE_ACTION (ExportTo, 0) +{ if (selection().isEmpty()) return; - + str fname = QFileDialog::getSaveFileName(); + if (fname.length() == 0) return; - + QFile file (fname); - if (!file.open (QIODevice::WriteOnly | QIODevice::Text)) { - critical (fmt ("Unable to open %1 for writing (%2)", fname, strerror (errno))); + + if (!file.open (QIODevice::WriteOnly | QIODevice::Text)) + { critical (fmt ("Unable to open %1 for writing (%2)", fname, strerror (errno))); return; } - - for (LDObject* obj : g_win->sel()) { - str contents = obj->raw(); + + for (LDObject* obj : selection()) + { str contents = obj->raw(); QByteArray data = contents.toUtf8(); file.write (data, data.size()); file.write ("\r\n", 2); @@ -407,128 +404,153 @@ // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (InsertRaw, 0) { - ulong idx = g_win->getInsertionPoint(); - +DEFINE_ACTION (InsertRaw, 0) +{ int idx = g_win->getInsertionPoint(); + QDialog* const dlg = new QDialog; QVBoxLayout* const layout = new QVBoxLayout; QTextEdit* const te_edit = new QTextEdit; QDialogButtonBox* const bbx_buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel); - + layout->addWidget (te_edit); layout->addWidget (bbx_buttons); dlg->setLayout (layout); dlg->setWindowTitle (APPNAME ": Insert Raw"); dlg->connect (bbx_buttons, SIGNAL (accepted()), dlg, SLOT (accept())); dlg->connect (bbx_buttons, SIGNAL (rejected()), dlg, SLOT (reject())); - + if (dlg->exec() == false) return; - - g_win->sel().clear(); - - for (str line : str (te_edit->toPlainText()).split ("\n")) { - LDObject* obj = parseLine (line); - + + LDFile::current()->clearSelection(); + + for (str line : str (te_edit->toPlainText()).split ("\n")) + { LDObject* obj = parseLine (line); + LDFile::current()->insertObj (idx, obj); - g_win->sel() << obj; + obj->select(); g_win->R()->compileObject (obj); idx++; } - + g_win->refresh(); g_win->scrollToSelection(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Screenshot, 0) { - setlocale (LC_ALL, "C"); - - ushort w, h; +DEFINE_ACTION (Screenshot, 0) +{ setlocale (LC_ALL, "C"); + + int w, h; uchar* imgdata = g_win->R()->screencap (w, h); QImage img = imageFromScreencap (imgdata, w, h); - + str root = basename (LDFile::current()->name()); + if (root.right (4) == ".dat") root.chop (4); - + str defaultname = (root.length() > 0) ? fmt ("%1.png", root) : ""; str fname = QFileDialog::getSaveFileName (g_win, "Save Screencap", defaultname, - "PNG images (*.png);;JPG images (*.jpg);;BMP images (*.bmp);;All Files (*.*)"); - + "PNG images (*.png);;JPG images (*.jpg);;BMP images (*.bmp);;All Files (*.*)"); + if (fname.length() > 0 && !img.save (fname)) critical (fmt ("Couldn't open %1 for writing to save screencap: %2", fname, strerror (errno))); - + delete[] imgdata; } // ============================================================================= // ----------------------------------------------------------------------------- extern_cfg (Bool, gl_axes); -DEFINE_ACTION (Axes, 0) { - gl_axes = !gl_axes; +DEFINE_ACTION (Axes, 0) +{ gl_axes = !gl_axes; ACTION (Axes)->setChecked (gl_axes); g_win->R()->update(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Visibility, 0) { - for (LDObject* obj : g_win->sel()) +DEFINE_ACTION (VisibilityToggle, 0) +{ for (LDObject* obj : selection()) obj->setHidden (!obj->hidden()); + + g_win->refresh(); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +DEFINE_ACTION (VisibilityHide, 0) +{ for (LDObject* obj : selection()) + obj->setHidden (true); + + g_win->refresh(); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +DEFINE_ACTION (VisibilityReveal, 0) +{ for (LDObject* obj : selection()) + obj->setHidden (false); g_win->refresh(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Wireframe, 0) { - gl_wireframe = !gl_wireframe; +DEFINE_ACTION (Wireframe, 0) +{ gl_wireframe = !gl_wireframe; g_win->R()->refresh(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (SetOverlay, 0) { - OverlayDialog dlg; - +DEFINE_ACTION (SetOverlay, 0) +{ OverlayDialog dlg; + if (!dlg.exec()) return; - - g_win->R()->setupOverlay ((GL::Camera) dlg.camera(), dlg.fpath(), dlg.ofsx(), - dlg.ofsy(), dlg.lwidth(), dlg.lheight() ); + + g_win->R()->setupOverlay ( (GL::Camera) dlg.camera(), dlg.fpath(), dlg.ofsx(), + dlg.ofsy(), dlg.lwidth(), dlg.lheight()); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (ClearOverlay, 0) { - g_win->R()->clearOverlay(); +DEFINE_ACTION (ClearOverlay, 0) +{ g_win->R()->clearOverlay(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (ModeSelect, CTRL (1)) { - g_win->R()->setEditMode (Select); +DEFINE_ACTION (ModeSelect, CTRL (1)) +{ g_win->R()->setEditMode (Select); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +DEFINE_ACTION (ModeDraw, CTRL (2)) +{ g_win->R()->setEditMode (Draw); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (ModeDraw, CTRL (2)) { - g_win->R()->setEditMode (Draw); +DEFINE_ACTION (ModeCircle, CTRL (3)) +{ g_win->R()->setEditMode (CircleMode); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (SetDrawDepth, 0) { - if (g_win->R()->camera() == GL::Free) +DEFINE_ACTION (SetDrawDepth, 0) +{ if (g_win->R()->camera() == GL::Free) return; - + bool ok; double depth = QInputDialog::getDouble (g_win, "Set Draw Depth", - fmt ("Depth value for %1 Camera:", g_win->R()->cameraName()), - g_win->R()->depthValue(), -10000.0f, 10000.0f, 3, &ok); - + fmt ("Depth value for %1 Camera:", g_win->R()->cameraName()), + g_win->R()->depthValue(), -10000.0f, 10000.0f, 3, &ok); + if (ok) g_win->R()->setDepthValue (depth); } @@ -537,17 +559,17 @@ // This is a test to draw a dummy axle. Meant to be used as a primitive gallery, // but I can't figure how to generate these pictures properly. Multi-threading // these is an immense pain. -DEFINE_ACTION (testpic, "Test picture", "", "", (0)) { - LDFile* file = getFile ("axle.dat"); +DEFINE_ACTION (testpic, "Test picture", "", "", (0)) +{ LDFile* file = getFile ("axle.dat"); setlocale (LC_ALL, "C"); - - if (!file) { - critical ("couldn't load axle.dat"); + + if (!file) + { critical ("couldn't load axle.dat"); return; } - - ushort w, h; - + + int w, h; + GLRenderer* rend = new GLRenderer; rend->resize (64, 64); rend->setAttribute (Qt::WA_DontShowOnScreen); @@ -557,21 +579,22 @@ rend->compileAllObjects(); rend->initGLData(); rend->drawGLScene(); - + uchar* imgdata = rend->screencap (w, h); QImage img = imageFromScreencap (imgdata, w, h); - - if (img.isNull()) { - critical ("Failed to create the image!\n"); - } else { - QLabel* label = new QLabel; + + if (img.isNull()) + { critical ("Failed to create the image!\n"); + } + else + { QLabel* label = new QLabel; QDialog* dlg = new QDialog; label->setPixmap (QPixmap::fromImage (img)); QVBoxLayout* layout = new QVBoxLayout (dlg); layout->addWidget (label); dlg->exec(); } - + delete[] imgdata; rend->deleteLater(); } @@ -579,35 +602,35 @@ // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (ScanPrimitives, 0) { - PrimitiveLister::start(); +DEFINE_ACTION (ScanPrimitives, 0) +{ PrimitiveLister::start(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (BFCView, SHIFT (B)) { - gl_colorbfc = !gl_colorbfc; +DEFINE_ACTION (BFCView, SHIFT (B)) +{ gl_colorbfc = !gl_colorbfc; ACTION (BFCView)->setChecked (gl_colorbfc); g_win->R()->refresh(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (JumpTo, CTRL (G)) { - bool ok; +DEFINE_ACTION (JumpTo, CTRL (G)) +{ bool ok; int defval = 0; LDObject* obj; - - if (g_win->sel().size() == 1) - defval = g_win->sel()[0]->getIndex(); - + + if (selection().size() == 1) + defval = selection()[0]->getIndex(); + int idx = QInputDialog::getInt (null, "Go to line", "Go to line:", defval, 1, LDFile::current()->numObjs(), 1, &ok); - + if (!ok || (obj = LDFile::current()->object (idx - 1)) == null) return; - - g_win->clearSelection(); - g_win->sel() << obj; + + LDFile::current()->clearSelection(); + obj->select(); g_win->updateSelection(); -} \ No newline at end of file +}
--- a/src/gui_editactions.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/gui_editactions.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -40,59 +40,59 @@ // ============================================================================= // ----------------------------------------------------------------------------- -static int copyToClipboard() { - List<LDObject*> objs = g_win->sel(); +static int copyToClipboard() +{ QList<LDObject*> objs = selection(); int num = 0; - + // Clear the clipboard first. qApp->clipboard()->clear(); - + // Now, copy the contents into the clipboard. str data; - - for (LDObject* obj : objs) { - if (data.length() > 0) + + for (LDObject* obj : objs) + { if (data.length() > 0) data += "\n"; - + data += obj->raw(); ++num; } - + qApp->clipboard()->setText (data); return num; } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Cut, CTRL (X)) { - int num = copyToClipboard(); +DEFINE_ACTION (Cut, CTRL (X)) +{ int num = copyToClipboard(); g_win->deleteSelection(); log (ForgeWindow::tr ("%1 objects cut"), num); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Copy, CTRL (C)) { - int num = copyToClipboard(); +DEFINE_ACTION (Copy, CTRL (C)) +{ int num = copyToClipboard(); log (ForgeWindow::tr ("%1 objects copied"), num); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Paste, CTRL (V)) { - const str clipboardText = qApp->clipboard()->text(); - ulong idx = g_win->getInsertionPoint(); - g_win->sel().clear(); +DEFINE_ACTION (Paste, CTRL (V)) +{ const str clipboardText = qApp->clipboard()->text(); + int idx = g_win->getInsertionPoint(); + LDFile::current()->clearSelection(); int num = 0; - - for (str line : clipboardText.split ("\n")) { - LDObject* pasted = parseLine (line); + + for (str line : clipboardText.split ("\n")) + { LDObject* pasted = parseLine (line); LDFile::current()->insertObj (idx++, pasted); - g_win->sel() << pasted; + pasted->select(); g_win->R()->compileObject (pasted); ++num; } - + log (ForgeWindow::tr ("%1 objects pasted"), num); g_win->refresh(); g_win->scrollToSelection(); @@ -100,127 +100,127 @@ // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Delete, KEY (Delete)) { - int num = g_win->deleteSelection(); +DEFINE_ACTION (Delete, KEY (Delete)) +{ int num = g_win->deleteSelection(); log (ForgeWindow::tr ("%1 objects deleted"), num); } // ============================================================================= // ----------------------------------------------------------------------------- -static void doInline (bool deep) { - List<LDObject*> sel = g_win->sel(); - - for (LDObject* obj : sel) { - // Get the index of the subfile so we know where to insert the +static void doInline (bool deep) +{ QList<LDObject*> sel = selection(); + + for (LDObject* obj : sel) + { // Get the index of the subfile so we know where to insert the // inlined contents. long idx = obj->getIndex(); - + if (idx == -1) continue; - - List<LDObject*> objs; - + + QList<LDObject*> objs; + if (obj->getType() == LDObject::Subfile) objs = static_cast<LDSubfile*> (obj)->inlineContents ( - (LDSubfile::InlineFlags) - ((deep) ? LDSubfile::DeepInline : 0) | - LDSubfile::CacheInline - ); + (LDSubfile::InlineFlags) + ( (deep) ? LDSubfile::DeepInline : 0) | + LDSubfile::CacheInline + ); else continue; - + // Merge in the inlined objects - for (LDObject* inlineobj : objs) { - str line = inlineobj->raw(); + for (LDObject * inlineobj : objs) + { str line = inlineobj->raw(); delete inlineobj; - + LDObject* newobj = parseLine (line); LDFile::current()->insertObj (idx++, newobj); - g_win->sel() << newobj; + newobj->select(); g_win->R()->compileObject (newobj); } - + // Delete the subfile now as it's been inlined. LDFile::current()->forgetObject (obj); delete obj; } - + g_win->refresh(); } -DEFINE_ACTION (Inline, CTRL (I)) { - doInline (false); +DEFINE_ACTION (Inline, CTRL (I)) +{ doInline (false); } -DEFINE_ACTION (InlineDeep, CTRL_SHIFT (I)) { - doInline (true); +DEFINE_ACTION (InlineDeep, CTRL_SHIFT (I)) +{ doInline (true); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (SplitQuads, 0) { - List<LDObject*> objs = g_win->sel(); +DEFINE_ACTION (SplitQuads, 0) +{ QList<LDObject*> objs = selection(); int num = 0; - - for (LDObject* obj : objs) { - if (obj->getType() != LDObject::Quad) + + for (LDObject* obj : objs) + { if (obj->getType() != LDObject::Quad) continue; - + // Find the index of this quad long index = obj->getIndex(); - + if (index == -1) return; - - List<LDTriangle*> triangles = static_cast<LDQuad*> (obj)->splitToTriangles(); - + + QList<LDTriangle*> triangles = static_cast<LDQuad*> (obj)->splitToTriangles(); + // Replace the quad with the first triangle and add the second triangle // after the first one. LDFile::current()->setObject (index, triangles[0]); LDFile::current()->insertObj (index + 1, triangles[1]); - - for (LDTriangle * t : triangles) + + for (LDTriangle* t : triangles) g_win->R()->compileObject (t); - + // Delete this quad now, it has been split. delete obj; - + num++; } - + log ("%1 quadrilaterals split", num); g_win->refresh(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (EditRaw, KEY (F9)) { - if (g_win->sel().size() != 1) +DEFINE_ACTION (EditRaw, KEY (F9)) +{ if (selection().size() != 1) return; - - LDObject* obj = g_win->sel() [0]; + + LDObject* obj = selection()[0]; QDialog* dlg = new QDialog; Ui::EditRawUI ui; - + ui.setupUi (dlg); ui.code->setText (obj->raw()); - + if (obj->getType() == LDObject::Error) ui.errorDescription->setText (static_cast<LDError*> (obj)->reason); - else { - ui.errorDescription->hide(); + else + { ui.errorDescription->hide(); ui.errorIcon->hide(); } - + if (!dlg->exec()) return; - + LDObject* oldobj = obj; - + // Reinterpret it from the text of the input field obj = parseLine (ui.code->text()); oldobj->replace (obj); - + // Refresh g_win->R()->compileObject (obj); g_win->refresh(); @@ -228,494 +228,514 @@ // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (SetColor, KEY (C)) { - if (g_win->sel().size() <= 0) +DEFINE_ACTION (SetColor, KEY (C)) +{ if (selection().isEmpty()) return; - + short colnum; short defcol = -1; - - List<LDObject*> objs = g_win->sel(); - + + QList<LDObject*> objs = selection(); + // If all selected objects have the same color, said color is our default // value to the color selection dialog. defcol = g_win->getSelectedColor(); - + // Show the dialog to the user now and ask for a color. - if (ColorSelector::getColor (colnum, defcol, g_win)) { - for (LDObject* obj : objs) { - if (obj->isColored() == false) + if (ColorSelector::getColor (colnum, defcol, g_win)) + { for (LDObject* obj : objs) + { if (obj->isColored() == false) continue; - + obj->setColor (colnum); g_win->R()->compileObject (obj); } - + g_win->refresh(); } } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Borders, CTRL_SHIFT (B)) { - List<LDObject*> objs = g_win->sel(); +DEFINE_ACTION (Borders, CTRL_SHIFT (B)) +{ QList<LDObject*> objs = selection(); int num = 0; - - for (LDObject* obj : objs) { - if (obj->getType() != LDObject::Quad && obj->getType() != LDObject::Triangle) + + for (LDObject* obj : objs) + { const LDObject::Type type = obj->getType(); + if (type != LDObject::Quad && type != LDObject::Triangle) continue; - + short numLines; LDLine* lines[4]; - - if (obj->getType() == LDObject::Quad) { - numLines = 4; - + + if (type == LDObject::Quad) + { numLines = 4; + LDQuad* quad = static_cast<LDQuad*> (obj); lines[0] = new LDLine (quad->getVertex (0), quad->getVertex (1)); lines[1] = new LDLine (quad->getVertex (1), quad->getVertex (2)); lines[2] = new LDLine (quad->getVertex (2), quad->getVertex (3)); lines[3] = new LDLine (quad->getVertex (3), quad->getVertex (0)); - } else { - numLines = 3; - + } + else + { numLines = 3; + LDTriangle* tri = static_cast<LDTriangle*> (obj); lines[0] = new LDLine (tri->getVertex (0), tri->getVertex (1)); lines[1] = new LDLine (tri->getVertex (1), tri->getVertex (2)); lines[2] = new LDLine (tri->getVertex (2), tri->getVertex (0)); } - - for (short i = 0; i < numLines; ++i) { - ulong idx = obj->getIndex() + i + 1; - + + for (short i = 0; i < numLines; ++i) + { long idx = obj->getIndex() + i + 1; + lines[i]->setColor (edgecolor); LDFile::current()->insertObj (idx, lines[i]); g_win->R()->compileObject (lines[i]); } - + num += numLines; } - + log (ForgeWindow::tr ("Added %1 border lines"), num); g_win->refresh(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (CornerVerts, 0) { - int num = 0; - - for (LDObject* obj : g_win->sel()) { - if (obj->vertices() < 2) +DEFINE_ACTION (CornerVerts, 0) +{ int num = 0; + + for (LDObject* obj : selection()) + { if (obj->vertices() < 2) continue; - - ulong idx = obj->getIndex(); - - for (short i = 0; i < obj->vertices(); ++i) { - LDVertex* vert = new LDVertex; + + int idx = obj->getIndex(); + + for (int i = 0; i < obj->vertices(); ++i) + { LDVertex* vert = new LDVertex; vert->pos = obj->getVertex (i); vert->setColor (obj->color()); - + LDFile::current()->insertObj (++idx, vert); g_win->R()->compileObject (vert); ++num; } } - + log (ForgeWindow::tr ("Added %1 vertices"), num); g_win->refresh(); } // ============================================================================= // ----------------------------------------------------------------------------- -static void doMoveSelection (const bool up) { - List<LDObject*> objs = g_win->sel(); +static void doMoveSelection (const bool up) +{ QList<LDObject*> objs = selection(); LDObject::moveObjects (objs, up); g_win->buildObjList(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (MoveUp, KEY (PageUp)) { - doMoveSelection (true); +DEFINE_ACTION (MoveUp, KEY (PageUp)) +{ doMoveSelection (true); } -DEFINE_ACTION (MoveDown, KEY (PageDown)) { - doMoveSelection (false); +DEFINE_ACTION (MoveDown, KEY (PageDown)) +{ doMoveSelection (false); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Undo, CTRL (Z)) { - LDFile::current()->undo(); +DEFINE_ACTION (Undo, CTRL (Z)) +{ LDFile::current()->undo(); } -DEFINE_ACTION (Redo, CTRL_SHIFT (Z)) { - LDFile::current()->redo(); +DEFINE_ACTION (Redo, CTRL_SHIFT (Z)) +{ LDFile::current()->redo(); } // ============================================================================= // ----------------------------------------------------------------------------- -void doMoveObjects (vertex vect) { - // Apply the grid values +void doMoveObjects (vertex vect) +{ // Apply the grid values vect[X] *= currentGrid().confs[Grid::X]->value; vect[Y] *= currentGrid().confs[Grid::Y]->value; vect[Z] *= currentGrid().confs[Grid::Z]->value; - - for (LDObject* obj : g_win->sel()) { - obj->move (vect); + + for (LDObject* obj : selection()) + { obj->move (vect); g_win->R()->compileObject (obj); } - + g_win->refresh(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (MoveXNeg, KEY (Left)) { - doMoveObjects ({-1, 0, 0}); +DEFINE_ACTION (MoveXNeg, KEY (Left)) +{ doMoveObjects ( { -1, 0, 0}); } -DEFINE_ACTION (MoveYNeg, KEY (Home)) { - doMoveObjects ({0, -1, 0}); +DEFINE_ACTION (MoveYNeg, KEY (Home)) +{ doMoveObjects ( {0, -1, 0}); } -DEFINE_ACTION (MoveZNeg, KEY (Down)) { - doMoveObjects ({0, 0, -1}); +DEFINE_ACTION (MoveZNeg, KEY (Down)) +{ doMoveObjects ( {0, 0, -1}); } -DEFINE_ACTION (MoveXPos, KEY (Right)) { - doMoveObjects ({1, 0, 0}); +DEFINE_ACTION (MoveXPos, KEY (Right)) +{ doMoveObjects ( {1, 0, 0}); } -DEFINE_ACTION (MoveYPos, KEY (End)) { - doMoveObjects ({0, 1, 0}); +DEFINE_ACTION (MoveYPos, KEY (End)) +{ doMoveObjects ( {0, 1, 0}); } -DEFINE_ACTION (MoveZPos, KEY (Up)) { - doMoveObjects ({0, 0, 1}); +DEFINE_ACTION (MoveZPos, KEY (Up)) +{ doMoveObjects ( {0, 0, 1}); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Invert, CTRL_SHIFT (W)) { - List<LDObject*> sel = g_win->sel(); - - for (LDObject* obj : sel) { - obj->invert(); +DEFINE_ACTION (Invert, CTRL_SHIFT (W)) +{ QList<LDObject*> sel = selection(); + + for (LDObject* obj : sel) + { obj->invert(); g_win->R()->compileObject (obj); } - + g_win->refresh(); } // ============================================================================= // ----------------------------------------------------------------------------- -static void rotateVertex (vertex& v, const vertex& rotpoint, const matrix& transform) { - v.move (-rotpoint); +static void rotateVertex (vertex& v, const vertex& rotpoint, const matrix& transform) +{ v.move (-rotpoint); v.transform (transform, g_origin); v.move (rotpoint); } // ============================================================================= // ----------------------------------------------------------------------------- -static void doRotate (const short l, const short m, const short n) { - List<LDObject*> sel = g_win->sel(); - List<vertex*> queue; +static void doRotate (const short l, const short m, const short n) +{ QList<LDObject*> sel = selection(); + QList<vertex*> queue; const vertex rotpoint = rotPoint (sel); const double angle = (pi * currentGrid().confs[Grid::Angle]->value) / 180, - cosangle = cos (angle), - sinangle = sin (angle); - + cosangle = cos (angle), + sinangle = sin (angle); + // ref: http://en.wikipedia.org/wiki/Transformation_matrix#Rotation_2 - matrix transform ({ - (l * l * (1 - cosangle)) + cosangle, - (m * l * (1 - cosangle)) - (n * sinangle), - (n * l * (1 - cosangle)) + (m * sinangle), - - (l * m * (1 - cosangle)) + (n * sinangle), - (m * m * (1 - cosangle)) + cosangle, - (n * m * (1 - cosangle)) - (l * sinangle), - - (l * n * (1 - cosangle)) - (m * sinangle), - (m * n * (1 - cosangle)) + (l * sinangle), - (n * n * (1 - cosangle)) + cosangle + matrix transform ( + { (l* l * (1 - cosangle)) + cosangle, + (m* l * (1 - cosangle)) - (n* sinangle), + (n* l * (1 - cosangle)) + (m* sinangle), + + (l* m * (1 - cosangle)) + (n* sinangle), + (m* m * (1 - cosangle)) + cosangle, + (n* m * (1 - cosangle)) - (l* sinangle), + + (l* n * (1 - cosangle)) - (m* sinangle), + (m* n * (1 - cosangle)) + (l* sinangle), + (n* n * (1 - cosangle)) + cosangle }); - + // Apply the above matrix to everything - for (LDObject* obj : sel) { - if (obj->vertices()) { - for (short i = 0; i < obj->vertices(); ++i) { - vertex v = obj->getVertex (i); + for (LDObject* obj : sel) + { if (obj->vertices()) + { for (short i = 0; i < obj->vertices(); ++i) + { vertex v = obj->getVertex (i); rotateVertex (v, rotpoint, transform); obj->setVertex (i, v); } - } elif (obj->hasMatrix()) { - LDMatrixObject* mo = dynamic_cast<LDMatrixObject*> (obj); - + } elif (obj->hasMatrix()) + + { LDMatrixObject* mo = dynamic_cast<LDMatrixObject*> (obj); + // Transform the position vertex v = mo->position(); rotateVertex (v, rotpoint, transform); mo->setPosition (v); - + // Transform the matrix mo->setTransform (mo->transform() * transform); - } elif (obj->getType() == LDObject::Vertex) { - LDVertex* vert = static_cast<LDVertex*> (obj); + } elif (obj->getType() == LDObject::Vertex) + { LDVertex* vert = static_cast<LDVertex*> (obj); vertex v = vert->pos; rotateVertex (v, rotpoint, transform); vert->pos = v; } - + g_win->R()->compileObject (obj); } - + g_win->refresh(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (RotateXPos, CTRL (Right)) { doRotate (1, 0, 0); } -DEFINE_ACTION (RotateYPos, CTRL (End)) { doRotate (0, 1, 0); } -DEFINE_ACTION (RotateZPos, CTRL (Up)) { doRotate (0, 0, 1); } -DEFINE_ACTION (RotateXNeg, CTRL (Left)) { doRotate (-1, 0, 0); } -DEFINE_ACTION (RotateYNeg, CTRL (Home)) { doRotate (0, -1, 0); } -DEFINE_ACTION (RotateZNeg, CTRL (Down)) { doRotate (0, 0, -1); } +DEFINE_ACTION (RotateXPos, CTRL (Right)) +{ doRotate (1, 0, 0); +} +DEFINE_ACTION (RotateYPos, CTRL (End)) +{ doRotate (0, 1, 0); +} +DEFINE_ACTION (RotateZPos, CTRL (Up)) +{ doRotate (0, 0, 1); +} +DEFINE_ACTION (RotateXNeg, CTRL (Left)) +{ doRotate (-1, 0, 0); +} +DEFINE_ACTION (RotateYNeg, CTRL (Home)) +{ doRotate (0, -1, 0); +} +DEFINE_ACTION (RotateZNeg, CTRL (Down)) +{ doRotate (0, 0, -1); +} -DEFINE_ACTION (RotationPoint, (0)) { - configRotationPoint(); +DEFINE_ACTION (RotationPoint, (0)) +{ configRotationPoint(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (RoundCoordinates, 0) { - setlocale (LC_ALL, "C"); +DEFINE_ACTION (RoundCoordinates, 0) +{ setlocale (LC_ALL, "C"); int num = 0; - - for (LDObject* obj : g_win->sel()) - for (short i = 0; i < obj->vertices(); ++i) { - vertex v = obj->getVertex (i); - - for (const Axis ax : g_Axes) { - // HACK: .. should find a better way to do this - char valstr[64]; - sprintf (valstr, "%.3f", v[ax]); - v[ax] = atof (valstr); + + for (LDObject* obj : selection()) + { for (short i = 0; i < obj->vertices(); ++i) + { vertex v = obj->getVertex (i); + + for (const Axis ax : g_Axes) + { // HACK: .. should find a better way to do this + str valstr; + valstr.sprintf ("%.3f", v[ax]); + v[ax] = valstr.toDouble(); + } + + obj->setVertex (i, v); + g_win->R()->compileObject (obj); + num += 3; } - - obj->setVertex (i, v); - g_win->R()->compileObject (obj); - num += 3; } - + log (ForgeWindow::tr ("Rounded %1 coordinates"), num); g_win->refresh(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Uncolorize, 0) { - int num = 0; - - for (LDObject* obj : g_win->sel()) { - if (obj->isColored() == false) +DEFINE_ACTION (Uncolorize, 0) +{ int num = 0; + + for (LDObject* obj : selection()) + { if (obj->isColored() == false) continue; - + int col = maincolor; - + if (obj->getType() == LDObject::Line || obj->getType() == LDObject::CndLine) col = edgecolor; - + obj->setColor (col); g_win->R()->compileObject (obj); num++; } - + log (ForgeWindow::tr ("%1 objects uncolored"), num); g_win->refresh(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (ReplaceCoords, CTRL (R)) { - QDialog* dlg = new QDialog (g_win); +DEFINE_ACTION (ReplaceCoords, CTRL (R)) +{ QDialog* dlg = new QDialog (g_win); Ui::ReplaceCoordsUI ui; ui.setupUi (dlg); - + if (!dlg->exec()) return; - + const double search = ui.search->value(), replacement = ui.replacement->value(); const bool any = ui.any->isChecked(), rel = ui.relative->isChecked(); - - List<Axis> sel; + + QList<Axis> sel; int num = 0; - + if (ui.x->isChecked()) sel << X; if (ui.y->isChecked()) sel << Y; if (ui.z->isChecked()) sel << Z; - for (LDObject* obj : g_win->sel()) - for (short i = 0; i < obj->vertices(); ++i) { - vertex v = obj->getVertex (i); - - for (Axis ax : sel) { - double& coord = v[ax]; - - if (any || coord == search) { - if (!rel) - coord = 0; - - coord += replacement; - num++; + for (LDObject* obj : selection()) + { for (short i = 0; i < obj->vertices(); ++i) + { vertex v = obj->getVertex (i); + + for (Axis ax : sel) + { double& coord = v[ax]; + + if (any || coord == search) + { if (!rel) + coord = 0; + + coord += replacement; + num++; + } } + + obj->setVertex (i, v); + g_win->R()->compileObject (obj); } - - obj->setVertex (i, v); - g_win->R()->compileObject (obj); } - + log (ForgeWindow::tr ("Altered %1 values"), num); g_win->refresh(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Flip, CTRL_SHIFT (F)) { - QDialog* dlg = new QDialog; +DEFINE_ACTION (Flip, CTRL_SHIFT (F)) +{ QDialog* dlg = new QDialog; Ui::FlipUI ui; ui.setupUi (dlg); - + if (!dlg->exec()) return; - - List<Axis> sel; + + QList<Axis> sel; + if (ui.x->isChecked()) sel << X; if (ui.y->isChecked()) sel << Y; if (ui.z->isChecked()) sel << Z; - - for (LDObject* obj : g_win->sel()) - for (short i = 0; i < obj->vertices(); ++i) { - vertex v = obj->getVertex (i); - - for (Axis ax : sel) - v[ax] *= -1; + + for (LDObject* obj : selection()) + { for (short i = 0; i < obj->vertices(); ++i) + { vertex v = obj->getVertex (i); - obj->setVertex (i, v); - g_win->R()->compileObject (obj); + for (Axis ax : sel) + v[ax] *= -1; + + obj->setVertex (i, v); + g_win->R()->compileObject (obj); + } } - + g_win->refresh(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Demote, 0) { - List<LDObject*> sel = g_win->sel(); +DEFINE_ACTION (Demote, 0) +{ QList<LDObject*> sel = selection(); int num = 0; - - for (LDObject* obj : sel) { - if (obj->getType() != LDObject::CndLine) + + for (LDObject* obj : sel) + { if (obj->getType() != LDObject::CndLine) continue; - + LDLine* repl = static_cast<LDCndLine*> (obj)->demote(); g_win->R()->compileObject (repl); ++num; } - + log (ForgeWindow::tr ("Demoted %1 conditional lines"), num); g_win->refresh(); } // ============================================================================= // ----------------------------------------------------------------------------- -static bool isColorUsed (short colnum) { - for (LDObject* obj : LDFile::current()->objects()) +static bool isColorUsed (short colnum) +{ for (LDObject* obj : LDFile::current()->objects()) if (obj->isColored() && obj->color() == colnum) return true; - + return false; } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (Autocolor, 0) { - short colnum = 0; - +DEFINE_ACTION (Autocolor, 0) +{ short colnum = 0; + while (colnum < MAX_COLORS && (getColor (colnum) == null || isColorUsed (colnum))) colnum++; - - if (colnum >= MAX_COLORS) { - log (ForgeWindow::tr ("Cannot auto-color: all colors are in use!")); + + if (colnum >= MAX_COLORS) + { log (ForgeWindow::tr ("Cannot auto-color: all colors are in use!")); return; } - - for (LDObject* obj : g_win->sel()) { - if (obj->isColored() == false) + + for (LDObject* obj : selection()) + { if (obj->isColored() == false) continue; - + obj->setColor (colnum); g_win->R()->compileObject (obj); } - + log (ForgeWindow::tr ("Auto-colored: new color is [%1] %2"), colnum, getColor (colnum)->name); g_win->refresh(); } // ============================================================================= // ----------------------------------------------------------------------------- -DEFINE_ACTION (AddHistoryLine, 0) { - LDObject* obj; +DEFINE_ACTION (AddHistoryLine, 0) +{ LDObject* obj; bool ishistory = false, - prevIsHistory = false; - + prevIsHistory = false; + QDialog* dlg = new QDialog; Ui_AddHistoryLine* ui = new Ui_AddHistoryLine; ui->setupUi (dlg); ui->m_username->setText (ld_defaultuser); ui->m_date->setDate (QDate::currentDate()); ui->m_comment->setFocus(); - + if (!dlg->exec()) return; - + // Create the comment object based on input str commentText = fmt ("!HISTORY %1 [%2] %3", - ui->m_date->date().toString("yyyy-MM-dd"), - ui->m_username->text(), - ui->m_comment->text()); - + ui->m_date->date().toString ("yyyy-MM-dd"), + ui->m_username->text(), + ui->m_comment->text()); + LDComment* comm = new LDComment (commentText); - + // Find a spot to place the new comment for ( obj = LDFile::current()->object (0); obj && obj->next() && !obj->next()->isScemantic(); obj = obj->next() - ) { - LDComment* comm = dynamic_cast<LDComment*> (obj); + ) + { LDComment* comm = dynamic_cast<LDComment*> (obj); + if (comm && comm->text.startsWith ("!HISTORY ")) ishistory = true; - - if (prevIsHistory && !ishistory) { - // Last line was history, this isn't, thus insert the new history + + if (prevIsHistory && !ishistory) + { // Last line was history, this isn't, thus insert the new history // line here. break; } - + prevIsHistory = ishistory; } - + int idx = obj ? obj->getIndex() : 0; LDFile::current()->insertObj (idx++, comm); - + // If we're adding a history line right before a scemantic object, pad it // an empty line if (obj && obj->next() && obj->next()->isScemantic()) LDFile::current()->insertObj (idx, new LDEmpty); - + g_win->buildObjList(); delete ui; -} \ No newline at end of file +}
--- a/src/history.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/history.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -33,90 +33,90 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void History::undo() { - if (m_changesets.size() == 0 || pos() == -1) +void History::undo() +{ if (m_changesets.isEmpty() || pos() == -1) return; - - const list& set = changeset (pos()); + + const Changeset& set = changeset (pos()); g_fullRefresh = false; - + // Iterate the list in reverse and undo all actions - for (const AbstractHistoryEntry * change : c_rev<AbstractHistoryEntry*> (set)) - change->undo(); - + for (auto it = set.end() - 1; it != set.begin(); --it) + (*it)->undo(); + setPos (pos() - 1); - + if (!g_fullRefresh) g_win->refresh(); else g_win->fullRefresh(); - + updateActions(); } // ============================================================================= // ----------------------------------------------------------------------------- -void History::redo() { - if (pos() == (long) m_changesets.size()) +void History::redo() +{ if (pos() == (long) m_changesets.size()) return; - - const list& set = changeset (pos() + 1); + + const Changeset& set = changeset (pos() + 1); g_fullRefresh = false; - + // Redo things - in the order as they were done in the first place - for (const AbstractHistoryEntry * change : set) + for (const AbstractHistoryEntry* change : set) change->redo(); - + setPos (pos() + 1); - + if (!g_fullRefresh) g_win->refresh(); else g_win->fullRefresh(); - + updateActions(); } // ============================================================================= // ----------------------------------------------------------------------------- -void History::clear() { - for (List<AbstractHistoryEntry*> set : m_changesets) - for (AbstractHistoryEntry * change : set) +void History::clear() +{ for (Changeset set : m_changesets) + for (auto change : set) delete change; - + m_changesets.clear(); } // ============================================================================= // ----------------------------------------------------------------------------- -void History::updateActions() const { - ACTION (Undo)->setEnabled (pos() != -1); +void History::updateActions() const +{ ACTION (Undo)->setEnabled (pos() != -1); ACTION (Redo)->setEnabled (pos() < (long) m_changesets.size() - 1); } // ============================================================================= // ----------------------------------------------------------------------------- -void History::open() { - if (opened()) +void History::open() +{ if (opened()) return; - + setOpened (true); } // ============================================================================= // ----------------------------------------------------------------------------- -void History::close() { - if (!opened()) +void History::close() +{ if (!opened()) return; - + setOpened (false); - - if (m_currentArchive.size() == 0) + + if (m_currentArchive.isEmpty()) return; - + while (pos() < size() - 1) - m_changesets.erase (size() - 1); - + m_changesets.removeLast(); + m_changesets << m_currentArchive; m_currentArchive.clear(); setPos (pos() + 1); @@ -125,31 +125,31 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void History::add (AbstractHistoryEntry* entry) { - if (!opened()) { - delete entry; +void History::add (AbstractHistoryEntry* entry) +{ if (!opened()) + { delete entry; return; } - + entry->setParent (this); m_currentArchive << entry; } // ============================================================================= // ----------------------------------------------------------------------------- -void AddHistory::undo() const { - LDFile* f = parent()->file(); +void AddHistory::undo() const +{ LDFile* f = parent()->file(); LDObject* obj = f->object (index()); f->forgetObject (obj); delete obj; - + g_fullRefresh = true; } // ============================================================================= // ----------------------------------------------------------------------------- -void AddHistory::redo() const { - LDFile* f = parent()->file(); +void AddHistory::redo() const +{ LDFile* f = parent()->file(); LDObject* obj = parseLine (code()); f->insertObj (index(), obj); g_win->R()->compileObject (obj); @@ -160,8 +160,8 @@ // ============================================================================= // heh // ----------------------------------------------------------------------------- -void DelHistory::undo() const { - LDFile* f = parent()->file(); +void DelHistory::undo() const +{ LDFile* f = parent()->file(); LDObject* obj = parseLine (code()); f->insertObj (index(), obj); g_win->R()->compileObject (obj); @@ -169,12 +169,12 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void DelHistory::redo() const { - LDFile* f = parent()->file(); +void DelHistory::redo() const +{ LDFile* f = parent()->file(); LDObject* obj = f->object (index()); f->forgetObject (obj); delete obj; - + g_fullRefresh = true; } @@ -182,8 +182,8 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void EditHistory::undo() const { - LDObject* obj = LDFile::current()->object (index()); +void EditHistory::undo() const +{ LDObject* obj = LDFile::current()->object (index()); LDObject* newobj = parseLine (oldCode()); obj->replace (newobj); g_win->R()->compileObject (newobj); @@ -191,8 +191,8 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void EditHistory::redo() const { - LDObject* obj = LDFile::current()->object (index()); +void EditHistory::redo() const +{ LDObject* obj = LDFile::current()->object (index()); LDObject* newobj = parseLine (newCode()); obj->replace (newobj); g_win->R()->compileObject (newobj); @@ -202,12 +202,12 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void SwapHistory::undo() const { - LDObject::fromID (a)->swap (LDObject::fromID (b)); +void SwapHistory::undo() const +{ LDObject::fromID (a)->swap (LDObject::fromID (b)); } -void SwapHistory::redo() const { - undo(); // :v +void SwapHistory::redo() const +{ undo(); // :v } -SwapHistory::~SwapHistory() {} \ No newline at end of file +SwapHistory::~SwapHistory() {}
--- a/src/history.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/history.h Wed Oct 23 12:46:10 2013 +0300 @@ -31,146 +31,151 @@ class AbstractHistoryEntry; // ============================================================================= -class History { - PROPERTY (long, pos, setPos) +class History +{ PROPERTY (long, pos, setPos) PROPERTY (LDFile*, file, setFile) READ_PROPERTY (bool, opened, setOpened) - -public: - typedef List<AbstractHistoryEntry*> list; - - enum Type { - Del, - Edit, - Add, - Move, - Swap, - }; - - History(); - void undo(); - void redo(); - void clear(); - void updateActions() const; - - void open(); - void close(); - void add (AbstractHistoryEntry* entry); - long size() const { return m_changesets.size(); } - - History& operator<< (AbstractHistoryEntry* entry) { - add (entry); - return *this; - } - - const list& changeset (long pos) const { - return m_changesets[pos]; - } - -private: - list m_currentArchive; - List<list> m_changesets; + + public: + typedef QList<AbstractHistoryEntry*> Changeset; + + enum Type + { Del, + Edit, + Add, + Move, + Swap, + }; + + History(); + void undo(); + void redo(); + void clear(); + void updateActions() const; + + void open(); + void close(); + void add (AbstractHistoryEntry* entry); + + inline long size() const + { return m_changesets.size(); + } + + inline History& operator<< (AbstractHistoryEntry* entry) + { add (entry); + return *this; + } + + inline const Changeset& changeset (long pos) const + { return m_changesets[pos]; + } + + private: + Changeset m_currentArchive; + QList<Changeset> m_changesets; }; // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= -class AbstractHistoryEntry { - PROPERTY (History*, parent, setParent) - -public: - virtual void undo() const {} - virtual void redo() const {} - virtual ~AbstractHistoryEntry() {} - virtual History::Type getType() const { return (History::Type) 0; } +class AbstractHistoryEntry +{ PROPERTY (History*, parent, setParent) + + public: + virtual void undo() const {} + virtual void redo() const {} + virtual ~AbstractHistoryEntry() {} + virtual History::Type getType() const + { return (History::Type) 0; + } }; // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= -class DelHistory : public AbstractHistoryEntry { -public: - enum Type { - Cut, // was deleted with a cut operation - Other, // was deleted witout specific reason - }; - - PROPERTY (ulong, index, setIndex) - PROPERTY (str, code, setCode) - PROPERTY (DelHistory::Type, type, setType) - -public: - IMPLEMENT_HISTORY_TYPE (Del) - - DelHistory (ulong idx, LDObject* obj, Type type = Other) : - m_index (idx), - m_code (obj->raw()), - m_type (type) {} +class DelHistory : public AbstractHistoryEntry +{ public: + enum Type + { Cut, // was deleted with a cut operation + Other, // was deleted witout specific reason + }; + + PROPERTY (int, index, setIndex) + PROPERTY (str, code, setCode) + PROPERTY (DelHistory::Type, type, setType) + + public: + IMPLEMENT_HISTORY_TYPE (Del) + + DelHistory (int idx, LDObject* obj, Type type = Other) : + m_index (idx), + m_code (obj->raw()), + m_type (type) {} }; // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= -class EditHistory : public AbstractHistoryEntry { - PROPERTY (ulong, index, setIndex) +class EditHistory : public AbstractHistoryEntry +{ PROPERTY (int, index, setIndex) PROPERTY (str, oldCode, setOldCode) PROPERTY (str, newCode, setNewCode) - -public: - IMPLEMENT_HISTORY_TYPE (Edit) - - EditHistory (ulong idx, str oldCode, str newCode) : - m_index (idx), - m_oldCode (oldCode), - m_newCode (newCode) {} + + public: + IMPLEMENT_HISTORY_TYPE (Edit) + + EditHistory (int idx, str oldCode, str newCode) : + m_index (idx), + m_oldCode (oldCode), + m_newCode (newCode) {} }; // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= -class AddHistory : public AbstractHistoryEntry { -public: - enum Type { - Other, // was "just added" - Paste, // was added through a paste operation - }; - - PROPERTY (ulong, index, setIndex) - PROPERTY (str, code, setCode) - PROPERTY (AddHistory::Type, type, setType) - -public: - IMPLEMENT_HISTORY_TYPE (Add) - - AddHistory (ulong idx, LDObject* obj, Type type = Other) : - m_index (idx), - m_code (obj->raw()), - m_type (type) {} +class AddHistory : public AbstractHistoryEntry +{ public: + enum Type + { Other, // was "just added" + Paste, // was added through a paste operation + }; + + PROPERTY (int, index, setIndex) + PROPERTY (str, code, setCode) + PROPERTY (AddHistory::Type, type, setType) + + public: + IMPLEMENT_HISTORY_TYPE (Add) + + AddHistory (int idx, LDObject* obj, Type type = Other) : + m_index (idx), + m_code (obj->raw()), + m_type (type) {} }; // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= -class MoveHistory : public AbstractHistoryEntry { -public: - IMPLEMENT_HISTORY_TYPE (Move) - - List<ulong> indices; - vertex dest; - - MoveHistory (List<ulong> indices, vertex dest) : - indices (indices), - dest (dest) {} +class MoveHistory : public AbstractHistoryEntry +{ public: + IMPLEMENT_HISTORY_TYPE (Move) + + QList<int> indices; + vertex dest; + + MoveHistory (QList<int> indices, vertex dest) : + indices (indices), + dest (dest) {} }; -class SwapHistory : public AbstractHistoryEntry { -public: - IMPLEMENT_HISTORY_TYPE (Swap) - ulong a, b; - - SwapHistory (ulong a, ulong b) : - a (a), - b (b) {} +class SwapHistory : public AbstractHistoryEntry +{ public: + IMPLEMENT_HISTORY_TYPE (Swap) + int a, b; + + SwapHistory (int a, int b) : + a (a), + b (b) {} }; -#endif // HISTORY_H \ No newline at end of file +#endif // HISTORY_H
--- a/src/ldconfig.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/ldconfig.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -25,78 +25,78 @@ // ============================================================================= // Helper function for parseLDConfig // ----------------------------------------------------------------------------- -static bool parseLDConfigTag (LDConfigParser& pars, char const* tag, str& val) { - short pos; - +static bool parseLDConfigTag (LDConfigParser& pars, char const* tag, str& val) +{ short pos; + // Try find the token and get its position if (!pars.findToken (pos, tag, 1)) return false; - + // Get the token after it and store it into val return pars.getToken (val, pos + 1); } // ============================================================================= // ----------------------------------------------------------------------------- -void parseLDConfig() { - File* f = openLDrawFile ("LDConfig.ldr", false); - - if (!f) { - critical (fmt (QObject::tr ("Unable to open LDConfig.ldr for parsing! (%1)"), +void parseLDConfig() +{ File* f = openLDrawFile ("LDConfig.ldr", false); + + if (!f) + { critical (fmt (QObject::tr ("Unable to open LDConfig.ldr for parsing! (%1)"), strerror (errno))); return; } - + // Read in the lines - for (str line : *f) { - if (line.length() == 0 || line[0] != '0') + for (str line : *f) + { if (line.length() == 0 || line[0] != '0') continue; // empty or illogical - + line.remove ('\r'); line.remove ('\n'); - + // Parse the line LDConfigParser pars (line, ' '); - + short code = 0, alpha = 255; str name, facename, edgename, valuestr; - + // Check 0 !COLOUR, parse the name if (!pars.tokenCompare (0, "0") || !pars.tokenCompare (1, "!COLOUR") || !pars.getToken (name, 2)) continue; - + // Replace underscores in the name with spaces for readability name.replace ("_", " "); - + // Get the CODE tag if (!parseLDConfigTag (pars, "CODE", valuestr)) continue; - - if (!isNumber (valuestr)) + + if (!numeric (valuestr)) continue; // not a number - + // Ensure that the code is within [0 - 511] bool ok; code = valuestr.toShort (&ok); - + if (!ok || code < 0 || code >= 512) continue; - + // VALUE and EDGE tags if (!parseLDConfigTag (pars, "VALUE", facename) || !parseLDConfigTag (pars, "EDGE", edgename)) continue; - + // Ensure that our colors are correct QColor faceColor (facename), edgeColor (edgename); - + if (!faceColor.isValid() || !edgeColor.isValid()) continue; - + // Parse alpha if given. if (parseLDConfigTag (pars, "ALPHA", valuestr)) alpha = clamp<short> (valuestr.toShort(), 0, 255); - + LDColor* col = new LDColor; col->name = name; col->faceColor = faceColor; @@ -106,88 +106,89 @@ col->index = code; setColor (code, col); } - + delete f; } // ============================================================================= // ----------------------------------------------------------------------------- -LDConfigParser::LDConfigParser (str inText, char sep) { - m_tokens = container_cast<QStringList, List<str>> (inText.split (sep, QString::SkipEmptyParts)); +LDConfigParser::LDConfigParser (str inText, char sep) +{ m_tokens = inText.split (sep, QString::SkipEmptyParts); m_pos = -1; } // ============================================================================= // ----------------------------------------------------------------------------- -bool LDConfigParser::atBeginning() { - return (m_pos == -1); +bool LDConfigParser::atBeginning() +{ return (m_pos == -1); } // ============================================================================= // ----------------------------------------------------------------------------- -bool LDConfigParser::atEnd() { - return (m_pos == (signed) m_tokens.size() - 1); +bool LDConfigParser::atEnd() +{ return (m_pos == m_tokens.size() - 1); } // ============================================================================= // ----------------------------------------------------------------------------- -bool LDConfigParser::getToken (str& val, const ushort pos) { - if (pos >= m_tokens.size()) +bool LDConfigParser::getToken (str& val, const int pos) +{ if (pos >= m_tokens.size()) return false; - + val = m_tokens[pos]; return true; } // ============================================================================= // ----------------------------------------------------------------------------- -bool LDConfigParser::next (str& val) { - return getToken (val, ++m_pos); +bool LDConfigParser::next (str& val) +{ return getToken (val, ++m_pos); } // ============================================================================= // ----------------------------------------------------------------------------- -bool LDConfigParser::peekNext (str& val) { - return getToken (val, m_pos + 1); +bool LDConfigParser::peekNext (str& val) +{ return getToken (val, m_pos + 1); } // ============================================================================= // ----------------------------------------------------------------------------- -bool LDConfigParser::findToken (short& result, char const* needle, short args) { - for (ushort i = 0; i < (m_tokens.size() - args); ++i) { - if (m_tokens[i] == needle) { - result = i; +bool LDConfigParser::findToken (short& result, char const* needle, short args) +{ for (int i = 0; i < (m_tokens.size() - args); ++i) + { if (m_tokens[i] == needle) + { result = i; return true; } } - + return false; } // ============================================================================= // ----------------------------------------------------------------------------- -void LDConfigParser::rewind() { - m_pos = -1; +void LDConfigParser::rewind() +{ m_pos = -1; } // ============================================================================= // ----------------------------------------------------------------------------- -void LDConfigParser::seek (short amount, bool rel) { - m_pos = (rel ? m_pos : 0) + amount; +void LDConfigParser::seek (short amount, bool rel) +{ m_pos = (rel ? m_pos : 0) + amount; } // ============================================================================= // ----------------------------------------------------------------------------- -size_t LDConfigParser::size() { - return m_tokens.size(); +size_t LDConfigParser::size() +{ return m_tokens.size(); } // ============================================================================= // ----------------------------------------------------------------------------- -bool LDConfigParser::tokenCompare (short inPos, const char* sOther) { - str tok; +bool LDConfigParser::tokenCompare (short inPos, const char* sOther) +{ str tok; + if (!getToken (tok, inPos)) return false; - + return (tok == sOther); -} \ No newline at end of file +}
--- a/src/ldconfig.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/ldconfig.h Wed Oct 23 12:46:10 2013 +0300 @@ -20,36 +20,37 @@ #define LDCONFIG_H #include "types.h" +#include <QStringList> // ============================================================================= // StringParser // // String parsing utility // ============================================================================= -class LDConfigParser { -public: - LDConfigParser (str inText, char sep); - - bool atEnd(); - bool atBeginning(); - bool next (str& val); - bool peekNext (str& val); - bool getToken (str& val, const ushort pos); - bool findToken (short& result, char const* needle, short args); - size_t size(); - void rewind(); - void seek (short amount, bool rel); - bool tokenCompare (short inPos, const char* sOther); - - str operator[] (const size_t idx) { - return m_tokens[idx]; - } - -private: - List<str> m_tokens; - short m_pos; +class LDConfigParser +{ public: + LDConfigParser (str inText, char sep); + + bool atEnd(); + bool atBeginning(); + bool next (str& val); + bool peekNext (str& val); + bool getToken (str& val, const int pos); + bool findToken (short& result, char const* needle, short args); + size_t size(); + void rewind(); + void seek (short amount, bool rel); + bool tokenCompare (short inPos, const char* sOther); + + str operator[] (const size_t idx) + { return m_tokens[idx]; + } + + private: + QStringList m_tokens; + int m_pos; }; void parseLDConfig(); -#endif // LDCONFIG_H \ No newline at end of file +#endif // LDCONFIG_H
--- a/src/ldtypes.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/ldtypes.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -31,7 +31,7 @@ cfg (Int, ld_defaultlicense, 0); // List of all LDObjects -List<LDObject*> g_LDObjects; +QList<LDObject*> g_LDObjects; // ============================================================================= // LDObject constructors @@ -44,13 +44,15 @@ qObjListEntry (null), m_glinit (false) { + memset (m_coords, 0, sizeof m_coords); + // Determine ID int32 id = 1; // 0 is invalid - + for (LDObject* obj : g_LDObjects) if (obj->id() >= id) id = obj->id() + 1; - + setID (id); g_LDObjects << this; } @@ -60,34 +62,34 @@ // actually called, for a subclass-less LDObject should never come into existance. // These exist only to satisfy the linker. // ----------------------------------------------------------------------------- -LDObject::Type LDObject::getType() const { - return LDObject::Unidentified; +LDObject::Type LDObject::getType() const +{ return LDObject::Unidentified; } -bool LDObject::hasMatrix() const { - return false; +bool LDObject::hasMatrix() const +{ return false; } -bool LDObject::isColored() const { - return false; +bool LDObject::isColored() const +{ return false; } -bool LDObject::isScemantic() const { - return false; +bool LDObject::isScemantic() const +{ return false; } -str LDObject::typeName() const { - return ""; +str LDObject::typeName() const +{ return ""; } -short LDObject::vertices() const { - return 0; +short LDObject::vertices() const +{ return 0; } // ============================================================================= // ----------------------------------------------------------------------------- -void LDObject::setVertexCoord (int i, Axis ax, double value) { - vertex v = getVertex (i); +void LDObject::setVertexCoord (int i, Axis ax, double value) +{ vertex v = getVertex (i); v[ax] = value; setVertex (i, v); } @@ -96,14 +98,14 @@ // ============================================================================= // ----------------------------------------------------------------------------- -str LDComment::raw() { - return fmt ("0 %1", text); +str LDComment::raw() +{ return fmt ("0 %1", text); } // ============================================================================= // ----------------------------------------------------------------------------- -str LDSubfile::raw() { - str val = fmt ("1 %1 %2 ", color(), position()); +str LDSubfile::raw() +{ str val = fmt ("1 %1 %2 ", color(), position()); val += transform().stringRep(); val += ' '; val += fileInfo()->name(); @@ -112,71 +114,71 @@ // ============================================================================= // ----------------------------------------------------------------------------- -str LDLine::raw() { - str val = fmt ("2 %1", color()); - - for (ushort i = 0; i < 2; ++i) +str LDLine::raw() +{ str val = fmt ("2 %1", color()); + + for (int i = 0; i < 2; ++i) val += fmt (" %1", getVertex (i)); - + return val; } // ============================================================================= // ----------------------------------------------------------------------------- -str LDTriangle::raw() { - str val = fmt ("3 %1", color()); - - for (ushort i = 0; i < 3; ++i) +str LDTriangle::raw() +{ str val = fmt ("3 %1", color()); + + for (int i = 0; i < 3; ++i) val += fmt (" %1", getVertex (i)); - + return val; } // ============================================================================= // ----------------------------------------------------------------------------- -str LDQuad::raw() { - str val = fmt ("4 %1", color()); - - for (ushort i = 0; i < 4; ++i) +str LDQuad::raw() +{ str val = fmt ("4 %1", color()); + + for (int i = 0; i < 4; ++i) val += fmt (" %1", getVertex (i)); - + return val; } // ============================================================================= // ----------------------------------------------------------------------------- -str LDCndLine::raw() { - str val = fmt ("5 %1", color()); - +str LDCndLine::raw() +{ str val = fmt ("5 %1", color()); + // Add the coordinates - for (ushort i = 0; i < 4; ++i) + for (int i = 0; i < 4; ++i) val += fmt (" %1", getVertex (i)); - + return val; } // ============================================================================= // ----------------------------------------------------------------------------- -str LDError::raw() { - return contents; +str LDError::raw() +{ return contents; } // ============================================================================= // ----------------------------------------------------------------------------- -str LDVertex::raw() { - return fmt ("0 !LDFORGE VERTEX %1 %2", color(), pos); +str LDVertex::raw() +{ return fmt ("0 !LDFORGE VERTEX %1 %2", color(), pos); } // ============================================================================= // ----------------------------------------------------------------------------- -str LDEmpty::raw() { - return ""; +str LDEmpty::raw() +{ return ""; } // ============================================================================= // ----------------------------------------------------------------------------- -const char* LDBFC::statements[] = { - "CERTIFY CCW", +const char* LDBFC::statements[] = +{ "CERTIFY CCW", "CCW", "CERTIFY CW", "CW", @@ -188,14 +190,14 @@ "NOCLIP", }; -str LDBFC::raw() { - return fmt ("0 BFC %1", LDBFC::statements[type]); +str LDBFC::raw() +{ return fmt ("0 BFC %1", LDBFC::statements[type]); } // ============================================================================= // ----------------------------------------------------------------------------- -List<LDTriangle*> LDQuad::splitToTriangles() { - // Create the two triangles based on this quadrilateral: +QList<LDTriangle*> LDQuad::splitToTriangles() +{ // Create the two triangles based on this quadrilateral: // 0---3 0---3 3 // | | | / /| // | | ==> | / / | @@ -203,12 +205,12 @@ // 1---2 1 1---2 LDTriangle* tri1 = new LDTriangle (getVertex (0), getVertex (1), getVertex (3)); LDTriangle* tri2 = new LDTriangle (getVertex (1), getVertex (2), getVertex (3)); - + // The triangles also inherit the quad's color tri1->setColor (color()); tri2->setColor (color()); - - List<LDTriangle*> triangles; + + QList<LDTriangle*> triangles; triangles << tri1; triangles << tri2; return triangles; @@ -216,27 +218,28 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void LDObject::replace (LDObject* other) { - long idx = getIndex(); +void LDObject::replace (LDObject* other) +{ long idx = getIndex(); assert (idx != -1); - + // Replace the instance of the old object with the new object file()->setObject (idx, other); - + // Remove the old object delete this; } // ============================================================================= // ----------------------------------------------------------------------------- -void LDObject::swap (LDObject* other) { - int i = 0; - for (LDObject* obj : file()->objects()) { - if (obj == this) +void LDObject::swap (LDObject* other) +{ int i = 0; + + for (LDObject* obj : file()->objects()) + { if (obj == this) file()->setObject (i, other); elif (obj == other) file()->setObject (i, this); - + ++i; } @@ -245,131 +248,139 @@ // ============================================================================= // ----------------------------------------------------------------------------- -LDLine::LDLine (vertex v1, vertex v2) { - setVertex (0, v1); +LDLine::LDLine (vertex v1, vertex v2) +{ setVertex (0, v1); setVertex (1, v2); } // ============================================================================= // ----------------------------------------------------------------------------- -LDObject::~LDObject() { - // Remove this object from the selection array if it is there. - for (ulong i = 0; i < g_win->sel().size(); ++i) - if (g_win->sel() [i] == this) - g_win->sel().erase (i); - - // Delete the GL lists - GL::deleteLists (this); - - // Remove this object from the list of LDObjects - ulong pos = g_LDObjects.find (this); - - if (pos < g_LDObjects.size()) - g_LDObjects.erase (pos); - - g_vertexCompiler.forgetObject (this); +LDQuad::LDQuad (const vertex& v0, const vertex& v1, const vertex& v2, const vertex& v3) +{ setVertex (0, v0); + setVertex (1, v1); + setVertex (2, v2); + setVertex (3, v3); } // ============================================================================= // ----------------------------------------------------------------------------- -static void transformObject (LDObject* obj, matrix transform, vertex pos, short parentcolor) { - switch (obj->getType()) { - case LDObject::Line: - case LDObject::CndLine: - case LDObject::Triangle: - case LDObject::Quad: - for (short i = 0; i < obj->vertices(); ++i) { - vertex v = obj->getVertex (i); - v.transform (transform, pos); - obj->setVertex (i, v); - } +LDObject::~LDObject() +{ // If this object was selected, unselect it now + if (selected()) + unselect(); + + // If this object was associated to a file, remove it off it now + if (file()) + file()->forgetObject (this); + + // Delete the GL lists + GL::deleteLists (this); + + // Remove this object from the list of LDObjects + g_LDObjects.removeOne (this); +} - break; +// ============================================================================= +// ----------------------------------------------------------------------------- +static void transformObject (LDObject* obj, matrix transform, vertex pos, short parentcolor) +{ switch (obj->getType()) + { case LDObject::Line: + case LDObject::CndLine: + case LDObject::Triangle: + case LDObject::Quad: - case LDObject::Subfile: - { - LDSubfile* ref = static_cast<LDSubfile*> (obj); + for (short i = 0; i < obj->vertices(); ++i) + { vertex v = obj->getVertex (i); + v.transform (transform, pos); + obj->setVertex (i, v); + } + + break; + + case LDObject::Subfile: + { LDSubfile* ref = static_cast<LDSubfile*> (obj); matrix newMatrix = transform * ref->transform(); vertex newpos = ref->position(); - + newpos.transform (transform, pos); ref->setPosition (newpos); ref->setTransform (newMatrix); } break; - default: - break; + default: + break; } - + if (obj->color() == maincolor) obj->setColor (parentcolor); } // ============================================================================= // ----------------------------------------------------------------------------- -List<LDObject*> LDSubfile::inlineContents (InlineFlags flags) { - List<LDObject*> objs = fileInfo()->inlineContents (flags); - +QList<LDObject*> LDSubfile::inlineContents (InlineFlags flags) +{ QList<LDObject*> objs = fileInfo()->inlineContents (flags); + // Transform the objects - for (LDObject* obj : objs) { - // Set the parent now so we know what inlined this. +for (LDObject * obj : objs) + { // Set the parent now so we know what inlined this. obj->setParent (this); transformObject (obj, transform(), position(), color()); } - + return objs; } // ============================================================================= // ----------------------------------------------------------------------------- -long LDObject::getIndex() const { +long LDObject::getIndex() const +{ #ifndef RELEASE assert (file() != null); #endif - - for (ulong i = 0; i < file()->numObjs(); ++i) + + for (int i = 0; i < file()->numObjs(); ++i) if (file()->obj (i) == this) return i; - + return -1; } // ============================================================================= // ----------------------------------------------------------------------------- -void LDObject::moveObjects (List<LDObject*> objs, const bool up) { - if (objs.size() == 0) +void LDObject::moveObjects (QList<LDObject*> objs, const bool up) +{ if (objs.isEmpty()) return; - + // If we move down, we need to iterate the array in reverse order. const long start = up ? 0 : (objs.size() - 1); const long end = up ? objs.size() : -1; const long incr = up ? 1 : -1; - List<LDObject*> objsToCompile; + QList<LDObject*> objsToCompile; LDFile* file = objs[0]->file(); - - for (long i = start; i != end; i += incr) { - LDObject* obj = objs[i]; - + + for (long i = start; i != end; i += incr) + { LDObject* obj = objs[i]; + const long idx = obj->getIndex(), - target = idx + (up ? -1 : 1); - - if ((up && idx == 0) || (!up && idx == (long) (file->objects().size() - 1))) { - // One of the objects hit the extrema. If this happens, this should be the first + target = idx + (up ? -1 : 1); + + if ( (up && idx == 0) || (!up && idx == (long) (file->objects().size() - 1))) + { // One of the objects hit the extrema. If this happens, this should be the first // object to be iterated on. Thus, nothing has changed yet and it's safe to just // abort the entire operation. assert (i == start); return; } - + objsToCompile << obj; objsToCompile << file->obj (target); - + obj->swap (file->obj (target)); } - - objsToCompile.makeUnique(); - + + removeDuplicates (objsToCompile); + // The objects need to be recompiled, otherwise their pick lists are left with // the wrong index colors which messes up selection. for (LDObject* obj : objsToCompile) @@ -378,8 +389,8 @@ // ============================================================================= // ----------------------------------------------------------------------------- -str LDObject::typeName (LDObject::Type type) { - LDObject* obj = LDObject::getDefault (type); +str LDObject::typeName (LDObject::Type type) +{ LDObject* obj = LDObject::getDefault (type); str name = obj->typeName(); delete obj; return name; @@ -387,48 +398,49 @@ // ============================================================================= // ----------------------------------------------------------------------------- -str LDObject::objectListContents (const List<LDObject*>& objs) { - bool firstDetails = true; +str LDObject::objectListContents (const QList<LDObject*>& objs) +{ bool firstDetails = true; str text = ""; - - if (objs.size() == 0) + + if (objs.isEmpty()) return "nothing"; // :) - - for (long i = 0; i < LDObject::NumTypes; ++i) { - LDObject::Type objType = (LDObject::Type) i; - ulong objCount = 0; - - for (LDObject* obj : objs) + + for (long i = 0; i < LDObject::NumTypes; ++i) + { LDObject::Type objType = (LDObject::Type) i; + int count = 0; + + for (LDObject * obj : objs) if (obj->getType() == objType) - objCount++; - - if (objCount == 0) + count++; + + if (count == 0) continue; - + if (!firstDetails) text += ", "; - - str noun = fmt ("%1%2", typeName (objType), plural (objCount)); + + str noun = fmt ("%1%2", typeName (objType), plural (count)); + + // Plural of "vertex" is "vertices", correct that - // Plural of "vertex" is "vertices". Stupid English. - if (objType == LDObject::Vertex && objCount != 1) + if (objType == LDObject::Vertex && count != 1) noun = "vertices"; - - text += fmt ("%1 %2", objCount, noun); + + text += fmt ("%1 %2", count, noun); firstDetails = false; } - + return text; } // ============================================================================= // ----------------------------------------------------------------------------- -LDObject* LDObject::topLevelParent() { - if (!parent()) +LDObject* LDObject::topLevelParent() +{ if (!parent()) return this; - + LDObject* it = this; - + while (it->parent()) it = it->parent(); @@ -437,73 +449,83 @@ // ============================================================================= // ----------------------------------------------------------------------------- -LDObject* LDObject::next() const { - long idx = getIndex(); +LDObject* LDObject::next() const +{ long idx = getIndex(); assert (idx != -1); - + if (idx == (long) file()->numObjs() - 1) return null; - + return file()->obj (idx + 1); } // ============================================================================= // ----------------------------------------------------------------------------- -LDObject* LDObject::prev() const { - long idx = getIndex(); +LDObject* LDObject::prev() const +{ long idx = getIndex(); assert (idx != -1); - + if (idx == 0) return null; - + return file()->obj (idx - 1); } // ============================================================================= // ----------------------------------------------------------------------------- -void LDObject::move (vertex vect) { (void) vect; } -void LDEmpty::move (vertex vect) { (void) vect; } -void LDBFC::move (vertex vect) { (void) vect; } -void LDComment::move (vertex vect) { (void) vect; } -void LDError::move (vertex vect) { (void) vect; } - -// ============================================================================= -// ----------------------------------------------------------------------------- -void LDVertex::move (vertex vect) { - pos += vect; +void LDObject::move (vertex vect) +{ (void) vect; +} +void LDEmpty::move (vertex vect) +{ (void) vect; +} +void LDBFC::move (vertex vect) +{ (void) vect; +} +void LDComment::move (vertex vect) +{ (void) vect; +} +void LDError::move (vertex vect) +{ (void) vect; } // ============================================================================= // ----------------------------------------------------------------------------- -void LDSubfile::move (vertex vect) { - setPosition (position() + vect); +void LDVertex::move (vertex vect) +{ pos += vect; } // ============================================================================= // ----------------------------------------------------------------------------- -void LDLine::move (vertex vect) { - for (short i = 0; i < 2; ++i) +void LDSubfile::move (vertex vect) +{ setPosition (position() + vect); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void LDLine::move (vertex vect) +{ for (short i = 0; i < 2; ++i) setVertex (i, getVertex (i) + vect); } // ============================================================================= // ----------------------------------------------------------------------------- -void LDTriangle::move (vertex vect) { - for (short i = 0; i < 3; ++i) +void LDTriangle::move (vertex vect) +{ for (short i = 0; i < 3; ++i) setVertex (i, getVertex (i) + vect); } // ============================================================================= // ----------------------------------------------------------------------------- -void LDQuad::move (vertex vect) { - for (short i = 0; i < 4; ++i) +void LDQuad::move (vertex vect) +{ for (short i = 0; i < 4; ++i) setVertex (i, getVertex (i) + vect); } // ============================================================================= // ----------------------------------------------------------------------------- -void LDCndLine::move (vertex vect) { - for (short i = 0; i < 4; ++i) +void LDCndLine::move (vertex vect) +{ for (short i = 0; i < 4; ++i) setVertex (i, getVertex (i) + vect); } @@ -513,8 +535,8 @@ if (type == LDObject::N) \ return new LD##N; -LDObject* LDObject::getDefault (const LDObject::Type type) { - CHECK_FOR_OBJ (Comment) +LDObject* LDObject::getDefault (const LDObject::Type type) +{ CHECK_FOR_OBJ (Comment) CHECK_FOR_OBJ (BFC) CHECK_FOR_OBJ (Line) CHECK_FOR_OBJ (CndLine) @@ -539,8 +561,8 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void LDTriangle::invert() { - // Triangle goes 0 -> 1 -> 2, reversed: 0 -> 2 -> 1. +void LDTriangle::invert() +{ // Triangle goes 0 -> 1 -> 2, reversed: 0 -> 2 -> 1. // Thus, we swap 1 and 2. vertex tmp = getVertex (1); setVertex (1, getVertex (2)); @@ -551,8 +573,8 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void LDQuad::invert() { - // Quad: 0 -> 1 -> 2 -> 3 +void LDQuad::invert() +{ // Quad: 0 -> 1 -> 2 -> 3 // rev: 0 -> 3 -> 2 -> 1 // Thus, we swap 1 and 3. vertex tmp = getVertex (1); @@ -562,26 +584,26 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void LDSubfile::invert() { - // Subfiles are inverted when they're prefixed with +void LDSubfile::invert() +{ // Subfiles are inverted when they're prefixed with // a BFC INVERTNEXT statement. Thus we need to toggle this status. // For flat primitives it's sufficient that the determinant is // flipped but I don't have a method for checking flatness yet. // Food for thought... - - ulong idx = getIndex(); - - if (idx > 0) { - LDBFC* bfc = dynamic_cast<LDBFC*> (prev()); - - if (bfc && bfc->type == LDBFC::InvertNext) { - // This is prefixed with an invertnext, thus remove it. + + int idx = getIndex(); + + if (idx > 0) + { LDBFC* bfc = dynamic_cast<LDBFC*> (prev()); + + if (bfc && bfc->type == LDBFC::InvertNext) + { // This is prefixed with an invertnext, thus remove it. file()->forgetObject (bfc); delete bfc; return; } } - + // Not inverted, thus prefix it with a new invertnext. LDBFC* bfc = new LDBFC (LDBFC::InvertNext); file()->insertObj (idx, bfc); @@ -589,57 +611,57 @@ // ============================================================================= // ----------------------------------------------------------------------------- -static void invertLine (LDObject* line) { - // For lines, we swap the vertices. I don't think that a +static void invertLine (LDObject* line) +{ // For lines, we swap the vertices. I don't think that a // cond-line's control points need to be swapped, do they? vertex tmp = line->getVertex (0); line->setVertex (0, line->getVertex (1)); line->setVertex (1, tmp); } -void LDLine::invert() { - invertLine (this); +void LDLine::invert() +{ invertLine (this); } -void LDCndLine::invert() { - invertLine (this); +void LDCndLine::invert() +{ invertLine (this); } void LDVertex::invert() {} // ============================================================================= // ----------------------------------------------------------------------------- -LDLine* LDCndLine::demote() { - LDLine* repl = new LDLine; - +LDLine* LDCndLine::demote() +{ LDLine* repl = new LDLine; + for (int i = 0; i < repl->vertices(); ++i) repl->setVertex (i, getVertex (i)); - + repl->setColor (color()); - + replace (repl); return repl; } // ============================================================================= // ----------------------------------------------------------------------------- -LDObject* LDObject::fromID (int id) { - for (LDObject* obj : g_LDObjects) +LDObject* LDObject::fromID (int id) +{ for (LDObject * obj : g_LDObjects) if (obj->id() == id) return obj; - + return null; } // ============================================================================= // ----------------------------------------------------------------------------- -str LDOverlay::raw() { - return fmt ("0 !LDFORGE OVERLAY %1 %2 %3 %4 %5 %6", - filename(), camera(), x(), y(), width(), height()); +str LDOverlay::raw() +{ return fmt ("0 !LDFORGE OVERLAY %1 %2 %3 %4 %5 %6", + filename(), camera(), x(), y(), width(), height()); } -void LDOverlay::move (vertex vect) { - Q_UNUSED (vect) +void LDOverlay::move (vertex vect) +{ Q_UNUSED (vect) } void LDOverlay::invert() {} @@ -649,55 +671,108 @@ // It takes care of history management so we can capture low-level changes, this // makes history stuff work out of the box. // ----------------------------------------------------------------------------- -template<class T> void changeProperty (LDObject* obj, T* ptr, const T& val) { - long idx; - - if (obj->file() && (idx = obj->getIndex()) != -1) { - str before = obj->raw(); +template<class T> static void changeProperty (LDObject* obj, T* ptr, const T& val) +{ long idx; + + if (*ptr == val) + return; + + if (obj->file() && (idx = obj->getIndex()) != -1) + { str before = obj->raw(); *ptr = val; str after = obj->raw(); - + obj->file()->addToHistory (new EditHistory (idx, before, after)); - } else + } + else *ptr = val; } // ============================================================================= // ----------------------------------------------------------------------------- -READ_ACCESSOR (short, LDObject::color) { - return m_color; +READ_ACCESSOR (short, LDObject::color) +{ return m_color; +} + +SET_ACCESSOR (short, LDObject::setColor) +{ changeProperty (this, &m_color, val); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +const vertex& LDObject::getVertex (int i) const +{ return m_coords[i]->data(); } -SET_ACCESSOR (short, LDObject::setColor) { - changeProperty (this, &m_color, val); +void LDObject::setVertex (int i, const vertex& vert) +{ changeProperty (this, &m_coords[i], LDSharedVertex::getSharedVertex (vert)); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void LDMatrixObject::setPosition (const vertex& a) +{ changeProperty (linkPointer(), &m_position, LDSharedVertex::getSharedVertex (a)); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +READ_ACCESSOR (matrix, LDMatrixObject::transform) +{ return m_transform; +} + +SET_ACCESSOR (matrix, LDMatrixObject::setTransform) +{ changeProperty (linkPointer(), &m_transform, val); } // ============================================================================= // ----------------------------------------------------------------------------- -const vertex& LDObject::getVertex (int i) const { - return m_coords[i]; +static QMap<vertex, LDSharedVertex*> g_sharedVerts; + +LDSharedVertex* LDSharedVertex::getSharedVertex (const vertex& a) +{ auto it = g_sharedVerts.find (a); + + if (it == g_sharedVerts.end()) + { LDSharedVertex* v = new LDSharedVertex (a); + g_sharedVerts[a] = v; + return v; + } + + return *it; } -void LDObject::setVertex (int i, const vertex& vert) { - changeProperty (this, &m_coords[i], vert); +// ============================================================================= +// ----------------------------------------------------------------------------- +void LDSharedVertex::addRef (LDObject* a) +{ m_refs << a; } // ============================================================================= // ----------------------------------------------------------------------------- -READ_ACCESSOR (vertex, LDMatrixObject::position) { - return m_position; -} +void LDSharedVertex::delRef (LDObject* a) +{ m_refs.removeOne (a); -SET_ACCESSOR (vertex, LDMatrixObject::setPosition) { - changeProperty (linkPointer(), &m_position, val); + if (m_refs.empty()) + { g_sharedVerts.remove (m_data); + delete this; + } } // ============================================================================= // ----------------------------------------------------------------------------- -READ_ACCESSOR (matrix, LDMatrixObject::transform) { - return m_transform; +void LDObject::select() +{ if (!file()) + { log ("Warning: Object #%1 cannot be selected as it is not assigned a file!\n", id()); + return; + } + + file()->addToSelection (this); } -SET_ACCESSOR (matrix, LDMatrixObject::setTransform) { - changeProperty (linkPointer(), &m_transform, val); +void LDObject::unselect() +{ if (!file()) + { log ("Warning: Object #%1 cannot be unselected as it is not assigned a file!\n", id()); + return; + } + + file()->removeFromSelection (this); } \ No newline at end of file
--- a/src/ldtypes.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/ldtypes.h Wed Oct 23 12:46:10 2013 +0300 @@ -52,6 +52,7 @@ class QListWidgetItem; class LDSubfile; class LDFile; +class LDSharedVertex; // ============================================================================= // LDObject @@ -61,74 +62,106 @@ // which is a token of the object's type. The object can be casted into // sub-classes based on this enumerator. // ============================================================================= -class LDObject { - PROPERTY (bool, hidden, setHidden) +class LDObject +{ PROPERTY (bool, hidden, setHidden) PROPERTY (bool, selected, setSelected) PROPERTY (LDObject*, parent, setParent) PROPERTY (LDFile*, file, setFile) READ_PROPERTY (int32, id, setID) DECLARE_PROPERTY (short, color, setColor) -public: - // Object type codes. Codes are sorted in order of significance. - enum Type { - Subfile, // Object represents a sub-file reference - Quad, // Object represents a quadrilateral - Triangle, // Object represents a triangle - Line, // Object represents a line - CndLine, // Object represents a conditional line - Vertex, // Object is a vertex, LDForge extension object - BFC, // Object represents a BFC statement - Overlay, // Object contains meta-info about an overlay image. - Comment, // Object represents a comment - Error, // Object is the result of failed parsing - Empty, // Object represents an empty line - Unidentified, // Object is an uninitialized (SHOULD NEVER HAPPEN) - NumTypes // Amount of object types - }; + public: + // Object type codes. Codes are sorted in order of significance. + enum Type + { Subfile, // Object represents a sub-file reference + Quad, // Object represents a quadrilateral + Triangle, // Object represents a triangle + Line, // Object represents a line + CndLine, // Object represents a conditional line + Vertex, // Object is a vertex, LDForge extension object + BFC, // Object represents a BFC statement + Overlay, // Object contains meta-info about an overlay image. + Comment, // Object represents a comment + Error, // Object is the result of failed parsing + Empty, // Object represents an empty line + Unidentified, // Object is an uninitialized (SHOULD NEVER HAPPEN) + NumTypes // Amount of object types + }; + + LDObject(); + virtual ~LDObject(); + + virtual LDObject* clone() + { return 0; // Creates a new LDObject identical to this one. + } + long getIndex() const; // Index (i.e. line number) of this object + virtual LDObject::Type getType() const; // Type enumerator of this object + const vertex& getVertex (int i) const; // Get a vertex by index + virtual bool hasMatrix() const; // Does this object have a matrix and position? (see LDMatrixObject) + virtual void invert(); // Inverts this object (winding is reversed) + virtual bool isColored() const; // Is this object colored? + virtual bool isScemantic() const; // Does this object have meaning in the part model? + virtual void move (vertex vect); // Moves this object using the given vertex as a movement List + LDObject* next() const; // Object after this in the current file + LDObject* prev() const; // Object prior to this in the current file + virtual str raw() { return ""; } // This object as LDraw code + void replace (LDObject* other); // Replace this LDObject with another LDObject. Object is deleted in the process. + void select(); + void setVertex (int i, const vertex& vert); // Set a vertex to the given value + void setVertexCoord (int i, Axis ax, double value); // Set a single coordinate of a vertex + void swap (LDObject* other); // Swap this object with another. + LDObject* topLevelParent(); // What object in the current file ultimately references this? + virtual str typeName() const; // Type name of this object + void unselect(); + virtual short vertices() const; // Number of vertices this object has - LDObject(); - virtual ~LDObject(); - - virtual LDObject* clone() {return 0;} // Creates a new LDObject identical to this one. - long getIndex() const; // Index (i.e. line number) of this object - virtual LDObject::Type getType() const; // Type enumerator of this object - const vertex& getVertex (int i) const; // Get a vertex by index - virtual bool hasMatrix() const; // Does this object have a matrix and position? (see LDMatrixObject) - virtual void invert(); // Inverts this object (winding is reversed) - virtual bool isColored() const; // Is this object colored? - virtual bool isScemantic() const; // Does this object have meaning in the part model? - virtual void move (vertex vect); // Moves this object using the given vertex as a movement List - LDObject* next() const; // Object after this in the current file - LDObject* prev() const; // Object prior to this in the current file - virtual str raw() { return ""; } // This object as LDraw code - void replace (LDObject* other); // Replace this LDObject with another LDObject. Object is deleted in the process. - void setVertex (int i, const vertex& vert); // Set a vertex to the given value - void setVertexCoord (int i, Axis ax, double value); // Set a single coordinate of a vertex - void swap (LDObject* other); // Swap this object with another. - LDObject* topLevelParent(); // What object in the current file ultimately references this? - virtual str typeName() const; // Type name of this object - virtual short vertices() const; // Number of vertices this object has - - static str typeName (LDObject::Type type); // Get type name by enumerator - static LDObject* getDefault (const LDObject::Type type); // Returns a sample object by the given enumerator - static void moveObjects (List<LDObject*> objs, const bool up); // TODO: move this to LDFile? - static str objectListContents (const List<LDObject*>& objs); // Get a description of a list of LDObjects - static LDObject* fromID (int id); - - // TODO: make these private! - // OpenGL list for this object - uint glLists[4]; - - // Object list entry for this object - QListWidgetItem* qObjListEntry; + static str typeName (LDObject::Type type); // Get type name by enumerator + static LDObject* getDefault (const LDObject::Type type); // Returns a sample object by the given enumerator + static void moveObjects (QList<LDObject*> objs, const bool up); // TODO: move this to LDFile? + static str objectListContents (const QList<LDObject*>& objs); // Get a description of a list of LDObjects + static LDObject* fromID (int id); + + // TODO: make these private! + // OpenGL list for this object + uint glLists[4]; + + // Object list entry for this object + QListWidgetItem* qObjListEntry; + + protected: + bool m_glinit; + friend class GLRenderer; + + private: + LDSharedVertex* m_coords[4]; +}; -protected: - bool m_glinit; - friend class GLRenderer; +// ============================================================================= +// LDSharedVertex +// +// For use as coordinates of LDObjects. Keeps count of references. +// ----------------------------------------------------------------------------- +class LDSharedVertex +{ public: + inline const vertex& data() const + { return m_data; + } -private: - vertex m_coords[4]; + inline operator const vertex&() const + { return m_data; + } + + void addRef (LDObject* a); + void delRef (LDObject* a); + + static LDSharedVertex* getSharedVertex (const vertex& a); + + protected: + LDSharedVertex (const vertex& a) : m_data (a) {} + + private: + QList<LDObject*> m_refs; + vertex m_data; }; // ============================================================================= @@ -146,23 +179,31 @@ // matrix as well. Even though right now only LDSubfile uses this, I'm keeping // this class distinct in case I get new extension ideas. :) // ============================================================================= -class LDMatrixObject { - DECLARE_PROPERTY (matrix, transform, setTransform) - DECLARE_PROPERTY (vertex, position, setPosition) +class LDMatrixObject +{ DECLARE_PROPERTY (matrix, transform, setTransform) PROPERTY (LDObject*, linkPointer, setLinkPointer) -public: - LDMatrixObject() {} - LDMatrixObject (const matrix& transform, const vertex& pos) : - PROP_NAME (transform) (transform), PROP_NAME (position) (pos) {} + public: + LDMatrixObject() {} + LDMatrixObject (const matrix& transform, const vertex& pos) : + m_transform (transform), m_position (LDSharedVertex::getSharedVertex (pos)) {} + + const vertex& position() const + { return m_position->data(); + } + + void setPosition (const vertex& a); - const double& setCoordinate (const Axis ax, double value) { - vertex v = position(); - v[ax] = value; - setPosition (v); + const double& setCoordinate (const Axis ax, double value) + { vertex v = position(); + v[ax] = value; + setPosition (v); - return position() [ax]; - } + return position() [ax]; + } + + private: + LDSharedVertex* m_position; }; // ============================================================================= @@ -173,8 +214,8 @@ // allowing garbage lines be debugged and corrected within LDForge. The member // zContent contains the contents of the unparsable line. // ============================================================================= -class LDError : public LDObject { - LDOBJ (Error) +class LDError : public LDObject +{ LDOBJ (Error) LDOBJ_NAME (error) LDOBJ_VERTICES (0) LDOBJ_UNCOLORED @@ -182,15 +223,15 @@ LDOBJ_NO_MATRIX PROPERTY (str, fileRef, setFileRef) -public: - LDError(); - LDError (str contents, str reason) : contents (contents), reason (reason) {} + public: + LDError(); + LDError (str contents, str reason) : contents (contents), reason (reason) {} - // Content of this unknown line - str contents; + // Content of this unknown line + str contents; - // Why is this gibberish? - str reason; + // Why is this gibberish? + str reason; }; // ============================================================================= @@ -198,8 +239,8 @@ // // Represents an empty line in the LDraw code file. // ============================================================================= -class LDEmpty : public LDObject { - LDOBJ (Empty) +class LDEmpty : public LDObject +{ LDOBJ (Empty) LDOBJ_VERTICES (0) LDOBJ_UNCOLORED LDOBJ_NON_SCEMANTIC @@ -212,19 +253,19 @@ // Represents a code-0 comment in the LDraw code file. Member text contains // the text of the comment. // ============================================================================= -class LDComment : public LDObject { - LDOBJ (Comment) +class LDComment : public LDObject +{ LDOBJ (Comment) LDOBJ_NAME (comment) LDOBJ_VERTICES (0) LDOBJ_UNCOLORED LDOBJ_NON_SCEMANTIC LDOBJ_NO_MATRIX -public: - LDComment() {} - LDComment (str text) : text (text) {} + public: + LDComment() {} + LDComment (str text) : text (text) {} - str text; // The text of this comment + str text; // The text of this comment }; // ============================================================================= @@ -233,37 +274,37 @@ // Represents a 0 BFC statement in the LDraw code. eStatement contains the type // of this statement. // ============================================================================= -class LDBFC : public LDObject { -public: - enum Type { - CertifyCCW, - CCW, - CertifyCW, - CW, - NoCertify, - InvertNext, - Clip, - ClipCCW, - ClipCW, - NoClip, - NumStatements - }; - - LDOBJ (BFC) - LDOBJ_NAME (bfc) - LDOBJ_VERTICES (0) - LDOBJ_UNCOLORED - LDOBJ_CUSTOM_SCEMANTIC { return (type == InvertNext); } - LDOBJ_NO_MATRIX - -public: - LDBFC() {} - LDBFC (const LDBFC::Type type) : type (type) {} +class LDBFC : public LDObject +{ public: + enum Type + { CertifyCCW, + CCW, + CertifyCW, + CW, + NoCertify, + InvertNext, + Clip, + ClipCCW, + ClipCW, + NoClip, + NumStatements + }; - // Statement strings - static const char* statements[]; + LDOBJ (BFC) + LDOBJ_NAME (bfc) + LDOBJ_VERTICES (0) + LDOBJ_UNCOLORED + LDOBJ_CUSTOM_SCEMANTIC { return (type == InvertNext); } + LDOBJ_NO_MATRIX - Type type; + public: + LDBFC() {} + LDBFC (const LDBFC::Type type) : type (type) {} + + // Statement strings + static const char* statements[]; + + Type type; }; // ============================================================================= @@ -271,8 +312,8 @@ // // Represents a single code-1 subfile reference. // ============================================================================= -class LDSubfile : public LDObject, public LDMatrixObject { - LDOBJ (Subfile) +class LDSubfile : public LDObject, public LDMatrixObject +{ LDOBJ (Subfile) LDOBJ_NAME (subfile) LDOBJ_VERTICES (0) LDOBJ_COLORED @@ -280,24 +321,24 @@ LDOBJ_HAS_MATRIX PROPERTY (LDFile*, fileInfo, setFileInfo) -public: - enum InlineFlag { - DeepInline = (1 << 0), - CacheInline = (1 << 1), - RendererInline = (1 << 2), - - DeepCacheInline = DeepInline | CacheInline, - }; - - Q_DECLARE_FLAGS (InlineFlags, InlineFlag) - - LDSubfile() { - setLinkPointer (this); - } - - // Inlines this subfile. Note that return type is an array of heap-allocated - // LDObject-clones, they must be deleted one way or another. - List<LDObject*> inlineContents (InlineFlags flags); + public: + enum InlineFlag + { DeepInline = (1 << 0), + CacheInline = (1 << 1), + RendererInline = (1 << 2), + + DeepCacheInline = DeepInline | CacheInline, + }; + + Q_DECLARE_FLAGS (InlineFlags, InlineFlag) + + LDSubfile() + { setLinkPointer (this); + } + + // Inlines this subfile. Note that return type is an array of heap-allocated + // LDObject-clones, they must be deleted one way or another. + QList<LDObject*> inlineContents (InlineFlags flags); }; Q_DECLARE_OPERATORS_FOR_FLAGS (LDSubfile::InlineFlags) @@ -309,17 +350,17 @@ // points of the line. The line is colored with dColor unless uncolored mode is // set. // ============================================================================= -class LDLine : public LDObject { - LDOBJ (Line) +class LDLine : public LDObject +{ LDOBJ (Line) LDOBJ_NAME (line) LDOBJ_VERTICES (2) LDOBJ_COLORED LDOBJ_SCEMANTIC LDOBJ_NO_MATRIX -public: - LDLine() {} - LDLine (vertex v1, vertex v2); + public: + LDLine() {} + LDLine (vertex v1, vertex v2); }; // ============================================================================= @@ -328,17 +369,17 @@ // Represents a single code-5 conditional line. The end-points v0 and v1 are // inherited from LDLine, c0 and c1 are the control points of this line. // ============================================================================= -class LDCndLine : public LDLine { - LDOBJ (CndLine) +class LDCndLine : public LDLine +{ LDOBJ (CndLine) LDOBJ_NAME (condline) LDOBJ_VERTICES (4) LDOBJ_COLORED LDOBJ_SCEMANTIC LDOBJ_NO_MATRIX -public: - LDCndLine() {} - LDLine* demote(); + public: + LDCndLine() {} + LDLine* demote(); }; // ============================================================================= @@ -348,21 +389,21 @@ // and v2 contain the end-points of this triangle. dColor is the color the // triangle is colored with. // ============================================================================= -class LDTriangle : public LDObject { - LDOBJ (Triangle) +class LDTriangle : public LDObject +{ LDOBJ (Triangle) LDOBJ_NAME (triangle) LDOBJ_VERTICES (3) LDOBJ_COLORED LDOBJ_SCEMANTIC LDOBJ_NO_MATRIX -public: - LDTriangle() {} - LDTriangle (vertex v0, vertex v1, vertex v2) { - setVertex (0, v0); - setVertex (1, v1); - setVertex (2, v2); - } + public: + LDTriangle() {} + LDTriangle (vertex v0, vertex v1, vertex v2) + { setVertex (0, v0); + setVertex (1, v1); + setVertex (2, v2); + } }; // ============================================================================= @@ -371,19 +412,20 @@ // Represents a single code-4 quadrilateral. v0, v1, v2 and v3 are the end points // of the quad, dColor is the color used for the quad. // ============================================================================= -class LDQuad : public LDObject { -public: - LDOBJ (Quad) +class LDQuad : public LDObject +{ LDOBJ (Quad) LDOBJ_NAME (quad) LDOBJ_VERTICES (4) LDOBJ_COLORED LDOBJ_SCEMANTIC LDOBJ_NO_MATRIX - LDQuad() {} + public: + LDQuad() {} + LDQuad (const vertex& v0, const vertex& v1, const vertex& v2, const vertex& v3); - // Split this quad into two triangles (note: heap-allocated) - List<LDTriangle*> splitToTriangles(); + // Split this quad into two triangles (note: heap-allocated) + QList<LDTriangle*> splitToTriangles(); }; // ============================================================================= @@ -394,18 +436,18 @@ // with. Vertices are a part authoring tool and they should not appear in // finished parts. // ============================================================================= -class LDVertex : public LDObject { -public: - LDOBJ (Vertex) +class LDVertex : public LDObject +{ LDOBJ (Vertex) LDOBJ_NAME (vertex) LDOBJ_VERTICES (0) // TODO: move pos to vaCoords[0] LDOBJ_COLORED LDOBJ_NON_SCEMANTIC LDOBJ_NO_MATRIX - LDVertex() {} + public: + LDVertex() {} - vertex pos; + vertex pos; }; // ============================================================================= @@ -414,8 +456,8 @@ // Overlay image meta, stored in the header of parts so as to preserve overlay // information. // ============================================================================= -class LDOverlay : public LDObject { - LDOBJ (Overlay) +class LDOverlay : public LDObject +{ LDOBJ (Overlay) LDOBJ_NAME (overlay) LDOBJ_VERTICES (0) LDOBJ_UNCOLORED @@ -431,8 +473,8 @@ // Other common LDraw stuff static const str CALicense = "!LICENSE Redistributable under CCAL version 2.0 : see CAreadme.txt", - NonCALicense = "!LICENSE Not redistributable : see NonCAreadme.txt"; + NonCALicense = "!LICENSE Not redistributable : see NonCAreadme.txt"; static const short lores = 16; static const short hires = 48; -#endif // LDTYPES_H \ No newline at end of file +#endif // LDTYPES_H
--- a/src/main.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/main.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -30,94 +30,97 @@ #include "primitives.h" #include "gldraw.h" #include "configDialog.h" +#include "dialogs.h" +#include "crashcatcher.h" -List<LDFile*> g_loadedFiles; -ForgeWindow* g_win = null; +QList<LDFile*> g_loadedFiles; +ForgeWindow* g_win = null; const QApplication* g_app = null; File g_file_stdout (stdout, File::Write); File g_file_stderr (stderr, File::Write); static str g_versionString, g_fullVersionString; const vertex g_origin (0.0f, 0.0f, 0.0f); -const matrix g_identity ({1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}); +const matrix g_identity ( {1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f}); cfg (Bool, firststart, true); // ============================================================================= // ----------------------------------------------------------------------------- -int main (int argc, char* argv[]) { - QApplication app (argc, argv); +int main (int argc, char* argv[]) +{ QApplication app (argc, argv); app.setOrganizationName (APPNAME); app.setApplicationName (APPNAME); - g_app = &app; + + initCrashCatcher(); LDFile::setCurrent (null); - + // Load or create the configuration - if (!Config::load()) { - print ("Creating configuration file...\n"); + if (!Config::load()) + { log ("Creating configuration file...\n"); + if (Config::save()) - print ("Configuration file successfully created.\n"); + log ("Configuration file successfully created.\n"); else - print ("failed to create configuration file!\n"); + log ("failed to create configuration file!\n"); } - + LDPaths::initPaths(); initColors(); loadLogoedStuds(); - + ForgeWindow* win = new ForgeWindow; newFile(); win->show(); - + // If this is the first start, get the user to configuration. Especially point // them to the profile tab, it's the most important form to fill in. - if (firststart) { - (new ConfigDialog (ConfigDialog::ProfileTab))->exec(); + if (firststart) + { (new ConfigDialog (ConfigDialog::ProfileTab))->exec(); firststart = false; Config::save(); } - + loadPrimitives(); return app.exec(); } // ============================================================================= // ----------------------------------------------------------------------------- -void doPrint (File& f, initlist<StringFormatArg> args) { - str msg = DoFormat (args); +void doPrint (File& f, initlist<StringFormatArg> args) +{ str msg = DoFormat (args); f.write (msg.toUtf8()); f.flush(); } // ============================================================================= // ----------------------------------------------------------------------------- -void doPrint (FILE* fp, initlist<StringFormatArg> args) { - if (fp == stdout) - doPrint (g_file_stdout, args); - elif (fp == stderr) - doPrint (g_file_stderr, args); - else - fatal ("unknown FILE* argument"); +void doPrint (FILE* fp, initlist<StringFormatArg> args) +{ str msg = DoFormat (args); + fwrite (msg.toStdString().c_str(), 1, msg.length(), fp); + fflush (fp); } // ============================================================================= // ----------------------------------------------------------------------------- -str versionString() { - if (g_versionString.length() == 0) { +QString versionString() +{ if (g_versionString.length() == 0) + { #if VERSION_PATCH == 0 g_versionString = fmt ("%1.%2", VERSION_MAJOR, VERSION_MINOR); #else g_versionString = fmt ("%1.%2.%3", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH); #endif // VERSION_PATCH } - + return g_versionString; } // ============================================================================= // ----------------------------------------------------------------------------- -str versionMoniker() { +QString versionMoniker() +{ #if BUILD_ID == BUILD_INTERNAL return "Internal"; #elif BUILD_ID == BUILD_ALPHA @@ -133,61 +136,6 @@ // ============================================================================= // ----------------------------------------------------------------------------- -str fullVersionString() { - return fmt ("v%1 %2", versionString(), versionMoniker()); -} - -// ============================================================================= -// ----------------------------------------------------------------------------- -static void bombBox (str msg) { - msg.replace ("\n", "<br />"); - - QMessageBox box (null); - const QMessageBox::StandardButton btn = QMessageBox::Close; - box.setWindowTitle ("Fatal Error"); - box.setIconPixmap (getIcon ("bomb")); - box.setWindowIcon (getIcon ("ldforge")); - box.setText (msg); - box.addButton (btn); - box.button (btn)->setText ("Damn it"); - box.setDefaultButton (btn); - box.exec(); -} - -// ============================================================================= -// ----------------------------------------------------------------------------- -void assertionFailure (const char* file, const ulong line, const char* funcname, const char* expr) { - str errmsg = fmt ("File: %1\nLine: %2:\nFunction %3:\n\nAssertion `%4' failed", - file, line, funcname, expr); - -#if BUILD_ID == BUILD_INTERNAL - errmsg += ", aborting."; -#else - errmsg += "."; -#endif - - printf ("%s\n", errmsg.toStdString().c_str()); - -#if BUILD_ID == BUILD_INTERNAL - if (g_win) - g_win->deleteLater(); - - bombBox (errmsg); - abort(); -#endif -} - -// ============================================================================= -// ----------------------------------------------------------------------------- -void fatalError (const char* file, const ulong line, const char* funcname, str msg) { - str errmsg = fmt ("Aborting over a call to fatal():\nFile: %1\nLine: %2\nFunction: %3\n\n%4", - file, line, funcname, msg); - - print ("%1\n", errmsg); - - if (g_win) - g_win->deleteLater(); - - bombBox (errmsg); - abort(); +QString fullVersionString() +{ return fmt ("v%1 %2", versionString(), versionMoniker()); } \ No newline at end of file
--- a/src/messagelog.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/messagelog.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -21,16 +21,17 @@ #include "messagelog.h" #include "gldraw.h" #include "gui.h" +#include "moc_messagelog.cpp" -static const unsigned int g_maxMessages = 5; +static const int g_maxMessages = 5; static const int g_expiry = 5; static const int g_fadeTime = 500; // msecs // ============================================================================= // ----------------------------------------------------------------------------- MessageManager::MessageManager (QObject* parent) : - QObject (parent) { - m_ticker = new QTimer; + QObject (parent) +{ m_ticker = new QTimer; m_ticker->start (100); connect (m_ticker, SIGNAL (timeout()), this, SLOT (tick())); } @@ -38,45 +39,45 @@ // ============================================================================= // ----------------------------------------------------------------------------- MessageManager::Line::Line (str text) : - text (text), - alpha (1.0f), - expiry (QDateTime::currentDateTime().addSecs (g_expiry)) {} + text (text), + alpha (1.0f), + expiry (QDateTime::currentDateTime().addSecs (g_expiry)) {} // ============================================================================= // Check this line's expiry and update alpha accordingly. Returns true if the // line is to still stick around, false if it expired. 'changed' is updated to // whether the line has somehow changed since the last update. // ----------------------------------------------------------------------------- -bool MessageManager::Line::update (bool& changed) { - changed = false; +bool MessageManager::Line::update (bool& changed) +{ changed = false; QDateTime now = QDateTime::currentDateTime(); int msec = now.msecsTo (expiry); - - if (now >= expiry) { - // Message line has expired + + if (now >= expiry) + { // Message line has expired changed = true; return false; } - - if (msec <= g_fadeTime) { - // Message line has not expired but is fading out - alpha = ((float) msec) / g_fadeTime; + + if (msec <= g_fadeTime) + { // Message line has not expired but is fading out + alpha = ( (float) msec) / g_fadeTime; changed = true; } - + return true; } // ============================================================================= // Add a line to the message manager. // ----------------------------------------------------------------------------- -void MessageManager::addLine (str line) { - // If there's too many entries, pop the excess out +void MessageManager::addLine (str line) +{ // If there's too many entries, pop the excess out while (m_lines.size() >= g_maxMessages) - m_lines.erase (0); - + m_lines.removeFirst(); + m_lines << Line (line); - + // Update the renderer view if (renderer()) renderer()->update(); @@ -86,40 +87,43 @@ // Ticks the message manager. All lines are ticked and the renderer scene is // redrawn if something changed. // ----------------------------------------------------------------------------- -void MessageManager::tick() { - if (m_lines.size() == 0) +void MessageManager::tick() +{ if (m_lines.isEmpty()) return; - + bool changed = false; - - for (uint i = 0; i < m_lines.size(); ++i) { - bool lineChanged; - + + for (int i = 0; i < m_lines.size(); ++i) + { bool lineChanged; + if (!m_lines[i].update (lineChanged)) - m_lines.erase (i--); - + m_lines.removeAt (i--); + changed |= lineChanged; } - + if (changed && renderer()) renderer()->update(); } // ============================================================================= // ----------------------------------------------------------------------------- -const List<MessageManager::Line>& MessageManager::getLines() const { - return m_lines; +const QList<MessageManager::Line>& MessageManager::getLines() const +{ return m_lines; } // ============================================================================= // log() interface - format the argument list and add the resulting string to // the main message manager. // ----------------------------------------------------------------------------- -void DoLog (std::initializer_list<StringFormatArg> args) { - const str msg = DoFormat (args); - g_win->addMessage (msg); - - // Also print it to stdout - print ("%1\n", msg); +void DoLog (std::initializer_list<StringFormatArg> args) +{ const str msg = DoFormat (args); + + for (str& a : msg.split ("\n", QString::SkipEmptyParts)) + { if (g_win) + g_win->addMessage (a); + + // Also print it to stdout + fprint (stdout, "%1\n", a); + } } -#include "moc_messagelog.cpp"
--- a/src/messagelog.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/messagelog.h Wed Oct 23 12:46:10 2013 +0300 @@ -37,32 +37,32 @@ * their expiry. If the message manager's lines change, the renderer undergoes * repainting. */ -class MessageManager : public QObject { - Q_OBJECT - PROPERTY (GLRenderer*, renderer, setRenderer) - -public: - // Single line of the message log. - class Line { +class MessageManager : public QObject +{ Q_OBJECT + PROPERTY (GLRenderer*, renderer, setRenderer) + public: - Line (str text); - bool update (bool& changed); - - str text; - float alpha; - QDateTime expiry; - }; - - explicit MessageManager (QObject* parent = 0); - void addLine (str line); - const List<Line>& getLines() const; - -private: - List<Line> m_lines; - QTimer* m_ticker; - -private slots: - void tick(); + // Single line of the message log. + class Line + { public: + Line (str text); + bool update (bool& changed); + + str text; + float alpha; + QDateTime expiry; + }; + + explicit MessageManager (QObject* parent = 0); + void addLine (str line); + const QList<Line>& getLines() const; + + private: + QList<Line> m_lines; + QTimer* m_ticker; + + private slots: + void tick(); }; -#endif // MESSAGELOG_H \ No newline at end of file +#endif // MESSAGELOG_H
--- a/src/misc.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/misc.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -25,58 +25,60 @@ #include "dialogs.h" #include "ui_rotpoint.h" +RingFinder g_RingFinder; + // Prime number table. -const ushort g_primes[NUM_PRIMES] = { - 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, - 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, - 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, - 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, - 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, - 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, - 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, - 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, - 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, - 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, - 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, - 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, - 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, - 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, - 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, - 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, - 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, - 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, - 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, - 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, - 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, - 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, - 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, - 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, - 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, - 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, - 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, - 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, - 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, - 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, - 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, - 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, - 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, - 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, - 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, - 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, - 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, - 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, - 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, - 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, - 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, - 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, - 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, - 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, - 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, - 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, - 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, - 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, - 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, - 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, +const int g_primes[NUM_PRIMES] = +{ 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, + 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, + 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, + 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, + 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, + 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, + 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, + 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, + 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, + 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, + 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, + 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, + 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, + 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, + 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, + 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, + 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, + 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, + 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, + 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, + 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, + 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, + 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, + 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, + 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, + 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, + 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, + 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, + 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, + 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, + 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, + 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, + 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, + 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, + 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, + 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, + 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, + 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, + 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, + 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, + 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, + 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, + 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, + 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, + 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, + 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, + 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, + 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, + 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, + 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, }; // ============================================================================= @@ -101,8 +103,8 @@ cfg (Float, edit_rotpoint_y, 0.0f); cfg (Float, edit_rotpoint_z, 0.0f); -const gridinfo g_GridInfo[3] = { - { "Coarse", { &grid_coarse_x, &grid_coarse_y, &grid_coarse_z, &grid_coarse_angle }}, +const gridinfo g_GridInfo[3] = +{ { "Coarse", { &grid_coarse_x, &grid_coarse_y, &grid_coarse_z, &grid_coarse_angle }}, { "Medium", { &grid_medium_x, &grid_medium_y, &grid_medium_z, &grid_medium_angle }}, { "Fine", { &grid_fine_x, &grid_fine_y, &grid_fine_z, &grid_fine_angle }} }; @@ -110,158 +112,135 @@ // ============================================================================= // Snap the given coordinate value on the current grid's given axis. // ----------------------------------------------------------------------------- -double Grid::snap (double in, const Grid::Config axis) { - const double gridval = currentGrid().confs[axis]->value; +double Grid::snap (double in, const Grid::Config axis) +{ const double gridval = currentGrid().confs[axis]->value; const long mult = abs (in / gridval); const bool neg = (in < 0); double out = mult * gridval; - + if (abs<double> (in) - (mult * gridval) > gridval / 2) out += gridval; - + if (neg && out != 0) out *= -1; - + return out; } // ============================================================================= -// Float to string. Removes trailing zeroes and is locale-independant. -// TODO: Replace with QString::number() // ----------------------------------------------------------------------------- -str ftoa (double num) { - // Disable the locale first so that the decimal point will not - // turn into anything weird (like commas) - setlocale (LC_NUMERIC, "C"); - - str rep; - rep.sprintf ("%f", num); - - // Remove trailing zeroes - while (rep.right (1) == "0") - rep.chop (1); - - // If there were only zeroes in the decimal place, remove - // the decimal point now. - if (rep.right (1) == ".") - rep.chop (1); - - return rep; -} +bool numeric (const str& tok) +{ bool gotDot = false; -// ============================================================================= -// TODO: I guess Qt must have something like this stashed somewhere? -// ----------------------------------------------------------------------------- -bool isNumber (const str& tok) { - bool gotDot = false; - - for (int i = 0; i < tok.length(); ++i) { - const qchar c = tok[i]; - + for (int i = 0; i < tok.length(); ++i) + { const qchar c = tok[i]; + // Allow leading hyphen for negatives if (i == 0 && c == '-') continue; - + // Check for decimal point - if (!gotDot && c == '.') { - gotDot = true; + if (!gotDot && c == '.') + { gotDot = true; continue; } - + if (c >= '0' && c <= '9') continue; // Digit - + // If the above cases didn't catch this character, it was // illegal and this is therefore not a number. return false; } - + return true; } // ============================================================================= // ----------------------------------------------------------------------------- -void simplify (short& numer, short& denom) { - bool repeat; - - do { - repeat = false; - - for (ushort x = 0; x < NUM_PRIMES; x++) { - const ushort prime = g_primes[NUM_PRIMES - x - 1]; - +void simplify (int& numer, int& denom) +{ bool repeat; + + do + { repeat = false; + + for (int x = 0; x < NUM_PRIMES; x++) + { const int prime = g_primes[NUM_PRIMES - x - 1]; + if (numer <= prime || denom <= prime) continue; - - if ((numer % prime == 0) && (denom % prime == 0)) { - numer /= prime; + + if ( (numer % prime == 0) && (denom % prime == 0)) + { numer /= prime; denom /= prime; repeat = true; break; } } - } while (repeat); + } + while (repeat); } // ============================================================================= // ----------------------------------------------------------------------------- -vertex rotPoint (const List<LDObject*>& objs) { - LDBoundingBox box; - - switch (edit_rotpoint) { - case ObjectOrigin: - // Calculate center vertex +vertex rotPoint (const QList<LDObject*>& objs) +{ LDBoundingBox box; + + switch (edit_rotpoint) + { case ObjectOrigin: + + // Calculate center vertex for (LDObject * obj : objs) - if (obj->hasMatrix()) - box << dynamic_cast<LDMatrixObject*>(obj)->position(); - else - box << obj; - - return box.center(); - - case WorldOrigin: - return g_origin; - - case CustomPoint: - return vertex (edit_rotpoint_x, edit_rotpoint_y, edit_rotpoint_z); + if (obj->hasMatrix()) + box << dynamic_cast<LDMatrixObject*> (obj)->position(); + else + box << obj; + + return box.center(); + + case WorldOrigin: + return g_origin; + + case CustomPoint: + return vertex (edit_rotpoint_x, edit_rotpoint_y, edit_rotpoint_z); } - + return vertex(); } // ============================================================================= // ----------------------------------------------------------------------------- -void configRotationPoint() { - QDialog* dlg = new QDialog; +void configRotationPoint() +{ QDialog* dlg = new QDialog; Ui::RotPointUI ui; ui.setupUi (dlg); - - switch (edit_rotpoint) { - case ObjectOrigin: - ui.objectPoint->setChecked (true); - break; - - case WorldOrigin: - ui.worldPoint->setChecked (true); - break; - - case CustomPoint: - ui.customPoint->setChecked (true); - break; + + switch (edit_rotpoint) + { case ObjectOrigin: + ui.objectPoint->setChecked (true); + break; + + case WorldOrigin: + ui.worldPoint->setChecked (true); + break; + + case CustomPoint: + ui.customPoint->setChecked (true); + break; } - + ui.customX->setValue (edit_rotpoint_x); ui.customY->setValue (edit_rotpoint_y); ui.customZ->setValue (edit_rotpoint_z); - + if (!dlg->exec()) return; - + edit_rotpoint = (ui.objectPoint->isChecked()) ? ObjectOrigin : (ui.worldPoint->isChecked()) ? WorldOrigin : - CustomPoint; - + CustomPoint; + edit_rotpoint_x = ui.customX->value(); edit_rotpoint_y = ui.customY->value(); edit_rotpoint_z = ui.customZ->value(); @@ -269,31 +248,163 @@ // ============================================================================= // ----------------------------------------------------------------------------- -str join (initlist<StringFormatArg> vals, str delim) { - QStringList list; +str join (initlist<StringFormatArg> vals, str delim) +{ QStringList list; + for (const StringFormatArg& arg : vals) list << arg.value(); - + return list.join (delim); } // ============================================================================= -// TODO: I'm quite sure Qt has this covered as well. +// This is the main algorithm of the ring finder. It tries to use math to find +// the one ring between r0 and r1. If it fails (the ring number is non-integral), +// it finds an intermediate radius (ceil of the ring number times scale) and +// splits the radius at this point, calling this function again to try find the +// rings between r0 - r and r - r1. +// +// This does not always yield into usable results. If at some point r == r0 or +// r == r1, there is no hope of finding the rings, at least with this algorithm, +// as it would fall into an infinite recursion. // ----------------------------------------------------------------------------- -double atof (str val) { - // Disable the locale while parsing the line or atof's behavior changes - // between locales (i.e. fails to read decimals properly). That is - // quite undesired... - setlocale (LC_NUMERIC, "C"); - - char* buf = new char[val.length()]; - char* bufptr = &buf[0]; - - for (qchar& c : val) - *bufptr++ = c.toLatin1(); - *bufptr = '\0'; - - double fval = atof (buf); - delete[] buf; - return fval; -} \ No newline at end of file +bool RingFinder::findRingsRecursor (double r0, double r1, Solution& currentSolution) +{ char tabs[64]; + memset (tabs, '\t', m_stack); + tabs[m_stack] = '\0'; + + // Don't recurse too deep. + if (m_stack >= 5) + return false; + + // Find the scale and number of a ring between r1 and r0. + assert (r1 >= r0); + double scale = r1 - r0; + double num = r0 / scale; + + // If the ring number is integral, we have found a fitting ring to r0 -> r1! + if (isInteger (num)) + { Component cmp; + cmp.scale = scale; + cmp.num = (int) round (num); + currentSolution.addComponent (cmp); + + // If we're still at the first recursion, this is the only + // ring and there's nothing left to do. Guess we found the winner. + if (m_stack == 0) + { m_solutions.push_back (currentSolution); + return true; + } + } + else + { // Try find solutions by splitting the ring in various positions. + if (isZero (r1 - r0)) + return false; + + double interval; + + // Determine interval. The smaller delta between radii, the more precise + // interval should be used. We can't really use a 0.5 increment when + // calculating rings to 10 -> 105... that would take ages to process! + if (r1 - r0 < 0.5) + interval = 0.1; + else if (r1 - r0 < 10) + interval = 0.5; + else if (r1 - r0 < 50) + interval = 1; + else + interval = 5; + + // Now go through possible splits and try find rings for both segments. + for (double r = r0 + interval; r < r1; r += interval) + { Solution sol = currentSolution; + + m_stack++; + bool res = findRingsRecursor (r0, r, sol) && findRingsRecursor (r, r1, sol); + m_stack--; + + if (res) + { // We succeeded in finding radii for this segment. If the stack is 0, this + // is the first recursion to this function. Thus there are no more ring segments + // to process and we can add the solution. + // + // If not, when this function ends, it will be called again with more arguments. + // Accept the solution to this segment by setting currentSolution to sol, and + // return true to continue processing. + if (m_stack == 0) + m_solutions.push_back (sol); + else + { currentSolution = sol; + return true; + } + } + } + + return false; + } + + return true; +} + +// ============================================================================= +// Main function. Call this with r0 and r1. If this returns true, use bestSolution +// for the solution that was presented. +// ----------------------------------------------------------------------------- +bool RingFinder::findRings (double r0, double r1) +{ m_solutions.clear(); + Solution sol; + + // Recurse in and try find solutions. + findRingsRecursor (r0, r1, sol); + + // Compare the solutions and find the best one. The solution class has an operator> + // overload to compare two solutions. + m_bestSolution = null; + + for (QVector<Solution>::iterator solp = m_solutions.begin(); solp != m_solutions.end(); ++solp) + { const Solution& sol = *solp; + + if (m_bestSolution == null || sol > *m_bestSolution) + m_bestSolution = / + } + + return (m_bestSolution != null); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +bool RingFinder::Solution::operator> (const RingFinder::Solution& other) const +{ // If this solution has less components than the other one, this one + // is definitely better. + if (components().size() < other.components().size()) + return true; + + // vice versa + if (other.components().size() < components().size()) + return false; + + // Calculate the maximum ring number. Since the solutions have equal + // ring counts, the solutions with lesser maximum rings should result + // in cleaner code and less new primitives, right? + int maxA = 0, + maxB = 0; + + for (int i = 0; i < components().size(); ++i) + { if (components()[i].num > maxA) + maxA = components()[i].num; + + if (other.components()[i].num > maxB) + maxB = other.components()[i].num; + } + + if (maxA < maxB) + return true; + + if (maxB < maxA) + return false; + + // Solutions have equal rings and equal maximum ring numbers. Let's + // just say this one is better, at this point it does not matter which + // one is chosen. + return true; +}
--- a/src/misc.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/misc.h Wed Oct 23 12:46:10 2013 +0300 @@ -19,6 +19,7 @@ #ifndef MISC_H #define MISC_H +#include <QVector> #include "config.h" #include "common.h" #include "types.h" @@ -29,105 +30,160 @@ class QAction; // Prime numbers -extern const ushort g_primes[NUM_PRIMES]; +extern const int g_primes[NUM_PRIMES]; // Returns whether a given string represents a floating point number. -bool isNumber (const str& tok); - -// Converts a float value to a string value. -str ftoa (double num); - -double atof (str val); +bool numeric (const str& tok); // Simplifies the given fraction. -void simplify (short& numer, short& denom); +void simplify (int& numer, int& denom); str join (initlist<StringFormatArg> vals, str delim = " "); // Grid stuff -typedef struct { - const char* const name; +struct gridinfo +{ const char* const name; FloatConfig* const confs[4]; -} gridinfo; +}; extern_cfg (Int, grid); -static const short g_NumGrids = 3; +static const int g_NumGrids = 3; extern const gridinfo g_GridInfo[3]; -inline const gridinfo& currentGrid() { - return g_GridInfo[grid]; +inline const gridinfo& currentGrid() +{ return g_GridInfo[grid]; } // ============================================================================= enum RotationPoint -{ - ObjectOrigin, +{ ObjectOrigin, WorldOrigin, CustomPoint }; -vertex rotPoint (const List<LDObject*>& objs); +vertex rotPoint (const QList<LDObject*>& objs); void configRotationPoint(); -template<class T, class R> R container_cast (const T& a) { - R b; - - for (auto i : a) - b << i; - - return b; -} - // ============================================================================= -namespace Grid { - enum Type { - Coarse, +namespace Grid +{ enum Type + { Coarse, Medium, Fine }; - - enum Config { - X, + + enum Config + { X, Y, Z, Angle }; - + double snap (double value, const Grid::Config axis); } // ============================================================================= -template<class T> void dataswap (T& a, T& b) { - T c = a; +// RingFinder +// +// Provides an algorithm for finding a solution of rings between radii r0 and r1. +// ============================================================================= +class RingFinder +{ public: + struct Component + { int num; + double scale; + }; + + class Solution + { public: + // Components of this solution + inline const QVector<Component>& components() const + { return m_components; + } + + // Add a component to this solution + void addComponent (const Component& a) + { m_components.push_back (a); + } + + // Compare solutions + bool operator> (const Solution& other) const; + + private: + QVector<Component> m_components; + }; + + RingFinder() {} + bool findRings (double r0, double r1); + + inline const Solution* bestSolution() + { return m_bestSolution; + } + + inline const QVector<Solution>& allSolutions() const + { return m_solutions; + } + + inline bool operator() (double r0, double r1) + { return findRings (r0, r1); + } + +private: + QVector<Solution> m_solutions; + const Solution* m_bestSolution; + int m_stack; + + bool findRingsRecursor (double r0, double r1, Solution& currentSolution); +}; + +extern RingFinder g_RingFinder; + +// ============================================================================= +template<class T> void dataswap (T& a, T& b) +{ T c = a; a = b; b = c; } // ----------------------------------------------------------------------------- // Plural expression -template<class T> static inline const char* plural (T n) { - return (n != 1) ? "s" : ""; +template<class T> static inline const char* plural (T n) +{ return (n != 1) ? "s" : ""; } // ----------------------------------------------------------------------------- // Templated clamp -template<class T> static inline T clamp (T a, T min, T max) { - return (a > max) ? max : (a < min) ? min : a; +template<class T> static inline T clamp (T a, T min, T max) +{ return (a > max) ? max : (a < min) ? min : a; } // Templated minimum -template<class T> static inline T min (T a, T b) { - return (a < b) ? a : b; +template<class T> static inline T min (T a, T b) +{ return (a < b) ? a : b; } // Templated maximum -template<class T> static inline T max (T a, T b) { - return (a > b) ? a : b; +template<class T> static inline T max (T a, T b) +{ return (a > b) ? a : b; } // Templated absolute value -template<class T> static inline T abs (T a) { - return (a >= 0) ? a : -a; +template<class T> static inline T abs (T a) +{ return (a >= 0) ? a : -a; +} + +template<class T> inline bool isZero (T a) +{ return abs<T> (a) < 0.0001; } -#endif // MISC_H \ No newline at end of file +template<class T> inline bool isInteger (T a) +{ return isZero (a - (int) a); +} + +template<class T> void removeDuplicates (QList<T>& a) +{ std::sort (a.begin(), a.end()); + typename QList<T>::iterator pos = std::unique (a.begin(), a.end()); + a.erase (pos, a.end()); +} + +#endif // MISC_H
--- a/src/primitives.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/primitives.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -26,16 +26,16 @@ #include "ui_makeprim.h" #include "misc.h" #include "colors.h" +#include "moc_primitives.cpp" -List<PrimitiveCategory> g_PrimitiveCategories; +QList<PrimitiveCategory> g_PrimitiveCategories; +QList<Primitive> g_primitives; static PrimitiveLister* g_activePrimLister = null; static bool g_primListerMutex = false; -List<Primitive> g_primitives; - static const str g_Other = PrimitiveLister::tr ("Other"); -static const str g_radialNameRoots[] = { - "edge", +static const str g_radialNameRoots[] = +{ "edge", "cyli", "disc", "ndis", @@ -48,43 +48,44 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void loadPrimitives() { - print ("Loading primitives...\n"); +void loadPrimitives() +{ log ("Loading primitives...\n"); loadPrimitiveCatgories(); - + // Try to load prims.cfg File conf (Config::filepath ("prims.cfg"), File::Read); - - if (!conf) { - // No prims.cfg, build it + + if (!conf) + { // No prims.cfg, build it PrimitiveLister::start(); - } else { - // Read primitives from prims.cfg - for (str line : conf) { - int space = line.indexOf (" "); - + } + else + { // Read primitives from prims.cfg + for (str line : conf) + { int space = line.indexOf (" "); + if (space == -1) continue; - + Primitive info; info.name = line.left (space); info.title = line.mid (space + 1); g_primitives << info; } - + populateCategories(); } } // ============================================================================= // ----------------------------------------------------------------------------- -static void recursiveGetFilenames (QDir dir, List<str>& fnames) { - QFileInfoList flist = dir.entryInfoList(); - - for (const QFileInfo & info : flist) { - if (info.fileName() == "." || info.fileName() == "..") +static void recursiveGetFilenames (QDir dir, QList<str>& fnames) +{ QFileInfoList flist = dir.entryInfoList(); + +for (const QFileInfo & info : flist) + { if (info.fileName() == "." || info.fileName() == "..") continue; // skip . and .. - + if (info.isDir()) recursiveGetFilenames (QDir (info.absoluteFilePath()), fnames); else @@ -94,49 +95,49 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void PrimitiveLister::work() { - g_activePrimLister = this; +void PrimitiveLister::work() +{ g_activePrimLister = this; m_prims.clear(); - + QDir dir (LDPaths::prims()); - ulong baselen = dir.absolutePath().length(); - ulong i = 0; - List<str> fnames; - + int baselen = dir.absolutePath().length(); + int i = 0; + QList<str> fnames; + assert (dir.exists()); recursiveGetFilenames (dir, fnames); emit starting (fnames.size()); - - for (str fname : fnames) { - File f (fname, File::Read); - + +for (str fname : fnames) + { File f (fname, File::Read); + Primitive info; info.name = fname.mid (baselen + 1); // make full path relative info.name.replace ('/', '\\'); // use DOS backslashes, they're expected info.cat = null; - + if (!f.readLine (info.title)) info.title = ""; - + info.title = info.title.simplified(); - - if (info.title[0] == '0') { - info.title.remove (0, 1); // remove 0 + + if (info.title[0] == '0') + { info.title.remove (0, 1); // remove 0 info.title = info.title.simplified(); } - + m_prims << info; emit update (++i); } - + // Save to a config file File conf (Config::filepath ("prims.cfg"), File::Write); - - for (Primitive & info : m_prims) + +for (Primitive & info : m_prims) fprint (conf, "%1 %2\n", info.name, info.title); - + conf.close(); - + g_primListerMutex = true; g_primitives = m_prims; populateCategories(); @@ -147,15 +148,15 @@ // ============================================================================= // ----------------------------------------------------------------------------- -void PrimitiveLister::start() { - if (g_activePrimLister) +void PrimitiveLister::start() +{ if (g_activePrimLister) return; - + PrimitiveLister* lister = new PrimitiveLister; QThread* listerThread = new QThread; lister->moveToThread (listerThread); - connect (lister, SIGNAL (starting (ulong)), g_win, SLOT (primitiveLoaderStart (ulong))); - connect (lister, SIGNAL (update (ulong)), g_win, SLOT (primitiveLoaderUpdate (ulong))); + connect (lister, SIGNAL (starting (int)), g_win, SLOT (primitiveLoaderStart (int))); + connect (lister, SIGNAL (update (int)), g_win, SLOT (primitiveLoaderUpdate (int))); connect (lister, SIGNAL (workDone()), g_win, SLOT (primitiveLoaderEnd())); connect (listerThread, SIGNAL (started()), lister, SLOT (work())); connect (listerThread, SIGNAL (finished()), lister, SLOT (deleteLater())); @@ -164,60 +165,61 @@ // ============================================================================= // ----------------------------------------------------------------------------- -static PrimitiveCategory* findCategory (str name) { - for (PrimitiveCategory& cat : g_PrimitiveCategories) +static PrimitiveCategory* findCategory (str name) +{ for (PrimitiveCategory & cat : g_PrimitiveCategories) if (cat.name() == name) return &cat; - + return null; } // ============================================================================= // ----------------------------------------------------------------------------- -static void populateCategories() { - for (PrimitiveCategory& cat : g_PrimitiveCategories) +static void populateCategories() +{ for (PrimitiveCategory & cat : g_PrimitiveCategories) cat.prims.clear(); - + PrimitiveCategory* unmatched = findCategory (g_Other); - - if (!unmatched) { - // Shouldn't happen.. but catch it anyway. + + if (!unmatched) + { // Shouldn't happen.. but catch it anyway. PrimitiveCategory cat; cat.setName (g_Other); - unmatched = & (g_PrimitiveCategories << cat); + g_PrimitiveCategories << cat; + unmatched = &g_PrimitiveCategories.last(); } - - for (Primitive& prim : g_primitives) { - bool matched = false; + + for (Primitive & prim : g_primitives) + { bool matched = false; prim.cat = null; - + // Go over the categories and their regexes, if and when there's a match, // the primitive's category is set to the category the regex beloings to. - for (PrimitiveCategory& cat : g_PrimitiveCategories) { - for (PrimitiveCategory::RegexEntry& entry : cat.regexes) { - switch (entry.type) { - case PrimitiveCategory::Filename: - // f-regex, check against filename - matched = entry.regex.exactMatch (prim.name); - break; - - case PrimitiveCategory::Title: - // t-regex, check against title - matched = entry.regex.exactMatch (prim.title); - break; + for (PrimitiveCategory& cat : g_PrimitiveCategories) + { for (PrimitiveCategory::RegexEntry& entry : cat.regexes) + { switch (entry.type) + { case PrimitiveCategory::Filename: + // f-regex, check against filename + matched = entry.regex.exactMatch (prim.name); + break; + + case PrimitiveCategory::Title: + // t-regex, check against title + matched = entry.regex.exactMatch (prim.title); + break; } - - if (matched) { - prim.cat = &cat; + + if (matched) + { prim.cat = &cat; break; } } - + // Drop out if a category was decided on. if (prim.cat) break; } - + // If there was a match, add the primitive to the category. // Otherwise, add it to the list of unmatched primitives. if (prim.cat) @@ -229,53 +231,55 @@ // ============================================================================= // ----------------------------------------------------------------------------- -static void loadPrimitiveCatgories() { - g_PrimitiveCategories.clear(); +static void loadPrimitiveCatgories() +{ g_PrimitiveCategories.clear(); File f (Config::dirpath() + "primregexps.cfg", File::Read); - + if (!f) f.open (":/data/primitive-categories.cfg", File::Read); - + if (!f) critical (QObject::tr ("Failed to open primitive categories!")); - - if (f) { - PrimitiveCategory cat; - - for (str line : f) { - int colon; - + + if (f) + { PrimitiveCategory cat; + + for (str line : f) + { int colon; + if (line.length() == 0 || line[0] == '#') continue; - - if ((colon = line.indexOf (":")) == -1) { - if (cat.regexes.size() > 0) + + if ( (colon = line.indexOf (":")) == -1) + { if (cat.regexes.size() > 0) g_PrimitiveCategories << cat; - + cat.regexes.clear(); cat.prims.clear(); cat.setName (line); - } else { - str cmd = line.left (colon); + } + else + { str cmd = line.left (colon); PrimitiveCategory::Type type = PrimitiveCategory::Filename; - + if (cmd == "f") type = PrimitiveCategory::Filename; + elif (cmd == "t") - type = PrimitiveCategory::Title; + type = PrimitiveCategory::Title; else continue; - + QRegExp regex (line.mid (colon + 1)); PrimitiveCategory::RegexEntry entry = { regex, type }; cat.regexes << entry; } } - + if (cat.regexes.size() > 0) g_PrimitiveCategories << cat; } - + // Add a category for unmatched primitives PrimitiveCategory cat; cat.setName (g_Other); @@ -284,113 +288,126 @@ // ============================================================================= // ----------------------------------------------------------------------------- -bool primitiveLoaderBusy() { - return g_primListerMutex; +bool primitiveLoaderBusy() +{ return g_primListerMutex; } // ============================================================================= // ----------------------------------------------------------------------------- -static double radialPoint (int i, int divs, double (*func) (double)) { - return (*func) ((i * 2 * pi) / divs); +static double radialPoint (int i, int divs, double (*func) (double)) +{ return (*func) ( (i * 2 * pi) / divs); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void makeCircle (int segs, int divs, double radius, QList<QLineF>& lines) +{ for (int i = 0; i < segs; ++i) + { double x0 = radius * radialPoint (i, divs, cos), + x1 = radius * radialPoint (i + 1, divs, cos), + z0 = radius * radialPoint (i, divs, sin), + z1 = radius * radialPoint (i + 1, divs, sin); + + lines << QLineF (QPointF (x0, z0), QPointF (x1, z1)); + } } // ============================================================================= // ----------------------------------------------------------------------------- -List<LDObject*> makePrimitive (PrimitiveType type, int segs, int divs, int num) { - List<LDObject*> objs; - List<int> condLineSegs; - - for (int i = 0; i < segs; ++i) { - double x0 = radialPoint (i, divs, cos), - x1 = radialPoint (i + 1, divs, cos), - z0 = radialPoint (i, divs, sin), - z1 = radialPoint (i + 1, divs, sin); - - switch (type) { - case Circle: { - vertex v0 (x0, 0.0f, z0), - v1 (x1, 0.0f, z1); - - LDLine* line = new LDLine; - line->setVertex (0, v0); - line->setVertex (1, v1); - line->setColor (edgecolor); - objs << line; - } - break; - - case Cylinder: - case Ring: - case Cone: - { - double x2, x3, z2, z3; +QList<LDObject*> makePrimitive (PrimitiveType type, int segs, int divs, int num) +{ QList<LDObject*> objs; + QList<int> condLineSegs; + QList<QLineF> circle; + + makeCircle (segs, divs, 1, circle); + + for (int i = 0; i < segs; ++i) + { double x0 = circle[i].x1(), + x1 = circle[i].x2(), + z0 = circle[i].y1(), + z1 = circle[i].y2(); + + switch (type) + { case Circle: + { vertex v0 (x0, 0.0f, z0), + v1 (x1, 0.0f, z1); + + LDLine* line = new LDLine; + line->setVertex (0, v0); + line->setVertex (1, v1); + line->setColor (edgecolor); + objs << line; + } break; + + case Cylinder: + case Ring: + case Cone: + { double x2, x3, z2, z3; double y0, y1, y2, y3; - - if (type == Cylinder) { - x2 = x1; + + if (type == Cylinder) + { x2 = x1; x3 = x0; z2 = z1; z3 = z0; - + y0 = y1 = 0.0f; y2 = y3 = 1.0f; - } else { - x2 = x1 * (num + 1); + } + else + { x2 = x1 * (num + 1); x3 = x0 * (num + 1); z2 = z1 * (num + 1); z3 = z0 * (num + 1); - + x0 *= num; x1 *= num; z0 *= num; z1 *= num; - + if (type == Ring) y0 = y1 = y2 = y3 = 0.0f; - else { - y0 = y1 = 1.0f; + else + { y0 = y1 = 1.0f; y2 = y3 = 0.0f; } } - + vertex v0 (x0, y0, z0), - v1 (x1, y1, z1), - v2 (x2, y2, z2), - v3 (x3, y3, z3); - + v1 (x1, y1, z1), + v2 (x2, y2, z2), + v3 (x3, y3, z3); + LDQuad* quad = new LDQuad; quad->setColor (maincolor); quad->setVertex (0, v0); quad->setVertex (1, v1); quad->setVertex (2, v2); quad->setVertex (3, v3); - + if (type == Cylinder) quad->invert(); - + objs << quad; - + if (type == Cylinder || type == Cone) condLineSegs << i; - } - break; - - case Disc: - case DiscNeg: - { - double x2, z2; - + } break; + + case Disc: + case DiscNeg: + { double x2, z2; + if (type == Disc) x2 = z2 = 0.0f; - else { - x2 = (x0 >= 0.0f) ? 1.0f : -1.0f; + else + { x2 = (x0 >= 0.0f) ? 1.0f : -1.0f; z2 = (z0 >= 0.0f) ? 1.0f : -1.0f; } - + vertex v0 (x0, 0.0f, z0), - v1 (x1, 0.0f, z1), - v2 (x2, 0.0f, z2); - + v1 (x1, 0.0f, z1), + v2 (x2, 0.0f, z2); + // Disc negatives need to go the other way around, otherwise // they'll end up upside-down. LDTriangle* seg = new LDTriangle; @@ -399,34 +416,31 @@ seg->setVertex (1, v1); seg->setVertex (type == Disc ? 2 : 0, v2); objs << seg; - } - break; - - default: - break; + } break; } } - + // If this is not a full circle, we need a conditional line at the other // end, too. if (segs < divs && condLineSegs.size() != 0) condLineSegs << segs; - - for (int i : condLineSegs) { - vertex v0 (radialPoint (i, divs, cos), 0.0f, radialPoint (i, divs, sin)), - v1, - v2 (radialPoint (i + 1, divs, cos), 0.0f, radialPoint (i + 1, divs, sin)), - v3 (radialPoint (i - 1, divs, cos), 0.0f, radialPoint (i - 1, divs, sin)); - + +for (int i : condLineSegs) + { vertex v0 (radialPoint (i, divs, cos), 0.0f, radialPoint (i, divs, sin)), + v1, + v2 (radialPoint (i + 1, divs, cos), 0.0f, radialPoint (i + 1, divs, sin)), + v3 (radialPoint (i - 1, divs, cos), 0.0f, radialPoint (i - 1, divs, sin)); + if (type == Cylinder) v1 = vertex (v0[X], 1.0f, v0[Z]); - elif (type == Cone) { - v1 = vertex (v0[X] * (num + 1), 0.0f, v0[Z] * (num + 1)); + + elif (type == Cone) + { v1 = vertex (v0[X] * (num + 1), 0.0f, v0[Z] * (num + 1)); v0[X] *= num; v0[Y] = 1.0f; v0[Z] *= num; } - + LDCndLine* line = new LDCndLine; line->setColor (edgecolor); line->setVertex (0, v0); @@ -435,60 +449,141 @@ line->setVertex (3, v3); objs << line; } - + return objs; } // ============================================================================= // ----------------------------------------------------------------------------- -static str primitiveTypeName (PrimitiveType type) { - // Not translated as primitives are in English. +static str primitiveTypeName (PrimitiveType type) +{ // Not translated as primitives are in English. return type == Circle ? "Circle" : - type == Cylinder ? "Cylinder" : - type == Disc ? "Disc" : - type == DiscNeg ? "Disc Negative" : - type == Ring ? "Ring" : "Cone"; + type == Cylinder ? "Cylinder" : + type == Disc ? "Disc" : + type == DiscNeg ? "Disc Negative" : + type == Ring ? "Ring" : "Cone"; } // ============================================================================= // ----------------------------------------------------------------------------- -str radialFileName (PrimitiveType type, int segs, int divs, int num) { - short numer = segs, - denom = divs; - +str radialFileName (PrimitiveType type, int segs, int divs, int num) +{ int numer = segs, + denom = divs; + // Simplify the fractional part, but the denominator must be at least 4. simplify (numer, denom); - - if (denom < 4) { - const short factor = 4 / denom; - + + if (denom < 4) + { const int factor = 4 / denom; numer *= factor; denom *= factor; } - + // Compose some general information: prefix, fraction, root, ring number str prefix = (divs == lores) ? "" : fmt ("%1/", divs); str frac = fmt ("%1-%2", numer, denom); str root = g_radialNameRoots[type]; str numstr = (type == Ring || type == Cone) ? fmt ("%1", num) : ""; - + // Truncate the root if necessary (7-16rin4.dat for instance). // However, always keep the root at least 2 characters. int extra = (frac.length() + numstr.length() + root.length()) - 8; - root.chop (min<short> (max<short> (extra, 0), 2)); - + root.chop (clamp (extra, 0, 2)); + // Stick them all together and return the result. return prefix + frac + root + numstr + ".dat"; } // ============================================================================= // ----------------------------------------------------------------------------- -void generatePrimitive() { - PrimitivePrompt* dlg = new PrimitivePrompt (g_win); - +LDFile* generatePrimitive (PrimitiveType type, int segs, int divs, int num) +{ // Make the description + str frac = str::number ((float) segs / divs); + str name = radialFileName (type, segs, divs, num); + str descr; + + // Ensure that there's decimals, even if they're 0. + if (frac.indexOf (".") == -1) + frac += ".0"; + + if (type == Ring || type == Cone) + { str spacing = + (num < 10) ? " " : + (num < 100) ? " " : ""; + + descr = fmt ("%1 %2%3 x %4", primitiveTypeName (type), spacing, num, frac); + } + else + descr = fmt ("%1 %2", primitiveTypeName (type), frac); + + // Prepend "Hi-Res" if 48/ primitive. + if (divs == hires) + descr.insert (0, "Hi-Res "); + + LDFile* f = new LDFile; + f->setDefaultName (name); + + f->addObjects ( + { new LDComment (descr), + new LDComment (fmt ("Name: %1", name)), + new LDComment (fmt ("Author: LDForge")), + new LDComment (fmt ("!LDRAW_ORG Unofficial_%1Primitive", divs == hires ? "48_" : "")), + new LDComment (CALicense), + new LDEmpty, + new LDBFC (LDBFC::CertifyCCW), + new LDEmpty, + }); + + f->addObjects (makePrimitive (type, segs, divs, num)); + return f; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +LDFile* getPrimitive (PrimitiveType type, int segs, int divs, int num) +{ str name = radialFileName (type, segs, divs, num); + LDFile* f = getFile (name); + + if (f != null) + return f; + + return generatePrimitive (type, segs, divs, num); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +PrimitivePrompt::PrimitivePrompt (QWidget* parent, Qt::WindowFlags f) : + QDialog (parent, f) +{ ui = new Ui_MakePrimUI; + ui->setupUi (this); + connect (ui->cb_hires, SIGNAL (toggled (bool)), this, SLOT (hiResToggled (bool))); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +PrimitivePrompt::~PrimitivePrompt() +{ delete ui; +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +void PrimitivePrompt::hiResToggled (bool on) +{ ui->sb_segs->setMaximum (on ? hires : lores); + + // If the current value is 16 and we switch to hi-res, default the + // spinbox to 48. + if (on && ui->sb_segs->value() == lores) + ui->sb_segs->setValue (hires); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +DEFINE_ACTION (MakePrimitive, 0) +{ PrimitivePrompt* dlg = new PrimitivePrompt (g_win); + if (!dlg->exec()) return; - + int segs = dlg->ui->sb_segs->value(); int divs = dlg->ui->cb_hires->isChecked() ? hires : lores; int num = dlg->ui->sb_ringnum->value(); @@ -498,73 +593,9 @@ dlg->ui->rb_disc->isChecked() ? Disc : dlg->ui->rb_ndisc->isChecked() ? DiscNeg : dlg->ui->rb_ring->isChecked() ? Ring : Cone; - - // Make the description - str frac = ftoa (((float) segs) / divs); - str name = radialFileName (type, segs, divs, num); - str descr; - - // Ensure that there's decimals, even if they're 0. - if (frac.indexOf (".") == -1) - frac += ".0"; - - if (type == Ring || type == Cone) { - str spacing = - (num < 10 ) ? " " : - (num < 100) ? " " : ""; - - descr = fmt ("%1 %2%3 x %4", primitiveTypeName (type), spacing, num, frac); - } else - descr = fmt ("%1 %2", primitiveTypeName (type), frac); - - // Prepend "Hi-Res" if 48/ primitive. - if (divs == hires) - descr.insert (0, "Hi-Res "); - - LDFile* f = new LDFile; - f->setName (QFileDialog::getSaveFileName (null, QObject::tr ("Save Primitive"), name)); - - f->addObjects ({ - new LDComment (descr), - new LDComment (fmt ("Name: %1", name)), - new LDComment (fmt ("Author: LDForge")), - new LDComment (fmt ("!LDRAW_ORG Unofficial_%1Primitive", divs == hires ? "48_" : "")), - new LDComment (CALicense), - new LDEmpty, - new LDBFC (LDBFC::CertifyCCW), - new LDEmpty, - }); - - f->addObjects (makePrimitive (type, segs, divs, num)); - + + LDFile* f = generatePrimitive (type, segs, divs, num); + g_win->save (f, false); delete f; } - -// ============================================================================= -// ----------------------------------------------------------------------------- -PrimitivePrompt::PrimitivePrompt (QWidget* parent, Qt::WindowFlags f) : - QDialog (parent, f) { - - ui = new Ui_MakePrimUI; - ui->setupUi (this); - connect (ui->cb_hires, SIGNAL (toggled(bool)), this, SLOT (hiResToggled (bool))); -} - -// ============================================================================= -// ----------------------------------------------------------------------------- -PrimitivePrompt::~PrimitivePrompt() { - delete ui; -} - -// ============================================================================= -// ----------------------------------------------------------------------------- -void PrimitivePrompt::hiResToggled (bool on) { - ui->sb_segs->setMaximum (on ? hires : lores); - - // If the current value is 16 and we switch to hi-res, default the - // spinbox to 48. - if (on && ui->sb_segs->value() == lores) - ui->sb_segs->setValue (hires); -} -#include "moc_primitives.cpp"
--- a/src/primitives.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/primitives.h Wed Oct 23 12:46:10 2013 +0300 @@ -16,77 +16,74 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef PRIMITIVES_H -#define PRIMITIVES_H +#ifndef LDFORGE_PRIMITIVES_H +#define LDFORGE_PRIMITIVES_H #include "common.h" #include "types.h" #include <QRegExp> #include <QDialog> +class LDFile; class Ui_MakePrimUI; class PrimitiveCategory; -struct Primitive { - str name, title; +struct Primitive +{ str name, title; PrimitiveCategory* cat; }; -class PrimitiveCategory { - PROPERTY (str, name, setName) - -public: - enum Type { - Filename, - Title - }; - - struct RegexEntry { - QRegExp regex; - Type type; - }; - - typedef List<RegexEntry>::it it; - typedef List<RegexEntry>::c_it c_it; - - List<RegexEntry> regexes; - List<Primitive> prims; - static List<Primitive> uncat; +class PrimitiveCategory +{ PROPERTY (str, name, setName) + + public: + enum Type + { Filename, + Title + }; + + struct RegexEntry + { QRegExp regex; + Type type; + }; + + QList<RegexEntry> regexes; + QList<Primitive> prims; + static QList<Primitive> uncat; }; // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= // PrimitiveLister -// +// // Worker object that scans the primitives folder for primitives and // builds an index of them. // ============================================================================= -class PrimitiveLister : public QObject { - Q_OBJECT - -public: - static void start(); - -public slots: - void work(); - -signals: - void starting (ulong num); - void workDone(); - void update (ulong i); - -private: - List<Primitive> m_prims; +class PrimitiveLister : public QObject +{ Q_OBJECT + + public: + static void start(); + + public slots: + void work(); + + signals: + void starting (int num); + void workDone(); + void update (int i); + + private: + QList<Primitive> m_prims; }; -extern List<PrimitiveCategory> g_PrimitiveCategories; +extern QList<PrimitiveCategory> g_PrimitiveCategories; void loadPrimitives(); bool primitiveLoaderBusy(); enum PrimitiveType -{ - Circle, +{ Circle, Cylinder, Disc, DiscNeg, @@ -95,18 +92,25 @@ }; // ============================================================================= -class PrimitivePrompt : public QDialog { - Q_OBJECT - -public: - explicit PrimitivePrompt (QWidget* parent = null, Qt::WindowFlags f = 0); - virtual ~PrimitivePrompt(); - Ui_MakePrimUI* ui; - -public slots: - void hiResToggled (bool on); +class PrimitivePrompt : public QDialog +{ Q_OBJECT + + public: + explicit PrimitivePrompt (QWidget* parent = null, Qt::WindowFlags f = 0); + virtual ~PrimitivePrompt(); + Ui_MakePrimUI* ui; + + public slots: + void hiResToggled (bool on); }; -void generatePrimitive(); +void makeCircle (int segs, int divs, double radius, QList<QLineF>& lines); +LDFile* generatePrimitive (PrimitiveType type, int segs, int divs, int num); -#endif // PRIMITIVES_H \ No newline at end of file +// Gets a primitive by the given specs. If the primitive cannot be found, it will +// be automatically generated. +LDFile* getPrimitive (PrimitiveType type, int segs, int divs, int num); + +str radialFileName (PrimitiveType type, int segs, int divs, int num); + +#endif // LDFORGE_PRIMITIVES_H
--- a/src/src.pro Wed Sep 25 11:02:44 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,19 +0,0 @@ -TARGET = ../ldforge -DEPENDPATH += . -INCLUDEPATH += . -RC_FILE = ../ldforge.rc -RESOURCES = ../ldforge.qrc -RCC_DIR = ./build/ -OBJECTS_DIR = ./build/ -MOC_DIR = ./build/ -RCC_DIR = ./build/ -SOURCES = *.cpp -HEADERS = *.h -FORMS = ui/*.ui -CONFIG += qt debug -QT += opengl network -QMAKE_CXXFLAGS += -std=c++0x - -unix { - LIBS += -lGLU -} \ No newline at end of file
--- a/src/types.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/types.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -29,59 +29,60 @@ // ============================================================================= // ----------------------------------------------------------------------------- -str DoFormat (List<StringFormatArg> args) { - assert (args.size() >= 1); +str DoFormat (QList<StringFormatArg> args) +{ assert (args.size() >= 1); str text = args[0].value(); - + for (uchar i = 1; i < args.size(); ++i) text = text.arg (args[i].value()); - + return text; } // ============================================================================= // ----------------------------------------------------------------------------- -vertex::vertex (double x, double y, double z) { - m_coords[X] = x; +vertex::vertex (double x, double y, double z) +{ m_coords[X] = x; m_coords[Y] = y; m_coords[Z] = z; } // ============================================================================= // ----------------------------------------------------------------------------- -void vertex::move (const vertex& other) { - for (const Axis ax : g_Axes) +void vertex::move (const vertex& other) +{ for (const Axis ax : g_Axes) m_coords[ax] += other[ax]; } // ============================================================================= // ----------------------------------------------------------------------------- -vertex vertex::midpoint (const vertex& other) { - vertex mid; - - for (const Axis ax : g_Axes) +vertex vertex::midpoint (const vertex& other) +{ vertex mid; + +for (const Axis ax : g_Axes) mid[ax] = (m_coords[ax] + other[ax]) / 2; - + return mid; } // ============================================================================= // ----------------------------------------------------------------------------- -str vertex::stringRep (bool mangled) const { - str fmtstr = "%1 %2 %3"; +str vertex::stringRep (bool mangled) const +{ str fmtstr = "%1 %2 %3"; + if (mangled) fmtstr = "(%1, %2, %3)"; - + return fmt (fmtstr, coord (X), coord (Y), coord (Z)); } // ============================================================================= // ----------------------------------------------------------------------------- -void vertex::transform (matrix matr, vertex pos) { - double x2 = (matr[0] * x()) + (matr[1] * y()) + (matr[2] * z()) + pos[X]; +void vertex::transform (matrix matr, vertex pos) +{ double x2 = (matr[0] * x()) + (matr[1] * y()) + (matr[2] * z()) + pos[X]; double y2 = (matr[3] * x()) + (matr[4] * y()) + (matr[5] * z()) + pos[Y]; double z2 = (matr[6] * x()) + (matr[7] * y()) + (matr[8] * z()) + pos[Z]; - + x() = x2; y() = y2; z() = z2; @@ -89,258 +90,268 @@ // ============================================================================= // ----------------------------------------------------------------------------- -vertex vertex::operator-() const { - return vertex (-m_coords[X], -m_coords[Y], -m_coords[Z]); +vertex vertex::operator-() const +{ return vertex (-m_coords[X], -m_coords[Y], -m_coords[Z]); } // ============================================================================= // ----------------------------------------------------------------------------- -bool vertex::operator!= (const vertex& other) const { - return !operator== (other); +bool vertex::operator!= (const vertex& other) const +{ return !operator== (other); } // ============================================================================= // ----------------------------------------------------------------------------- -double& vertex::operator[] (const Axis ax) { - return coord ((ushort) ax); +double& vertex::operator[] (const Axis ax) +{ return coord ( (int) ax); } -const double& vertex::operator[] (const Axis ax) const { - return coord ((ushort) ax); +const double& vertex::operator[] (const Axis ax) const +{ return coord ( (int) ax); } -double& vertex::operator[] (const int ax) { - return coord (ax); +double& vertex::operator[] (const int ax) +{ return coord (ax); } -const double& vertex::operator[] (const int ax) const { - return coord (ax); +const double& vertex::operator[] (const int ax) const +{ return coord (ax); } // ============================================================================= // ----------------------------------------------------------------------------- -bool vertex::operator== (const vertex& other) const { - return coord (X) == other[X] && - coord (Y) == other[Y] && - coord (Z) == other[Z]; +bool vertex::operator== (const vertex& other) const +{ return coord (X) == other[X] && + coord (Y) == other[Y] && + coord (Z) == other[Z]; } // ============================================================================= // ----------------------------------------------------------------------------- -vertex& vertex::operator/= (const double d) { - for (const Axis ax : g_Axes) +vertex& vertex::operator/= (const double d) +{ for (const Axis ax : g_Axes) m_coords[ax] /= d; - + return *this; } // ============================================================================= // ----------------------------------------------------------------------------- -vertex vertex::operator/ (const double d) const { - vertex other (*this); +vertex vertex::operator/ (const double d) const +{ vertex other (*this); return other /= d; } // ============================================================================= // ----------------------------------------------------------------------------- -vertex& vertex::operator+= (const vertex& other) { - move (other); +vertex& vertex::operator+= (const vertex& other) +{ move (other); return *this; } // ============================================================================= // ----------------------------------------------------------------------------- -vertex vertex::operator+ (const vertex& other) const { - vertex newvert (*this); +vertex vertex::operator+ (const vertex& other) const +{ vertex newvert (*this); newvert.move (other); return newvert; } // ============================================================================= // ----------------------------------------------------------------------------- -int vertex::operator< (const vertex& other) const { - if (operator== (other)) +int vertex::operator< (const vertex& other) const +{ if (operator== (other)) return false; - + if (coord (X) < other[X]) return true; - + if (coord (X) > other[X]) return false; - + if (coord (Y) < other[Y]) return true; - + if (coord (Y) > other[Y]) return false; - + return coord (Z) < other[Z]; } // ============================================================================= // ----------------------------------------------------------------------------- -matrix::matrix (double vals[]) { - for (short i = 0; i < 9; ++i) +matrix::matrix (double vals[]) +{ for (short i = 0; i < 9; ++i) m_vals[i] = vals[i]; } // ============================================================================= // ----------------------------------------------------------------------------- -matrix::matrix (double fillval) { - for (short i = 0; i < 9; ++i) +matrix::matrix (double fillval) +{ for (short i = 0; i < 9; ++i) m_vals[i] = fillval; } // ============================================================================= // ----------------------------------------------------------------------------- -matrix::matrix (initlist<double> vals) { - assert (vals.size() == 9); +matrix::matrix (initlist<double> vals) +{ assert (vals.size() == 9); memcpy (&m_vals[0], & (*vals.begin()), sizeof m_vals); } // ============================================================================= // ----------------------------------------------------------------------------- -void matrix::puts() const { - for (short i = 0; i < 3; ++i) { - for (short j = 0; j < 3; ++j) - print ("%1\t", m_vals[ (i * 3) + j]); - - print ("\n"); +void matrix::puts() const +{ for (short i = 0; i < 3; ++i) + { for (short j = 0; j < 3; ++j) + log ("%1\t", m_vals[ (i * 3) + j]); + + log ("\n"); } } // ============================================================================= // ----------------------------------------------------------------------------- -str matrix::stringRep() const { - str val; - - for (short i = 0; i < 9; ++i) { - if (i > 0) +str matrix::stringRep() const +{ str val; + + for (short i = 0; i < 9; ++i) + { if (i > 0) val += ' '; - - val += ftoa (m_vals[i]); + + val += str::number (m_vals[i]); } - + return val; } // ============================================================================= // ----------------------------------------------------------------------------- -void matrix::zero() { - memset (&m_vals[0], 0, sizeof m_vals); +void matrix::zero() +{ memset (&m_vals[0], 0, sizeof m_vals); } // ============================================================================= // ----------------------------------------------------------------------------- -matrix matrix::mult (matrix other) const { - matrix val; +matrix matrix::mult (matrix other) const +{ matrix val; val.zero(); - + for (short i = 0; i < 3; ++i) - for (short j = 0; j < 3; ++j) - for (short k = 0; k < 3; ++k) - val[ (i * 3) + j] += m_vals[(i * 3) + k] * other[(k * 3) + j]; - + for (short j = 0; j < 3; ++j) + for (short k = 0; k < 3; ++k) + val[ (i * 3) + j] += m_vals[ (i * 3) + k] * other[ (k * 3) + j]; + return val; } // ============================================================================= // ----------------------------------------------------------------------------- -matrix& matrix::operator= (matrix other) { - memcpy (&m_vals[0], &other.m_vals[0], sizeof m_vals); +matrix& matrix::operator= (matrix other) +{ memcpy (&m_vals[0], &other.m_vals[0], sizeof m_vals); return *this; } // ============================================================================= // ----------------------------------------------------------------------------- -double matrix::determinant() const { - return (val (0) * val (4) * val (8)) + - (val (1) * val (5) * val (6)) + - (val (2) * val (3) * val (7)) - - (val (2) * val (4) * val (6)) - - (val (1) * val (3) * val (8)) - - (val (0) * val (5) * val (7)); +double matrix::determinant() const +{ return (val (0) * val (4) * val (8)) + + (val (1) * val (5) * val (6)) + + (val (2) * val (3) * val (7)) - + (val (2) * val (4) * val (6)) - + (val (1) * val (3) * val (8)) - + (val (0) * val (5) * val (7)); +} + +// ============================================================================= +// ----------------------------------------------------------------------------- +bool matrix::operator== (const matrix& other) const +{ for (int i = 0; i < 9; ++i) + if (val (i) != other[i]) + return false; + + return true; } // ============================================================================= // ----------------------------------------------------------------------------- -StringFormatArg::StringFormatArg (const str& v) { - m_val = v; +StringFormatArg::StringFormatArg (const str& v) +{ m_val = v; } -StringFormatArg::StringFormatArg (const char& v) { - m_val = v; +StringFormatArg::StringFormatArg (const char& v) +{ m_val = v; } -StringFormatArg::StringFormatArg (const uchar& v) { - m_val = v; +StringFormatArg::StringFormatArg (const uchar& v) +{ m_val = v; } -StringFormatArg::StringFormatArg (const qchar& v) { - m_val = v; +StringFormatArg::StringFormatArg (const qchar& v) +{ m_val = v; } -StringFormatArg::StringFormatArg (const float& v) { - m_val = ftoa (v); +StringFormatArg::StringFormatArg (const float& v) +{ m_val = str::number (v); } -StringFormatArg::StringFormatArg (const double& v) { - m_val = ftoa (v); +StringFormatArg::StringFormatArg (const double& v) +{ m_val = str::number (v); } -StringFormatArg::StringFormatArg (const vertex& v) { - m_val = v.stringRep (false); +StringFormatArg::StringFormatArg (const vertex& v) +{ m_val = v.stringRep (false); } -StringFormatArg::StringFormatArg (const matrix& v) { - m_val = v.stringRep(); +StringFormatArg::StringFormatArg (const matrix& v) +{ m_val = v.stringRep(); } -StringFormatArg::StringFormatArg (const char* v) { - m_val = v; +StringFormatArg::StringFormatArg (const char* v) +{ m_val = v; } -StringFormatArg::StringFormatArg (const StringConfig& v) { - m_val = v.value; +StringFormatArg::StringFormatArg (const StringConfig& v) +{ m_val = v.value; } -StringFormatArg::StringFormatArg (const IntConfig& v) { - m_val.number (v.value); +StringFormatArg::StringFormatArg (const IntConfig& v) +{ m_val.number (v.value); } -StringFormatArg::StringFormatArg (const FloatConfig& v) { - m_val.number (v.value); +StringFormatArg::StringFormatArg (const FloatConfig& v) +{ m_val.number (v.value); } -StringFormatArg::StringFormatArg (const void* v) { - m_val.sprintf ("%p", v); +StringFormatArg::StringFormatArg (const void* v) +{ m_val.sprintf ("%p", v); } // ============================================================================= // ----------------------------------------------------------------------------- -File::File() { - // Make a null file +File::File() +{ // Make a null file m_file = null; m_textstream = null; } -File::File (str path, OpenType rtype) { - m_file = null; +File::File (str path, OpenType rtype) +{ m_file = null; open (path, rtype); } -File::File (FILE* fp, OpenType rtype) { - m_file = null; +File::File (FILE* fp, OpenType rtype) +{ m_file = null; open (fp, rtype); } // ============================================================================= // ----------------------------------------------------------------------------- -File::~File() { - if (m_file) { - m_file->close(); +File::~File() +{ if (m_file) + { m_file->close(); delete m_file; - + if (m_textstream) delete m_textstream; } @@ -348,34 +359,34 @@ // ============================================================================= // ----------------------------------------------------------------------------- -bool File::open (FILE* fp, OpenType rtype) { - return open ("", rtype, fp); +bool File::open (FILE* fp, OpenType rtype) +{ return open ("", rtype, fp); } -bool File::open (str path, OpenType rtype, FILE* fp) { - close(); - +bool File::open (str path, OpenType rtype, FILE* fp) +{ close(); + if (!m_file) m_file = new QFile; - + m_file->setFileName (path); - + bool result; - + QIODevice::OpenMode mode = - (rtype == Read) ? QIODevice::ReadOnly : - (rtype == Write) ? QIODevice::WriteOnly : QIODevice::Append; - + (rtype == Read) ? QIODevice::ReadOnly : + (rtype == Write) ? QIODevice::WriteOnly : QIODevice::Append; + if (fp) result = m_file->open (fp, mode); else result = m_file->open (mode); - - if (result) { - m_textstream = new QTextStream (m_file); + + if (result) + { m_textstream = new QTextStream (m_file); return true; } - + delete m_file; m_file = null; return false; @@ -383,222 +394,222 @@ // ============================================================================= // ----------------------------------------------------------------------------- -File::iterator File::begin() { - return iterator (this); +File::iterator File::begin() +{ return iterator (this); } -File::iterator& File::end() { - return m_endIterator; +File::iterator& File::end() +{ return m_endIterator; } // ============================================================================= // ----------------------------------------------------------------------------- -void File::write (str msg) { - m_file->write (msg.toUtf8(), msg.length()); +void File::write (str msg) +{ m_file->write (msg.toUtf8(), msg.length()); } // ============================================================================= // ----------------------------------------------------------------------------- -bool File::readLine (str& line) { - if (!m_textstream || m_textstream->atEnd()) +bool File::readLine (str& line) +{ if (!m_textstream || m_textstream->atEnd()) return false; - + line = m_textstream->readLine(); return true; } // ============================================================================= // ----------------------------------------------------------------------------- -bool File::atEnd() const { - if (!m_textstream) - fatal ("cannot use atEnd on a null file"); - +bool File::atEnd() const +{ assert (m_textstream != null); return m_textstream->atEnd(); } // ============================================================================= // ----------------------------------------------------------------------------- -bool File::isNull() const { - return m_file == null; +bool File::isNull() const +{ return m_file == null; } -bool File::operator!() const { - return isNull(); +bool File::operator!() const +{ return isNull(); } // ============================================================================= // ----------------------------------------------------------------------------- -void File::close() { - if (!m_file) +void File::close() +{ if (!m_file) return; - + delete m_file; m_file = null; - - if (m_textstream) { - delete m_textstream; + + if (m_textstream) + { delete m_textstream; m_textstream = null; } } // ============================================================================= // ----------------------------------------------------------------------------- -bool File::flush() { - return m_file->flush(); +bool File::flush() +{ return m_file->flush(); } // ============================================================================= // ----------------------------------------------------------------------------- -File::operator bool() const { - return !isNull(); +File::operator bool() const +{ return !isNull(); } // ============================================================================= // ----------------------------------------------------------------------------- -void File::rewind() { - m_file->seek (0); +void File::rewind() +{ m_file->seek (0); } // ============================================================================= // ----------------------------------------------------------------------------- -File::iterator::iterator (File* f) : m_file (f) { - operator++(); +File::iterator::iterator (File* f) : m_file (f) +{ operator++(); } // ============================================================================= // ----------------------------------------------------------------------------- -void File::iterator::operator++() { - m_gotdata = m_file->readLine (m_text); +void File::iterator::operator++() +{ m_gotdata = m_file->readLine (m_text); } // ============================================================================= // ----------------------------------------------------------------------------- -str File::iterator::operator*() { - return m_text; +str File::iterator::operator*() +{ return m_text; } // ============================================================================= // The prime contestant for the weirdest operator== 2013 award? // ----------------------------------------------------------------------------- -bool File::iterator::operator== (File::iterator& other) { - return (other.m_file == null && !m_gotdata); +bool File::iterator::operator== (File::iterator& other) +{ return (other.m_file == null && !m_gotdata); } // ============================================================================= // ----------------------------------------------------------------------------- -bool File::iterator::operator!= (File::iterator& other) { - return !operator== (other); +bool File::iterator::operator!= (File::iterator& other) +{ return !operator== (other); } // ============================================================================= // ----------------------------------------------------------------------------- -LDBoundingBox::LDBoundingBox() { - reset(); +LDBoundingBox::LDBoundingBox() +{ reset(); } // ============================================================================= // ----------------------------------------------------------------------------- -void LDBoundingBox::calculate() { - reset(); - +void LDBoundingBox::calculate() +{ reset(); + if (!LDFile::current()) return; - - for (LDObject* obj : LDFile::current()->objects()) + +for (LDObject * obj : LDFile::current()->objects()) calcObject (obj); } // ============================================================================= // ----------------------------------------------------------------------------- -void LDBoundingBox::calcObject (LDObject* obj) { - switch (obj->getType()) { - case LDObject::Line: - case LDObject::Triangle: - case LDObject::Quad: - case LDObject::CndLine: - for (short i = 0; i < obj->vertices(); ++i) - calcVertex (obj->getVertex (i)); - +void LDBoundingBox::calcObject (LDObject* obj) +{ switch (obj->getType()) + { case LDObject::Line: + case LDObject::Triangle: + case LDObject::Quad: + case LDObject::CndLine: + + for (short i = 0; i < obj->vertices(); ++i) + calcVertex (obj->getVertex (i)); + + break; + + case LDObject::Subfile: + { LDSubfile* ref = static_cast<LDSubfile*> (obj); + QList<LDObject*> objs = ref->inlineContents (LDSubfile::DeepCacheInline); + + for (LDObject * obj : objs) + { calcObject (obj); + delete obj; + } + } break; - case LDObject::Subfile: { - LDSubfile* ref = static_cast<LDSubfile*> (obj); - List<LDObject*> objs = ref->inlineContents (LDSubfile::DeepCacheInline); - - for (LDObject* obj : objs) { - calcObject (obj); - delete obj; - } - } - break; - - default: - break; + default: + break; } } // ============================================================================= // ----------------------------------------------------------------------------- -LDBoundingBox& LDBoundingBox::operator<< (const vertex& v) { - calcVertex (v); +LDBoundingBox& LDBoundingBox::operator<< (const vertex& v) +{ calcVertex (v); return *this; } // ============================================================================= // ----------------------------------------------------------------------------- -LDBoundingBox& LDBoundingBox::operator<< (LDObject* obj) { - calcObject (obj); +LDBoundingBox& LDBoundingBox::operator<< (LDObject* obj) +{ calcObject (obj); return *this; } // ============================================================================= // ----------------------------------------------------------------------------- -void LDBoundingBox::calcVertex (const vertex& v) { - for (const Axis ax : g_Axes) { - if (v[ax] < m_v0[ax]) +void LDBoundingBox::calcVertex (const vertex& v) +{ for (const Axis ax : g_Axes) + { if (v[ax] < m_v0[ax]) m_v0[ax] = v[ax]; - + if (v[ax] > m_v1[ax]) m_v1[ax] = v[ax]; } - + m_empty = false; } // ============================================================================= // ----------------------------------------------------------------------------- -void LDBoundingBox::reset() { - m_v0[X] = m_v0[Y] = m_v0[Z] = 0x7FFFFFFF; +void LDBoundingBox::reset() +{ m_v0[X] = m_v0[Y] = m_v0[Z] = 0x7FFFFFFF; m_v1[X] = m_v1[Y] = m_v1[Z] = 0xFFFFFFFF; - + m_empty = true; } // ============================================================================= // ----------------------------------------------------------------------------- -double LDBoundingBox::size() const { - double xscale = (m_v0[X] - m_v1[X]); +double LDBoundingBox::size() const +{ double xscale = (m_v0[X] - m_v1[X]); double yscale = (m_v0[Y] - m_v1[Y]); double zscale = (m_v0[Z] - m_v1[Z]); double size = zscale; - - if (xscale > yscale) { - if (xscale > zscale) + + if (xscale > yscale) + { if (xscale > zscale) size = xscale; } elif (yscale > zscale) - size = yscale; - + + size = yscale; + if (abs (size) >= 2.0f) return abs (size / 2); - + return 1.0f; } // ============================================================================= // ----------------------------------------------------------------------------- -vertex LDBoundingBox::center() const { - return vertex ( +vertex LDBoundingBox::center() const +{ return vertex ( (m_v0[X] + m_v1[X]) / 2, (m_v0[Y] + m_v1[Y]) / 2, (m_v0[Z] + m_v1[Z]) / 2); -} \ No newline at end of file +}
--- a/src/types.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/types.h Wed Oct 23 12:46:10 2013 +0300 @@ -28,8 +28,6 @@ typedef QChar qchar; typedef QString str; -template<class T> class ConstListReverser; -template<class T> using c_rev = ConstListReverser<T>; class StringConfig; class IntConfig; class FloatConfig; @@ -62,403 +60,233 @@ // // A mathematical 3 x 3 matrix // ============================================================================= -class matrix { -public: - matrix() {} - matrix (initlist<double> vals); - matrix (double fillval); - matrix (double vals[]); - - double determinant () const; - matrix mult (matrix other) const; - void puts () const; - str stringRep () const; - void zero (); - double& val (const uint idx) { return m_vals[idx]; } - const double& val (const uint idx) const { return m_vals[idx]; } - - matrix& operator= (matrix other); - matrix operator* (matrix other) const { return mult (other); } - double& operator[] (const uint idx) { return m_vals[idx]; } - const double& operator[] (const uint idx) const { return m_vals[idx]; } +class matrix +{ public: + matrix() {} + matrix (initlist<double> vals); + matrix (double fillval); + matrix (double vals[]); + + double determinant () const; + matrix mult (matrix other) const; + void puts () const; + str stringRep () const; + void zero (); + matrix& operator= (matrix other); + + inline double& val (int idx) + { return m_vals[idx]; + } -private: - double m_vals[9]; + inline const double& val (int idx) const + { return m_vals[idx]; + } + + inline matrix operator* (matrix other) const + { return mult (other); + } + + inline double& operator[] (int idx) + { return val (idx); + } + inline const double& operator[] (int idx) const + { return val (idx); + } + + bool operator== (const matrix& other) const; + + private: + double m_vals[9]; }; // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= // vertex -// +// // Vertex class, contains a single point in 3D space. Not to be confused with // LDVertex, which is a vertex used in an LDraw part file. // ============================================================================= -class vertex { -public: - vertex() {} - vertex (double x, double y, double z); - - double& coord (const ushort n) { return m_coords[n]; } - const double& coord (const ushort n) const { return m_coords[n]; } - vertex midpoint (const vertex& other); - void move (const vertex& other); - str stringRep (bool mangled) const; - void transform (matrix matr, vertex pos); - double& x () { return m_coords[X]; } - const double& x () const { return m_coords[X]; } - double& y () { return m_coords[Y]; } - const double& y () const { return m_coords[Y]; } - double& z () { return m_coords[Z]; } - const double& z () const { return m_coords[Z]; } - - vertex& operator+= (const vertex& other); - vertex operator+ (const vertex& other) const; - vertex operator/ (const double d) const; - vertex& operator/= (const double d); - bool operator== (const vertex& other) const; - bool operator!= (const vertex& other) const; - vertex operator- () const; - int operator< (const vertex& other) const; - double& operator[] (const Axis ax); - const double& operator[] (const Axis ax) const; - double& operator[] (const int ax); - const double& operator[] (const int ax) const; +class vertex +{ public: + vertex() {} + vertex (double x, double y, double z); + + vertex midpoint (const vertex& other); + void move (const vertex& other); + str stringRep (bool mangled) const; + void transform (matrix matr, vertex pos); + + inline double& coord (int n) + { return m_coords[n]; + } + + inline const double& coord (int n) const + { return m_coords[n]; + } + + inline double& x () + { return m_coords[X]; + } + + inline const double& x () const + { return m_coords[X]; + } -private: - double m_coords[3]; + inline double& y () + { return m_coords[Y]; + } + + inline const double& y () const + { return m_coords[Y]; + } + + inline double& z () + { return m_coords[Z]; + } + + inline const double& z () const + { return m_coords[Z]; + } + + vertex& operator+= (const vertex& other); + vertex operator+ (const vertex& other) const; + vertex operator/ (const double d) const; + vertex& operator/= (const double d); + bool operator== (const vertex& other) const; + bool operator!= (const vertex& other) const; + vertex operator- () const; + int operator< (const vertex& other) const; + double& operator[] (const Axis ax); + const double& operator[] (const Axis ax) const; + double& operator[] (const int ax); + const double& operator[] (const int ax) const; + + private: + double m_coords[3]; }; // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= -// List -// -// Array class that wraps around std::deque -// ============================================================================= -template<class T> class List { -public: - typedef typename std::deque<T>::iterator it; - typedef typename std::deque<T>::const_iterator c_it; - typedef typename std::deque<T>::reverse_iterator r_it; - typedef typename std::deque<T>::const_reverse_iterator cr_it; - - List() {} - List (initlist<T> vals) { - m_vect = vals; - } - - it begin() { - return m_vect.begin(); - } - - c_it begin() const { - return m_vect.cbegin(); - } - - it end() { - return m_vect.end(); - } - - c_it end() const { - return m_vect.cend(); - } - - r_it rbegin() { - return m_vect.rbegin(); - } - - cr_it crbegin() const { - return m_vect.crbegin(); - } - - r_it rend() { - return m_vect.rend(); - } - - cr_it crend() const { - return m_vect.crend(); - } - - void erase (ulong pos) { - assert (pos < size()); - m_vect.erase (m_vect.begin() + pos); - } - - T& push_back (const T& value) { - m_vect.push_back (value); - return m_vect[m_vect.size() - 1]; - } - - void push_back (const List<T>& vals) { - for (const T& val : vals) - push_back (val); - } - - bool pop (T& val) { - if (size() == 0) - return false; - - val = m_vect[size() - 1]; - erase (size() - 1); - return true; - } - - T& operator<< (const T& value) { - return push_back (value); - } - - void operator<< (const List<T>& vals) { - push_back (vals); - } - - bool operator>> (T& value) { - return pop (value); - } - - List<T> reverse() const { - List<T> rev; - - for (const T& val : c_rev<T> (*this)) - rev << val; - - return rev; - } - - void clear() { - m_vect.clear(); - } - - void insert (ulong pos, const T& value) { - m_vect.insert (m_vect.begin() + pos, value); - } - - void makeUnique() { - // Remove duplicate entries. For this to be effective, the List must be - // sorted first. - sort(); - it pos = std::unique (begin(), end()); - resize (std::distance (begin(), pos)); - } - - ulong size() const { - return m_vect.size(); - } - - T& operator[] (ulong n) { - assert (n < size()); - return m_vect[n]; - } - - const T& operator[] (ulong n) const { - assert (n < size()); - return m_vect[n]; - } - - void resize (std::ptrdiff_t size) { - m_vect.resize (size); - } - - void sort() { - std::sort (begin(), end()); - } - - ulong find (const T& needle) { - ulong i = 0; - for (const T& hay : *this) { - if (hay == needle) - return i; - - i++; - } - - return -1u; - } - -private: - std::deque<T> m_vect; -}; - -template<class T> static inline T& operator>> (const T& a, List<T>& b) { - b.insert (0, a); - return b; -} - -// ============================================================================= -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// ============================================================================= -// ListReverser (aka rev) -// -// Helper class used to reverse-iterate Lists in range-for-loops. -// ============================================================================= -template<class T> class ListReverser { -public: - typedef typename List<T>::r_it it; - - ListReverser (List<T>& vect) { - m_vect = &vect; - } - - it begin() { - return m_vect->rbegin(); - } - - it end() { - return m_vect->rend(); - } - -private: - List<T>* m_vect; -}; - -// ============================================================================= -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// ============================================================================= -// ConstListReverser (aka c_rev) -// -// Like ListReverser, except works on const Lists. -// ============================================================================= -template<class T> class ConstListReverser { -public: - typedef typename List<T>::cr_it it; - - ConstListReverser (const List<T>& vect) { - m_vect = &vect; - } - - it begin() const { - return m_vect->crbegin(); - } - - it end() const { - return m_vect->crend(); - } - -private: - const List<T>* m_vect; -}; - -template<class T> using rev = ListReverser<T>; -template<class T> using c_rev = ConstListReverser<T>; - -// ============================================================================= -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// ============================================================================= // StringFormatArg -// +// // Converts a given value into a string that can be retrieved with ::value(). // Used as the argument type to the formatting functions, hence its name. // ============================================================================= -class StringFormatArg { -public: - StringFormatArg (const str& v); - StringFormatArg (const char& v); - StringFormatArg (const uchar& v); - StringFormatArg (const qchar& v); - +class StringFormatArg +{ public: + StringFormatArg (const str& v); + StringFormatArg (const char& v); + StringFormatArg (const uchar& v); + StringFormatArg (const qchar& v); + #define NUMERIC_FORMAT_ARG(T,C) \ StringFormatArg (const T& v) { \ char valstr[32]; \ sprintf (valstr, "%" #C, v); \ m_val = valstr; \ } - - NUMERIC_FORMAT_ARG (int, d) - NUMERIC_FORMAT_ARG (short, d) - NUMERIC_FORMAT_ARG (long, ld) - NUMERIC_FORMAT_ARG (uint, u) - NUMERIC_FORMAT_ARG (ushort, u) - NUMERIC_FORMAT_ARG (ulong, lu) - - StringFormatArg (const float& v); - StringFormatArg (const double& v); - StringFormatArg (const vertex& v); - StringFormatArg (const matrix& v); - StringFormatArg (const char* v); - StringFormatArg (const StringConfig& v); - StringFormatArg (const IntConfig& v); - StringFormatArg (const FloatConfig& v); - StringFormatArg (const void* v); - - template<class T> StringFormatArg (const List<T>& v) { - m_val = "{ "; - - uint i = 0; - for (const T& it : v) { - if (i++) - m_val += ", "; - - StringFormatArg arg (it); - m_val += arg.value(); + + NUMERIC_FORMAT_ARG (int, d) + NUMERIC_FORMAT_ARG (short, d) + NUMERIC_FORMAT_ARG (long, ld) + NUMERIC_FORMAT_ARG (uint, u) + NUMERIC_FORMAT_ARG (ushort, u) + NUMERIC_FORMAT_ARG (ulong, lu) + + StringFormatArg (const float& v); + StringFormatArg (const double& v); + StringFormatArg (const vertex& v); + StringFormatArg (const matrix& v); + StringFormatArg (const char* v); + StringFormatArg (const StringConfig& v); + StringFormatArg (const IntConfig& v); + StringFormatArg (const FloatConfig& v); + StringFormatArg (const void* v); + + template<class T> StringFormatArg (const QList<T>& v) + { m_val = "{ "; + + int i = 0; + + for (const T& it : v) + { if (i++) + m_val += ", "; + + StringFormatArg arg (it); + m_val += arg.value(); + } + + if (i) + m_val += " "; + + m_val += "}"; } - - if (i) - m_val += " "; - - m_val += "}"; - } - - str value() const { return m_val; } -private: - str m_val; + + str value() const + { return m_val; + } + private: + str m_val; }; // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= // File -// +// // A file interface with simple interface and support for range-for-loops. // ============================================================================= -class File { -private: - // Iterator class to enable range-for-loop support. Rough hack.. don't use directly! - class iterator { +class File +{ private: + // Iterator class to enable range-for-loop support. Rough hack.. don't use directly! + class iterator + { public: + iterator() : m_file (null) {} // end iterator has m_file == null + iterator (File* f); + void operator++(); + str operator*(); + bool operator== (iterator& other); + bool operator!= (iterator& other); + + private: + File* m_file; + str m_text; + bool m_gotdata = false; + }; + public: - iterator() : m_file (null) {} // end iterator has m_file == null - iterator (File* f); - void operator++(); - str operator*(); - bool operator== (iterator& other); - bool operator!= (iterator& other); - - private: - File* m_file; - str m_text; - bool m_gotdata = false; - }; + enum OpenType + { Read, + Write, + Append + }; -public: - enum OpenType { - Read, - Write, - Append - }; - - File(); - File (str path, File::OpenType rtype); - File (FILE* fp, File::OpenType rtype); - ~File(); - - bool atEnd() const; - iterator begin(); - void close(); - iterator& end(); - bool flush(); - bool isNull() const; - bool readLine (str& line); - void rewind(); - bool open (FILE* fp, OpenType rtype); - bool open (str path, OpenType rtype, FILE* fp = null); - void write (str msg); - - bool operator!() const; - operator bool() const; - -private: - QFile* m_file; - QTextStream* m_textstream; - iterator m_endIterator; + File(); + File (str path, File::OpenType rtype); + File (FILE* fp, File::OpenType rtype); + ~File(); + + bool atEnd() const; + iterator begin(); + void close(); + iterator& end(); + bool flush(); + bool isNull() const; + bool readLine (str& line); + void rewind(); + bool open (FILE* fp, OpenType rtype); + bool open (str path, OpenType rtype, FILE* fp = null); + void write (str msg); + + bool operator!() const; + operator bool() const; + + private: + QFile* m_file; + QTextStream* m_textstream; + iterator m_endIterator; }; // ============================================================================= @@ -467,26 +295,26 @@ // The bounding box is the box that encompasses a given set of objects. // v0 is the minimum vertex, v1 is the maximum vertex. // ============================================================================= -class LDBoundingBox { - READ_PROPERTY (bool, empty, setEmpty) +class LDBoundingBox +{ READ_PROPERTY (bool, empty, setEmpty) READ_PROPERTY (vertex, v0, setV0) READ_PROPERTY (vertex, v1, setV1) - -public: - LDBoundingBox(); - void reset(); - void calculate(); - double size() const; - void calcObject (LDObject* obj); - void calcVertex (const vertex& v); - vertex center() const; - - LDBoundingBox& operator<< (LDObject* obj); - LDBoundingBox& operator<< (const vertex& v); + + public: + LDBoundingBox(); + void reset(); + void calculate(); + double size() const; + void calcObject (LDObject* obj); + void calcVertex (const vertex& v); + vertex center() const; + + LDBoundingBox& operator<< (LDObject* obj); + LDBoundingBox& operator<< (const vertex& v); }; // Formatter function -str DoFormat (List<StringFormatArg> args); +str DoFormat (QList<StringFormatArg> args); // printf replacement void doPrint (File& f, initlist<StringFormatArg> args); @@ -497,14 +325,12 @@ void DoLog (std::initializer_list<StringFormatArg> args); // Macros to access these functions -# ifndef IN_IDE_PARSER +# ifndef IN_IDE_PARSER #define fmt(...) DoFormat ({__VA_ARGS__}) -# define print(...) doPrint (g_file_stdout, {__VA_ARGS__}) # define fprint(F, ...) doPrint (F, {__VA_ARGS__}) -# define log(...) DoLog({ __VA_ARGS__ }); +# define log(...) DoLog({ __VA_ARGS__ }) #else str fmt (const char* fmtstr, ...); -void print (const char* fmtstr, ...); void fprint (File& f, const char* fmtstr, ...); void log (const char* fmtstr, ...); #endif @@ -516,4 +342,4 @@ static const double pi = 3.14159265358979323846; -#endif // TYPES_H \ No newline at end of file +#endif // TYPES_H
--- a/src/widgets.cpp Wed Sep 25 11:02:44 2013 +0300 +++ b/src/widgets.cpp Wed Oct 23 12:46:10 2013 +0300 @@ -27,151 +27,151 @@ #include <map> #include "widgets.h" +#include "moc_widgets.cpp" // ============================================================================= // ----------------------------------------------------------------------------- -RadioGroup::RadioGroup (const QString& title, QWidget* parent) : QGroupBox (title, parent) { - init (Qt::Vertical); +RadioGroup::RadioGroup (const QString& title, QWidget* parent) : QGroupBox (title, parent) +{ init (Qt::Vertical); } // ============================================================================= // ----------------------------------------------------------------------------- -QBoxLayout::Direction makeDirection (Qt::Orientation orient, bool invert = false) { - return (orient == (invert ? Qt::Vertical : Qt::Horizontal)) ? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom; +QBoxLayout::Direction makeDirection (Qt::Orientation orient, bool invert = false) +{ return (orient == (invert ? Qt::Vertical : Qt::Horizontal)) ? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom; } // ============================================================================= // ----------------------------------------------------------------------------- -bool RadioGroup::isChecked (int n) const { - return m_buttonGroup->checkedId() == n; +bool RadioGroup::isChecked (int n) const +{ return m_buttonGroup->checkedId() == n; } // ============================================================================= // ----------------------------------------------------------------------------- -void RadioGroup::init (Qt::Orientation orient) { - m_vert = orient == Qt::Vertical; - +void RadioGroup::init (Qt::Orientation orient) +{ m_vert = orient == Qt::Vertical; + m_buttonGroup = new QButtonGroup; m_oldId = m_curId = 0; m_coreLayout = null; - - m_coreLayout = new QBoxLayout ((orient == Qt::Vertical) ? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom); + + m_coreLayout = new QBoxLayout ( (orient == Qt::Vertical) ? QBoxLayout::LeftToRight : QBoxLayout::TopToBottom); setLayout (m_coreLayout); - + // Init the first row with a break rowBreak(); - + connect (m_buttonGroup, SIGNAL (buttonPressed (int)), this, SLOT (slot_buttonPressed (int))); connect (m_buttonGroup, SIGNAL (buttonReleased (int)), this, SLOT (slot_buttonReleased (int))); } // ============================================================================= // ----------------------------------------------------------------------------- -RadioGroup::RadioGroup (const QString& title, initlist<char const*> entries, int const defaultId, - const Qt::Orientation orient, QWidget* parent) : QGroupBox (title, parent), m_defId (defaultId) -{ - init (orient); +RadioGroup::RadioGroup (const QString& title, initlist<char const*> entries, int const defaultId, const Qt::Orientation orient, QWidget* parent) : + QGroupBox (title, parent), + m_defId (defaultId) +{ init (orient); m_oldId = m_defId; - - for (char const* entry : entries) + + for (const char* entry : entries) addButton (entry); } // ============================================================================= // ----------------------------------------------------------------------------- -void RadioGroup::rowBreak() { - QBoxLayout* newLayout = new QBoxLayout (m_vert ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight); +void RadioGroup::rowBreak() +{ QBoxLayout* newLayout = new QBoxLayout (m_vert ? QBoxLayout::TopToBottom : QBoxLayout::LeftToRight); m_currentLayout = newLayout; m_layouts << newLayout; - + m_coreLayout->addLayout (newLayout); } // ============================================================================= // ----------------------------------------------------------------------------- -void RadioGroup::addButton (const char* entry) { - QRadioButton* button = new QRadioButton (entry); +void RadioGroup::addButton (const char* entry) +{ QRadioButton* button = new QRadioButton (entry); addButton (button); } // ============================================================================= // ----------------------------------------------------------------------------- -void RadioGroup::addButton (QRadioButton* button) { - bool const selectThis = (m_curId == m_defId); - +void RadioGroup::addButton (QRadioButton* button) +{ bool const selectThis = (m_curId == m_defId); + m_objects << button; m_buttonGroup->addButton (button, m_curId++); m_currentLayout->addWidget (button); - + if (selectThis) button->setChecked (true); } // ============================================================================= // ----------------------------------------------------------------------------- -RadioGroup& RadioGroup::operator<< (QRadioButton* button) { - addButton (button); +RadioGroup& RadioGroup::operator<< (QRadioButton* button) +{ addButton (button); return *this; } // ============================================================================= // ----------------------------------------------------------------------------- -RadioGroup& RadioGroup::operator<< (const char* entry) { - addButton (entry); +RadioGroup& RadioGroup::operator<< (const char* entry) +{ addButton (entry); return *this; } // ============================================================================= // ----------------------------------------------------------------------------- -void RadioGroup::setCurrentRow (uint row) { - m_currentLayout = m_layouts[row]; +void RadioGroup::setCurrentRow (int row) +{ m_currentLayout = m_layouts[row]; } // ============================================================================= // ----------------------------------------------------------------------------- -int RadioGroup::value() const { - return m_buttonGroup->checkedId(); +int RadioGroup::value() const +{ return m_buttonGroup->checkedId(); } // ============================================================================= // ----------------------------------------------------------------------------- -void RadioGroup::setValue (int val) { - m_buttonGroup->button (val)->setChecked (true); +void RadioGroup::setValue (int val) +{ m_buttonGroup->button (val)->setChecked (true); } // ============================================================================= // ----------------------------------------------------------------------------- -QRadioButton* RadioGroup::operator[] (uint n) const { - return m_objects[n]; +QRadioButton* RadioGroup::operator[] (int n) const +{ return m_objects[n]; } // ============================================================================= // ----------------------------------------------------------------------------- -void RadioGroup::slot_buttonPressed (int btn) { - emit buttonPressed (btn); - +void RadioGroup::slot_buttonPressed (int btn) +{ emit buttonPressed (btn); + m_oldId = m_buttonGroup->checkedId(); } // ============================================================================= // ----------------------------------------------------------------------------- -void RadioGroup::slot_buttonReleased (int btn) { - emit buttonReleased (btn); +void RadioGroup::slot_buttonReleased (int btn) +{ emit buttonReleased (btn); int newid = m_buttonGroup->checkedId(); - + if (m_oldId != newid) emit valueChanged (newid); } // ============================================================================= // ----------------------------------------------------------------------------- -RadioGroup::it RadioGroup::begin() { - return m_objects.begin(); +RadioGroup::Iterator RadioGroup::begin() +{ return m_objects.begin(); } // ============================================================================= // ----------------------------------------------------------------------------- -RadioGroup::it RadioGroup::end() { - return m_objects.end(); +RadioGroup::Iterator RadioGroup::end() +{ return m_objects.end(); } -#include "moc_widgets.cpp"
--- a/src/widgets.h Wed Sep 25 11:02:44 2013 +0300 +++ b/src/widgets.h Wed Oct 23 12:46:10 2013 +0300 @@ -36,52 +36,58 @@ // // Convenience widget - is a groupbox of radio buttons. // ============================================================================= -class RadioGroup : public QGroupBox { - Q_OBJECT - -public: - typedef List<QRadioButton*>::it it; - - explicit RadioGroup() { init (Qt::Vertical); } - explicit RadioGroup (QWidget* parent = null) : QGroupBox (parent) { init (Qt::Vertical); } - explicit RadioGroup (const QString& title, QWidget* parent = null); - explicit RadioGroup (const QString& title, initlist<char const*> entries, int const defaultId, - const Qt::Orientation orient = Qt::Vertical, QWidget* parent = null); - - void addButton (const char* entry); - void addButton (QRadioButton* button); - it begin (); - it end (); - void init (Qt::Orientation orient); - bool isChecked (int n) const; - void rowBreak (); - void setCurrentRow (uint row); - void setValue (int val); - int value () const; - - QRadioButton* operator[] (uint n) const; - RadioGroup& operator<< (QRadioButton* button); - RadioGroup& operator<< (const char* entry); +class RadioGroup : public QGroupBox +{ Q_OBJECT + + public: + typedef QList<QRadioButton*>::Iterator Iterator; + + explicit RadioGroup() + { init (Qt::Vertical); + } + + explicit RadioGroup (QWidget* parent = null) : QGroupBox (parent) + { init (Qt::Vertical); + } + + explicit RadioGroup (const QString& title, QWidget* parent = null); + explicit RadioGroup (const QString& title, initlist<char const*> entries, int const defaultId, + const Qt::Orientation orient = Qt::Vertical, QWidget* parent = null); -signals: - void buttonPressed (int btn); - void buttonReleased (int btn); - void valueChanged (int val); + void addButton (const char* entry); + void addButton (QRadioButton* button); + Iterator begin(); + Iterator end(); + void init (Qt::Orientation orient); + bool isChecked (int n) const; + void rowBreak(); + void setCurrentRow (int row); + void setValue (int val); + int value() const; + + QRadioButton* operator[] (int n) const; + RadioGroup& operator<< (QRadioButton* button); + RadioGroup& operator<< (const char* entry); -private: - List<QRadioButton*> m_objects; - List<QBoxLayout*> m_layouts; - QBoxLayout* m_coreLayout; - QBoxLayout* m_currentLayout; - bool m_vert; - int m_curId, m_defId, m_oldId; - QButtonGroup* m_buttonGroup; - - Q_DISABLE_COPY (RadioGroup) + signals: + void buttonPressed (int btn); + void buttonReleased (int btn); + void valueChanged (int val); -private slots: - void slot_buttonPressed (int btn); - void slot_buttonReleased (int btn); + private: + QList<QRadioButton*> m_objects; + QList<QBoxLayout*> m_layouts; + QBoxLayout* m_coreLayout; + QBoxLayout* m_currentLayout; + bool m_vert; + int m_curId, m_defId, m_oldId; + QButtonGroup* m_buttonGroup; + + Q_DISABLE_COPY (RadioGroup) + + private slots: + void slot_buttonPressed (int btn); + void slot_buttonReleased (int btn); }; -#endif // WIDGETS_H \ No newline at end of file +#endif // WIDGETS_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ui/bombbox.ui Wed Oct 23 12:46:10 2013 +0300 @@ -0,0 +1,104 @@ +<?xml version="1.0" encoding="UTF-8"?> +<ui version="4.0"> + <class>BombBox</class> + <widget class="QDialog" name="BombBox"> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>676</width> + <height>569</height> + </rect> + </property> + <property name="windowTitle"> + <string>Fatal Error</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_2"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <layout class="QVBoxLayout" name="verticalLayout"> + <item> + <widget class="QLabel" name="label"> + <property name="text"> + <string/> + </property> + <property name="pixmap"> + <pixmap resource="../ldforge.qrc">:/icons/bomb.png</pixmap> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>138</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + <item> + <widget class="QTextEdit" name="m_text"> + <property name="readOnly"> + <bool>true</bool> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QDialogButtonBox" name="buttonBox"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="standardButtons"> + <set>QDialogButtonBox::Close</set> + </property> + </widget> + </item> + </layout> + </widget> + <resources> + <include location="../ldforge.qrc"/> + </resources> + <connections> + <connection> + <sender>buttonBox</sender> + <signal>accepted()</signal> + <receiver>BombBox</receiver> + <slot>accept()</slot> + <hints> + <hint type="sourcelabel"> + <x>248</x> + <y>254</y> + </hint> + <hint type="destinationlabel"> + <x>157</x> + <y>274</y> + </hint> + </hints> + </connection> + <connection> + <sender>buttonBox</sender> + <signal>rejected()</signal> + <receiver>BombBox</receiver> + <slot>reject()</slot> + <hints> + <hint type="sourcelabel"> + <x>316</x> + <y>260</y> + </hint> + <hint type="destinationlabel"> + <x>286</x> + <y>274</y> + </hint> + </hints> + </connection> + </connections> +</ui>
--- a/ui/config.ui Wed Sep 25 11:02:44 2013 +0300 +++ b/ui/config.ui Wed Oct 23 12:46:10 2013 +0300 @@ -6,401 +6,361 @@ <rect> <x>0</x> <y>0</y> - <width>561</width> - <height>351</height> + <width>717</width> + <height>328</height> </rect> </property> <property name="windowTitle"> <string>Settings</string> </property> <property name="windowIcon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/settings.png</normaloff>:/icons/settings.png</iconset> </property> <layout class="QVBoxLayout" name="verticalLayout"> <item> - <widget class="QTabWidget" name="tabs"> - <property name="tabPosition"> - <enum>QTabWidget::North</enum> - </property> - <property name="currentIndex"> - <number>0</number> - </property> - <property name="elideMode"> - <enum>Qt::ElideNone</enum> - </property> - <property name="documentMode"> - <bool>false</bool> - </property> - <property name="tabsClosable"> - <bool>false</bool> - </property> - <property name="movable"> - <bool>false</bool> - </property> - <widget class="QWidget" name="tab"> - <attribute name="title"> - <string>Interface</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_2"> + <layout class="QHBoxLayout" name="horizontalLayout_7" stretch="0,0"> + <item> + <widget class="QListWidget" name="m_pagelist"> + <property name="minimumSize"> + <size> + <width>144</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>144</width> + <height>16777215</height> + </size> + </property> <item> - <widget class="QGroupBox" name="groupBox"> - <property name="title"> - <string>Colors</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_3" stretch="0"> - <item> - <layout class="QFormLayout" name="formLayout"> - <property name="fieldGrowthPolicy"> - <enum>QFormLayout::ExpandingFieldsGrow</enum> - </property> - <item row="0" column="0"> - <widget class="QLabel" name="label"> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>Main color:</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QPushButton" name="mainColorButton"> - <property name="whatsThis"> - <string>This color is used for the main color.</string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset resource="../../ldforge.qrc"> - <normaloff>:/icons/colorselect.png</normaloff>:/icons/colorselect.png</iconset> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_3"> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>Main color alpha:</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QSlider" name="mainColorAlpha"> - <property name="whatsThis"> - <string>Opacity of main color in the viewport.</string> - </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>10</number> - </property> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="tickPosition"> - <enum>QSlider::TicksAbove</enum> - </property> - <property name="tickInterval"> - <number>1</number> - </property> - </widget> - </item> - <item row="2" column="0"> - <widget class="QLabel" name="label_2"> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>Background:</string> - </property> - </widget> - </item> - <item row="2" column="1"> - <widget class="QPushButton" name="backgroundColorButton"> - <property name="whatsThis"> - <string>This is the background color for the viewport.</string> - </property> - <property name="text"> - <string/> - </property> - <property name="icon"> - <iconset resource="../../ldforge.qrc"> - <normaloff>:/icons/colorselect.png</normaloff>:/icons/colorselect.png</iconset> - </property> - </widget> - </item> - </layout> - </item> - </layout> - </widget> + <property name="text"> + <string>Interface</string> + </property> </item> <item> - <layout class="QFormLayout" name="formLayout_2"> - <property name="fieldGrowthPolicy"> - <enum>QFormLayout::ExpandingFieldsGrow</enum> - </property> - <item row="0" column="0"> - <widget class="QLabel" name="label_5"> - <property name="whatsThis"> - <string/> - </property> - <property name="text"> - <string>Line thickness:</string> - </property> - </widget> - </item> - <item row="0" column="1"> - <layout class="QHBoxLayout" name="horizontalLayout"> - <item> - <widget class="QSlider" name="lineThickness"> - <property name="whatsThis"> - <string>How thick lines should be drawn in the viewport.</string> - </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>8</number> - </property> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - <property name="tickPosition"> - <enum>QSlider::TicksAbove</enum> - </property> - <property name="tickInterval"> - <number>1</number> - </property> - </widget> - </item> - <item> - <widget class="QLabel" name="label_6"> - <property name="text"> - <string>#</string> - </property> - </widget> - </item> - </layout> - </item> - </layout> + <property name="text"> + <string>Profile</string> + </property> + </item> + <item> + <property name="text"> + <string>Shortcuts</string> + </property> + </item> + <item> + <property name="text"> + <string>Quick colors</string> + </property> + </item> + <item> + <property name="text"> + <string>Grids</string> + </property> + </item> + <item> + <property name="text"> + <string>External Programs</string> + </property> </item> <item> - <layout class="QHBoxLayout" name="horizontalLayout_8"> + <property name="text"> + <string>Downloads</string> + </property> + </item> + </widget> + </item> + <item> + <widget class="QStackedWidget" name="m_pages"> + <property name="currentIndex"> + <number>0</number> + </property> + <widget class="QWidget" name="page_3"> + <layout class="QVBoxLayout" name="verticalLayout_13"> <item> - <layout class="QVBoxLayout" name="verticalLayout_11"> - <item> - <widget class="QCheckBox" name="blackEdges"> - <property name="whatsThis"> - <string>Makes all edgelines appear black. If this is not set, edge lines take their color as defined in LDConfig.ldr.</string> - </property> - <property name="text"> - <string>Black edges</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="colorBFC"> - <property name="whatsThis"> - <string>Polygons' front sides become green and back sides red.</string> - </property> - <property name="text"> - <string>Red/green BFC view (incomplete)</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="colorizeObjects"> - <property name="whatsThis"> - <string>Makes colored objects (non-16 and 24) appear colored in the list view. A red triangle will, for instance, have its entry written in red text. This can be useful to locate colored objects.</string> - </property> - <property name="text"> - <string>Colorize objects in list view</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="implicitFiles"> - <property name="text"> - <string>List implicitly loaded files</string> - </property> - </widget> - </item> - </layout> - </item> - <item> - <layout class="QVBoxLayout" name="verticalLayout_12"> - <item> - <widget class="QCheckBox" name="m_logostuds"> - <property name="text"> - <string>Use logoed studs</string> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer_6"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> + <widget class="QGroupBox" name="groupBox"> + <property name="title"> + <string>Interface</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_3" stretch="0,0,0"> + <item> + <layout class="QFormLayout" name="formLayout"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::ExpandingFieldsGrow</enum> + </property> + <item row="0" column="0"> + <widget class="QLabel" name="label"> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string>Main color:</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QPushButton" name="mainColorButton"> + <property name="whatsThis"> + <string>This color is used for the main color.</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../ldforge.qrc"> + <normaloff>:/icons/colorselect.png</normaloff>:/icons/colorselect.png</iconset> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_3"> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string>Main color alpha:</string> + </property> + </widget> + </item> + <item row="1" column="1"> + <widget class="QSlider" name="mainColorAlpha"> + <property name="whatsThis"> + <string>Opacity of main color in the viewport.</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>10</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksAbove</enum> + </property> + <property name="tickInterval"> + <number>1</number> + </property> + </widget> + </item> + <item row="2" column="0"> + <widget class="QLabel" name="label_2"> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string>Background:</string> + </property> + </widget> + </item> + <item row="2" column="1"> + <widget class="QPushButton" name="backgroundColorButton"> + <property name="whatsThis"> + <string>This is the background color for the viewport.</string> + </property> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../ldforge.qrc"> + <normaloff>:/icons/colorselect.png</normaloff>:/icons/colorselect.png</iconset> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QFormLayout" name="formLayout_2"> + <property name="fieldGrowthPolicy"> + <enum>QFormLayout::ExpandingFieldsGrow</enum> + </property> + <item row="0" column="1"> + <layout class="QHBoxLayout" name="horizontalLayout"> + <item> + <widget class="QSlider" name="lineThickness"> + <property name="whatsThis"> + <string>How thick lines should be drawn in the viewport.</string> + </property> + <property name="minimum"> + <number>1</number> + </property> + <property name="maximum"> + <number>8</number> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="tickPosition"> + <enum>QSlider::TicksAbove</enum> + </property> + <property name="tickInterval"> + <number>1</number> + </property> + </widget> + </item> + </layout> + </item> + <item row="0" column="0"> + <widget class="QLabel" name="label_5"> + <property name="whatsThis"> + <string/> + </property> + <property name="text"> + <string>Line thickness:</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_8"> + <item> + <layout class="QVBoxLayout" name="verticalLayout_11"> + <item> + <widget class="QCheckBox" name="blackEdges"> + <property name="whatsThis"> + <string>Makes all edgelines appear black. If this is not set, edge lines take their color as defined in LDConfig.ldr.</string> + </property> + <property name="text"> + <string>Black edges</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="colorBFC"> + <property name="whatsThis"> + <string>Polygons' front sides become green and back sides red.</string> + </property> + <property name="text"> + <string>Red/green BFC view (incomplete)</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="colorizeObjects"> + <property name="whatsThis"> + <string>Makes colored objects (non-16 and 24) appear colored in the list view. A red triangle will, for instance, have its entry written in red text. This can be useful to locate colored objects.</string> + </property> + <property name="text"> + <string>Colorize objects in list view</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="m_aa"> + <property name="text"> + <string>Anti-aliased lines</string> + </property> + </widget> + </item> + </layout> + </item> + <item> + <layout class="QVBoxLayout" name="verticalLayout_12"> + <item> + <widget class="QCheckBox" name="m_logostuds"> + <property name="text"> + <string>Use logoed studs</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="implicitFiles"> + <property name="text"> + <string>List implicitly loaded files</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_6"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> + </item> + </layout> + </item> + </layout> + </widget> </item> </layout> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_7"> - <attribute name="title"> - <string>Profile</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_10"> - <item> - <widget class="QGroupBox" name="groupBox_4"> - <property name="title"> - <string>Profile</string> - </property> - <layout class="QVBoxLayout" name="verticalLayout_8"> - <item> - <layout class="QFormLayout" name="formLayout_3"> - <item row="2" column="0"> - <widget class="QLabel" name="label_8"> - <property name="text"> - <string>Username:</string> - </property> - </widget> - </item> - <item row="1" column="0"> - <widget class="QLabel" name="label_7"> - <property name="text"> - <string>Name:</string> - </property> - </widget> - </item> - <item row="3" column="0"> - <widget class="QLabel" name="label_9"> - <property name="text"> - <string>License:</string> - </property> - </widget> - </item> - <item row="1" column="1"> - <widget class="QLineEdit" name="m_profileName"/> - </item> - <item row="2" column="1"> - <widget class="QLineEdit" name="m_profileUsername"/> - </item> - <item row="3" column="1"> - <widget class="QComboBox" name="m_profileLicense"> - <property name="sizePolicy"> - <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> - <horstretch>0</horstretch> - <verstretch>0</verstretch> - </sizepolicy> - </property> - <item> - <property name="text"> - <string>CA - redistributable</string> - </property> + </widget> + <widget class="QWidget" name="page_4"> + <layout class="QVBoxLayout" name="verticalLayout_14"> + <item> + <widget class="QGroupBox" name="groupBox_4"> + <property name="title"> + <string>Profile</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_8"> + <item> + <layout class="QFormLayout" name="formLayout_3"> + <item row="2" column="0"> + <widget class="QLabel" name="label_8"> + <property name="text"> + <string>Username:</string> + </property> + </widget> + </item> + <item row="1" column="0"> + <widget class="QLabel" name="label_7"> + <property name="text"> + <string>Name:</string> + </property> + </widget> + </item> + <item row="3" column="0"> + <widget class="QLabel" name="label_9"> + <property name="text"> + <string>License:</string> + </property> + </widget> </item> - <item> - <property name="text"> - <string>NonCA - not redistributable</string> - </property> + <item row="1" column="1"> + <widget class="QLineEdit" name="m_profileName"/> </item> - <item> - <property name="text"> - <string>None</string> - </property> + <item row="2" column="1"> + <widget class="QLineEdit" name="m_profileUsername"/> </item> - </widget> - </item> - </layout> - </item> - <item> - <spacer name="verticalSpacer_7"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_2"> - <attribute name="title"> - <string>Shortcuts</string> - </attribute> - <layout class="QHBoxLayout" name="horizontalLayout_3"> - <item> - <widget class="QGroupBox" name="groupBox_2"> - <property name="whatsThis"> - <string>Here you can alter keyboard shortcuts for almost all LDForge actions. Only exceptions are the controls for the viewport. Use the set button to set a key shortcut, clear to remove it and reset to restore the shortcut to its default value. - -Shortcut changes apply immediately after closing this window.</string> - </property> - <property name="title"> - <string>Shortcuts</string> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_5"> - <item> - <widget class="QListWidget" name="shortcutsList"> - <property name="verticalScrollBarPolicy"> - <enum>Qt::ScrollBarAsNeeded</enum> - </property> - </widget> - </item> - <item> - <layout class="QVBoxLayout" name="verticalLayout_4"> - <item> - <widget class="QPushButton" name="shortcut_set"> - <property name="text"> - <string>Set</string> - </property> - </widget> + <item row="3" column="1"> + <widget class="QComboBox" name="m_profileLicense"> + <property name="sizePolicy"> + <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <item> + <property name="text"> + <string>CA - redistributable</string> + </property> + </item> + <item> + <property name="text"> + <string>NonCA - not redistributable</string> + </property> + </item> + <item> + <property name="text"> + <string>None</string> + </property> + </item> + </widget> + </item> + </layout> </item> <item> - <widget class="QPushButton" name="shortcut_reset"> - <property name="text"> - <string>Reset</string> - </property> - <property name="icon"> - <iconset resource="../../ldforge.qrc"> - <normaloff>:/icons/undo.png</normaloff>:/icons/undo.png</iconset> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="shortcut_clear"> - <property name="text"> - <string>Clear</string> - </property> - <property name="icon"> - <iconset resource="../../ldforge.qrc"> - <normaloff>:/icons/delete.png</normaloff>:/icons/delete.png</iconset> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer_2"> + <spacer name="verticalSpacer_7"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> @@ -413,237 +373,300 @@ </spacer> </item> </layout> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_3"> - <attribute name="title"> - <string>Quick colors</string> - </attribute> - <layout class="QHBoxLayout" name="horizontalLayout_4"> - <item> - <widget class="QGroupBox" name="groupBox_3"> - <property name="whatsThis"> - <string>Here you can alter the layout of the quick colors toolbar. Use the controls to add, remove or edit the colors used. You can also add separators in between colors. + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="page_5"> + <layout class="QVBoxLayout" name="verticalLayout_15"> + <item> + <widget class="QGroupBox" name="groupBox_2"> + <property name="whatsThis"> + <string>Here you can alter keyboard shortcuts for almost all LDForge actions. Only exceptions are the controls for the viewport. Use the set button to set a key shortcut, clear to remove it and reset to restore the shortcut to its default value. -Usually this contains MainColor, EdgeColor and some auxiliary colors used to group objects.</string> - </property> - <property name="title"> - <string>Quick colors</string> - </property> - <layout class="QHBoxLayout" name="horizontalLayout_6"> - <item> - <widget class="QListWidget" name="quickColorList"> - <property name="verticalScrollBarPolicy"> - <enum>Qt::ScrollBarAsNeeded</enum> - </property> - </widget> - </item> - <item> - <layout class="QVBoxLayout" name="verticalLayout_5"> +Shortcut changes apply immediately after closing this window.</string> + </property> + <property name="title"> + <string>Shortcuts</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_5"> <item> - <widget class="QPushButton" name="quickColor_add"> - <property name="text"> - <string>Add Color</string> - </property> - <property name="icon"> - <iconset resource="../../ldforge.qrc"> - <normaloff>:/icons/palette.png</normaloff>:/icons/palette.png</iconset> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="quickColor_addSep"> - <property name="text"> - <string>Add Separator</string> + <widget class="QListWidget" name="shortcutsList"> + <property name="verticalScrollBarPolicy"> + <enum>Qt::ScrollBarAsNeeded</enum> </property> </widget> </item> <item> - <widget class="QPushButton" name="quickColor_edit"> - <property name="text"> - <string>Edit</string> - </property> - <property name="icon"> - <iconset resource="../../ldforge.qrc"> - <normaloff>:/icons/mode-draw.png</normaloff>:/icons/mode-draw.png</iconset> - </property> - </widget> + <layout class="QVBoxLayout" name="verticalLayout_4"> + <item> + <widget class="QPushButton" name="shortcut_set"> + <property name="text"> + <string>Set</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="shortcut_reset"> + <property name="text"> + <string>Reset</string> + </property> + <property name="icon"> + <iconset resource="../ldforge.qrc"> + <normaloff>:/icons/undo.png</normaloff>:/icons/undo.png</iconset> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="shortcut_clear"> + <property name="text"> + <string>Clear</string> + </property> + <property name="icon"> + <iconset resource="../ldforge.qrc"> + <normaloff>:/icons/delete.png</normaloff>:/icons/delete.png</iconset> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> </item> - <item> - <widget class="Line" name="line_2"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> + </layout> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="page_6"> + <layout class="QVBoxLayout" name="verticalLayout_16"> + <item> + <widget class="QGroupBox" name="groupBox_3"> + <property name="whatsThis"> + <string>Here you can alter the layout of the quick colors toolbar. Use the controls to add, remove or edit the colors used. You can also add separators in between colors. + +Usually this contains MainColor, EdgeColor and some auxiliary colors used to group objects.</string> + </property> + <property name="title"> + <string>Quick colors</string> + </property> + <layout class="QHBoxLayout" name="horizontalLayout_6"> <item> - <widget class="QPushButton" name="quickColor_moveUp"> - <property name="text"> - <string>Move Up</string> - </property> - <property name="icon"> - <iconset resource="../../ldforge.qrc"> - <normaloff>:/icons/arrow-up.png</normaloff>:/icons/arrow-up.png</iconset> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="quickColor_moveDown"> - <property name="text"> - <string>Move Down</string> - </property> - <property name="icon"> - <iconset resource="../../ldforge.qrc"> - <normaloff>:/icons/arrow-down.png</normaloff>:/icons/arrow-down.png</iconset> - </property> - </widget> - </item> - <item> - <widget class="Line" name="line"> - <property name="orientation"> - <enum>Qt::Horizontal</enum> - </property> - </widget> - </item> - <item> - <widget class="QPushButton" name="quickColor_remove"> - <property name="text"> - <string>Remove</string> - </property> - <property name="icon"> - <iconset resource="../../ldforge.qrc"> - <normaloff>:/icons/delete.png</normaloff>:/icons/delete.png</iconset> + <widget class="QListWidget" name="quickColorList"> + <property name="verticalScrollBarPolicy"> + <enum>Qt::ScrollBarAsNeeded</enum> </property> </widget> </item> <item> - <widget class="QPushButton" name="quickColor_clear"> - <property name="text"> - <string>Clear List</string> - </property> - <property name="icon"> - <iconset resource="../../ldforge.qrc"> - <normaloff>:/icons/delete.png</normaloff>:/icons/delete.png</iconset> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer_3"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> + <layout class="QVBoxLayout" name="verticalLayout_5"> + <item> + <widget class="QPushButton" name="quickColor_add"> + <property name="text"> + <string>Add Color</string> + </property> + <property name="icon"> + <iconset resource="../ldforge.qrc"> + <normaloff>:/icons/palette.png</normaloff>:/icons/palette.png</iconset> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="quickColor_addSep"> + <property name="text"> + <string>Add Separator</string> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="quickColor_edit"> + <property name="text"> + <string>Edit</string> + </property> + <property name="icon"> + <iconset resource="../ldforge.qrc"> + <normaloff>:/icons/mode-draw.png</normaloff>:/icons/mode-draw.png</iconset> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line_2"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="quickColor_moveUp"> + <property name="text"> + <string>Move Up</string> + </property> + <property name="icon"> + <iconset resource="../ldforge.qrc"> + <normaloff>:/icons/arrow-up.png</normaloff>:/icons/arrow-up.png</iconset> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="quickColor_moveDown"> + <property name="text"> + <string>Move Down</string> + </property> + <property name="icon"> + <iconset resource="../ldforge.qrc"> + <normaloff>:/icons/arrow-down.png</normaloff>:/icons/arrow-down.png</iconset> + </property> + </widget> + </item> + <item> + <widget class="Line" name="line"> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="quickColor_remove"> + <property name="text"> + <string>Remove</string> + </property> + <property name="icon"> + <iconset resource="../ldforge.qrc"> + <normaloff>:/icons/delete.png</normaloff>:/icons/delete.png</iconset> + </property> + </widget> + </item> + <item> + <widget class="QPushButton" name="quickColor_clear"> + <property name="text"> + <string>Clear List</string> + </property> + <property name="icon"> + <iconset resource="../ldforge.qrc"> + <normaloff>:/icons/delete.png</normaloff>:/icons/delete.png</iconset> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_3"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + </layout> </item> </layout> - </item> - </layout> - </widget> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_4"> - <attribute name="title"> - <string>Grids</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_6"> - <item> - <widget class="QGroupBox" name="grids"> - <property name="title"> - <string>Grids</string> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_5"> - <attribute name="title"> - <string>External Programs</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_9"> - <item> - <widget class="QGroupBox" name="extProgs"> - <property name="whatsThis"> - <string>LDForge supports launching of several third-party utility tools; here you can set the file paths to these tools. Set the paths of the tools to the exe files. - -Under Linux, you can also set the programs to be launched with Wine, so you can use Windows binaries here as well. You will obviously need Wine installed. A 'wine' command in PATH is necessary for this to work.</string> - </property> - <property name="title"> - <string>External Programs</string> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer_4"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - <widget class="QWidget" name="tab_6"> - <attribute name="title"> - <string>Downloading</string> - </attribute> - <layout class="QVBoxLayout" name="verticalLayout_7"> - <item> - <layout class="QHBoxLayout" name="horizontalLayout_2"> + </widget> + </item> + </layout> + </widget> + <widget class="QWidget" name="page_7"> + <layout class="QVBoxLayout" name="verticalLayout_17"> <item> - <widget class="QLabel" name="label_4"> - <property name="text"> - <string>Download path:</string> + <widget class="QGroupBox" name="grids"> + <property name="title"> + <string>Grids</string> </property> </widget> </item> <item> - <widget class="QLineEdit" name="downloadPath"/> + <spacer name="verticalSpacer"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> </item> + </layout> + </widget> + <widget class="QWidget" name="page_8"> + <layout class="QVBoxLayout" name="verticalLayout_18"> <item> - <widget class="QPushButton" name="findDownloadPath"> - <property name="text"> - <string/> + <widget class="QGroupBox" name="extProgs"> + <property name="whatsThis"> + <string>LDForge supports launching of several third-party utility tools; here you can set the file paths to these tools. Set the paths of the tools to the exe files. + +Under Linux, you can also set the programs to be launched with Wine, so you can use Windows binaries here as well. You will obviously need Wine installed. A 'wine' command in PATH is necessary for this to work.</string> </property> - <property name="icon"> - <iconset resource="../../ldforge.qrc"> - <normaloff>:/icons/folder.png</normaloff>:/icons/folder.png</iconset> + <property name="title"> + <string>External Programs</string> </property> </widget> </item> + <item> + <spacer name="verticalSpacer_4"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> </layout> - </item> - <item> - <widget class="QCheckBox" name="guessNetPaths"> - <property name="whatsThis"> - <string><p>When this is set, LDForge tries to adjust and correct part paths based on the input. A full path given to the download prompt should be of form <tt>"&lt;dir&gt;/&lt;file&gt;.dat"</tt> - with this set, input can be automatically completed.</p> + </widget> + <widget class="QWidget" name="page_9"> + <layout class="QVBoxLayout" name="verticalLayout_19"> + <item> + <widget class="QGroupBox" name="groupBox_5"> + <property name="title"> + <string>Downloads</string> + </property> + <layout class="QVBoxLayout" name="verticalLayout_20"> + <item> + <layout class="QHBoxLayout" name="horizontalLayout_2"> + <item> + <widget class="QLabel" name="label_4"> + <property name="text"> + <string>Download path:</string> + </property> + </widget> + </item> + <item> + <widget class="QLineEdit" name="downloadPath"/> + </item> + <item> + <widget class="QPushButton" name="findDownloadPath"> + <property name="text"> + <string/> + </property> + <property name="icon"> + <iconset resource="../ldforge.qrc"> + <normaloff>:/icons/folder.png</normaloff>:/icons/folder.png</iconset> + </property> + </widget> + </item> + </layout> + </item> + <item> + <widget class="QCheckBox" name="guessNetPaths"> + <property name="whatsThis"> + <string><p>When this is set, LDForge tries to adjust and correct part paths based on the input. A full path given to the download prompt should be of form <tt>"&lt;dir&gt;/&lt;file&gt;.dat"</tt> - with this set, input can be automatically completed.</p> <p>Examples: <ul> @@ -652,38 +675,43 @@ <li>3002s01 -> parts/s/3002s01.dat</li> <li>4-4cyli -> p/4-4cyli.dat</li> </ul></p></string> - </property> - <property name="text"> - <string>Correct and guess part paths</string> - </property> - </widget> - </item> - <item> - <widget class="QCheckBox" name="autoCloseNetPrompt"> - <property name="whatsThis"> - <string>If this is set, LDForge will close the download prompt after everything has been downloaded. The prompt will not be closed if a download has failed.</string> - </property> - <property name="text"> - <string>Close download prompt after completion</string> - </property> - </widget> - </item> - <item> - <spacer name="verticalSpacer_5"> - <property name="orientation"> - <enum>Qt::Vertical</enum> - </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> - </property> - </spacer> - </item> - </layout> - </widget> - </widget> + </property> + <property name="text"> + <string>Correct and guess part paths</string> + </property> + </widget> + </item> + <item> + <widget class="QCheckBox" name="autoCloseNetPrompt"> + <property name="whatsThis"> + <string>If this is set, LDForge will close the download prompt after everything has been downloaded. The prompt will not be closed if a download has failed.</string> + </property> + <property name="text"> + <string>Close download prompt after completion</string> + </property> + </widget> + </item> + <item> + <spacer name="verticalSpacer_5"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>187</height> + </size> + </property> + </spacer> + </item> + </layout> + </widget> + </item> + </layout> + </widget> + </widget> + </item> + </layout> </item> <item> <widget class="QDialogButtonBox" name="buttonBox"> @@ -698,7 +726,7 @@ </layout> </widget> <resources> - <include location="../../ldforge.qrc"/> + <include location="../ldforge.qrc"/> </resources> <connections/> </ui>
--- a/ui/ldforge.ui Wed Sep 25 11:02:44 2013 +0300 +++ b/ui/ldforge.ui Wed Oct 23 12:46:10 2013 +0300 @@ -14,7 +14,7 @@ <string/> </property> <property name="windowIcon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/ldforge.png</normaloff>:/icons/ldforge.png</iconset> </property> <widget class="QWidget" name="centralwidget"> @@ -70,7 +70,7 @@ <x>0</x> <y>0</y> <width>900</width> - <height>22</height> + <height>24</height> </rect> </property> <widget class="QMenu" name="menuFile"> @@ -82,7 +82,7 @@ <string>Open Recent...</string> </property> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/open-recent.png</normaloff>:/icons/open-recent.png</iconset> </property> </widget> @@ -182,10 +182,13 @@ <addaction name="actionBorders"/> <addaction name="actionCornerVerts"/> <addaction name="actionRoundCoordinates"/> - <addaction name="actionVisibility"/> <addaction name="actionReplaceCoords"/> <addaction name="actionFlip"/> <addaction name="actionDemote"/> + <addaction name="separator"/> + <addaction name="actionVisibilityHide"/> + <addaction name="actionVisibilityToggle"/> + <addaction name="actionVisibilityReveal"/> </widget> <widget class="QMenu" name="menuExternal_Tools"> <property name="title"> @@ -294,6 +297,7 @@ <attribute name="toolBarBreak"> <bool>false</bool> </attribute> + <addaction name="actionDownloadFrom"/> <addaction name="actionNewSubfile"/> <addaction name="actionNewLine"/> <addaction name="actionNewTriangle"/> @@ -377,11 +381,15 @@ <addaction name="actionUncolorize"/> <addaction name="actionInvert"/> <addaction name="actionSplitQuads"/> + <addaction name="actionInline"/> <addaction name="actionEditRaw"/> <addaction name="actionBorders"/> + <addaction name="actionCornerVerts"/> <addaction name="actionReplaceCoords"/> <addaction name="actionRoundCoordinates"/> - <addaction name="actionVisibility"/> + <addaction name="actionVisibilityHide"/> + <addaction name="actionVisibilityToggle"/> + <addaction name="actionVisibilityReveal"/> </widget> <widget class="QToolBar" name="toolBar_8"> <property name="windowTitle"> @@ -395,6 +403,7 @@ </attribute> <addaction name="actionModeSelect"/> <addaction name="actionModeDraw"/> + <addaction name="actionModeCircle"/> </widget> <widget class="QToolBar" name="colorToolbar"> <property name="windowTitle"> @@ -409,7 +418,7 @@ </widget> <action name="actionNew"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/brick.png</normaloff>:/icons/brick.png</iconset> </property> <property name="text"> @@ -424,7 +433,7 @@ </action> <action name="actionOpen"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/file-open.png</normaloff>:/icons/file-open.png</iconset> </property> <property name="text"> @@ -439,7 +448,7 @@ </action> <action name="actionSave"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/file-save.png</normaloff>:/icons/file-save.png</iconset> </property> <property name="text"> @@ -454,7 +463,7 @@ </action> <action name="actionSaveAs"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/file-save-as.png</normaloff>:/icons/file-save-as.png</iconset> </property> <property name="text"> @@ -466,7 +475,7 @@ </action> <action name="actionInsertFrom"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/file-import.png</normaloff>:/icons/file-import.png</iconset> </property> <property name="text"> @@ -475,7 +484,7 @@ </action> <action name="actionExportTo"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/file-export.png</normaloff>:/icons/file-export.png</iconset> </property> <property name="text"> @@ -484,7 +493,7 @@ </action> <action name="actionSettings"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/settings.png</normaloff>:/icons/settings.png</iconset> </property> <property name="text"> @@ -499,7 +508,7 @@ </action> <action name="actionSetLDrawPath"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/settings.png</normaloff>:/icons/settings.png</iconset> </property> <property name="text"> @@ -511,7 +520,7 @@ </action> <action name="actionScanPrimitives"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/radial.png</normaloff>:/icons/radial.png</iconset> </property> <property name="text"> @@ -523,7 +532,7 @@ </action> <action name="actionExit"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/exit.png</normaloff>:/icons/exit.png</iconset> </property> <property name="text"> @@ -546,7 +555,7 @@ <bool>true</bool> </property> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/axes.png</normaloff>:/icons/axes.png</iconset> </property> <property name="text"> @@ -558,7 +567,7 @@ <bool>true</bool> </property> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/wireframe.png</normaloff>:/icons/wireframe.png</iconset> </property> <property name="text"> @@ -570,7 +579,7 @@ <bool>true</bool> </property> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/bfc-view.png</normaloff>:/icons/bfc-view.png</iconset> </property> <property name="text"> @@ -579,7 +588,7 @@ </action> <action name="actionSetOverlay"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/overlay.png</normaloff>:/icons/overlay.png</iconset> </property> <property name="text"> @@ -588,7 +597,7 @@ </action> <action name="actionClearOverlay"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/overlay-clear.png</normaloff>:/icons/overlay-clear.png</iconset> </property> <property name="text"> @@ -597,7 +606,7 @@ </action> <action name="actionScreenshot"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/screencap.png</normaloff>:/icons/screencap.png</iconset> </property> <property name="text"> @@ -611,7 +620,7 @@ </action> <action name="actionNewLine"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/add-line.png</normaloff>:/icons/add-line.png</iconset> </property> <property name="text"> @@ -620,7 +629,7 @@ </action> <action name="actionNewSubfile"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/add-subfile.png</normaloff>:/icons/add-subfile.png</iconset> </property> <property name="text"> @@ -629,7 +638,7 @@ </action> <action name="actionNewTriangle"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/add-triangle.png</normaloff>:/icons/add-triangle.png</iconset> </property> <property name="text"> @@ -638,7 +647,7 @@ </action> <action name="actionNewQuad"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/add-quad.png</normaloff>:/icons/add-quad.png</iconset> </property> <property name="text"> @@ -647,7 +656,7 @@ </action> <action name="actionNewCLine"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/add-condline.png</normaloff>:/icons/add-condline.png</iconset> </property> <property name="text"> @@ -656,7 +665,7 @@ </action> <action name="actionNewComment"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/add-comment.png</normaloff>:/icons/add-comment.png</iconset> </property> <property name="text"> @@ -665,7 +674,7 @@ </action> <action name="actionNewBFC"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/add-bfc.png</normaloff>:/icons/add-bfc.png</iconset> </property> <property name="text"> @@ -674,7 +683,7 @@ </action> <action name="actionNewVertex"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/add-vertex.png</normaloff>:/icons/add-vertex.png</iconset> </property> <property name="text"> @@ -683,7 +692,7 @@ </action> <action name="actionUndo"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/undo.png</normaloff>:/icons/undo.png</iconset> </property> <property name="text"> @@ -695,7 +704,7 @@ </action> <action name="actionRedo"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/redo.png</normaloff>:/icons/redo.png</iconset> </property> <property name="text"> @@ -707,7 +716,7 @@ </action> <action name="actionCut"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/cut.png</normaloff>:/icons/cut.png</iconset> </property> <property name="text"> @@ -719,7 +728,7 @@ </action> <action name="actionCopy"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/copy.png</normaloff>:/icons/copy.png</iconset> </property> <property name="text"> @@ -734,7 +743,7 @@ </action> <action name="actionPaste"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/paste.png</normaloff>:/icons/paste.png</iconset> </property> <property name="text"> @@ -746,7 +755,7 @@ </action> <action name="actionDelete"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/delete.png</normaloff>:/icons/delete.png</iconset> </property> <property name="text"> @@ -758,7 +767,7 @@ </action> <action name="actionSelectAll"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/select-all.png</normaloff>:/icons/select-all.png</iconset> </property> <property name="text"> @@ -767,7 +776,7 @@ </action> <action name="actionSelectByColor"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/select-color.png</normaloff>:/icons/select-color.png</iconset> </property> <property name="text"> @@ -776,7 +785,7 @@ </action> <action name="actionSelectByType"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/select-type.png</normaloff>:/icons/select-type.png</iconset> </property> <property name="text"> @@ -791,7 +800,7 @@ <bool>true</bool> </property> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/mode-select.png</normaloff>:/icons/mode-select.png</iconset> </property> <property name="text"> @@ -803,7 +812,7 @@ <bool>true</bool> </property> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/mode-draw.png</normaloff>:/icons/mode-draw.png</iconset> </property> <property name="text"> @@ -817,7 +826,7 @@ </action> <action name="actionSetColor"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/palette.png</normaloff>:/icons/palette.png</iconset> </property> <property name="text"> @@ -829,7 +838,7 @@ </action> <action name="actionAutocolor"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/autocolor.png</normaloff>:/icons/autocolor.png</iconset> </property> <property name="text"> @@ -841,7 +850,7 @@ </action> <action name="actionUncolorize"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/uncolorize.png</normaloff>:/icons/uncolorize.png</iconset> </property> <property name="text"> @@ -853,7 +862,7 @@ </action> <action name="actionInline"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/inline.png</normaloff>:/icons/inline.png</iconset> </property> <property name="text"> @@ -865,7 +874,7 @@ </action> <action name="actionInlineDeep"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/inline-deep.png</normaloff>:/icons/inline-deep.png</iconset> </property> <property name="text"> @@ -877,7 +886,7 @@ </action> <action name="actionInvert"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/invert.png</normaloff>:/icons/invert.png</iconset> </property> <property name="text"> @@ -886,7 +895,7 @@ </action> <action name="actionMakePrimitive"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/radial.png</normaloff>:/icons/radial.png</iconset> </property> <property name="text"> @@ -895,7 +904,7 @@ </action> <action name="actionSplitQuads"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/quad-split.png</normaloff>:/icons/quad-split.png</iconset> </property> <property name="text"> @@ -907,7 +916,7 @@ </action> <action name="actionEditRaw"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/set-contents.png</normaloff>:/icons/set-contents.png</iconset> </property> <property name="text"> @@ -919,7 +928,7 @@ </action> <action name="actionBorders"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/make-borders.png</normaloff>:/icons/make-borders.png</iconset> </property> <property name="text"> @@ -931,7 +940,7 @@ </action> <action name="actionCornerVerts"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/corner-verts.png</normaloff>:/icons/corner-verts.png</iconset> </property> <property name="text"> @@ -943,7 +952,7 @@ </action> <action name="actionRoundCoordinates"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/round-coords.png</normaloff>:/icons/round-coords.png</iconset> </property> <property name="text"> @@ -953,10 +962,10 @@ <string>Round coordinates down to 3/4 decimals</string> </property> </action> - <action name="actionVisibility"> + <action name="actionVisibilityToggle"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> - <normaloff>:/icons/visibility.png</normaloff>:/icons/visibility.png</iconset> + <iconset resource="../ldforge.qrc"> + <normaloff>:/icons/visibility-toggle.png</normaloff>:/icons/visibility-toggle.png</iconset> </property> <property name="text"> <string>Toggle Visibility</string> @@ -967,7 +976,7 @@ </action> <action name="actionReplaceCoords"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/replace-coords.png</normaloff>:/icons/replace-coords.png</iconset> </property> <property name="text"> @@ -979,7 +988,7 @@ </action> <action name="actionFlip"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/flip.png</normaloff>:/icons/flip.png</iconset> </property> <property name="text"> @@ -999,7 +1008,7 @@ </action> <action name="actionYtruder"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/ytruder.png</normaloff>:/icons/ytruder.png</iconset> </property> <property name="text"> @@ -1011,7 +1020,7 @@ </action> <action name="actionRectifier"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/rectifier.png</normaloff>:/icons/rectifier.png</iconset> </property> <property name="text"> @@ -1023,7 +1032,7 @@ </action> <action name="actionIntersector"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/intersector.png</normaloff>:/icons/intersector.png</iconset> </property> <property name="text"> @@ -1035,7 +1044,7 @@ </action> <action name="actionIsecalc"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/isecalc.png</normaloff>:/icons/isecalc.png</iconset> </property> <property name="text"> @@ -1047,7 +1056,7 @@ </action> <action name="actionCoverer"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/coverer.png</normaloff>:/icons/coverer.png</iconset> </property> <property name="text"> @@ -1067,7 +1076,7 @@ <bool>false</bool> </property> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/help.png</normaloff>:/icons/help.png</iconset> </property> <property name="text"> @@ -1076,7 +1085,7 @@ </action> <action name="actionAbout"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/ldforge.png</normaloff>:/icons/ldforge.png</iconset> </property> <property name="text"> @@ -1093,7 +1102,7 @@ <bool>true</bool> </property> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/grid-coarse.png</normaloff>:/icons/grid-coarse.png</iconset> </property> <property name="text"> @@ -1108,7 +1117,7 @@ <bool>true</bool> </property> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/grid-medium.png</normaloff>:/icons/grid-medium.png</iconset> </property> <property name="text"> @@ -1120,7 +1129,7 @@ <bool>true</bool> </property> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/grid-fine.png</normaloff>:/icons/grid-fine.png</iconset> </property> <property name="text"> @@ -1134,7 +1143,7 @@ </action> <action name="actionMoveUp"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/arrow-up.png</normaloff>:/icons/arrow-up.png</iconset> </property> <property name="text"> @@ -1143,7 +1152,7 @@ </action> <action name="actionMoveDown"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/arrow-down.png</normaloff>:/icons/arrow-down.png</iconset> </property> <property name="text"> @@ -1152,7 +1161,7 @@ </action> <action name="actionMoveXNeg"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/move-x-neg.png</normaloff>:/icons/move-x-neg.png</iconset> </property> <property name="text"> @@ -1161,7 +1170,7 @@ </action> <action name="actionMoveXPos"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/move-x-pos.png</normaloff>:/icons/move-x-pos.png</iconset> </property> <property name="text"> @@ -1170,7 +1179,7 @@ </action> <action name="actionMoveYNeg"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/move-y-neg.png</normaloff>:/icons/move-y-neg.png</iconset> </property> <property name="text"> @@ -1179,7 +1188,7 @@ </action> <action name="actionMoveYPos"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/move-y-pos.png</normaloff>:/icons/move-y-pos.png</iconset> </property> <property name="text"> @@ -1188,7 +1197,7 @@ </action> <action name="actionMoveZNeg"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/move-z-neg.png</normaloff>:/icons/move-z-neg.png</iconset> </property> <property name="text"> @@ -1197,7 +1206,7 @@ </action> <action name="actionMoveZPos"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/move-z-pos.png</normaloff>:/icons/move-z-pos.png</iconset> </property> <property name="text"> @@ -1256,7 +1265,7 @@ </action> <action name="actionNewFile"> <property name="icon"> - <iconset resource="../../ldforge.qrc"> + <iconset resource="../ldforge.qrc"> <normaloff>:/icons/file-new.png</normaloff>:/icons/file-new.png</iconset> </property> <property name="text"> @@ -1278,9 +1287,45 @@ <string>Go to Line...</string> </property> </action> + <action name="actionModeCircle"> + <property name="checkable"> + <bool>true</bool> + </property> + <property name="icon"> + <iconset resource="../ldforge.qrc"> + <normaloff>:/icons/mode-circle.png</normaloff>:/icons/mode-circle.png</iconset> + </property> + <property name="text"> + <string>Circle Mode</string> + </property> + </action> + <action name="actionVisibilityHide"> + <property name="icon"> + <iconset resource="../ldforge.qrc"> + <normaloff>:/icons/visibility-hide.png</normaloff>:/icons/visibility-hide.png</iconset> + </property> + <property name="text"> + <string>Hide</string> + </property> + <property name="toolTip"> + <string>Hides objects from view</string> + </property> + </action> + <action name="actionVisibilityReveal"> + <property name="icon"> + <iconset resource="../ldforge.qrc"> + <normaloff>:/icons/visibility-show.png</normaloff>:/icons/visibility-show.png</iconset> + </property> + <property name="text"> + <string>Reveal</string> + </property> + <property name="toolTip"> + <string>Reveals objects. Undoes hiding.</string> + </property> + </action> </widget> <resources> - <include location="../../ldforge.qrc"/> + <include location="../ldforge.qrc"/> </resources> <connections/> </ui>