Tue, 09 Apr 2013 14:06:40 +0300
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