Keyboard shortcuts can now be configured.

Tue, 09 Apr 2013 14:06:40 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Tue, 09 Apr 2013 14:06:40 +0300
changeset 78
c190fe218506
parent 77
7c2f500405fe
child 79
f8917e9d07f6

Keyboard shortcuts can now be configured.

common.h file | annotate | diff | comparison | revisions
config.cpp file | annotate | diff | comparison | revisions
config.h file | annotate | diff | comparison | revisions
gui.cpp file | annotate | diff | comparison | revisions
gui.h file | annotate | diff | comparison | revisions
misc.cpp file | annotate | diff | comparison | revisions
misc.h file | annotate | diff | comparison | revisions
zz_configDialog.cpp file | annotate | diff | comparison | revisions
zz_configDialog.h file | annotate | diff | comparison | revisions
--- a/common.h	Mon Apr 08 19:24:23 2013 +0300
+++ b/common.h	Tue Apr 09 14:06:40 2013 +0300
@@ -95,6 +95,10 @@
 	return (a > b) ? a : b;
 }
 
+static inline const char* qchars (QString qstr) {
+	return qstr.toStdString ().c_str ();
+}
+
 static const double pi = 3.14159265358979323846f;
 
 // main.cpp
--- a/config.cpp	Mon Apr 08 19:24:23 2013 +0300
+++ b/config.cpp	Tue Apr 09 14:06:40 2013 +0300
@@ -59,6 +59,7 @@
 	"String",
 	"Float",
 	"Boolean",
+	"Key sequence",
 };
 
 // =============================================================================
@@ -121,12 +122,15 @@
 		case CONFIG_int:
 			static_cast<intconfig*> (cfg)->value = atoi (valstring.chars());
 			break;
+		
 		case CONFIG_str:
 			static_cast<strconfig*> (cfg)->value = valstring;
 			break;
+		
 		case CONFIG_float:
 			static_cast<floatconfig*> (cfg)->value = atof (valstring.chars());
 			break;
+		
 		case CONFIG_bool:
 		{
 			bool& val = static_cast<boolconfig*> (cfg)->value;
@@ -137,6 +141,11 @@
 				val = false;
 			break;
 		}
+		
+		case CONFIG_keyseq:
+			static_cast<keyseqconfig*> (cfg)->value = keyseq::fromString (valstring.chars ());
+			break;
+		
 		default:
 			break;
 		}
@@ -224,12 +233,18 @@
 		case CONFIG_bool:
 			valstring = (static_cast<boolconfig*> (cfg)->value) ? "true" : "false";
 			break;
+		case CONFIG_keyseq:
+			valstring = static_cast<keyseqconfig*> (cfg)->value.toString ();
+			break;
 		default:
 			break;
 		}
 		
+		const char* sDefault = (cfg->getType() != CONFIG_keyseq) ? cfg->defaultstring :
+			static_cast<keyseqconfig*> (cfg)->defval.toString ().toUtf8 ().constData ();
+		
 		// Write the entry now.
-		writef (fp, "\n# [%s] default: %s\n", g_ConfigTypeNames[cfg->getType()], cfg->defaultstring);
+		writef (fp, "\n# [%s] default: %s\n", g_ConfigTypeNames[cfg->getType()], sDefault);
 		writef (fp, "%s=%s\n", cfg->name, valstring.chars());
 	}
 	
--- a/config.h	Mon Apr 08 19:24:23 2013 +0300
+++ b/config.h	Tue Apr 09 14:06:40 2013 +0300
@@ -25,6 +25,7 @@
 // =============================================================================
 #define CONFIGFILE APPNAME ".cfg"
 #include <QString>
+#include <qkeysequence.h>
 
 #define MAX_INI_LINE 512
 #define NUM_CONFIG (g_pConfigPointers.size ())
@@ -42,6 +43,7 @@
 	CONFIG_str,
 	CONFIG_float,
 	CONFIG_bool,
+	CONFIG_keyseq,
 };
 
 // =========================================================
@@ -213,4 +215,14 @@
 	DEFINE_ASSIGN_OPERATOR (bool, =)
 };
 
+// =============================================================================
+typedef QKeySequence keyseq;
+
+CONFIGTYPE (keyseq) {
+public:
+	IMPLEMENT_CONFIG (keyseq)
+	DEFINE_ALL_COMPARE_OPERATORS (keyseq)
+	DEFINE_ASSIGN_OPERATOR (keyseq, =)
+};
+
 #endif // __OPTIONS_H__
