diff --git a/openscad.pro b/openscad.pro index d9b99c73..80785f84 100644 --- a/openscad.pro +++ b/openscad.pro @@ -247,6 +247,7 @@ HEADERS += src/typedefs.h \ src/ProgressWidget.h \ src/parsersettings.h \ src/renderer.h \ + src/settings.h \ src/rendersettings.h \ src/colormap.h \ src/ThrownTogetherRenderer.h \ @@ -399,6 +400,7 @@ SOURCES += src/version_check.cc \ src/FreetypeRenderer.cc \ src/FontCache.cc \ \ + src/settings.cc \ src/rendersettings.cc \ src/highlighter.cc \ src/Preferences.cc \ diff --git a/src/Preferences.cc b/src/Preferences.cc index 9c8f9b59..11d64502 100644 --- a/src/Preferences.cc +++ b/src/Preferences.cc @@ -45,6 +45,55 @@ Preferences *Preferences::instance = NULL; const char * Preferences::featurePropertyName = "FeatureProperty"; Q_DECLARE_METATYPE(Feature *); +class SettingsReader : public Settings::Visitor +{ + QSettings settings; + const Value getValue(const Settings::SettingsEntry& entry, const std::string& value) const { + if (value.empty()) { + return entry.defaultValue(); + } + + try { + switch (entry.defaultValue().type()) { + case Value::STRING: + return Value(value); + case Value::NUMBER: + return Value(boost::lexical_cast(value)); + case Value::BOOL: + return Value(boost::lexical_cast(value)); + default: + assert(false && "invalid value type for settings"); + } + } catch (const boost::bad_lexical_cast& e) { + return entry.defaultValue(); + } + } + + virtual void handle(Settings::SettingsEntry& entry) const { + Settings::Settings *s = Settings::Settings::inst(); + + std::string key = entry.category() + "/" + entry.name(); + std::string value = settings.value(QString::fromStdString(key)).toString().toStdString(); + s->set(entry, getValue(entry, value)); + } +}; + +class SettingsWriter : public Settings::Visitor +{ + virtual void handle(Settings::SettingsEntry& entry) const { + Settings::Settings *s = Settings::Settings::inst(); + + QSettings settings; + QString key = QString::fromStdString(entry.category() + "/" + entry.name()); + if (entry.is_default()) { + settings.remove(key); + } else { + Value value = s->get(entry); + settings.setValue(key, QString::fromStdString(value.toString())); + } + } +}; + Preferences::Preferences(QWidget *parent) : QMainWindow(parent) { setupUi(this); @@ -140,6 +189,22 @@ void Preferences::init() { #endif this->polysetCacheSizeEdit->setValidator(validator); this->opencsgLimitEdit->setValidator(validator); + + initComboBox(this->comboBoxIndentUsing, Settings::Settings::indentStyle); + initComboBox(this->comboBoxLineWrap, Settings::Settings::lineWrap); + initComboBox(this->comboBoxLineWrapIndentationStyle, Settings::Settings::lineWrapIndentationStyle); + initComboBox(this->comboBoxLineWrapVisualizationEnd, Settings::Settings::lineWrapVisualizationEnd); + initComboBox(this->comboBoxLineWrapVisualizationStart, Settings::Settings::lineWrapVisualizationBegin); + initComboBox(this->comboBoxShowWhitespace, Settings::Settings::showWhitespace); + initComboBox(this->comboBoxTabKeyFunction, Settings::Settings::tabKeyFunction); + initSpinBox(this->spinBoxIndentationWidth, Settings::Settings::indentationWidth); + initSpinBox(this->spinBoxLineWrapIndentationIndent, Settings::Settings::lineWrapIndentation); + initSpinBox(this->spinBoxShowWhitespaceSize, Settings::Settings::showWhitespaceSize); + initSpinBox(this->spinBoxTabWidth, Settings::Settings::tabWidth); + + SettingsReader settingsReader; + Settings::Settings::inst()->visit(settingsReader); + emit editorConfigChanged(); } Preferences::~Preferences() @@ -400,13 +465,96 @@ void Preferences::on_mouseWheelZoomBox_toggled(bool state) settings.setValue("editor/ctrlmousewheelzoom", state); } -void -Preferences::on_launcherBox_toggled(bool state) +void Preferences::on_launcherBox_toggled(bool state) { QSettings settings; settings.setValue("launcher/showOnStartup", state); } +void Preferences::on_spinBoxIndentationWidth_valueChanged(int val) +{ + Settings::Settings::inst()->set(Settings::Settings::indentationWidth, Value(val)); + fireEditorConfigChanged(); +} + +void Preferences::on_spinBoxTabWidth_valueChanged(int val) +{ + Settings::Settings::inst()->set(Settings::Settings::tabWidth, Value(val)); + fireEditorConfigChanged(); +} + +void Preferences::on_comboBoxLineWrap_activated(int val) +{ + applyComboBox(comboBoxLineWrap, val, Settings::Settings::lineWrap); +} + +void Preferences::on_comboBoxLineWrapIndentationStyle_activated(int val) +{ + applyComboBox(comboBoxLineWrapIndentationStyle, val, Settings::Settings::lineWrapIndentationStyle); +} + +void Preferences::on_spinBoxLineWrapIndentationIndent_valueChanged(int val) +{ + Settings::Settings::inst()->set(Settings::Settings::lineWrapIndentation, Value(val)); + fireEditorConfigChanged(); +} + +void Preferences::on_comboBoxLineWrapVisualizationStart_activated(int val) +{ + applyComboBox(comboBoxLineWrapVisualizationStart, val, Settings::Settings::lineWrapVisualizationBegin); +} + +void Preferences::on_comboBoxLineWrapVisualizationEnd_activated(int val) +{ + applyComboBox(comboBoxLineWrapVisualizationEnd, val, Settings::Settings::lineWrapVisualizationEnd); +} + +void Preferences::on_comboBoxShowWhitespace_activated(int val) +{ + applyComboBox(comboBoxShowWhitespace, val, Settings::Settings::showWhitespace); +} + +void Preferences::on_spinBoxShowWhitespaceSize_valueChanged(int val) +{ + Settings::Settings::inst()->set(Settings::Settings::showWhitespaceSize, Value(val)); + fireEditorConfigChanged(); +} + +void Preferences::on_checkBoxAutoIndent_toggled(bool val) +{ + Settings::Settings::inst()->set(Settings::Settings::autoIndent, Value(val)); + fireEditorConfigChanged(); +} + +void Preferences::on_comboBoxIndentUsing_activated(int val) +{ + applyComboBox(comboBoxIndentUsing, val, Settings::Settings::indentStyle); +} + +void Preferences::on_comboBoxTabKeyFunction_activated(int val) +{ + applyComboBox(comboBoxTabKeyFunction, val, Settings::Settings::tabKeyFunction); +} + +void Preferences::on_checkBoxHighlightCurrentLine_toggled(bool val) +{ + Settings::Settings::inst()->set(Settings::Settings::highlightCurrentLine, Value(val)); + fireEditorConfigChanged(); +} + +void Preferences::on_checkBoxEnableBraceMatching_toggled(bool val) +{ + Settings::Settings::inst()->set(Settings::Settings::enableBraceMatching, Value(val)); + fireEditorConfigChanged(); +} + +void Preferences::fireEditorConfigChanged() const +{ + SettingsWriter settingsWriter; + Settings::Settings::inst()->visit(settingsWriter); + emit editorConfigChanged(); +} + void Preferences::keyPressEvent(QKeyEvent *e) { #ifdef Q_OS_MAC @@ -500,6 +648,68 @@ void Preferences::updateGUI() this->undockCheckBox->setChecked(getValue("advanced/undockableWindows").toBool()); this->undockCheckBox->setEnabled(this->reorderCheckBox->isChecked()); this->launcherBox->setChecked(getValue("launcher/showOnStartup").toBool()); + + Settings::Settings *s = Settings::Settings::inst(); + updateComboBox(this->comboBoxLineWrap, Settings::Settings::lineWrap); + updateComboBox(this->comboBoxLineWrapIndentationStyle, Settings::Settings::lineWrapIndentationStyle); + updateComboBox(this->comboBoxLineWrapVisualizationStart, Settings::Settings::lineWrapVisualizationBegin); + updateComboBox(this->comboBoxLineWrapVisualizationEnd, Settings::Settings::lineWrapVisualizationEnd); + updateComboBox(this->comboBoxShowWhitespace, Settings::Settings::showWhitespace); + updateComboBox(this->comboBoxIndentUsing, Settings::Settings::indentStyle); + updateComboBox(this->comboBoxTabKeyFunction, Settings::Settings::tabKeyFunction); + this->spinBoxIndentationWidth->setValue(s->get(Settings::Settings::indentationWidth).toDouble()); + this->spinBoxTabWidth->setValue(s->get(Settings::Settings::tabWidth).toDouble()); + this->spinBoxLineWrapIndentationIndent->setValue(s->get(Settings::Settings::lineWrapIndentation).toDouble()); + this->spinBoxShowWhitespaceSize->setValue(s->get(Settings::Settings::showWhitespaceSize).toDouble()); + this->checkBoxAutoIndent->setChecked(s->get(Settings::Settings::autoIndent).toBool()); + this->checkBoxHighlightCurrentLine->setChecked(s->get(Settings::Settings::highlightCurrentLine).toBool()); + this->checkBoxEnableBraceMatching->setChecked(s->get(Settings::Settings::enableBraceMatching).toBool()); +} + +void Preferences::initComboBox(QComboBox *comboBox, const Settings::SettingsEntry& entry) +{ + comboBox->clear(); + Value::VectorType vector = entry.range().toVector(); + for (Value::VectorType::iterator it = vector.begin();it != vector.end();it++) { + QString val = QString::fromStdString((*it)[0].toString()); + QString text = QString::fromStdString((*it)[1].toString()); + comboBox->addItem(text, val); + } +} + +void Preferences::initSpinBox(QSpinBox *spinBox, const Settings::SettingsEntry& entry) +{ + Value::RangeType range = entry.range().toRange(); + spinBox->setMinimum(range.begin_value()); + spinBox->setMaximum(range.end_value()); +} + +void Preferences::updateComboBox(QComboBox *comboBox, const Settings::SettingsEntry& entry) +{ + Settings::Settings *s = Settings::Settings::inst(); + + Value value = s->get(entry); + QString text = QString::fromStdString(value.toString()); + int idx = comboBox->findData(text); + if (idx >= 0) { + comboBox->setCurrentIndex(idx); + } else { + Value defaultValue = entry.defaultValue(); + QString defaultText = QString::fromStdString(defaultValue.toString()); + int defIdx = comboBox->findData(defaultText); + if (defIdx >= 0) { + comboBox->setCurrentIndex(defIdx); + } else { + comboBox->setCurrentIndex(0); + } + } +} + +void Preferences::applyComboBox(QComboBox *comboBox, int val, Settings::SettingsEntry& entry) +{ + QString s = comboBox->itemData(val).toString(); + Settings::Settings::inst()->set(entry, Value(s.toStdString())); + fireEditorConfigChanged(); } void Preferences::apply() const diff --git a/src/Preferences.h b/src/Preferences.h index cd89fa97..35c7d625 100644 --- a/src/Preferences.h +++ b/src/Preferences.h @@ -1,9 +1,11 @@ #pragma once -#include "qtgettext.h" #include #include + +#include "qtgettext.h" #include "ui_Preferences.h" +#include "settings.h" class Preferences : public QMainWindow, public Ui::Preferences { @@ -43,6 +45,30 @@ public slots: void on_launcherBox_toggled(bool); void on_editorType_editTextChanged(const QString &); + // + // editor settings + // + + // Indentation + void on_checkBoxAutoIndent_toggled(bool); + void on_comboBoxIndentUsing_activated(int); + void on_spinBoxIndentationWidth_valueChanged(int); + void on_spinBoxTabWidth_valueChanged(int); + void on_comboBoxTabKeyFunction_activated(int); + void on_comboBoxShowWhitespace_activated(int); + void on_spinBoxShowWhitespaceSize_valueChanged(int); + + // Line wrap + void on_comboBoxLineWrap_activated(int); + void on_comboBoxLineWrapIndentationStyle_activated(int); + void on_spinBoxLineWrapIndentationIndent_valueChanged(int); + void on_comboBoxLineWrapVisualizationStart_activated(int); + void on_comboBoxLineWrapVisualizationEnd_activated(int); + + // Display + void on_checkBoxHighlightCurrentLine_toggled(bool); + void on_checkBoxEnableBraceMatching_toggled(bool); + signals: void requestRedraw() const; void updateMdiMode(bool mdi) const; @@ -53,6 +79,7 @@ signals: void openCSGSettingsChanged() const; void syntaxHighlightChanged(const QString &s) const; void editorTypeChanged(const QString &type); + void editorConfigChanged() const; private: Preferences(QWidget *parent = NULL); @@ -60,8 +87,18 @@ private: void updateGUI(); void removeDefaultSettings(); void setupFeaturesPage(); + void fireEditorConfigChanged() const; void addPrefPage(QActionGroup *group, QAction *action, QWidget *widget); + /** Initialize combobox list values from the settings range values */ + void initComboBox(QComboBox *comboBox, const Settings::SettingsEntry& entry); + /** Initialize spinbox min/max values from the settings range values */ + void initSpinBox(QSpinBox *spinBox, const Settings::SettingsEntry& entry); + /** Update combobox from current settings */ + void updateComboBox(QComboBox *comboBox, const Settings::SettingsEntry& entry); + /** Set value from combobox to settings */ + void applyComboBox(QComboBox *comboBox, int val, Settings::SettingsEntry& entry); + QSettings::SettingsMap defaultmap; QHash prefPages; diff --git a/src/Preferences.ui b/src/Preferences.ui index eff8da96..7c411229 100644 --- a/src/Preferences.ui +++ b/src/Preferences.ui @@ -6,8 +6,8 @@ 0 0 - 852 - 554 + 621 + 413 @@ -23,11 +23,11 @@ true - + - 4 + 0 @@ -75,237 +75,897 @@ - - - - Qt::Vertical - - - - 20 - 645 - - - - + + 0 + + + 0 + - - - - - - 75 - true - - - - Editor Type - - - - - - - - Simple Editor - + + + true + + + + + 0 + 0 + 659 + 769 + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 30 + 20 + + + + + + + + Editor Type + + + + + + + + + + + + Simple Editor + + + + + QScintilla Editor + + + + + + + + + 10 + 50 + false + + + + (requires restart) + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 30 + 20 + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 30 + 20 + + + + + + + + Font + + + false + + + + + + + + + + + + Liberation Sans + 12 + + + + + + + + true + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 30 + 20 + + + + + + + + Color syntax highlighting + + + + + + + + + Qt::Horizontal + + + + 198 + 20 + + + + + + + + Ctrl/Cmd-Mouse-wheel zooms text + + + + + + + + + + 0 + 0 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 30 + 20 + + + + + + + - - - QScintilla Editor - + + + + Indentation + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 99 + + + 4 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + Qt::Horizontal + + + + 223 + 20 + + + + + + + + Auto Indent + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Indent using + + + + + + + + + + + + Spaces + + + + + Tabs + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Indentation width + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Tab width + + + + + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 4 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Tab key function + + + + + + + + + + + + Indent + + + + + Insert Tab + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Show whitespace + + + + + + + + + + + + Never + + + + + Always + + + + + Only after indentation + + + + + + + + Size + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + 1 + + + 9 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + - - - - - - - 10 - 50 - false - - - - (requires restart) - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 30 - 20 - - - - - - - - - - - - - 75 - true - - - - Font - - - false - - - - - - - - Nimbus Sans L - 12 - - - - - - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - 0 - - - - - - 75 - true - - - - Color syntax highlighting - - - - - - - - 0 - 0 - - - - - - - - Qt::Horizontal - - - QSizePolicy::Expanding - - - - 30 - 20 - - - - - - - - - - 5 - - - - - - 75 - true - - - - Use Ctrl/Cmd-Mouse-wheel to zoom text - - - - - - - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - Qt::Vertical - - - - 20 - 723 - - - + + + + Display + + + + + + Enable brace matching + + + + + + + Highlight current line + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Line wrap + + + + + + + + + None + + + + + Wrap at character boundaries + + + + + Wrap at word boundaries + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Line wrap indentation + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Line wrap visualization + + + + + + + + + + + Style + + + + + + + + Fixed + + + + + Same + + + + + Indented + + + + + + + + Indent + + + + + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Start + + + + + + + + 0 + 0 + + + + + None + + + + + Text + + + + + Border + + + + + Margin + + + + + + + + End + + + + + + + + 0 + 0 + + + + + None + + + + + Text + + + + + Border + + + + + Margin + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Line wrap + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + - + @@ -522,153 +1182,193 @@ + + 0 + - - - OpenCSG + + + QFrame::Plain - - - - - Show capability warning - - - true - - - - - - - Enable for OpenGL 1.x - - - - - - - - - Turn off rendering at - - - - - - - - - - elements - - - - - - - - - Force Goldfeather - - - - - - - - - - - - CGAL Cache size - - - - - - - - - - bytes - - - - - - - - - - - PolySet Cache size - - - - - - - - - - bytes - - - - - - - - - Allow to open multiple documents + + Qt::ScrollBarAlwaysOn - - - - - - Enable docking of Editor and Console in different places - - - - - - - Enable undocking of Editor and Console to separate windows - - - - - - - Show Welcome Screen - - - - - - - Enable user interface localization (requires restart of OpenSCAD) - - + true + + + + 0 + 0 + 596 + 499 + + + + + 9 + + + 9 + + + 9 + + + + + OpenCSG + + + + + + Show capability warning + + + true + + + + + + + Enable for OpenGL 1.x + + + + + + + + + Turn off rendering at + + + + + + + + + + elements + + + + + + + + + Force Goldfeather + + + + + + + + + + + + CGAL Cache size + + + + + + + + + + bytes + + + + + + + + + 0 + + + + + PolySet Cache size + + + + + + + + + + bytes + + + + + + + + + Allow to open multiple documents + + + + + + + Enable docking of Editor and Console in different places + + + + + + + Enable undocking of Editor and Console to separate windows + + + + + + + Show Welcome Screen + + + + + + + Enable user interface localization (requires restart of OpenSCAD) + + + true + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + - - - - Qt::Vertical - - - - 20 - 11 - - - - diff --git a/src/mainwin.cc b/src/mainwin.cc index cfb44bda..e4a01584 100644 --- a/src/mainwin.cc +++ b/src/mainwin.cc @@ -43,6 +43,7 @@ #include "progress.h" #include "dxfdim.h" #include "legacyeditor.h" +#include "settings.h" #ifdef USE_SCINTILLA_EDITOR #include "scintillaeditor.h" #endif @@ -192,6 +193,7 @@ MainWindow::MainWindow(const QString &filename) #ifdef USE_SCINTILLA_EDITOR if (useScintilla) { editor = new ScintillaEditor(editorDockContents); + } else #endif @@ -199,6 +201,13 @@ MainWindow::MainWindow(const QString &filename) Preferences::create(editor->colorSchemes()); +#ifdef USE_SCINTILLA_EDITOR + if (useScintilla) { + connect(Preferences::inst(), SIGNAL(editorConfigChanged()), editor, SLOT(applySettings())); + Preferences::inst()->editorConfigChanged(); + } +#endif + editorDockContents->layout()->addWidget(editor); setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea); diff --git a/src/scintillaeditor.cpp b/src/scintillaeditor.cpp index 2d0f07d0..a240d24c 100644 --- a/src/scintillaeditor.cpp +++ b/src/scintillaeditor.cpp @@ -6,489 +6,568 @@ #include #include "Preferences.h" #include "PlatformUtils.h" +#include "settings.h" + +class SettingsConverter { +public: + QsciScintilla::WrapMode toWrapMode(Value val); + QsciScintilla::WrapVisualFlag toLineWrapVisualization(Value val); + QsciScintilla::WrapIndentMode toLineWrapIndentationStyle(Value val); + QsciScintilla::WhitespaceVisibility toShowWhitespaces(Value val); +}; + +QsciScintilla::WrapMode SettingsConverter::toWrapMode(Value val) +{ + std::string v = val.toString(); + if (v == "Char") { + return QsciScintilla::WrapCharacter; + } else if (v == "Word") { + return QsciScintilla::WrapWord; + } else { + return QsciScintilla::WrapNone; + } +} + +QsciScintilla::WrapVisualFlag SettingsConverter::toLineWrapVisualization(Value val) +{ + std::string v = val.toString(); + if (v == "Text") { + return QsciScintilla::WrapFlagByText; + } else if (v == "Border") { + return QsciScintilla::WrapFlagByBorder; + } else if (v == "Margin") { + return QsciScintilla::WrapFlagInMargin; + } else { + return QsciScintilla::WrapFlagNone; + } +} + +QsciScintilla::WrapIndentMode SettingsConverter::toLineWrapIndentationStyle(Value val) +{ + std::string v = val.toString(); + if (v == "Same") { + return QsciScintilla::WrapIndentSame; + } else if (v == "Indented") { + return QsciScintilla::WrapIndentIndented; + } else { + return QsciScintilla::WrapIndentFixed; + } +} + +QsciScintilla::WhitespaceVisibility SettingsConverter::toShowWhitespaces(Value val) +{ + std::string v = val.toString(); + if (v == "Always") { + return QsciScintilla::WsVisible; + } else if (v == "AfterIndentation") { + return QsciScintilla::WsVisibleAfterIndent; + } else { + return QsciScintilla::WsInvisible; + } +} EditorColorScheme::EditorColorScheme(fs::path path) : path(path) { - try { - boost::property_tree::read_json(boosty::stringy(path).c_str(), pt); - _name = QString(pt.get("name").c_str()); - _index = pt.get("index"); - } catch (const std::exception & e) { - PRINTB("Error reading color scheme file '%s': %s", path.c_str() % e.what()); - _name = ""; - _index = 0; - } + try { + boost::property_tree::read_json(boosty::stringy(path).c_str(), pt); + _name = QString(pt.get("name").c_str()); + _index = pt.get("index"); + } catch (const std::exception & e) { + PRINTB("Error reading color scheme file '%s': %s", path.c_str() % e.what()); + _name = ""; + _index = 0; + } } EditorColorScheme::~EditorColorScheme() { - + } bool EditorColorScheme::valid() const { - return !_name.isEmpty(); + return !_name.isEmpty(); } const QString & EditorColorScheme::name() const { - return _name; + return _name; } int EditorColorScheme::index() const { - return _index; + return _index; } const boost::property_tree::ptree & EditorColorScheme::propertyTree() const { - return pt; + return pt; } ScintillaEditor::ScintillaEditor(QWidget *parent) : EditorInterface(parent) { - scintillaLayout = new QVBoxLayout(this); - qsci = new QsciScintilla(this); + scintillaLayout = new QVBoxLayout(this); + qsci = new QsciScintilla(this); - // Force EOL mode to Unix, since QTextStream will manage local EOL modes. - qsci->setEolMode(QsciScintilla::EolUnix); + // Force EOL mode to Unix, since QTextStream will manage local EOL modes. + qsci->setEolMode(QsciScintilla::EolUnix); - // - // Remapping some scintilla key binding which conflict with OpenSCAD global - // key bindings, as well as some minor scintilla bugs - // - QsciCommand *c; + // + // Remapping some scintilla key binding which conflict with OpenSCAD global + // key bindings, as well as some minor scintilla bugs + // + QsciCommand *c; #ifdef Q_OS_MAC - // Alt-Backspace should delete left word (Alt-Delete already deletes right word) - c= qsci->standardCommands()->find(QsciCommand::DeleteWordLeft); - c->setKey(Qt::Key_Backspace | Qt::ALT); + // Alt-Backspace should delete left word (Alt-Delete already deletes right word) + c = qsci->standardCommands()->find(QsciCommand::DeleteWordLeft); + c->setKey(Qt::Key_Backspace | Qt::ALT); #endif - // Cmd/Ctrl-T is handled by the menu - c = qsci->standardCommands()->boundTo(Qt::Key_T | Qt::CTRL); - c->setKey(0); - // Cmd/Ctrl-D is handled by the menu - c = qsci->standardCommands()->boundTo(Qt::Key_D | Qt::CTRL); - c->setKey(0); - // Ctrl-Shift-Z should redo on all platforms - c= qsci->standardCommands()->find(QsciCommand::Redo); - c->setKey(Qt::Key_Z | Qt::CTRL | Qt::SHIFT); + // Cmd/Ctrl-T is handled by the menu + c = qsci->standardCommands()->boundTo(Qt::Key_T | Qt::CTRL); + c->setKey(0); + // Cmd/Ctrl-D is handled by the menu + c = qsci->standardCommands()->boundTo(Qt::Key_D | Qt::CTRL); + c->setKey(0); + // Ctrl-Shift-Z should redo on all platforms + c = qsci->standardCommands()->find(QsciCommand::Redo); + c->setKey(Qt::Key_Z | Qt::CTRL | Qt::SHIFT); - scintillaLayout->setContentsMargins(0, 0, 0, 0); - scintillaLayout->addWidget(qsci); + scintillaLayout->setContentsMargins(0, 0, 0, 0); + scintillaLayout->addWidget(qsci); - qsci->setBraceMatching (QsciScintilla::SloppyBraceMatch); - qsci->setWrapMode(QsciScintilla::WrapCharacter); - qsci->setWrapVisualFlags(QsciScintilla::WrapFlagByBorder, QsciScintilla::WrapFlagNone, 0); - qsci->setAutoIndent(true); - qsci->indicatorDefine(QsciScintilla::RoundBoxIndicator, indicatorNumber); - qsci->markerDefine(QsciScintilla::Circle, markerNumber); - qsci->setUtf8(true); - qsci->setTabIndents(true); - qsci->setTabWidth(8); - qsci->setIndentationWidth(4); - qsci->setIndentationsUseTabs(false); - - lexer = new ScadLexer(this); - qsci->setLexer(lexer); - initMargin(); - qsci->setFolding(QsciScintilla::BoxedTreeFoldStyle, 4); - qsci->setCaretLineVisible(true); + qsci->indicatorDefine(QsciScintilla::RoundBoxIndicator, indicatorNumber); + qsci->markerDefine(QsciScintilla::Circle, markerNumber); + qsci->setUtf8(true); + qsci->setFolding(QsciScintilla::BoxedTreeFoldStyle, 4); - connect(qsci, SIGNAL(textChanged()), this, SIGNAL(contentsChanged())); - connect(qsci, SIGNAL(modificationChanged(bool)), this, SIGNAL(modificationChanged(bool))); + lexer = new ScadLexer(this); + qsci->setLexer(lexer); + initMargin(); + + connect(qsci, SIGNAL(textChanged()), this, SIGNAL(contentsChanged())); + connect(qsci, SIGNAL(modificationChanged(bool)), this, SIGNAL(modificationChanged(bool))); +} + +/** + * Apply the settings that are changeable in the preferences. This is also + * called in the event handler from the preferences. + */ +void ScintillaEditor::applySettings() +{ + SettingsConverter conv; + Settings::Settings *s = Settings::Settings::inst(); + + qsci->setIndentationWidth(s->get(Settings::Settings::indentationWidth).toDouble()); + qsci->setTabWidth(s->get(Settings::Settings::tabWidth).toDouble()); + qsci->setWrapMode(conv.toWrapMode(s->get(Settings::Settings::lineWrap))); + qsci->setWrapIndentMode(conv.toLineWrapIndentationStyle(s->get(Settings::Settings::lineWrapIndentationStyle))); + qsci->setWrapVisualFlags(conv.toLineWrapVisualization(s->get(Settings::Settings::lineWrapVisualizationEnd)), + conv.toLineWrapVisualization(s->get(Settings::Settings::lineWrapVisualizationBegin)), + s->get(Settings::Settings::lineWrapIndentation).toDouble()); + qsci->setWhitespaceVisibility(conv.toShowWhitespaces(s->get(Settings::Settings::showWhitespace))); + qsci->setWhitespaceSize(s->get(Settings::Settings::showWhitespaceSize).toDouble()); + qsci->setAutoIndent(s->get(Settings::Settings::autoIndent).toBool()); + + std::string indentStyle = s->get(Settings::Settings::indentStyle).toString(); + qsci->setIndentationsUseTabs(indentStyle == "Tabs"); + std::string tabKeyFunction = s->get(Settings::Settings::tabKeyFunction).toString(); + qsci->setTabIndents(tabKeyFunction == "Indent"); + + qsci->setBraceMatching(s->get(Settings::Settings::enableBraceMatching).toBool() ? QsciScintilla::SloppyBraceMatch : QsciScintilla::NoBraceMatch); + qsci->setCaretLineVisible(s->get(Settings::Settings::highlightCurrentLine).toBool()); } void ScintillaEditor::setPlainText(const QString &text) -{ - qsci->setText(text); - setContentModified(false); +{ + qsci->setText(text); + setContentModified(false); } QString ScintillaEditor::toPlainText() { - return qsci->text(); + return qsci->text(); } void ScintillaEditor::setContentModified(bool modified) { - // FIXME: Due to an issue with QScintilla, we need to do this on the document itself. + // FIXME: Due to an issue with QScintilla, we need to do this on the document itself. #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) - qsci->SCN_SAVEPOINTLEFT(); + qsci->SCN_SAVEPOINTLEFT(); #endif - qsci->setModified(modified); + qsci->setModified(modified); } bool ScintillaEditor::isContentModified() { - return qsci->isModified(); + return qsci->isModified(); } -void ScintillaEditor::highlightError(int error_pos) +void ScintillaEditor::highlightError(int error_pos) { - int line, index; - qsci->lineIndexFromPosition(error_pos, &line, &index); - qsci->fillIndicatorRange(line, index, line, index+1, indicatorNumber); - qsci->markerAdd(line, markerNumber); + int line, index; + qsci->lineIndexFromPosition(error_pos, &line, &index); + qsci->fillIndicatorRange(line, index, line, index + 1, indicatorNumber); + qsci->markerAdd(line, markerNumber); } -void ScintillaEditor::unhighlightLastError() +void ScintillaEditor::unhighlightLastError() { - int totalLength = qsci->text().length(); - int line, index; - qsci->lineIndexFromPosition(totalLength, &line, &index); - qsci->clearIndicatorRange(0, 0, line, index, indicatorNumber); - qsci->markerDeleteAll(markerNumber); + int totalLength = qsci->text().length(); + int line, index; + qsci->lineIndexFromPosition(totalLength, &line, &index); + qsci->clearIndicatorRange(0, 0, line, index, indicatorNumber); + qsci->markerDeleteAll(markerNumber); } QColor ScintillaEditor::readColor(const boost::property_tree::ptree &pt, const std::string name, const QColor defaultColor) { - try { - const std::string val = pt.get(name); - return QColor(val.c_str()); - } catch (std::exception e) { - return defaultColor; - } + try { + const std::string val = pt.get(name); + return QColor(val.c_str()); + } catch (std::exception e) { + return defaultColor; + } } std::string ScintillaEditor::readString(const boost::property_tree::ptree &pt, const std::string name, const std::string defaultValue) { - try { - const std::string val = pt.get(name); - return val; - } catch (std::exception e) { - return defaultValue; - } + try { + const std::string val = pt.get(name); + return val; + } catch (std::exception e) { + return defaultValue; + } } int ScintillaEditor::readInt(const boost::property_tree::ptree &pt, const std::string name, const int defaultValue) { - try { - const int val = pt.get(name); - return val; - } catch (std::exception e) { - return defaultValue; - } + try { + const int val = pt.get(name); + return val; + } catch (std::exception e) { + return defaultValue; + } } void ScintillaEditor::setColormap(const EditorColorScheme *colorScheme) { - const boost::property_tree::ptree & pt = colorScheme->propertyTree(); + const boost::property_tree::ptree & pt = colorScheme->propertyTree(); - try { - QFont font = lexer->font(lexer->defaultStyle()); - const QColor textColor(pt.get("text").c_str()); - const QColor paperColor(pt.get("paper").c_str()); + try { + QFont font = lexer->font(lexer->defaultStyle()); + const QColor textColor(pt.get("text").c_str()); + const QColor paperColor(pt.get("paper").c_str()); - ScadLexer *l = new ScadLexer(this); + ScadLexer *l = new ScadLexer(this); - // Keywords must be set before the lexer is attached to QScintilla - // as they seem to be read and cached at attach time. - boost::optional keywords = pt.get_child_optional("keywords"); - if (keywords.is_initialized()) { - l->setKeywords(1, readString(keywords.get(), "keyword-set1", "")); - l->setKeywords(2, readString(keywords.get(), "keyword-set2", "")); - l->setKeywords(3, readString(keywords.get(), "keyword-set-doc", "")); - l->setKeywords(4, readString(keywords.get(), "keyword-set3", "")); + // Keywords must be set before the lexer is attached to QScintilla + // as they seem to be read and cached at attach time. + boost::optional keywords = pt.get_child_optional("keywords"); + if (keywords.is_initialized()) { + l->setKeywords(1, readString(keywords.get(), "keyword-set1", "")); + l->setKeywords(2, readString(keywords.get(), "keyword-set2", "")); + l->setKeywords(3, readString(keywords.get(), "keyword-set-doc", "")); + l->setKeywords(4, readString(keywords.get(), "keyword-set3", "")); + } + + qsci->setLexer(l); + delete lexer; + lexer = l; + + // All other properties must be set after attaching to QSCintilla so + // the editor gets the change events and updates itself to match + l->setFont(font); + l->setColor(textColor); + l->setPaper(paperColor); + + const boost::property_tree::ptree& colors = pt.get_child("colors"); + l->setColor(readColor(colors, "keyword1", textColor), QsciLexerCPP::Keyword); + l->setColor(readColor(colors, "keyword2", textColor), QsciLexerCPP::KeywordSet2); + l->setColor(readColor(colors, "keyword3", textColor), QsciLexerCPP::GlobalClass); + l->setColor(readColor(colors, "number", textColor), QsciLexerCPP::Number); + l->setColor(readColor(colors, "string", textColor), QsciLexerCPP::SingleQuotedString); + l->setColor(readColor(colors, "string", textColor), QsciLexerCPP::DoubleQuotedString); + l->setColor(readColor(colors, "operator", textColor), QsciLexerCPP::Operator); + l->setColor(readColor(colors, "comment", textColor), QsciLexerCPP::Comment); + l->setColor(readColor(colors, "commentline", textColor), QsciLexerCPP::CommentLine); + l->setColor(readColor(colors, "commentdoc", textColor), QsciLexerCPP::CommentDoc); + l->setColor(readColor(colors, "commentdoc", textColor), QsciLexerCPP::CommentLineDoc); + l->setColor(readColor(colors, "commentdockeyword", textColor), QsciLexerCPP::CommentDocKeyword); + + const boost::property_tree::ptree& caret = pt.get_child("caret"); + qsci->setCaretWidth(readInt(caret, "width", 1)); + qsci->setCaretForegroundColor(readColor(caret, "foreground", textColor)); + qsci->setCaretLineBackgroundColor(readColor(caret, "line-background", paperColor)); + + qsci->setMarkerBackgroundColor(readColor(colors, "error-marker", QColor(255, 0, 0, 100)), markerNumber); + qsci->setIndicatorForegroundColor(readColor(colors, "error-indicator", QColor(255, 0, 0, 100)), indicatorNumber); + qsci->setIndicatorOutlineColor(readColor(colors, "error-indicator-outline", QColor(255, 0, 0, 100)), indicatorNumber); + qsci->setWhitespaceBackgroundColor(readColor(colors, "whitespace-background", paperColor)); + qsci->setWhitespaceForegroundColor(readColor(colors, "whitespace-foreground", textColor)); + qsci->setMarginsBackgroundColor(readColor(colors, "margin-background", paperColor)); + qsci->setMarginsForegroundColor(readColor(colors, "margin-foreground", textColor)); + qsci->setMatchedBraceBackgroundColor(readColor(colors, "matched-brace-background", paperColor)); + qsci->setMatchedBraceForegroundColor(readColor(colors, "matched-brace-foreground", textColor)); + qsci->setUnmatchedBraceBackgroundColor(readColor(colors, "unmatched-brace-background", paperColor)); + qsci->setUnmatchedBraceForegroundColor(readColor(colors, "unmatched-brace-foreground", textColor)); + qsci->setSelectionForegroundColor(readColor(colors, "selection-foreground", paperColor)); + qsci->setSelectionBackgroundColor(readColor(colors, "selection-background", textColor)); + qsci->setFoldMarginColors(readColor(colors, "margin-foreground", textColor), + readColor(colors, "margin-background", paperColor)); + qsci->setEdgeColor(readColor(colors, "edge", textColor)); + } catch (std::exception e) { + noColor(); } - - qsci->setLexer(l); - delete lexer; - lexer = l; - - // All other properties must be set after attaching to QSCintilla so - // the editor gets the change events and updates itself to match - l->setFont(font); - l->setColor(textColor); - l->setPaper(paperColor); - - const boost::property_tree::ptree& colors = pt.get_child("colors"); - l->setColor(readColor(colors, "keyword1", textColor), QsciLexerCPP::Keyword); - l->setColor(readColor(colors, "keyword2", textColor), QsciLexerCPP::KeywordSet2); - l->setColor(readColor(colors, "keyword3", textColor), QsciLexerCPP::GlobalClass); - l->setColor(readColor(colors, "number", textColor), QsciLexerCPP::Number); - l->setColor(readColor(colors, "string", textColor), QsciLexerCPP::SingleQuotedString); - l->setColor(readColor(colors, "string", textColor), QsciLexerCPP::DoubleQuotedString); - l->setColor(readColor(colors, "operator", textColor), QsciLexerCPP::Operator); - l->setColor(readColor(colors, "comment", textColor), QsciLexerCPP::Comment); - l->setColor(readColor(colors, "commentline", textColor), QsciLexerCPP::CommentLine); - l->setColor(readColor(colors, "commentdoc", textColor), QsciLexerCPP::CommentDoc); - l->setColor(readColor(colors, "commentdoc", textColor), QsciLexerCPP::CommentLineDoc); - l->setColor(readColor(colors, "commentdockeyword", textColor), QsciLexerCPP::CommentDocKeyword); - - const boost::property_tree::ptree& caret = pt.get_child("caret"); - qsci->setCaretWidth(readInt(caret, "width", 1)); - qsci->setCaretForegroundColor(readColor(caret, "foreground", textColor)); - qsci->setCaretLineBackgroundColor(readColor(caret, "line-background", paperColor)); - - qsci->setMarkerBackgroundColor(readColor(colors, "error-marker", QColor(255, 0, 0, 100)), markerNumber); - qsci->setIndicatorForegroundColor(readColor(colors, "error-indicator", QColor(255, 0, 0, 100)), indicatorNumber); - qsci->setIndicatorOutlineColor(readColor(colors, "error-indicator-outline", QColor(255, 0, 0, 100)), indicatorNumber); - qsci->setWhitespaceBackgroundColor(readColor(colors, "whitespace-background", paperColor)); - qsci->setWhitespaceForegroundColor(readColor(colors, "whitespace-foreground", textColor)); - qsci->setMarginsBackgroundColor(readColor(colors, "margin-background", paperColor)); - qsci->setMarginsForegroundColor(readColor(colors, "margin-foreground", textColor)); - qsci->setMatchedBraceBackgroundColor(readColor(colors, "matched-brace-background", paperColor)); - qsci->setMatchedBraceForegroundColor(readColor(colors, "matched-brace-foreground", textColor)); - qsci->setUnmatchedBraceBackgroundColor(readColor(colors, "unmatched-brace-background", paperColor)); - qsci->setUnmatchedBraceForegroundColor(readColor(colors, "unmatched-brace-foreground", textColor)); - qsci->setSelectionForegroundColor(readColor(colors, "selection-foreground", paperColor)); - qsci->setSelectionBackgroundColor(readColor(colors, "selection-background", textColor)); - qsci->setFoldMarginColors(readColor(colors, "margin-foreground", textColor), - readColor(colors, "margin-background", paperColor)); - qsci->setEdgeColor(readColor(colors, "edge", textColor)); - } catch (std::exception e) { - noColor(); - } } void ScintillaEditor::noColor() { - lexer->setPaper(Qt::white); - lexer->setColor(Qt::black); - qsci->setCaretWidth(2); - qsci->setCaretForegroundColor(Qt::black); - qsci->setMarkerBackgroundColor(QColor(255, 0, 0, 100), markerNumber); - qsci->setIndicatorForegroundColor(QColor(255, 0, 0, 128), indicatorNumber); - qsci->setIndicatorOutlineColor(QColor(0, 0, 0, 255), indicatorNumber); // only alpha part is used - qsci->setCaretLineBackgroundColor(Qt::white); - qsci->setWhitespaceBackgroundColor(Qt::white); - qsci->setWhitespaceForegroundColor(Qt::black); - qsci->setMarginsBackgroundColor(Qt::white); - qsci->setMarginsForegroundColor(Qt::black); - qsci->setSelectionForegroundColor(Qt::white); - qsci->setSelectionBackgroundColor(Qt::black); - qsci->setMatchedBraceBackgroundColor(Qt::white); - qsci->setMatchedBraceForegroundColor(Qt::black); - qsci->setUnmatchedBraceBackgroundColor(Qt::white); - qsci->setUnmatchedBraceForegroundColor(Qt::black); - qsci->setMarginsBackgroundColor(Qt::lightGray); - qsci->setMarginsForegroundColor(Qt::black); - qsci->setFoldMarginColors(Qt::black, Qt::lightGray); - qsci->setEdgeColor(Qt::black); + lexer->setPaper(Qt::white); + lexer->setColor(Qt::black); + qsci->setCaretWidth(2); + qsci->setCaretForegroundColor(Qt::black); + qsci->setMarkerBackgroundColor(QColor(255, 0, 0, 100), markerNumber); + qsci->setIndicatorForegroundColor(QColor(255, 0, 0, 128), indicatorNumber); + qsci->setIndicatorOutlineColor(QColor(0, 0, 0, 255), indicatorNumber); // only alpha part is used + qsci->setCaretLineBackgroundColor(Qt::white); + qsci->setWhitespaceBackgroundColor(Qt::white); + qsci->setWhitespaceForegroundColor(Qt::black); + qsci->setMarginsBackgroundColor(Qt::white); + qsci->setMarginsForegroundColor(Qt::black); + qsci->setSelectionForegroundColor(Qt::white); + qsci->setSelectionBackgroundColor(Qt::black); + qsci->setMatchedBraceBackgroundColor(Qt::white); + qsci->setMatchedBraceForegroundColor(Qt::black); + qsci->setUnmatchedBraceBackgroundColor(Qt::white); + qsci->setUnmatchedBraceForegroundColor(Qt::black); + qsci->setMarginsBackgroundColor(Qt::lightGray); + qsci->setMarginsForegroundColor(Qt::black); + qsci->setFoldMarginColors(Qt::black, Qt::lightGray); + qsci->setEdgeColor(Qt::black); } void ScintillaEditor::enumerateColorSchemesInPath(ScintillaEditor::colorscheme_set_t &result_set, const fs::path path) { - const fs::path color_schemes = path / "color-schemes" / "editor"; + const fs::path color_schemes = path / "color-schemes" / "editor"; - fs::directory_iterator end_iter; - - if (fs::exists(color_schemes) && fs::is_directory(color_schemes)) { - for (fs::directory_iterator dir_iter(color_schemes); dir_iter != end_iter; ++dir_iter) { - if (!fs::is_regular_file(dir_iter->status())) { - continue; - } - - const fs::path path = (*dir_iter).path(); - if (!(path.extension().string() == ".json")) { - continue; - } - - EditorColorScheme *colorScheme = new EditorColorScheme(path); - if (colorScheme->valid()) { - result_set.insert(colorscheme_set_t::value_type(colorScheme->index(), boost::shared_ptr(colorScheme))); - } else { - delete colorScheme; - } + fs::directory_iterator end_iter; + + if (fs::exists(color_schemes) && fs::is_directory(color_schemes)) { + for (fs::directory_iterator dir_iter(color_schemes); dir_iter != end_iter; ++dir_iter) { + if (!fs::is_regular_file(dir_iter->status())) { + continue; + } + + const fs::path path = (*dir_iter).path(); + if (!(path.extension().string() == ".json")) { + continue; + } + + EditorColorScheme *colorScheme = new EditorColorScheme(path); + if (colorScheme->valid()) { + result_set.insert(colorscheme_set_t::value_type(colorScheme->index(), boost::shared_ptr(colorScheme))); + } else { + delete colorScheme; + } + } } - } } ScintillaEditor::colorscheme_set_t ScintillaEditor::enumerateColorSchemes() { - colorscheme_set_t result_set; + colorscheme_set_t result_set; - enumerateColorSchemesInPath(result_set, PlatformUtils::resourceBasePath()); - enumerateColorSchemesInPath(result_set, PlatformUtils::userConfigPath()); - - return result_set; + enumerateColorSchemesInPath(result_set, PlatformUtils::resourceBasePath()); + enumerateColorSchemesInPath(result_set, PlatformUtils::userConfigPath()); + + return result_set; } QStringList ScintillaEditor::colorSchemes() { - const colorscheme_set_t colorscheme_set = enumerateColorSchemes(); + const colorscheme_set_t colorscheme_set = enumerateColorSchemes(); - QStringList colorSchemes; - for (colorscheme_set_t::const_iterator it = colorscheme_set.begin();it != colorscheme_set.end();it++) { - colorSchemes << (*it).second.get()->name(); - } - colorSchemes << "Off"; - - return colorSchemes; + QStringList colorSchemes; + for (colorscheme_set_t::const_iterator it = colorscheme_set.begin(); it != colorscheme_set.end(); it++) { + colorSchemes << (*it).second.get()->name(); + } + colorSchemes << "Off"; + + return colorSchemes; } void ScintillaEditor::setHighlightScheme(const QString &name) { - const colorscheme_set_t colorscheme_set = enumerateColorSchemes(); + const colorscheme_set_t colorscheme_set = enumerateColorSchemes(); - for (colorscheme_set_t::const_iterator it = colorscheme_set.begin();it != colorscheme_set.end();it++) { - const EditorColorScheme *colorScheme = (*it).second.get(); - if (colorScheme->name() == name) { - setColormap(colorScheme); - return; + for (colorscheme_set_t::const_iterator it = colorscheme_set.begin(); it != colorscheme_set.end(); it++) { + const EditorColorScheme *colorScheme = (*it).second.get(); + if (colorScheme->name() == name) { + setColormap(colorScheme); + return; + } } - } - - noColor(); + + noColor(); } void ScintillaEditor::insert(const QString &text) { - qsci->insert(text); + qsci->insert(text); } void ScintillaEditor::replaceAll(const QString &text) { - qsci->selectAll(true); - qsci->replaceSelectedText(text); + qsci->selectAll(true); + qsci->replaceSelectedText(text); } void ScintillaEditor::undo() { - qsci->undo(); + qsci->undo(); } void ScintillaEditor::redo() { - qsci->redo(); + qsci->redo(); } void ScintillaEditor::cut() { - qsci->cut(); + qsci->cut(); } void ScintillaEditor::copy() { - qsci->copy(); + qsci->copy(); } void ScintillaEditor::paste() -{ - qsci->paste(); +{ + qsci->paste(); } void ScintillaEditor::zoomIn() { - qsci->zoomIn(); + qsci->zoomIn(); } -void ScintillaEditor::zoomOut() +void ScintillaEditor::zoomOut() { - qsci->zoomOut(); + qsci->zoomOut(); } void ScintillaEditor::initFont(const QString& fontName, uint size) { - QFont font(fontName, size); - font.setFixedPitch(true); - lexer->setFont(font); + QFont font(fontName, size); + font.setFixedPitch(true); + lexer->setFont(font); } void ScintillaEditor::initMargin() { - QFontMetrics fontmetrics = QFontMetrics(qsci->font()); - qsci->setMarginsFont(qsci->font()); - qsci->setMarginWidth(1, fontmetrics.width(QString::number(qsci->lines())) + 6); - qsci->setMarginLineNumbers(1, true); - - connect(qsci, SIGNAL(textChanged()), this, SLOT(onTextChanged())); + QFontMetrics fontmetrics = QFontMetrics(qsci->font()); + qsci->setMarginsFont(qsci->font()); + qsci->setMarginWidth(1, fontmetrics.width(QString::number(qsci->lines())) + 6); + qsci->setMarginLineNumbers(1, true); + + connect(qsci, SIGNAL(textChanged()), this, SLOT(onTextChanged())); } void ScintillaEditor::onTextChanged() { - QFontMetrics fontmetrics = qsci->fontMetrics(); - qsci->setMarginWidth(1, fontmetrics.width(QString::number(qsci->lines())) + 6); + QFontMetrics fontmetrics = qsci->fontMetrics(); + qsci->setMarginWidth(1, fontmetrics.width(QString::number(qsci->lines())) + 6); } bool ScintillaEditor::find(const QString &expr, bool findNext, bool findBackwards) { - int startline = -1, startindex = -1; + int startline = -1, startindex = -1; - // If findNext, start from the end of the current selection - if (qsci->hasSelectedText()) { - int lineFrom, indexFrom, lineTo, indexTo; - qsci->getSelection(&lineFrom, &indexFrom, &lineTo, &indexTo); - - startline = !(findBackwards xor findNext) ? std::min(lineFrom, lineTo) : std::max(lineFrom, lineTo); - startindex = !(findBackwards xor findNext) ? std::min(indexFrom, indexTo) : std::max(indexFrom, indexTo); - } + // If findNext, start from the end of the current selection + if (qsci->hasSelectedText()) { + int lineFrom, indexFrom, lineTo, indexTo; + qsci->getSelection(&lineFrom, &indexFrom, &lineTo, &indexTo); - return qsci->findFirst(expr, false, false, false, true, - !findBackwards, startline, startindex); + startline = !(findBackwards xor findNext) ? std::min(lineFrom, lineTo) : std::max(lineFrom, lineTo); + startindex = !(findBackwards xor findNext) ? std::min(indexFrom, indexTo) : std::max(indexFrom, indexTo); + } + + return qsci->findFirst(expr, false, false, false, true, + !findBackwards, startline, startindex); } void ScintillaEditor::replaceSelectedText(const QString &newText) { - if (qsci->selectedText() != newText) qsci->replaceSelectedText(newText); + if (qsci->selectedText() != newText) qsci->replaceSelectedText(newText); } void ScintillaEditor::getRange(int *lineFrom, int *lineTo) { - int indexFrom, indexTo; - if (qsci->hasSelectedText()) { - qsci->getSelection(lineFrom, &indexFrom, lineTo, &indexTo); - if (indexTo == 0) { - *lineTo = *lineTo - 1; + int indexFrom, indexTo; + if (qsci->hasSelectedText()) { + qsci->getSelection(lineFrom, &indexFrom, lineTo, &indexTo); + if (indexTo == 0) { + *lineTo = *lineTo - 1; + } + } else { + qsci->getCursorPosition(lineFrom, &indexFrom); + *lineTo = *lineFrom; } - } else { - qsci->getCursorPosition(lineFrom, &indexFrom); - *lineTo = *lineFrom; - } } void ScintillaEditor::indentSelection() { - int lineFrom, lineTo; - getRange(&lineFrom, &lineTo); - for (int line = lineFrom;line <= lineTo;line++) { - qsci->indent(line); - } + int lineFrom, lineTo; + getRange(&lineFrom, &lineTo); + for (int line = lineFrom; line <= lineTo; line++) { + qsci->indent(line); + } } void ScintillaEditor::unindentSelection() { - int lineFrom, lineTo; - getRange(&lineFrom, &lineTo); - for (int line = lineFrom;line <= lineTo;line++) { - qsci->unindent(line); - } + int lineFrom, lineTo; + getRange(&lineFrom, &lineTo); + for (int line = lineFrom; line <= lineTo; line++) { + qsci->unindent(line); + } } void ScintillaEditor::commentSelection() { - bool hasSelection = qsci->hasSelectedText(); - - int lineFrom, lineTo; - getRange(&lineFrom, &lineTo); - for (int line = lineFrom;line <= lineTo;line++) { - qsci->insertAt("//", line, 0); - } - - if (hasSelection) { - qsci->setSelection(lineFrom, 0, lineTo, std::max(0, qsci->lineLength(lineTo) - 1)); - } + bool hasSelection = qsci->hasSelectedText(); + + int lineFrom, lineTo; + getRange(&lineFrom, &lineTo); + for (int line = lineFrom; line <= lineTo; line++) { + qsci->insertAt("//", line, 0); + } + + if (hasSelection) { + qsci->setSelection(lineFrom, 0, lineTo, std::max(0, qsci->lineLength(lineTo) - 1)); + } } void ScintillaEditor::uncommentSelection() { - bool hasSelection = qsci->hasSelectedText(); + bool hasSelection = qsci->hasSelectedText(); - int lineFrom, lineTo; - getRange(&lineFrom, &lineTo); - for (int line = lineFrom;line <= lineTo;line++) { - QString lineText = qsci->text(line); - if (lineText.startsWith("//")) { - qsci->setSelection(line, 0, line, 2); - qsci->removeSelectedText(); + int lineFrom, lineTo; + getRange(&lineFrom, &lineTo); + for (int line = lineFrom; line <= lineTo; line++) { + QString lineText = qsci->text(line); + if (lineText.startsWith("//")) { + qsci->setSelection(line, 0, line, 2); + qsci->removeSelectedText(); + } + } + if (hasSelection) { + qsci->setSelection(lineFrom, 0, lineTo, std::max(0, qsci->lineLength(lineTo) - 1)); } - } - if (hasSelection) { - qsci->setSelection(lineFrom, 0, lineTo, std::max(0, qsci->lineLength(lineTo) - 1)); - } } QString ScintillaEditor::selectedText() { - return qsci->selectedText(); + return qsci->selectedText(); } diff --git a/src/scintillaeditor.h b/src/scintillaeditor.h index 42fcd274..4a4cdaa0 100644 --- a/src/scintillaeditor.h +++ b/src/scintillaeditor.h @@ -87,6 +87,7 @@ public slots: private slots: void onTextChanged(); + void applySettings(); private: QVBoxLayout *scintillaLayout; diff --git a/src/settings.cc b/src/settings.cc new file mode 100644 index 00000000..8af5fea3 --- /dev/null +++ b/src/settings.cc @@ -0,0 +1,139 @@ +#include "settings.h" +#include "printutils.h" + +#include +using namespace boost::assign; // bring 'operator+=()' into scope + +namespace Settings { + +static std::list entries; + +SettingsEntry::SettingsEntry(const std::string category, const std::string name, const Value range, const Value def) + : _category(category), _name(name), _value(def), _range(range), _default(def) +{ + entries.push_back(this); +} + +SettingsEntry::~SettingsEntry() +{ +} + +const std::string & SettingsEntry::category() const +{ + return _category; +} + +const std::string & SettingsEntry::name() const +{ + return _name; +} + +const Value & SettingsEntry::defaultValue() const +{ + return _default; +} + +const Value & SettingsEntry::range() const +{ + return _range; +} + +bool SettingsEntry::is_default() const +{ + return _value == _default; +} + +static Value value(std::string s1, std::string s2) { + Value::VectorType v; + v += Value(s1), Value(s2); + return v; +} + +static Value values(std::string s1, std::string s1disp, std::string s2, std::string s2disp) { + Value::VectorType v; + v += value(s1, s1disp), value(s2, s2disp); + return v; +} + +static Value values(std::string s1, std::string s1disp, std::string s2, std::string s2disp, std::string s3, std::string s3disp) { + Value::VectorType v; + v += value(s1, s1disp), value(s2, s2disp), value(s3, s3disp); + return v; +} + +static Value values(std::string s1, std::string s1disp, std::string s2, std::string s2disp, std::string s3, std::string s3disp, std::string s4, std::string s4disp) { + Value::VectorType v; + v += value(s1, s1disp), value(s2, s2disp), value(s3, s3disp), value(s4, s4disp); + return v; +} + +Settings *Settings::inst(bool erase) +{ + static Settings *instance = new Settings; + + if (erase) { + delete instance; + instance = NULL; + } + + return instance; +} + +Settings::Settings() +{ +} + +Settings::~Settings() +{ +} + +void Settings::visit(Visitor& visitor) +{ + for (std::list::iterator it = entries.begin();it != entries.end();it++) { + visitor.handle(*(*it)); + } +} + +Value Settings::get(const SettingsEntry& entry) +{ + return entry._value; +} + +void Settings::set(SettingsEntry& entry, const Value val) +{ + entry._value = val; +} + +Visitor::Visitor() +{ +} + +Visitor::~Visitor() +{ +} + +/* + * Supported settings entry types are: bool / int and string selection + * + * String selection is used to handle comboboxes and has two values + * per config selection. The first value is used internally for both + * finding the combobox selection and for storing the value in the + * external settings file. The second value is the display value that + * can be translated. + */ +SettingsEntry Settings::indentationWidth("editor", "indentationWidth", Value(Value::RangeType(1, 16)), Value(4)); +SettingsEntry Settings::tabWidth("editor", "tabWidth", Value(Value::RangeType(1, 16)), Value(8)); +SettingsEntry Settings::lineWrap("editor", "lineWrap", values("None", _("None"), "Char", _("Wrap at character boundaries"), "Word", _("Wrap at word boundaries")), Value("Word")); +SettingsEntry Settings::lineWrapIndentationStyle("editor", "lineWrapIndentationStyle", values("Fixed", _("Fixed"), "Same", _("Same"), "Indented", _("Indented")), Value("Fixed")); +SettingsEntry Settings::lineWrapIndentation("editor", "lineWrapIndentation", Value(Value::RangeType(0, 999)), Value(4)); +SettingsEntry Settings::lineWrapVisualizationBegin("editor", "lineWrapVisualizationBegin", values("None", _("None"), "Text", _("Text"), "Border", _("Border"), "Margin", _("Margin")), Value("None")); +SettingsEntry Settings::lineWrapVisualizationEnd("editor", "lineWrapVisualizationEnd", values("None", _("None"), "Text", _("Text"), "Border", _("Border"), "Margin", _("Margin")), Value("Border")); +SettingsEntry Settings::showWhitespace("editor", "showWhitespaces", values("Never", _("Never"), "Always", _("Always"), "AfterIndentation", _("After indentation")), Value("Never")); +SettingsEntry Settings::showWhitespaceSize("editor", "showWhitespacesSize", Value(Value::RangeType(1, 16)), Value(2)); +SettingsEntry Settings::autoIndent("editor", "autoIndent", Value(true), Value(true)); +SettingsEntry Settings::indentStyle("editor", "indentStyle", values("Spaces", _("Spaces"), "Tabs", _("Tabs")), Value("Spaces")); +SettingsEntry Settings::tabKeyFunction("editor", "tabKeyFunction", values("Indent", _("Indent"), "InsertTab", _("Insert Tab")), Value("Indent")); +SettingsEntry Settings::highlightCurrentLine("editor", "highlightCurrentLine", Value(true), Value(true)); +SettingsEntry Settings::enableBraceMatching("editor", "enableBraceMatching", Value(true), Value(true)); + +} diff --git a/src/settings.h b/src/settings.h new file mode 100644 index 00000000..a3099fe8 --- /dev/null +++ b/src/settings.h @@ -0,0 +1,75 @@ +#pragma once + +#include +#include +#include + +#include "value.h" + +namespace Settings { + +class SettingsEntry +{ +private: + std::string _category; + std::string _name; + Value _value; + Value _range; + Value _default; + +public: + const std::string & category() const; + const std::string & name() const; + + virtual const Value & defaultValue() const; + virtual const Value & range() const; + virtual bool is_default() const; + +protected: + SettingsEntry(const std::string category, const std::string name, const Value range, const Value def); + virtual ~SettingsEntry(); + + friend class Settings; +}; + +class Settings +{ +public: + static SettingsEntry indentationWidth; + static SettingsEntry tabWidth; + static SettingsEntry lineWrap; + static SettingsEntry lineWrapIndentationStyle; + static SettingsEntry lineWrapIndentation; + static SettingsEntry lineWrapVisualizationBegin; + static SettingsEntry lineWrapVisualizationEnd; + static SettingsEntry showWhitespace; + static SettingsEntry showWhitespaceSize; + static SettingsEntry autoIndent; + static SettingsEntry indentStyle; + static SettingsEntry tabKeyFunction; + static SettingsEntry highlightCurrentLine; + static SettingsEntry enableBraceMatching; + + static Settings *inst(bool erase = false); + + void visit(class Visitor& visitor); + + Value defaultValue(const SettingsEntry& entry); + Value get(const SettingsEntry& entry); + void set(SettingsEntry& entry, const Value val); + +private: + Settings(); + virtual ~Settings(); +}; + +class Visitor +{ +public: + Visitor(); + virtual ~Visitor(); + + virtual void handle(SettingsEntry& entry) const = 0; +}; + +} \ No newline at end of file diff --git a/src/value.h b/src/value.h index 63b57ce6..f646681f 100644 --- a/src/value.h +++ b/src/value.h @@ -82,6 +82,10 @@ public: this->end_val == other.end_val; } + double begin_value() { return begin_val; } + double step_value() { return step_val; } + double end_value() { return end_val; } + iterator begin() { return iterator(*this, RANGE_TYPE_BEGIN); } iterator end() { return iterator(*this, RANGE_TYPE_END); }