diff --git a/src/MainWindow.h b/src/MainWindow.h index 029da467..192a9b5a 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -51,7 +51,7 @@ public: static const int maxRecentFiles = 10; QAction *actionRecentFile[maxRecentFiles]; - MainWindow(const char *filename = 0); + MainWindow(const QString &filename); ~MainWindow(); protected: diff --git a/src/context.cc b/src/context.cc index 8c843745..a9ccc98e 100644 --- a/src/context.cc +++ b/src/context.cc @@ -28,6 +28,8 @@ #include "function.h" #include "module.h" #include "printutils.h" +#include +#include Context::Context(const Context *parent) { @@ -35,6 +37,7 @@ Context::Context(const Context *parent) functions_p = NULL; modules_p = NULL; inst_p = NULL; + if (parent) document_path = parent->document_path; ctx_stack.append(this); } @@ -109,3 +112,8 @@ AbstractNode *Context::evaluate_module(const ModuleInstantiation *inst) const return NULL; } +QString Context::get_absolute_path(const QString &filename) const +{ + return QFileInfo(QDir(this->document_path), filename).absoluteFilePath(); +} + diff --git a/src/context.h b/src/context.h index e78c8833..fa679920 100644 --- a/src/context.h +++ b/src/context.h @@ -14,6 +14,7 @@ public: const QHash *functions_p; const QHash *modules_p; const class ModuleInstantiation *inst_p; + QString document_path; static QVector ctx_stack; @@ -25,6 +26,8 @@ public: void set_variable(QString name, Value value); Value lookup_variable(QString name, bool silent = false) const; + QString get_absolute_path(const QString &filename) const; + Value evaluate_function(QString name, const QVector &argnames, const QVector &argvalues) const; class AbstractNode *evaluate_module(const ModuleInstantiation *inst) const; }; diff --git a/src/dxfdim.cc b/src/dxfdim.cc index 4b0cb595..02a12742 100644 --- a/src/dxfdim.cc +++ b/src/dxfdim.cc @@ -29,6 +29,7 @@ #include "dxfdata.h" #include "builtin.h" #include "printutils.h" +#include "context.h" #include #include @@ -39,7 +40,7 @@ QHash dxf_dim_cache; QHash dxf_cross_cache; -Value builtin_dxf_dim(const QVector &argnames, const QVector &args) +Value builtin_dxf_dim(const Context *ctx, const QVector &argnames, const QVector &args) { QString filename; QString layername; @@ -50,7 +51,7 @@ Value builtin_dxf_dim(const QVector &argnames, const QVector &ar for (int i = 0; i < argnames.count() && i < args.count(); i++) { if (argnames[i] == "file") - filename = args[i].text; + filename = ctx->get_absolute_path(args[i].text); if (argnames[i] == "layer") layername = args[i].text; if (argnames[i] == "origin") @@ -124,7 +125,7 @@ Value builtin_dxf_dim(const QVector &argnames, const QVector &ar return Value(); } -Value builtin_dxf_cross(const QVector &argnames, const QVector &args) +Value builtin_dxf_cross(const Context *ctx, const QVector &argnames, const QVector &args) { QString filename; QString layername; @@ -134,7 +135,7 @@ Value builtin_dxf_cross(const QVector &argnames, const QVector & for (int i = 0; i < argnames.count() && i < args.count(); i++) { if (argnames[i] == "file") - filename = args[i].text; + filename = ctx->get_absolute_path(args[i].text); if (argnames[i] == "layer") layername = args[i].text; if (argnames[i] == "origin") diff --git a/src/dxflinextrude.cc b/src/dxflinextrude.cc index 39a39716..b1bb6f1d 100644 --- a/src/dxflinextrude.cc +++ b/src/dxflinextrude.cc @@ -91,7 +91,7 @@ AbstractNode *DxfLinearExtrudeModule::evaluate(const Context *ctx, const ModuleI Value twist = c.lookup_variable("twist", true); Value slices = c.lookup_variable("slices", true); - node->filename = file.text; + node->filename = c.get_absolute_path(file.text); node->layername = layer.text; node->height = height.num; node->convexity = (int)convexity.num; diff --git a/src/dxfrotextrude.cc b/src/dxfrotextrude.cc index 170a7e33..58e6304f 100644 --- a/src/dxfrotextrude.cc +++ b/src/dxfrotextrude.cc @@ -84,7 +84,7 @@ AbstractNode *DxfRotateExtrudeModule::evaluate(const Context *ctx, const ModuleI Value origin = c.lookup_variable("origin", true); Value scale = c.lookup_variable("scale", true); - node->filename = file.text; + node->filename = c.get_absolute_path(file.text); node->layername = layer.text; node->convexity = (int)convexity.num; origin.getv2(node->origin_x, node->origin_y); diff --git a/src/func.cc b/src/func.cc index fa301dca..ca7a8d40 100644 --- a/src/func.cc +++ b/src/func.cc @@ -80,9 +80,9 @@ BuiltinFunction::~BuiltinFunction() { } -Value BuiltinFunction::evaluate(const Context*, const QVector &call_argnames, const QVector &call_argvalues) const +Value BuiltinFunction::evaluate(const Context *ctx, const QVector &call_argnames, const QVector &call_argvalues) const { - return eval_func(call_argnames, call_argvalues); + return eval_func(ctx, call_argnames, call_argvalues); } QString BuiltinFunction::dump(QString indent, QString name) const @@ -110,7 +110,7 @@ static double rad2deg(double x) return x; } -Value builtin_min(const QVector&, const QVector &args) +Value builtin_min(const Context *, const QVector&, const QVector &args) { if (args.size() >= 1 && args[0].type == Value::NUMBER) { double val = args[0].num; @@ -122,7 +122,7 @@ Value builtin_min(const QVector&, const QVector &args) return Value(); } -Value builtin_max(const QVector&, const QVector &args) +Value builtin_max(const Context *, const QVector&, const QVector &args) { if (args.size() >= 1 && args[0].type == Value::NUMBER) { double val = args[0].num; @@ -134,98 +134,98 @@ Value builtin_max(const QVector&, const QVector &args) return Value(); } -Value builtin_sin(const QVector&, const QVector &args) +Value builtin_sin(const Context *, const QVector&, const QVector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(sin(deg2rad(args[0].num))); return Value(); } -Value builtin_cos(const QVector&, const QVector &args) +Value builtin_cos(const Context *, const QVector&, const QVector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(cos(deg2rad(args[0].num))); return Value(); } -Value builtin_asin(const QVector&, const QVector &args) +Value builtin_asin(const Context *, const QVector&, const QVector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(rad2deg(asin(args[0].num))); return Value(); } -Value builtin_acos(const QVector&, const QVector &args) +Value builtin_acos(const Context *, const QVector&, const QVector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(rad2deg(acos(args[0].num))); return Value(); } -Value builtin_tan(const QVector&, const QVector &args) +Value builtin_tan(const Context *, const QVector&, const QVector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(tan(deg2rad(args[0].num))); return Value(); } -Value builtin_atan(const QVector&, const QVector &args) +Value builtin_atan(const Context *, const QVector&, const QVector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(rad2deg(atan(args[0].num))); return Value(); } -Value builtin_atan2(const QVector&, const QVector &args) +Value builtin_atan2(const Context *, const QVector&, const QVector &args) { if (args.size() == 2 && args[0].type == Value::NUMBER && args[1].type == Value::NUMBER) return Value(rad2deg(atan2(args[0].num, args[1].num))); return Value(); } -Value builtin_round(const QVector&, const QVector &args) -{ - if (args.size() == 1 && args[0].type == Value::NUMBER) - return Value(round(args[0].num)); - return Value(); -} - -Value builtin_ceil(const QVector&, const QVector &args) -{ - if (args.size() == 1 && args[0].type == Value::NUMBER) - return Value(ceil(args[0].num)); - return Value(); -} - -Value builtin_floor(const QVector&, const QVector &args) -{ - if (args.size() == 1 && args[0].type == Value::NUMBER) - return Value(floor(args[0].num)); - return Value(); -} - -Value builtin_pow(const QVector&, const QVector &args) +Value builtin_pow(const Context *, const QVector&, const QVector &args) { if (args.size() == 2 && args[0].type == Value::NUMBER && args[1].type == Value::NUMBER) return Value(pow(args[0].num, args[1].num)); return Value(); } -Value builtin_sqrt(const QVector&, const QVector &args) +Value builtin_round(const Context *, const QVector&, const QVector &args) +{ + if (args.size() == 1 && args[0].type == Value::NUMBER) + return Value(round(args[0].num)); + return Value(); +} + +Value builtin_ceil(const Context *, const QVector&, const QVector &args) +{ + if (args.size() == 1 && args[0].type == Value::NUMBER) + return Value(ceil(args[0].num)); + return Value(); +} + +Value builtin_floor(const Context *, const QVector&, const QVector &args) +{ + if (args.size() == 1 && args[0].type == Value::NUMBER) + return Value(floor(args[0].num)); + return Value(); +} + +Value builtin_sqrt(const Context *, const QVector&, const QVector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(sqrt(args[0].num)); return Value(); } -Value builtin_exp(const QVector&, const QVector &args) +Value builtin_exp(const Context *, const QVector&, const QVector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(exp(args[0].num)); return Value(); } -Value builtin_log(const QVector&, const QVector &args) +Value builtin_log(const Context *, const QVector&, const QVector &args) { if (args.size() == 2 && args[0].type == Value::NUMBER && args[1].type == Value::NUMBER) return Value(log(args[1].num) / log(args[0].num)); @@ -234,14 +234,14 @@ Value builtin_log(const QVector&, const QVector &args) return Value(); } -Value builtin_ln(const QVector&, const QVector &args) +Value builtin_ln(const Context *, const QVector&, const QVector &args) { if (args.size() == 1 && args[0].type == Value::NUMBER) return Value(log(args[0].num)); return Value(); } -Value builtin_str(const QVector&, const QVector &args) +Value builtin_str(const Context *, const QVector&, const QVector &args) { QString str; for (int i = 0; i < args.size(); i++) @@ -254,7 +254,7 @@ Value builtin_str(const QVector&, const QVector &args) return Value(str); } -Value builtin_lookup(const QVector&, const QVector &args) +Value builtin_lookup(const Context *, const QVector&, const QVector &args) { double p, low_p, low_v, high_p, high_v; if (args.size() < 2 || !args[0].getnum(p) || args[1].vec.size() < 2 || args[1].vec[0]->vec.size() < 2) diff --git a/src/function.h b/src/function.h index 31ca2d69..3bb89c2c 100644 --- a/src/function.h +++ b/src/function.h @@ -15,7 +15,7 @@ public: class BuiltinFunction : public AbstractFunction { public: - typedef Value (*eval_func_t)(const QVector &argnames, const QVector &args); + typedef Value (*eval_func_t)(const Context *ctx, const QVector &argnames, const QVector &args); eval_func_t eval_func; BuiltinFunction(eval_func_t f) : eval_func(f) { } diff --git a/src/import.cc b/src/import.cc index f346407a..dbc67ada 100644 --- a/src/import.cc +++ b/src/import.cc @@ -93,7 +93,7 @@ AbstractNode *ImportModule::evaluate(const Context *ctx, const ModuleInstantiati node->fs = c.lookup_variable("$fs").num; node->fa = c.lookup_variable("$fa").num; - node->filename = c.lookup_variable("file").text; + node->filename = c.get_absolute_path(c.lookup_variable("file").text); node->layername = c.lookup_variable("layer", true).text; node->convexity = c.lookup_variable("convexity", true).num; diff --git a/src/mainwin.cc b/src/mainwin.cc index 296cdb5d..0767a058 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -117,7 +117,7 @@ static char copyrighttext[] = QPointer MainWindow::current_win = NULL; -MainWindow::MainWindow(const char *filename) +MainWindow::MainWindow(const QString &filename) { setupUi(this); @@ -299,7 +299,7 @@ MainWindow::MainWindow(const char *filename) PRINT(copyrighttext); PRINT(""); - if (filename) { + if (!filename.isEmpty()) { openFile(filename); } else { setFileName(""); @@ -387,7 +387,7 @@ static void report_func(const class AbstractNode*, void *vp, int mark) #ifdef ENABLE_MDI void MainWindow::requestOpenFile(const QString &filename) { - new MainWindow(filename.toUtf8()); + new MainWindow(filename); } #else void MainWindow::requestOpenFile(const QString &) @@ -400,7 +400,7 @@ MainWindow::openFile(const QString &new_filename) { #ifdef ENABLE_MDI if (!editor->toPlainText().isEmpty()) { - new MainWindow(new_filename.toUtf8()); + new MainWindow(new_filename); current_win = NULL; return; } @@ -415,6 +415,7 @@ MainWindow::setFileName(const QString &filename) { if (filename.isEmpty()) { this->fileName.clear(); + this->root_ctx.document_path = currentdir; setWindowTitle("OpenSCAD - New Document[*]"); } else { @@ -437,6 +438,7 @@ MainWindow::setFileName(const QString &filename) this->fileName = fileinfo.fileName(); } + this->root_ctx.document_path = fileinfo.dir().absolutePath(); QDir::setCurrent(fileinfo.dir().absolutePath()); } @@ -773,7 +775,7 @@ void MainWindow::compileCSG(bool procevents) void MainWindow::actionNew() { #ifdef ENABLE_MDI - new MainWindow; + new MainWindow(QString()); #else setFileName(""); editor->setPlainText(""); diff --git a/src/openscad.cc b/src/openscad.cc index f23848b0..71d0297e 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -59,6 +59,7 @@ static void help(const char *progname) QString commandline_commands; const char *make_command = NULL; QSet dependencies; +QString currentdir; QString examplesdir; QString librarydir; @@ -101,6 +102,7 @@ int main(int argc, char **argv) #ifdef Q_WS_MAC app.installEventFilter(new EventFilter(&app)); #endif + QDir original_path = QDir::current(); // set up groups for QSettings QCoreApplication::setOrganizationName("OpenSCAD"); @@ -161,6 +163,8 @@ int main(int argc, char **argv) help(argv[0]); #endif + currentdir = QDir::currentPath(); + QDir exdir(QApplication::instance()->applicationDirPath()); #ifdef Q_WS_MAC exdir.cd("../Resources"); // Examples can be bundled @@ -232,7 +236,6 @@ int main(int argc, char **argv) root_module = parse((text+commandline_commands).toAscii().data(), fileInfo.absolutePath().toLocal8Bit(), false); } - QString original_path = QDir::currentPath(); QDir::setCurrent(fileInfo.absolutePath()); AbstractNode::resetIndexCounter(); @@ -241,7 +244,7 @@ int main(int argc, char **argv) CGAL_Nef_polyhedron *root_N; root_N = new CGAL_Nef_polyhedron(root_node->render_cgal_nef_polyhedron()); - QDir::setCurrent(original_path); + QDir::setCurrent(original_path.absolutePath()); if (deps_output_file) { fp = fopen(deps_output_file, "wt"); @@ -279,6 +282,8 @@ int main(int argc, char **argv) installAppleEventHandlers(); #endif + QString qfilename = QFileInfo(original_path, filename).absoluteFilePath(); + #if 0 /*** disabled by clifford wolf: adds rendering artefacts with OpenCSG ***/ // turn on anti-aliasing QGLFormat f; @@ -287,12 +292,12 @@ int main(int argc, char **argv) QGLFormat::setDefaultFormat(f); #endif #ifdef ENABLE_MDI - new MainWindow(filename); + new MainWindow(qfilename); while (optind < argc) - new MainWindow(argv[optind++]); + new MainWindow(QFileInfo(original_path, argv[optind++]).absoluteFilePath()); app.connect(&app, SIGNAL(lastWindowClosed()), &app, SLOT(quit())); #else - MainWindow *m = new MainWindow(filename); + MainWindow *m = new MainWindow(qfilename); app.connect(m, SIGNAL(destroyed()), &app, SLOT(quit())); #endif rc = app.exec(); diff --git a/src/openscad.h b/src/openscad.h index 125cc0c0..5a1e7939 100644 --- a/src/openscad.h +++ b/src/openscad.h @@ -46,6 +46,10 @@ extern int parser_error_pos; extern void handle_dep(QString filename); +// The CWD when application started. We shouldn't change CWD, but until we stop +// doing this, use currentdir to get the original CWD. +extern QString currentdir; + extern QString examplesdir; extern QString librarydir; diff --git a/src/surface.cc b/src/surface.cc index b2abbed4..ddcd3a67 100644 --- a/src/surface.cc +++ b/src/surface.cc @@ -64,7 +64,7 @@ AbstractNode *SurfaceModule::evaluate(const Context *ctx, const ModuleInstantiat Context c(ctx); c.args(argnames, argexpr, inst->argnames, inst->argvalues); - node->filename = c.lookup_variable("file").text; + node->filename = c.get_absolute_path(c.lookup_variable("file").text); Value center = c.lookup_variable("center", true); if (center.type == Value::BOOL) {