summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMarius Kintel <marius@kintel.net>2013-05-28 05:25:03 (GMT)
committerMarius Kintel <marius@kintel.net>2013-05-28 05:25:03 (GMT)
commit33e873d8dae644b28dd3d6cbcf04450d6675fafd (patch)
treea0d6e570b21f18763ef33099b486d735ec22f2f4 /src
parenteade7ede546f2415dfe6a8ff36a77136f883d03b (diff)
Changed compile GUI logic to properly handler automatic reload on cascading changes
Diffstat (limited to 'src')
-rw-r--r--src/AppleEvents.cc2
-rw-r--r--src/MainWindow.h20
-rw-r--r--src/lexer.l2
-rw-r--r--src/mainwin.cc237
-rw-r--r--src/parsersettings.cc14
5 files changed, 179 insertions, 96 deletions
diff --git a/src/AppleEvents.cc b/src/AppleEvents.cc
index 1fb4f99..3102792 100644
--- a/src/AppleEvents.cc
+++ b/src/AppleEvents.cc
@@ -15,7 +15,7 @@ OSErr eventHandler(const AppleEvent *, AppleEvent *, SRefCon )
if (mainwin) break;
}
if (mainwin) {
- mainwin->actionReloadCompile();
+ mainwin->actionReloadRenderCSG();
}
return noErr;
}
diff --git a/src/MainWindow.h b/src/MainWindow.h
index bd32bdd..fc64137 100644
--- a/src/MainWindow.h
+++ b/src/MainWindow.h
@@ -28,6 +28,7 @@ public:
QTimer *autoReloadTimer;
std::string autoReloadId;
+ QTimer *waitAfterReloadTimer;
ModuleContext top_ctx;
FileModule *root_module; // Result of parsing
@@ -77,8 +78,8 @@ private:
void updateTemporalVariables();
bool fileChangedOnDisk();
bool includesChanged();
- bool compileTopLevelDocument(bool reload);
- bool compile(bool reload, bool procevents);
+ void compileTopLevelDocument();
+ void compile(bool reload, bool forcedone = false);
void compileCSG(bool procevents);
bool maybeSave();
bool checkEditorModified();
@@ -103,6 +104,10 @@ private slots:
void actionReload();
void actionShowLibraryFolder();
+ void instantiateRoot();
+ void compileDone(bool didchange);
+ void compileEnded();
+
private slots:
void pasteViewportTranslation();
void pasteViewportRotation();
@@ -110,10 +115,13 @@ private slots:
void preferences();
private slots:
- void actionCompile();
+ void actionRenderCSG();
+ void csgRender();
+ void csgReloadRender();
#ifdef ENABLE_CGAL
void actionRenderCGAL();
void actionRenderCGALDone(class CGAL_Nef_polyhedron *);
+ void cgalRender();
#endif
void actionDisplayAST();
void actionDisplayCSGTree();
@@ -132,6 +140,7 @@ public:
void clearCurrentOutput();
public slots:
+ void actionReloadRenderCSG();
#ifdef ENABLE_OPENCSG
void viewModeOpenCSG();
#endif
@@ -164,13 +173,16 @@ public slots:
void helpManual();
void helpLibrary();
void quit();
- void actionReloadCompile();
void checkAutoReload();
+ void waitAfterReload();
void autoReloadSet(bool);
private:
static void report_func(const class AbstractNode*, void *vp, int mark);
+ char const * afterCompileSlot;
+ bool procevents;
+
class ProgressWidget *progresswidget;
class CGALWorker *cgalworker;
QMutex consolemutex;
diff --git a/src/lexer.l b/src/lexer.l
index 0b8048f..3dd3b6b 100644
--- a/src/lexer.l
+++ b/src/lexer.l
@@ -100,7 +100,7 @@ E [Ee][+-]?{D}+
%%
-include[ \t\r\n>]*"<" { BEGIN(cond_include); filepath = filename = "";}
+include[ \t\r\n>]*"<" { BEGIN(cond_include); filepath = filename = ""; }
<cond_include>{
[^\t\r\n>]*"/" { filepath = yytext; }
[^\t\r\n>/]+ { filename = yytext; }
diff --git a/src/mainwin.cc b/src/mainwin.cc
index ac75269..52b432c 100644
--- a/src/mainwin.cc
+++ b/src/mainwin.cc
@@ -205,10 +205,16 @@ MainWindow::MainWindow(const QString &filename)
connect(animate_timer, SIGNAL(timeout()), this, SLOT(updateTVal()));
autoReloadTimer = new QTimer(this);
- autoReloadTimer->setSingleShot(false);
+ autoReloadTimer->setSingleShot(true);
+ autoReloadTimer->setInterval(200);
connect(autoReloadTimer, SIGNAL(timeout()), this, SLOT(checkAutoReload()));
- connect(this->e_tval, SIGNAL(textChanged(QString)), this, SLOT(actionCompile()));
+ waitAfterReloadTimer = new QTimer(this);
+ waitAfterReloadTimer->setSingleShot(true);
+ waitAfterReloadTimer->setInterval(200);
+ connect(waitAfterReloadTimer, SIGNAL(timeout()), this, SLOT(waitAfterReload()));
+
+ connect(this->e_tval, SIGNAL(textChanged(QString)), this, SLOT(actionRenderCSG()));
connect(this->e_fps, SIGNAL(textChanged(QString)), this, SLOT(updatedFps()));
animate_panel->hide();
@@ -288,8 +294,8 @@ MainWindow::MainWindow(const QString &filename)
// Design menu
connect(this->designActionAutoReload, SIGNAL(toggled(bool)), this, SLOT(autoReloadSet(bool)));
- connect(this->designActionReloadAndCompile, SIGNAL(triggered()), this, SLOT(actionReloadCompile()));
- connect(this->designActionCompile, SIGNAL(triggered()), this, SLOT(actionCompile()));
+ connect(this->designActionReloadAndCompile, SIGNAL(triggered()), this, SLOT(actionReloadRenderCSG()));
+ connect(this->designActionCompile, SIGNAL(triggered()), this, SLOT(actionRenderCSG()));
#ifdef ENABLE_CGAL
connect(this->designActionCompileAndRender, SIGNAL(triggered()), this, SLOT(actionRenderCGAL()));
#else
@@ -580,7 +586,7 @@ void MainWindow::updateTVal()
double fps = this->e_fps->text().toDouble(&fps_ok);
if (fps_ok) {
if (fps <= 0) {
- actionCompile();
+ actionRenderCSG();
} else {
double s = this->e_fsteps->text().toDouble();
double t = this->e_tval->text().toDouble() + 1/s;
@@ -612,14 +618,88 @@ void MainWindow::refreshDocument()
}
/*!
- Parse and evaluate the design => this->root_node
-
- Returns true if something was compiled, false if nothing was changed
- and the root_node was left untouched.
+ compiles the design. Calls compileDone() if anything was compiled
*/
-bool MainWindow::compile(bool reload, bool procevents)
+void MainWindow::compile(bool reload, bool forcedone)
+{
+ bool shouldcompiletoplevel = false;
+ bool didcompile = false;
+
+ // Reload checks the timestamp of the toplevel file and refreshes if necessary,
+ if (reload) {
+ if (fileChangedOnDisk() && checkEditorModified()) {
+ shouldcompiletoplevel = true;
+ refreshDocument();
+ }
+ }
+ else {
+ shouldcompiletoplevel = true;
+ }
+
+ if (!shouldcompiletoplevel && includesChanged()) {
+ shouldcompiletoplevel = true;
+ }
+
+ if (shouldcompiletoplevel) {
+ compileTopLevelDocument();
+ didcompile = true;
+ }
+
+ if (this->root_module) {
+ if (this->root_module->handleDependencies()) {
+ PRINTB("Module cache size: %d modules", ModuleCache::instance()->size());
+ didcompile = true;
+ }
+ }
+
+ // If we're auto-reloading, listen for a cascade of changes by starting a timer
+ // if something changed _and_ there are any external dependencies
+ if (reload && didcompile && this->root_module) {
+ if (this->root_module->includes.size() > 0 ||
+ this->root_module->usedlibs.size() > 0) {
+ this->waitAfterReloadTimer->start();
+ return;
+ }
+ }
+ compileDone(didcompile | forcedone);
+}
+
+void MainWindow::waitAfterReload()
+{
+ if (this->root_module->handleDependencies()) {
+ this->waitAfterReloadTimer->start();
+ return;
+ }
+ else {
+ compile(true, true); // In case file itself or top-level includes changed during dependency updates
+ }
+}
+
+void MainWindow::compileDone(bool didchange)
+{
+ const char *callslot;
+ if (didchange) {
+ instantiateRoot();
+ callslot = afterCompileSlot;
+ }
+ else {
+ callslot = "compileEnded";
+ }
+
+ this->procevents = false;
+ QMetaObject::invokeMethod(this, callslot);
+}
+
+void MainWindow::compileEnded()
+{
+ clearCurrentOutput();
+ GuiLocker::unlock();
+ if (designActionAutoReload->isChecked()) autoReloadTimer->start();
+}
+
+void MainWindow::instantiateRoot()
{
- if (!compileTopLevelDocument(reload)) return false;
+ // Go on and instantiate root_node, then call the continuation slot
// Invalidate renderers before we kill the CSG tree
this->qglview->setRenderer(NULL);
@@ -652,7 +732,7 @@ bool MainWindow::compile(bool reload, bool procevents)
if (this->root_module) {
// Evaluate CSG tree
PRINT("Compiling design (CSG Tree generation)...");
- if (procevents) QApplication::processEvents();
+ if (this->procevents) QApplication::processEvents();
AbstractNode::resetIndexCounter();
this->root_inst = ModuleInstantiation("group");
@@ -677,10 +757,8 @@ bool MainWindow::compile(bool reload, bool procevents)
} else {
PRINT("ERROR: Compilation failed!");
}
- if (procevents) QApplication::processEvents();
+ if (this->procevents) QApplication::processEvents();
}
-
- return true;
}
/*!
@@ -1049,66 +1127,44 @@ bool MainWindow::includesChanged()
}
/*!
- If reload is true, does a timestamp check on the document and tries to reload it.
- Otherwise, just reparses the current document and any dependencies, updates the
- GUI accordingly and populates this->root_module.
-
Returns true if anything was compiled.
*/
-bool MainWindow::compileTopLevelDocument(bool reload)
+void MainWindow::compileTopLevelDocument()
{
- bool shouldcompiletoplevel = !reload;
-
- if (includesChanged()) shouldcompiletoplevel = true;
-
- if (reload && fileChangedOnDisk() && checkEditorModified()) {
- shouldcompiletoplevel = true;
- refreshDocument();
- }
+ console->clear();
- if (shouldcompiletoplevel) {
- console->clear();
-
- updateTemporalVariables();
-
- this->last_compiled_doc = editor->toPlainText();
- std::string fulltext =
- std::string(this->last_compiled_doc.toLocal8Bit().constData()) +
- "\n" + commandline_commands;
-
- delete this->root_module;
- this->root_module = NULL;
-
- this->root_module = parse(fulltext.c_str(),
- this->fileName.isEmpty() ?
- "" :
- QFileInfo(this->fileName).absolutePath().toLocal8Bit(),
- false);
-
- if (!animate_panel->isVisible()) {
- highlighter->unhighlightLastError();
- if (!this->root_module) {
- QTextCursor cursor = editor->textCursor();
- cursor.setPosition(parser_error_pos);
- editor->setTextCursor(cursor);
- highlighter->highlightError( parser_error_pos );
- }
+ updateTemporalVariables();
+
+ this->last_compiled_doc = editor->toPlainText();
+ std::string fulltext =
+ std::string(this->last_compiled_doc.toLocal8Bit().constData()) +
+ "\n" + commandline_commands;
+
+ delete this->root_module;
+ this->root_module = NULL;
+
+ this->root_module = parse(fulltext.c_str(),
+ this->fileName.isEmpty() ?
+ "" :
+ QFileInfo(this->fileName).absolutePath().toLocal8Bit(),
+ false);
+
+ if (!animate_panel->isVisible()) {
+ highlighter->unhighlightLastError();
+ if (!this->root_module) {
+ QTextCursor cursor = editor->textCursor();
+ cursor.setPosition(parser_error_pos);
+ editor->setTextCursor(cursor);
+ highlighter->highlightError( parser_error_pos );
}
-
- }
-
- bool changed = shouldcompiletoplevel;
- if (this->root_module) {
- changed |= this->root_module->handleDependencies();
- if (changed) PRINTB("Module cache size: %d modules", ModuleCache::instance()->size());
}
-
- return changed;
}
void MainWindow::checkAutoReload()
{
- if (!this->fileName.isEmpty()) actionReloadCompile();
+ if (!this->fileName.isEmpty()) {
+ actionReloadRenderCSG();
+ }
}
void MainWindow::autoReloadSet(bool on)
@@ -1117,7 +1173,7 @@ void MainWindow::autoReloadSet(bool on)
settings.setValue("design/autoReload",designActionAutoReload->isChecked());
if (on) {
autoReloadId = "";
- autoReloadTimer->start(200);
+ autoReloadTimer->start();
} else {
autoReloadTimer->stop();
}
@@ -1139,15 +1195,22 @@ bool MainWindow::checkEditorModified()
return true;
}
-void MainWindow::actionReloadCompile()
+void MainWindow::actionReloadRenderCSG()
{
if (GuiLocker::isLocked()) return;
- GuiLocker lock;
+ GuiLocker::lock();
+ autoReloadTimer->stop();
setCurrentOutput();
// PRINT("Parsing design (AST generation)...");
// QApplication::processEvents();
- if (!compile(true, true)) return;
+ this->afterCompileSlot = "csgReloadRender";
+ this->procevents = true;
+ compile(true);
+}
+
+void MainWindow::csgReloadRender()
+{
if (this->root_node) compileCSG(true);
// Go to non-CGAL view mode
@@ -1161,20 +1224,26 @@ void MainWindow::actionReloadCompile()
viewModeThrownTogether();
#endif
}
-
- clearCurrentOutput();
+ compileEnded();
}
-void MainWindow::actionCompile()
+void MainWindow::actionRenderCSG()
{
if (GuiLocker::isLocked()) return;
- GuiLocker lock;
+ GuiLocker::lock();
+ autoReloadTimer->stop();
setCurrentOutput();
console->clear();
PRINT("Parsing design (AST generation)...");
QApplication::processEvents();
- compile(false, !viewActionAnimate->isChecked());
+ this->afterCompileSlot = "csgRender";
+ this->procevents = !viewActionAnimate->isChecked();
+ compile(false);
+}
+
+void MainWindow::csgRender()
+{
if (this->root_node) compileCSG(!viewActionAnimate->isChecked());
// Go to non-CGAL view mode
@@ -1198,7 +1267,7 @@ void MainWindow::actionCompile()
img.save(filename, "PNG");
}
- clearCurrentOutput();
+ compileEnded();
}
#ifdef ENABLE_CGAL
@@ -1206,15 +1275,20 @@ void MainWindow::actionCompile()
void MainWindow::actionRenderCGAL()
{
if (GuiLocker::isLocked()) return;
- GuiLocker lock;
-
+ GuiLocker::lock();
+ autoReloadTimer->stop();
setCurrentOutput();
console->clear();
PRINT("Parsing design (AST generation)...");
QApplication::processEvents();
- compile(false, true);
+ this->afterCompileSlot = "cgalRender";
+ this->procevents = true;
+ compile(false);
+}
+void MainWindow::cgalRender()
+{
if (!this->root_module || !this->root_node) {
return;
}
@@ -1234,7 +1308,6 @@ void MainWindow::actionRenderCGAL()
progress_report_prep(this->root_node, report_func, this);
- GuiLocker::lock(); // Will be unlocked in actionRenderCGALDone()
this->cgalworker->start(this->tree);
}
@@ -1297,9 +1370,7 @@ void MainWindow::actionRenderCGALDone(CGAL_Nef_polyhedron *root_N)
this->statusBar()->removeWidget(this->progresswidget);
delete this->progresswidget;
this->progresswidget = NULL;
- clearCurrentOutput();
-
- GuiLocker::unlock();
+ compileEnded();
}
#endif /* ENABLE_CGAL */
@@ -1612,7 +1683,7 @@ void MainWindow::viewModeAnimate()
{
if (viewActionAnimate->isChecked()) {
animate_panel->show();
- actionCompile();
+ actionRenderCSG();
updatedFps();
} else {
animate_panel->hide();
diff --git a/src/parsersettings.cc b/src/parsersettings.cc
index ab93b78..04c20ed 100644
--- a/src/parsersettings.cc
+++ b/src/parsersettings.cc
@@ -30,24 +30,24 @@ fs::path search_libs(const fs::path &localpath)
}
// files must be 'ordinary' - they must exist and be non-directories
-// FIXME: We cannot print any output here since these function is called periodically
-// from "Automatic reload and compile"
+// FIXME: Don't print anything from this function as it's called repeatedly
+// for the automatic reload function (FileModule::include_modified())
static bool check_valid(const fs::path &p, const std::vector<std::string> *openfilenames)
{
if (p.empty()) {
-// PRINTB("WARNING: File path is blank: %s",p);
+ //PRINTB("WARNING: File path is blank: %s",p);
return false;
}
if (!p.has_parent_path()) {
-// PRINTB("WARNING: No parent path: %s",p);
+ //PRINTB("WARNING: No parent path: %s",p);
return false;
}
if (!fs::exists(p)) {
-// PRINTB("WARNING: File not found: %s",p);
+ //PRINTB("WARNING: File not found: %s",p);
return false;
}
if (fs::is_directory(p)) {
-// PRINTB("WARNING: %s invalid - points to a directory",p);
+ //PRINTB("WARNING: %s invalid - points to a directory",p);
return false;
}
std::string fullname = boosty::stringy(p);
@@ -55,7 +55,7 @@ static bool check_valid(const fs::path &p, const std::vector<std::string> *openf
if (openfilenames) {
BOOST_FOREACH(const std::string &s, *openfilenames) {
if (s == fullname) {
-// PRINTB("WARNING: circular include file %s", fullname);
+ //PRINTB("WARNING: circular include file %s", fullname);
return false;
}
}
contact: Jan Huwald // Impressum