Begin work on external program support (Ytruder partially supported)

Mon, 06 May 2013 03:31:03 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Mon, 06 May 2013 03:31:03 +0300
changeset 165
88a03c1a52d9
parent 164
8c93d8e38494
child 166
72ec7b60da54

Begin work on external program support (Ytruder partially supported)

extprogs.cpp file | annotate | diff | comparison | revisions
extprogs.h file | annotate | diff | comparison | revisions
gui.cpp file | annotate | diff | comparison | revisions
gui.h file | annotate | diff | comparison | revisions
gui_editactions.cpp file | annotate | diff | comparison | revisions
ldforge.pro file | annotate | diff | comparison | revisions
misc.h file | annotate | diff | comparison | revisions
zz_configDialog.cpp file | annotate | diff | comparison | revisions
zz_configDialog.h file | annotate | diff | comparison | revisions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extprogs.cpp	Mon May 06 03:31:03 2013 +0300
@@ -0,0 +1,151 @@
+#include "common.h"
+#include "config.h"
+#include "misc.h"
+#include "extprogs.h"
+#include "gui.h"
+#include "file.h"
+#include <qprocess.h>
+#include <qtemporaryfile.h>
+#include <qeventloop.h>
+
+// =============================================================================
+cfg (str, prog_isecalc, "");
+cfg (str, prog_intersector, "");
+cfg (str, prog_coverer, "");
+cfg (str, prog_ytruder, "");
+cfg (str, prog_datheader, "");
+
+strconfig* g_extProgPaths[] = {
+	&prog_isecalc,
+	&prog_intersector,
+	&prog_coverer,
+	&prog_ytruder,
+	&prog_datheader,
+};
+
+const char* g_extProgNames[] = {
+	"Isecalc",
+	"Intersector",
+	"Coverer",
+	"Ytruder",
+	"DATHeader",
+};
+
+// =============================================================================
+static void noPathConfigured (const extprog prog) {
+	const char* name = g_extProgNames[prog];
+	
+	critical (fmt ("Couldn't run %s as no path has "
+		"been defined for it. Use the configuration dialog's External Programs "
+		"tab to define a path for %s.", name, name));
+}
+
+// =============================================================================
+static void processError (const extprog prog, QProcess& proc) {
+	const char* name = g_extProgNames[prog];
+	str errmsg;
+	
+	switch (proc.error ()) {
+	case QProcess::FailedToStart:
+		errmsg = fmt ("Failed to launch %s. Check that you have set the proper path "
+			"to %s and that you have the proper permissions to launch it.", name, name);
+		break;
+	
+	case QProcess::Crashed:
+		errmsg = fmt ("%s crashed.", name);
+		break;
+	
+	case QProcess::WriteError:
+	case QProcess::ReadError:
+		errmsg = fmt ("I/O error while interacting with %s.", name);
+		break;
+	
+	case QProcess::UnknownError:
+		errmsg = fmt ("Unknown error occurred while executing %s.", name);
+		break;
+	
+	case QProcess::Timedout:
+		errmsg = fmt ("%s timed out.", name);
+		break;
+	}
+	
+	critical (errmsg);
+}
+
+// =============================================================================
+static bool mkTempFile (QTemporaryFile& tmp, str& fname) {
+	if (!tmp.open ())
+		return false;
+	
+	fname = tmp.fileName ();
+	tmp.close ();
+	return true;
+}
+
+bool g_processDone = false;
+
+// =============================================================================
+void runYtruder () {
+	if (prog_ytruder.value.len () == 0) {
+		noPathConfigured (Ytruder);
+		return;
+	}
+	
+	QTemporaryFile in, out, input;
+	str inname, outname, inputname;
+	FILE* fp;
+	
+	if (!mkTempFile (in, inname) || !mkTempFile (out, outname) || !mkTempFile (input, inputname))
+		return;
+	
+	QProcess proc;
+	QStringList argv ({"-p", "0", "-y", inname, outname});
+	
+	// Write the input file
+	fp = fopen (inname, "w");
+	if (!fp)
+		return;
+	
+	for (LDObject* obj : g_win->sel ()) {
+		str line = fmt ("%s\r\n", obj->getContents ().chars ());
+		fwrite (line.chars(), 1, ~line, fp);
+	}
+	fclose (fp);
+	
+	// Init stdin
+	FILE* stdinfp = fopen (inputname, "w");
+	
+	// Begin!
+	proc.setStandardInputFile (inputname);
+	proc.setStandardOutputFile ("blarg");
+	proc.start (prog_ytruder.value, argv);
+	
+	// Write an enter - one is expected
+	char enter[2] = "\n";
+	enter[1] = '\0';
+	fwrite (enter, 1, sizeof enter, stdinfp);
+	fflush (stdinfp);
+	
+	// Wait while it runs
+	proc.waitForFinished ();
+	
+	if (proc.exitStatus () == QProcess::CrashExit) {
+		processError (Ytruder, proc);
+		return;
+	}
+	
+	// Read the output file
+	fp = fopen (outname, "r");
+	if (!fp)
+		fprintf (stderr, "couldn't read %s\n", outname.chars ());
+	
+	char line[1024];
+	while (fgets (line, sizeof line, fp)) {
+		printf ("%s", line);
+		LDObject* obj = parseLine (str (line).strip ({'\n', '\r'}));
+		g_curfile->addObject (obj);
+	}
+	fclose (fp);
+	
+	g_win->refresh ();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/extprogs.h	Mon May 06 03:31:03 2013 +0300
@@ -0,0 +1,39 @@
+#ifndef EXTPROGS_H
+#define EXTPROGS_H
+
+#include <qobject.h>
+
+class QProcess;
+class ProcessWaiter : public QObject {
+	Q_OBJECT
+	
+public:
+	ProcessWaiter (QProcess* proc, bool& readyvar) : m_proc (proc), m_readyvar (readyvar) {
+		m_readyvar = false;
+	}
+	
+	int exitFlag () { return m_exitflag; }
+	
+public slots:
+	void slot_procDone (int exitflag) {
+		m_readyvar = true;
+		m_exitflag = exitflag;
+	}
+	
+private:
+	QProcess* m_proc;
+	bool& m_readyvar;
+	int m_exitflag;
+};
+
+enum extprog {
+	IseCalc,
+	Intersector,
+	Coverer,
+	Ytruder,
+	DATHeader
+};
+
+void runYtruder ();
+
+#endif // EXTPROGS_H
\ No newline at end of file
--- a/gui.cpp	Mon May 06 00:10:56 2013 +0300
+++ b/gui.cpp	Mon May 06 03:31:03 2013 +0300
@@ -375,7 +375,7 @@
 	addToolBarAction ("roundCoords");
 	addToolBarAction ("screencap");
 	addToolBarAction ("uncolorize");
-	
+	addToolBarAction ("extrude");
 	
 	updateToolBars ();
 }
