Sat, 20 Apr 2013 04:18:22 +0300
Added winding reversal, though undoing it isn't quite ready yet.
gui.cpp | file | annotate | diff | comparison | revisions | |
gui_editactions.cpp | file | annotate | diff | comparison | revisions | |
history.cpp | file | annotate | diff | comparison | revisions | |
history.h | file | annotate | diff | comparison | revisions |
--- a/gui.cpp Fri Apr 19 15:21:46 2013 +0300 +++ b/gui.cpp Sat Apr 20 04:18:22 2013 +0300 @@ -69,6 +69,7 @@ EXTERN_ACTION (moveXPos) EXTERN_ACTION (moveYPos) EXTERN_ACTION (moveZPos) +EXTERN_ACTION (invert) #ifndef RELEASE EXTERN_ACTION (addTestQuad) @@ -118,6 +119,8 @@ createMenus (); createToolbars (); + setStatusBar (new QStatusBar); + slot_selectionChanged (); setWindowIcon (QIcon ("icons/ldforge.png")); @@ -198,6 +201,7 @@ qEditMenu->addAction (ACTION_NAME (selectByType)); // Select by Type qEditMenu->addSeparator (); // ----- qEditMenu->addAction (ACTION_NAME (setColor)); // Set Color + qEditMenu->addAction (ACTION_NAME (invert)); // Invert qEditMenu->addAction (ACTION_NAME (inlineContents)); // Inline qEditMenu->addAction (ACTION_NAME (deepInline)); // Deep Inline qEditMenu->addAction (ACTION_NAME (splitQuads)); // Split Quads @@ -323,6 +327,7 @@ g_ToolBarArea = Qt::LeftToolBarArea; initSingleToolBar ("Objects"); ADD_TOOLBAR_ITEM (setColor) + ADD_TOOLBAR_ITEM (invert) ADD_TOOLBAR_ITEM (inlineContents) ADD_TOOLBAR_ITEM (deepInline) ADD_TOOLBAR_ITEM (splitQuads)
--- a/gui_editactions.cpp Fri Apr 19 15:21:46 2013 +0300 +++ b/gui_editactions.cpp Sat Apr 20 04:18:22 2013 +0300 @@ -435,4 +435,129 @@ ACTION (moveZPos, "Move +Z", "move-z-pos", "Move selected objects positive on the Z axis.", KEY (Up)) { doMoveObjects ({0, 0, 1}); +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// invert - reverse winding +// +// NOTE: History management gets a little tricky here. For lines, cond-lines, +// triangles and quads, we edit the object, thus we record an EditHistory. For +// subfiles and radials we create or delete invertnext objects. Since we have +// multiple actions of different types, we store a history entry for each of +// them and wrap them into a ComboHistory, which allows storage of multiple +// simultaneous edits with different type. This is what we ultimately store into +// History. +// ============================================================================= +ACTION (invert, "Invert", "invert", "Reverse the winding of given objects.", CTRL_SHIFT (W)) { + std::vector<LDObject*> paSelection = g_ForgeWindow->selection (); + std::vector<HistoryEntry*> paHistory; + + for (LDObject* obj : paSelection) { + // For the objects we end up editing, we store information into these + // variables and we store them into an EditHistory after the switch + // block. Subfile and radial management is stored into the history + // list immediately. + ulong ulHistoryIndex = obj->getIndex (g_CurrentFile); + LDObject* pOldCopy, *pNewCopy; + bool bEdited = false; + + switch (obj->getType ()) { + case OBJ_Line: + case OBJ_CondLine: + { + // For lines, we swap the vertices. I don't think that a + // cond-line's control points need to be swapped, do they? + LDLine* pLine = static_cast<LDLine*> (obj); + vertex vTemp = pLine->vaCoords[0]; + + pOldCopy = pLine->clone (); + pLine->vaCoords[0] = pLine->vaCoords[1]; + pLine->vaCoords[1] = vTemp; + pNewCopy = pLine->clone (); + bEdited = true; + } + break; + + case OBJ_Triangle: + { + // Triangle goes 0 -> 1 -> 2, reversed: 0 -> 2 -> 1. + // Thus, we swap 1 and 2. + LDTriangle* pTri = static_cast<LDTriangle*> (obj); + vertex vTemp = pTri->vaCoords[1]; + + pOldCopy = pTri->clone (); + pTri->vaCoords[1] = pTri->vaCoords[2]; + pTri->vaCoords[2] = vTemp; + pNewCopy = pTri->clone (); + bEdited = true; + } + break; + + case OBJ_Quad: + { + // Quad: 0 -> 1 -> 2 -> 3 + // rev: 0 -> 3 -> 2 -> 1 + // Thus, we swap 1 and 3. + LDQuad* pQuad = static_cast<LDQuad*> (obj); + vertex vTemp = pQuad->vaCoords[1]; + + pOldCopy = pQuad->clone (); + pQuad->vaCoords[1] = pQuad->vaCoords[3]; + pQuad->vaCoords[3] = vTemp; + pNewCopy = pQuad->clone (); + bEdited = true; + } + break; + + case OBJ_Subfile: + case OBJ_Radial: + { + // Subfiles and radials 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... + + bool inverted = false; + ulong idx = obj->getIndex (g_CurrentFile); + + if (idx > 0) { + LDObject* prev = g_CurrentFile->object (idx - 1); + LDBFC* bfc = dynamic_cast<LDBFC*> (prev); + + if (bfc && bfc->eStatement == LDBFC::InvertNext) { + // Object is prefixed with an invertnext, thus remove it. + paHistory.push_back (new DelHistory ({idx - 1}, {bfc->clone ()})); + + inverted = true; + g_CurrentFile->forgetObject (bfc); + delete bfc; + } + } + + if (!inverted) { + // Not inverted, thus prefix it with a new invertnext. + LDBFC* bfc = new LDBFC (LDBFC::InvertNext); + g_CurrentFile->objects.insert (g_CurrentFile->objects.begin () + idx, bfc); + + paHistory.push_back (new AddHistory ({idx}, {bfc->clone ()})); + } + } + break; + + default: + break; + } + + // If we edited this object, store the EditHistory based on collected + // information now. + if (bEdited == true) + paHistory.push_back (new EditHistory ({ulHistoryIndex}, {pOldCopy}, {pNewCopy})); + } + + if (paHistory.size () > 0) { + History::addEntry (new ComboHistory (paHistory)); + g_ForgeWindow->refresh (); + } } \ No newline at end of file
--- a/history.cpp Fri Apr 19 15:21:46 2013 +0300 +++ b/history.cpp Sat Apr 20 04:18:22 2013 +0300 @@ -144,18 +144,16 @@ // ============================================================================= void EditHistory::undo () { for (ulong idx : ulaIndices) { - LDObject* obj = g_CurrentFile->objects[idx]; - obj->replace (paOldObjs[idx]->clone ()); + printf ("undo %lu\n", idx); + g_CurrentFile->object (idx)->replace (paOldObjs[idx]->clone ()); } g_ForgeWindow->refresh (); } void EditHistory::redo () { - for (ulong idx : ulaIndices) { - LDObject* obj = g_CurrentFile->objects[idx]; - obj->replace (paNewObjs[idx]->clone ()); - } + for (ulong idx : ulaIndices) + g_CurrentFile->object (idx)->replace (paNewObjs[idx]->clone ()); g_ForgeWindow->refresh (); } @@ -324,4 +322,24 @@ for (ulong i : ulaIndices) g_CurrentFile->object (i)->move (vVector); g_ForgeWindow->refresh (); +} + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= +ComboHistory::~ComboHistory () { + for (HistoryEntry* pEntry : paEntries) + delete pEntry; +} + +void ComboHistory::undo () { + for (long i = paEntries.size() - 1; i >= 0; --i) { + HistoryEntry* pEntry = paEntries[i]; + pEntry->undo (); + } +} + +void ComboHistory::redo () { + for (HistoryEntry* pEntry : paEntries) + pEntry->redo (); } \ No newline at end of file
--- a/history.h Fri Apr 19 15:21:46 2013 +0300 +++ b/history.h Sat Apr 20 04:18:22 2013 +0300 @@ -38,6 +38,7 @@ HISTORY_QuadSplit, HISTORY_Inline, HISTORY_Move, + HISTORY_Combo, }; // ============================================================================= @@ -184,6 +185,18 @@ // ============================================================================= // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // ============================================================================= +class ComboHistory : public HistoryEntry { +public: + IMPLEMENT_HISTORY_TYPE (Combo) + + const std::vector<HistoryEntry*> paEntries; + + ComboHistory (const std::vector<HistoryEntry*> paEntries) : paEntries (paEntries) {} +}; + +// ============================================================================= +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +// ============================================================================= namespace History { extern std::vector<HistoryEntry*> entries;