1 /* This file is part of Clementine.
2    Copyright 2010, David Sansome <me@davidsansome.com>
3 
4    Clementine is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8 
9    Clementine is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with Clementine.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 
18 #include "ui/iconloader.h"
19 #include "consts.h"
20 #include "shortcuts.h"
21 #include "wiimotesettingspage.h"
22 #include "wiimoteshortcutgrabber.h"
23 #include "ui_wiimotesettingspage.h"
24 
25 #include <QMessageBox>
26 
WiimoteSettingsPage(SettingsDialog * dialog)27 WiimoteSettingsPage::WiimoteSettingsPage(SettingsDialog* dialog)
28     : SettingsPage(dialog), ui_(new Ui_WiimoteSettingsPage) {
29   ui_->setupUi(this);
30   ui_->list->header()->setSectionResizeMode(QHeaderView::ResizeToContents);
31   setWindowIcon(IconLoader::Load("wiimotedev", IconLoader::Base));
32   ui_->wiimotedev_add_action->setIcon(IconLoader::Load("list-add",
33                                       IconLoader::Base));
34   ui_->wiimotedev_delete_action->setIcon(IconLoader::Load("list-remove",
35                                       IconLoader::Base));
36   ui_->wiimotedev_reload->setIcon(IconLoader::Load("view-refresh",
37                                       IconLoader::Base));
38 
39   text_buttons_.insert(WIIMOTE_BTN_1, "Wii Remote 1");
40   text_buttons_.insert(WIIMOTE_BTN_2, "Wii Remote 2");
41   text_buttons_.insert(WIIMOTE_BTN_A, "Wii Remote A");
42   text_buttons_.insert(WIIMOTE_BTN_B, "Wii Remote B");
43   text_buttons_.insert(WIIMOTE_BTN_PLUS, "Wii Remote ⊕");
44   text_buttons_.insert(WIIMOTE_BTN_MINUS, "Wii Remote ⊖");
45   text_buttons_.insert(WIIMOTE_BTN_HOME, "Wii Remote ⌂");
46   text_buttons_.insert(WIIMOTE_BTN_UP, "Wii Remote ↑");
47   text_buttons_.insert(WIIMOTE_BTN_DOWN, "Wii Remote ↓");
48   text_buttons_.insert(WIIMOTE_BTN_LEFT, "Wii Remote ←");
49   text_buttons_.insert(WIIMOTE_BTN_RIGHT, "Wii Remote →");
50   text_buttons_.insert(WIIMOTE_BTN_SHIFT_UP, "Wii Remote Shift ↑");
51   text_buttons_.insert(WIIMOTE_BTN_SHIFT_DOWN, "Wii Remote Shift ↓");
52   text_buttons_.insert(WIIMOTE_BTN_SHIFT_LEFT, "Wii Remote Shift ←");
53   text_buttons_.insert(WIIMOTE_BTN_SHIFT_RIGHT, "Wii Remote Shift →");
54   text_buttons_.insert(WIIMOTE_BTN_SHIFT_FORWARD, "Wii Remote Shift Forward");
55   text_buttons_.insert(WIIMOTE_BTN_SHIFT_BACKWARD, "Wii Remote Shift Backward");
56   text_buttons_.insert(WIIMOTE_BTN_TILT_FRONT, "Wii Remote Tilt Frontwards");
57   text_buttons_.insert(WIIMOTE_BTN_TILT_BACK, "Wii Remote Tilt Backwards");
58   text_buttons_.insert(WIIMOTE_BTN_TILT_LEFT, "Wii Remote Tilt Leftwards");
59   text_buttons_.insert(WIIMOTE_BTN_TILT_RIGHT, "Wii Remote Tilt Rightwards");
60   text_buttons_.insert(NUNCHUK_BTN_Z, "Nunchuk Z");
61   text_buttons_.insert(NUNCHUK_BTN_C, "Nunchuk B");
62   text_buttons_.insert(NUNCHUK_BTN_STICK_UP, "Nunchuk Stick ↑");
63   text_buttons_.insert(NUNCHUK_BTN_STICK_DOWN, "Nunchuk Stick ↓");
64   text_buttons_.insert(NUNCHUK_BTN_STICK_LEFT, "Nunchuk Stick ←");
65   text_buttons_.insert(NUNCHUK_BTN_STICK_RIGHT, "Nunchuk Stick →");
66   text_buttons_.insert(NUNCHUK_BTN_SHIFT_UP, "Nunchuk Shift ↑");
67   text_buttons_.insert(NUNCHUK_BTN_SHIFT_DOWN, "Nunchuk Shift ↓");
68   text_buttons_.insert(NUNCHUK_BTN_SHIFT_LEFT, "Nunchuk Shift ←");
69   text_buttons_.insert(NUNCHUK_BTN_SHIFT_RIGHT, "Nunchuk Shift →");
70   text_buttons_.insert(NUNCHUK_BTN_SHIFT_FORWARD, "Nunchuk Shift Forward");
71   text_buttons_.insert(NUNCHUK_BTN_SHIFT_BACKWARD, "Nunchuk Shift Backward");
72   text_buttons_.insert(NUNCHUK_BTN_TILT_FRONT, "Nunchuk Tilt Frontwards");
73   text_buttons_.insert(NUNCHUK_BTN_TILT_BACK, "Nunchuk Tilt Backwards");
74   text_buttons_.insert(NUNCHUK_BTN_TILT_LEFT, "Nunchuk Tilt Leftwards");
75   text_buttons_.insert(NUNCHUK_BTN_TILT_RIGHT, "Nunchuk Tilt Rightwards");
76   text_buttons_.insert(CLASSIC_BTN_X, "Classic X");
77   text_buttons_.insert(CLASSIC_BTN_Y, "Classic Y");
78   text_buttons_.insert(CLASSIC_BTN_A, "Classic A");
79   text_buttons_.insert(CLASSIC_BTN_B, "Classic B");
80   text_buttons_.insert(CLASSIC_BTN_L, "Classic L");
81   text_buttons_.insert(CLASSIC_BTN_R, "Classic R");
82   text_buttons_.insert(CLASSIC_BTN_ZL, "Classic ZL");
83   text_buttons_.insert(CLASSIC_BTN_ZR, "Classic ZR");
84   text_buttons_.insert(CLASSIC_BTN_MINUS, "Classic ⊖");
85   text_buttons_.insert(CLASSIC_BTN_PLUS, "Classic ⊕");
86   text_buttons_.insert(CLASSIC_BTN_HOME, "Classic ⌂");
87   text_buttons_.insert(CLASSIC_BTN_UP, "Classic ↑");
88   text_buttons_.insert(CLASSIC_BTN_DOWN, "Classic ↓");
89   text_buttons_.insert(CLASSIC_BTN_LEFT, "Classic ←");
90   text_buttons_.insert(CLASSIC_BTN_RIGHT, "Classic →");
91   text_buttons_.insert(CLASSIC_BTN_LSTICK_UP, "Classic Left-Stick ↑");
92   text_buttons_.insert(CLASSIC_BTN_LSTICK_DOWN, "Classic Left-Stick ↓");
93   text_buttons_.insert(CLASSIC_BTN_LSTICK_LEFT, "Classic Left-Stick ←");
94   text_buttons_.insert(CLASSIC_BTN_LSTICK_RIGHT, "Classic Left-Stick →");
95   text_buttons_.insert(CLASSIC_BTN_RSTICK_UP, "Classic Right-Stick ↑");
96   text_buttons_.insert(CLASSIC_BTN_RSTICK_DOWN, "Classic Right-Stick ↓");
97   text_buttons_.insert(CLASSIC_BTN_RSTICK_LEFT, "Classic Right-Stick ←");
98   text_buttons_.insert(CLASSIC_BTN_RSTICK_RIGHT, "Classic Right-Stick →");
99   text_buttons_.insert(WIIMOTE_BTN_SHIFT_SHAKE, "Wiiremote Shift Shake");
100   text_buttons_.insert(NUNCHUK_BTN_SHIFT_SHAKE, "Nunchuk Shift Shake");
101 
102   text_actions_.insert(WiimotedevShortcuts::WiimotedevActiveDeactive,
103                        tr("Activate/Deactivate Wii Remote"));
104   text_actions_.insert(WiimotedevShortcuts::PlayerNextTrack, tr("Next track"));
105   text_actions_.insert(WiimotedevShortcuts::PlayerPreviousTrack,
106                        tr("Previous track"));
107   text_actions_.insert(WiimotedevShortcuts::PlayerPlay, tr("Play"));
108   text_actions_.insert(WiimotedevShortcuts::PlayerStop, tr("Stop"));
109   text_actions_.insert(WiimotedevShortcuts::PlayerIncVolume,
110                        tr("Increase volume"));
111   text_actions_.insert(WiimotedevShortcuts::PlayerDecVolume,
112                        tr("Decrease volume"));
113   text_actions_.insert(WiimotedevShortcuts::PlayerMute, tr("Mute"));
114   text_actions_.insert(WiimotedevShortcuts::PlayerPause, tr("Pause"));
115   text_actions_.insert(WiimotedevShortcuts::PlayerTogglePause,
116                        tr("Play/Pause"));
117   text_actions_.insert(WiimotedevShortcuts::PlayerSeekBackward,
118                        tr("Seek backward"));
119   text_actions_.insert(WiimotedevShortcuts::PlayerSeekForward,
120                        tr("Seek forward"));
121   text_actions_.insert(WiimotedevShortcuts::PlayerStopAfter, tr("Stop after"));
122   text_actions_.insert(WiimotedevShortcuts::PlayerShowOSD, tr("Show OSD"));
123 
124   connect(ui_->list,
125           SIGNAL(currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)),
126           SLOT(ItemClicked(QTreeWidgetItem*)));
127 
128   connect(ui_->wiimotedev_add_action, SIGNAL(clicked()), this,
129           SLOT(AddAction()));
130   connect(ui_->wiimotedev_delete_action, SIGNAL(clicked()), this,
131           SLOT(DeleteAction()));
132   connect(ui_->wiimotedev_reload, SIGNAL(clicked()), this,
133           SLOT(DefaultSettings()));
134 }
135 
AddShortcut(quint64 button,quint32 action)136 void WiimoteSettingsPage::AddShortcut(quint64 button, quint32 action) {
137   for (const Shortcut& shortcut : actions_) {
138     if (shortcut.button == button) {
139       QMessageBox::information(this, tr("Information"),
140                                QString(tr("Shortcut for %1 already exists"))
141                                    .arg(GetReadableWiiremoteSequence(button)),
142                                QMessageBox::Ok);
143       return;
144     }
145   }
146 
147   Shortcut s;
148   s.object = new QTreeWidgetItem(
149       ui_->list, QStringList() << GetReadableWiiremoteSequence(button)
150                                << text_actions_[action]);
151   s.button = button;
152   s.action = action;
153   actions_ << s;
154 }
155 
Load()156 void WiimoteSettingsPage::Load() {
157   QSettings s;
158   s.beginGroup(WiimotedevShortcuts::kSettingsGroup);
159   ui_->wiimotedev_enable->setChecked(s.value("enabled", false).toBool());
160   ui_->wiimotedev_active->setChecked(
161       s.value("use_active_action", true).toBool());
162   ui_->wiimotedev_focus->setChecked(
163       s.value("only_when_focused", false).toBool());
164   ui_->wiimotedev_notification->setChecked(
165       s.value("use_notification", true).toBool());
166   ui_->wiimotedev_device->setValue(s.value("device", 1).toUInt());
167   bool first_conf = s.value("first_conf", true).toBool();
168   s.endGroup();
169 
170   if (first_conf) {
171     DefaultSettings();
172     return;
173   }
174 
175   s.beginGroup(WiimotedevShortcuts::kActionsGroup);
176   ui_->list->clear();
177   actions_.clear();
178 
179   quint64 fvalue, svalue;
180   bool fvalid, svalid;
181 
182   for (const QString& str : s.allKeys()) {
183     fvalue = str.toULongLong(&fvalid, 10);
184     svalue = s.value(str, 0).toULongLong(&svalid);
185     if (fvalid && svalid) AddShortcut(fvalue, svalue);
186   }
187   s.endGroup();
188 
189   ui_->list->sortItems(1, Qt::AscendingOrder);
190 }
191 
Save()192 void WiimoteSettingsPage::Save() {
193   QSettings s;
194 
195   s.beginGroup(WiimotedevShortcuts::kActionsGroup);
196   s.remove("");
197   for (const Shortcut& shortcut : actions_)
198     s.setValue(QString::number(shortcut.button), shortcut.action);
199   s.endGroup();
200 
201   s.beginGroup(WiimotedevShortcuts::kSettingsGroup);
202   s.setValue("first_conf", false);
203   s.setValue("enabled", ui_->wiimotedev_enable->isChecked());
204   s.setValue("only_when_focused", ui_->wiimotedev_focus->isChecked());
205   s.setValue("use_active_action", ui_->wiimotedev_active->isChecked());
206   s.setValue("use_notification", ui_->wiimotedev_notification->isChecked());
207   s.setValue("device", ui_->wiimotedev_device->value());
208   s.endGroup();
209 }
210 
DefaultSettings()211 void WiimoteSettingsPage::DefaultSettings() {
212   ui_->list->clear();
213   actions_.clear();
214 
215   AddShortcut(WIIMOTE_BTN_LEFT, WiimotedevShortcuts::PlayerPreviousTrack);
216   AddShortcut(WIIMOTE_BTN_RIGHT, WiimotedevShortcuts::PlayerNextTrack);
217   AddShortcut(WIIMOTE_BTN_SHIFT_LEFT, WiimotedevShortcuts::PlayerPreviousTrack);
218   AddShortcut(WIIMOTE_BTN_SHIFT_RIGHT, WiimotedevShortcuts::PlayerNextTrack);
219   AddShortcut(WIIMOTE_BTN_PLUS, WiimotedevShortcuts::PlayerIncVolume);
220   AddShortcut(WIIMOTE_BTN_MINUS, WiimotedevShortcuts::PlayerDecVolume);
221   AddShortcut(WIIMOTE_BTN_1, WiimotedevShortcuts::PlayerTogglePause);
222   AddShortcut(WIIMOTE_BTN_2, WiimotedevShortcuts::PlayerShowOSD);
223   AddShortcut(WIIMOTE_BTN_A, WiimotedevShortcuts::WiimotedevActiveDeactive);
224 
225   ui_->list->sortItems(1, Qt::AscendingOrder);
226 }
227 
ItemClicked(QTreeWidgetItem * selected_item)228 void WiimoteSettingsPage::ItemClicked(QTreeWidgetItem* selected_item) {
229   selected_item_ = selected_item;
230 }
231 
GetReadableWiiremoteSequence(quint64 value)232 QString WiimoteSettingsPage::GetReadableWiiremoteSequence(quint64 value) {
233   QMapIterator<quint64, QString> text(text_buttons_);
234 
235   QStringList list;
236   while (text.hasNext()) {
237     text.next();
238     if ((text.key() & value) == text.key()) list << text.value();
239   }
240 
241   QString output;
242   if (!list.isEmpty()) {
243     for (int i = 0; i < (list.count() - 1); ++i) output += list.at(i) + " + ";
244     output += list.last();
245   } else
246     output = tr("Push Wii Remote button");
247 
248   return output;
249 }
250 
AddAction()251 void WiimoteSettingsPage::AddAction() {
252   emit SetWiimotedevInterfaceActived(false);
253   WiimoteShortcutGrabber grabber(0, ui_->wiimotedev_device->value(), this);
254   connect(&grabber, SIGNAL(AddShortcut(quint64, quint32)), this,
255           SLOT(AddShortcut(quint64, quint32)), Qt::QueuedConnection);
256   grabber.exec();
257   emit SetWiimotedevInterfaceActived(true);
258 
259   ui_->list->sortItems(1, Qt::AscendingOrder);
260 }
261 
DeleteAction()262 void WiimoteSettingsPage::DeleteAction() {
263   for (int i = 0; i < actions_.count(); ++i) {
264     if (actions_.at(i).object == selected_item_) {
265       delete selected_item_;
266       actions_.removeAt(i);
267       break;
268     }
269   }
270 }
271