--- a/gui.h	Mon May 06 00:10:56 2013 +0300
+++ b/gui.h	Mon May 06 03:31:03 2013 +0300
@@ -27,6 +27,8 @@
 #include <QTextEdit>
 #include <qpushbutton.h>
 #include <qlistwidget.h>
+#include <qlabel.h>
+#include <qboxlayout.h>
 #include "gldraw.h"
 #include "config.h"
 
@@ -183,6 +185,37 @@
 	void slot_lastSecondCleanup ();
 };
 
+// =============================================================================
+// LabeledWidget
+//
+// Convenience class for a widget with a label beside it.
+// =============================================================================
+template<class R> class LabeledWidget : public QWidget {
+public:
+	LabeledWidget (const char* labelstr, QWidget* parent) : QWidget (parent) {
+		m_widget = new R (this);
+		m_label = new QLabel (labelstr, this);
+		
+		m_layout = new QHBoxLayout;
+		m_layout->addWidget (m_label);
+		m_layout->addWidget (m_widget);
+		setLayout (m_layout);
+	}
+	
+	R* widget () const { return m_widget; }
+	R* w () const { return m_widget; }
+	QLabel* label () const { return m_label; }
+	QLabel* l () const { return m_label; }
+	void setWidget (R* widget) { m_widget = widget; }
+	void setLabel (QLabel* label) { m_label = label; }
+	operator R* () { return m_widget; }
+	
+private:
+	R* m_widget;
+	QLabel* m_label;
+	QHBoxLayout* m_layout;
+};
+
 // -----------------------------------------------------------------------------
 // Other GUI-related stuff not directly part of ForgeWindow:
 QPixmap getIcon (const char* sIconName);
--- a/gui_editactions.cpp	Mon May 06 00:10:56 2013 +0300
+++ b/gui_editactions.cpp	Mon May 06 03:31:03 2013 +0300
@@ -25,6 +25,10 @@
 #include "zz_setContentsDialog.h"
 #include "misc.h"
 #include "bbox.h"
+#include "radiobox.h"
+#include "extprogs.h"
+#include <qspinbox.h>
+#include <qcheckbox.h>
 
 vector<LDObject*> g_Clipboard;
 
@@ -680,4 +684,43 @@
 		History::addEntry (new EditHistory (indices, oldCopies, newCopies));
 		g_win->refresh ();
 	}
