# HG changeset patch # User Santeri Piippo # Date 1371259244 -10800 # Node ID be0c367e7420be32b954c960bb4dc6e84e0aa36d # Parent d7bf5c11d299794afdc4d0621c64496efcd802d2 Added primitive scanning, replaced parts list in subfile add dialog with it diff -r d7bf5c11d299 -r be0c367e7420 changelog.txt --- a/changelog.txt Sat Jun 15 01:29:46 2013 +0300 +++ b/changelog.txt Sat Jun 15 04:20:44 2013 +0300 @@ -5,6 +5,8 @@ - Completely rewrote history (undo/redo) code, making it a LOT stabler in the process. - Added ability to snap to pre-existing vertices while drawing. - When drawing, drawn vertices now display coordinate labels. +- Replaced parts list in subfile item list with a primitive listing. Listing is generated either if + it's not cached (prims.cfg in configuration directory) or on user demand. - Added an export to file action, moved it + insert from to File menu - Parts are now zoomed to fit properly, making the initial view of the part clearer. - Replace coords: allow replacing all coords regardless of original value, plus relative moving (offset) diff -r d7bf5c11d299 -r be0c367e7420 src/addObjectDialog.cpp --- a/src/addObjectDialog.cpp Sat Jun 15 01:29:46 2013 +0300 +++ b/src/addObjectDialog.cpp Sat Jun 15 04:20:44 2013 +0300 @@ -34,15 +34,14 @@ #include "widgets.h" #include "misc.h" -// ============================================================================= class SubfileListItem : public QTreeWidgetItem { + PROPERTY (PrimitiveInfo*, primInfo, setPrimInfo) + public: - SubfileListItem (QTreeWidgetItem* parent, int subfileID) : - QTreeWidgetItem (parent), subfileID (subfileID) {} - SubfileListItem (QTreeWidget* parent, int subfileID) : - QTreeWidgetItem (parent), subfileID (subfileID) {} - - int subfileID; + SubfileListItem (QTreeWidgetItem* parent, PrimitiveInfo* info) : + QTreeWidgetItem (parent), m_primInfo (info) {} + SubfileListItem (QTreeWidget* parent, PrimitiveInfo* info) : + QTreeWidgetItem (parent), m_primInfo (info) {} }; // ============================================================================= @@ -92,60 +91,32 @@ break; case LDObject::Subfile: - coordCount = 3; - - enum { - Parts, - Subparts, - Primitives, - HiRes, - }; - - tw_subfileList = new QTreeWidget (); -/* - for (int i : vector ({Parts, Subparts, Primitives, HiRes})) { - SubfileListItem* parentItem = new SubfileListItem (tw_subfileList, -1); - parentItem->setText (0, (i == Parts) ? "Parts" : - (i == Subparts) ? "Subparts" : - (i == Primitives) ? "Primitives" : - "Hi-Res"); + { + coordCount = 3; - ulong j = 0; - for (partListEntry& part : g_PartList) { - QList subfileItems; - - str fileName = part.name; - const bool isSubpart = fileName.mid (0, 2) == "s\\"; - const bool isPrimitive = part.title.mid (0, 9) == "Primitive"; - const bool isHiRes = fileName.mid (0, 3) == "48\\"; - - if ((i == Subparts && isSubpart) || - (i == Primitives && isPrimitive) || - (i == HiRes && isHiRes) || - (i == Parts && !isSubpart && !isPrimitive && !isHiRes)) - { - SubfileListItem* item = new SubfileListItem (parentItem, j); - item->setText (0, fmt ("%1 - %2", part.name, part.title)); - subfileItems.append (item); - } - - j++; + tw_subfileList = new QTreeWidget (); + SubfileListItem* parentItem = new SubfileListItem (tw_subfileList, null); + parentItem->setText (0, "Primitives"); + QList subfileItems; + + for (PrimitiveInfo& info : g_Primitives) { + SubfileListItem* item = new SubfileListItem (parentItem, &info); + item->setText (0, fmt ("%1 - %2", info.name, info.title)); + subfileItems << 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 (obj); + le_subfileName->setText (ref->fileInfo ()->name ()); + } + break; } -*/ - - 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 (obj); - le_subfileName->setText (ref->fileInfo ()->name ()); - } - break; case LDObject::Radial: coordCount = 3; @@ -311,7 +282,12 @@ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= str AddObjectDialog::currentSubfileName () { - return ""; + SubfileListItem* item = static_cast (tw_subfileList->currentItem ()); + + if (item->primInfo () == null) + return ""; // selected a heading + + return item->primInfo ()->name; } // ============================================================================= diff -r d7bf5c11d299 -r be0c367e7420 src/addObjectDialog.h --- a/src/addObjectDialog.h Sat Jun 15 01:29:46 2013 +0300 +++ b/src/addObjectDialog.h Sat Jun 15 04:20:44 2013 +0300 @@ -22,6 +22,7 @@ #include #include "ldtypes.h" +class QTreeWidgetItem; class QLineEdit; class RadioBox; class QCheckBox; diff -r d7bf5c11d299 -r be0c367e7420 src/config.cpp --- a/src/config.cpp Sat Jun 15 01:29:46 2013 +0300 +++ b/src/config.cpp Sat Jun 15 04:20:44 2013 +0300 @@ -69,8 +69,6 @@ str entry = line.left (equals); str valstring = line.right (line.length () - equals - 1); - print ("config: `%1` -> %2 == %3 (%4)\n", line, entry, valstring, equals); - // Find the config entry for this. config* cfg = null; for (config* i : g_configPointers) { diff -r d7bf5c11d299 -r be0c367e7420 src/file.cpp --- a/src/file.cpp Sat Jun 15 01:29:46 2013 +0300 +++ b/src/file.cpp Sat Jun 15 04:20:44 2013 +0300 @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -37,6 +38,9 @@ cfg (str, io_recentfiles, ""); static bool g_loadingMainFile = false; +PrimitiveLister* g_activePrimLister = null; +bool g_primListerMutex = false; +vector g_Primitives; // ============================================================================= namespace LDPaths { @@ -925,4 +929,108 @@ g_loadedFiles.clear (); g_loadedFiles << filesUsed; +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +void recursiveGetFilenames (QDir dir, vector& 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 + fnames << info.absoluteFilePath (); + } +} + +void PrimitiveLister::work () { + g_activePrimLister = this; + m_prims.clear (); + + QDir dir (LDPaths::prims ()); + assert (dir.exists ()); + + ulong baselen = dir.absolutePath ().length (); + + vector fnames; + recursiveGetFilenames (dir, fnames); + emit starting (fnames.size ()); + + ulong i = 0; + for (str fname : fnames) { + File f (fname, File::Read); + + PrimitiveInfo info; + info.name = fname.mid (baselen + 1); // make full path relative + info.name.replace ('/', '\\'); // use DOS backslashes, they're expected + + if (!f.readLine (info.title)) + info.title = ""; + + info.title = info.title.simplified (); + + 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::dirpath () + "prims.cfg", File::Write); + for (PrimitiveInfo& info : m_prims) + fprint (conf, "%1 %2\n", info.name, info.title); + + conf.close (); + + g_primListerMutex = true; + g_Primitives = m_prims; + g_primListerMutex = false; + + g_activePrimLister = null; + emit workDone (); +} + +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 (workDone ()), g_win, SLOT (primitiveLoaderEnd ())); + connect (listerThread, SIGNAL (started ()), lister, SLOT (work ())); + connect (listerThread, SIGNAL (finished ()), lister, SLOT (deleteLater ())); + listerThread->start (); +} + +void loadPrimitiveInfo () { + g_Primitives.clear (); + + // Try to load prims.cfg + File conf (config::dirpath () + "prims.cfg", File::Read); + if (!conf) { + // No prims.cfg, build it + PrimitiveLister::start (); + return; + } + + for (str line : conf) { + int space = line.indexOf (" "); + if (space == -1) + continue; + + PrimitiveInfo info; + info.name = line.left (space); + info.title = line.mid (space + 1); + g_Primitives << info; + } } \ No newline at end of file diff -r d7bf5c11d299 -r be0c367e7420 src/file.h --- a/src/file.h Sat Jun 15 01:29:46 2013 +0300 +++ b/src/file.h Sat Jun 15 04:20:44 2013 +0300 @@ -26,6 +26,7 @@ class History; class OpenProgressDialog; + namespace LDPaths { void initPaths (); bool tryConfigure (str path); @@ -138,6 +139,14 @@ str basename (str path); str dirname (str path); +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +// 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. +// ============================================================================= class FileLoader : public QObject { Q_OBJECT @@ -158,4 +167,40 @@ void workDone (); }; +struct PrimitiveInfo { + str name, title; +}; + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +// 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: + vector m_prims; +}; + +extern vector g_Primitives; +extern PrimitiveLister* g_activePrimLister; +extern bool g_primListerMutex; + +void loadPrimitiveInfo (); + #endif // FILE_H \ No newline at end of file diff -r d7bf5c11d299 -r be0c367e7420 src/gui.cpp --- a/src/gui.cpp Sat Jun 15 01:29:46 2013 +0300 +++ b/src/gui.cpp Sat Jun 15 04:20:44 2013 +0300 @@ -28,7 +28,10 @@ #include #include #include +#include +#include #include +#include #include "common.h" #include "gldraw.h" @@ -88,6 +91,15 @@ slot_selectionChanged (); setStatusBar (new QStatusBar); + + m_primLoaderBar = new QProgressBar; + m_primLoaderWidget = new QWidget; + QHBoxLayout* primLoaderLayout = new QHBoxLayout (m_primLoaderWidget); + primLoaderLayout->addWidget (new QLabel ("Loading primitives:")); + primLoaderLayout->addWidget (m_primLoaderBar); + statusBar ()->addPermanentWidget (m_primLoaderWidget); + m_primLoaderWidget->hide (); + setWindowIcon (getIcon ("ldforge")); updateTitle (); setMinimumSize (320, 200); @@ -174,6 +186,7 @@ addMenuAction ("setLDrawPath"); // Set LDraw Path menu->addSeparator (); // ------- addMenuAction ("testpic"); // Set LDraw Path + addMenuAction ("reloadPrimitives"); menu->addSeparator (); // ------- addMenuAction ("exit"); // Exit @@ -992,6 +1005,23 @@ AddObjectDialog::staticDialog (obj->getType (), obj); } +void ForgeWindow::primitiveLoaderStart (ulong max) { + m_primLoaderWidget->show (); + m_primLoaderBar->setRange (0, max); + m_primLoaderBar->setValue (0); +} + +void ForgeWindow::primitiveLoaderUpdate (ulong prog) { + m_primLoaderBar->setValue (prog); +} + +void ForgeWindow::primitiveLoaderEnd () { + QTimer* hidetimer = new QTimer; + connect (hidetimer, SIGNAL (timeout ()), m_primLoaderWidget, SLOT (hide ())); + hidetimer->setSingleShot (true); + hidetimer->start (2000); +} + // ============================================================================ void ObjectList::contextMenuEvent (QContextMenuEvent* ev) { g_win->spawnContextMenu (ev->globalPos ()); @@ -1097,7 +1127,7 @@ } } -// ======================================================================================================================================== +// ============================================================================= QDialogButtonBox* makeButtonBox (QDialog& dlg) { QDialogButtonBox* bbx_buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel); QWidget::connect (bbx_buttons, SIGNAL (accepted ()), &dlg, SLOT (accept ())); diff -r d7bf5c11d299 -r be0c367e7420 src/gui.h --- a/src/gui.h Sat Jun 15 01:29:46 2013 +0300 +++ b/src/gui.h Sat Jun 15 04:20:44 2013 +0300 @@ -25,7 +25,6 @@ #include "config.h" #include "ldtypes.h" -class QComboBox; class ForgeWindow; class color; class QSplitter; @@ -33,6 +32,8 @@ class QDialogButtonBox; class GLRenderer; class CheckBoxGroup; +class QComboBox; +class QProgressBar; // Stuff for dialogs #define IMPLEMENT_DIALOG_BUTTONS \ @@ -129,6 +130,11 @@ void setStatusBarText (str text); void addActionMeta (actionmeta& meta); +public slots: + void primitiveLoaderStart (ulong max); + void primitiveLoaderUpdate (ulong prog); + void primitiveLoaderEnd (); + protected: void closeEvent (QCloseEvent* ev); void logVA (LogType eType, const char* fmtstr, va_list va); @@ -143,6 +149,8 @@ QSplitter* m_splitter; str m_msglogHTML; QToolBar* m_colorToolBar; + QProgressBar* m_primLoaderBar; + QWidget* m_primLoaderWidget; vector m_toolBars; vector m_sel; vector m_colorMeta; diff -r d7bf5c11d299 -r be0c367e7420 src/gui_actions.cpp --- a/src/gui_actions.cpp Sat Jun 15 01:29:46 2013 +0300 +++ b/src/gui_actions.cpp Sat Jun 15 04:20:44 2013 +0300 @@ -494,4 +494,8 @@ delete[] imgdata; rend->deleteLater (); +} + +MAKE_ACTION (reloadPrimitives, "Scan Primitives", "", "", (0)) { + PrimitiveLister::start (); } \ No newline at end of file diff -r d7bf5c11d299 -r be0c367e7420 src/main.cpp --- a/src/main.cpp Sat Jun 15 01:29:46 2013 +0300 +++ b/src/main.cpp Sat Jun 15 04:20:44 2013 +0300 @@ -79,6 +79,8 @@ ForgeWindow* win = new ForgeWindow; newFile (); + loadPrimitiveInfo (); + win->show (); return app.exec (); } diff -r d7bf5c11d299 -r be0c367e7420 src/types.h --- a/src/types.h Sat Jun 15 01:29:46 2013 +0300 +++ b/src/types.h Sat Jun 15 04:20:44 2013 +0300 @@ -20,6 +20,7 @@ #define TYPES_H #include +#include #include #include "common.h"