1 /*
2 ** jstest-gtk - A graphical joystick tester
3 ** Copyright (C) 2009 Ingo Ruhnke <grumbel@gmail.com>
4 **
5 ** This program is free software: you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License as published by
7 ** the Free Software Foundation, either version 3 of the License, or
8 ** (at your option) any later version.
9 **
10 ** This program is distributed in the hope that it will be useful,
11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ** GNU General Public License for more details.
14 **
15 ** You should have received a copy of the GNU General Public License
16 ** along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <sstream>
20 #include <iostream>
21 #include <gtkmm/label.h>
22 #include <gtkmm/stock.h>
23 #include <gtkmm/dialog.h>
24 #include <gtkmm/image.h>
25
26 #include "main.hpp"
27 #include "joystick.hpp"
28 #include "button_widget.hpp"
29 #include "joystick_map_widget.hpp"
30 #include "joystick_calibration_widget.hpp"
31 #include "joystick_test_widget.hpp"
32
JoystickTestWidget(JoystickGui & gui,Joystick & joystick_,bool simple_ui)33 JoystickTestWidget::JoystickTestWidget(JoystickGui& gui, Joystick& joystick_, bool simple_ui) :
34 Gtk::Window(),
35 m_gui(gui),
36 joystick(joystick_),
37 m_simple_ui(simple_ui),
38 label("<b>" + joystick.get_name() + "</b>\nDevice: " + joystick.get_filename(),
39 Gtk::ALIGN_START, Gtk::ALIGN_START),
40 axis_frame("Axes"),
41 button_frame("Buttons"),
42 mapping_button("Mapping"),
43 calibration_button("Calibration"),
44 close_button(Gtk::Stock::CLOSE),
45 buttonbox(),
46 stick1_widget(128, 128),
47 stick2_widget(128, 128),
48 stick3_widget(128, 128),
49 rudder_widget(128, 32),
50 throttle_widget(32, 128),
51 left_trigger_widget(32, 128, true),
52 right_trigger_widget(32, 128, true)
53 {
54 set_title(joystick_.get_name());
55 set_icon_from_file(Main::current()->get_data_directory() + "generic.png");
56 label.set_use_markup(true);
57
58 label.set_selectable(true);
59
60 axis_frame.set_border_width(5);
61 axis_table.set_border_width(5);
62 axis_table.set_spacings(5);
63 button_frame.set_border_width(5);
64 button_table.set_border_width(5);
65 button_table.set_spacings(8);
66 buttonbox.set_border_width(5);
67
68 for(int i = 0; i < joystick.get_axis_count(); ++i)
69 {
70 std::ostringstream str;
71 str << "Axis " << i << ": ";
72 Gtk::Label& label = *Gtk::manage(new Gtk::Label(str.str()));
73
74 Gtk::ProgressBar& progressbar = *Gtk::manage(new Gtk::ProgressBar());
75 progressbar.set_fraction(0.5);
76
77 //Each column must have at most 10 axes
78
79 int x = (i/10)*2;
80 int y = i%10;
81
82 axis_table.attach(label, x, x+1, y, y+1, Gtk::SHRINK, Gtk::FILL);
83 axis_table.attach(progressbar, x+1, x+2, y, y+1, Gtk::FILL|Gtk::EXPAND, Gtk::EXPAND);
84
85 axes.push_back(&progressbar);
86 }
87
88 for(int i = 0; i < joystick.get_button_count(); ++i)
89 {
90 int x = i / 10;
91 int y = i % 10;
92
93 std::ostringstream str;
94 str << i;
95 ButtonWidget& button = *Gtk::manage(new ButtonWidget(32, 32, str.str()));
96 button_table.attach(button, x, x+1, y, y+1, Gtk::EXPAND, Gtk::EXPAND);
97 buttons.push_back(&button);
98 }
99
100 alignment.set_padding(8, 8, 8, 8);
101 alignment.add(label);
102 m_vbox.pack_start(alignment, Gtk::PACK_SHRINK);
103
104 buttonbox.add(mapping_button);
105 buttonbox.add(calibration_button);
106 buttonbox.add(close_button);
107
108 test_hbox.pack_start(axis_frame, Gtk::PACK_EXPAND_WIDGET);
109 test_hbox.pack_start(button_frame, Gtk::PACK_EXPAND_WIDGET);
110 m_vbox.pack_start(test_hbox, Gtk::PACK_SHRINK);
111 m_vbox.pack_end(buttonbox, Gtk::PACK_SHRINK);
112
113 add(m_vbox);
114
115 stick_hbox.set_border_width(5);
116
117 axis_callbacks.clear();
118 // Using manual loop instead of resize, as else all the signals
119 // would be clones of each other, instead of individual signals
120 for(int i = 0; i < (int)joystick.get_axis_count(); ++i)
121 axis_callbacks.push_back(sigc::signal<void, double>());
122
123 switch(joystick.get_axis_count())
124 {
125 case 2: // Simple stick
126 stick_hbox.pack_start(stick1_widget, Gtk::PACK_EXPAND_PADDING);
127 axis_callbacks[0].connect(sigc::mem_fun(stick1_widget, &AxisWidget::set_x_axis));
128 axis_callbacks[1].connect(sigc::mem_fun(stick1_widget, &AxisWidget::set_y_axis));
129 break;
130
131 case 6: // Flightstick
132 {
133 Gtk::Table& table = *Gtk::manage(new Gtk::Table(2, 2));
134
135 table.attach(stick1_widget, 0, 1, 0, 1, Gtk::SHRINK, Gtk::SHRINK);
136 table.attach(rudder_widget, 0, 1, 1, 2, Gtk::SHRINK, Gtk::SHRINK);
137 table.attach(throttle_widget, 1, 2, 0, 1, Gtk::SHRINK, Gtk::SHRINK);
138
139 stick_hbox.pack_start(table, Gtk::PACK_EXPAND_PADDING);
140 stick_hbox.pack_start(stick3_widget, Gtk::PACK_EXPAND_PADDING);
141
142 axis_callbacks[0].connect(sigc::mem_fun(stick1_widget, &AxisWidget::set_x_axis));
143 axis_callbacks[1].connect(sigc::mem_fun(stick1_widget, &AxisWidget::set_y_axis));
144 axis_callbacks[2].connect(sigc::mem_fun(rudder_widget, &RudderWidget::set_pos));
145 axis_callbacks[3].connect(sigc::mem_fun(throttle_widget, &ThrottleWidget::set_pos));
146 axis_callbacks[4].connect(sigc::mem_fun(stick3_widget, &AxisWidget::set_x_axis));
147 axis_callbacks[5].connect(sigc::mem_fun(stick3_widget, &AxisWidget::set_y_axis));
148 break;
149 }
150 /*
151 // Dual Analog Gamepad
152
153 // FIXME: never reached as this is the same as Flightstick, no
154 // way to tell them apart from simple axis count
155 stick_hbox.pack_start(stick1_widget, Gtk::PACK_EXPAND_PADDING);
156 stick_hbox.pack_start(stick2_widget, Gtk::PACK_EXPAND_PADDING);
157 stick_hbox.pack_start(stick3_widget, Gtk::PACK_EXPAND_PADDING);
158
159 axis_callbacks[0].connect(sigc::mem_fun(stick1_widget, &AxisWidget::set_x_axis));
160 axis_callbacks[1].connect(sigc::mem_fun(stick1_widget, &AxisWidget::set_y_axis));
161 axis_callbacks[2].connect(sigc::mem_fun(stick2_widget, &AxisWidget::set_x_axis));
162 axis_callbacks[3].connect(sigc::mem_fun(stick2_widget, &AxisWidget::set_y_axis));
163 axis_callbacks[4].connect(sigc::mem_fun(stick3_widget, &AxisWidget::set_x_axis));
164 axis_callbacks[5].connect(sigc::mem_fun(stick3_widget, &AxisWidget::set_y_axis));
165 */
166
167 case 8: // Dual Analog Gamepad + Analog Trigger
168 stick_hbox.pack_start(stick1_widget, Gtk::PACK_EXPAND_PADDING);
169 stick_hbox.pack_start(stick2_widget, Gtk::PACK_EXPAND_PADDING);
170 stick_hbox.pack_start(stick3_widget, Gtk::PACK_EXPAND_PADDING);
171 stick_hbox.pack_start(left_trigger_widget, Gtk::PACK_EXPAND_PADDING);
172 stick_hbox.pack_start(right_trigger_widget, Gtk::PACK_EXPAND_PADDING);
173
174 axis_callbacks[0].connect(sigc::mem_fun(stick1_widget, &AxisWidget::set_x_axis));
175 axis_callbacks[1].connect(sigc::mem_fun(stick1_widget, &AxisWidget::set_y_axis));
176 axis_callbacks[2].connect(sigc::mem_fun(stick2_widget, &AxisWidget::set_x_axis));
177 axis_callbacks[3].connect(sigc::mem_fun(stick2_widget, &AxisWidget::set_y_axis));
178 axis_callbacks[6].connect(sigc::mem_fun(stick3_widget, &AxisWidget::set_x_axis));
179 axis_callbacks[7].connect(sigc::mem_fun(stick3_widget, &AxisWidget::set_y_axis));
180 axis_callbacks[4].connect(sigc::mem_fun(left_trigger_widget, &ThrottleWidget::set_pos));
181 axis_callbacks[5].connect(sigc::mem_fun(right_trigger_widget, &ThrottleWidget::set_pos));
182 break;
183
184
185 case 7: // Dual Analog Gamepad DragonRise Inc. Generic USB Joystick
186 stick_hbox.pack_start(stick1_widget, Gtk::PACK_EXPAND_PADDING);
187 stick_hbox.pack_start(stick2_widget, Gtk::PACK_EXPAND_PADDING);
188 stick_hbox.pack_start(stick3_widget, Gtk::PACK_EXPAND_PADDING);
189
190 axis_callbacks[0].connect(sigc::mem_fun(stick1_widget, &AxisWidget::set_x_axis));
191 axis_callbacks[1].connect(sigc::mem_fun(stick1_widget, &AxisWidget::set_y_axis));
192 axis_callbacks[3].connect(sigc::mem_fun(stick2_widget, &AxisWidget::set_x_axis));
193 axis_callbacks[4].connect(sigc::mem_fun(stick2_widget, &AxisWidget::set_y_axis));
194 axis_callbacks[5].connect(sigc::mem_fun(stick3_widget, &AxisWidget::set_x_axis));
195 axis_callbacks[6].connect(sigc::mem_fun(stick3_widget, &AxisWidget::set_y_axis));
196 break;
197
198 case 27: // Playstation 3 Controller
199 stick_hbox.pack_start(stick1_widget, Gtk::PACK_EXPAND_PADDING);
200 stick_hbox.pack_start(stick2_widget, Gtk::PACK_EXPAND_PADDING);
201 // Not using stick3 for now, as the dpad is 4 axis on the PS3, not 2 (one for each direction)
202 //stick_hbox.pack_start(stick3_widget, Gtk::PACK_EXPAND_PADDING);
203 stick_hbox.pack_start(left_trigger_widget, Gtk::PACK_EXPAND_PADDING);
204 stick_hbox.pack_start(right_trigger_widget, Gtk::PACK_EXPAND_PADDING);
205
206 axis_callbacks[0].connect(sigc::mem_fun(stick1_widget, &AxisWidget::set_x_axis));
207 axis_callbacks[1].connect(sigc::mem_fun(stick1_widget, &AxisWidget::set_y_axis));
208 axis_callbacks[2].connect(sigc::mem_fun(stick2_widget, &AxisWidget::set_x_axis));
209 axis_callbacks[3].connect(sigc::mem_fun(stick2_widget, &AxisWidget::set_y_axis));
210 //axis_callbacks[6].connect(sigc::mem_fun(stick3_widget, &AxisWidget::set_x_axis));
211 //axis_callbacks[7].connect(sigc::mem_fun(stick3_widget, &AxisWidget::set_y_axis));
212 axis_callbacks[12].connect(sigc::mem_fun(left_trigger_widget, &ThrottleWidget::set_pos));
213 axis_callbacks[13].connect(sigc::mem_fun(right_trigger_widget, &ThrottleWidget::set_pos));
214 break;
215
216 default:
217 std::cout << "Warning: unknown joystick, not displaying graphical representation." << std::endl;
218 }
219
220 if (!m_simple_ui)
221 {
222 axis_vbox.pack_start(stick_hbox, Gtk::PACK_SHRINK);
223 }
224
225 axis_vbox.add(axis_table);
226 axis_frame.add(axis_vbox);
227
228 button_frame.add(button_table);
229
230 joystick.axis_move.connect(sigc::mem_fun(this, &JoystickTestWidget::axis_move));
231 joystick.button_move.connect(sigc::mem_fun(this, &JoystickTestWidget::button_move));
232
233 calibration_button.signal_clicked().connect(sigc::mem_fun(this, &JoystickTestWidget::on_calibrate));
234 mapping_button.signal_clicked().connect(sigc::mem_fun(this, &JoystickTestWidget::on_mapping));
235 close_button.signal_clicked().connect([this]{ hide(); });
236
237 close_button.grab_focus();
238 }
239
240 void
axis_move(int number,int value)241 JoystickTestWidget::axis_move(int number, int value)
242 {
243 axes.at(number)->set_fraction((value + 32767) / (double)(2*32767));
244
245 std::ostringstream str;
246 str << value;
247 axes.at(number)->set_text(str.str());
248 axis_callbacks[number](value / 32767.0);
249 }
250
251 void
button_move(int number,bool value)252 JoystickTestWidget::button_move(int number, bool value)
253 {
254 if (value)
255 buttons.at(number)->set_down(true);
256 else
257 buttons.at(number)->set_down(false);
258 }
259
260 void
on_calibrate()261 JoystickTestWidget::on_calibrate()
262 {
263 m_gui.show_calibration_dialog();
264 }
265
266 void
on_mapping()267 JoystickTestWidget::on_mapping()
268 {
269 m_gui.show_mapping_dialog();
270 }
271
272 /* EOF */
273