+}
+
+// =============================================================================
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// =============================================================================
+MAKE_ACTION (extrude, "Extrude", "extrude", "Extrude selected lines to a given plane", KEY (F8)) {
+	QDialog* dlg = new QDialog (g_win);
+	
+	RadioBox* rb_mode = new RadioBox ("Extrusion mode", {"Project", "Mirror"}, 0, Qt::Horizontal, dlg);
+	RadioBox* rb_axis = new RadioBox ("Axis", {"X", "Y", "Z"}, 0, Qt::Horizontal, dlg);
+	LabeledWidget<QDoubleSpinBox>* dsb_depth = new LabeledWidget<QDoubleSpinBox> ("Plane depth", dlg);
+	QDialogButtonBox* bbx_buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+	QCheckBox* cb_edges = new QCheckBox ("Add edgelines to extrusion point");
+	
+	QWidget::connect (bbx_buttons, SIGNAL (accepted ()), dlg, SLOT (accept ()));
+	QWidget::connect (bbx_buttons, SIGNAL (rejected ()), dlg, SLOT (reject ()));
+	
+	dsb_depth->w ()->setMinimum (-10000.0);
+	dsb_depth->w ()->setMaximum (10000.0);
+	dsb_depth->w ()->setDecimals (3);
+	
+	QVBoxLayout* layout = new QVBoxLayout (dlg);
+	layout->addWidget (rb_mode);
+	layout->addWidget (rb_axis);
+	layout->addWidget (dsb_depth);
+	layout->addWidget (cb_edges);
+	layout->addWidget (bbx_buttons);
+	
+	dlg->setWindowIcon (getIcon ("extrude"));
+	
+	if (!dlg->exec ())
+		return;
+	
+	const double depth = dsb_depth->w ()->value ();
+	const Axis axis = (Axis) rb_axis->value ();
+	const enum modetype { Projection, Mirror } mode = (modetype) rb_mode->value ();
+	const bool addEdges = cb_edges->isChecked ();
+	
+	runYtruder ();
 }
\ No newline at end of file
--- a/ldforge.pro	Mon May 06 00:10:56 2013 +0300
+++ b/ldforge.pro	Mon May 06 03:31:03 2013 +0300
@@ -15,6 +15,7 @@
 	colors.h \
 	common.h \
 	config.h \
+	extprogs.h \
 	file.h \
 	gldraw.h \
 	gui.h \
@@ -33,14 +34,15 @@
 	zz_setContentsDialog.h
 
 SOURCES += bbox.cpp \
+	colors.cpp \
 	config.cpp \
-	colors.cpp \
+	extprogs.cpp \
+	file.cpp \
 	gldraw.cpp \
 	gui.cpp \
 	gui_actions.cpp \
 	gui_editactions.cpp \
 	history.cpp \
-	file.cpp \
 	ldtypes.cpp \
 	main.cpp \
 	misc.cpp \
--- a/misc.h	Mon May 06 00:10:56 2013 +0300
+++ b/misc.h	Mon May 06 03:31:03 2013 +0300
@@ -21,6 +21,7 @@
 
 #include "common.h"
 #include "str.h"
+#include "config.h"
 
 #define NUM_PRIMES 500
 
@@ -71,6 +72,7 @@
 	double snap (double value, const Grid::Config axis);
 };
 
+// =============================================================================
 template<class T> void dataswap (T& a, T& b) {
 	T c = a;
 	a = b;
--- a/zz_configDialog.cpp	Mon May 06 00:10:56 2013 +0300
+++ b/zz_configDialog.cpp	Mon May 06 03:31:03 2013 +0300
@@ -314,6 +314,15 @@
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
+void ConfigDialog::initExtProgTab () {
+	QWidget* tab = new QWidget;
+	
+	QGridLayout* layout = new QGridLayout;
+}
+
+// =============================================================================
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// =============================================================================
 void ConfigDialog::updateQuickColorList (quickColorMetaEntry* pSel) {
 	for (QListWidgetItem* qItem : quickColorItems)
 		delete qItem;
--- a/zz_configDialog.h	Mon May 06 00:10:56 2013 +0300
+++ b/zz_configDialog.h	Mon May 06 03:31:03 2013 +0300
@@ -34,7 +34,7 @@
 	
 public:
 	QTabWidget* tabs;
-	QWidget* mainTab, *shortcutsTab, *quickColorTab;
+	QWidget* mainTab, *shortcutsTab, *quickColorTab, *extProgTab;
 	
 	// =========================================================================
 	// Main tab widgets
@@ -80,6 +80,7 @@
 	void initShortcutsTab ();
 	void initQuickColorTab ();
 	void initGridTab ();
+	void initExtProgTab ();
 	
 	void makeSlider (QSlider*& qSlider, short int dMin, short int dMax, short int dDefault);
 	void setButtonBackground (QPushButton* qButton, str zValue);

mercurial