src/gui.cpp

changeset 382
c1642530ea35
parent 379
f5f3faac60cd
child 383
10e60ae9ed58
--- a/src/gui.cpp	Mon Jul 15 14:43:29 2013 +0300
+++ b/src/gui.cpp	Mon Jul 15 19:30:16 2013 +0300
@@ -47,9 +47,7 @@
 #include "addObjectDialog.h"
 #include "messagelog.h"
 #include "config.h"
-
-actionmeta g_actionMeta[MAX_ACTIONS];
-static ushort g_metacursor = 0;
+#include "ui_ldforge.h"
 
 static bool g_bSelectionLocked = false;
 
@@ -71,255 +69,96 @@
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-ForgeWindow::ForgeWindow () {
+ForgeWindow::ForgeWindow() {
 	g_win = this;
 	m_renderer = new GLRenderer;
 	
-	m_objList = new ObjectList;
-	m_objList->setSelectionMode (QListWidget::ExtendedSelection);
-	m_objList->setAlternatingRowColors (true);
-	connect (m_objList, SIGNAL (itemSelectionChanged ()), this, SLOT (slot_selectionChanged ()));
-	connect (m_objList, SIGNAL (itemDoubleClicked (QListWidgetItem*)), this, SLOT (slot_editObject (QListWidgetItem*)));
+	ui = new Ui_LDForgeUI;
+	ui->setupUi (this);
 	
-	m_msglog = new MessageManager;
-	m_msglog->setRenderer( R() );
-	m_renderer->setMessageLog( m_msglog );
+	// Stuff the renderer into its frame
+	QVBoxLayout* rendererLayout = new QVBoxLayout (ui->rendererFrame);
+	rendererLayout->addWidget (R());
 	
-	m_splitter = new QSplitter;
-	m_splitter->addWidget (m_renderer);
-	m_splitter->addWidget (m_objList);
-	setCentralWidget (m_splitter);
-	
-	m_colorMeta = parseQuickColorMeta ();
+	connect (ui->objectList, SIGNAL (itemSelectionChanged()), this, SLOT (slot_selectionChanged()));
+	connect (ui->objectList, SIGNAL (itemDoubleClicked (QListWidgetItem*)), this, SLOT (slot_editObject (QListWidgetItem*)));
 	
-	createMenuActions ();
-	createMenus ();
-	createToolbars ();
-	
-	slot_selectionChanged ();
-	
+	// Init message log manager
+	m_msglog = new MessageManager;
+	m_msglog->setRenderer (R());
+	m_renderer->setMessageLog (m_msglog);
+	m_colorMeta = parseQuickColorMeta();
+	slot_selectionChanged();
 	setStatusBar (new QStatusBar);
 	
+	// Init primitive loader task stuff
 	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 ();
+	statusBar()->addPermanentWidget (m_primLoaderWidget);
+	m_primLoaderWidget->hide();
 	
-	setWindowIcon (getIcon ("ldforge"));
-	updateTitle ();
-	setMinimumSize (320, 200);
-	resize (800, 600);
+	// Make certain actions checkable
+	ui->actionAxes->setChecked (gl_axes);
+	ui->actionWireframe->setChecked (gl_wireframe);
+	ui->actionBFCView->setChecked (gl_colorbfc);
+	updateGridToolBar();
+	updateEditModeActions();
+	updateRecentFilesMenu();
+	updateToolBars();
+	updateTitle();
 	
-	connect (qApp, SIGNAL (aboutToQuit ()), this, SLOT (slot_lastSecondCleanup ()));
+	setMinimumSize (300, 200);
+	
+	connect (qApp, SIGNAL (aboutToQuit()), this, SLOT (slot_lastSecondCleanup()));
+	
+	// Connect all actions
+#define act(N) \
+	connect (ui->action##N, SIGNAL (triggered()), this, SLOT (slot_action()));
+#include "actions.h"
 }
 
-// =============================================================================
-void ForgeWindow::slot_lastSecondCleanup () {
-	delete m_renderer;
+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) ()) {
+	// Open the history so we can record the edits done during this action.
+	if (act != ACTION (Undo) && act != ACTION (Redo) && act != ACTION (Open))
+		currentFile()->openHistory();
+	
+	// Invoke the function
+	(*func) ();
+	
+	// Close the history now.
+	currentFile()->closeHistory();
 }
 
 // =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void ForgeWindow::createMenuActions () {
-	// Create the actions based on stored meta.
-	for (actionmeta meta : g_actionMeta) {
-		if (meta.qAct == null)
-			break;
-		
-		QAction*& act = *meta.qAct;
-		act = new QAction (getIcon (meta.sIconName), meta.sDisplayName, this);
-		act->setStatusTip (meta.sDescription);
-		act->setShortcut (*meta.conf);
-		
-		connect (act, SIGNAL (triggered ()), this, SLOT (slot_action ()));
-	}
-	
-	// Make certain actions checkable
-	findAction ("gridCoarse")->setCheckable (true);
-	findAction ("gridMedium")->setCheckable (true);
-	findAction ("gridFine")->setCheckable (true);
-	
-	findAction ("axes")->setCheckable (true);
-	findAction ("axes")->setChecked (gl_axes);
-
-	findAction ("wireframe")->setCheckable (true);
-	findAction ("wireframe")->setChecked (gl_wireframe);
-	
-	findAction ("colorbfc")->setCheckable (true);
-	findAction ("colorbfc")->setChecked (gl_colorbfc);
-	
-	updateEditModeActions ();
-	
-	// things not implemented yet
-	findAction ("help")->setEnabled (false);
+void ForgeWindow::slot_lastSecondCleanup() {
+	delete m_renderer;
+	delete ui;
 }
 
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-QMenu* g_CurrentMenu;
-
-QMenu* ForgeWindow::initMenu (const char* name) {
-	return g_CurrentMenu = menuBar ()->addMenu (tr (name));
-}
-
-void ForgeWindow::addMenuAction (const char* name) {
-	g_CurrentMenu->addAction (findAction (name));
-}
-
-
-// =============================================================================
-void ForgeWindow::createMenus () {
-	m_recentFilesMenu = new QMenu (tr ("Open &Recent"));
-	m_recentFilesMenu->setIcon (getIcon ("open-recent"));
-	updateRecentFilesMenu ();
-	
-	QMenu*& menu = g_CurrentMenu;
-	
-	// File menu
-	initMenu ("&File");
-	addMenuAction ("newFile");
-	addMenuAction ("open");
-	menu->addMenu (m_recentFilesMenu);
-	addMenuAction ("save");
-	addMenuAction ("saveAs");
-	menu->addSeparator ();
-	addMenuAction ("insertFrom");
-	addMenuAction ("exportTo");
-	menu->addSeparator ();
-	addMenuAction ("settings");
-	addMenuAction ("setLDrawPath");
-	menu->addSeparator ();
-#ifndef RELEASE
-	addMenuAction ("testpic");
-#endif
-	addMenuAction ("reloadPrimitives");
-	menu->addSeparator ();
-	addMenuAction ("exit");
-	
-	// View menu
-	initMenu ("&View");
-	addMenuAction ("resetView");
-	addMenuAction ("axes");
-	addMenuAction ("wireframe");
-	addMenuAction ("colorbfc");
-	menu->addSeparator ();
-	addMenuAction ("setOverlay");
-	addMenuAction ("clearOverlay");
-	menu->addSeparator ();
-	addMenuAction ("screencap");
-	
-	// Insert menu
-	initMenu ("&Insert");
-	addMenuAction ("insertRaw");
-	menu->addSeparator ();
-	addMenuAction ("newSubfile");
-	addMenuAction ("newLine");
-	addMenuAction ("newTriangle");
-	addMenuAction ("newQuad");
-	addMenuAction ("newCondLine");
-	addMenuAction ("newComment");
-	addMenuAction ("newBFC");
-	addMenuAction ("newVertex");
-	
-	// Edit menu
-	initMenu ("&Edit");
-	addMenuAction ("undo");
-	addMenuAction ("redo");
-	menu->addSeparator ();
-	addMenuAction ("cut");
-	addMenuAction ("copy");
-	addMenuAction ("paste");
-	addMenuAction ("del");
-	menu->addSeparator ();
-	addMenuAction ("selectAll");
-	addMenuAction ("selectByColor");
-	addMenuAction ("selectByType");
-	menu->addSeparator ();
-	addMenuAction ("modeSelect");
-	addMenuAction ("modeDraw");
-	menu->addSeparator ();
-	addMenuAction ("setDrawDepth");
-	
-	// Move menu
-	initMenu ("&Move");
-	addMenuAction ("moveUp");
-	addMenuAction ("moveDown");
-	menu->addSeparator ();
-	addMenuAction ("gridCoarse");
-	addMenuAction ("gridMedium");
-	addMenuAction ("gridFine");
-	menu->addSeparator ();
-	addMenuAction ("moveXPos");
-	addMenuAction ("moveXNeg");
-	addMenuAction ("moveYPos");
-	addMenuAction ("moveYNeg");
-	addMenuAction ("moveZPos");
-	addMenuAction ("moveZNeg");
-	menu->addSeparator ();
-	addMenuAction ("rotateXPos");
-	addMenuAction ("rotateXNeg");
-	addMenuAction ("rotateYPos");
-	addMenuAction ("rotateYNeg");
-	addMenuAction ("rotateZPos");
-	addMenuAction ("rotateZNeg");
-	addMenuAction ("rotpoint");
-	
-	initMenu ("&Tools");
-	addMenuAction ("setColor");
-	addMenuAction ("autoColor");
-	addMenuAction ("uncolorize");
-	menu->addSeparator ();
-	addMenuAction ("invert");
-	addMenuAction ("inlineContents");
-	addMenuAction ("deepInline");
-	addMenuAction ("makePrimitive");
-	menu->addSeparator ();
-	addMenuAction ("splitQuads");
-	addMenuAction ("setContents");
-	addMenuAction ("makeBorders");
-	addMenuAction ("makeCornerVerts");
-	addMenuAction ("roundCoords");
-	addMenuAction ("visibility");
-	addMenuAction ("replaceCoords");
-	addMenuAction ("flip");
-	addMenuAction ("demote");
-	
-	initMenu ("E&xternal Programs");
-	addMenuAction ("ytruder");
-	addMenuAction ("rectifier");
-	addMenuAction ("intersector");
-	addMenuAction ("isecalc");
-	addMenuAction ("coverer");
-	addMenuAction ("edger2");
-	
-	// Help menu
-	initMenu ("&Help");
-	addMenuAction ("help");
-	menu->addSeparator ();
-	addMenuAction ("about");
-	addMenuAction ("aboutQt");
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-void ForgeWindow::updateRecentFilesMenu () {
+void ForgeWindow::updateRecentFilesMenu() {
 	// First, clear any items in the recent files menu
 	for (QAction* recent : m_recentFiles)
 		delete recent;
-	m_recentFiles.clear ();
+	m_recentFiles.clear();
 	
 	vector<str> files = container_cast<QStringList, vector<str>> (io_recentfiles.value.split ("@"));
 	for (str file : c_rev<str> (files)) {
 		QAction* recent = new QAction (getIcon ("open-recent"), file, this);
 		
-		connect (recent, SIGNAL (triggered ()), this, SLOT (slot_recentFile ()));
-		m_recentFilesMenu->addAction (recent);
+		connect (recent, SIGNAL (triggered()), this, SLOT (slot_recentFile()));
+		ui->menuOpenRecent->addAction (recent);
 		m_recentFiles << recent;
 	}
 }
@@ -327,105 +166,14 @@
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-static QToolBar* g_CurrentToolBar;
-static Qt::ToolBarArea g_ToolBarArea = Qt::TopToolBarArea;
-
-void ForgeWindow::initSingleToolBar (const char* name) {
-	QToolBar* toolbar = new QToolBar (name);
-	addToolBar (g_ToolBarArea, toolbar);
-	m_toolBars << toolbar;
-	
-	g_CurrentToolBar = toolbar;
-}
-
-// =============================================================================
-void ForgeWindow::addToolBarAction (const char* name) {
-	g_CurrentToolBar->addAction (findAction (name));
-}
-
-// =============================================================================
-void ForgeWindow::createToolbars () {
-	initSingleToolBar ("File");
-	addToolBarAction ("newFile");
-	addToolBarAction ("open");
-	addToolBarAction ("save");
-	addToolBarAction ("saveAs");
-	
-	// ==========================================
-	initSingleToolBar ("Insert");
-	addToolBarAction ("newSubfile");
-	addToolBarAction ("newLine");
-	addToolBarAction ("newTriangle");
-	addToolBarAction ("newQuad");
-	addToolBarAction ("newCondLine");
-	addToolBarAction ("newComment");
-	addToolBarAction ("newBFC");
-	addToolBarAction ("newVertex");
-	
-	// ==========================================
-	initSingleToolBar ("Edit");
-	addToolBarAction ("undo");
-	addToolBarAction ("redo");
-	addToolBarAction ("cut");
-	addToolBarAction ("copy");
-	addToolBarAction ("paste");
-	addToolBarAction ("del");
-	addToolBarBreak (Qt::TopToolBarArea);
-	
-	// ==========================================
-	initSingleToolBar ("Select");
-	addToolBarAction ("selectAll");
-	addToolBarAction ("selectByColor");
-	addToolBarAction ("selectByType");
-	
-	// ==========================================
-	initSingleToolBar ("Grids");
-	addToolBarAction ("gridCoarse");
-	addToolBarAction ("gridMedium");
-	addToolBarAction ("gridFine");
-	
-	// ==========================================
-	initSingleToolBar ("View");
-	addToolBarAction ("axes");
-	addToolBarAction ("wireframe");
-	addToolBarAction ("colorbfc");
-	
-	// ==========================================
-	// Color toolbar
-	m_colorToolBar = new QToolBar ("Quick Colors");
-	addToolBar (Qt::RightToolBarArea, m_colorToolBar);
-	
-	// ==========================================
-	initSingleToolBar ("Tools");
-	addToolBarAction ("setColor");
-	addToolBarAction ("autoColor");
-	addToolBarAction ("splitQuads");
-	addToolBarAction ("setContents");
-	addToolBarAction ("makeBorders");
-	addToolBarAction ("replaceCoords");
-	addToolBarAction ("roundCoords");
-	addToolBarAction ("visibility");
-	
-	// ==========================================
-	g_ToolBarArea = Qt::LeftToolBarArea;
-	initSingleToolBar ("Modes");
-	addToolBarAction ("modeSelect");
-	addToolBarAction ("modeDraw");
-	
-	updateToolBars ();
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-vector<quickColor> parseQuickColorMeta () {
+vector<quickColor> parseQuickColorMeta() {
 	vector<quickColor> meta;
 	
 	for (str colorname : gui_colortoolbar.value.split (":")) {
 		if (colorname == "|") {
 			meta << quickColor ({null, null, true});
 		} else {
-			LDColor* col = getColor (colorname.toLong ());
+			LDColor* col = getColor (colorname.toLong());
 			assert (col != null);
 			meta << quickColor ({col, null, false});
 		}
@@ -437,73 +185,68 @@
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-void ForgeWindow::updateToolBars () {
-	const QSize iconsize (gui_toolbar_iconsize, gui_toolbar_iconsize);
-	
-	for (QToolBar* bar : m_toolBars)
-		bar->setIconSize (iconsize);
-	
+void ForgeWindow::updateToolBars() {
 	// Update the quick color toolbar.
 	for (QToolButton* btn : m_colorButtons)
 		delete btn;
 	
-	m_colorButtons.clear ();
+	m_colorButtons.clear();
 	
-	// Clear the toolbar to remove separators
-	m_colorToolBar->clear ();
+	// Clear the toolbar - we deleted the buttons but there's still separators
+	ui->colorToolbar->clear();
 	
 	for (quickColor& entry : m_colorMeta) {
 		if (entry.isSeparator)
-			m_colorToolBar->addSeparator ();
+			ui->colorToolbar->addSeparator();
 		else {
 			QToolButton* colorButton = new QToolButton;
 			colorButton->setIcon (makeColorIcon (entry.col, gui_toolbar_iconsize));
-			colorButton->setIconSize (iconsize);
+			colorButton->setIconSize (QSize (22, 22));
 			colorButton->setToolTip (entry.col->name);
 			
-			connect (colorButton, SIGNAL (clicked ()), this, SLOT (slot_quickColor ()));
-			m_colorToolBar->addWidget (colorButton);
+			connect (colorButton, SIGNAL (clicked()), this, SLOT (slot_quickColor()));
+			ui->colorToolbar->addWidget (colorButton);
 			m_colorButtons << colorButton;
 			
 			entry.btn = colorButton;
 		}
 	}
 	
-	updateGridToolBar ();
+	updateGridToolBar();
 }
 
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-void ForgeWindow::updateGridToolBar () {
+void ForgeWindow::updateGridToolBar() {
 	// Ensure that the current grid - and only the current grid - is selected.
-	findAction ("gridCoarse")->setChecked (grid == Grid::Coarse);
-	findAction ("gridMedium")->setChecked (grid == Grid::Medium);
-	findAction ("gridFine")->setChecked (grid == Grid::Fine);
+	ui->actionGridCoarse->setChecked (grid == Grid::Coarse);
+	ui->actionGridMedium->setChecked (grid == Grid::Medium);
+	ui->actionGridFine->setChecked (grid == Grid::Fine);
 }
 
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-void ForgeWindow::updateTitle () {
+void ForgeWindow::updateTitle() {
 	str title = fmt (APPNAME " %1", fullVersionString());
 	
 	// Append our current file if we have one
 	if (currentFile()) {
-		if (currentFile()->name ().length () > 0)
-			title += fmt (": %1", basename (currentFile()->name ()));
+		if (currentFile()->name().length() > 0)
+			title += fmt (": %1", basename (currentFile()->name()));
 		else
 			title += fmt (": <anonymous>");
 		
-		if (currentFile()->numObjs () > 0 &&
-			currentFile()->obj (0)->getType () == LDObject::Comment)
+		if (currentFile()->numObjs() > 0 &&
+			currentFile()->obj (0)->getType() == LDObject::Comment)
 		{
 			// Append title
 			LDCommentObject* comm = static_cast<LDCommentObject*> (currentFile()->obj (0));
 			title += fmt (": %1", comm->text);
 		}
 		
-		if (currentFile()->history ().pos () != currentFile()->savePos ())
+		if (currentFile()->history().pos() != currentFile()->savePos())
 			title += '*';
 	}
 	
@@ -513,44 +256,6 @@
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-EXTERN_ACTION( undo );
-EXTERN_ACTION( redo );
-EXTERN_ACTION( open );
-void ForgeWindow::slot_action () {
-	// Open the history so we can record the edits done during this action.
-	if( sender() != ACTION( undo ) && sender() != ACTION( redo ) && sender() != ACTION( open ))
-		currentFile()->openHistory ();
-	
-	// Get the action that triggered this slot.
-	QAction* qAct = static_cast<QAction*> (sender ());
-	
-	// Find the meta for the action.
-	actionmeta* meta = null;
-	
-	for (actionmeta& it : g_actionMeta) {
-		if (it.qAct == null)
-			break;
-		
-		if (*it.qAct == qAct) {
-			meta = &it;
-			break;
-		}
-	}
-	
-	if (!meta) {
-		log ("Warning: unknown signal sender %p!\n", qAct);
-		return;
-	}
-	
-	// We have the meta, now call the handler.
-	(*meta->handler) ();
-	
-	currentFile()->closeHistory ();
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
 int ForgeWindow::deleteSelection()
 {
 	if( m_sel.size() == 0 )
@@ -560,9 +265,8 @@
 	int num = 0;
 	
 	// Delete the objects that were being selected
-	for( LDObject * obj : selCopy )
-	{
-		currentFile()->forgetObject( obj );
+	for (LDObject* obj : selCopy) {
+		currentFile()->forgetObject (obj);
 		++num;
 		delete obj;
 	}
@@ -574,7 +278,7 @@
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-void ForgeWindow::buildObjList () {
+void ForgeWindow::buildObjList() {
 	if (!currentFile())
 		return;
 	
@@ -583,15 +287,15 @@
 	// while this is done.
 	g_bSelectionLocked = true;
 	
-	for (int i = 0; i < m_objList->count (); ++i)
-		delete m_objList->item (i);
+	for (int i = 0; i < ui->objectList->count(); ++i)
+		delete ui->objectList->item (i);
 	
-	m_objList->clear ();
+	ui->objectList->clear();
 	
-	for (LDObject* obj : currentFile()->objs ()) {
+	for (LDObject* obj : currentFile()->objs()) {
 		str descr;
 		
-		switch (obj->getType ()) {
+		switch (obj->getType()) {
 		case LDObject::Comment:
 			descr = static_cast<LDCommentObject*> (obj)->text;
 			
@@ -607,7 +311,7 @@
 		case LDObject::Triangle:
 		case LDObject::Quad:
 		case LDObject::CondLine:
-			for (short i = 0; i < obj->vertices (); ++i) {
+			for (short i = 0; i < obj->vertices(); ++i) {
 				if (i != 0)
 					descr += ", ";
 				
@@ -627,11 +331,11 @@
 			{
 				LDSubfileObject* ref = static_cast<LDSubfileObject*> (obj);
 				
-				descr = fmt ("%1 %2, (", ref->fileInfo ()->name (),
-					ref->position ().stringRep (true));
+				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]),
+					descr += fmt ("%1%2", ftoa (ref->transform()[i]),
 						(i != 8) ? " " : "");
 				
 				descr += ')';
@@ -656,7 +360,7 @@
 		}
 		
 		// Put it into brackets if it's hidden
-		if (obj->hidden ()) {
+		if (obj->hidden()) {
 			descr = fmt ("[[ %1 ]]", descr);
 		}
 		
@@ -667,64 +371,56 @@
 		if (obj->getType() == LDObject::Error) {
 			item->setBackground (QColor ("#AA0000"));
 			item->setForeground (QColor ("#FFAA00"));
-		} elif (lv_colorize && obj->isColored () &&
-			obj->color () != maincolor && obj->color () != edgecolor)
+		} 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 ());
+			LDColor* col = getColor (obj->color());
 			if (col)
 				item->setForeground (col->faceColor);
 		}
 		
 		obj->qObjListEntry = item;
-		m_objList->insertItem (m_objList->count (), item);
+		ui->objectList->insertItem (ui->objectList->count(), item);
 	}
 	
 	g_bSelectionLocked = false;
-	updateSelection ();
-	scrollToSelection ();
+	updateSelection();
+	scrollToSelection();
 }
 
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-void ForgeWindow::scrollToSelection () {
+void ForgeWindow::scrollToSelection() {
 	if (m_sel.size() == 0)
 		return;
 	
-	LDObject* obj = m_sel[m_sel.size () - 1];
-	m_objList->scrollToItem (obj->qObjListEntry);
+	LDObject* obj = m_sel[m_sel.size() - 1];
+	ui->objectList->scrollToItem (obj->qObjListEntry);
 }
 
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-void ForgeWindow::slot_selectionChanged () {
+void ForgeWindow::slot_selectionChanged() {
 	if (g_bSelectionLocked == true || currentFile() == null)
 		return;
 	
-	/*
-	// If the selection isn't 1 exact, disable setting contents
-	findAction ("setContents")->setEnabled (qObjList->selectedItems().size() == 1);
-	
-	// If we have no selection, disable splitting quads
-	findAction ("splitQuads")->setEnabled (qObjList->selectedItems().size() > 0);
-	*/
-	
 	// 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 ())
+	if (m_renderer->picking())
 		return;
 	
 	vector<LDObject*> priorSelection = m_sel;
 	
 	// Get the objects from the object list selection
-	m_sel.clear ();	
-	const QList<QListWidgetItem*> items = m_objList->selectedItems ();
+	m_sel.clear();
+	const QList<QListWidgetItem*> items = ui->objectList->selectedItems();
 	
-	for (LDObject* obj : currentFile()->objs ())
+	for (LDObject* obj : currentFile()->objs())
 	for (QListWidgetItem* item : items) {
 		if (item == obj->qObjListEntry) {
 			m_sel << obj;
@@ -743,21 +439,21 @@
 		m_renderer->compileObject (obj);
 	}
 	
-	m_renderer->update ();
+	m_renderer->update();
 }
 
 // =============================================================================
-void ForgeWindow::slot_recentFile () {
-	QAction* qAct = static_cast<QAction*> (sender ());
-	openMainFile (qAct->text ());
+void ForgeWindow::slot_recentFile() {
+	QAction* qAct = static_cast<QAction*> (sender());
+	openMainFile (qAct->text());
 }
 
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-void ForgeWindow::slot_quickColor () {
-	currentFile()->openHistory ();
-	QToolButton* button = static_cast<QToolButton*> (sender ());
+void ForgeWindow::slot_quickColor() {
+	currentFile()->openHistory();
+	QToolButton* button = static_cast<QToolButton*> (sender());
 	LDColor* col = null;
 	
 	for (quickColor entry : m_colorMeta) {
@@ -773,52 +469,52 @@
 	short newColor = col->index;
 	
 	for (LDObject* obj : m_sel) {
-		if (obj->isColored () == false)
+		if (obj->isColored() == false)
 			continue; // uncolored object
 		
 		obj->setColor (newColor);
 	}
 	
-	fullRefresh ();
-	currentFile()->closeHistory ();
+	fullRefresh();
+	currentFile()->closeHistory();
 }
 
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-ulong ForgeWindow::getInsertionPoint () {
-	if (m_sel.size () > 0) {
+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 (currentFile())) + 1;
 	}
 	
 	// Otherwise place the object at the end.
-	return currentFile()->numObjs ();
+	return currentFile()->numObjs();
 }
 
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-void ForgeWindow::fullRefresh () {
-	buildObjList ();
-	m_renderer->hardRefresh ();
+void ForgeWindow::fullRefresh() {
+	buildObjList();
+	m_renderer->hardRefresh();
 }
 
-void ForgeWindow::refresh () {
-	buildObjList ();
-	m_renderer->update ();
+void ForgeWindow::refresh() {
+	buildObjList();
+	m_renderer->update();
 }
 
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-void ForgeWindow::updateSelection () {
+void ForgeWindow::updateSelection() {
 	g_bSelectionLocked = true;
 	
-	for (LDObject* obj : currentFile()->objs ())
+	for (LDObject* obj : currentFile()->objs())
 		obj->setSelected (false);
 	
-	m_objList->clearSelection ();
+	ui->objectList->clearSelection();
 	for (LDObject* obj : m_sel) {
 		if( obj->qObjListEntry == null )
 			continue;
@@ -828,14 +524,14 @@
 	}
 	
 	g_bSelectionLocked = false;
-	slot_selectionChanged ();
+	slot_selectionChanged();
 }
 
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
 bool ForgeWindow::isSelected (LDObject* obj) {
-	LDObject* needle = obj->topLevelParent ();
+	LDObject* needle = obj->topLevelParent();
 	
 	for (LDObject* hay : m_sel)
 		if (hay == needle)
@@ -844,18 +540,18 @@
 	return false;
 }
 
-short ForgeWindow::getSelectedColor () {
+short ForgeWindow::getSelectedColor() {
 	short result = -1;
 	
 	for (LDObject* obj : m_sel) {
-		if (obj->isColored () == false)
+		if (obj->isColored() == false)
 			continue; // doesn't use color
 		
-		if (result != -1 && obj->color () != result)
+		if (result != -1 && obj->color() != result)
 			return -1; // No consensus in object color
 		
 		if (result == -1)
-			result = obj->color ();
+			result = obj->color();
 	}
 	
 	return result;
@@ -864,15 +560,15 @@
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-LDObject::Type ForgeWindow::uniformSelectedType () {
+LDObject::Type ForgeWindow::uniformSelectedType() {
 	LDObject::Type result = LDObject::Unidentified;
 	
 	for (LDObject* obj : m_sel) {
-		if (result != LDObject::Unidentified && obj->color () != result)
+		if (result != LDObject::Unidentified && obj->color() != result)
 			return LDObject::Unidentified;
 		
 		if (result == LDObject::Unidentified)
-			result = obj->getType ();
+			result = obj->getType();
 	}
 	
 	return result;
@@ -883,52 +579,51 @@
 // =============================================================================
 void ForgeWindow::closeEvent (QCloseEvent* ev) {
 	// Check whether it's safe to close all files.
-	if (!safeToCloseAll ()) {
-		ev->ignore ();
+	if (!safeToCloseAll()) {
+		ev->ignore();
 		return;
 	}
 	
 	// Save the configuration before leaving so that, for instance, grid choice
 	// is preserved across instances.
-	config::save ();
+	config::save();
 	
-	ev->accept ();
+	ev->accept();
 }
 
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
 void ForgeWindow::spawnContextMenu (const QPoint pos) {
-	const bool single = (g_win->sel ().size () == 1);
-	LDObject* singleObj = (single) ? g_win->sel ()[0] : null;
+	const bool single = (g_win->sel().size() == 1);
+	LDObject* singleObj = (single) ? g_win->sel()[0] : null;
 	
 	QMenu* contextMenu = new QMenu;
 	
-	if (single && singleObj->getType () != LDObject::Empty) {
-		contextMenu->addAction (findAction ("editObject"));
-		contextMenu->addSeparator ();
+	if (single && singleObj->getType() != LDObject::Empty) {
+		contextMenu->addAction (ACTION (Edit));
+		contextMenu->addSeparator();
 	}
 	
-	contextMenu->addAction (findAction ("cut"));
-	contextMenu->addAction (findAction ("copy"));
-	contextMenu->addAction (findAction ("paste"));
-	contextMenu->addAction (findAction ("del"));
-	contextMenu->addSeparator ();
-	contextMenu->addAction (findAction ("setColor"));
+	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 (findAction ("setContents"));
-	
-	contextMenu->addAction (findAction ("makeBorders"));
-	contextMenu->addAction (findAction ("setOverlay"));
-	contextMenu->addAction (findAction ("clearOverlay"));
+		contextMenu->addAction (ACTION (EditRaw));
 	
-	for (const char* mode : g_modeActionNames)
-		contextMenu->addAction (findAction (mode));
+	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 (findAction ("setDrawDepth"));
+	if (R()->camera() != GL::Free) {
+		contextMenu->addSeparator();
+		contextMenu->addAction (ACTION (SetDrawDepth));
 	}
 	
 	contextMenu->exec (pos);
@@ -945,8 +640,8 @@
 // =============================================================================
 void ForgeWindow::deleteByColor (const short colnum) {
 	vector<LDObject*> objs;
-	for (LDObject* obj : currentFile()->objs ()) {
-		if (!obj->isColored () || obj->color () != colnum)
+	for (LDObject* obj : currentFile()->objs()) {
+		if (!obj->isColored() || obj->color() != colnum)
 			continue;
 		
 		objs << obj;
@@ -956,20 +651,10 @@
 }
 
 // =============================================================================
-void ForgeWindow::updateEditModeActions () {
-	const EditMode mode = R ()->editMode ();
-	const size_t numModeActions = (sizeof g_modeActionNames / sizeof *g_modeActionNames);
-	assert ((size_t) mode < numModeActions);
-	
-	for (size_t i = 0; i < numModeActions; ++i) {
-		QAction* act = findAction (g_modeActionNames[i]);
-		
-		act->setCheckable (true);
-		act->setChecked (i == (size_t) mode);
-		
-		if (i != Select)
-			act->setEnabled (R ()->camera () != GL::Free);
-	}
+void ForgeWindow::updateEditModeActions() {
+	const EditMode mode = R()->editMode();
+	ACTION (ModeSelect)->setChecked (mode == Select);
+	ACTION (ModeDraw)->setChecked (mode == Draw);
 }
 
 void ForgeWindow::slot_editObject (QListWidgetItem* listitem) {
@@ -981,11 +666,11 @@
 		}
 	}
 	
-	AddObjectDialog::staticDialog (obj->getType (), obj);
+	AddObjectDialog::staticDialog (obj->getType(), obj);
 }
 
 void ForgeWindow::primitiveLoaderStart (ulong max) {
-	m_primLoaderWidget->show ();
+	m_primLoaderWidget->show();
 	m_primLoaderBar->setRange (0, max);
 	m_primLoaderBar->setValue (0);
 	m_primLoaderBar->setFormat ("%p%");
@@ -995,26 +680,26 @@
 	m_primLoaderBar->setValue (prog);
 }
 
-void ForgeWindow::primitiveLoaderEnd () {
+void ForgeWindow::primitiveLoaderEnd() {
 	QTimer* hidetimer = new QTimer;
-	connect (hidetimer, SIGNAL (timeout ()), m_primLoaderWidget, SLOT (hide ()));
+	connect (hidetimer, SIGNAL (timeout()), m_primLoaderWidget, SLOT (hide()));
 	hidetimer->setSingleShot (true);
 	hidetimer->start (1500);
 	m_primLoaderBar->setFormat( tr( "Done" ));
-	log( tr( "Primitives scanned: %1 primitives listed" ), m_primLoaderBar->value() );
+	log (tr ("Primitives scanned: %1 primitives listed"), m_primLoaderBar->value());
 }
 
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
 void ForgeWindow::save (LDOpenFile* f, bool saveAs) {
-	str path = f->name ();
+	str path = f->name();
 	
-	if (path.length () == 0 || saveAs) {
+	if (path.length() == 0 || saveAs) {
 		path = QFileDialog::getSaveFileName (g_win, tr ("Save As"),
-			currentFile()->name (), tr ("LDraw files (*.dat *.ldr)"));
+			currentFile()->name(), tr ("LDraw files (*.dat *.ldr)"));
 		
-		if (path.length () == 0) {
+		if (path.length() == 0) {
 			// User didn't give a file name. This happens if the user cancelled
 			// saving in the save file dialog. Abort.
 			return;
@@ -1025,20 +710,17 @@
 		f->setName (path);
 		
 		if (f == currentFile())
-			g_win->updateTitle ();
+			g_win->updateTitle();
 		
 		log ("Saved to %1.", path);
 		
 		// Add it to recent files
 		addRecentFile (path);
 	} else {
-		setlocale (LC_ALL, "C");
-		
 		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);
+		QMessageBox dlg (QMessageBox::Critical, tr ("Save Failure"), message, QMessageBox::Close, g_win);
 		
 		// Add a save-as button
 		QPushButton* saveAsBtn = new QPushButton (tr ("Save As"));
@@ -1047,19 +729,18 @@
 		dlg.setDefaultButton (QMessageBox::Close);
 		dlg.exec();
 		
-		if (dlg.clickedButton () == saveAsBtn)
+		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 ());
+	g_win->spawnContextMenu (ev->globalPos());
 }
 
 // =============================================================================
@@ -1071,7 +752,7 @@
 
 // =============================================================================
 bool confirm (str msg) {
-	return confirm ("Confirm", msg);
+	return confirm (ForgeWindow::tr ("Confirm"), msg);
 }
 
 bool confirm (str title, str msg) {
@@ -1081,26 +762,11 @@
 
 // =============================================================================
 void critical (str msg) {
-	QMessageBox::critical (g_win, QObject::tr( "Error" ), msg,
+	QMessageBox::critical (g_win, ForgeWindow::tr("Error"), msg,
 		(QMessageBox::Close), QMessageBox::Close);
 }
 
 // =============================================================================
-QAction* findAction (str name) {
-	for (actionmeta& meta : g_actionMeta) {
-		if (meta.qAct == null)
-			break;
-		
-		if (name == meta.name)
-			return *meta.qAct;
-	}
-	
-	fatal (fmt ("Couldn't find action named `%2'!", name));
-	abort ();
-	return null;
-}
-
-// =============================================================================
 QIcon makeColorIcon (LDColor* colinfo, const ushort size) {
 	// Create an image object and link a painter to it.
 	QImage img (size, size, QImage::Format_ARGB32);
@@ -1110,11 +776,11 @@
 	if (colinfo->index == maincolor) {
 		// Use the user preferences for main color here
 		col = gl_maincolor.value;
-		col.setAlpha (gl_maincolor_alpha * 255.0f);
+		col.setAlphaF (gl_maincolor_alpha);
 	}
 	
 	// Paint the icon
-	paint.fillRect (QRect (0, 0, size, size), Qt::black);
+	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));
 	paint.fillRect (QRect (1, 1, size - 2, size - 2), col);
 	return QIcon (QPixmap::fromImage (img));
@@ -1124,17 +790,17 @@
 void makeColorSelector (QComboBox* box) {
 	std::map<short, ulong> counts;
 	
-	for (LDObject* obj : currentFile()->objs ()) {
-		if (!obj->isColored ())
+	for (LDObject* obj : currentFile()->objs()) {
+		if (!obj->isColored())
 			continue;
 		
-		if (counts.find (obj->color ()) == counts.end ())
-			counts[obj->color ()] = 1;
+		if (counts.find (obj->color()) == counts.end())
+			counts[obj->color()] = 1;
 		else
-			counts[obj->color ()]++;
+			counts[obj->color()]++;
 	}
 	
-	box->clear ();
+	box->clear();
 	ulong row = 0;
 	for (const auto& pair : counts) {
 		LDColor* col = getColor (pair.first);
@@ -1152,12 +818,12 @@
 // =============================================================================
 QDialogButtonBox* makeButtonBox (QDialog& dlg) {
 	QDialogButtonBox* bbx_buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
-	QWidget::connect (bbx_buttons, SIGNAL (accepted ()), &dlg, SLOT (accept ()));
-	QWidget::connect (bbx_buttons, SIGNAL (rejected ()), &dlg, SLOT (reject ()));
+	QWidget::connect (bbx_buttons, SIGNAL (accepted()), &dlg, SLOT (accept()));
+	QWidget::connect (bbx_buttons, SIGNAL (rejected()), &dlg, SLOT (reject()));
 	return bbx_buttons;
 }
 
-CheckBoxGroup* makeAxesBox () {
+CheckBoxGroup* makeAxesBox() {
 	CheckBoxGroup* cbg_axes = new CheckBoxGroup ("Axes", Qt::Horizontal);
 	cbg_axes->addCheckBox ("X", X);
 	cbg_axes->addCheckBox ("Y", Y);
@@ -1166,23 +832,21 @@
 }
 
 void ForgeWindow::setStatusBarText (str text) {
-	statusBar ()->showMessage (text);
+	statusBar()->showMessage (text);
 }
 
-void ForgeWindow::addActionMeta (actionmeta& meta) {
-	if (g_metacursor == 0)
-		memset (g_actionMeta, 0, sizeof g_actionMeta);
-	
-	assert (g_metacursor < MAX_ACTIONS);
-	g_actionMeta[g_metacursor++] = meta;
-}
-
-void ForgeWindow::clearSelection()
-{
+void ForgeWindow::clearSelection() {
 	m_sel.clear();
 }
 
+Ui_LDForgeUI* ForgeWindow::interface() const {
+	return ui;
+}
+
+#define act(N) QAction* ForgeWindow::action##N() { return ui->action##N; }
+#include "actions.h"
+
 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.
-	return QImage (data, w, h, QImage::Format_ARGB32).rgbSwapped ().mirrored ();
+	return QImage (data, w, h, QImage::Format_ARGB32).rgbSwapped().mirrored();
 }
\ No newline at end of file

mercurial