\ No newline at end of file
--- a/gui.cpp	Mon Apr 08 19:24:23 2013 +0300
+++ b/gui.cpp	Tue Apr 09 14:06:40 2013 +0300
@@ -46,39 +46,32 @@
 };
 
 // Key-binding configurations
-cfg (str, key_newFile,			"ctrl-n");
-cfg (str, key_open,				"ctrl-o");
-cfg (str, key_save,				"ctrl-s");
-cfg (str, key_saveAs,			"ctrl-shift-s");
-cfg (str, key_exit,				"ctrl-q");
-cfg (str, key_cut,				"ctrl-x");
-cfg (str, key_copy,				"ctrl-c");
-cfg (str, key_paste,			"ctrl-v");
-cfg (str, key_del,				"del");
-cfg (str, key_newSubfile,		"");
-cfg (str, key_newLine,			"");
-cfg (str, key_newTriangle,		"");
-cfg (str, key_newQuad,			"");
-cfg (str, key_newCondLine,		"");
-cfg (str, key_newComment,		"");
-cfg (str, key_newVertex,		"");
-cfg (str, key_splitQuads,		"");
-cfg (str, key_setContents,		"");
-cfg (str, key_inlineContents,	"ctrl-i");
-cfg (str, key_deepInline,		"ctrl-shift-i");
-cfg (str, key_makeBorders,		"ctrl-shift-b");
-cfg (str, key_settings,			"");
-cfg (str, key_help,				"f1");
-cfg (str, key_about,			"");
-cfg (str, key_aboutQt,			"");
-cfg (str, key_setColor,			"");
-
-// =============================================================================
-// Metadata for actions
-typedef struct {
-	QAction** const qAct;
-	strconfig* const cfg;
-} actionmeta;
+cfg (keyseq, key_newFile,			(Qt::CTRL | Qt::Key_N));
+cfg (keyseq, key_open,				(Qt::CTRL | Qt::Key_O));
+cfg (keyseq, key_save,				(Qt::CTRL | Qt::Key_S));
+cfg (keyseq, key_saveAs,			(Qt::CTRL | Qt::SHIFT | Qt::Key_S));
+cfg (keyseq, key_exit,				(Qt::CTRL | Qt::Key_Q));
+cfg (keyseq, key_cut,				(Qt::CTRL | Qt::Key_X));
+cfg (keyseq, key_copy,				(Qt::CTRL | Qt::Key_C));
+cfg (keyseq, key_paste,				(Qt::CTRL | Qt::Key_V));
+cfg (keyseq, key_del,				(Qt::Key_Delete));
+cfg (keyseq, key_newSubfile,		0);
+cfg (keyseq, key_newLine,			0);
+cfg (keyseq, key_newTriangle,		0);
+cfg (keyseq, key_newQuad,			0);
+cfg (keyseq, key_newCondLine,		0);
+cfg (keyseq, key_newComment,		0);
+cfg (keyseq, key_newVertex,			0);
+cfg (keyseq, key_splitQuads,		0);
+cfg (keyseq, key_setContents,		0);
+cfg (keyseq, key_inlineContents,	(Qt::CTRL | Qt::Key_I));
+cfg (keyseq, key_deepInline,		(Qt::CTRL | Qt::SHIFT | Qt::Key_I));
+cfg (keyseq, key_makeBorders,		(Qt::CTRL | Qt::SHIFT | Qt::Key_B));
+cfg (keyseq, key_settings,			0);
+cfg (keyseq, key_help,				(Qt::Key_F1));
+cfg (keyseq, key_about,				0);
+cfg (keyseq, key_aboutQt,			0);
+cfg (keyseq, key_setColor,			0);
 
 vector<LDObject*> g_Clipboard;
 vector<actionmeta> g_ActionMeta;
@@ -174,16 +167,9 @@
 	MAKE_ACTION (about,			sAboutText,		"ldforge",		"Shows information about " APPNAME_DISPLAY ".")
 	MAKE_ACTION (aboutQt,		"About Qt",		"aboutQt",		"Shows information about Qt.")
 	
