mirror of https://github.com/vitalif/openscad
Merge branch 'vector-concat' of git://github.com/t-paul/openscad into t-paul-vector-concat
Conflicts: src/Preferences.uiexport-menu
commit
bee5233a91
|
@ -12,4 +12,6 @@ parser_yacc.h
|
|||
/tmp
|
||||
/OpenSCAD.app
|
||||
*/#*#
|
||||
/nbproject
|
||||
/openscad
|
||||
/tests/openscad_nogui
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
Taken from http://tango.freedesktop.org/Tango_Icon_Library, version 0.8.90 / public domain:
|
||||
|
||||
- prefsFeatures.png (converted from preferences-system.svg)
|
Binary file not shown.
After Width: | Height: | Size: 6.0 KiB |
|
@ -222,6 +222,7 @@ HEADERS += src/typedefs.h \
|
|||
src/highlighter.h \
|
||||
src/localscope.h \
|
||||
src/module.h \
|
||||
src/feature.h \
|
||||
src/node.h \
|
||||
src/csgnode.h \
|
||||
src/linearextrudenode.h \
|
||||
|
@ -280,6 +281,7 @@ SOURCES += src/version_check.cc \
|
|||
src/func.cc \
|
||||
src/localscope.cc \
|
||||
src/module.cc \
|
||||
src/feature.cc \
|
||||
src/node.cc \
|
||||
src/context.cc \
|
||||
src/modcontext.cc \
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>icons/prefsFeatures.png</file>
|
||||
<file>icons/stopbutton.png</file>
|
||||
<file>icons/prefsAdvanced.png</file>
|
||||
<file>icons/prefs3DView.png</file>
|
||||
|
|
|
@ -33,12 +33,16 @@
|
|||
#include <QStatusBar>
|
||||
#include "PolySetCache.h"
|
||||
#include "AutoUpdater.h"
|
||||
#include "feature.h"
|
||||
#ifdef ENABLE_CGAL
|
||||
#include "CGALCache.h"
|
||||
#endif
|
||||
|
||||
Preferences *Preferences::instance = NULL;
|
||||
|
||||
const char * Preferences::featurePropertyName = "FeatureProperty";
|
||||
Q_DECLARE_METATYPE(Feature *);
|
||||
|
||||
Preferences::Preferences(QWidget *parent) : QMainWindow(parent)
|
||||
{
|
||||
setupUi(this);
|
||||
|
@ -89,10 +93,11 @@ Preferences::Preferences(QWidget *parent) : QMainWindow(parent)
|
|||
|
||||
// Toolbar
|
||||
QActionGroup *group = new QActionGroup(this);
|
||||
group->addAction(prefsAction3DView);
|
||||
group->addAction(prefsActionEditor);
|
||||
group->addAction(prefsActionUpdate);
|
||||
group->addAction(prefsActionAdvanced);
|
||||
addPrefPage(group, prefsAction3DView, page3DView);
|
||||
addPrefPage(group, prefsActionEditor, pageEditor);
|
||||
addPrefPage(group, prefsActionUpdate, pageUpdate);
|
||||
addPrefPage(group, prefsActionFeatures, pageFeatures);
|
||||
addPrefPage(group, prefsActionAdvanced, pageAdvanced);
|
||||
connect(group, SIGNAL(triggered(QAction*)), this, SLOT(actionTriggered(QAction*)));
|
||||
|
||||
prefsAction3DView->setChecked(true);
|
||||
|
@ -140,6 +145,7 @@ Preferences::Preferences(QWidget *parent) : QMainWindow(parent)
|
|||
this->polysetCacheSizeEdit->setValidator(validator);
|
||||
this->opencsgLimitEdit->setValidator(validator);
|
||||
|
||||
setupFeaturesPage();
|
||||
updateGUI();
|
||||
|
||||
RenderSettings::inst()->setColors(this->colorschemes[getValue("3dview/colorscheme").toString()]);
|
||||
|
@ -150,21 +156,103 @@ Preferences::~Preferences()
|
|||
removeDefaultSettings();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a page for the preferences GUI. This handles both the action grouping
|
||||
* and the registration of the widget for each action to have a generalized
|
||||
* callback to switch pages.
|
||||
*
|
||||
* @param group The action group for all page actions. This one will have the
|
||||
* callback attached after creating all actions/pages.
|
||||
* @param action The action specific for the added page.
|
||||
* @param widget The widget that should be shown when the action is triggered.
|
||||
* This must be a child page of the stackedWidget.
|
||||
*/
|
||||
void
|
||||
Preferences::addPrefPage(QActionGroup *group, QAction *action, QWidget *widget)
|
||||
{
|
||||
group->addAction(action);
|
||||
prefPages[action] = widget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback to switch pages in the preferences GUI.
|
||||
*
|
||||
* @param action The action triggered by the user.
|
||||
*/
|
||||
void
|
||||
Preferences::actionTriggered(QAction *action)
|
||||
{
|
||||
if (action == this->prefsAction3DView) {
|
||||
this->stackedWidget->setCurrentWidget(this->page3DView);
|
||||
this->stackedWidget->setCurrentWidget(prefPages[action]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the dynamically created checkboxes on the features
|
||||
* page. The specific Feature object is associated as property with
|
||||
* the callback.
|
||||
*
|
||||
* @param state the state of the checkbox.
|
||||
*/
|
||||
void Preferences::featuresCheckBoxToggled(bool state)
|
||||
{
|
||||
const QObject *sender = QObject::sender();
|
||||
if (sender == NULL) {
|
||||
return;
|
||||
}
|
||||
else if (action == this->prefsActionEditor) {
|
||||
this->stackedWidget->setCurrentWidget(this->pageEditor);
|
||||
QVariant v = sender->property(featurePropertyName);
|
||||
if (!v.isValid()) {
|
||||
return;
|
||||
}
|
||||
else if (action == this->prefsActionUpdate) {
|
||||
this->stackedWidget->setCurrentWidget(this->pageUpdate);
|
||||
}
|
||||
else if (action == this->prefsActionAdvanced) {
|
||||
this->stackedWidget->setCurrentWidget(this->pageAdvanced);
|
||||
Feature *feature = v.value<Feature *>();
|
||||
feature->enable(state);
|
||||
QSettings settings;
|
||||
settings.setValue(QString("feature/%1").arg(QString::fromStdString(feature->get_name())), state);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup feature GUI and synchronize the Qt settings with the feature values.
|
||||
*
|
||||
* In case a feature was enabled on the commandline this will have precedence
|
||||
* and cause the checkbox in the settings GUI to be not editable.
|
||||
* Otherwise the value from the Qt settings is pushed into the feature state
|
||||
* and the checkbox is initialized accordingly.
|
||||
*/
|
||||
void
|
||||
Preferences::setupFeaturesPage()
|
||||
{
|
||||
int row = 0;
|
||||
for (Feature::iterator it = Feature::begin();it != Feature::end();it++) {
|
||||
Feature *feature = *it;
|
||||
|
||||
QString featurekey = QString("feature/%1").arg(QString::fromStdString(feature->get_name()));
|
||||
this->defaultmap[featurekey] = false;
|
||||
|
||||
// spacer item between the features, just for some optical separation
|
||||
gridLayoutExperimentalFeatures->addItem(new QSpacerItem(1, 8, QSizePolicy::Expanding, QSizePolicy::Fixed), row, 1, 1, 1, Qt::AlignCenter);
|
||||
row++;
|
||||
|
||||
QCheckBox *cb = new QCheckBox(QString::fromStdString(feature->get_name()), pageFeatures);
|
||||
QFont bold_font(cb->font());
|
||||
bold_font.setBold(true);
|
||||
cb->setFont(bold_font);
|
||||
// synchronize Qt settings with the feature settings
|
||||
bool value = getValue(featurekey).toBool();
|
||||
feature->enable(value);
|
||||
cb->setChecked(value);
|
||||
cb->setProperty(featurePropertyName, QVariant::fromValue<Feature *>(feature));
|
||||
connect(cb, SIGNAL(toggled(bool)), this, SLOT(featuresCheckBoxToggled(bool)));
|
||||
gridLayoutExperimentalFeatures->addWidget(cb, row, 0, 1, 2, Qt::AlignLeading);
|
||||
row++;
|
||||
|
||||
QLabel *l = new QLabel(QString::fromStdString(feature->get_description()), pageFeatures);
|
||||
l->setTextFormat(Qt::RichText);
|
||||
gridLayoutExperimentalFeatures->addWidget(l, row, 1, 1, 1, Qt::AlignLeading);
|
||||
row++;
|
||||
}
|
||||
// Force fixed indentation, the checkboxes use column span of 2 so
|
||||
// first row is not constrained in size by the visible controls. The
|
||||
// fixed size space essentially gives the first row the width of the
|
||||
// spacer item itself.
|
||||
gridLayoutExperimentalFeatures->addItem(new QSpacerItem(20, 0, QSizePolicy::Fixed, QSizePolicy::Fixed), 1, 0, 1, 1, Qt::AlignLeading);
|
||||
}
|
||||
|
||||
void Preferences::on_colorSchemeChooser_itemSelectionChanged()
|
||||
|
@ -316,7 +404,6 @@ QVariant Preferences::getValue(const QString &key) const
|
|||
|
||||
void Preferences::updateGUI()
|
||||
{
|
||||
QSettings settings;
|
||||
QList<QListWidgetItem *> found =
|
||||
this->colorSchemeChooser->findItems(getValue("3dview/colorscheme").toString(),
|
||||
Qt::MatchExactly);
|
||||
|
|
|
@ -21,6 +21,7 @@ public:
|
|||
|
||||
public slots:
|
||||
void actionTriggered(class QAction *);
|
||||
void featuresCheckBoxToggled(bool);
|
||||
void on_colorSchemeChooser_itemSelectionChanged();
|
||||
void on_fontChooser_activated(const QString &);
|
||||
void on_fontSize_editTextChanged(const QString &);
|
||||
|
@ -46,11 +47,15 @@ private:
|
|||
void keyPressEvent(QKeyEvent *e);
|
||||
void updateGUI();
|
||||
void removeDefaultSettings();
|
||||
void setupFeaturesPage();
|
||||
void addPrefPage(QActionGroup *group, QAction *action, QWidget *widget);
|
||||
|
||||
QSettings::SettingsMap defaultmap;
|
||||
QHash<QString, std::map<RenderSettings::RenderColor, Color4f> > colorschemes;
|
||||
QHash<const QAction *, QWidget *> prefPages;
|
||||
|
||||
static Preferences *instance;
|
||||
static const char *featurePropertyName;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>473</width>
|
||||
<height>320</height>
|
||||
<width>823</width>
|
||||
<height>433</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
|
@ -378,6 +378,78 @@
|
|||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="pageFeatures">
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_9">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Features</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QScrollArea" name="scrollArea">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::NoFrame</enum>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Plain</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="widgetResizable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<widget class="QWidget" name="scrollAreaWidgetContents">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>803</width>
|
||||
<height>311</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||
<item>
|
||||
<layout class="QGridLayout" name="gridLayoutExperimentalFeatures" rowminimumheight="0">
|
||||
<property name="spacing">
|
||||
<number>8</number>
|
||||
</property>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>282</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="pageAdvanced">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
|
@ -520,6 +592,7 @@
|
|||
<addaction name="prefsAction3DView"/>
|
||||
<addaction name="prefsActionEditor"/>
|
||||
<addaction name="prefsActionUpdate"/>
|
||||
<addaction name="prefsActionFeatures"/>
|
||||
<addaction name="prefsActionAdvanced"/>
|
||||
</widget>
|
||||
<action name="prefsAction3DView">
|
||||
|
@ -570,6 +643,21 @@
|
|||
<string>Update</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="prefsActionFeatures">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../openscad.qrc">
|
||||
<normaloff>:/icons/prefsFeatures.png</normaloff>:/icons/prefsFeatures.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Features</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Enable/Disable experimental features</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources>
|
||||
<include location="../openscad.qrc"/>
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
#include "feature.h"
|
||||
#include "printutils.h"
|
||||
|
||||
/**
|
||||
* Feature registration map/list for later lookup. This must be initialized
|
||||
* before the static feature instances as those register with this map.
|
||||
*/
|
||||
Feature::map_t Feature::feature_map;
|
||||
Feature::list_t Feature::feature_list;
|
||||
|
||||
/*
|
||||
* List of features, the names given here are used in both command line
|
||||
* argument to enable the option and for saving the option value in GUI
|
||||
* context.
|
||||
*/
|
||||
const Feature Feature::ExperimentalConcatFunction("concat", "Enable the <code>concat()</code> function.");
|
||||
|
||||
Feature::Feature(const std::string &name, const std::string &description)
|
||||
: enabled(false), name(name), description(description)
|
||||
{
|
||||
feature_map[name] = this;
|
||||
feature_list.push_back(this);
|
||||
}
|
||||
|
||||
Feature::~Feature()
|
||||
{
|
||||
}
|
||||
|
||||
const std::string &Feature::get_name() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
const std::string &Feature::get_description() const
|
||||
{
|
||||
return description;
|
||||
}
|
||||
|
||||
bool Feature::is_enabled() const
|
||||
{
|
||||
return enabled;
|
||||
}
|
||||
|
||||
void Feature::enable(bool status)
|
||||
{
|
||||
enabled = status;
|
||||
}
|
||||
|
||||
void Feature::enable_feature(const std::string &feature_name, bool status)
|
||||
{
|
||||
map_t::iterator it = feature_map.find(feature_name);
|
||||
if (it != feature_map.end()) {
|
||||
it->second->enable(status);
|
||||
} else {
|
||||
PRINTB("WARNING: Ignoring request to enable unknown feature '%s'.", feature_name);
|
||||
}
|
||||
}
|
||||
|
||||
Feature::iterator Feature::begin()
|
||||
{
|
||||
return feature_list.begin();
|
||||
}
|
||||
|
||||
Feature::iterator Feature::end()
|
||||
{
|
||||
return feature_list.end();
|
||||
}
|
||||
|
||||
void Feature::dump_features()
|
||||
{
|
||||
for (map_t::iterator it = feature_map.begin(); it != feature_map.end(); it++) {
|
||||
std::cout << "Feature('" << it->first << "') = " << (it->second->is_enabled() ? "enabled" : "disabled") << std::endl;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef FEATURE_H_
|
||||
#define FEATURE_H_
|
||||
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
class Feature
|
||||
{
|
||||
public:
|
||||
typedef std::vector<Feature *> list_t;
|
||||
typedef list_t::iterator iterator;
|
||||
|
||||
static const Feature ExperimentalConcatFunction;
|
||||
|
||||
const std::string& get_name() const;
|
||||
const std::string& get_description() const;
|
||||
|
||||
bool is_enabled() const;
|
||||
void enable(bool status);
|
||||
|
||||
static iterator begin();
|
||||
static iterator end();
|
||||
|
||||
static void dump_features();
|
||||
static void enable_feature(const std::string &feature_name, bool status = true);
|
||||
|
||||
private:
|
||||
bool enabled;
|
||||
|
||||
const std::string name;
|
||||
const std::string description;
|
||||
|
||||
typedef std::map<std::string, Feature *> map_t;
|
||||
static map_t feature_map;
|
||||
static list_t feature_list;
|
||||
|
||||
Feature(const std::string &name, const std::string &description);
|
||||
virtual ~Feature();
|
||||
};
|
||||
|
||||
#endif
|
19
src/func.cc
19
src/func.cc
|
@ -343,6 +343,24 @@ Value builtin_str(const Context *, const EvalContext *evalctx)
|
|||
return Value(stream.str());
|
||||
}
|
||||
|
||||
Value builtin_concat(const Context *, const EvalContext *evalctx)
|
||||
{
|
||||
Value::VectorType result;
|
||||
|
||||
for (size_t i = 0; i < evalctx->numArgs(); i++) {
|
||||
const Value v = evalctx->getArgValue(i);
|
||||
if (v.type() == Value::VECTOR) {
|
||||
Value::VectorType vec = v.toVector();
|
||||
for (Value::VectorType::const_iterator it = vec.begin(); it != vec.end(); it++) {
|
||||
result.push_back(*it);
|
||||
}
|
||||
} else {
|
||||
result.push_back(v);
|
||||
}
|
||||
}
|
||||
return Value(result);
|
||||
}
|
||||
|
||||
Value builtin_lookup(const Context *, const EvalContext *evalctx)
|
||||
{
|
||||
double p, low_p, low_v, high_p, high_v;
|
||||
|
@ -604,6 +622,7 @@ void register_builtin_functions()
|
|||
Builtins::init("log", new BuiltinFunction(&builtin_log));
|
||||
Builtins::init("ln", new BuiltinFunction(&builtin_ln));
|
||||
Builtins::init("str", new BuiltinFunction(&builtin_str));
|
||||
Builtins::init("concat", new BuiltinFunction(&builtin_concat, Feature::ExperimentalConcatFunction));
|
||||
Builtins::init("lookup", new BuiltinFunction(&builtin_lookup));
|
||||
Builtins::init("search", new BuiltinFunction(&builtin_search));
|
||||
Builtins::init("version", new BuiltinFunction(&builtin_version));
|
||||
|
|
|
@ -3,13 +3,21 @@
|
|||
|
||||
#include "value.h"
|
||||
#include "typedefs.h"
|
||||
#include "feature.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
class AbstractFunction
|
||||
{
|
||||
private:
|
||||
const Feature *feature;
|
||||
public:
|
||||
AbstractFunction() : feature(NULL) {}
|
||||
AbstractFunction(const Feature& feature) : feature(&feature) {}
|
||||
virtual ~AbstractFunction();
|
||||
virtual bool is_enabled() const { return (feature == NULL) || feature->is_enabled(); };
|
||||
virtual Value evaluate(const class Context *ctx, const class EvalContext *evalctx) const;
|
||||
virtual std::string dump(const std::string &indent, const std::string &name) const;
|
||||
};
|
||||
|
@ -21,6 +29,7 @@ public:
|
|||
eval_func_t eval_func;
|
||||
|
||||
BuiltinFunction(eval_func_t f) : eval_func(f) { }
|
||||
BuiltinFunction(eval_func_t f, const Feature& feature) : AbstractFunction(feature), eval_func(f) { }
|
||||
virtual ~BuiltinFunction();
|
||||
|
||||
virtual Value evaluate(const Context *ctx, const EvalContext *evalctx) const;
|
||||
|
|
|
@ -95,7 +95,12 @@ void ModuleContext::registerBuiltin()
|
|||
const AbstractFunction *ModuleContext::findLocalFunction(const std::string &name) const
|
||||
{
|
||||
if (this->functions_p && this->functions_p->find(name) != this->functions_p->end()) {
|
||||
return this->functions_p->find(name)->second;
|
||||
AbstractFunction *f = this->functions_p->find(name)->second;
|
||||
if (!f->is_enabled()) {
|
||||
PRINTB("WARNING: Experimental builtin function '%s' is not enabled.", name);
|
||||
return NULL;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
@ -104,6 +109,10 @@ const AbstractModule *ModuleContext::findLocalModule(const std::string &name) co
|
|||
{
|
||||
if (this->modules_p && this->modules_p->find(name) != this->modules_p->end()) {
|
||||
AbstractModule *m = this->modules_p->find(name)->second;
|
||||
if (!m->is_enabled()) {
|
||||
PRINTB("WARNING: Experimental builtin module '%s' is not enabled.", name);
|
||||
return NULL;
|
||||
}
|
||||
std::string replacement = Builtins::instance()->isDeprecated(name);
|
||||
if (!replacement.empty()) {
|
||||
PRINTB("DEPRECATED: The %s() module will be removed in future releases. Use %s() instead.", name % replacement);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "value.h"
|
||||
#include "typedefs.h"
|
||||
#include "localscope.h"
|
||||
#include "feature.h"
|
||||
|
||||
class ModuleInstantiation
|
||||
{
|
||||
|
@ -60,8 +61,13 @@ public:
|
|||
|
||||
class AbstractModule
|
||||
{
|
||||
private:
|
||||
const Feature *feature;
|
||||
public:
|
||||
AbstractModule() : feature(NULL) {}
|
||||
AbstractModule(const Feature& feature) : feature(&feature) {}
|
||||
virtual ~AbstractModule();
|
||||
virtual bool is_enabled() const { return (feature == NULL) || feature->is_enabled(); };
|
||||
virtual class AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const class EvalContext *evalctx = NULL) const;
|
||||
virtual std::string dump(const std::string &indent, const std::string &name) const;
|
||||
};
|
||||
|
@ -70,6 +76,7 @@ class Module : public AbstractModule
|
|||
{
|
||||
public:
|
||||
Module() { }
|
||||
Module(const Feature& feature) : AbstractModule(feature) { }
|
||||
virtual ~Module();
|
||||
|
||||
virtual AbstractNode *instantiate(const Context *ctx, const ModuleInstantiation *inst, const EvalContext *evalctx = NULL) const;
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "builtin.h"
|
||||
#include "printutils.h"
|
||||
#include "handle_dep.h"
|
||||
#include "feature.h"
|
||||
#include "parsersettings.h"
|
||||
#include "rendersettings.h"
|
||||
#include "PlatformUtils.h"
|
||||
|
@ -111,6 +112,7 @@ static void help(const char *progname)
|
|||
"%2% --camera=eyex,y,z,centerx,y,z ] \\\n"
|
||||
"%2%[ --imgsize=width,height ] [ --projection=(o)rtho|(p)ersp] \\\n"
|
||||
"%2%[ --render | --preview[=throwntogether] ] \\\n"
|
||||
"%2%[ --enable=<feature> \\\n"
|
||||
"%2%filename\n",
|
||||
progname % (const char *)tabstr);
|
||||
exit(1);
|
||||
|
@ -587,7 +589,8 @@ int main(int argc, char **argv)
|
|||
("x,x", po::value<string>(), "dxf-file")
|
||||
("d,d", po::value<string>(), "deps-file")
|
||||
("m,m", po::value<string>(), "makefile")
|
||||
("D,D", po::value<vector<string> >(), "var=val");
|
||||
("D,D", po::value<vector<string> >(), "var=val")
|
||||
("enable", po::value<vector<string> >(), "enable experimental features");
|
||||
|
||||
po::options_description hidden("Hidden options");
|
||||
hidden.add_options()
|
||||
|
@ -651,6 +654,11 @@ int main(int argc, char **argv)
|
|||
commandline_commands += ";\n";
|
||||
}
|
||||
}
|
||||
if (vm.count("enable")) {
|
||||
BOOST_FOREACH(const string &feature, vm["enable"].as<vector<string> >()) {
|
||||
Feature::enable_feature(feature);
|
||||
}
|
||||
}
|
||||
vector<string> inputFiles;
|
||||
if (vm.count("input-file")) {
|
||||
inputFiles = vm["input-file"].as<vector<string> >();
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
u = undef;
|
||||
|
||||
echo("--- empty");
|
||||
echo(concat());
|
||||
echo(concat([]));
|
||||
echo(concat([], []));
|
||||
echo(concat([], [], []));
|
||||
|
||||
echo("--- single elements");
|
||||
echo(concat(u));
|
||||
echo(concat(true));
|
||||
echo(concat(3));
|
||||
echo(concat("abc"));
|
||||
echo(concat([0:1:10]));
|
||||
|
||||
echo("--- single vectors");
|
||||
echo(concat([1, 2, 3]));
|
||||
echo(concat([[1, 2, 3]]));
|
||||
echo(concat([[[1, 2, 3]]]));
|
||||
echo(concat([[[1, 2, [3, 4], 5]]]));
|
||||
|
||||
echo("--- multiple elements");
|
||||
echo(concat(3, 3));
|
||||
echo(concat(1, 2, 3));
|
||||
echo(concat(1, 2, 3, 4, 5));
|
||||
echo(concat(1, "text", false, [1:0.5:3]));
|
||||
|
||||
echo("--- vector / element");
|
||||
echo(concat([3, 4], u));
|
||||
echo(concat([3, 4, 5], 6));
|
||||
echo(concat([3, 4, 5, 6], true));
|
||||
echo(concat([3, 4, "5", 6], "test"));
|
||||
echo(concat([3, 4, true, 6], [4:1:3]));
|
||||
|
||||
echo("--- element / vector");
|
||||
echo(concat(3, []));
|
||||
echo(concat(3, [3, 4]));
|
||||
echo(concat(true, [3, [4]]));
|
||||
echo(concat("9", [1, 2, 3]));
|
||||
echo(concat([6:2:9], [3, [4]]));
|
||||
|
||||
echo("--- vector / vector");
|
||||
echo(concat([], [3, 4]));
|
||||
echo(concat([[]], [3, 4]));
|
||||
echo(concat([[2, 4]], [3, 4]));
|
||||
echo(concat([5, 6], ["d", [3, 4]]));
|
||||
echo(concat([[1, 0, 0], [2, 0, 0]], [3, 0, 0]));
|
||||
echo(concat([[1, 0, 0], [2, 0, 0]], [[3, 0, 0]]));
|
||||
echo(concat([[1, 0, 0], [2, 0, 0], [3, 0, 0]], [[4, 4, 4], [5, 5, 5]]));
|
||||
|
||||
echo("--- recursive function");
|
||||
function r(i) = i > 0 ? concat(r(i - 1), [[i, i * i]]) : [];
|
||||
echo(r(10));
|
|
@ -517,6 +517,7 @@ set(CORE_SOURCES
|
|||
../src/context.cc
|
||||
../src/modcontext.cc
|
||||
../src/evalcontext.cc
|
||||
../src/feature.cc
|
||||
../src/csgterm.cc
|
||||
../src/csgtermnormalizer.cc
|
||||
../src/polyset.cc
|
||||
|
@ -990,6 +991,11 @@ add_cmdline_test(throwntogethertest EXE ${OPENSCAD_BINPATH} ARGS --preview=throw
|
|||
# with anything. It's self-contained and returns != 0 on error
|
||||
add_cmdline_test(cgalstlsanitytest EXE ${CMAKE_SOURCE_DIR}/cgalstlsanitytest SUFFIX txt ARGS ${OPENSCAD_BINPATH} FILES ${CGALSTLSANITYTEST_FILES})
|
||||
|
||||
# Add experimental tests
|
||||
|
||||
add_cmdline_test(echotest EXE ${OPENSCAD_BINPATH} ARGS --enable=concat -o SUFFIX echo FILES ${CMAKE_SOURCE_DIR}/../testdata/scad/experimental/concat-tests.scad)
|
||||
|
||||
|
||||
# Tests using the actual OpenSCAD binary
|
||||
|
||||
# non-ASCII filenames
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
ECHO: "--- empty"
|
||||
ECHO: []
|
||||
ECHO: []
|
||||
ECHO: []
|
||||
ECHO: []
|
||||
ECHO: "--- single elements"
|
||||
ECHO: [undef]
|
||||
ECHO: [true]
|
||||
ECHO: [3]
|
||||
ECHO: ["abc"]
|
||||
ECHO: [[0 : 1 : 10]]
|
||||
ECHO: "--- single vectors"
|
||||
ECHO: [1, 2, 3]
|
||||
ECHO: [[1, 2, 3]]
|
||||
ECHO: [[[1, 2, 3]]]
|
||||
ECHO: [[[1, 2, [3, 4], 5]]]
|
||||
ECHO: "--- multiple elements"
|
||||
ECHO: [3, 3]
|
||||
ECHO: [1, 2, 3]
|
||||
ECHO: [1, 2, 3, 4, 5]
|
||||
ECHO: [1, "text", false, [1 : 0.5 : 3]]
|
||||
ECHO: "--- vector / element"
|
||||
ECHO: [3, 4, undef]
|
||||
ECHO: [3, 4, 5, 6]
|
||||
ECHO: [3, 4, 5, 6, true]
|
||||
ECHO: [3, 4, "5", 6, "test"]
|
||||
ECHO: [3, 4, true, 6, [4 : 1 : 3]]
|
||||
ECHO: "--- element / vector"
|
||||
ECHO: [3]
|
||||
ECHO: [3, 3, 4]
|
||||
ECHO: [true, 3, [4]]
|
||||
ECHO: ["9", 1, 2, 3]
|
||||
ECHO: [[6 : 2 : 9], 3, [4]]
|
||||
ECHO: "--- vector / vector"
|
||||
ECHO: [3, 4]
|
||||
ECHO: [[], 3, 4]
|
||||
ECHO: [[2, 4], 3, 4]
|
||||
ECHO: [5, 6, "d", [3, 4]]
|
||||
ECHO: [[1, 0, 0], [2, 0, 0], 3, 0, 0]
|
||||
ECHO: [[1, 0, 0], [2, 0, 0], [3, 0, 0]]
|
||||
ECHO: [[1, 0, 0], [2, 0, 0], [3, 0, 0], [4, 4, 4], [5, 5, 5]]
|
||||
ECHO: "--- recursive function"
|
||||
ECHO: [[1, 1], [2, 4], [3, 9], [4, 16], [5, 25], [6, 36], [7, 49], [8, 64], [9, 81], [10, 100]]
|
Loading…
Reference in New Issue