From 89f98f504add4ecba5e7aed79f9a479a76416793 Mon Sep 17 00:00:00 2001 From: f4exb Date: Thu, 4 Jan 2018 11:11:53 +0100 Subject: [PATCH] Commands: implemented management GUI --- doc/img/bin.xcf | Bin 0 -> 23570 bytes doc/img/keyboard.xcf | Bin 0 -> 44272 bytes doc/img/load.xcf | Bin 0 -> 19590 bytes doc/img/save.xcf | Bin 0 -> 11962 bytes sdrbase/CMakeLists.txt | 2 + {sdrgui => sdrbase}/commands/command.cpp | 37 ++- {sdrgui => sdrbase}/commands/command.h | 46 ++- sdrbase/sdrbase.pro | 4 +- sdrbase/settings/mainsettings.cpp | 68 +++- sdrbase/settings/mainsettings.h | 11 + sdrgui/CMakeLists.txt | 9 +- sdrgui/gui/commanditem.cpp | 28 ++ sdrgui/gui/commanditem.h | 26 ++ sdrgui/gui/editcommanddialog.cpp | 252 +++++++++++++++ sdrgui/gui/editcommanddialog.h | 75 +++++ sdrgui/gui/editcommanddialog.ui | 270 ++++++++++++++++ sdrgui/mainwindow.cpp | 224 +++++++++++-- sdrgui/mainwindow.h | 7 + sdrgui/mainwindow.ui | 380 ++++++++++++----------- sdrgui/resources/bin.png | Bin 0 -> 382 bytes sdrgui/resources/duplicate.png | Bin 0 -> 366 bytes sdrgui/resources/keyboard.png | Bin 0 -> 588 bytes sdrgui/resources/load.png | Bin 0 -> 492 bytes sdrgui/resources/res.qrc | 5 + sdrgui/resources/save.png | Bin 0 -> 565 bytes sdrgui/sdrgui.pro | 5 + 26 files changed, 1228 insertions(+), 221 deletions(-) create mode 100644 doc/img/bin.xcf create mode 100644 doc/img/keyboard.xcf create mode 100644 doc/img/load.xcf create mode 100644 doc/img/save.xcf rename {sdrgui => sdrbase}/commands/command.cpp (71%) rename {sdrgui => sdrbase}/commands/command.h (63%) create mode 100644 sdrgui/gui/commanditem.cpp create mode 100644 sdrgui/gui/commanditem.h create mode 100644 sdrgui/gui/editcommanddialog.cpp create mode 100644 sdrgui/gui/editcommanddialog.h create mode 100644 sdrgui/gui/editcommanddialog.ui create mode 100644 sdrgui/resources/bin.png create mode 100644 sdrgui/resources/duplicate.png create mode 100644 sdrgui/resources/keyboard.png create mode 100644 sdrgui/resources/load.png create mode 100644 sdrgui/resources/save.png diff --git a/doc/img/bin.xcf b/doc/img/bin.xcf new file mode 100644 index 0000000000000000000000000000000000000000..bcf620583dfb92e26f94db5091f6fa1d2b8b468f GIT binary patch literal 23570 zcmeHOTWnm_61tP385D`@xiP)L90fEO}qMWEC znzMCX*Tm}&u&kfuW0RT7Q?u#h?A6RAHtB&8bS^F}&!rQK3v-!EUGdJD+3AJ3g{z59 zw@6-{y*QQV@9lSwbte*FoKVbCcJy_EzyBdql2zmC=vAGROEbp0_`Jb!zd&|Tf#ms#2?By#<%gOua78cW&daumS>L%TyL!+S4Fhnd{*J$j@)>%NKqHA=-30vRo zt5^H#HNJWs>w2y|s#vl2TS>5e;a}0`y$f>`u@YSdMt@KImH1%o|7C9iWxwVlDP`qt z#Q%VbPe|4Uf`nEs5U&DNza>5;{>ARFKe5M1;@^o6iI0HYe*mh7h`#_e_YrKb`yIjd zI<__N-Hk*O@7YJ}e;;UNUt0f3@O^iG2DB0PehwTY4u1h0`I7jW_!j8mbGnJ-pMgFi z#b*t$Ujq(t4H*0tF!XQW#1wFn&mK+!BPrq(!TyY#C;0z}ArHv+(O(eni5E^i3;`$B zZ|cyugYbI6-jKhxeh(6+6$j0J95(xK#5AMRG@;Av#Zl9UZnFnHrU6M)k6ss|pcefu zYLGG()i`E0gA-XH2imsvZHGwNVN%vfs*aMPZc@}kijt&A)MzY3iKW6)Fkp7WV$j54 zF=Te(W;l_zNExMSJKtvdP`9IS<;O~PUb%G{mlTQT;%^mBm`a>96*y(eF>In3H4%)N z8x-7Kudg$GoU(C5%m~WNDO8vfs4~Y9Geg*A1`#*MP;FAEG5x4@8PlSG5*!5$ag zXf#K$*L0!DMJJlg5$to(ffjQZ`*S#iyNty_v>JmTet&&qVL3~d5A&^KWU*5{k$a-Ve4TdFhBhDC%>f)TccH_yY&yv_ z!8ExvsWh4N^y4Px;sohF=?-`$2V8?*;l6pqlu?O9%C(ogH%=;ht7t^ zGnjCqR0i=rPK`lMmlSPNuWNnx(01*mRhD&brj>4Sr<|sp?3*9A>j~qWYEl52j+&mD zrdE=y4fO2ds;%^FW*lB0Zv6>x)q&Ka?1JpD-etWE>v>pjB){}}aXX$-P1=Widi{mc6|N4}u7<+ZfnP_4^>B4iaw~;!b-?eTrQ!vLbgsYZ34P;`1L5kR zP%k>D*9B#D;FMnr?7nWHU;aa1zVv)~|CooLyu+{lp{(k7yh8(z4{d%YTH{tjC zyl5VI=!JTK#eAK@tMf7JM%XIK)`P;ZEk+rEJI2s#!SChlR9*3s7G9=KmXvXQn;*{mX~IcmslX^!rqh+5ccpJkHW}O$kz3&?@{p$kwLGe&v5l)A=}V7>w!1sdJdB<0>m(SFvvPz|r&Q)fO4ewWI zzx1=h`IV(31<|XEM|h#)|DE{TjKJRF{q=6DT^Bp@uG=ZGSFVAQas;^r;%V*Qa$I-Q zh~3;|6dNjj4HVdxYgiNwc-S zYnZADrRnmp`LDV)dyGBf>jB%xUI8Y*A^rorpx5%SJsf`n7=M%aCBYon@&5v+GsI=$ zWrFvfUM6uP1oKBHE)b++;^)A94-w~xCz+SsNAUVHeG8vq_79v=dp5SY9A#2D}-@f2}>0(hEu<_z$x@Br~J@SJc1 z_{pDu=b5wnQ@(pr;QJ@}-pLg4GvY1c9fCQxlV6DwoIk7B=IqaH&B*lAsd|7@60dKV zdMG7wQ_^5i^6)%44ztfT&31C46SNk^k@gdAQwD3=8a?oDS`QT=rT;Uq~4m1Mh>tPD)`hygM`oB_C588iPU34T@ez4vB>~_4}inryhY@=_!h0g6(?NjIWs#ka-=$Oa?{|BOY Bu|@y@ literal 0 HcmV?d00001 diff --git a/doc/img/keyboard.xcf b/doc/img/keyboard.xcf new file mode 100644 index 0000000000000000000000000000000000000000..69f97d5659cab52995417f4d37f51f2daba8d6b4 GIT binary patch literal 44272 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 L@#PX~y1x9s;sS=e literal 0 HcmV?d00001 diff --git a/doc/img/load.xcf b/doc/img/load.xcf new file mode 100644 index 0000000000000000000000000000000000000000..aefc3e946b892add63dc2c90ce282db44ffff7d9 GIT binary patch literal 19590 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 H)e`z2Dc1kE literal 0 HcmV?d00001 diff --git a/doc/img/save.xcf b/doc/img/save.xcf new file mode 100644 index 0000000000000000000000000000000000000000..7582c32e55ef086bc6f69707ce2fc01de8b7c538 GIT binary patch literal 11962 zcmeHNTWnNS6y5Uzie-4TrSCF8AJan10P;{qrf3ZYkdy=yVj8rRc4!!ALkB1caX?Lc z{LsWd6%&YwHKKly7{5%TKZL{&5@{lWAI2bxMttz>oU>i~&b=^G=24&}mCkK;*S_bT zbI&>Z?0ffFvv06-SGT9Pt;5sN8EPjSr%VxjCd6jLzdXp4r~91mi$KqZI3ae(Y*Uwd z1*l&JoDsxr>pOR~2HWd{dpftHh;ZFT-k$J*P`jt6E7ZBYcB;1{*wz*5+T-yWP`@X* zt<~de@EJ!EWwCjw7EQM$X=+{fq*kP9Z%=n?Tj%beXR*~63J)YJG|TGu?(PhGI(N72 zXz!8sT^$`g?cv)4l-73_#Yz&JiXF_u_L`*uEu)JKr}eb%Ykz4^>;8uB-9f1%MwVj| zM2yamDW)zBa!egSVtlD1$5e==KNhFw#_7}I^y$#$zSc1riq$@T!OiRTMpLl{kGl32 zqK4y;&l0cM`!W2}80tYH_vi4B0r<)Z_|86}5;#!BAW>xqa)YRLJ=$aJ4bMX0k`3?5 zy(0D_gJZc~r{b(~M~{#(eisGet11J9sEJRR}RO^dmTN(`x{VivK^E2)$x zkrVeS#oI%$jGYFSv%|m&wi`HyZ3cQ+6FX2*2Jo6m=eYzWLC~K&C8a#1cVaJZH}7+v%UN~DpI5N%iMu@icEyRS%|USY zl4h)k4evNR-fs@P+s0BRNQb>Jsp5lhY#Zyt@MiesGPp3nKd!-*k;z$sO(Lu?L5ZyC z7~{QOE8$8+M7acoqRg904ix#&~0M4Bm^y@T-MJ z4A&n4z(acx$q~Wdb{Y{pdS;!?2;D;$j=bpi<@nP7JTuaVt(f&-e|f(P`(6DeV)OWc zT+&NJ?vOb$ob|FBPp>h+yUyHY?y~!xLpi15v=Q3?MVtd1aS=sqgbg;0Vcn5%vf2~5 zCuCFsU&PtSfqofTAQYiP94M2~2|KZ#xppF6^^1T z#v3+XGT%Ep?#wnyy+-l27CrO5?(COGy6K(6juZL~*_r>!bKprjk39lg0i~pD-x{bx zJQuE|p1BDuCe?C{=fTC)qLW<7dA^~Qn+~7mh%?AF{rYQggBsEs#tRgM^hUy)WdnX} z)L#zQ3b?3D7sN{Mf81laqt4!YY#B?|z7KBSaZh`)158Uzg*{m;DHV&d%B^~t(5gQi zGqscJ!`lo$AIUxLuTJs}w&YDEe=2#@tgS3x$=Yhe)=`_cz@T+h+=A^I3Qq|wb z;8+aS8=&mpA-RoYcR(T8jokM>08-(56;k2ge`it1NWM`M=SAy}s zcJW-Zs98Tboa5c$ePDZjz3@TVULw0Kis~7k?mEV;!_~flaMu(?`q}y+KBB?8eKhg1|K)#dq>;a_s;%{ zpCF~WY_8JbYWdK}k1DTHa@Eh#U$zo + Command::Command() { resetToDefaults(); @@ -31,8 +33,9 @@ void Command::resetToDefaults() m_description = "no name"; m_command = ""; m_argString = ""; - m_pressKey = static_cast(0); - m_releaseKey = static_cast(0); + m_key = static_cast(0); + m_associateKey = false; + m_release = false; } QByteArray Command::serialize() const @@ -43,8 +46,10 @@ QByteArray Command::serialize() const s.writeString(2, m_description); s.writeString(3, m_command); s.writeString(4, m_argString); - s.writeS32(5, (int) m_pressKey); - s.writeS32(6, (int) m_releaseKey); + s.writeS32(5, (int) m_key); + s.writeS32(6, (int) m_keyModifiers); + s.writeBool(7, m_associateKey); + s.writeBool(8, m_release); return s.final(); } @@ -69,9 +74,11 @@ bool Command::deserialize(const QByteArray& data) d.readString(3, &m_command, ""); d.readString(4, &m_argString, ""); d.readS32(5, &tmpInt, 0); - m_pressKey = static_cast(tmpInt); + m_key = static_cast(tmpInt); d.readS32(6, &tmpInt, 0); - m_releaseKey = static_cast(tmpInt); + m_keyModifiers = static_cast(tmpInt); + d.readBool(7, &m_associateKey, false); + d.readBool(8, &m_release, false); return true; } @@ -81,3 +88,21 @@ bool Command::deserialize(const QByteArray& data) return false; } } + +QString Command::getKeyLabel() const +{ + if (m_key == 0) + { + return ""; + } + else if (m_keyModifiers != Qt::NoModifier) + { + QString altGrStr = m_keyModifiers & Qt::GroupSwitchModifier ? "Gr " : ""; + int maskedModifiers = (m_keyModifiers & 0x3FFFFFFF) + ((m_keyModifiers & 0x40000000)>>3); + return altGrStr + QKeySequence(maskedModifiers, m_key).toString(); + } + else + { + return QKeySequence(m_key).toString(); + } +} diff --git a/sdrgui/commands/command.h b/sdrbase/commands/command.h similarity index 63% rename from sdrgui/commands/command.h rename to sdrbase/commands/command.h index cca9e0bc7..76fc21047 100644 --- a/sdrgui/commands/command.h +++ b/sdrbase/commands/command.h @@ -20,6 +20,7 @@ #include #include #include +#include class Command { @@ -39,20 +40,51 @@ public: const QString& getGroup() const { return m_group; } void setDescription(const QString& description) { m_description = description; } const QString& getDescription() const { return m_description; } - void setPressKey(Qt::Key key) { m_pressKey = key; } - Qt::Key getPressKey() const { return m_pressKey; } - void setReleaseKey(Qt::Key key) { m_releaseKey = key; } - Qt::Key getReleaseKey() const { return m_releaseKey; } + void setKey(Qt::Key key) { m_key = key; } + Qt::Key getKey() const { return m_key; } + void setKeyModifiers(Qt::KeyboardModifiers keyModifiers) { m_keyModifiers = keyModifiers; } + Qt::KeyboardModifiers getKeyModifiers() const { return m_keyModifiers; } + void setAssociateKey(bool associate) { m_associateKey = associate; } + bool getAssociateKey() const { return m_associateKey; } + void setRelease(bool release) { m_release = release; } + bool getRelease() const { return m_release; } + + QString getKeyLabel() const; + + static bool commandCompare(const Command *c1, Command *c2) + { + if (c1->m_group != c2->m_group) + { + return c1->m_group < c2->m_group; + } + else + { + if (c1->m_description != c2->m_description) { + return c1->m_description < c2->m_description; + } + else + { + if (c1->m_key != c2->m_key) { + return c1->m_key < c2->m_key; + } else { + return c1->m_release; + } + } + } + } private: QString m_command; QString m_argString; QString m_group; QString m_description; - Qt::Key m_pressKey; - Qt::Key m_releaseKey; + Qt::Key m_key; + Qt::KeyboardModifiers m_keyModifiers; + bool m_associateKey; + bool m_release; }; - +Q_DECLARE_METATYPE(const Command*); +Q_DECLARE_METATYPE(Command*); #endif /* SDRBASE_COMMANDS_COMMAND_H_ */ diff --git a/sdrbase/sdrbase.pro b/sdrbase/sdrbase.pro index 20ed349e9..ecef3b911 100644 --- a/sdrbase/sdrbase.pro +++ b/sdrbase/sdrbase.pro @@ -53,6 +53,7 @@ SOURCES += audio/audiodeviceinfo.cpp\ audio/audioinput.cpp\ channel/channelsinkapi.cpp\ channel/channelsourceapi.cpp\ + commands/command.cpp\ device/devicesourceapi.cpp\ device/devicesinkapi.cpp\ device/deviceenumerator.cpp\ @@ -119,7 +120,8 @@ HEADERS += audio/audiodeviceinfo.h\ audio/audiooutput.h\ audio/audioinput.h\ channel/channelsinkapi.h\ - channel/channelsourceapi.h\ + channel/channelsourceapi.h\ + commands/command.h\ device/devicesourceapi.h\ device/devicesinkapi.h\ device/deviceenumerator.h\ diff --git a/sdrbase/settings/mainsettings.cpp b/sdrbase/settings/mainsettings.cpp index 75d8ab5e2..7e4a15a37 100644 --- a/sdrbase/settings/mainsettings.cpp +++ b/sdrbase/settings/mainsettings.cpp @@ -2,6 +2,7 @@ #include #include "settings/mainsettings.h" +#include "commands/command.h" MainSettings::MainSettings() { @@ -14,6 +15,11 @@ MainSettings::~MainSettings() { delete m_presets[i]; } + + for(int i = 0; i < m_commands.count(); ++i) + { + delete m_commands[i]; + } } void MainSettings::load() @@ -32,7 +38,7 @@ void MainSettings::load() for(int i = 0; i < groups.size(); ++i) { - if(groups[i].startsWith("preset")) + if (groups[i].startsWith("preset")) { s.beginGroup(groups[i]); Preset* preset = new Preset; @@ -48,6 +54,22 @@ void MainSettings::load() s.endGroup(); } + else if (groups[i].startsWith("command")) + { + s.beginGroup(groups[i]); + Command* command = new Command; + + if(command->deserialize(qUncompress(QByteArray::fromBase64(s.value("data").toByteArray())))) + { + m_commands.append(command); + } + else + { + delete command; + } + + s.endGroup(); + } } } @@ -67,19 +89,27 @@ void MainSettings::save() const for(int i = 0; i < groups.size(); ++i) { - if(groups[i].startsWith("preset")) + if ((groups[i].startsWith("preset")) || (groups[i].startsWith("command"))) { s.remove(groups[i]); } } - for(int i = 0; i < m_presets.count(); ++i) + for (int i = 0; i < m_presets.count(); ++i) { QString group = QString("preset-%1").arg(i + 1); s.beginGroup(group); s.setValue("data", qCompress(m_presets[i]->serialize()).toBase64()); s.endGroup(); } + + for (int i = 0; i < m_commands.count(); ++i) + { + QString group = QString("command-%1").arg(i + 1); + s.beginGroup(group); + s.setValue("data", qCompress(m_commands[i]->serialize()).toBase64()); + s.endGroup(); + } } void MainSettings::resetToDefaults() @@ -124,3 +154,35 @@ const Preset* MainSettings::getPreset(const QString& groupName, quint64 centerFr return 0; } + +void MainSettings::addCommand(Command *command) +{ + m_commands.append(command); +} + +void MainSettings::deleteCommand(const Command* command) +{ + m_commands.removeAll((Command*)command); + delete (Command*)command; +} + +void MainSettings::sortCommands() +{ + qSort(m_commands.begin(), m_commands.end(), Command::commandCompare); +} + +const Command* MainSettings::getCommand(const QString& groupName, const QString& description) const +{ + int nbCommands = getCommandCount(); + + for (int i = 0; i < nbCommands; i++) + { + if ((getCommand(i)->getGroup() == groupName) && + (getCommand(i)->getDescription() == description)) + { + return getCommand(i); + } + } + + return 0; +} diff --git a/sdrbase/settings/mainsettings.h b/sdrbase/settings/mainsettings.h index da82e3563..6edb0c98a 100644 --- a/sdrbase/settings/mainsettings.h +++ b/sdrbase/settings/mainsettings.h @@ -6,6 +6,8 @@ #include "preset.h" #include "audio/audiodeviceinfo.h" +class Command; + class MainSettings { public: MainSettings(); @@ -23,6 +25,13 @@ public: const Preset* getPreset(const QString& groupName, quint64 centerFrequency, const QString& description) const; void sortPresets(); + void addCommand(Command *command); + void deleteCommand(const Command* command); + int getCommandCount() const { return m_commands.count(); } + const Command* getCommand(int index) const { return m_commands[index]; } + const Command* getCommand(const QString& groupName, const QString& description) const; + void sortCommands(); + Preset* getWorkingPreset() { return &m_workingPreset; } int getSourceIndex() const { return m_preferences.getSourceIndex(); } void setSourceIndex(int value) { m_preferences.setSourceIndex(value); } @@ -52,6 +61,8 @@ protected: Preset m_workingPreset; typedef QList Presets; Presets m_presets; + typedef QList Commands; + Commands m_commands; }; #endif // INCLUDE_SETTINGS_H diff --git a/sdrgui/CMakeLists.txt b/sdrgui/CMakeLists.txt index d907d9480..cc10f3c5b 100644 --- a/sdrgui/CMakeLists.txt +++ b/sdrgui/CMakeLists.txt @@ -9,7 +9,9 @@ set(sdrgui_SOURCES gui/channelwindow.cpp gui/clickablelabel.cpp gui/colormapper.cpp + gui/commanditem.cpp gui/cwkeyergui.cpp + gui/editcommanddialog.cpp gui/externalclockbutton.cpp gui/externalclockdialog.cpp gui/glscope.cpp @@ -40,8 +42,6 @@ set(sdrgui_SOURCES gui/valuedial.cpp gui/valuedialz.cpp - commands/command.cpp - dsp/scopevis.cpp dsp/scopevisng.cpp dsp/scopevismulti.cpp @@ -62,7 +62,9 @@ set(sdrgui_HEADERS gui/buttonswitch.h gui/channelwindow.h gui/colormapper.h + gui/commanditem.h gui/cwkeyergui.h + gui/editcommanddialog.h gui/externalclockbutton.h gui/externalclockdialog.h gui/glscope.h @@ -94,8 +96,6 @@ set(sdrgui_HEADERS gui/valuedial.h gui/valuedialz.h - commands/command.h - dsp/scopevis.h dsp/scopevisng.h dsp/scopevismulti.h @@ -119,6 +119,7 @@ set(sdrgui_FORMS gui/addpresetdialog.ui gui/basicchannelsettingsdialog.ui gui/cwkeyergui.ui + gui/editcommanddialog.ui gui/externalclockdialog.ui gui/glscopegui.ui gui/glscopenggui.ui diff --git a/sdrgui/gui/commanditem.cpp b/sdrgui/gui/commanditem.cpp new file mode 100644 index 000000000..f35920a05 --- /dev/null +++ b/sdrgui/gui/commanditem.cpp @@ -0,0 +1,28 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Edouard Griffiths, F4EXB // +// // +// 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 as version 3 of the License, or // +// // +// 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 V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "commanditem.h" + +CommandItem::CommandItem(QTreeWidgetItem* parent, const QStringList& strings, const QString& description, int type) : + QTreeWidgetItem(parent, strings, type), + m_description(description) +{ +} + +bool CommandItem::operator<(const QTreeWidgetItem& other) const +{ + return m_description < ((const CommandItem&)other).m_description; +} diff --git a/sdrgui/gui/commanditem.h b/sdrgui/gui/commanditem.h new file mode 100644 index 000000000..1ab492858 --- /dev/null +++ b/sdrgui/gui/commanditem.h @@ -0,0 +1,26 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Edouard Griffiths, F4EXB // +// // +// 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 as version 3 of the License, or // +// // +// 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 V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include + +class CommandItem : public QTreeWidgetItem { +public: + CommandItem(QTreeWidgetItem* parent, const QStringList& strings, const QString& description, int type); + bool operator<(const QTreeWidgetItem& other) const; + +private: + QString m_description; +}; diff --git a/sdrgui/gui/editcommanddialog.cpp b/sdrgui/gui/editcommanddialog.cpp new file mode 100644 index 000000000..e35c64869 --- /dev/null +++ b/sdrgui/gui/editcommanddialog.cpp @@ -0,0 +1,252 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Edouard Griffiths, F4EXB // +// // +// 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 as version 3 of the License, or // +// // +// 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 V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#include "editcommanddialog.h" +#include "ui_editcommanddialog.h" +#include "commands/command.h" + +#include +#include +#include +#include + +const std::vector EditCommandDialog::m_composeKeys = {Qt::Key_Shift, Qt::Key_Control, Qt::Key_Meta, Qt::Key_Alt, Qt::Key_AltGr}; + +EditCommandDialog::EditCommandDialog(const QStringList& groups, const QString& group, QWidget* parent) : + QDialog(parent), + ui(new Ui::EditCommandDialog), + m_key(static_cast(0)) +{ + ui->setupUi(this); + ui->group->addItems(groups); + ui->group->lineEdit()->setText(group); + setKeyAssociate(); + setKeyLabel(); +} + +EditCommandDialog::~EditCommandDialog() +{ + delete ui; +} + +QString EditCommandDialog::getGroup() const +{ + return ui->group->lineEdit()->text(); +} + +QString EditCommandDialog::getDescription() const +{ + return ui->description->text(); +} + +void EditCommandDialog::setGroup(const QString& group) +{ + ui->group->lineEdit()->setText(group); +} + +void EditCommandDialog::setDescription(const QString& description) +{ + ui->description->setText(description); +} + +QString EditCommandDialog::getCommand() const +{ + return ui->command->text(); +} + +void EditCommandDialog::setCommand(const QString& command) +{ + ui->command->setText(command); +} + +QString EditCommandDialog::getArguments() const +{ + return ui->args->text(); +} + +void EditCommandDialog::setArguments(const QString& arguments) +{ + ui->args->setText(arguments); +} + +Qt::Key EditCommandDialog::getKey() const +{ + return m_key; +} + +Qt::KeyboardModifiers EditCommandDialog::getKeyModifiers() const +{ + return m_keyModifiers; +} + +void EditCommandDialog::setKey(Qt::Key key, Qt::KeyboardModifiers modifiers) +{ + m_key = key; + m_keyModifiers = modifiers; + setKeyAssociate(); + setKeyLabel(); +} + +bool EditCommandDialog::getAssociateKey() const +{ + return ui->keyAssociate->isChecked(); +} + +void EditCommandDialog::setAssociateKey(bool release) +{ + ui->keyAssociate->setChecked(release); +} + +bool EditCommandDialog::getRelease() const +{ + return ui->keyRelease->isChecked(); +} + +void EditCommandDialog::setRelease(bool release) +{ + ui->keyRelease->setChecked(release); +} + +void EditCommandDialog::on_showFileDialog_clicked(bool checked __attribute__((unused))) +{ + QString commandFileName = ui->command->text(); + QFileInfo commandFileInfo(commandFileName); + QString commandFolderName = commandFileInfo.baseName(); + QFileInfo commandDirInfo(commandFolderName); + QString dirStr; + + if (commandFileInfo.exists()) { + dirStr = commandFileName; + } else if (commandDirInfo.exists()) { + dirStr = commandFolderName; + } else { + dirStr = "."; + } + + QString fileName = QFileDialog::getOpenFileName( + this, + tr("Select command"), + dirStr, + tr("Python (*.py);;Shell (*.sh *.bat);;Binary (*.bin *.exe);;All (*.*)")); + + if (fileName != "") { + ui->command->setText(fileName); + } +} + +void EditCommandDialog::on_keyCapture_toggled(bool checked) +{ + if (checked) + { + ui->keyCapture->setFocus(); + ui->keyCapture->setFocusPolicy(Qt::StrongFocus); + } + else + { + ui->keyCapture->setFocusPolicy(Qt::NoFocus); + ui->keyCapture->clearFocus(); + } +} + +void EditCommandDialog::keyPressEvent(QKeyEvent *e) +{ + if (ui->keyCapture->isChecked() && (!isComposeKey(static_cast(e->key())))) + { + m_key = static_cast(e->key()); + + if (e->modifiers()) + { + //qDebug("EditCommandDialog::keyPressEvent: has modifiers: %x", QFlags::Int(e->modifiers())); + m_keyModifiers = e->modifiers(); + } + else + { + m_keyModifiers = Qt::NoModifier; + } + + setKeyAssociate(); + setKeyLabel(); + //qDebug("EditCommandDialog::keyPressEvent: key: %x", m_key); + + ui->keyCapture->setChecked(false); + ui->keyCapture->setFocusPolicy(Qt::NoFocus); + ui->keyCapture->clearFocus(); + } +} + +void EditCommandDialog::toCommand(Command& command) const +{ + command.setGroup(ui->group->currentText()); + command.setDescription(ui->description->text()); + command.setCommand(ui->command->text()); + command.setArgString(ui->args->text()); + command.setAssociateKey(ui->keyAssociate->isChecked()); + command.setKey(m_key); + command.setKeyModifiers(m_keyModifiers); + command.setRelease(ui->keyRelease->isChecked()); +} + +void EditCommandDialog::fromCommand(const Command& command) +{ + ui->group->lineEdit()->setText(command.getGroup()); + ui->description->setText(command.getDescription()); + ui->command->setText(command.getCommand()); + ui->args->setText(command.getArgString()); + ui->keyAssociate->setChecked(command.getAssociateKey()); + m_key = command.getKey(); + m_keyModifiers = command.getKeyModifiers(); + setKeyAssociate(); + setKeyLabel(); + ui->keyRelease->setChecked(command.getRelease()); +} + +bool EditCommandDialog::isComposeKey(Qt::Key key) +{ + auto it = std::find(m_composeKeys.begin(), m_composeKeys.end(), key); + return it != m_composeKeys.end(); +} + +void EditCommandDialog::setKeyLabel() +{ + if (m_key == 0) + { + ui->keyLabel->setText(""); + } + else if (m_keyModifiers != Qt::NoModifier) + { + QString altGrStr = m_keyModifiers & Qt::GroupSwitchModifier ? "Gr " : ""; + int maskedModifiers = (m_keyModifiers & 0x3FFFFFFF) + ((m_keyModifiers & 0x40000000)>>3); + ui->keyLabel->setText(altGrStr + QKeySequence(maskedModifiers, m_key).toString()); + } + else + { + ui->keyLabel->setText(QKeySequence(m_key).toString()); + } +} + +void EditCommandDialog::setKeyAssociate() +{ + if (m_key == 0) + { + ui->keyAssociate->setChecked(false); + ui->keyAssociate->setEnabled(false); + } + else + { + ui->keyAssociate->setEnabled(true); + } +} + diff --git a/sdrgui/gui/editcommanddialog.h b/sdrgui/gui/editcommanddialog.h new file mode 100644 index 000000000..6f6184844 --- /dev/null +++ b/sdrgui/gui/editcommanddialog.h @@ -0,0 +1,75 @@ +/////////////////////////////////////////////////////////////////////////////////// +// Copyright (C) 2018 Edouard Griffiths, F4EXB // +// // +// 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 as version 3 of the License, or // +// // +// 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 V3 for more details. // +// // +// You should have received a copy of the GNU General Public License // +// along with this program. If not, see . // +/////////////////////////////////////////////////////////////////////////////////// + +#ifndef SDRGUI_GUI_EDITCOMMANDDIALOG_H_ +#define SDRGUI_GUI_EDITCOMMANDDIALOG_H_ + +#include +#include + +namespace Ui { + class EditCommandDialog; +} + +class Command; + +class EditCommandDialog : public QDialog { + Q_OBJECT + +public: + explicit EditCommandDialog(const QStringList& groups, const QString& group, QWidget* parent = 0); + ~EditCommandDialog(); + + QString getGroup() const; + void setGroup(const QString& group); + QString getDescription() const; + void setDescription(const QString& description); + QString getCommand() const; + void setCommand(const QString& command); + QString getArguments() const; + void setArguments(const QString& arguments); + Qt::Key getKey() const; + Qt::KeyboardModifiers getKeyModifiers() const; + void setKey(Qt::Key key, Qt::KeyboardModifiers modifiers); + bool getAssociateKey() const; + void setAssociateKey(bool associate); + bool getRelease() const; + void setRelease(bool release); + + void toCommand(Command& command) const; + void fromCommand(const Command& command); + +private: + Ui::EditCommandDialog* ui; + Qt::Key m_key; + Qt::KeyboardModifiers m_keyModifiers; + + virtual void keyPressEvent(QKeyEvent *e); + bool isComposeKey(Qt::Key key); + void setKeyLabel(); + void setKeyAssociate(); + + static const std::vector m_composeKeys; + +private slots: + void on_showFileDialog_clicked(bool checked); + void on_keyCapture_toggled(bool checked); + +}; + + + +#endif /* SDRGUI_GUI_EDITCOMMANDDIALOG_H_ */ diff --git a/sdrgui/gui/editcommanddialog.ui b/sdrgui/gui/editcommanddialog.ui new file mode 100644 index 000000000..6a052b533 --- /dev/null +++ b/sdrgui/gui/editcommanddialog.ui @@ -0,0 +1,270 @@ + + + EditCommandDialog + + + + 0 + 0 + 324 + 239 + + + + + Sans Serif + 9 + + + + Edit command + + + + + + Command Description + + + + + + &Group + + + group + + + + + + + Choose or create new group + + + true + + + + + + + &Description + + + description + + + + + + + Edit description + + + + + + + + + + + + + 0 + 0 + + + + Cmd + + + + + + + + 24 + 24 + + + + + 24 + 24 + + + + Choose command + + + + + + + :/load.png:/load.png + + + + + + + ... + + + + + + + + + + + Arg + + + + + + + Edit arguments + + + + + + + + + 6 + + + 6 + + + + + Associate key event to run the command + + + + + + + + + + Enter key to associate + + + Key + + + true + + + + + + + + 0 + 0 + + + + Associated key or composed key + + + .. + + + + + + + Run command on key release + + + Release + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+
+ + description + buttonBox + group + + + + + + + buttonBox + accepted() + EditCommandDialog + accept() + + + 257 + 194 + + + 157 + 203 + + + + + buttonBox + rejected() + EditCommandDialog + reject() + + + 314 + 194 + + + 286 + 203 + + + + +
diff --git a/sdrgui/mainwindow.cpp b/sdrgui/mainwindow.cpp index 2456dcf55..df81b5f5c 100644 --- a/sdrgui/mainwindow.cpp +++ b/sdrgui/mainwindow.cpp @@ -34,7 +34,9 @@ #include "audio/audiodeviceinfo.h" #include "gui/indicator.h" #include "gui/presetitem.h" +#include "gui/commanditem.h" #include "gui/addpresetdialog.h" +#include "gui/editcommanddialog.h" #include "gui/pluginsdialog.h" #include "gui/aboutdialog.h" #include "gui/rollupwidget.h" @@ -55,6 +57,7 @@ #include "webapi/webapirequestmapper.h" #include "webapi/webapiserver.h" #include "webapi/webapiadaptergui.h" +#include "commands/command.h" #include "mainwindow.h" #include "ui_mainwindow.h" @@ -514,6 +517,13 @@ void MainWindow::loadSettings() } } + m_settings.sortCommands(); + + for (int i = 0; i < m_settings.getCommandCount(); ++i) + { + treeItem = addCommandToTree(m_settings.getCommand(i)); + } + setLoggingOptions(); } @@ -646,6 +656,44 @@ QTreeWidgetItem* MainWindow::addPresetToTree(const Preset* preset) return item; } +QTreeWidgetItem* MainWindow::addCommandToTree(const Command* command) +{ + QTreeWidgetItem* group = 0; + + for(int i = 0; i < ui->commandTree->topLevelItemCount(); i++) + { + if(ui->commandTree->topLevelItem(i)->text(0) == command->getGroup()) + { + group = ui->commandTree->topLevelItem(i); + break; + } + } + + if(group == 0) + { + QStringList sl; + sl.append(command->getGroup()); + group = new QTreeWidgetItem(ui->commandTree, sl, PGroup); + group->setFirstColumnSpanned(true); + group->setExpanded(true); + ui->commandTree->sortByColumn(0, Qt::AscendingOrder); + } + + QStringList sl; + sl.append(QString("%1").arg(command->getDescription())); // Descriptions column + sl.append(QString("%1").arg(command->getKeyLabel())); // key column + sl.append(QString("%1").arg(command->getAssociateKey() ? command->getRelease() ? "R" : "P" : "")); // key press/release column + CommandItem* item = new CommandItem(group, sl, command->getDescription(), PItem); + item->setData(0, Qt::UserRole, qVariantFromValue(command)); + item->setTextAlignment(0, Qt::AlignLeft); + ui->presetTree->resizeColumnToContents(0); // Resize description column to minimum + ui->presetTree->resizeColumnToContents(1); // Resize key column to minimum + ui->presetTree->resizeColumnToContents(2); // Resize key press/release column to minimum + + //updatePresetControls(); + return item; +} + void MainWindow::applySettings() { } @@ -772,48 +820,170 @@ void MainWindow::on_action_View_Fullscreen_toggled(bool checked) else showNormal(); } +void MainWindow::on_commandNew_clicked() +{ + QStringList groups; + QString group = ""; + QString description = ""; + + for(int i = 0; i < ui->commandTree->topLevelItemCount(); i++) { + groups.append(ui->commandTree->topLevelItem(i)->text(0)); + } + + QTreeWidgetItem* item = ui->commandTree->currentItem(); + + if(item != 0) + { + if(item->type() == PGroup) { + group = item->text(0); + } else if(item->type() == PItem) { + group = item->parent()->text(0); + description = item->text(0); + } + } + + Command *command = new Command(); + command->setGroup(group); + command->setDescription(description); + EditCommandDialog editCommandDialog(groups, group, this); + editCommandDialog.fromCommand(*command); + + if (editCommandDialog.exec() == QDialog::Accepted) + { + editCommandDialog.toCommand(*command); + m_settings.addCommand(command); + ui->commandTree->setCurrentItem(addCommandToTree(command)); + m_settings.sortCommands(); + } +} + +void MainWindow::on_commandDuplicate_clicked() +{ + QTreeWidgetItem* item = ui->commandTree->currentItem(); + const Command* command = qvariant_cast(item->data(0, Qt::UserRole)); + Command *commandCopy = new Command(*command); + m_settings.addCommand(commandCopy); + ui->commandTree->setCurrentItem(addCommandToTree(commandCopy)); + m_settings.sortCommands(); +} + +void MainWindow::on_commandEdit_clicked() +{ + QTreeWidgetItem* item = ui->commandTree->currentItem(); + + if(item != 0) + { + if(item->type() == PItem) + { + const Command* command = qvariant_cast(item->data(0, Qt::UserRole)); + + if (command != 0) + { + QStringList groups; + + for(int i = 0; i < ui->commandTree->topLevelItemCount(); i++) { + groups.append(ui->commandTree->topLevelItem(i)->text(0)); + } + + EditCommandDialog editCommandDialog(groups, command->getGroup(), this); + editCommandDialog.fromCommand(*command); + + if (editCommandDialog.exec() == QDialog::Accepted) + { + Command* command_mod = const_cast(command); + editCommandDialog.toCommand(*command_mod); + m_settings.sortCommands(); + + ui->commandTree->clear(); + + for (int i = 0; i < m_settings.getCommandCount(); ++i) + { + QTreeWidgetItem *item_x = addCommandToTree(m_settings.getCommand(i)); + const Command* command_x = qvariant_cast(item_x->data(0, Qt::UserRole)); + if (command_x == command_mod) { + ui->commandTree->setCurrentItem(item_x); + } + } + } + } + } + } +} + +void MainWindow::on_commandDelete_clicked() +{ + QTreeWidgetItem* item = ui->commandTree->currentItem(); + + if(item == 0) { + return; + } + + const Command* command = qvariant_cast(item->data(0, Qt::UserRole)); + + if(command == 0) { + return; + } + + if (QMessageBox::question(this, + tr("Delete command"), + tr("Do you want to delete command '%1'?") + .arg(command->getDescription()), QMessageBox::No | QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) + { + delete item; + m_settings.deleteCommand(command); + } +} + void MainWindow::on_presetSave_clicked() { - QStringList groups; - QString group; - QString description = ""; - for(int i = 0; i < ui->presetTree->topLevelItemCount(); i++) - groups.append(ui->presetTree->topLevelItem(i)->text(0)); + QStringList groups; + QString group; + QString description = ""; - QTreeWidgetItem* item = ui->presetTree->currentItem(); - if(item != 0) { - if(item->type() == PGroup) - group = item->text(0); - else if(item->type() == PItem) { - group = item->parent()->text(0); - description = item->text(0); - } - } + for(int i = 0; i < ui->presetTree->topLevelItemCount(); i++) { + groups.append(ui->presetTree->topLevelItem(i)->text(0)); + } - AddPresetDialog dlg(groups, group, this); + QTreeWidgetItem* item = ui->presetTree->currentItem(); - if (description.length() > 0) { - dlg.setDescription(description); - } + if(item != 0) + { + if(item->type() == PGroup) { + group = item->text(0); + } else if(item->type() == PItem) { + group = item->parent()->text(0); + description = item->text(0); + } + } - if(dlg.exec() == QDialog::Accepted) { - Preset* preset = m_settings.newPreset(dlg.group(), dlg.description()); - savePresetSettings(preset, ui->tabInputsView->currentIndex()); + AddPresetDialog dlg(groups, group, this); - ui->presetTree->setCurrentItem(addPresetToTree(preset)); - } + if (description.length() > 0) { + dlg.setDescription(description); + } - m_settings.sortPresets(); + if(dlg.exec() == QDialog::Accepted) { + Preset* preset = m_settings.newPreset(dlg.group(), dlg.description()); + savePresetSettings(preset, ui->tabInputsView->currentIndex()); + + ui->presetTree->setCurrentItem(addPresetToTree(preset)); + } + + m_settings.sortPresets(); } void MainWindow::on_presetUpdate_clicked() { QTreeWidgetItem* item = ui->presetTree->currentItem(); - if(item != 0) { - if(item->type() == PItem) { + if(item != 0) + { + if(item->type() == PItem) + { const Preset* preset = qvariant_cast(item->data(0, Qt::UserRole)); - if (preset != 0) { + + if (preset != 0) + { Preset* preset_mod = const_cast(preset); savePresetSettings(preset_mod, ui->tabInputsView->currentIndex()); } diff --git a/sdrgui/mainwindow.h b/sdrgui/mainwindow.h index 414b77046..b92e1e85e 100644 --- a/sdrgui/mainwindow.h +++ b/sdrgui/mainwindow.h @@ -54,6 +54,8 @@ class QWidget; class WebAPIRequestMapper; class WebAPIServer; class WebAPIAdapterGUI; +class Preset; +class Command; namespace qtwebapp { class LoggerWithFile; @@ -317,6 +319,7 @@ private: void closeEvent(QCloseEvent*); void updatePresetControls(); QTreeWidgetItem* addPresetToTree(const Preset* preset); + QTreeWidgetItem* addCommandToTree(const Command* command); void applySettings(); void addSourceDevice(int deviceIndex); @@ -341,6 +344,10 @@ private slots: void on_presetDelete_clicked(); void on_presetTree_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); void on_presetTree_itemActivated(QTreeWidgetItem *item, int column); + void on_commandNew_clicked(); + void on_commandDuplicate_clicked(); + void on_commandEdit_clicked(); + void on_commandDelete_clicked(); void on_action_Audio_triggered(); void on_action_Logging_triggered(); void on_action_DV_Serial_triggered(bool checked); diff --git a/sdrgui/mainwindow.ui b/sdrgui/mainwindow.ui index 5d82b3bb3..aebc9b6da 100644 --- a/sdrgui/mainwindow.ui +++ b/sdrgui/mainwindow.ui @@ -318,173 +318,6 @@ 3 - - - - Save current settings as new preset - - - ... - - - - :/preset-save.png:/preset-save.png - - - - 16 - 16 - - - - - - - - Load selected preset - - - ... - - - - :/preset-load.png:/preset-load.png - - - - 16 - 16 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Delete selected preset - - - ... - - - - :/preset-delete.png:/preset-delete.png - - - - 16 - 16 - - - - - - - - Update selected preset with current settings - - - ... - - - - :/preset-update.png:/preset-update.png - - - - 16 - 16 - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Save the current settings (inc. presets) - - - ... - - - - :/preset-last.png:/preset-last.png - - - - 16 - 16 - - - - - - - - Export current preset to file - - - - - - - :/export.png:/export.png - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - Import preset from file into current group - - - - - - - :/import.png:/import.png - - - @@ -519,6 +352,160 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Save current settings as new preset + + + ... + + + + :/create.png:/create.png + + + + 16 + 16 + + + + + + + + Delete selected preset + + + ... + + + + :/bin.png:/bin.png + + + + 16 + 16 + + + + + + + + Update selected preset with current settings + + + ... + + + + :/edit.png:/edit.png + + + + 16 + 16 + + + + + + + + Import preset from file into current group + + + + + + + :/import.png:/import.png + + + + + + + Export current preset to file + + + + + + + :/export.png:/export.png + + + + + + + Save the current settings (inc. presets) + + + ... + + + + :/save.png:/save.png + + + + 16 + 16 + + + + + + + + Load selected preset + + + ... + + + + :/load.png:/load.png + + + + 16 + 16 + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -584,7 +571,7 @@ 2 - + 5 @@ -604,12 +591,12 @@ - Key press + Key - Key release + P/R @@ -642,6 +629,20 @@ + + + + Duplicate command + + + + + + + :/duplicate.png:/duplicate.png + + + @@ -694,7 +695,34 @@ - :/preset-last.png:/preset-last.png + :/save.png:/save.png + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Toggle keyboard to command connection + + + + + + + :/keyboard.png:/keyboard.png @@ -721,7 +749,7 @@ - :/preset-delete.png:/preset-delete.png + :/bin.png:/bin.png @@ -873,11 +901,17 @@ commandsDock + + + ButtonSwitch + QToolButton +
gui/buttonswitch.h
+
+
presetTree presetSave presetDelete - presetLoad diff --git a/sdrgui/resources/bin.png b/sdrgui/resources/bin.png new file mode 100644 index 0000000000000000000000000000000000000000..b20e354d6b17b20a8c72101703dc085964f8ac19 GIT binary patch literal 382 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1rX+877Y2q^y~;*F9%q3^Bv6!F z7=#%aX3YVqXD{*eb!C6V$igWnIHjs9hk=2S-_yl0#NzbZDf_*c9R=F=N1ivyRMSn?6X^Ff%`6t>IbwnTyeph1**(id*bEi)PRYiF1$BCtH92W~LrteRhNK z=d<%4Z5Nmk6~}O`V}aiDB?snc&u+W-z1>vZrO2B0BB-MUJdJ99FQ!V9Qy__=%rH^KydXCRW^GobIjm#OGAc7CyV(@hJb6Mw<&;$TFe3O0v literal 0 HcmV?d00001 diff --git a/sdrgui/resources/duplicate.png b/sdrgui/resources/duplicate.png new file mode 100644 index 0000000000000000000000000000000000000000..377d24db36223fc457abe4ba87191859505a564b GIT binary patch literal 366 zcmV-!0g?WRP)Yu#$_(E^i-j~&~zwq(nR2_Ee! z!FvnzycHW3=v#V)rUB-<5)C)#mD_L8*N_?w0}Lg;V5}+P2;<7@P+ZFc4x*2*B3}Gh z>OtWY7jcgdB3^uRWw4D={K6X%@r*SQ^+l}X=`VunNq5*(Zh*|;wytQoW~)4 zYKa%0XucY>O|c&_#JBQU*BHF|ahJG~h6@~ literal 0 HcmV?d00001 diff --git a/sdrgui/resources/keyboard.png b/sdrgui/resources/keyboard.png new file mode 100644 index 0000000000000000000000000000000000000000..dcf2489aed6cfdf004a1ee67c02a20475de12dc4 GIT binary patch literal 588 zcmV-S0<-;zP)5CYJdRimjyZPgn}J28^kKpn{i( zc7hh$D8!JBy2cC9^|5e1*(~d&&?odNZ_{~k90A`cMQ0$RWz zFbu2%C7=d;20j4?vZi;rZ!gdW1P%h5xvvgXBO;0pR9Dmq^@93RJ+02D_teYkqw z;BMx4T_o+M=ne1`7z2(0E5IJ$c+#~BjAzU<;0VwFUH~0n0%!tjX^%v~QPEDKot)RQ z!xpd)7y>qO&nWOQzdGyYC~OCXVbT+UP=3$+9?wC zYEWQM9RjLAS&f{QQg%@R%D_PS%0N{urfM7dQM8d`SWjwRC0(`D0pJkuK501$d`NqL zj_Xf~x(`?f9;9zF1Dt-*gm;Ukb<1^0000DBn literal 0 HcmV?d00001 diff --git a/sdrgui/resources/load.png b/sdrgui/resources/load.png new file mode 100644 index 0000000000000000000000000000000000000000..80b4e75158d89437216a5ec997af94217dc7646b GIT binary patch literal 492 zcmVUI13?hQf0wxkf-x!<3I_jx+NhO9niL9xg`KEKzz<+$u=6vBt%4vT#8NA<2v+HA zgb+k5EUkj*DMCypYoT8DE;$irtDV_l-h21v;D4ci&N@~(%K*l|8VXWYB-9Y|pD&Tc zA?}|ciaH??vjJVv?ZAChuk=DE!@yh%f*Y#L1LHa^)j(R|2dB|adVLnJB*oKfx~PUG z2a4QChcCw+TdmMtK~r4PL!JsJoVBQGXyMRB4=L72(a!`8zxKlImyWi$-$cb| z9c6)K3(^BS7#6i8rFJSoTuwPvv2=qtGmH??P}eznDOx0I956;wlXL*evozd*O+3=< z5w~(x`iQZP160W1*$qOOV}{$B|X iL-qrf)PMgZ{uG}j&U12GRF2XB0000dmA8 literal 0 HcmV?d00001 diff --git a/sdrgui/resources/res.qrc b/sdrgui/resources/res.qrc index f72d85d5a..27eaec90d 100644 --- a/sdrgui/resources/res.qrc +++ b/sdrgui/resources/res.qrc @@ -85,5 +85,10 @@ edit.png listing.png create.png + duplicate.png + bin.png + save.png + load.png + keyboard.png diff --git a/sdrgui/resources/save.png b/sdrgui/resources/save.png new file mode 100644 index 0000000000000000000000000000000000000000..ced55b2edf12cfab42456fe1723666d91547130f GIT binary patch literal 565 zcmV-50?Pe~P)~$mADbI$|kF9UE~FH9>7I>0QbItOJBgX zZe2+bB>@Q}lR-ujlZj?x9~Vx7boNs57W zU0R91Mz-Ke-WG-nD*v&Zq1or(v9sH9ht=2LqMlIkAgi=;V87CCy_+CaUB9PfcWU`x`h?=_q;z&Nl2RHH8RqaFZ% zJyB z0^fi{QU!RP=br~K4Ag+Bf)>5>H4dzJ=1agx2!MI;T0h1*3-AlrxJSH8U= zAMTT}q<2LC=1xPvi`3wR+(Vzt?9{&tYjD#kUrStgk+&`(MFyw<)e;P1-~#v^3eW;R z<_%84WS^H|Fj%q%u_yFB6yOms;k5{{0e=UA88m_Ik`i461DILjL)Vu{w#=Z!o_Xn? z05iMu#Ksxzo^