-	// Keyboard shortcuts
-	ACTION (newFile)->setShortcut (Qt::CTRL | Qt::Key_N);
-	ACTION (open)->setShortcut (Qt::CTRL | Qt::Key_O);
-	ACTION (save)->setShortcut (Qt::CTRL | Qt::Key_S);
-	ACTION (saveAs)->setShortcut (Qt::CTRL | Qt::SHIFT | Qt::Key_S);
-	
-	ACTION (cut)->setShortcut (Qt::CTRL | Qt::Key_X);
-	ACTION (copy)->setShortcut (Qt::CTRL | Qt::Key_C);
-	ACTION (paste)->setShortcut (Qt::CTRL | Qt::Key_V);
-	ACTION (del)->setShortcut (Qt::Key_Delete);
+	// Apply the shortcuts now
+	for (actionmeta meta : g_ActionMeta)
+		(*meta.qAct)->setShortcut (*meta.conf);
 	
 	// things not implemented yet
 	QAction* const qaDisabledActions[] = {
@@ -306,7 +292,7 @@
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-void ForgeWindow::slot_new () {
+void ForgeWindow::slot_newFile () {
 	// newFile ();
 	NewPartDialog::StaticDialog ();
 }
@@ -444,7 +430,7 @@
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-void ForgeWindow::slot_delete () {
+void ForgeWindow::slot_del () {
 	deleteSelection ();
 	refresh ();
 }
@@ -490,7 +476,7 @@
 	refresh ();
 }
 
-void ForgeWindow::slot_inline () {
+void ForgeWindow::slot_inlineContents () {
 	doInline (false);
 }
 
--- a/gui.h	Mon Apr 08 19:24:23 2013 +0300
+++ b/gui.h	Tue Apr 09 14:06:40 2013 +0300
@@ -27,6 +27,7 @@
 #include <QToolBar>
 #include <QTextEdit>
 #include "gldraw.h"
+#include "config.h"
 
 // Stuff for dialogs
 #define IMPLEMENT_DIALOG_BUTTONS \
@@ -73,7 +74,7 @@
 private slots:
 	void slot_selectionChanged ();
 	
-	void slot_new ();
+	void slot_newFile ();
 	void slot_open ();
 	void slot_save ();
 	void slot_saveAs ();
@@ -87,7 +88,7 @@
 	void slot_newComment ();
 	void slot_newVertex ();
 	
-	void slot_inline ();
+	void slot_inlineContents ();
 	void slot_deepInline ();
 	void slot_splitQuads ();
 	void slot_setContents ();
@@ -96,7 +97,7 @@
 	void slot_cut ();
 	void slot_copy ();
 	void slot_paste ();
-	void slot_delete ();
+	void slot_del ();
 	
 	void slot_settings ();
 	
@@ -113,4 +114,13 @@
 	NUM_LDOL_Columns
 };
 
+// =============================================================================
+// Metadata for actions
+typedef struct {
+	QAction** const qAct;
+	keyseqconfig* const conf;
+} actionmeta;
+
+extern vector<actionmeta> g_ActionMeta;
+
 #endif
\ No newline at end of file
--- a/misc.cpp	Mon Apr 08 19:24:23 2013 +0300
+++ b/misc.cpp	Tue Apr 09 14:06:40 2013 +0300
@@ -51,8 +51,6 @@
 	if (zRep[~zRep - 1] == '.')
 		zRep -= 1;
 	
-	// Reset the locale
-	setlocale (LC_NUMERIC, "");
 	return zRep;
 }
 
@@ -103,12 +101,12 @@
 
 // -----------------------------------------------------------------------------
 bool stringparser::atEnd () {
-	return (dPos == zaTokens.size() - 1);
+	return (dPos == (signed)zaTokens.size() - 1);
 }
 
 // -----------------------------------------------------------------------------
 bool stringparser::getToken (str& zVal, const ushort uInPos) {
-	if (uInPos < 0 || uInPos >= zaTokens.size())
+	if (uInPos >= zaTokens.size())
 		return false;
 	
 	zVal = zaTokens[uInPos];
@@ -127,7 +125,7 @@
 
 // -----------------------------------------------------------------------------
 bool stringparser::findToken (short& dResult, char const* sNeedle, short dArgs) {
-	for (short i = 0; i < (zaTokens.size() - dArgs); ++i) {
+	for (ushort i = 0; i < (zaTokens.size() - dArgs); ++i) {
 		if (zaTokens[i] == sNeedle) {
 			dResult = i;
 			return true;
--- a/misc.h	Mon Apr 08 19:24:23 2013 +0300
+++ b/misc.h	Tue Apr 09 14:06:40 2013 +0300
@@ -36,9 +36,11 @@
 str ftoa (double fCoord);
 
 template<class T> bool in (T needle, std::initializer_list<T> haystack) {
-	for (size_t i = 0; i < haystack.size(); ++i)
-		if (needle = *(haystack.begin() + i))
+	for (T hay : haystack) {
+		printf ("%s: %ld <-> %ld\n", __func__, needle, hay);
+		if (needle == hay)
 			return true;
+	}
 	
 	return false;
 }
--- a/zz_configDialog.cpp	Mon Apr 08 19:24:23 2013 +0300
+++ b/zz_configDialog.cpp	Tue Apr 09 14:06:40 2013 +0300
@@ -20,9 +20,12 @@
 #include "zz_configDialog.h"
 #include "file.h"
 #include "config.h"
+#include "misc.h"
 #include <qgridlayout.h>
 #include <qfiledialog.h>
 #include <qcolordialog.h>
+#include <qboxlayout.h>
+#include <qevent.h>
 
 extern_cfg (str, io_ldpath);
 extern_cfg (str, gl_bgcolor);
@@ -45,7 +48,30 @@
 // =============================================================================
 ConfigDialog::ConfigDialog (ForgeWindow* parent) : QDialog (parent) {
 	g_ConfigDialog = this;
+	qTabs = new QTabWidget;
 	
+	initMainTab ();
+	initShortcutsTab ();
+	
+	IMPLEMENT_DIALOG_BUTTONS
+	
+	QVBoxLayout* layout = new QVBoxLayout;
+	layout->addWidget (qTabs);
+	layout->addWidget (qButtons);
+	setLayout (layout);
+	
+	setWindowTitle (APPNAME_DISPLAY " - editing settings");
+	setWindowIcon (QIcon ("icons/settings.png"));
+}
+
+// =============================================================================
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// =============================================================================
+void ConfigDialog::initMainTab () {
+	qMainTab = new QWidget;
+	
+	// =========================================================================
+	// LDraw path
 	qLDrawPath = new QLineEdit;
 	qLDrawPath->setText (io_ldpath.value.chars());
 	
@@ -56,6 +82,8 @@
 	connect (qLDrawPathFindButton, SIGNAL (clicked ()),
 		this, SLOT (slot_findLDrawPath ()));
 	
+	// =========================================================================
+	// Background and foreground colors
 	qGLBackgroundLabel = new QLabel ("Background color:");
 	qGLBackgroundButton = new QPushButton;
 	setButtonBackground (qGLBackgroundButton, gl_bgcolor.value);
@@ -68,20 +96,22 @@
 	connect (qGLForegroundButton, SIGNAL (clicked ()),
 		this, SLOT (slot_setGLForeground ()));
 	
+	// =========================================================================
+	// Alpha and line thickness sliders
 	qGLForegroundAlphaLabel = new QLabel ("Alpha:");
 	makeSlider (qGLForegroundAlpha, 1, 10, (gl_maincolor_alpha * 10.0f));
 	
 	qGLLineThicknessLabel = new QLabel ("Line thickness:");
 	makeSlider (qGLLineThickness, 1, 8, gl_linethickness);
 	
+	// =========================================================================
+	// List view colorizer and BFC red/green view checkboxes
 	qLVColorize = new QCheckBox ("Colorize polygons in list view");
 	INIT_CHECKBOX (qLVColorize, lv_colorize)
 	
 	qGLColorBFC = new QCheckBox ("Red/green BFC view");
 	INIT_CHECKBOX (qGLColorBFC, gl_colorbfc)
 	
-	IMPLEMENT_DIALOG_BUTTONS
-	
 	QGridLayout* layout = new QGridLayout;
 	layout->addWidget (qLDrawPathLabel, 0, 0);
 	layout->addWidget (qLDrawPath, 0, 1, 1, 2);
@@ -99,12 +129,50 @@
 	
 	layout->addWidget (qLVColorize, 3, 0, 1, 2);
 	layout->addWidget (qGLColorBFC, 3, 2, 1, 2);
+	qMainTab->setLayout (layout);
 	
-	layout->addWidget (qButtons, 4, 2, 1, 2);
-	setLayout (layout);
+	// Add the tab to the manager
+	qTabs->addTab (qMainTab, "Main settings");
+}
+
+// =============================================================================
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// =============================================================================
+void ConfigDialog::initShortcutsTab () {
+	QGridLayout* qLayout;
+	
+	qShortcutsTab = new QWidget;
+	qShortcutList = new QListWidget;
+	qLayout = new QGridLayout;
 	
-	setWindowTitle (APPNAME_DISPLAY " - editing settings");
-	setWindowIcon (QIcon ("icons/settings.png"));
+	// Init table items
+	ulong i = 0;
+	for (actionmeta meta : g_ActionMeta) {
+		QAction* const qAct = *meta.qAct;
+		QListWidgetItem* qItem = new QListWidgetItem;
+		setShortcutText (qItem, meta);
+		qItem->setIcon (qAct->icon ());
+		
+		qaShortcutItems.push_back (qItem);
+		qShortcutList->insertItem (i, qItem);
+		++i;
+	}
+	
+	qBTN_setShortcut = new QPushButton ("Set");
+	qBTN_resetShortcut = new QPushButton ("Reset");
+	
+	connect (qBTN_setShortcut, SIGNAL (clicked ()), this, SLOT (slot_setShortcut ()));
+	connect (qBTN_resetShortcut, SIGNAL (clicked ()), this, SLOT (slot_resetShortcut ()));
+	
+	QVBoxLayout* qButtonLayout = new QVBoxLayout;
+	qButtonLayout->addWidget (qBTN_setShortcut);
+	qButtonLayout->addWidget (qBTN_resetShortcut);
+	qButtonLayout->addStretch (10);
+	
+	qLayout->addWidget (qShortcutList, 0, 0);
+	qLayout->addLayout (qButtonLayout, 0, 1);
+	qShortcutsTab->setLayout (qLayout);
+	qTabs->addTab (qShortcutsTab, "Shortcuts");
 }
 
 // =============================================================================
@@ -123,7 +191,7 @@
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-ConfigDialog::~ConfigDialog() {
+ConfigDialog::~ConfigDialog () {
 	g_ConfigDialog = nullptr;
 }
 
@@ -174,6 +242,66 @@
 }
 
 // =============================================================================
+long ConfigDialog::getItemRow (QListWidgetItem* qItem) {
+	long i = 0;
+	
+	for (QListWidgetItem* it : qaShortcutItems) {
+		if (it == qItem)
+			return i;
+		++i;
+	}
+	
+	return -1;
+}
+
+// =============================================================================
+void ConfigDialog::slot_setShortcut () {
+	QList<QListWidgetItem*> qaSel = qShortcutList->selectedItems ();
+	
+	if (qaSel.size() < 1)
+		return;
+	
+	QListWidgetItem* qItem = qaSel[0];
+	
+	// Find the row this object is on.
+	long idx = getItemRow (qItem);
+	
+	if (KeySequenceDialog::staticDialog (g_ActionMeta[idx], this))
+		setShortcutText (qItem, g_ActionMeta[idx]);
+}
+
+// =============================================================================
+void ConfigDialog::slot_resetShortcut () {
+	QList<QListWidgetItem*> qaSel = qShortcutList->selectedItems ();
+	
+	for (QListWidgetItem* qItem : qaSel) {
+		long idx = getItemRow (qItem);
+		
+		if (idx == -1)
+			continue;
+		
+		actionmeta meta = g_ActionMeta[idx];
+		keyseqconfig* conf = g_ActionMeta[idx].conf;
+		
+		conf->reset ();
+		(*meta.qAct)->setShortcut (*conf);
+		
+		setShortcutText (qItem, meta);
+	}
+}
+
+// =============================================================================
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// =============================================================================
+void ConfigDialog::setShortcutText (QListWidgetItem* qItem, actionmeta meta) {
+	QAction* const qAct = *meta.qAct;
+	str zLabel = qAct->iconText ();
+	str zKeybind = qAct->shortcut ().toString ();
+	
+	qItem->setText (str::mkfmt ("%s (%s)", zLabel.chars () ,zKeybind.chars ()).chars());
+}
+
+// =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
 void ConfigDialog::staticDialog (ForgeWindow* window) {
@@ -197,4 +325,73 @@
 		window->R->setBackground ();
 		window->refresh ();
 	}
+}
+
+// =============================================================================
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// =============================================================================
+KeySequenceDialog::KeySequenceDialog (QKeySequence seq, QWidget* parent,
+	Qt::WindowFlags f) : QDialog (parent, f), seq (seq)
+{
+	qOutput = new QLabel;
+	IMPLEMENT_DIALOG_BUTTONS
+	
+	setWhatsThis ("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 (qOutput);
+	layout->addWidget (qButtons);
+	setLayout (layout);
+	
+	updateOutput ();
+}
+
+// =============================================================================
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// =============================================================================
+bool KeySequenceDialog::staticDialog (actionmeta& meta, QWidget* parent) {
+	KeySequenceDialog dlg (*meta.conf, parent);
+	
+	if (dlg.exec () == false)
+		return false;
+	
+	*meta.conf = dlg.seq;
+	(*meta.qAct)->setShortcut (*meta.conf);
+	return true;
+}
+
+// =============================================================================
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// =============================================================================
+void KeySequenceDialog::updateOutput () {
+	str zShortcut = seq.toString ();
+	
+	str zText = str::mkfmt ("<center><b>%s</b></center>", zShortcut.chars ());
+	
+	qOutput->setText (zText);
+}
+
+// =============================================================================
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// =============================================================================
+void KeySequenceDialog::keyPressEvent (QKeyEvent* ev) {
+	seq = ev->key ();
+	
+	switch (seq) {
+	case Qt::Key_Shift:
+	case Qt::Key_Control:
+	case Qt::Key_Alt:
+	case Qt::Key_Meta:
+		seq = 0;
+		break;
+	
+	default:
+		break;
+	}
+	
+	seq = (seq | ev->modifiers ());
+	
+	updateOutput ();
 }
\ No newline at end of file
--- a/zz_configDialog.h	Mon Apr 08 19:24:23 2013 +0300
+++ b/zz_configDialog.h	Tue Apr 09 14:06:40 2013 +0300
@@ -23,11 +23,17 @@
 #include <qdialogbuttonbox.h>
 #include <qpushbutton.h>
 #include <qcheckbox.h>
+#include <qlistwidget.h>
 
 class ConfigDialog : public QDialog {
 	Q_OBJECT
 	
 public:
+	QTabWidget* qTabs;
+	QWidget* qMainTab, *qShortcutsTab;
+	
+	// =========================================================================
+	// Main tab widgets
 	QLabel* qLDrawPathLabel;
 	QLabel* qGLBackgroundLabel, *qGLForegroundLabel, *qGLForegroundAlphaLabel;
 	QLabel* qGLLineThicknessLabel;
@@ -37,6 +43,12 @@
 	QCheckBox* qLVColorize, *qGLColorBFC;
 	QSlider* qGLForegroundAlpha, *qGLLineThickness;
 	
+	// =========================================================================
+	// Shortcuts tab
+	QListWidget* qShortcutList;
+	QPushButton* qBTN_setShortcut, *qBTN_resetShortcut;
+	std::vector<QListWidgetItem*> qaShortcutItems;
+	
 	QDialogButtonBox* qButtons;
 	
 	ConfigDialog (ForgeWindow* parent);
@@ -44,12 +56,40 @@
 	static void staticDialog (ForgeWindow* window);
 	
 private:
+	void initMainTab ();
+	void initShortcutsTab ();
+	
 	void makeSlider (QSlider*& qSlider, short int dMin, short int dMax, short int dDefault);
-    void setButtonBackground (QPushButton* qButton, str zValue);
-    void pickColor (strconfig& cfg, QPushButton* qButton);
+	void setButtonBackground (QPushButton* qButton, str zValue);
+	void pickColor (strconfig& cfg, QPushButton* qButton);
+	void setShortcutText (QListWidgetItem* qItem, actionmeta meta);
+	long getItemRow (QListWidgetItem* qItem);
 	
 private slots:
 	void slot_findLDrawPath ();
 	void slot_setGLBackground ();
 	void slot_setGLForeground ();
+	void slot_setShortcut ();
+	void slot_resetShortcut ();
+};
+
+// =============================================================================
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// =============================================================================
+class KeySequenceDialog : public QDialog {
+	Q_OBJECT
+	
+public:
+	explicit KeySequenceDialog (QKeySequence seq, QWidget* parent = nullptr, Qt::WindowFlags f = 0);
+	static bool staticDialog (actionmeta& meta, QWidget* parent = nullptr);
+	
+	QLabel* qOutput;
+	QDialogButtonBox* qButtons;
+	QKeySequence seq;
+	
+private:
+	void updateOutput ();
+	
+private slots:
+	virtual void keyPressEvent (QKeyEvent* ev);
 };
\ No newline at end of file

mercurial