diff options
| author | Marius Kintel <marius@kintel.net> | 2014-01-03 18:58:13 (GMT) | 
|---|---|---|
| committer | Marius Kintel <marius@kintel.net> | 2014-01-03 18:58:13 (GMT) | 
| commit | 064247ae5e3975c3e9f529f4a4c4a0546892d96f (patch) | |
| tree | b2a11e24e73a26fc4f6551982a1677d261dea9e5 /src | |
| parent | 8dca991045a9f0563e6b654b1b946e5d778e8fd2 (diff) | |
| parent | c4a1d855f11d076d30e98f799315446da021514a (diff) | |
Merge branch 'master' of github.com:openscad/openscad
Diffstat (limited to 'src')
| -rw-r--r-- | src/Preferences.cc | 114 | ||||
| -rw-r--r-- | src/Preferences.h | 5 | ||||
| -rw-r--r-- | src/Preferences.ui | 92 | ||||
| -rw-r--r-- | src/feature.cc | 79 | ||||
| -rw-r--r-- | src/feature.h | 44 | ||||
| -rw-r--r-- | src/func.cc | 19 | ||||
| -rw-r--r-- | src/function.h | 9 | ||||
| -rw-r--r-- | src/modcontext.cc | 11 | ||||
| -rw-r--r-- | src/module.h | 7 | ||||
| -rw-r--r-- | src/openscad.cc | 10 | 
10 files changed, 372 insertions, 18 deletions
| diff --git a/src/Preferences.cc b/src/Preferences.cc index eed877d..92f11c7 100644 --- a/src/Preferences.cc +++ b/src/Preferences.cc @@ -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,102 @@ 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); -	} -	else if (action == this->prefsActionEditor) { -		this->stackedWidget->setCurrentWidget(this->pageEditor); +	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->prefsActionUpdate) { -		this->stackedWidget->setCurrentWidget(this->pageUpdate); +	QVariant v = sender->property(featurePropertyName); +	if (!v.isValid()) { +		return;  	} -	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. + *  + * When running in GUI mode, the feature setting that might have been set + * from commandline is ignored. This always uses the value coming from the + * QSettings. + */ +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 +403,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); diff --git a/src/Preferences.h b/src/Preferences.h index 1230c8a..d74ada9 100644 --- a/src/Preferences.h +++ b/src/Preferences.h @@ -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 diff --git a/src/Preferences.ui b/src/Preferences.ui index ea039f2..100bcb1 100644 --- a/src/Preferences.ui +++ b/src/Preferences.ui @@ -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"/> diff --git a/src/feature.cc b/src/feature.cc new file mode 100644 index 0000000..80d7887 --- /dev/null +++ b/src/feature.cc @@ -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; +	} +} diff --git a/src/feature.h b/src/feature.h new file mode 100644 index 0000000..20b4f16 --- /dev/null +++ b/src/feature.h @@ -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 diff --git a/src/func.cc b/src/func.cc index 4587f72..878bc1c 100644 --- a/src/func.cc +++ b/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)); diff --git a/src/function.h b/src/function.h index a1fde3c..2491809 100644 --- a/src/function.h +++ b/src/function.h @@ -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; diff --git a/src/modcontext.cc b/src/modcontext.cc index 7941cf5..21b04fd 100644 --- a/src/modcontext.cc +++ b/src/modcontext.cc @@ -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); diff --git a/src/module.h b/src/module.h index 8414706..81e5f10 100644 --- a/src/module.h +++ b/src/module.h @@ -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; diff --git a/src/openscad.cc b/src/openscad.cc index ab84235..16a6e89 100644 --- a/src/openscad.cc +++ b/src/openscad.cc @@ -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> >(); | 
