Move ConfigDialog into src/dialogs/ subfolder

Mon, 31 Aug 2015 23:23:45 +0300

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Mon, 31 Aug 2015 23:23:45 +0300
changeset 975
24ba5aa3393f
parent 974
b2fa5f89798a
child 976
b7aac3606b65

Move ConfigDialog into src/dialogs/ subfolder

CMakeLists.txt file | annotate | diff | comparison | revisions
src/configDialog.cpp file | annotate | diff | comparison | revisions
src/configDialog.h file | annotate | diff | comparison | revisions
src/dialogs/configdialog.cpp file | annotate | diff | comparison | revisions
src/dialogs/configdialog.h file | annotate | diff | comparison | revisions
src/dialogs/configdialog.ui file | annotate | diff | comparison | revisions
src/mainwindow.cpp file | annotate | diff | comparison | revisions
src/toolsets/filetoolset.cpp file | annotate | diff | comparison | revisions
ui/config.ui file | annotate | diff | comparison | revisions
--- a/CMakeLists.txt	Mon Aug 31 23:18:17 2015 +0300
+++ b/CMakeLists.txt	Mon Aug 31 23:23:45 2015 +0300
@@ -35,7 +35,6 @@
 	src/addObjectDialog.cpp
 	src/basics.cpp
 	src/colors.cpp
-	src/configDialog.cpp
 	src/crashCatcher.cpp
 	src/dialogs.cpp
 	src/documentation.cpp
@@ -58,6 +57,7 @@
 	src/ringFinder.cpp
 	src/version.cpp
 	src/dialogs/colorselector.cpp
+	src/dialogs/configdialog.cpp
 	src/dialogs/ldrawpathdialog.cpp
 	src/dialogs/newpartdialog.cpp
 	src/dialogs/openprogressdialog.cpp
@@ -95,7 +95,6 @@
 	src/documentation.h
 	src/main.h
 	src/basics.h
-	src/configDialog.h
 	src/glRenderer.h
 	src/glCompiler.h
 	src/mainwindow.h
@@ -105,6 +104,7 @@
 	src/hierarchyelement.h
 	src/guiutilities.h
 	src/dialogs/colorselector.h
+	src/dialogs/configdialog.h
 	src/dialogs/ldrawpathdialog.h
 	src/dialogs/newpartdialog.h
 	src/dialogs/openprogressdialog.h
