# HG changeset patch # User Santeri Piippo # Date 1365518479 -10800 # Node ID f8917e9d07f65841e964bb5271f3d659fea677c8 # Parent c190fe2185067189f63d1553cb9590682c00f8f1 Extracted actions from ForgeWindow into their own files. The ACTION macro now manages meta, instances and callback definitions all in one. Too bad I still need to extern these actions in gui.cpp... maybe someday I'll find a way around it :) diff -r c190fe218506 -r f8917e9d07f6 common.h --- a/common.h Tue Apr 09 14:06:40 2013 +0300 +++ b/common.h Tue Apr 09 17:41:19 2013 +0300 @@ -54,6 +54,10 @@ #define DIRSLASH "/" #endif // WIN32 +#ifdef RELEASE +#define NDEBUG // remove asserts +#endif // RELEASE + static const double fMaxCoord = 10000.0; static const short dMainColor = 16; static const short dEdgeColor = 24; @@ -112,14 +116,25 @@ // Vertex at (0, 0, 0) extern const vertex g_Origin; +extern bool g_bApplicationReady; void logf (const char* fmt, ...) FORMAT_PRINTF (1, 2); void logf (logtype_e eType, const char* fmt, ...) FORMAT_PRINTF (2, 3); +// ----------------------------------------------------------------------------- +// Pointer to the OpenFile which is currently being edited by the user. extern OpenFile* g_CurrentFile; + +// ----------------------------------------------------------------------------- +// Pointer to the bounding box. extern bbox g_BBox; -extern ForgeWindow* g_qWindow; + +// ----------------------------------------------------------------------------- +// Vector of all currently opened files. extern vector g_LoadedFiles; + +// ----------------------------------------------------------------------------- +// Pointer to the main application. extern QApplication* g_qMainApp; #ifndef unix @@ -127,13 +142,14 @@ typedef unsigned long ulong; #endif // unix -typedef int8_t xchar; -typedef int16_t xshort; -typedef int32_t xlong; -typedef int64_t xlonglong; -typedef uint8_t xuchar; -typedef uint16_t xushort; -typedef uint32_t xulong; -typedef uint64_t xulonglong; +// Typedef out the _t suffices :) +typedef int8_t int8; +typedef int16_t int16; +typedef int32_t int32; +typedef int64_t int64; +typedef uint8_t uint8; +typedef uint16_t uint16; +typedef uint32_t uint32; +typedef uint64_t uint64; #endif \ No newline at end of file diff -r c190fe218506 -r f8917e9d07f6 file.cpp --- a/file.cpp Tue Apr 09 14:06:40 2013 +0300 +++ b/file.cpp Tue Apr 09 17:41:19 2013 +0300 @@ -176,7 +176,7 @@ g_LoadedFiles.clear(); g_CurrentFile = NULL; - g_qWindow->refresh (); + g_ForgeWindow->refresh (); } // ============================================================================= @@ -192,7 +192,7 @@ g_CurrentFile = f; g_BBox.calculate(); - g_qWindow->refresh (); + g_ForgeWindow->refresh (); } // ============================================================================= @@ -212,7 +212,7 @@ g_BBox.calculate(); // Rebuild the object tree view now. - g_qWindow->refresh (); + g_ForgeWindow->refresh (); } // ============================================================================= @@ -474,7 +474,7 @@ return; } - const ulong ulSpot = g_qWindow->getInsertionPoint (); + const ulong ulSpot = g_ForgeWindow->getInsertionPoint (); objects.insert (objects.begin() + ulSpot, obj); } diff -r c190fe218506 -r f8917e9d07f6 gui.cpp --- a/gui.cpp Tue Apr 09 14:06:40 2013 +0300 +++ b/gui.cpp Tue Apr 09 17:41:19 2013 +0300 @@ -26,56 +26,35 @@ #include "misc.h" #include "colors.h" #include "config.h" -#include "zz_addObjectDialog.h" -#include "zz_colorSelectDialog.h" -#include "zz_configDialog.h" -#include "zz_newPartDialog.h" -#include "zz_setContentsDialog.h" - -// ============================================================================= -// ACTION ARMADA -namespace Actions { - QAction* newFile, *open, *save, *saveAs, *exit; - QAction* cut, *copy, *paste, *del; - QAction* newSubfile, *newLine, *newTriangle, *newQuad; - QAction* newCondLine, *newComment, *newVertex; - QAction* splitQuads, *setContents, *setColor; - QAction* inlineContents, *deepInline, *makeBorders; - QAction* settings; - QAction* help, *about, *aboutQt; -}; -// Key-binding configurations -cfg (keyseq, key_newFile, (Qt::CTRL | Qt::Key_N)); -cfg (keyseq, key_open, (Qt::CTRL | Qt::Key_O)); -cfg (keyseq, key_save, (Qt::CTRL | Qt::Key_S)); -cfg (keyseq, key_saveAs, (Qt::CTRL | Qt::SHIFT | Qt::Key_S)); -cfg (keyseq, key_exit, (Qt::CTRL | Qt::Key_Q)); -cfg (keyseq, key_cut, (Qt::CTRL | Qt::Key_X)); -cfg (keyseq, key_copy, (Qt::CTRL | Qt::Key_C)); -cfg (keyseq, key_paste, (Qt::CTRL | Qt::Key_V)); -cfg (keyseq, key_del, (Qt::Key_Delete)); -cfg (keyseq, key_newSubfile, 0); -cfg (keyseq, key_newLine, 0); -cfg (keyseq, key_newTriangle, 0); -cfg (keyseq, key_newQuad, 0); -cfg (keyseq, key_newCondLine, 0); -cfg (keyseq, key_newComment, 0); -cfg (keyseq, key_newVertex, 0); -cfg (keyseq, key_splitQuads, 0); -cfg (keyseq, key_setContents, 0); -cfg (keyseq, key_inlineContents, (Qt::CTRL | Qt::Key_I)); -cfg (keyseq, key_deepInline, (Qt::CTRL | Qt::SHIFT | Qt::Key_I)); -cfg (keyseq, key_makeBorders, (Qt::CTRL | Qt::SHIFT | Qt::Key_B)); -cfg (keyseq, key_settings, 0); -cfg (keyseq, key_help, (Qt::Key_F1)); -cfg (keyseq, key_about, 0); -cfg (keyseq, key_aboutQt, 0); -cfg (keyseq, key_setColor, 0); +EXTERN_ACTION (newFile) +EXTERN_ACTION (open) +EXTERN_ACTION (save) +EXTERN_ACTION (saveAs) +EXTERN_ACTION (settings) +EXTERN_ACTION (exit) +EXTERN_ACTION (cut) +EXTERN_ACTION (copy) +EXTERN_ACTION (paste) +EXTERN_ACTION (del) +EXTERN_ACTION (setColor) +EXTERN_ACTION (inlineContents) +EXTERN_ACTION (deepInline) +EXTERN_ACTION (splitQuads) +EXTERN_ACTION (setContents) +EXTERN_ACTION (makeBorders) +EXTERN_ACTION (newSubfile) +EXTERN_ACTION (newLine) +EXTERN_ACTION (newCondLine) +EXTERN_ACTION (newTriangle) +EXTERN_ACTION (newQuad) +EXTERN_ACTION (newVertex) +EXTERN_ACTION (newComment) +EXTERN_ACTION (help) +EXTERN_ACTION (about) +EXTERN_ACTION (aboutQt) -vector g_Clipboard; vector g_ActionMeta; - cfg (bool, lv_colorize, true); // ============================================================================= @@ -119,63 +98,22 @@ // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= -#define ACTION(N) (Actions::N) -#define MAKE_ACTION(OBJECT, DISPLAYNAME, IMAGENAME, DESCR) \ - ACTION (OBJECT) = new QAction (QIcon ("./icons/" IMAGENAME ".png"), tr (DISPLAYNAME), this); \ - ACTION (OBJECT)->setStatusTip (tr (DESCR)); \ - connect (ACTION (OBJECT), SIGNAL (triggered ()), this, SLOT (slot_##OBJECT ())); \ - { \ - actionmeta meta = {&ACTION (OBJECT), &key_##OBJECT}; \ - g_ActionMeta.push_back (meta); \ +void ForgeWindow::createMenuActions () { + // Create the actions based on stored meta. + for (actionmeta meta : g_ActionMeta) { + QAction*& qAct = *meta.qAct; + qAct = new QAction (getIcon (meta.sIconName), meta.sDisplayName, this); + qAct->setStatusTip (meta.sDescription); + qAct->setShortcut (*meta.conf); + + connect (qAct, SIGNAL (triggered ()), this, SLOT (slot_action ())); } - -void ForgeWindow::createMenuActions () { - // Long menu names go here so my cool action definition table doesn't get out of proportions - char const* sNewCdLineText = "New Conditional Line", - *sNewQuadText = "New Quadrilateral", - *sAboutText = "About " APPNAME_DISPLAY; - - MAKE_ACTION (newFile, "&New", "brick", "Create a new part model.") - MAKE_ACTION (open, "&Open", "file-open", "Load a part model from a file.") - MAKE_ACTION (save, "&Save", "file-save", "Save the part model.") - MAKE_ACTION (saveAs, "Save &As", "file-save-as", "Save the part to a specific file.") - MAKE_ACTION (exit, "&Exit", "exit", "Close " APPNAME_DISPLAY ".") - - MAKE_ACTION (cut, "Cut", "cut", "Cut the current selection to clipboard.") - MAKE_ACTION (copy, "Copy", "copy", "Copy the current selection to clipboard.") - MAKE_ACTION (paste, "Paste", "paste", "Paste clipboard contents.") - MAKE_ACTION (del, "Delete", "delete", "Delete the selection") - - MAKE_ACTION (setColor, "Set Color", "palette", "Set the color on given objects.") - MAKE_ACTION (inlineContents,"Inline", "inline", "Inline selected subfiles.") - MAKE_ACTION (deepInline, "Deep Inline", "inline-deep", "Recursively inline selected subfiles down to polygons only.") - MAKE_ACTION (splitQuads, "Split Quads", "quad-split", "Split quads into triangles.") - MAKE_ACTION (setContents, "Set Contents", "set-contents", "Set the raw code of this object.") - MAKE_ACTION (makeBorders, "Make Borders", "make-borders", "Add borders around given polygons.") - - MAKE_ACTION (newSubfile, "New Subfile", "add-subfile", "Creates a new subfile reference.") - MAKE_ACTION (newLine, "New Line", "add-line", "Creates a new line.") - MAKE_ACTION (newTriangle, "New Triangle", "add-triangle", "Creates a new triangle.") - MAKE_ACTION (newQuad, sNewQuadText, "add-quad", "Creates a new quadrilateral.") - MAKE_ACTION (newCondLine, sNewCdLineText, "add-condline", "Creates a new conditional line.") - MAKE_ACTION (newComment, "New Comment", "add-comment", "Creates a new comment.") - MAKE_ACTION (newVertex, "New Vertex", "add-vertex", "Creates a new vertex.") - - MAKE_ACTION (settings, "Settings", "settings", "Edit the settings of " APPNAME_DISPLAY ".") - - MAKE_ACTION (help, "Help", "help", "Shows the " APPNAME_DISPLAY " help manual.") - MAKE_ACTION (about, sAboutText, "ldforge", "Shows information about " APPNAME_DISPLAY ".") - MAKE_ACTION (aboutQt, "About Qt", "aboutQt", "Shows information about Qt.") - - // Apply the shortcuts now - for (actionmeta meta : g_ActionMeta) - (*meta.qAct)->setShortcut (*meta.conf); // things not implemented yet QAction* const qaDisabledActions[] = { - ACTION (newSubfile), - ACTION (about), - ACTION (help), + ACTION_NAME (newSubfile), + ACTION_NAME (about), + ACTION_NAME (help), }; for (QAction* act : qaDisabledActions) @@ -185,7 +123,7 @@ // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= -#define ADD_MENU_ITEM(MENU, ACT) q##MENU##Menu->addAction (ACTION (ACT)); +#define ADD_MENU_ITEM(MENU, ACT) q##MENU##Menu->addAction (ACTION_NAME (ACT)); void ForgeWindow::createMenus () { // File menu @@ -199,7 +137,7 @@ qFileMenu->addSeparator (); // ------- ADD_MENU_ITEM (File, exit) // Exit - // Edit menu + // Insert menu qInsertMenu = menuBar ()->addMenu (tr ("&Insert")); ADD_MENU_ITEM (Insert, newSubfile) // New Subfile ADD_MENU_ITEM (Insert, newLine) // New Line @@ -209,6 +147,7 @@ ADD_MENU_ITEM (Insert, newComment) // New Comment ADD_MENU_ITEM (Insert, newVertex) // New Vertex + // Edit menu qEditMenu = menuBar ()->addMenu (tr ("&Edit")); ADD_MENU_ITEM (Edit, cut) // Cut ADD_MENU_ITEM (Edit, copy) // Copy @@ -234,7 +173,7 @@ // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= -#define ADD_TOOLBAR_ITEM(BAR, ACT) q##BAR##ToolBar->addAction (ACTION (ACT)); +#define ADD_TOOLBAR_ITEM(BAR, ACT) q##BAR##ToolBar->addAction (ACTION_NAME (ACT)); void ForgeWindow::createToolbars () { qFileToolBar = new QToolBar ("File"); @@ -292,319 +231,27 @@ // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= -void ForgeWindow::slot_newFile () { - // newFile (); - NewPartDialog::StaticDialog (); -} - -void ForgeWindow::slot_open () { - str zName; - zName += QFileDialog::getOpenFileName (this, "Open File", - "", "LDraw files (*.dat *.ldr)"); +void ForgeWindow::slot_action () { + // Get the action that triggered this slot. + QAction* qAct = static_cast (sender ()); + + // Find the meta for the action. + actionmeta* pMeta = nullptr; - if (~zName) - openMainFile (zName); -} - -void ForgeWindow::slot_save () { - if (!~g_CurrentFile->zFileName) { - // If we don't have a file name, this is an anonymous file created - // with the new file command. We cannot save without a name so ask - // the user for one. - slot_saveAs (); + for (actionmeta meta : g_ActionMeta) { + if (*meta.qAct == qAct) { + pMeta = &meta; + break; + } + } + + if (!pMeta) { + fprintf (stderr, "unknown signal sender %p!\n", qAct); return; } - g_CurrentFile->save (); -} - -void ForgeWindow::slot_saveAs () { - str zName; - zName += QFileDialog::getSaveFileName (this, "Save As", - "", "LDraw files (*.dat *.ldr)"); - - if (~zName && g_CurrentFile->save (zName)) - g_CurrentFile->zFileName = zName; -} - -void ForgeWindow::slot_settings () { - ConfigDialog::staticDialog (this); -} - -void ForgeWindow::slot_exit () { - exit (0); -} - -void ForgeWindow::slot_newSubfile () { - -} - -void ForgeWindow::slot_newLine () { - AddObjectDialog::staticDialog (OBJ_Line, this); -} - -void ForgeWindow::slot_newTriangle () { - AddObjectDialog::staticDialog (OBJ_Triangle, this); -} - -void ForgeWindow::slot_newQuad () { - AddObjectDialog::staticDialog (OBJ_Quad, this); -} - -void ForgeWindow::slot_newCondLine () { - AddObjectDialog::staticDialog (OBJ_CondLine, this); -} - -void ForgeWindow::slot_newComment () { - AddObjectDialog::staticDialog (OBJ_Comment, this); -} - -void ForgeWindow::slot_help () { - -} - -void ForgeWindow::slot_about () { - -} - -void ForgeWindow::slot_aboutQt () { - QMessageBox::aboutQt (this); -} - -// ============================================================================= -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// ============================================================================= -bool ForgeWindow::copyToClipboard () { - vector objs = getSelectedObjects (); - - if (objs.size() == 0) - return false; - - // Clear the clipboard first. - for (LDObject* obj : g_Clipboard) - delete obj; - - g_Clipboard.clear (); - - // Now, copy the contents into the clipboard. The objects should be - // separate objects so that modifying the existing ones does not affect - // the clipboard. Thus, we add clones of the objects to the clipboard, not - // the objects themselves. - for (ulong i = 0; i < objs.size(); ++i) - g_Clipboard.push_back (objs[i]->clone ()); - - return true; -} - -// ============================================================================= -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// ============================================================================= -void ForgeWindow::slot_cut () { - if (!copyToClipboard ()) - return; - - deleteSelection (); - - ACTION (paste)->setEnabled (true); - refresh (); -} - -// ============================================================================= -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// ============================================================================= -void ForgeWindow::slot_copy () { - if (copyToClipboard ()) - ACTION (paste)->setEnabled (true); -} - -// ============================================================================= -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// ============================================================================= -void ForgeWindow::slot_paste () { - for (LDObject* obj : g_Clipboard) - g_CurrentFile->addObject (obj->clone ()); - - refresh (); -} - -// ============================================================================= -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// ============================================================================= -void ForgeWindow::slot_del () { - deleteSelection (); - refresh (); -} - -// ============================================================================= -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// ============================================================================= -void ForgeWindow::slot_newVertex () { - AddObjectDialog::staticDialog (OBJ_Vertex, this); -} - -// ============================================================================= -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// ============================================================================= -void ForgeWindow::doInline (bool bDeep) { - vector sel = getSelectedObjects (); - - for (LDObject* obj : sel) { - // Obviously, only subfiles can be inlined. - if (obj->getType() != OBJ_Subfile) - continue; - - // Get the index of the subfile so we know where to insert the - // inlined contents. - long idx = obj->getIndex (g_CurrentFile); - if (idx == -1) - continue; - - LDSubfile* ref = static_cast (obj); - - // Get the inlined objects. These are clones of the subfile's contents. - vector objs = ref->inlineContents (bDeep, true); - - // Merge in the inlined objects - for (LDObject* inlineobj : objs) - g_CurrentFile->objects.insert (g_CurrentFile->objects.begin() + idx++, inlineobj); - - // Delete the subfile now as it's been inlined. - g_CurrentFile->forgetObject (ref); - delete ref; - } - - refresh (); -} - -void ForgeWindow::slot_inlineContents () { - doInline (false); -} - -void ForgeWindow::slot_deepInline () { - doInline (true); -} - -// ============================================================================= -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// ============================================================================= -void ForgeWindow::slot_splitQuads () { - vector objs = getSelectedObjects (); - - for (LDObject* obj : objs) { - if (obj->getType() != OBJ_Quad) - continue; - - // Find the index of this quad - long lIndex = obj->getIndex (g_CurrentFile); - - if (lIndex == -1) { - // couldn't find it? - logf (LOG_Error, "Couldn't find quad %p in " - "current object list!!\n", this); - return; - } - - std::vector triangles = static_cast (obj)->splitToTriangles (); - - // Replace the quad with the first triangle and add the second triangle - // after the first one. - g_CurrentFile->objects[lIndex] = triangles[0]; - g_CurrentFile->objects.insert (g_CurrentFile->objects.begin() + lIndex + 1, triangles[1]); - - // Delete this quad now, it has been split. - delete this; - } - - refresh (); -} - -// ============================================================================= -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// ============================================================================= -void ForgeWindow::slot_setContents () { - if (qObjList->selectedItems().size() != 1) - return; - - LDObject* obj = getSelectedObjects ()[0]; - SetContentsDialog::staticDialog (obj, this); -} - -// ============================================================================= -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// ============================================================================= -void ForgeWindow::slot_setColor () { - if (qObjList->selectedItems().size() <= 0) - return; - - short dColor; - short dDefault = -1; - - std::vector objs = getSelectedObjects (); - - // If all selected objects have the same color, said color is our default - // value to the color selection dialog. - for (LDObject* obj : objs) { - if (obj->dColor == -1) - continue; // doesn't use color - - if (dDefault != -1 && obj->dColor != dDefault) { - // No consensus in object color, therefore we don't have a - // proper default value to use. - dDefault = -1; - break; - } - - if (dDefault == -1) - dDefault = obj->dColor; - } - - // Show the dialog to the user now and ask for a color. - if (ColorSelectDialog::staticDialog (dColor, dDefault, this)) { - for (LDObject* obj : objs) - if (obj->dColor != -1) - obj->dColor = dColor; - - refresh (); - } -} - -// ============================================================================= -// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -// ============================================================================= -void ForgeWindow::slot_makeBorders () { - vector objs = getSelectedObjects (); - - for (LDObject* obj : objs) { - if (obj->getType() != OBJ_Quad && obj->getType() != OBJ_Triangle) - continue; - - short dNumLines; - LDLine* lines[4]; - - if (obj->getType() == OBJ_Quad) { - dNumLines = 4; - - LDQuad* quad = static_cast (obj); - lines[0] = new LDLine (quad->vaCoords[0], quad->vaCoords[1]); - lines[1] = new LDLine (quad->vaCoords[1], quad->vaCoords[2]); - lines[2] = new LDLine (quad->vaCoords[2], quad->vaCoords[3]); - lines[3] = new LDLine (quad->vaCoords[3], quad->vaCoords[0]); - } else { - dNumLines = 3; - - LDTriangle* tri = static_cast (obj); - lines[0] = new LDLine (tri->vaCoords[0], tri->vaCoords[1]); - lines[1] = new LDLine (tri->vaCoords[1], tri->vaCoords[2]); - lines[2] = new LDLine (tri->vaCoords[2], tri->vaCoords[0]); - } - - for (short i = 0; i < dNumLines; ++i) { - lines[i]->dColor = dEdgeColor; - g_CurrentFile->addObject (lines[i]); - } - } - - refresh (); + // We have the meta, now call the handler. + (*pMeta->handler) (); } // ============================================================================= @@ -618,6 +265,9 @@ g_CurrentFile->forgetObject (obj); delete obj; } + + if (objs.size() > 0) + refresh (); } // ============================================================================= @@ -755,11 +405,13 @@ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= void ForgeWindow::slot_selectionChanged () { + /* // If the selection isn't 1 exact, disable setting contents ACTION (setContents)->setEnabled (qObjList->selectedItems().size() == 1); // If we have no selection, disable splitting quads ACTION (splitQuads)->setEnabled (qObjList->selectedItems().size() > 0); + */ } // ============================================================================= @@ -806,4 +458,11 @@ } return objs; +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +QIcon getIcon (const char* sIconName) { + return (QIcon (str::mkfmt ("./icons/%s.png", sIconName))); } \ No newline at end of file diff -r c190fe218506 -r f8917e9d07f6 gui.h --- a/gui.h Tue Apr 09 14:06:40 2013 +0300 +++ b/gui.h Tue Apr 09 17:41:19 2013 +0300 @@ -35,6 +35,61 @@ connect (qButtons, SIGNAL (accepted ()), this, SLOT (accept ())); \ connect (qButtons, SIGNAL (rejected ()), this, SLOT (reject ())); \ +// ============================================================================= +// Metadata for actions +typedef struct { + QAction** const qAct; + keyseqconfig* const conf; + const char* const sDisplayName, *sIconName, *sDescription; + void (*const handler) (); +} actionmeta; + +extern vector g_ActionMeta; + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +#define ACTION(NAME, DISPLAYNAME, ICONNAME, DESCR, DEFSHORTCUT) \ + QAction* ACTION_NAME (NAME); \ + cfg (keyseq, key_##NAME, DEFSHORTCUT); \ + static void actionHandler_##NAME (); \ + static ActionAdder ActionAdderInstance_##NAME (&ACTION_NAME(NAME), DISPLAYNAME, \ + ICONNAME, DESCR, &key_##NAME, actionHandler_##NAME); \ + static void actionHandler_##NAME () + +#define EXTERN_ACTION(NAME) extern QAction* ACTION_NAME (NAME); +#define ACTION_NAME(N) (LDForgeAction_##N) + +// Convenience macros for key sequences. +#define KEY(N) (Qt::Key_##N) +#define CTRL(N) (Qt::CTRL | Qt::Key_##N) +#define SHIFT(N) (Qt::SHIFT | Qt::Key_##N) +#define CTRL_SHIFT(N) (Qt::CTRL | Qt::SHIFT | Qt::Key_##N) + +// ============================================================================= +// ActionAdder +// +// The ACTION macro expands into - among other stuff - into an instance of this. +// This class' constructor creates meta for the newly defined action and stores +// it in g_ActionMeta. It is not supposed to be used directly! +// ============================================================================= +class ActionAdder { +public: + ActionAdder (QAction** qAct, const char* sDisplayName, const char* sIconName, + const char* sDescription, keyseqconfig* conf, void (*const handler) ()) + { + actionmeta meta = {qAct, conf, sDisplayName, sIconName, sDescription, handler}; + g_ActionMeta.push_back (meta); + } +}; + +// ============================================================================= +// 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 @@ -43,84 +98,43 @@ // Object list view QTreeWidget* qObjList; - - // Message log QTextEdit* qMessageLog; - str zMessageLogHTML; + QMenu* qFileMenu, *qEditMenu, *qInsertMenu, *qHelpMenu; + QToolBar* qFileToolBar, *qEditToolBar, *qInsertToolBar; - // Menus - QMenu* qFileMenu, *qEditMenu, *qInsertMenu, *qHelpMenu; - - // Toolbars - QToolBar* qFileToolBar, *qEditToolBar, *qInsertToolBar; + str zMessageLogHTML; ForgeWindow (); void buildObjList (); void setTitle (); void refresh (); std::vector getSelectedObjects (); - - // Where would a new item be inserted into? ulong getInsertionPoint (); - + void deleteSelection (); + private: void createMenuActions (); void createMenus (); void createToolbars (); - bool copyToClipboard (); - void deleteSelection (); - void doInline (bool bDeep); private slots: void slot_selectionChanged (); - - void slot_newFile (); - void slot_open (); - void slot_save (); - void slot_saveAs (); - void slot_exit (); - - void slot_newSubfile (); - void slot_newLine (); - void slot_newTriangle (); - void slot_newQuad (); - void slot_newCondLine (); - void slot_newComment (); - void slot_newVertex (); - - void slot_inlineContents (); - void slot_deepInline (); - void slot_splitQuads (); - void slot_setContents (); - void slot_makeBorders (); - - void slot_cut (); - void slot_copy (); - void slot_paste (); - void slot_del (); - - void slot_settings (); - - void slot_help (); - void slot_about (); - void slot_aboutQt (); - - void slot_setColor (); + void slot_action (); }; +// ----------------------------------------------------------------------------- +// Other GUI-related stuff not directly part of ForgeWindow: +QIcon getIcon (const char* sIconName); + +// ----------------------------------------------------------------------------- +// Pointer to the instance of ForgeWindow. +extern ForgeWindow* g_ForgeWindow; + +// Is this still needed? enum { LDOLC_Icon, LDOLC_Data, NUM_LDOL_Columns }; -// ============================================================================= -// Metadata for actions -typedef struct { - QAction** const qAct; - keyseqconfig* const conf; -} actionmeta; - -extern vector g_ActionMeta; - #endif \ No newline at end of file diff -r c190fe218506 -r f8917e9d07f6 gui_actions.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gui_actions.cpp Tue Apr 09 17:41:19 2013 +0300 @@ -0,0 +1,140 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013 Santeri `arezey` Piippo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include "gui.h" +#include "file.h" +#include "zz_newPartDialog.h" +#include "zz_configDialog.h" +#include "zz_addObjectDialog.h" + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +ACTION (newFile, "&New", "brick", "Create a new part model.", CTRL (N)) { + NewPartDialog::StaticDialog (); +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +ACTION (open, "&Open", "file-open", "Load a part model from a file.", CTRL (O)) { + str zName; + zName += QFileDialog::getOpenFileName (g_ForgeWindow, "Open File", + "", "LDraw files (*.dat *.ldr)"); + + if (~zName) + openMainFile (zName); +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +void doSaveAs () { + str zName; + zName += QFileDialog::getSaveFileName (g_ForgeWindow, "Save As", + "", "LDraw files (*.dat *.ldr)"); + + if (~zName && g_CurrentFile->save (zName)) + g_CurrentFile->zFileName = zName; +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +ACTION (save, "&Save", "file-save", "Save the part model.", CTRL (S)) { + if (!~g_CurrentFile->zFileName) { + // If we don't have a file name, this is an anonymous file created + // with the new file command. We cannot save without a name so ask + // the user for one. + doSaveAs (); + return; + } + + g_CurrentFile->save (); +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +ACTION (saveAs, "Save &As", "file-save-as", "Save the part model to a specific file.", CTRL_SHIFT (S)) +{ + doSaveAs (); +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +ACTION (settings, "Settings", "settings", "Edit the settings of " APPNAME_DISPLAY ".", (0)) { + ConfigDialog::staticDialog (g_ForgeWindow); +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +ACTION (exit, "&Exit", "exit", "Close " APPNAME_DISPLAY ".", CTRL (Q)) { + exit (0); +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +ACTION (newSubfile, "New Subfile", "add-subfile", "Creates a new subfile reference.", 0) { + +} + +ACTION (newLine, "New Line", "add-line", "Creates a new line.", 0) { + AddObjectDialog::staticDialog (OBJ_Line, g_ForgeWindow); +} + +ACTION (newTriangle, "New Triangle", "add-triangle", "Creates a new triangle.", 0) { + AddObjectDialog::staticDialog (OBJ_Triangle, g_ForgeWindow); +} + +ACTION (newQuad, "New Quadrilateral", "add-quad", "Creates a new quadrilateral.", 0) { + AddObjectDialog::staticDialog (OBJ_Quad, g_ForgeWindow); +} + +ACTION (newCondLine, "New Conditional Line", "add-condline", "Creates a new conditional line.", 0) { + AddObjectDialog::staticDialog (OBJ_CondLine, g_ForgeWindow); +} + +ACTION (newComment, "New Comment", "add-comment", "Creates a new comment.", 0) { + AddObjectDialog::staticDialog (OBJ_Comment, g_ForgeWindow); +} +ACTION (newVertex, "New Vertex", "add-vertex", "Creates a new vertex.", 0) { + AddObjectDialog::staticDialog (OBJ_Vertex, g_ForgeWindow); +} + +ACTION (help, "Help", "help", "Shows the " APPNAME_DISPLAY " help manual.", KEY (F1)) { + +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +ACTION (about, "About" APPNAME_DISPLAY, "ldforge", + "Shows information about " APPNAME_DISPLAY ".", CTRL (F1)) +{ + +} + +ACTION (aboutQt, "About Qt", "aboutQt", "Shows information about Qt.", CTRL_SHIFT (F1)) { + QMessageBox::aboutQt (g_ForgeWindow); +} \ No newline at end of file diff -r c190fe218506 -r f8917e9d07f6 gui_editactions.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gui_editactions.cpp Tue Apr 09 17:41:19 2013 +0300 @@ -0,0 +1,253 @@ +/* + * LDForge: LDraw parts authoring CAD + * Copyright (C) 2013 Santeri `arezey` Piippo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "gui.h" +#include "common.h" +#include "zz_setContentsDialog.h" +#include "file.h" +#include "zz_colorSelectDialog.h" + +vector g_Clipboard; + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +static bool copyToClipboard () { + vector objs = g_ForgeWindow->getSelectedObjects (); + + if (objs.size() == 0) + return false; + + // Clear the clipboard first. + for (LDObject* obj : g_Clipboard) + delete obj; + + g_Clipboard.clear (); + + // Now, copy the contents into the clipboard. The objects should be + // separate objects so that modifying the existing ones does not affect + // the clipboard. Thus, we add clones of the objects to the clipboard, not + // the objects themselves. + for (ulong i = 0; i < objs.size(); ++i) + g_Clipboard.push_back (objs[i]->clone ()); + + return true; +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +ACTION (cut, "Cut", "cut", "Cut the current selection to clipboard.", CTRL (X)) { + if (!copyToClipboard ()) + return; + + g_ForgeWindow->deleteSelection (); +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +ACTION (copy, "Copy", "copy", "Copy the current selection to clipboard.", CTRL (C)) { + copyToClipboard (); +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +ACTION (paste, "Paste", "paste", "Paste clipboard contents.", CTRL (V)) { + for (LDObject* obj : g_Clipboard) + g_CurrentFile->addObject (obj->clone ()); + + g_ForgeWindow->refresh (); +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +ACTION (del, "Delete", "delete", "Delete the selection", KEY (Delete)) { + g_ForgeWindow->deleteSelection (); +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +static void doInline (bool bDeep) { + vector sel = g_ForgeWindow->getSelectedObjects (); + + for (LDObject* obj : sel) { + // Obviously, only subfiles can be inlined. + if (obj->getType() != OBJ_Subfile) + continue; + + // Get the index of the subfile so we know where to insert the + // inlined contents. + long idx = obj->getIndex (g_CurrentFile); + if (idx == -1) + continue; + + LDSubfile* ref = static_cast (obj); + + // Get the inlined objects. These are clones of the subfile's contents. + vector objs = ref->inlineContents (bDeep, true); + + // Merge in the inlined objects + for (LDObject* inlineobj : objs) + g_CurrentFile->objects.insert (g_CurrentFile->objects.begin() + idx++, inlineobj); + + // Delete the subfile now as it's been inlined. + g_CurrentFile->forgetObject (ref); + delete ref; + } + + g_ForgeWindow->refresh (); +} + +ACTION (inlineContents, "Inline", "inline", "Inline selected subfiles.", CTRL (I)) { + doInline (false); +} + +ACTION (deepInline, "Deep Inline", "inline-deep", "Recursively inline selected subfiles " + "down to polygons only.", CTRL_SHIFT (I)) +{ + doInline (true); +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +ACTION (splitQuads, "Split Quads", "quad-split", "Split quads into triangles.", (0)) { + vector objs = g_ForgeWindow->getSelectedObjects (); + + for (LDObject* obj : objs) { + if (obj->getType() != OBJ_Quad) + continue; + + // Find the index of this quad + long lIndex = obj->getIndex (g_CurrentFile); + + if (lIndex == -1) { + // couldn't find it? + logf (LOG_Error, "Couldn't find quad %p in " + "current object list!!\n", obj); + return; + } + + std::vector triangles = static_cast (obj)->splitToTriangles (); + + // Replace the quad with the first triangle and add the second triangle + // after the first one. + g_CurrentFile->objects[lIndex] = triangles[0]; + g_CurrentFile->objects.insert (g_CurrentFile->objects.begin() + lIndex + 1, triangles[1]); + + // Delete this quad now, it has been split. + delete obj; + } + + g_ForgeWindow->refresh (); +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +ACTION (setContents, "Set Contents", "set-contents", "Set the raw code of this object.", KEY (F9)) { + if (g_ForgeWindow->qObjList->selectedItems().size() != 1) + return; + + LDObject* obj = g_ForgeWindow->getSelectedObjects ()[0]; + SetContentsDialog::staticDialog (obj, g_ForgeWindow); +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +ACTION (setColor, "Set Color", "palette", "Set the color on given objects.", KEY (F10)) { + if (g_ForgeWindow->qObjList->selectedItems().size() <= 0) + return; + + short dColor; + short dDefault = -1; + + std::vector objs = g_ForgeWindow->getSelectedObjects (); + + // If all selected objects have the same color, said color is our default + // value to the color selection dialog. + for (LDObject* obj : objs) { + if (obj->dColor == -1) + continue; // doesn't use color + + if (dDefault != -1 && obj->dColor != dDefault) { + // No consensus in object color, therefore we don't have a + // proper default value to use. + dDefault = -1; + break; + } + + if (dDefault == -1) + dDefault = obj->dColor; + } + + // Show the dialog to the user now and ask for a color. + if (ColorSelectDialog::staticDialog (dColor, dDefault, g_ForgeWindow)) { + for (LDObject* obj : objs) + if (obj->dColor != -1) + obj->dColor = dColor; + + g_ForgeWindow->refresh (); + } +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +ACTION (makeBorders, "Make Borders", "make-borders", "Add borders around given polygons.", + CTRL_SHIFT (B)) +{ + vector objs = g_ForgeWindow->getSelectedObjects (); + + for (LDObject* obj : objs) { + if (obj->getType() != OBJ_Quad && obj->getType() != OBJ_Triangle) + continue; + + short dNumLines; + LDLine* lines[4]; + + if (obj->getType() == OBJ_Quad) { + dNumLines = 4; + + LDQuad* quad = static_cast (obj); + lines[0] = new LDLine (quad->vaCoords[0], quad->vaCoords[1]); + lines[1] = new LDLine (quad->vaCoords[1], quad->vaCoords[2]); + lines[2] = new LDLine (quad->vaCoords[2], quad->vaCoords[3]); + lines[3] = new LDLine (quad->vaCoords[3], quad->vaCoords[0]); + } else { + dNumLines = 3; + + LDTriangle* tri = static_cast (obj); + lines[0] = new LDLine (tri->vaCoords[0], tri->vaCoords[1]); + lines[1] = new LDLine (tri->vaCoords[1], tri->vaCoords[2]); + lines[2] = new LDLine (tri->vaCoords[2], tri->vaCoords[0]); + } + + for (short i = 0; i < dNumLines; ++i) { + lines[i]->dColor = dEdgeColor; + g_CurrentFile->addObject (lines[i]); + } + } + + g_ForgeWindow->refresh (); +} diff -r c190fe218506 -r f8917e9d07f6 ldforge.pro --- a/ldforge.pro Tue Apr 09 14:06:40 2013 +0300 +++ b/ldforge.pro Tue Apr 09 17:41:19 2013 +0300 @@ -32,6 +32,8 @@ colors.cpp \ gldraw.cpp \ gui.cpp \ + gui_actions.cpp \ + gui_editactions.cpp \ file.cpp \ ldtypes.cpp \ main.cpp \ diff -r c190fe218506 -r f8917e9d07f6 main.cpp --- a/main.cpp Tue Apr 09 14:06:40 2013 +0300 +++ b/main.cpp Tue Apr 09 17:41:19 2013 +0300 @@ -27,7 +27,7 @@ vector g_LoadedFiles; OpenFile* g_CurrentFile = nullptr; -ForgeWindow* g_qWindow = nullptr; +ForgeWindow* g_ForgeWindow = nullptr; bbox g_BBox; QApplication* g_qMainApp = nullptr; @@ -49,7 +49,7 @@ ForgeWindow* win = new ForgeWindow; g_qMainApp = &app; - g_qWindow = win; + g_ForgeWindow = win; newFile (); @@ -80,7 +80,7 @@ zText.replace (">", ">"); zText.replace ("\n", "
"); - str* zpHTML = &g_qWindow->zMessageLogHTML; + str* zpHTML = &g_ForgeWindow->zMessageLogHTML; switch (eType) { case LOG_Normal: @@ -108,7 +108,7 @@ break; } - g_qWindow->qMessageLog->setHtml (*zpHTML); + g_ForgeWindow->qMessageLog->setHtml (*zpHTML); } diff -r c190fe218506 -r f8917e9d07f6 zz_newPartDialog.cpp --- a/zz_newPartDialog.cpp Tue Apr 09 14:06:40 2013 +0300 +++ b/zz_newPartDialog.cpp Tue Apr 09 17:41:19 2013 +0300 @@ -87,7 +87,7 @@ // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= void NewPartDialog::StaticDialog () { - NewPartDialog dlg (g_qWindow); + NewPartDialog dlg (g_ForgeWindow); if (dlg.exec ()) { newFile (); @@ -119,6 +119,6 @@ objs.push_back (new LDBFC (eBFCType)); objs.push_back (new LDEmpty); - g_qWindow->refresh (); + g_ForgeWindow->refresh (); } } \ No newline at end of file