@@ -127,7 +127,6 @@
 set (LDFORGE_FORMS
 	ui/about.ui
 	ui/addhistoryline.ui
-	ui/config.ui
 	ui/coverer.ui
 	ui/downloadfrom.ui
 	ui/edger2.ui
@@ -144,6 +143,7 @@
 	ui/ytruder.ui
 	src/mainwindow.ui
 	src/dialogs/colorselector.ui
+	src/dialogs/configdialog.ui
 	src/dialogs/ldrawpathdialog.ui
 	src/dialogs/newpartdialog.ui
 	src/dialogs/openprogressdialog.ui
--- a/src/configDialog.cpp	Mon Aug 31 23:18:17 2015 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,703 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013 - 2015 Teemu Piippo
- *
- *  This program is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *  =====================================================================
- *
- *  configDialog.cxx: Settings dialog and everything related to it.
- *  Actual configuration core is in config.cxx.
- */
-
-#include <QGridLayout>
-#include <QFileDialog>
-#include <QColorDialog>
-#include <QBoxLayout>
-#include <QKeyEvent>
-#include <QGroupBox>
-#include <QDoubleSpinBox>
-#include <QLineEdit>
-#include <QCheckBox>
-#include <QSettings>
-#include "main.h"
-#include "configDialog.h"
-#include "ldDocument.h"
-#include "miscallenous.h"
-#include "colors.h"
-#include "dialogs/colorselector.h"
-#include "glRenderer.h"
-#include "ui_config.h"
-#include "guiutilities.h"
-
-const char* g_extProgPathFilter =
-#ifdef _WIN32
-	"Applications (*.exe)(*.exe);;"
-#endif
-	"All files (*.*)(*.*)";
-
-ConfigDialog::ConfigDialog (QWidget* parent, ConfigDialog::Tab defaulttab, Qt::WindowFlags f) :
-	QDialog (parent, f),
-	HierarchyElement (parent),
-	m_settings (m_window->makeSettings (this))
-{
-	ui = new Ui_ConfigUI;
-	ui->setupUi (this);
-
-	// Set defaults
-	applyToWidgetOptions (
-	[&](QWidget* widget, QString confname)
-	{
-		QVariant value = m_settings->value (confname, m_config->defaultValueByName (confname));
-		QLineEdit* le;
-		QSpinBox* spinbox;
-		QDoubleSpinBox* doublespinbox;
-		QSlider* slider;
-		QCheckBox* checkbox;
-		QPushButton* button;
-
-		if ((le = qobject_cast<QLineEdit*> (widget)) != null)
-		{
-			le->setText (value.toString());
-		}
-		else if ((spinbox = qobject_cast<QSpinBox*> (widget)) != null)
-		{
-			spinbox->setValue (value.toInt());
-		}
-		else if ((doublespinbox = qobject_cast<QDoubleSpinBox*> (widget)) != null)
-		{
-			doublespinbox->setValue (value.toDouble());
-		}
-		else if ((slider = qobject_cast<QSlider*> (widget)) != null)
-		{
-			slider->setValue (value.toInt());
-		}
-		else if ((checkbox = qobject_cast<QCheckBox*> (widget)) != null)
-		{
-			checkbox->setChecked (value.toBool());
-		}
-		else if ((button = qobject_cast<QPushButton*> (widget)) != null)
-		{
-			setButtonBackground (button, value.toString());
-			connect (button, SIGNAL (clicked()), this, SLOT (setButtonColor()));
-		}
-		else
-		{
-			print ("Unknown widget of type %1\n", widget->metaObject()->className());
-		}
-	});
-
-	m_window->applyToActions ([&](QAction* act)
-	{
-		addShortcut (act);
-	});
-
-	ui->shortcutsList->setSortingEnabled (true);
-	ui->shortcutsList->sortItems();
-	quickColors = LoadQuickColorList();
-	updateQuickColorList();
-	initExtProgs();
-	selectPage (defaulttab);
-	connect (ui->shortcut_set, SIGNAL (clicked()), this, SLOT (slot_setShortcut()));
-	connect (ui->shortcut_reset, SIGNAL (clicked()), this, SLOT (slot_resetShortcut()));
-	connect (ui->shortcut_clear, SIGNAL (clicked()), this, SLOT (slot_clearShortcut()));
-	connect (ui->quickColor_add, SIGNAL (clicked()), this, SLOT (slot_setColor()));
-	connect (ui->quickColor_remove, SIGNAL (clicked()), this, SLOT (slot_delColor()));
-	connect (ui->quickColor_edit, SIGNAL (clicked()), this, SLOT (slot_setColor()));
-	connect (ui->quickColor_addSep, SIGNAL (clicked()), this, SLOT (slot_addColorSeparator()));
-	connect (ui->quickColor_moveUp, SIGNAL (clicked()), this, SLOT (slot_moveColor()));
-	connect (ui->quickColor_moveDown, SIGNAL (clicked()), this, SLOT (slot_moveColor()));
-	connect (ui->quickColor_clear, SIGNAL (clicked()), this, SLOT (slot_clearColors()));
-	connect (ui->findDownloadPath, SIGNAL (clicked (bool)), this, SLOT (slot_findDownloadFolder()));
-	connect (ui->buttonBox, SIGNAL (clicked (QAbstractButton*)),
-		this, SLOT (buttonClicked (QAbstractButton*)));
-	connect (ui->m_pages, SIGNAL (currentChanged (int)), this, SLOT (selectPage (int)));
-	connect (ui->m_pagelist, SIGNAL (currentRowChanged (int)), this, SLOT (selectPage (int)));
-}
-
-ConfigDialog::~ConfigDialog()
-{
-	delete ui;
-}
-
-void ConfigDialog::selectPage (int row)
-{
-	ui->m_pagelist->setCurrentRow (row);
-	ui->m_pages->setCurrentIndex (row);
-}
-
-//
-// Adds a shortcut entry to the list of shortcuts.
-//
-void ConfigDialog::addShortcut (QAction* act)
-{
-	ShortcutListItem* item = new ShortcutListItem;
-	item->setIcon (act->icon());
-	item->setAction (act);
-	item->setSequence (act->shortcut());
-	setShortcutText (item);
-
-	// If the action doesn't have a valid icon, use an empty one
-	// so that the list is kept aligned.
-	if (act->icon().isNull())
-		item->setIcon (GetIcon ("empty"));
-
-	ui->shortcutsList->insertItem (ui->shortcutsList->count(), item);
-}
-
-//
-// Initializes the stuff in the ext programs tab
-//
-void ConfigDialog::initExtProgs()
-{
-	QGridLayout* pathsLayout = new QGridLayout;
-	int row = 0;
-
-	for (int i = 0; i < NumExternalPrograms; ++i)
-	{
-		ExtProgramType program = (ExtProgramType) i;
-		ExternalProgramWidgets& widgets = m_externalProgramWidgets[i];
-		QString name = m_window->externalPrograms()->externalProgramName (program);
-		QLabel* icon = new QLabel;
-		QLabel* progLabel = new QLabel (name);
-		QLineEdit* input = new QLineEdit;
-		QPushButton* setPathButton = new QPushButton;
-
-		icon->setPixmap (GetIcon (name.toLower()));
-		input->setText (m_window->externalPrograms()->getPathSetting (program));
-		setPathButton->setIcon (GetIcon ("folder"));
-		widgets.input = input;
-		widgets.setPathButton = setPathButton;
-		widgets.wineBox = nullptr;
-		connect (setPathButton, SIGNAL (clicked()), this, SLOT (slot_setExtProgPath()));
-		pathsLayout->addWidget (icon, row, 0);
-		pathsLayout->addWidget (progLabel, row, 1);
-		pathsLayout->addWidget (input, row, 2);
-		pathsLayout->addWidget (setPathButton, row, 3);
-
-#ifdef Q_OS_UNIX
-		{
-			QCheckBox* wineBox = new QCheckBox ("Wine");
-			wineBox->setChecked (m_window->externalPrograms()->programUsesWine (program));
-			widgets.wineBox = wineBox;
-			pathsLayout->addWidget (wineBox, row, 4);
-		}
-#endif
-		++row;
-	}
-	ui->extProgs->setLayout (pathsLayout);
-}
-
-void ConfigDialog::applyToWidgetOptions (std::function<void (QWidget*, QString)> func)
-{
-	// Apply configuration
-	for (QWidget* widget : findChildren<QWidget*>())
-	{
-		if (not widget->objectName().startsWith ("config"))
-			continue;
-
-		QString optionname (widget->objectName().mid (strlen ("config")));
-
-		if (m_config->existsEntry (optionname))
-			func (widget, optionname);
-		else
-			print ("Couldn't find configuration entry named %1", optionname);
-	}
-}
-
-//
-// Set the settings based on widget data.
-//
-void ConfigDialog::applySettings()
-{
-	applyToWidgetOptions ([&](QWidget* widget, QString confname)
-	{
-		QVariant value;
-		QLineEdit* le;
-		QSpinBox* spinbox;
-		QDoubleSpinBox* doublespinbox;
-		QSlider* slider;
-		QCheckBox* checkbox;
-		QPushButton* button;
-
-		if ((le = qobject_cast<QLineEdit*> (widget)) != null)
-			value = le->text();
-		else if ((spinbox = qobject_cast<QSpinBox*> (widget)) != null)
-			value = spinbox->value();
-		else if ((doublespinbox = qobject_cast<QDoubleSpinBox*> (widget)) != null)
-			value = doublespinbox->value();
-		else if ((slider = qobject_cast<QSlider*> (widget)) != null)
-			value = slider->value();
-		else if ((checkbox = qobject_cast<QCheckBox*> (widget)) != null)
-			value = checkbox->isChecked();
-		else if ((button = qobject_cast<QPushButton*> (widget)) != null)
-			value = m_buttonColors[button];
-		else
-		{
-			print ("Unknown widget of type %1\n", widget->metaObject()->className());
-			return;
-		}
-
-		m_settings->setValue (confname, value);
-	});
-
-	// Rebuild the quick color toolbar
-	m_window->setQuickColors (quickColors);
-	m_config->setQuickColorToolbar (quickColorString());
-
-	// Ext program settings
-	for (int i = 0; i < NumExternalPrograms; ++i)
-	{
-		ExtProgramType program = (ExtProgramType) i;
-		ExtProgramToolset* toolset = m_window->externalPrograms();
-		ExternalProgramWidgets& widgets = m_externalProgramWidgets[i];
-		toolset->getPathSetting (program) = widgets.input->text();
-
-		if (widgets.wineBox)
-			toolset->setWineSetting (program, widgets.wineBox->isChecked());
-	}
-
-	// Apply shortcuts
-	for (int i = 0; i < ui->shortcutsList->count(); ++i)
-	{
-		auto item = static_cast<ShortcutListItem*> (ui->shortcutsList->item (i));
-		item->action()->setShortcut (item->sequence());
-	}
-
-	m_window->syncSettings();
-	LDDocument::current()->reloadAllSubfiles();
-	LoadLogoStuds();
-
-	m_window->R()->setBackground();
-	m_window->doFullRefresh();
-	m_window->updateDocumentList();
-}
-
-//
-// A dialog button was clicked
-//
-void ConfigDialog::buttonClicked (QAbstractButton* button)
-{
-	QDialogButtonBox* dbb = ui->buttonBox;
-
-	if (button == dbb->button (QDialogButtonBox::Ok))
-	{
-		applySettings();
-		accept();
-	}
-	else if (button == dbb->button (QDialogButtonBox::Apply))
-	{
-		applySettings();
-	}
-	else if (button == dbb->button (QDialogButtonBox::Cancel))
-	{
-		reject();
-	}
-}
-
-//
-// Update the list of color toolbar items in the quick color tab.
-//
-void ConfigDialog::updateQuickColorList (LDQuickColor* sel)
-{
-	for (QListWidgetItem * item : quickColorItems)
-		delete item;
-
-	quickColorItems.clear();
-
-	// Init table items
-	for (LDQuickColor& entry : quickColors)
-	{
-		QListWidgetItem* item = new QListWidgetItem;
-
-		if (entry.isSeparator())
-		{
-			item->setText ("<hr />");
-			item->setIcon (GetIcon ("empty"));
-		}
-		else
-		{
-			LDColor color = entry.color();
-
-			if (color.isValid())
-			{
-				item->setText (color.name());
-				item->setIcon (guiUtilities()->makeColorIcon (color, 16));
-			}
-			else
-			{
-				item->setText ("[[unknown color]]");
-				item->setIcon (GetIcon ("error"));
-			}
-		}
-
-		ui->quickColorList->addItem (item);
-		quickColorItems << item;
-
-		if (sel and &entry == sel)
-		{
-			ui->quickColorList->setCurrentItem (item);
-			ui->quickColorList->scrollToItem (item);
-		}
-	}
-}
-
-//
-// Quick colors: add or edit button was clicked.
-//
-void ConfigDialog::slot_setColor()
-{
-	LDQuickColor* entry = null;
-	QListWidgetItem* item = null;
-	const bool isNew = static_cast<QPushButton*> (sender()) == ui->quickColor_add;
-
-	if (not isNew)
-	{
-		item = getSelectedQuickColor();
-
-		if (not item)
-			return;
-
-		int i = getItemRow (item, quickColorItems);
-		entry = &quickColors[i];
-
-		if (entry->isSeparator() == true)
-			return; // don't color separators
-	}
-
-	LDColor defaultValue = entry ? entry->color() : LDColor::nullColor();
-	LDColor value;
-
-	if (not ColorSelector::selectColor (this, value, defaultValue))
-		return;
-
-	if (entry != null)
-	{
-		entry->setColor (value);
-	}
-	else
-	{
-		LDQuickColor newentry (value, null);
-		item = getSelectedQuickColor();
-		int idx = (item) ? getItemRow (item, quickColorItems) + 1 : quickColorItems.size();
-		quickColors.insert (idx, newentry);
-		entry = &quickColors[idx];
-	}
-
-	updateQuickColorList (entry);
-}
-
-//
-// Remove a quick color
-//
-void ConfigDialog::slot_delColor()
-{
-	if (ui->quickColorList->selectedItems().isEmpty())
-		return;
-
-	QListWidgetItem* item = ui->quickColorList->selectedItems() [0];
-	quickColors.removeAt (getItemRow (item, quickColorItems));
-	updateQuickColorList();
-}
-
-//
-// Move a quick color up/down
-//
-void ConfigDialog::slot_moveColor()
-{
-	const bool up = (static_cast<QPushButton*> (sender()) == ui->quickColor_moveUp);
-
-	if (ui->quickColorList->selectedItems().isEmpty())
-		return;
-
-	QListWidgetItem* item = ui->quickColorList->selectedItems() [0];
-	int idx = getItemRow (item, quickColorItems);
-	int dest = up ? (idx - 1) : (idx + 1);
-
-	if (dest < 0 or dest >= quickColorItems.size())
-		return; // destination out of bounds
-
-	qSwap (quickColors[dest], quickColors[idx]);
-	updateQuickColorList (&quickColors[dest]);
-}
-
-//
-//
-// Add a separator to quick colors
-//
-void ConfigDialog::slot_addColorSeparator()
-{
-	quickColors << LDQuickColor::getSeparator();
-	updateQuickColorList (&quickColors[quickColors.size() - 1]);
-}
-
-//
-//
-// Clear all quick colors
-//
-void ConfigDialog::slot_clearColors()
-{
-	quickColors.clear();
-	updateQuickColorList();
-}
-
-//
-//
-void ConfigDialog::setButtonColor()
-{
-	QPushButton* button = qobject_cast<QPushButton*> (sender());
-
-	if (button == null)
-	{
-		print ("setButtonColor: null sender!\n");
-		return;
-	}
-
-	QColor color = QColorDialog::getColor (m_buttonColors[button]);
-
-	if (color.isValid())
-	{
-		QString colorname;
-		colorname.sprintf ("#%.2X%.2X%.2X", color.red(), color.green(), color.blue());
-		setButtonBackground (button, colorname);
-	}
-}
-
-//
-// Sets background color of a given button.
-//
-void ConfigDialog::setButtonBackground (QPushButton* button, QString value)
-{
-	button->setIcon (GetIcon ("colorselect"));
-	button->setAutoFillBackground (true);
-	button->setStyleSheet (format ("background-color: %1", value));
-	m_buttonColors[button] = QColor (value);
-}
-
-//
-// Finds the given list widget item in the list of widget items given.
-//
-int ConfigDialog::getItemRow (QListWidgetItem* item, QList<QListWidgetItem*>& haystack)
-{
-	int i = 0;
-
-	for (QListWidgetItem* it : haystack)
-	{
-		if (it == item)
-			return i;
-
-		++i;
-	}
-
-	return -1;
-}
-
-//
-// Which quick color is currently selected?
-//
-QListWidgetItem* ConfigDialog::getSelectedQuickColor()
-{
-	if (ui->quickColorList->selectedItems().isEmpty())
-		return null;
-
-	return ui->quickColorList->selectedItems() [0];
-}
-
-//
-// Get the list of shortcuts selected
-//
-QList<ShortcutListItem*> ConfigDialog::getShortcutSelection()
-{
-	QList<ShortcutListItem*> out;
-
-	for (QListWidgetItem* entry : ui->shortcutsList->selectedItems())
-		out << static_cast<ShortcutListItem*> (entry);
-
-	return out;
-}
-
-//
-// Edit the shortcut of a given action.
-//
-void ConfigDialog::slot_setShortcut()
-{
-	QList<ShortcutListItem*> sel = getShortcutSelection();
-
-	if (sel.size() < 1)
-		return;
-
-	ShortcutListItem* item = sel[0];
-
-	if (KeySequenceDialog::staticDialog (item, this))
-		setShortcutText (item);
-}
-
-//
-// Reset a shortcut to defaults
-//
-void ConfigDialog::slot_resetShortcut()
-{
-	QList<ShortcutListItem*> sel = getShortcutSelection();
-
-	for (ShortcutListItem* item : sel)
-	{
-		item->setSequence (MainWindow::defaultShortcut (item->action()));
-		setShortcutText (item);
-	}
-}
-
-//
-// Remove the shortcut of an action.
-//
-void ConfigDialog::slot_clearShortcut()
-{
-	QList<ShortcutListItem*> sel = getShortcutSelection();
-
-	for (ShortcutListItem* item : sel)
-	{
-		item->setSequence (QKeySequence());
-		setShortcutText (item);
-	}
-}
-
-//
-// Set the path of an external program
-//
-void ConfigDialog::slot_setExtProgPath()
-{
-	ExtProgramType program = NumExternalPrograms;
-
-	for (int i = 0; i < NumExternalPrograms; ++i)
-	{
-		if (m_externalProgramWidgets[i].setPathButton == sender())
-		{
-			program = (ExtProgramType) i;
-			break;
-		}
-	}
-
-	if (program != NumExternalPrograms)
-	{
-		ExtProgramToolset* toolset = m_window->externalPrograms();
-		ExternalProgramWidgets& widgets = m_externalProgramWidgets[program];
-		QString filepath = QFileDialog::getOpenFileName (this,
-			format ("Path to %1", toolset->externalProgramName (program)),
-			widgets.input->text(), g_extProgPathFilter);
-	
-		if (filepath.isEmpty())
-			return;
-	
-		widgets.input->setText (filepath);
-	}
-}
-
-//
-// '...' button pressed for the download path
-//
-void ConfigDialog::slot_findDownloadFolder()
-{
-	QString dpath = QFileDialog::getExistingDirectory();
-
-	if (not dpath.isEmpty())
-		ui->configDownloadFilePath->setText (dpath);
-}
-
-//
-//
-// Updates the text string for a given shortcut list item
-//
-void ConfigDialog::setShortcutText (ShortcutListItem* item)
-{
-	QAction* act = item->action();
-	QString label = act->iconText();
-	QString keybind = item->sequence().toString();
-	item->setText (format ("%1 (%2)", label, keybind));
-}
-
-//
-// Gets the configuration string of the quick color toolbar
-//
-QString ConfigDialog::quickColorString()
-{
-	QString val;
-
-	for (const LDQuickColor& entry : quickColors)
-	{
-		if (val.length() > 0)
-			val += ':';
-
-		if (entry.isSeparator())
-			val += '|';
-		else
-			val += format ("%1", entry.color().index());
-	}
-
-	return val;
-}
-
-//
-//
-KeySequenceDialog::KeySequenceDialog (QKeySequence seq, QWidget* parent, Qt::WindowFlags f) :
-	QDialog (parent, f), seq (seq)
-{
-	lb_output = new QLabel;
-
-	bbx_buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel); \
-	connect (bbx_buttons, SIGNAL (accepted()), this, SLOT (accept())); \
-	connect (bbx_buttons, SIGNAL (rejected()), this, SLOT (reject())); \
-
-	setWhatsThis (tr ("Into this dialog you can input a key sequence for use as a "
-		"shortcut in LDForge. Use OK to confirm the new shortcut and Cancel to "
-		"dismiss."));
-
-	QVBoxLayout* layout = new QVBoxLayout;
-	layout->addWidget (lb_output);
-	layout->addWidget (bbx_buttons);
-	setLayout (layout);
-
-	updateOutput();
-}
-
-//
-//
-bool KeySequenceDialog::staticDialog (ShortcutListItem* item, QWidget* parent)
-{
-	KeySequenceDialog dlg (item->sequence(), parent);
-
-	if (dlg.exec() == QDialog::Rejected)
-		return false;
-
-	item->setSequence (dlg.seq);
-	return true;
-}
-
-//
-//
-void KeySequenceDialog::updateOutput()
-{
-	QString shortcut = seq.toString();
-
-	if (seq == QKeySequence())
-		shortcut = "&lt;empty&gt;";
-
-	QString text = format ("<center><b>%1</b></center>", shortcut);
-	lb_output->setText (text);
-}
-
-//
-//
-void KeySequenceDialog::keyPressEvent (QKeyEvent* ev)
-{
-	seq = ev->key() + ev->modifiers();
-	updateOutput();
-}
--- a/src/configDialog.h	Mon Aug 31 23:18:17 2015 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,123 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013 - 2015 Teemu Piippo
- *
- *  This program is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-#include "mainwindow.h"
-#include "toolsets/extprogramtoolset.h"
-#include <QDialog>
-
-class Ui_ConfigUI;
-class QLabel;
-class QDoubleSpinBox;
-
-// =============================================================================
-class ShortcutListItem : public QListWidgetItem
-{
-	PROPERTY (public,	QAction*,		action,		setAction,		STOCK_WRITE)
-	PROPERTY (public,	QKeySequence,	sequence,	setSequence,	STOCK_WRITE)
-
-public:
-	explicit ShortcutListItem (QListWidget* view = null, int type = Type) :
-		QListWidgetItem (view, type) {}
-};
-
-struct ExternalProgramWidgets
-{
-	class QLineEdit* input;
-	class QPushButton* setPathButton;
-	class QCheckBox* wineBox;
-};
-
-// =============================================================================
-class ConfigDialog : public QDialog, public HierarchyElement
-{
-	Q_OBJECT
-
-public:
-	enum Tab
-	{
-		InterfaceTab,
-		EditingToolsTab,
-		ProfileTab,
-		ShortcutsTab,
-		QuickColorsTab,
-		GridsTab,
-		ExtProgsTab,
-		DownloadTab
-	};
-
-	explicit ConfigDialog (QWidget* parent = nullptr, Tab defaulttab = (Tab) 0, Qt::WindowFlags f = 0);
-	virtual ~ConfigDialog();
-
-	QList<LDQuickColor> quickColors;
-
-private:
-	Ui_ConfigUI* ui;
-	QList<QListWidgetItem*> quickColorItems;
-	QMap<QPushButton*, QColor> m_buttonColors;
-	ExternalProgramWidgets m_externalProgramWidgets[NumExternalPrograms];
-	QSettings* m_settings;
-
-	void applySettings();
-	void addShortcut (QAction* act);
-	void setButtonBackground (QPushButton* button, QString value);
-	void updateQuickColorList (LDQuickColor* sel = null);
-	void setShortcutText (ShortcutListItem* item);
-	int getItemRow (QListWidgetItem* item, QList<QListWidgetItem*>& haystack);
-	QString quickColorString();
-	QListWidgetItem* getSelectedQuickColor();
-	QList<ShortcutListItem*> getShortcutSelection();
-	void initExtProgs();
-	void applyToWidgetOptions (std::function<void (QWidget*, QString)> func);
-
-private slots:
-	void setButtonColor();
-	void slot_setShortcut();
-	void slot_resetShortcut();
-	void slot_clearShortcut();
-	void slot_setColor();
-	void slot_delColor();
-	void slot_addColorSeparator();
-	void slot_moveColor();
-	void slot_clearColors();
-	void slot_setExtProgPath();
-	void slot_findDownloadFolder();
-	void buttonClicked (QAbstractButton* button);
-	void selectPage (int row);
-};
-
-// =============================================================================
-//
-class KeySequenceDialog : public QDialog
-{
-	Q_OBJECT
-
-public:
-	explicit KeySequenceDialog (QKeySequence seq, QWidget* parent = null, Qt::WindowFlags f = 0);
-	static bool staticDialog (ShortcutListItem* item, QWidget* parent = null);
-
-	QLabel* lb_output;
-	QDialogButtonBox* bbx_buttons;
-	QKeySequence seq;
-
-private:
-	void updateOutput();
-
-private slots:
-	virtual void keyPressEvent (QKeyEvent* ev) override;
-};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dialogs/configdialog.cpp	Mon Aug 31 23:23:45 2015 +0300
@@ -0,0 +1,703 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013 - 2015 Teemu Piippo
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *  =====================================================================
+ *
+ *  configDialog.cxx: Settings dialog and everything related to it.
+ *  Actual configuration core is in config.cxx.
+ */
+
+#include <QGridLayout>
+#include <QFileDialog>
+#include <QColorDialog>
+#include <QBoxLayout>
+#include <QKeyEvent>
+#include <QGroupBox>
+#include <QDoubleSpinBox>
+#include <QLineEdit>
+#include <QCheckBox>
+#include <QSettings>
+#include <QPushButton>
+#include "../main.h"
+#include "../ldDocument.h"
+#include "../miscallenous.h"
+#include "../glRenderer.h"
+#include "../guiutilities.h"
+#include "colorselector.h"
+#include "configdialog.h"
+#include "ui_configdialog.h"
+
+const char* g_extProgPathFilter =
+#ifdef _WIN32
+	"Applications (*.exe)(*.exe);;"
+#endif
+	"All files (*.*)(*.*)";
+
+ConfigDialog::ConfigDialog (QWidget* parent, ConfigDialog::Tab defaulttab, Qt::WindowFlags f) :
+	QDialog (parent, f),
+	HierarchyElement (parent),
+	m_settings (m_window->makeSettings (this))
+{
+	ui = new Ui_ConfigDialog;
+	ui->setupUi (this);
+
+	// Set defaults
+	applyToWidgetOptions (
+	[&](QWidget* widget, QString confname)
+	{
+		QVariant value = m_settings->value (confname, m_config->defaultValueByName (confname));
+		QLineEdit* le;
+		QSpinBox* spinbox;
+		QDoubleSpinBox* doublespinbox;
+		QSlider* slider;
+		QCheckBox* checkbox;
+		QPushButton* button;
+
+		if ((le = qobject_cast<QLineEdit*> (widget)) != null)
+		{
+			le->setText (value.toString());
+		}
+		else if ((spinbox = qobject_cast<QSpinBox*> (widget)) != null)
+		{
+			spinbox->setValue (value.toInt());
+		}
+		else if ((doublespinbox = qobject_cast<QDoubleSpinBox*> (widget)) != null)
+		{
+			doublespinbox->setValue (value.toDouble());
+		}
+		else if ((slider = qobject_cast<QSlider*> (widget)) != null)
+		{
+			slider->setValue (value.toInt());
+		}
+		else if ((checkbox = qobject_cast<QCheckBox*> (widget)) != null)
+		{
+			checkbox->setChecked (value.toBool());
+		}
+		else if ((button = qobject_cast<QPushButton*> (widget)) != null)
+		{
+			setButtonBackground (button, value.toString());
+			connect (button, SIGNAL (clicked()), this, SLOT (setButtonColor()));
+		}
+		else
+		{
+			print ("Unknown widget of type %1\n", widget->metaObject()->className());
+		}
+	});
+
+	m_window->applyToActions ([&](QAction* act)
+	{
+		addShortcut (act);
+	});
+
+	ui->shortcutsList->setSortingEnabled (true);
+	ui->shortcutsList->sortItems();
+	quickColors = LoadQuickColorList();
+	updateQuickColorList();
+	initExtProgs();
+	selectPage (defaulttab);
+	connect (ui->shortcut_set, SIGNAL (clicked()), this, SLOT (slot_setShortcut()));
+	connect (ui->shortcut_reset, SIGNAL (clicked()), this, SLOT (slot_resetShortcut()));
+	connect (ui->shortcut_clear, SIGNAL (clicked()), this, SLOT (slot_clearShortcut()));
+	connect (ui->quickColor_add, SIGNAL (clicked()), this, SLOT (slot_setColor()));
+	connect (ui->quickColor_remove, SIGNAL (clicked()), this, SLOT (slot_delColor()));
+	connect (ui->quickColor_edit, SIGNAL (clicked()), this, SLOT (slot_setColor()));
+	connect (ui->quickColor_addSep, SIGNAL (clicked()), this, SLOT (slot_addColorSeparator()));
+	connect (ui->quickColor_moveUp, SIGNAL (clicked()), this, SLOT (slot_moveColor()));
+	connect (ui->quickColor_moveDown, SIGNAL (clicked()), this, SLOT (slot_moveColor()));
+	connect (ui->quickColor_clear, SIGNAL (clicked()), this, SLOT (slot_clearColors()));
+	connect (ui->findDownloadPath, SIGNAL (clicked (bool)), this, SLOT (slot_findDownloadFolder()));
+	connect (ui->buttonBox, SIGNAL (clicked (QAbstractButton*)),
+		this, SLOT (buttonClicked (QAbstractButton*)));
+	connect (ui->m_pages, SIGNAL (currentChanged (int)), this, SLOT (selectPage (int)));
+	connect (ui->m_pagelist, SIGNAL (currentRowChanged (int)), this, SLOT (selectPage (int)));
+}
+
+ConfigDialog::~ConfigDialog()
+{
+	delete ui;
+}
+
+void ConfigDialog::selectPage (int row)
+{
+	ui->m_pagelist->setCurrentRow (row);
+	ui->m_pages->setCurrentIndex (row);
+}
+
+//
+// Adds a shortcut entry to the list of shortcuts.
+//
+void ConfigDialog::addShortcut (QAction* act)
+{
+	ShortcutListItem* item = new ShortcutListItem;
+	item->setIcon (act->icon());
+	item->setAction (act);
+	item->setSequence (act->shortcut());
+	setShortcutText (item);
+
+	// If the action doesn't have a valid icon, use an empty one
+	// so that the list is kept aligned.
+	if (act->icon().isNull())
+		item->setIcon (GetIcon ("empty"));
+
+	ui->shortcutsList->insertItem (ui->shortcutsList->count(), item);
+}
+
+//
+// Initializes the stuff in the ext programs tab
+//
+void ConfigDialog::initExtProgs()
+{
+	QGridLayout* pathsLayout = new QGridLayout;
+	int row = 0;
+
+	for (int i = 0; i < NumExternalPrograms; ++i)
+	{
+		ExtProgramType program = (ExtProgramType) i;
+		ExternalProgramWidgets& widgets = m_externalProgramWidgets[i];
+		QString name = m_window->externalPrograms()->externalProgramName (program);
+		QLabel* icon = new QLabel;
+		QLabel* progLabel = new QLabel (name);
+		QLineEdit* input = new QLineEdit;
+		QPushButton* setPathButton = new QPushButton;
+
+		icon->setPixmap (GetIcon (name.toLower()));
+		input->setText (m_window->externalPrograms()->getPathSetting (program));
+		setPathButton->setIcon (GetIcon ("folder"));
+		widgets.input = input;
+		widgets.setPathButton = setPathButton;
+		widgets.wineBox = nullptr;
+		connect (setPathButton, SIGNAL (clicked()), this, SLOT (slot_setExtProgPath()));
+		pathsLayout->addWidget (icon, row, 0);
+		pathsLayout->addWidget (progLabel, row, 1);
+		pathsLayout->addWidget (input, row, 2);
+		pathsLayout->addWidget (setPathButton, row, 3);
+
+#ifdef Q_OS_UNIX
+		{
+			QCheckBox* wineBox = new QCheckBox ("Wine");
+			wineBox->setChecked (m_window->externalPrograms()->programUsesWine (program));
+			widgets.wineBox = wineBox;
+			pathsLayout->addWidget (wineBox, row, 4);
+		}
+#endif
+		++row;
+	}
+	ui->extProgs->setLayout (pathsLayout);
+}
+
+void ConfigDialog::applyToWidgetOptions (std::function<void (QWidget*, QString)> func)
+{
+	// Apply configuration
+	for (QWidget* widget : findChildren<QWidget*>())
+	{
+		if (not widget->objectName().startsWith ("config"))
+			continue;
+
+		QString optionname (widget->objectName().mid (strlen ("config")));
+
+		if (m_config->existsEntry (optionname))
+			func (widget, optionname);
+		else
+			print ("Couldn't find configuration entry named %1", optionname);
+	}
+}
+
+//
+// Set the settings based on widget data.
+//
+void ConfigDialog::applySettings()
+{
+	applyToWidgetOptions ([&](QWidget* widget, QString confname)
+	{
+		QVariant value;
+		QLineEdit* le;
+		QSpinBox* spinbox;
+		QDoubleSpinBox* doublespinbox;
+		QSlider* slider;
+		QCheckBox* checkbox;
+		QPushButton* button;
+
+		if ((le = qobject_cast<QLineEdit*> (widget)) != null)
+			value = le->text();
+		else if ((spinbox = qobject_cast<QSpinBox*> (widget)) != null)
+			value = spinbox->value();
+		else if ((doublespinbox = qobject_cast<QDoubleSpinBox*> (widget)) != null)
+			value = doublespinbox->value();
+		else if ((slider = qobject_cast<QSlider*> (widget)) != null)
+			value = slider->value();
+		else if ((checkbox = qobject_cast<QCheckBox*> (widget)) != null)
+			value = checkbox->isChecked();
+		else if ((button = qobject_cast<QPushButton*> (widget)) != null)
+			value = m_buttonColors[button];
+		else
+		{
+			print ("Unknown widget of type %1\n", widget->metaObject()->className());
+			return;
+		}
+
+		m_settings->setValue (confname, value);
+	});
+
+	// Rebuild the quick color toolbar
+	m_window->setQuickColors (quickColors);
+	m_config->setQuickColorToolbar (quickColorString());
+
+	// Ext program settings
+	for (int i = 0; i < NumExternalPrograms; ++i)
+	{
+		ExtProgramType program = (ExtProgramType) i;
+		ExtProgramToolset* toolset = m_window->externalPrograms();
+		ExternalProgramWidgets& widgets = m_externalProgramWidgets[i];
+		toolset->getPathSetting (program) = widgets.input->text();
+
+		if (widgets.wineBox)
+			toolset->setWineSetting (program, widgets.wineBox->isChecked());
+	}
+
+	// Apply shortcuts
+	for (int i = 0; i < ui->shortcutsList->count(); ++i)
+	{
+		auto item = static_cast<ShortcutListItem*> (ui->shortcutsList->item (i));
+		item->action()->setShortcut (item->sequence());
+	}
+
+	m_window->syncSettings();
+	LDDocument::current()->reloadAllSubfiles();
+	LoadLogoStuds();
+
+	m_window->R()->setBackground();
+	m_window->doFullRefresh();
+	m_window->updateDocumentList();
+}
+
+//
+// A dialog button was clicked
+//
+void ConfigDialog::buttonClicked (QAbstractButton* button)
+{
+	QDialogButtonBox* dbb = ui->buttonBox;
+
+	if (button == dbb->button (QDialogButtonBox::Ok))
+	{
+		applySettings();
+		accept();
+	}
+	else if (button == dbb->button (QDialogButtonBox::Apply))
+	{
+		applySettings();
+	}
+	else if (button == dbb->button (QDialogButtonBox::Cancel))
+	{
+		reject();
+	}
+}
+
+//
+// Update the list of color toolbar items in the quick color tab.
+//
+void ConfigDialog::updateQuickColorList (LDQuickColor* sel)
+{
+	for (QListWidgetItem * item : quickColorItems)
+		delete item;
+
+	quickColorItems.clear();
+
+	// Init table items
+	for (LDQuickColor& entry : quickColors)
+	{
+		QListWidgetItem* item = new QListWidgetItem;
+
+		if (entry.isSeparator())
+		{
+			item->setText ("<hr />");
+			item->setIcon (GetIcon ("empty"));
+		}
+		else
+		{
+			LDColor color = entry.color();
+
+			if (color.isValid())
+			{
+				item->setText (color.name());
+				item->setIcon (guiUtilities()->makeColorIcon (color, 16));
+			}
+			else
+			{
+				item->setText ("[[unknown color]]");
+				item->setIcon (GetIcon ("error"));
+			}
+		}
+
+		ui->quickColorList->addItem (item);
+		quickColorItems << item;
+
+		if (sel and &entry == sel)
+		{
+			ui->quickColorList->setCurrentItem (item);
+			ui->quickColorList->scrollToItem (item);
+		}
+	}
+}
+
+//
+// Quick colors: add or edit button was clicked.
+//
+void ConfigDialog::slot_setColor()
+{
+	LDQuickColor* entry = null;
+	QListWidgetItem* item = null;
+	const bool isNew = static_cast<QPushButton*> (sender()) == ui->quickColor_add;
+
+	if (not isNew)
+	{
+		item = getSelectedQuickColor();
+
+		if (not item)
+			return;
+
+		int i = getItemRow (item, quickColorItems);
+		entry = &quickColors[i];
+
+		if (entry->isSeparator() == true)
+			return; // don't color separators
+	}
+
+	LDColor defaultValue = entry ? entry->color() : LDColor::nullColor();
+	LDColor value;
+
+	if (not ColorSelector::selectColor (this, value, defaultValue))
+		return;
+
+	if (entry != null)
+	{
+		entry->setColor (value);
+	}
+	else
+	{
+		LDQuickColor newentry (value, null);
+		item = getSelectedQuickColor();
+		int idx = (item) ? getItemRow (item, quickColorItems) + 1 : quickColorItems.size();
+		quickColors.insert (idx, newentry);
+		entry = &quickColors[idx];
+	}
+
+	updateQuickColorList (entry);
+}
+
+//
+// Remove a quick color
+//
+void ConfigDialog::slot_delColor()
+{
+	if (ui->quickColorList->selectedItems().isEmpty())
+		return;
+
+	QListWidgetItem* item = ui->quickColorList->selectedItems() [0];
+	quickColors.removeAt (getItemRow (item, quickColorItems));
+	updateQuickColorList();
+}
+
+//
+// Move a quick color up/down
+//
+void ConfigDialog::slot_moveColor()
+{
+	const bool up = (static_cast<QPushButton*> (sender()) == ui->quickColor_moveUp);
+
+	if (ui->quickColorList->selectedItems().isEmpty())
+		return;
+
+	QListWidgetItem* item = ui->quickColorList->selectedItems() [0];
+	int idx = getItemRow (item, quickColorItems);
+	int dest = up ? (idx - 1) : (idx + 1);
+
+	if (dest < 0 or dest >= quickColorItems.size())
+		return; // destination out of bounds
+
+	qSwap (quickColors[dest], quickColors[idx]);
+	updateQuickColorList (&quickColors[dest]);
+}
+
+//
+//
+// Add a separator to quick colors
+//
+void ConfigDialog::slot_addColorSeparator()
+{
+	quickColors << LDQuickColor::getSeparator();
+	updateQuickColorList (&quickColors[quickColors.size() - 1]);
+}
+
+//
+//
+// Clear all quick colors
+//
+void ConfigDialog::slot_clearColors()
+{
+	quickColors.clear();
+	updateQuickColorList();
+}
+
+//
+//
+void ConfigDialog::setButtonColor()
+{
+	QPushButton* button = qobject_cast<QPushButton*> (sender());
+
+	if (button == null)
+	{
+		print ("setButtonColor: null sender!\n");
+		return;
+	}
+
+	QColor color = QColorDialog::getColor (m_buttonColors[button]);
+
+	if (color.isValid())
+	{
+		QString colorname;
+		colorname.sprintf ("#%.2X%.2X%.2X", color.red(), color.green(), color.blue());
+		setButtonBackground (button, colorname);
+	}
+}
+
+//
+// Sets background color of a given button.
+//
+void ConfigDialog::setButtonBackground (QPushButton* button, QString value)
+{
+	button->setIcon (GetIcon ("colorselect"));
+	button->setAutoFillBackground (true);
+	button->setStyleSheet (format ("background-color: %1", value));
+	m_buttonColors[button] = QColor (value);
+}
+
+//
+// Finds the given list widget item in the list of widget items given.
+//
+int ConfigDialog::getItemRow (QListWidgetItem* item, QList<QListWidgetItem*>& haystack)
+{
+	int i = 0;
+
+	for (QListWidgetItem* it : haystack)
+	{
+		if (it == item)
+			return i;
+
+		++i;
+	}
+
+	return -1;
+}
+
+//
+// Which quick color is currently selected?
+//
+QListWidgetItem* ConfigDialog::getSelectedQuickColor()
+{
+	if (ui->quickColorList->selectedItems().isEmpty())
+		return null;
+
+	return ui->quickColorList->selectedItems() [0];
+}
+
+//
+// Get the list of shortcuts selected
+//
+QList<ShortcutListItem*> ConfigDialog::getShortcutSelection()
+{
+	QList<ShortcutListItem*> out;
+
+	for (QListWidgetItem* entry : ui->shortcutsList->selectedItems())
+		out << static_cast<ShortcutListItem*> (entry);
+
+	return out;
+}
+
+//
+// Edit the shortcut of a given action.
+//
+void ConfigDialog::slot_setShortcut()
+{
+	QList<ShortcutListItem*> sel = getShortcutSelection();
+
+	if (sel.size() < 1)
+		return;
+
+	ShortcutListItem* item = sel[0];
+
+	if (KeySequenceDialog::staticDialog (item, this))
+		setShortcutText (item);
+}
+
+//
+// Reset a shortcut to defaults
+//
+void ConfigDialog::slot_resetShortcut()
+{
+	QList<ShortcutListItem*> sel = getShortcutSelection();
+
+	for (ShortcutListItem* item : sel)
+	{
+		item->setSequence (MainWindow::defaultShortcut (item->action()));
+		setShortcutText (item);
+	}
+}
+
+//
+// Remove the shortcut of an action.
+//
+void ConfigDialog::slot_clearShortcut()
+{
+	QList<ShortcutListItem*> sel = getShortcutSelection();
+
+	for (ShortcutListItem* item : sel)
+	{
+		item->setSequence (QKeySequence());
+		setShortcutText (item);
+	}
+}
+
+//
+// Set the path of an external program
+//
+void ConfigDialog::slot_setExtProgPath()
+{
+	ExtProgramType program = NumExternalPrograms;
+
+	for (int i = 0; i < NumExternalPrograms; ++i)
+	{
+		if (m_externalProgramWidgets[i].setPathButton == sender())
+		{
+			program = (ExtProgramType) i;
+			break;
+		}
+	}
+
+	if (program != NumExternalPrograms)
+	{
+		ExtProgramToolset* toolset = m_window->externalPrograms();
+		ExternalProgramWidgets& widgets = m_externalProgramWidgets[program];
+		QString filepath = QFileDialog::getOpenFileName (this,
+			format ("Path to %1", toolset->externalProgramName (program)),
+			widgets.input->text(), g_extProgPathFilter);
+	
+		if (filepath.isEmpty())
+			return;
+	
+		widgets.input->setText (filepath);
+	}
+}
+
+//
+// '...' button pressed for the download path
+//
+void ConfigDialog::slot_findDownloadFolder()
+{
+	QString dpath = QFileDialog::getExistingDirectory();
+
+	if (not dpath.isEmpty())
+		ui->configDownloadFilePath->setText (dpath);
+}
+
+//
+//
+// Updates the text string for a given shortcut list item
+//
+void ConfigDialog::setShortcutText (ShortcutListItem* item)
+{
+	QAction* act = item->action();
+	QString label = act->iconText();
+	QString keybind = item->sequence().toString();
+	item->setText (format ("%1 (%2)", label, keybind));
+}
+
+//
+// Gets the configuration string of the quick color toolbar
+//
+QString ConfigDialog::quickColorString()
+{
+	QString val;
+
+	for (const LDQuickColor& entry : quickColors)
+	{
+		if (val.length() > 0)
+			val += ':';
+
+		if (entry.isSeparator())
+			val += '|';
+		else
+			val += format ("%1", entry.color().index());
+	}
+
+	return val;
+}
+
+//
+//
+KeySequenceDialog::KeySequenceDialog (QKeySequence seq, QWidget* parent, Qt::WindowFlags f) :
+	QDialog (parent, f), seq (seq)
+{
+	lb_output = new QLabel;
+
+	bbx_buttons = new QDialogButtonBox (QDialogButtonBox::Ok | QDialogButtonBox::Cancel); \
+	connect (bbx_buttons, SIGNAL (accepted()), this, SLOT (accept())); \
+	connect (bbx_buttons, SIGNAL (rejected()), this, SLOT (reject())); \
+
+	setWhatsThis (tr ("Into this dialog you can input a key sequence for use as a "
+		"shortcut in LDForge. Use OK to confirm the new shortcut and Cancel to "
+		"dismiss."));
+
+	QVBoxLayout* layout = new QVBoxLayout;
+	layout->addWidget (lb_output);
+	layout->addWidget (bbx_buttons);
+	setLayout (layout);
+
+	updateOutput();
+}
+
+//
+//
+bool KeySequenceDialog::staticDialog (ShortcutListItem* item, QWidget* parent)
+{
+	KeySequenceDialog dlg (item->sequence(), parent);
+
+	if (dlg.exec() == QDialog::Rejected)
+		return false;
+
+	item->setSequence (dlg.seq);
+	return true;
+}
+
+//
+//
+void KeySequenceDialog::updateOutput()
+{
+	QString shortcut = seq.toString();
+
+	if (seq == QKeySequence())
+		shortcut = "&lt;empty&gt;";
+
+	QString text = format ("<center><b>%1</b></center>", shortcut);
+	lb_output->setText (text);
+}
+
+//
+//
+void KeySequenceDialog::keyPressEvent (QKeyEvent* ev)
+{
+	seq = ev->key() + ev->modifiers();
+	updateOutput();
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dialogs/configdialog.h	Mon Aug 31 23:23:45 2015 +0300
@@ -0,0 +1,122 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013 - 2015 Teemu Piippo
+ *
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+#include "../mainwindow.h"
+#include "../toolsets/extprogramtoolset.h"
+#include <QDialog>
+
+class QLabel;
+class QDoubleSpinBox;
+
+// =============================================================================
+class ShortcutListItem : public QListWidgetItem
+{
+	PROPERTY (public,	QAction*,		action,		setAction,		STOCK_WRITE)
+	PROPERTY (public,	QKeySequence,	sequence,	setSequence,	STOCK_WRITE)
+
+public:
+	explicit ShortcutListItem (QListWidget* view = null, int type = Type) :
+		QListWidgetItem (view, type) {}
+};
+
+struct ExternalProgramWidgets
+{
+	class QLineEdit* input;
+	class QPushButton* setPathButton;
+	class QCheckBox* wineBox;
+};
+
+// =============================================================================
+class ConfigDialog : public QDialog, public HierarchyElement
+{
+	Q_OBJECT
+
+public:
+	enum Tab
+	{
+		InterfaceTab,
+		EditingToolsTab,
+		ProfileTab,
+		ShortcutsTab,
+		QuickColorsTab,
+		GridsTab,
+		ExtProgsTab,
+		DownloadTab
+	};
+
+	explicit ConfigDialog (QWidget* parent = nullptr, Tab defaulttab = (Tab) 0, Qt::WindowFlags f = 0);
+	virtual ~ConfigDialog();
+
+	QList<LDQuickColor> quickColors;
+
+private:
+	class Ui_ConfigDialog* ui;
+	QList<QListWidgetItem*> quickColorItems;
+	QMap<QPushButton*, QColor> m_buttonColors;
+	ExternalProgramWidgets m_externalProgramWidgets[NumExternalPrograms];
+	QSettings* m_settings;
+
+	void applySettings();
+	void addShortcut (QAction* act);
+	void setButtonBackground (QPushButton* button, QString value);
+	void updateQuickColorList (LDQuickColor* sel = null);
+	void setShortcutText (ShortcutListItem* item);
+	int getItemRow (QListWidgetItem* item, QList<QListWidgetItem*>& haystack);
+	QString quickColorString();
+	QListWidgetItem* getSelectedQuickColor();
+	QList<ShortcutListItem*> getShortcutSelection();
+	void initExtProgs();
+	void applyToWidgetOptions (std::function<void (QWidget*, QString)> func);
+
+private slots:
+	void setButtonColor();
+	void slot_setShortcut();
+	void slot_resetShortcut();
+	void slot_clearShortcut();
+	void slot_setColor();
+	void slot_delColor();
+	void slot_addColorSeparator();
+	void slot_moveColor();
+	void slot_clearColors();
+	void slot_setExtProgPath();
+	void slot_findDownloadFolder();
+	void buttonClicked (QAbstractButton* button);
+	void selectPage (int row);
+};
+
+// =============================================================================
+//
+class KeySequenceDialog : public QDialog
+{
+	Q_OBJECT
+
+public:
+	explicit KeySequenceDialog (QKeySequence seq, QWidget* parent = null, Qt::WindowFlags f = 0);
+	static bool staticDialog (ShortcutListItem* item, QWidget* parent = null);
+
+	QLabel* lb_output;
+	QDialogButtonBox* bbx_buttons;
+	QKeySequence seq;
+
+private:
+	void updateOutput();
+
+private slots:
+	virtual void keyPressEvent (QKeyEvent* ev) override;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/dialogs/configdialog.ui	Mon Aug 31 23:23:45 2015 +0300
@@ -0,0 +1,1070 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ConfigDialog</class>
+ <widget class="QDialog" name="ConfigDialog">
+  <property name="geometry">
+   <rect>
+    <x>0</x>
+    <y>0</y>
+    <width>668</width>
+    <height>408</height>
+   </rect>
+  </property>
+  <property name="windowTitle">
+   <string>Settings</string>
+  </property>
+  <property name="windowIcon">
+   <iconset resource="../../ldforge.qrc">
+    <normaloff>:/icons/settings.png</normaloff>:/icons/settings.png</iconset>
+  </property>
+  <layout class="QVBoxLayout" name="verticalLayout">
+   <item>
+    <layout class="QHBoxLayout" name="horizontalLayout_7" stretch="0,0">
+     <item>
+      <widget class="QListWidget" name="m_pagelist">
+       <property name="minimumSize">
+        <size>
+         <width>144</width>
+         <height>0</height>
+        </size>
+       </property>
+       <property name="maximumSize">
+        <size>
+         <width>144</width>
+         <height>16777215</height>
+        </size>
+       </property>
+       <item>
+        <property name="text">
+         <string>Interface</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>Editing tools</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>Profile</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>Shortcuts</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>Color Toolbar</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>Grids</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>External Programs</string>
+        </property>
+       </item>
+       <item>
+        <property name="text">
+         <string>Downloads</string>
+        </property>
+       </item>
+      </widget>
+     </item>
+     <item>
+      <widget class="QStackedWidget" name="m_pages">
+       <property name="currentIndex">
+        <number>0</number>
+       </property>
+       <widget class="QWidget" name="page_3">
+        <layout class="QVBoxLayout" name="verticalLayout_13">
+         <item>
+          <widget class="QGroupBox" name="groupBox">
+           <property name="title">
+            <string>Interface</string>
+           </property>
+           <layout class="QVBoxLayout" name="verticalLayout_10">
+            <item>
+             <layout class="QVBoxLayout" name="verticalLayout_3">
+              <item>
+               <layout class="QHBoxLayout" name="horizontalLayout">
+                <item>
+                 <spacer name="horizontalSpacer_2">
+                  <property name="orientation">
+                   <enum>Qt::Horizontal</enum>
+                  </property>
+                  <property name="sizeHint" stdset="0">
+                   <size>
+                    <width>40</width>
+                    <height>20</height>
+                   </size>
+                  </property>
+                 </spacer>
+                </item>
+                <item>
+                 <layout class="QFormLayout" name="formLayout">
+                  <item row="0" column="0">
+                   <widget class="QLabel" name="label_2">
+                    <property name="whatsThis">
+                     <string/>
+                    </property>
+                    <property name="text">
+                     <string>Background color</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="0" column="1">
+                   <widget class="QPushButton" name="configBackgroundColor">
+                    <property name="whatsThis">
+                     <string>This is the background color for the viewport.</string>
+                    </property>
+                    <property name="text">
+                     <string/>
+                    </property>
+                    <property name="icon">
+                     <iconset resource="../../ldforge.qrc">
+                      <normaloff>:/icons/colorselect.png</normaloff>:/icons/colorselect.png</iconset>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="1" column="0">
+                   <widget class="QLabel" name="label">
+                    <property name="whatsThis">
+                     <string/>
+                    </property>
+                    <property name="text">
+                     <string>Main color</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="1" column="1">
+                   <widget class="QPushButton" name="configMainColor">
+                    <property name="whatsThis">
+                     <string>This color is used for the main color.</string>
+                    </property>
+                    <property name="text">
+                     <string/>
+                    </property>
+                    <property name="icon">
+                     <iconset resource="../../ldforge.qrc">
+                      <normaloff>:/icons/colorselect.png</normaloff>:/icons/colorselect.png</iconset>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="2" column="0">
+                   <widget class="QLabel" name="selectedColorLabel">
+                    <property name="text">
+                     <string>Selected color</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="2" column="1">
+                   <widget class="QPushButton" name="configSelectColorBlend">
+                    <property name="whatsThis">
+                     <string>This color is used for the main color.</string>
+                    </property>
+                    <property name="text">
+                     <string/>
+                    </property>
+                    <property name="icon">
+                     <iconset resource="../../ldforge.qrc">
+                      <normaloff>:/icons/colorselect.png</normaloff>:/icons/colorselect.png</iconset>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="3" column="0">
+                   <widget class="QLabel" name="label_3">
+                    <property name="whatsThis">
+                     <string/>
+                    </property>
+                    <property name="text">
+                     <string>Main color alpha</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="3" column="1">
+                   <widget class="QDoubleSpinBox" name="configMainColorAlpha">
+                    <property name="maximum">
+                     <double>1.000000000000000</double>
+                    </property>
+                    <property name="singleStep">
+                     <double>0.050000000000000</double>
+                    </property>
+                    <property name="value">
+                     <double>1.000000000000000</double>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="4" column="0">
+                   <widget class="QLabel" name="label_5">
+                    <property name="whatsThis">
+                     <string/>
+                    </property>
+                    <property name="text">
+                     <string>Line thickness</string>
+                    </property>
+                   </widget>
+                  </item>
+                  <item row="4" column="1">
+                   <widget class="QSlider" name="configLineThickness">
+                    <property name="whatsThis">
+                     <string>How thick lines should be drawn in the viewport.</string>
+                    </property>
+                    <property name="minimum">
+                     <number>1</number>
+                    </property>
+                    <property name="maximum">
+                     <number>8</number>
+                    </property>
+                    <property name="orientation">
+                     <enum>Qt::Horizontal</enum>
+                    </property>
+                    <property name="tickPosition">
+                     <enum>QSlider::TicksAbove</enum>
+                    </property>
+                    <property name="tickInterval">
+                     <number>1</number>
+                    </property>
+                   </widget>
+                  </item>
+                 </layout>
+                </item>
+                <item>
+                 <spacer name="horizontalSpacer">
+                  <property name="orientation">
+                   <enum>Qt::Horizontal</enum>
+                  </property>
+                  <property name="sizeHint" stdset="0">
+                   <size>
+                    <width>40</width>
+                    <height>20</height>
+                   </size>
+                  </property>
+                 </spacer>
+                </item>
+               </layout>
+              </item>
+              <item>
+               <layout class="QGridLayout" name="gridLayout_3">
+                <item row="0" column="2">
+                 <widget class="QCheckBox" name="configUseLogoStuds">
+                  <property name="text">
+                   <string>Use logoed studs</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="0" column="0">
+                 <spacer name="horizontalSpacer_3">
+                  <property name="orientation">
+                   <enum>Qt::Horizontal</enum>
+                  </property>
+                  <property name="sizeHint" stdset="0">
+                   <size>
+                    <width>40</width>
+                    <height>20</height>
+                   </size>
+                  </property>
+                 </spacer>
+                </item>
+                <item row="3" column="1">
+                 <widget class="QCheckBox" name="configAntiAliasedLines">
+                  <property name="text">
+                   <string>Anti-aliased lines</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="1" column="2">
+                 <widget class="QCheckBox" name="configDrawLineLengths">
+                  <property name="text">
+                   <string>Display line lenghts when drawing</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="1" column="1">
+                 <widget class="QCheckBox" name="configBfcRedGreenView">
+                  <property name="whatsThis">
+                   <string>Polygons' front sides become green and back sides red.</string>
+                  </property>
+                  <property name="text">
+                   <string>Red/green BFC view (incomplete)</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="2" column="1">
+                 <widget class="QCheckBox" name="configColorizeObjectsList">
+                  <property name="whatsThis">
+                   <string>Makes colored objects (non-16 and 24) appear colored in the list view. A red triangle will, for instance, have its entry written in red text. This can be useful to locate colored objects.</string>
+                  </property>
+                  <property name="text">
+                   <string>Colorize objects in list view</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="0" column="1">
+                 <widget class="QCheckBox" name="configBlackEdges">
+                  <property name="whatsThis">
+                   <string>Makes all edgelines appear black. If this is not set, edge lines take their color as defined in LDConfig.ldr.</string>
+                  </property>
+                  <property name="text">
+                   <string>Black edges</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="1" column="3">
+                 <spacer name="horizontalSpacer_4">
+                  <property name="orientation">
+                   <enum>Qt::Horizontal</enum>
+                  </property>
+                  <property name="sizeHint" stdset="0">
+                   <size>
+                    <width>40</width>
+                    <height>20</height>
+                   </size>
+                  </property>
+                 </spacer>
+                </item>
+                <item row="3" column="2">
+                 <widget class="QCheckBox" name="configHighlightObjectBelowCursor">
+                  <property name="text">
+                   <string>Highlight object below cursor</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="2" column="2">
+                 <widget class="QCheckBox" name="configListImplicitFiles">
+                  <property name="text">
+                   <string>List implicitly loaded files</string>
+                  </property>
+                 </widget>
+                </item>
+               </layout>
+              </item>
+             </layout>
+            </item>
+           </layout>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+       <widget class="QWidget" name="page">
+        <layout class="QVBoxLayout" name="verticalLayout_6">
+         <item>
+          <widget class="QGroupBox" name="groupBox_6">
+           <property name="title">
+            <string>Editing tools</string>
+           </property>
+           <layout class="QVBoxLayout" name="verticalLayout_7">
+            <item>
+             <widget class="QGroupBox" name="groupBox_7">
+              <property name="title">
+               <string>Rounding</string>
+              </property>
+              <layout class="QVBoxLayout" name="verticalLayout_9">
+               <item>
+                <layout class="QGridLayout" name="gridLayout_2">
+                 <item row="0" column="1">
+                  <widget class="QLabel" name="label_17">
+                   <property name="text">
+                    <string>Position decimals:</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="0" column="2">
+                  <widget class="QSpinBox" name="configRoundPositionPrecision"/>
+                 </item>
+                 <item row="1" column="1">
+                  <widget class="QLabel" name="label_18">
+                   <property name="text">
+                    <string>Matrix decimals:</string>
+                   </property>
+                  </widget>
+                 </item>
+                 <item row="1" column="2">
+                  <widget class="QSpinBox" name="configRoundMatrixPrecision"/>
+                 </item>
+                 <item row="0" column="0">
+                  <spacer name="horizontalSpacer_5">
+                   <property name="orientation">
+                    <enum>Qt::Horizontal</enum>
+                   </property>
+                   <property name="sizeHint" stdset="0">
+                    <size>
+                     <width>40</width>
+                     <height>20</height>
+                    </size>
+                   </property>
+                  </spacer>
+                 </item>
+                 <item row="0" column="3">
+                  <spacer name="horizontalSpacer_6">
+                   <property name="orientation">
+                    <enum>Qt::Horizontal</enum>
+                   </property>
+                   <property name="sizeHint" stdset="0">
+                    <size>
+                     <width>40</width>
+                     <height>20</height>
+                    </size>
+                   </property>
+                  </spacer>
+                 </item>
+                </layout>
+               </item>
+              </layout>
+             </widget>
+            </item>
+           </layout>
+          </widget>
+         </item>
+         <item>
+          <spacer name="verticalSpacer_6">
+           <property name="orientation">
+            <enum>Qt::Vertical</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>20</width>
+             <height>40</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </widget>
+       <widget class="QWidget" name="page_4">
+        <layout class="QVBoxLayout" name="verticalLayout_14">
+         <item>
+          <widget class="QGroupBox" name="groupBox_4">
+           <property name="title">
+            <string>Profile</string>
+           </property>
+           <layout class="QVBoxLayout" name="verticalLayout_8">
+            <item>
+             <layout class="QHBoxLayout" name="horizontalLayout_4">
+              <item>
+               <spacer name="horizontalSpacer_7">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>40</width>
+                  <height>20</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item>
+               <layout class="QFormLayout" name="formLayout_3">
+                <property name="fieldGrowthPolicy">
+                 <enum>QFormLayout::ExpandingFieldsGrow</enum>
+                </property>
+                <item row="1" column="0">
+                 <widget class="QLabel" name="label_7">
+                  <property name="text">
+                   <string>Name:</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="1" column="1">
+                 <widget class="QLineEdit" name="configDefaultName">
+                  <property name="minimumSize">
+                   <size>
+                    <width>250</width>
+                    <height>0</height>
+                   </size>
+                  </property>
+                 </widget>
+                </item>
+                <item row="2" column="0">
+                 <widget class="QLabel" name="label_8">
+                  <property name="text">
+                   <string>Username:</string>
+                  </property>
+                 </widget>
+                </item>
+                <item row="2" column="1">
+                 <widget class="QLineEdit" name="configDefaultUser"/>
+                </item>
+                <item row="3" column="1">
+                 <widget class="QCheckBox" name="configUseCaLicense">
+                  <property name="text">
+                   <string>Use CA license</string>
+                  </property>
+                 </widget>
+                </item>
+               </layout>
+              </item>
+              <item>
+               <spacer name="horizontalSpacer_8">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>40</width>
+                  <height>20</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+             </layout>
+            </item>
+            <item>
+             <spacer name="verticalSpacer_7">
+              <property name="orientation">
+               <enum>Qt::Vertical</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>20</width>
+                <height>40</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+           </layout>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+       <widget class="QWidget" name="page_5">
+        <layout class="QVBoxLayout" name="verticalLayout_15">
+         <item>
+          <widget class="QGroupBox" name="groupBox_2">
+           <property name="whatsThis">
+            <string>Here you can alter keyboard shortcuts for almost all LDForge actions. Only exceptions are the controls for the viewport. Use the set button to set a key shortcut, clear to remove it and reset to restore the shortcut to its default value.
+
+Shortcut changes apply immediately after closing this window.</string>
+           </property>
+           <property name="title">
+            <string>Shortcuts</string>
+           </property>
+           <layout class="QHBoxLayout" name="horizontalLayout_5">
+            <item>
+             <widget class="QListWidget" name="shortcutsList">
+              <property name="verticalScrollBarPolicy">
+               <enum>Qt::ScrollBarAsNeeded</enum>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <layout class="QVBoxLayout" name="verticalLayout_4">
+              <item>
+               <widget class="QPushButton" name="shortcut_set">
+                <property name="text">
+                 <string>Set</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QPushButton" name="shortcut_reset">
+                <property name="text">
+                 <string>Reset</string>
+                </property>
+                <property name="icon">
+                 <iconset resource="../../ldforge.qrc">
+                  <normaloff>:/icons/undo.png</normaloff>:/icons/undo.png</iconset>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QPushButton" name="shortcut_clear">
+                <property name="text">
+                 <string>Clear</string>
+                </property>
+                <property name="icon">
+                 <iconset resource="../../ldforge.qrc">
+                  <normaloff>:/icons/delete.png</normaloff>:/icons/delete.png</iconset>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <spacer name="verticalSpacer_2">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>40</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+             </layout>
+            </item>
+           </layout>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+       <widget class="QWidget" name="page_6">
+        <layout class="QVBoxLayout" name="verticalLayout_16">
+         <item>
+          <widget class="QGroupBox" name="groupBox_3">
+           <property name="whatsThis">
+            <string>Here you can alter the layout of the quick colors toolbar. Use the controls to add, remove or edit the colors used. You can also add separators in between colors.
+
+Usually this contains MainColor, EdgeColor and some auxiliary colors used to group objects.</string>
+           </property>
+           <property name="title">
+            <string>Color Toolbar</string>
+           </property>
+           <layout class="QHBoxLayout" name="horizontalLayout_6">
+            <item>
+             <widget class="QListWidget" name="quickColorList">
+              <property name="verticalScrollBarPolicy">
+               <enum>Qt::ScrollBarAsNeeded</enum>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <layout class="QVBoxLayout" name="verticalLayout_5">
+              <item>
+               <widget class="QPushButton" name="quickColor_add">
+                <property name="text">
+                 <string>Add Color</string>
+                </property>
+                <property name="icon">
+                 <iconset resource="../../ldforge.qrc">
+                  <normaloff>:/icons/palette.png</normaloff>:/icons/palette.png</iconset>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QPushButton" name="quickColor_addSep">
+                <property name="text">
+                 <string>Add Separator</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QPushButton" name="quickColor_edit">
+                <property name="text">
+                 <string>Edit</string>
+                </property>
+                <property name="icon">
+                 <iconset resource="../../ldforge.qrc">
+                  <normaloff>:/icons/mode-draw.png</normaloff>:/icons/mode-draw.png</iconset>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="Line" name="line_2">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QPushButton" name="quickColor_moveUp">
+                <property name="text">
+                 <string>Move Up</string>
+                </property>
+                <property name="icon">
+                 <iconset resource="../../ldforge.qrc">
+                  <normaloff>:/icons/arrow-up.png</normaloff>:/icons/arrow-up.png</iconset>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QPushButton" name="quickColor_moveDown">
+                <property name="text">
+                 <string>Move Down</string>
+                </property>
+                <property name="icon">
+                 <iconset resource="../../ldforge.qrc">
+                  <normaloff>:/icons/arrow-down.png</normaloff>:/icons/arrow-down.png</iconset>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="Line" name="line">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QPushButton" name="quickColor_remove">
+                <property name="text">
+                 <string>Remove</string>
+                </property>
+                <property name="icon">
+                 <iconset resource="../../ldforge.qrc">
+                  <normaloff>:/icons/delete.png</normaloff>:/icons/delete.png</iconset>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QPushButton" name="quickColor_clear">
+                <property name="text">
+                 <string>Clear List</string>
+                </property>
+                <property name="icon">
+                 <iconset resource="../../ldforge.qrc">
+                  <normaloff>:/icons/delete.png</normaloff>:/icons/delete.png</iconset>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <spacer name="verticalSpacer_3">
+                <property name="orientation">
+                 <enum>Qt::Vertical</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>20</width>
+                  <height>40</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+             </layout>
+            </item>
+           </layout>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+       <widget class="QWidget" name="page_7">
+        <layout class="QVBoxLayout" name="verticalLayout_17">
+         <item>
+          <widget class="QGroupBox" name="grids">
+           <property name="title">
+            <string>Grids</string>
+           </property>
+           <layout class="QVBoxLayout" name="verticalLayout_2">
+            <item>
+             <layout class="QGridLayout" name="gridLayout">
+              <item row="3" column="4">
+               <widget class="QDoubleSpinBox" name="configGridFineAngleSnap">
+                <property name="suffix">
+                 <string>°</string>
+                </property>
+                <property name="decimals">
+                 <number>3</number>
+                </property>
+                <property name="maximum">
+                 <double>360.000000000000000</double>
+                </property>
+               </widget>
+              </item>
+              <item row="0" column="3">
+               <widget class="QLabel" name="label_15">
+                <property name="text">
+                 <string>Coordinate snap</string>
+                </property>
+               </widget>
+              </item>
+              <item row="0" column="4">
+               <widget class="QLabel" name="label_16">
+                <property name="text">
+                 <string>Angle snap</string>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="1">
+               <widget class="QLabel" name="label_6">
+                <property name="text">
+                 <string/>
+                </property>
+                <property name="pixmap">
+                 <pixmap resource="../../ldforge.qrc">:/icons/grid-coarse.png</pixmap>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="2">
+               <widget class="QLabel" name="label_12">
+                <property name="text">
+                 <string>Coarse</string>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="3">
+               <widget class="QDoubleSpinBox" name="configGridCoarseCoordinateSnap">
+                <property name="suffix">
+                 <string> LDU</string>
+                </property>
+                <property name="decimals">
+                 <number>5</number>
+                </property>
+                <property name="maximum">
+                 <double>10000.000000000000000</double>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="4">
+               <widget class="QDoubleSpinBox" name="configGridCoarseAngleSnap">
+                <property name="suffix">
+                 <string>°</string>
+                </property>
+                <property name="decimals">
+                 <number>3</number>
+                </property>
+                <property name="maximum">
+                 <double>360.000000000000000</double>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="1">
+               <widget class="QLabel" name="label_10">
+                <property name="text">
+                 <string/>
+                </property>
+                <property name="pixmap">
+                 <pixmap resource="../../ldforge.qrc">:/icons/grid-medium.png</pixmap>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="2">
+               <widget class="QLabel" name="label_13">
+                <property name="text">
+                 <string>Medium</string>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="3">
+               <widget class="QDoubleSpinBox" name="configGridMediumCoordinateSnap">
+                <property name="suffix">
+                 <string> LDU</string>
+                </property>
+                <property name="decimals">
+                 <number>5</number>
+                </property>
+                <property name="maximum">
+                 <double>10000.000000000000000</double>
+                </property>
+               </widget>
+              </item>
+              <item row="2" column="4">
+               <widget class="QDoubleSpinBox" name="configGridMediumAngleSnap">
+                <property name="suffix">
+                 <string>°</string>
+                </property>
+                <property name="decimals">
+                 <number>3</number>
+                </property>
+                <property name="maximum">
+                 <double>360.000000000000000</double>
+                </property>
+               </widget>
+              </item>
+              <item row="3" column="1">
+               <widget class="QLabel" name="label_11">
+                <property name="text">
+                 <string/>
+                </property>
+                <property name="pixmap">
+                 <pixmap resource="../../ldforge.qrc">:/icons/grid-fine.png</pixmap>
+                </property>
+               </widget>
+              </item>
+              <item row="3" column="2">
+               <widget class="QLabel" name="label_14">
+                <property name="text">
+                 <string>Fine</string>
+                </property>
+               </widget>
+              </item>
+              <item row="3" column="3">
+               <widget class="QDoubleSpinBox" name="configGridFineCoordinateSnap">
+                <property name="suffix">
+                 <string> LDU</string>
+                </property>
+                <property name="decimals">
+                 <number>5</number>
+                </property>
+                <property name="maximum">
+                 <double>10000.000000000000000</double>
+                </property>
+               </widget>
+              </item>
+              <item row="1" column="0">
+               <spacer name="horizontalSpacer_9">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>40</width>
+                  <height>20</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+              <item row="1" column="5">
+               <spacer name="horizontalSpacer_10">
+                <property name="orientation">
+                 <enum>Qt::Horizontal</enum>
+                </property>
+                <property name="sizeHint" stdset="0">
+                 <size>
+                  <width>40</width>
+                  <height>20</height>
+                 </size>
+                </property>
+               </spacer>
+              </item>
+             </layout>
+            </item>
+            <item>
+             <spacer name="verticalSpacer">
+              <property name="orientation">
+               <enum>Qt::Vertical</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>20</width>
+                <height>165</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+           </layout>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+       <widget class="QWidget" name="page_8">
+        <layout class="QVBoxLayout" name="verticalLayout_18">
+         <item>
+          <widget class="QGroupBox" name="extProgs">
+           <property name="whatsThis">
+            <string>LDForge supports launching of several third-party utility tools; here you can set the file paths to these tools. Set the paths of the tools to the exe files.
+
+Under Linux, you can also set the programs to be launched with Wine, so you can use Windows binaries here as well. You will obviously need Wine installed. A 'wine' command in PATH is necessary for this to work.</string>
+           </property>
+           <property name="title">
+            <string>External Programs</string>
+           </property>
+          </widget>
+         </item>
+         <item>
+          <spacer name="verticalSpacer_4">
+           <property name="orientation">
+            <enum>Qt::Vertical</enum>
+           </property>
+           <property name="sizeHint" stdset="0">
+            <size>
+             <width>20</width>
+             <height>40</height>
+            </size>
+           </property>
+          </spacer>
+         </item>
+        </layout>
+       </widget>
+       <widget class="QWidget" name="page_9">
+        <layout class="QVBoxLayout" name="verticalLayout_19">
+         <item>
+          <widget class="QGroupBox" name="groupBox_5">
+           <property name="title">
+            <string>Downloads</string>
+           </property>
+           <layout class="QVBoxLayout" name="verticalLayout_20">
+            <item>
+             <layout class="QHBoxLayout" name="horizontalLayout_2">
+              <item>
+               <widget class="QLabel" name="label_4">
+                <property name="text">
+                 <string>Download path:</string>
+                </property>
+               </widget>
+              </item>
+              <item>
+               <widget class="QLineEdit" name="configDownloadFilePath"/>
+              </item>
+              <item>
+               <widget class="QPushButton" name="findDownloadPath">
+                <property name="text">
+                 <string/>
+                </property>
+                <property name="icon">
+                 <iconset resource="../../ldforge.qrc">
+                  <normaloff>:/icons/folder.png</normaloff>:/icons/folder.png</iconset>
+                </property>
+               </widget>
+              </item>
+             </layout>
+            </item>
+            <item>
+             <widget class="QCheckBox" name="configTryDownloadMissingFiles">
+              <property name="text">
+               <string>Attempt to download missing parts from the PT</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QCheckBox" name="configGuessDownloadPaths">
+              <property name="whatsThis">
+               <string>&lt;p&gt;When this is set, LDForge tries to adjust and correct part paths based on the input. A full path given to the download prompt should be of form &lt;tt&gt;&quot;&amp;lt;dir&amp;gt;/&amp;lt;file&amp;gt;.dat&quot;&lt;/tt&gt; - with this set, input can be automatically completed.&lt;/p&gt;
+
+&lt;p&gt;Examples:
+&lt;ul&gt;
+&lt;li&gt;3002 -&gt; parts/3002.dat&lt;/li&gt;
+&lt;li&gt;3002.da -&gt; parts/3002.dat&lt;/li&gt;
+&lt;li&gt;3002s01 -&gt; parts/s/3002s01.dat&lt;/li&gt;
+&lt;li&gt;4-4cyli -&gt; p/4-4cyli.dat&lt;/li&gt;
+&lt;/ul&gt;&lt;/p&gt;</string>
+              </property>
+              <property name="text">
+               <string>Correct and guess part paths</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <widget class="QCheckBox" name="configAutoCloseDownloadDialog">
+              <property name="whatsThis">
+               <string>If this is set, LDForge will close the download prompt after everything has been downloaded. The prompt will not be closed if a download has failed.</string>
+              </property>
+              <property name="text">
+               <string>Close download prompt after completion</string>
+              </property>
+             </widget>
+            </item>
+            <item>
+             <spacer name="verticalSpacer_5">
+              <property name="orientation">
+               <enum>Qt::Vertical</enum>
+              </property>
+              <property name="sizeHint" stdset="0">
+               <size>
+                <width>20</width>
+                <height>187</height>
+               </size>
+              </property>
+             </spacer>
+            </item>
+           </layout>
+          </widget>
+         </item>
+        </layout>
+       </widget>
+      </widget>
+     </item>
+    </layout>
+   </item>
+   <item>
+    <widget class="QDialogButtonBox" name="buttonBox">
+     <property name="orientation">
+      <enum>Qt::Horizontal</enum>
+     </property>
+     <property name="standardButtons">
+      <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+     </property>
+    </widget>
+   </item>
+  </layout>
+ </widget>
+ <resources>
+  <include location="../../ldforge.qrc"/>
+ </resources>
+ <connections/>
+</ui>
--- a/src/mainwindow.cpp	Mon Aug 31 23:18:17 2015 +0300
+++ b/src/mainwindow.cpp	Mon Aug 31 23:23:45 2015 +0300
@@ -46,12 +46,12 @@
 #include "radioGroup.h"
 #include "addObjectDialog.h"
 #include "messageLog.h"
-#include "configDialog.h"
 #include "ui_mainwindow.h"
 #include "primitives.h"
 #include "editmodes/abstractEditMode.h"
 #include "toolsets/extprogramtoolset.h"
 #include "toolsets/toolset.h"
+#include "dialogs/configdialog.h"
 #include "guiutilities.h"
 
 static bool g_isSelectionLocked = false;
--- a/src/toolsets/filetoolset.cpp	Mon Aug 31 23:18:17 2015 +0300
+++ b/src/toolsets/filetoolset.cpp	Mon Aug 31 23:23:45 2015 +0300
@@ -18,13 +18,13 @@
 
 #include <QFileDialog>
 #include <QMessageBox>
-#include "../configDialog.h"
 #include "../dialogs.h"
 #include "../glRenderer.h"
 #include "../ldDocument.h"
 #include "../mainwindow.h"
 #include "../partDownloader.h"
 #include "../primitives.h"
+#include "../dialogs/configdialog.h"
 #include "../dialogs/ldrawpathdialog.h"
 #include "../dialogs/newpartdialog.h"
 #include "filetoolset.h"
--- a/ui/config.ui	Mon Aug 31 23:18:17 2015 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1070 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<ui version="4.0">
- <class>ConfigUI</class>
- <widget class="QDialog" name="ConfigUI">
-  <property name="geometry">
-   <rect>
-    <x>0</x>
-    <y>0</y>
-    <width>668</width>
-    <height>370</height>
-   </rect>
-  </property>
-  <property name="windowTitle">
-   <string>Settings</string>
-  </property>
-  <property name="windowIcon">
-   <iconset resource="../ldforge.qrc">
-    <normaloff>:/icons/settings.png</normaloff>:/icons/settings.png</iconset>
-  </property>
-  <layout class="QVBoxLayout" name="verticalLayout">
-   <item>
-    <layout class="QHBoxLayout" name="horizontalLayout_7" stretch="0,0">
-     <item>
-      <widget class="QListWidget" name="m_pagelist">
-       <property name="minimumSize">
-        <size>
-         <width>144</width>
-         <height>0</height>
-        </size>
-       </property>
-       <property name="maximumSize">
-        <size>
-         <width>144</width>
-         <height>16777215</height>
-        </size>
-       </property>
-       <item>
-        <property name="text">
-         <string>Interface</string>
-        </property>
-       </item>
-       <item>
-        <property name="text">
-         <string>Editing tools</string>
-        </property>
-       </item>
-       <item>
-        <property name="text">
-         <string>Profile</string>
-        </property>
-       </item>
-       <item>
-        <property name="text">
-         <string>Shortcuts</string>
-        </property>
-       </item>
-       <item>
-        <property name="text">
-         <string>Color Toolbar</string>
-        </property>
-       </item>
-       <item>
-        <property name="text">
-         <string>Grids</string>
-        </property>
-       </item>
-       <item>
-        <property name="text">
-         <string>External Programs</string>
-        </property>
-       </item>
-       <item>
-        <property name="text">
-         <string>Downloads</string>
-        </property>
-       </item>
-      </widget>
-     </item>
-     <item>
-      <widget class="QStackedWidget" name="m_pages">
-       <property name="currentIndex">
-        <number>0</number>
-       </property>
-       <widget class="QWidget" name="page_3">
-        <layout class="QVBoxLayout" name="verticalLayout_13">
-         <item>
-          <widget class="QGroupBox" name="groupBox">
-           <property name="title">
-            <string>Interface</string>
-           </property>
-           <layout class="QVBoxLayout" name="verticalLayout_10">
-            <item>
-             <layout class="QVBoxLayout" name="verticalLayout_3">
-              <item>
-               <layout class="QHBoxLayout" name="horizontalLayout">
-                <item>
-                 <spacer name="horizontalSpacer_2">
-                  <property name="orientation">
-                   <enum>Qt::Horizontal</enum>
-                  </property>
-                  <property name="sizeHint" stdset="0">
-                   <size>
-                    <width>40</width>
-                    <height>20</height>
-                   </size>
-                  </property>
-                 </spacer>
-                </item>
-                <item>
-                 <layout class="QFormLayout" name="formLayout">
-                  <item row="0" column="0">
-                   <widget class="QLabel" name="label_2">
-                    <property name="whatsThis">
-                     <string/>
-                    </property>
-                    <property name="text">
-                     <string>Background color</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item row="0" column="1">
-                   <widget class="QPushButton" name="configBackgroundColor">
-                    <property name="whatsThis">
-                     <string>This is the background color for the viewport.</string>
-                    </property>
-                    <property name="text">
-                     <string/>
-                    </property>
-                    <property name="icon">
-                     <iconset resource="../ldforge.qrc">
-                      <normaloff>:/icons/colorselect.png</normaloff>:/icons/colorselect.png</iconset>
-                    </property>
-                   </widget>
-                  </item>
-                  <item row="1" column="0">
-                   <widget class="QLabel" name="label">
-                    <property name="whatsThis">
-                     <string/>
-                    </property>
-                    <property name="text">
-                     <string>Main color</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item row="1" column="1">
-                   <widget class="QPushButton" name="configMainColor">
-                    <property name="whatsThis">
-                     <string>This color is used for the main color.</string>
-                    </property>
-                    <property name="text">
-                     <string/>
-                    </property>
-                    <property name="icon">
-                     <iconset resource="../ldforge.qrc">
-                      <normaloff>:/icons/colorselect.png</normaloff>:/icons/colorselect.png</iconset>
-                    </property>
-                   </widget>
-                  </item>
-                  <item row="2" column="0">
-                   <widget class="QLabel" name="selectedColorLabel">
-                    <property name="text">
-                     <string>Selected color</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item row="2" column="1">
-                   <widget class="QPushButton" name="configSelectColorBlend">
-                    <property name="whatsThis">
-                     <string>This color is used for the main color.</string>
-                    </property>
-                    <property name="text">
-                     <string/>
-                    </property>
-                    <property name="icon">
-                     <iconset resource="../ldforge.qrc">
-                      <normaloff>:/icons/colorselect.png</normaloff>:/icons/colorselect.png</iconset>
-                    </property>
-                   </widget>
-                  </item>
-                  <item row="3" column="0">
-                   <widget class="QLabel" name="label_3">
-                    <property name="whatsThis">
-                     <string/>
-                    </property>
-                    <property name="text">
-                     <string>Main color alpha</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item row="3" column="1">
-                   <widget class="QDoubleSpinBox" name="configMainColorAlpha">
-                    <property name="maximum">
-                     <double>1.000000000000000</double>
-                    </property>
-                    <property name="singleStep">
-                     <double>0.050000000000000</double>
-                    </property>
-                    <property name="value">
-                     <double>1.000000000000000</double>
-                    </property>
-                   </widget>
-                  </item>
-                  <item row="4" column="0">
-                   <widget class="QLabel" name="label_5">
-                    <property name="whatsThis">
-                     <string/>
-                    </property>
-                    <property name="text">
-                     <string>Line thickness</string>
-                    </property>
-                   </widget>
-                  </item>
-                  <item row="4" column="1">
-                   <widget class="QSlider" name="configLineThickness">
-                    <property name="whatsThis">
-                     <string>How thick lines should be drawn in the viewport.</string>
-                    </property>
-                    <property name="minimum">
-                     <number>1</number>
-                    </property>
-                    <property name="maximum">
-                     <number>8</number>
-                    </property>
-                    <property name="orientation">
-                     <enum>Qt::Horizontal</enum>
-                    </property>
-                    <property name="tickPosition">
-                     <enum>QSlider::TicksAbove</enum>
-                    </property>
-                    <property name="tickInterval">
-                     <number>1</number>
-                    </property>
-                   </widget>
-                  </item>
-                 </layout>
-                </item>
-                <item>
-                 <spacer name="horizontalSpacer">
-                  <property name="orientation">
-                   <enum>Qt::Horizontal</enum>
-                  </property>
-                  <property name="sizeHint" stdset="0">
-                   <size>
-                    <width>40</width>
-                    <height>20</height>
-                   </size>
-                  </property>
-                 </spacer>
-                </item>
-               </layout>
-              </item>
-              <item>
-               <layout class="QGridLayout" name="gridLayout_3">
-                <item row="0" column="2">
-                 <widget class="QCheckBox" name="configUseLogoStuds">
-                  <property name="text">
-                   <string>Use logoed studs</string>
-                  </property>
-                 </widget>
-                </item>
-                <item row="0" column="0">
-                 <spacer name="horizontalSpacer_3">
-                  <property name="orientation">
-                   <enum>Qt::Horizontal</enum>
-                  </property>
-                  <property name="sizeHint" stdset="0">
-                   <size>
-                    <width>40</width>
-                    <height>20</height>
-                   </size>
-                  </property>
-                 </spacer>
-                </item>
-                <item row="3" column="1">
-                 <widget class="QCheckBox" name="configAntiAliasedLines">
-                  <property name="text">
-                   <string>Anti-aliased lines</string>
-                  </property>
-                 </widget>
-                </item>
-                <item row="1" column="2">
-                 <widget class="QCheckBox" name="configDrawLineLengths">
-                  <property name="text">
-                   <string>Display line lenghts when drawing</string>
-                  </property>
-                 </widget>
-                </item>
-                <item row="1" column="1">
-                 <widget class="QCheckBox" name="configBfcRedGreenView">
-                  <property name="whatsThis">
-                   <string>Polygons' front sides become green and back sides red.</string>
-                  </property>
-                  <property name="text">
-                   <string>Red/green BFC view (incomplete)</string>
-                  </property>
-                 </widget>
-                </item>
-                <item row="2" column="1">
-                 <widget class="QCheckBox" name="configColorizeObjectsList">
-                  <property name="whatsThis">
-                   <string>Makes colored objects (non-16 and 24) appear colored in the list view. A red triangle will, for instance, have its entry written in red text. This can be useful to locate colored objects.</string>
-                  </property>
-                  <property name="text">
-                   <string>Colorize objects in list view</string>
-                  </property>
-                 </widget>
-                </item>
-                <item row="0" column="1">
-                 <widget class="QCheckBox" name="configBlackEdges">
-                  <property name="whatsThis">
-                   <string>Makes all edgelines appear black. If this is not set, edge lines take their color as defined in LDConfig.ldr.</string>
-                  </property>
-                  <property name="text">
-                   <string>Black edges</string>
-                  </property>
-                 </widget>
-                </item>
-                <item row="1" column="3">
-                 <spacer name="horizontalSpacer_4">
-                  <property name="orientation">
-                   <enum>Qt::Horizontal</enum>
-                  </property>
-                  <property name="sizeHint" stdset="0">
-                   <size>
-                    <width>40</width>
-                    <height>20</height>
-                   </size>
-                  </property>
-                 </spacer>
-                </item>
-                <item row="3" column="2">
-                 <widget class="QCheckBox" name="configHighlightObjectBelowCursor">
-                  <property name="text">
-                   <string>Highlight object below cursor</string>
-                  </property>
-                 </widget>
-                </item>
-                <item row="2" column="2">
-                 <widget class="QCheckBox" name="configListImplicitFiles">
-                  <property name="text">
-                   <string>List implicitly loaded files</string>
-                  </property>
-                 </widget>
-                </item>
-               </layout>
-              </item>
-             </layout>
-            </item>
-           </layout>
-          </widget>
-         </item>
-        </layout>
-       </widget>
-       <widget class="QWidget" name="page">
-        <layout class="QVBoxLayout" name="verticalLayout_6">
-         <item>
-          <widget class="QGroupBox" name="groupBox_6">
-           <property name="title">
-            <string>Editing tools</string>
-           </property>
-           <layout class="QVBoxLayout" name="verticalLayout_7">
-            <item>
-             <widget class="QGroupBox" name="groupBox_7">
-              <property name="title">
-               <string>Rounding</string>
-              </property>
-              <layout class="QVBoxLayout" name="verticalLayout_9">
-               <item>
-                <layout class="QGridLayout" name="gridLayout_2">
-                 <item row="0" column="1">
-                  <widget class="QLabel" name="label_17">
-                   <property name="text">
-                    <string>Position decimals:</string>
-                   </property>
-                  </widget>
-                 </item>
-                 <item row="0" column="2">
-                  <widget class="QSpinBox" name="configRoundPositionPrecision"/>
-                 </item>
-                 <item row="1" column="1">
-                  <widget class="QLabel" name="label_18">
-                   <property name="text">
-                    <string>Matrix decimals:</string>
-                   </property>
-                  </widget>
-                 </item>
-                 <item row="1" column="2">
-                  <widget class="QSpinBox" name="configRoundMatrixPrecision"/>
-                 </item>
-                 <item row="0" column="0">
-                  <spacer name="horizontalSpacer_5">
-                   <property name="orientation">
-                    <enum>Qt::Horizontal</enum>
-                   </property>
-                   <property name="sizeHint" stdset="0">
-                    <size>
-                     <width>40</width>
-                     <height>20</height>
-                    </size>
-                   </property>
-                  </spacer>
-                 </item>
-                 <item row="0" column="3">
-                  <spacer name="horizontalSpacer_6">
-                   <property name="orientation">
-                    <enum>Qt::Horizontal</enum>
-                   </property>
-                   <property name="sizeHint" stdset="0">
-                    <size>
-                     <width>40</width>
-                     <height>20</height>
-                    </size>
-                   </property>
-                  </spacer>
-                 </item>
-                </layout>
-               </item>
-              </layout>
-             </widget>
-            </item>
-           </layout>
-          </widget>
-         </item>
-         <item>
-          <spacer name="verticalSpacer_6">
-           <property name="orientation">
-            <enum>Qt::Vertical</enum>
-           </property>
-           <property name="sizeHint" stdset="0">
-            <size>
-             <width>20</width>
-             <height>40</height>
-            </size>
-           </property>
-          </spacer>
-         </item>
-        </layout>
-       </widget>
-       <widget class="QWidget" name="page_4">
-        <layout class="QVBoxLayout" name="verticalLayout_14">
-         <item>
-          <widget class="QGroupBox" name="groupBox_4">
-           <property name="title">
-            <string>Profile</string>
-           </property>
-           <layout class="QVBoxLayout" name="verticalLayout_8">
-            <item>
-             <layout class="QHBoxLayout" name="horizontalLayout_4">
-              <item>
-               <spacer name="horizontalSpacer_7">
-                <property name="orientation">
-                 <enum>Qt::Horizontal</enum>
-                </property>
-                <property name="sizeHint" stdset="0">
-                 <size>
-                  <width>40</width>
-                  <height>20</height>
-                 </size>
-                </property>
-               </spacer>
-              </item>
-              <item>
-               <layout class="QFormLayout" name="formLayout_3">
-                <property name="fieldGrowthPolicy">
-                 <enum>QFormLayout::ExpandingFieldsGrow</enum>
-                </property>
-                <item row="1" column="0">
-                 <widget class="QLabel" name="label_7">
-                  <property name="text">
-                   <string>Name:</string>
-                  </property>
-                 </widget>
-                </item>
-                <item row="1" column="1">
-                 <widget class="QLineEdit" name="configDefaultName">
-                  <property name="minimumSize">
-                   <size>
-                    <width>250</width>
-                    <height>0</height>
-                   </size>
-                  </property>
-                 </widget>
-                </item>
-                <item row="2" column="0">
-                 <widget class="QLabel" name="label_8">
-                  <property name="text">
-                   <string>Username:</string>
-                  </property>
-                 </widget>
-                </item>
-                <item row="2" column="1">
-                 <widget class="QLineEdit" name="configDefaultUser"/>
-                </item>
-                <item row="3" column="1">
-                 <widget class="QCheckBox" name="configUseCaLicense">
-                  <property name="text">
-                   <string>Use CA license</string>
-                  </property>
-                 </widget>
-                </item>
-               </layout>
-              </item>
-              <item>
-               <spacer name="horizontalSpacer_8">
-                <property name="orientation">
-                 <enum>Qt::Horizontal</enum>
-                </property>
-                <property name="sizeHint" stdset="0">
-                 <size>
-                  <width>40</width>
-                  <height>20</height>
-                 </size>
-                </property>
-               </spacer>
-              </item>
-             </layout>
-            </item>
-            <item>
-             <spacer name="verticalSpacer_7">
-              <property name="orientation">
-               <enum>Qt::Vertical</enum>
-              </property>
-              <property name="sizeHint" stdset="0">
-               <size>
-                <width>20</width>
-                <height>40</height>
-               </size>
-              </property>
-             </spacer>
-            </item>
-           </layout>
-          </widget>
-         </item>
-        </layout>
-       </widget>
-       <widget class="QWidget" name="page_5">
-        <layout class="QVBoxLayout" name="verticalLayout_15">
-         <item>
-          <widget class="QGroupBox" name="groupBox_2">
-           <property name="whatsThis">
-            <string>Here you can alter keyboard shortcuts for almost all LDForge actions. Only exceptions are the controls for the viewport. Use the set button to set a key shortcut, clear to remove it and reset to restore the shortcut to its default value.
-
-Shortcut changes apply immediately after closing this window.</string>
-           </property>
-           <property name="title">
-            <string>Shortcuts</string>
-           </property>
-           <layout class="QHBoxLayout" name="horizontalLayout_5">
-            <item>
-             <widget class="QListWidget" name="shortcutsList">
-              <property name="verticalScrollBarPolicy">
-               <enum>Qt::ScrollBarAsNeeded</enum>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <layout class="QVBoxLayout" name="verticalLayout_4">
-              <item>
-               <widget class="QPushButton" name="shortcut_set">
-                <property name="text">
-                 <string>Set</string>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <widget class="QPushButton" name="shortcut_reset">
-                <property name="text">
-                 <string>Reset</string>
-                </property>
-                <property name="icon">
-                 <iconset resource="../ldforge.qrc">
-                  <normaloff>:/icons/undo.png</normaloff>:/icons/undo.png</iconset>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <widget class="QPushButton" name="shortcut_clear">
-                <property name="text">
-                 <string>Clear</string>
-                </property>
-                <property name="icon">
-                 <iconset resource="../ldforge.qrc">
-                  <normaloff>:/icons/delete.png</normaloff>:/icons/delete.png</iconset>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <spacer name="verticalSpacer_2">
-                <property name="orientation">
-                 <enum>Qt::Vertical</enum>
-                </property>
-                <property name="sizeHint" stdset="0">
-                 <size>
-                  <width>20</width>
-                  <height>40</height>
-                 </size>
-                </property>
-               </spacer>
-              </item>
-             </layout>
-            </item>
-           </layout>
-          </widget>
-         </item>
-        </layout>
-       </widget>
-       <widget class="QWidget" name="page_6">
-        <layout class="QVBoxLayout" name="verticalLayout_16">
-         <item>
-          <widget class="QGroupBox" name="groupBox_3">
-           <property name="whatsThis">
-            <string>Here you can alter the layout of the quick colors toolbar. Use the controls to add, remove or edit the colors used. You can also add separators in between colors.
-
-Usually this contains MainColor, EdgeColor and some auxiliary colors used to group objects.</string>
-           </property>
-           <property name="title">
-            <string>Color Toolbar</string>
-           </property>
-           <layout class="QHBoxLayout" name="horizontalLayout_6">
-            <item>
-             <widget class="QListWidget" name="quickColorList">
-              <property name="verticalScrollBarPolicy">
-               <enum>Qt::ScrollBarAsNeeded</enum>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <layout class="QVBoxLayout" name="verticalLayout_5">
-              <item>
-               <widget class="QPushButton" name="quickColor_add">
-                <property name="text">
-                 <string>Add Color</string>
-                </property>
-                <property name="icon">
-                 <iconset resource="../ldforge.qrc">
-                  <normaloff>:/icons/palette.png</normaloff>:/icons/palette.png</iconset>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <widget class="QPushButton" name="quickColor_addSep">
-                <property name="text">
-                 <string>Add Separator</string>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <widget class="QPushButton" name="quickColor_edit">
-                <property name="text">
-                 <string>Edit</string>
-                </property>
-                <property name="icon">
-                 <iconset resource="../ldforge.qrc">
-                  <normaloff>:/icons/mode-draw.png</normaloff>:/icons/mode-draw.png</iconset>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <widget class="Line" name="line_2">
-                <property name="orientation">
-                 <enum>Qt::Horizontal</enum>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <widget class="QPushButton" name="quickColor_moveUp">
-                <property name="text">
-                 <string>Move Up</string>
-                </property>
-                <property name="icon">
-                 <iconset resource="../ldforge.qrc">
-                  <normaloff>:/icons/arrow-up.png</normaloff>:/icons/arrow-up.png</iconset>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <widget class="QPushButton" name="quickColor_moveDown">
-                <property name="text">
-                 <string>Move Down</string>
-                </property>
-                <property name="icon">
-                 <iconset resource="../ldforge.qrc">
-                  <normaloff>:/icons/arrow-down.png</normaloff>:/icons/arrow-down.png</iconset>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <widget class="Line" name="line">
-                <property name="orientation">
-                 <enum>Qt::Horizontal</enum>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <widget class="QPushButton" name="quickColor_remove">
-                <property name="text">
-                 <string>Remove</string>
-                </property>
-                <property name="icon">
-                 <iconset resource="../ldforge.qrc">
-                  <normaloff>:/icons/delete.png</normaloff>:/icons/delete.png</iconset>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <widget class="QPushButton" name="quickColor_clear">
-                <property name="text">
-                 <string>Clear List</string>
-                </property>
-                <property name="icon">
-                 <iconset resource="../ldforge.qrc">
-                  <normaloff>:/icons/delete.png</normaloff>:/icons/delete.png</iconset>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <spacer name="verticalSpacer_3">
-                <property name="orientation">
-                 <enum>Qt::Vertical</enum>
-                </property>
-                <property name="sizeHint" stdset="0">
-                 <size>
-                  <width>20</width>
-                  <height>40</height>
-                 </size>
-                </property>
-               </spacer>
-              </item>
-             </layout>
-            </item>
-           </layout>
-          </widget>
-         </item>
-        </layout>
-       </widget>
-       <widget class="QWidget" name="page_7">
-        <layout class="QVBoxLayout" name="verticalLayout_17">
-         <item>
-          <widget class="QGroupBox" name="grids">
-           <property name="title">
-            <string>Grids</string>
-           </property>
-           <layout class="QVBoxLayout" name="verticalLayout_2">
-            <item>
-             <layout class="QGridLayout" name="gridLayout">
-              <item row="3" column="4">
-               <widget class="QDoubleSpinBox" name="configGridFineAngleSnap">
-                <property name="suffix">
-                 <string>°</string>
-                </property>
-                <property name="decimals">
-                 <number>3</number>
-                </property>
-                <property name="maximum">
-                 <double>360.000000000000000</double>
-                </property>
-               </widget>
-              </item>
-              <item row="0" column="3">
-               <widget class="QLabel" name="label_15">
-                <property name="text">
-                 <string>Coordinate snap</string>
-                </property>
-               </widget>
-              </item>
-              <item row="0" column="4">
-               <widget class="QLabel" name="label_16">
-                <property name="text">
-                 <string>Angle snap</string>
-                </property>
-               </widget>
-              </item>
-              <item row="1" column="1">
-               <widget class="QLabel" name="label_6">
-                <property name="text">
-                 <string/>
-                </property>
-                <property name="pixmap">
-                 <pixmap resource="../ldforge.qrc">:/icons/grid-coarse.png</pixmap>
-                </property>
-               </widget>
-              </item>
-              <item row="1" column="2">
-               <widget class="QLabel" name="label_12">
-                <property name="text">
-                 <string>Coarse</string>
-                </property>
-               </widget>
-              </item>
-              <item row="1" column="3">
-               <widget class="QDoubleSpinBox" name="configGridCoarseCoordinateSnap">
-                <property name="suffix">
-                 <string> LDU</string>
-                </property>
-                <property name="decimals">
-                 <number>5</number>
-                </property>
-                <property name="maximum">
-                 <double>10000.000000000000000</double>
-                </property>
-               </widget>
-              </item>
-              <item row="1" column="4">
-               <widget class="QDoubleSpinBox" name="configGridCoarseAngleSnap">
-                <property name="suffix">
-                 <string>°</string>
-                </property>
-                <property name="decimals">
-                 <number>3</number>
-                </property>
-                <property name="maximum">
-                 <double>360.000000000000000</double>
-                </property>
-               </widget>
-              </item>
-              <item row="2" column="1">
-               <widget class="QLabel" name="label_10">
-                <property name="text">
-                 <string/>
-                </property>
-                <property name="pixmap">
-                 <pixmap resource="../ldforge.qrc">:/icons/grid-medium.png</pixmap>
-                </property>
-               </widget>
-              </item>
-              <item row="2" column="2">
-               <widget class="QLabel" name="label_13">
-                <property name="text">
-                 <string>Medium</string>
-                </property>
-               </widget>
-              </item>
-              <item row="2" column="3">
-               <widget class="QDoubleSpinBox" name="configGridMediumCoordinateSnap">
-                <property name="suffix">
-                 <string> LDU</string>
-                </property>
-                <property name="decimals">
-                 <number>5</number>
-                </property>
-                <property name="maximum">
-                 <double>10000.000000000000000</double>
-                </property>
-               </widget>
-              </item>
-              <item row="2" column="4">
-               <widget class="QDoubleSpinBox" name="configGridMediumAngleSnap">
-                <property name="suffix">
-                 <string>°</string>
-                </property>
-                <property name="decimals">
-                 <number>3</number>
-                </property>
-                <property name="maximum">
-                 <double>360.000000000000000</double>
-                </property>
-               </widget>
-              </item>
-              <item row="3" column="1">
-               <widget class="QLabel" name="label_11">
-                <property name="text">
-                 <string/>
-                </property>
-                <property name="pixmap">
-                 <pixmap resource="../ldforge.qrc">:/icons/grid-fine.png</pixmap>
-                </property>
-               </widget>
-              </item>
-              <item row="3" column="2">
-               <widget class="QLabel" name="label_14">
-                <property name="text">
-                 <string>Fine</string>
-                </property>
-               </widget>
-              </item>
-              <item row="3" column="3">
-               <widget class="QDoubleSpinBox" name="configGridFineCoordinateSnap">
-                <property name="suffix">
-                 <string> LDU</string>
-                </property>
-                <property name="decimals">
-                 <number>5</number>
-                </property>
-                <property name="maximum">
-                 <double>10000.000000000000000</double>
-                </property>
-               </widget>
-              </item>
-              <item row="1" column="0">
-               <spacer name="horizontalSpacer_9">
-                <property name="orientation">
-                 <enum>Qt::Horizontal</enum>
-                </property>
-                <property name="sizeHint" stdset="0">
-                 <size>
-                  <width>40</width>
-                  <height>20</height>
-                 </size>
-                </property>
-               </spacer>
-              </item>
-              <item row="1" column="5">
-               <spacer name="horizontalSpacer_10">
-                <property name="orientation">
-                 <enum>Qt::Horizontal</enum>
-                </property>
-                <property name="sizeHint" stdset="0">
-                 <size>
-                  <width>40</width>
-                  <height>20</height>
-                 </size>
-                </property>
-               </spacer>
-              </item>
-             </layout>
-            </item>
-            <item>
-             <spacer name="verticalSpacer">
-              <property name="orientation">
-               <enum>Qt::Vertical</enum>
-              </property>
-              <property name="sizeHint" stdset="0">
-               <size>
-                <width>20</width>
-                <height>165</height>
-               </size>
-              </property>
-             </spacer>
-            </item>
-           </layout>
-          </widget>
-         </item>
-        </layout>
-       </widget>
-       <widget class="QWidget" name="page_8">
-        <layout class="QVBoxLayout" name="verticalLayout_18">
-         <item>
-          <widget class="QGroupBox" name="extProgs">
-           <property name="whatsThis">
-            <string>LDForge supports launching of several third-party utility tools; here you can set the file paths to these tools. Set the paths of the tools to the exe files.
-
-Under Linux, you can also set the programs to be launched with Wine, so you can use Windows binaries here as well. You will obviously need Wine installed. A 'wine' command in PATH is necessary for this to work.</string>
-           </property>
-           <property name="title">
-            <string>External Programs</string>
-           </property>
-          </widget>
-         </item>
-         <item>
-          <spacer name="verticalSpacer_4">
-           <property name="orientation">
-            <enum>Qt::Vertical</enum>
-           </property>
-           <property name="sizeHint" stdset="0">
-            <size>
-             <width>20</width>
-             <height>40</height>
-            </size>
-           </property>
-          </spacer>
-         </item>
-        </layout>
-       </widget>
-       <widget class="QWidget" name="page_9">
-        <layout class="QVBoxLayout" name="verticalLayout_19">
-         <item>
-          <widget class="QGroupBox" name="groupBox_5">
-           <property name="title">
-            <string>Downloads</string>
-           </property>
-           <layout class="QVBoxLayout" name="verticalLayout_20">
-            <item>
-             <layout class="QHBoxLayout" name="horizontalLayout_2">
-              <item>
-               <widget class="QLabel" name="label_4">
-                <property name="text">
-                 <string>Download path:</string>
-                </property>
-               </widget>
-              </item>
-              <item>
-               <widget class="QLineEdit" name="configDownloadFilePath"/>
-              </item>
-              <item>
-               <widget class="QPushButton" name="findDownloadPath">
-                <property name="text">
-                 <string/>
-                </property>
-                <property name="icon">
-                 <iconset resource="../ldforge.qrc">
-                  <normaloff>:/icons/folder.png</normaloff>:/icons/folder.png</iconset>
-                </property>
-               </widget>
-              </item>
-             </layout>
-            </item>
-            <item>
-             <widget class="QCheckBox" name="configTryDownloadMissingFiles">
-              <property name="text">
-               <string>Attempt to download missing parts from the PT</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QCheckBox" name="configGuessDownloadPaths">
-              <property name="whatsThis">
-               <string>&lt;p&gt;When this is set, LDForge tries to adjust and correct part paths based on the input. A full path given to the download prompt should be of form &lt;tt&gt;&quot;&amp;lt;dir&amp;gt;/&amp;lt;file&amp;gt;.dat&quot;&lt;/tt&gt; - with this set, input can be automatically completed.&lt;/p&gt;
-
-&lt;p&gt;Examples:
-&lt;ul&gt;
-&lt;li&gt;3002 -&gt; parts/3002.dat&lt;/li&gt;
-&lt;li&gt;3002.da -&gt; parts/3002.dat&lt;/li&gt;
-&lt;li&gt;3002s01 -&gt; parts/s/3002s01.dat&lt;/li&gt;
-&lt;li&gt;4-4cyli -&gt; p/4-4cyli.dat&lt;/li&gt;
-&lt;/ul&gt;&lt;/p&gt;</string>
-              </property>
-              <property name="text">
-               <string>Correct and guess part paths</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <widget class="QCheckBox" name="configAutoCloseDownloadDialog">
-              <property name="whatsThis">
-               <string>If this is set, LDForge will close the download prompt after everything has been downloaded. The prompt will not be closed if a download has failed.</string>
-              </property>
-              <property name="text">
-               <string>Close download prompt after completion</string>
-              </property>
-             </widget>
-            </item>
-            <item>
-             <spacer name="verticalSpacer_5">
-              <property name="orientation">
-               <enum>Qt::Vertical</enum>
-              </property>
-              <property name="sizeHint" stdset="0">
-               <size>
-                <width>20</width>
-                <height>187</height>
-               </size>
-              </property>
-             </spacer>
-            </item>
-           </layout>
-          </widget>
-         </item>
-        </layout>
-       </widget>
-      </widget>
-     </item>
-    </layout>
-   </item>
-   <item>
-    <widget class="QDialogButtonBox" name="buttonBox">
-     <property name="orientation">
-      <enum>Qt::Horizontal</enum>
-     </property>
-     <property name="standardButtons">
-      <set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
-     </property>
-    </widget>
-   </item>
-  </layout>
- </widget>
- <resources>
-  <include location="../ldforge.qrc"/>
- </resources>
- <connections/>
-</ui>

mercurial