]>
Commit | Line | Data |
---|---|---|
3f63165c UH |
1 | /* |
2 | * This file is part of the sigrok project. | |
3 | * | |
4 | * Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz> | |
5 | * | |
6 | * This program is free software: you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation, either version 3 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
18 | */ | |
19 | ||
20 | #include <stdlib.h> | |
21 | ||
22 | #include <sigrok.h> | |
23 | ||
24 | #include <gtk/gtk.h> | |
25 | ||
26 | #include <stdlib.h> | |
27 | ||
28 | #include "sigrok-gtk.h" | |
29 | ||
30 | enum { | |
31 | DEV_PROP_CAPABILITY, | |
32 | DEV_PROP_TYPE, | |
33 | DEV_PROP_SHORTNAME, | |
34 | DEV_PROP_DESCRIPTION, | |
35 | DEV_PROP_IS_TEXT, | |
36 | DEV_PROP_TEXTVALUE, | |
37 | DEV_PROP_BOOLVALUE, | |
38 | MAX_DEV_PROP | |
39 | }; | |
40 | ||
41 | static void prop_edited(GtkCellRendererText *cel, gchar *path, gchar *text, | |
42 | GtkListStore *props) | |
43 | { | |
44 | (void)cel; | |
45 | ||
46 | struct sr_device *device = g_object_get_data(G_OBJECT(props), "device"); | |
47 | GtkTreeIter iter; | |
48 | int type, cap; | |
49 | guint64 tmp_u64; | |
50 | int ret = SR_ERR; | |
51 | ||
52 | gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(props), &iter, path); | |
53 | gtk_tree_model_get(GTK_TREE_MODEL(props), &iter, | |
54 | DEV_PROP_CAPABILITY, &cap, | |
55 | DEV_PROP_TYPE, &type, -1); | |
56 | ||
57 | switch (type) { | |
58 | case SR_T_UINT64: | |
59 | if (sr_parse_sizestring(text, &tmp_u64) != SR_OK) | |
60 | return; | |
61 | ||
62 | ret = device->plugin->set_configuration(device->plugin_index, | |
63 | cap, &tmp_u64); | |
64 | break; | |
65 | case SR_T_CHAR: | |
66 | ret = device->plugin-> set_configuration(device->plugin_index, | |
67 | cap, text); | |
68 | break; | |
69 | /* SR_T_BOOL will be handled by prop_toggled */ | |
70 | } | |
71 | ||
72 | if (!ret) | |
73 | gtk_list_store_set(props, &iter, DEV_PROP_TEXTVALUE, text, -1); | |
74 | } | |
75 | ||
76 | static void prop_toggled(GtkCellRendererToggle *cel, gchar *path, | |
77 | GtkListStore *props) | |
78 | { | |
79 | struct sr_device *device = g_object_get_data(G_OBJECT(props), "device"); | |
80 | GtkTreeIter iter; | |
81 | int type, cap; | |
82 | int ret; | |
83 | gboolean val; | |
84 | gtk_tree_model_get_iter_from_string(GTK_TREE_MODEL(props), &iter, path); | |
85 | gtk_tree_model_get(GTK_TREE_MODEL(props), &iter, | |
86 | DEV_PROP_CAPABILITY, &cap, | |
87 | DEV_PROP_TYPE, &type, -1); | |
88 | ||
89 | val = !gtk_cell_renderer_toggle_get_active(cel); | |
90 | ret = device->plugin-> set_configuration(device->plugin_index, cap, | |
91 | GINT_TO_POINTER(val)); | |
92 | ||
93 | if (!ret) | |
94 | gtk_list_store_set(props, &iter, DEV_PROP_BOOLVALUE, val, -1); | |
95 | } | |
96 | ||
97 | void dev_prop_bool_data_func(GtkCellLayout *cell_layout, | |
98 | GtkCellRenderer *cell, | |
99 | GtkTreeModel *tree_model, | |
100 | GtkTreeIter *iter, | |
101 | gpointer data) | |
102 | { | |
103 | (void)cell_layout; | |
104 | (void)data; | |
105 | ||
106 | gboolean istext, val; | |
107 | gtk_tree_model_get(tree_model, iter, | |
108 | DEV_PROP_IS_TEXT, &istext, | |
109 | DEV_PROP_BOOLVALUE, &val, -1); | |
110 | g_object_set(G_OBJECT(cell), "visible", !istext, "active", val, NULL); | |
111 | } | |
112 | ||
113 | static void dev_set_options(GtkAction *action, GtkWindow *parent) | |
114 | { | |
115 | (void)action; | |
116 | ||
117 | struct sr_device *device = g_object_get_data(G_OBJECT(parent), "device"); | |
118 | if (!device) | |
119 | return; | |
120 | ||
121 | GtkWidget *dialog = gtk_dialog_new_with_buttons("Device Properties", | |
122 | parent, GTK_DIALOG_MODAL, | |
123 | GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, | |
124 | NULL); | |
125 | GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL); | |
126 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), | |
127 | GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
128 | gtk_widget_set_size_request(sw, 300, 200); | |
129 | GtkWidget *tv = gtk_tree_view_new(); | |
130 | gtk_container_add(GTK_CONTAINER(sw), tv); | |
131 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), sw, | |
132 | TRUE, TRUE, 0); | |
133 | ||
134 | /* Populate list store with config options */ | |
135 | GtkListStore *props = gtk_list_store_new(MAX_DEV_PROP, | |
136 | G_TYPE_INT, G_TYPE_INT, | |
137 | G_TYPE_STRING, G_TYPE_STRING, | |
138 | G_TYPE_BOOLEAN, G_TYPE_STRING, | |
139 | G_TYPE_BOOLEAN); | |
140 | gtk_tree_view_set_model(GTK_TREE_VIEW(tv), GTK_TREE_MODEL(props)); | |
141 | int *capabilities = device->plugin->get_capabilities(); | |
142 | int cap; | |
143 | GtkTreeIter iter; | |
144 | for (cap = 0; capabilities[cap]; cap++) { | |
145 | struct sr_hwcap_option *hwo; | |
a9f1783a | 146 | if (!(hwo = sr_hw_hwcap_get(capabilities[cap]))) |
3f63165c UH |
147 | continue; |
148 | gtk_list_store_append(props, &iter); | |
149 | gtk_list_store_set(props, &iter, | |
150 | DEV_PROP_CAPABILITY, capabilities[cap], | |
151 | DEV_PROP_TYPE, hwo->type, | |
152 | DEV_PROP_SHORTNAME, hwo->shortname, | |
153 | DEV_PROP_DESCRIPTION, hwo->description, | |
154 | DEV_PROP_IS_TEXT, hwo->type != SR_T_BOOL, | |
155 | -1); | |
156 | } | |
157 | ||
158 | /* Popup tooltop containing description if mouse hovers */ | |
159 | gtk_tree_view_set_tooltip_column(GTK_TREE_VIEW(tv), | |
160 | DEV_PROP_DESCRIPTION); | |
161 | ||
162 | /* Save device with list so that property can be set by edited | |
163 | * handler. */ | |
164 | g_object_set_data(G_OBJECT(props), "device", device); | |
165 | ||
166 | /* Add columns to the tree view */ | |
167 | GtkTreeViewColumn *col; | |
168 | col = gtk_tree_view_column_new_with_attributes("Property", | |
169 | gtk_cell_renderer_text_new(), | |
170 | "text", DEV_PROP_SHORTNAME, NULL); | |
171 | gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col); | |
172 | /* We pack both a text and toggle renderer. Only one will be visible. | |
173 | * depending on type. | |
174 | */ | |
175 | GtkCellRenderer *cel = gtk_cell_renderer_text_new(); | |
176 | g_object_set(cel, "editable", TRUE, NULL); | |
177 | g_signal_connect(cel, "edited", G_CALLBACK(prop_edited), props); | |
178 | col = gtk_tree_view_column_new_with_attributes("Value", | |
179 | cel, "text", DEV_PROP_TEXTVALUE, | |
180 | "visible", DEV_PROP_IS_TEXT, NULL); | |
181 | cel = gtk_cell_renderer_toggle_new(); | |
182 | g_signal_connect(cel, "toggled", G_CALLBACK(prop_toggled), props); | |
183 | gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(col), cel, TRUE); | |
184 | gtk_cell_layout_set_cell_data_func(GTK_CELL_LAYOUT(col), cel, | |
185 | dev_prop_bool_data_func, NULL, NULL); | |
186 | gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col); | |
187 | ||
188 | ||
189 | gtk_widget_show_all(dialog); | |
190 | gtk_dialog_run(GTK_DIALOG(dialog)); | |
191 | ||
192 | gtk_widget_destroy(dialog); | |
193 | } | |
194 | ||
195 | enum { | |
196 | PROBE_NUMBER, | |
197 | PROBE_ENABLED, | |
198 | PROBE_NAME, | |
199 | PROBE_TRIGGER, | |
200 | MAX_PROBE | |
201 | }; | |
202 | ||
203 | static void probe_toggled(GtkCellRenderer *cel, gchar *path, | |
204 | GtkTreeModel *probes) | |
205 | { | |
206 | struct sr_device *device = g_object_get_data(G_OBJECT(probes), "device"); | |
207 | GtkTreeIter iter; | |
208 | struct sr_probe *probe; | |
209 | gint i; | |
210 | gboolean en; | |
211 | ||
212 | (void)cel; | |
213 | ||
214 | gtk_tree_model_get_iter_from_string(probes, &iter, path); | |
215 | gtk_tree_model_get(probes, &iter, PROBE_NUMBER, &i, | |
216 | PROBE_ENABLED, &en, -1); | |
91a22b68 | 217 | probe = sr_dev_probe_find(device, i); |
3f63165c UH |
218 | probe->enabled = !en; |
219 | gtk_list_store_set(GTK_LIST_STORE(probes), &iter, | |
220 | PROBE_ENABLED, probe->enabled, -1); | |
221 | } | |
222 | ||
223 | static void probe_named(GtkCellRendererText *cel, gchar *path, gchar *text, | |
224 | GtkTreeModel *probes) | |
225 | { | |
226 | struct sr_device *device = g_object_get_data(G_OBJECT(probes), "device"); | |
227 | GtkTreeIter iter; | |
228 | gint i; | |
229 | ||
230 | (void)cel; | |
231 | ||
232 | gtk_tree_model_get_iter_from_string(probes, &iter, path); | |
233 | gtk_tree_model_get(probes, &iter, PROBE_NUMBER, &i, -1); | |
91a22b68 | 234 | sr_dev_probe_name(device, i, text); |
3f63165c UH |
235 | gtk_list_store_set(GTK_LIST_STORE(probes), &iter, PROBE_NAME, text, -1); |
236 | } | |
237 | ||
238 | static void probe_trigger_set(GtkCellRendererText *cel, gchar *path, | |
239 | gchar *text, GtkTreeModel *probes) | |
240 | { | |
241 | struct sr_device *device = g_object_get_data(G_OBJECT(probes), "device"); | |
242 | GtkTreeIter iter; | |
243 | gint i; | |
244 | ||
245 | (void)cel; | |
246 | ||
247 | gtk_tree_model_get_iter_from_string(probes, &iter, path); | |
248 | gtk_tree_model_get(probes, &iter, PROBE_NUMBER, &i, -1); | |
91a22b68 | 249 | sr_dev_trigger_set(device, i, text); |
3f63165c UH |
250 | gtk_list_store_set(GTK_LIST_STORE(probes), &iter, |
251 | PROBE_TRIGGER, text, -1); | |
252 | } | |
253 | ||
254 | static void dev_set_probes(GtkAction *action, GtkWindow *parent) | |
255 | { | |
256 | (void)action; | |
257 | ||
258 | struct sr_device *device = g_object_get_data(G_OBJECT(parent), "device"); | |
259 | if (!device) | |
260 | return; | |
261 | ||
262 | GtkWidget *dialog = gtk_dialog_new_with_buttons("Configure Probes", | |
263 | parent, GTK_DIALOG_MODAL, | |
264 | GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE, | |
265 | NULL); | |
266 | GtkWidget *sw = gtk_scrolled_window_new(NULL, NULL); | |
267 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(sw), | |
268 | GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); | |
269 | gtk_widget_set_size_request(sw, 300, 200); | |
270 | GtkWidget *tv = gtk_tree_view_new(); | |
271 | gtk_container_add(GTK_CONTAINER(sw), tv); | |
272 | gtk_box_pack_start(GTK_BOX(GTK_DIALOG(dialog)->vbox), sw, | |
273 | TRUE, TRUE, 0); | |
274 | ||
275 | /* Populate list store with probe options */ | |
276 | GtkListStore *probes = gtk_list_store_new(MAX_PROBE, | |
277 | G_TYPE_INT, G_TYPE_BOOLEAN, | |
278 | G_TYPE_STRING, GTK_TYPE_STRING); | |
279 | gtk_tree_view_set_model(GTK_TREE_VIEW(tv), GTK_TREE_MODEL(probes)); | |
280 | GtkTreeIter iter; | |
281 | GSList *p; | |
282 | int i; | |
283 | for (p = device->probes, i = 1; p; p = g_slist_next(p), i++) { | |
284 | struct sr_probe *probe = p->data; | |
285 | gtk_list_store_append(probes, &iter); | |
286 | gtk_list_store_set(probes, &iter, PROBE_NUMBER, i, | |
287 | PROBE_ENABLED, probe->enabled, | |
288 | PROBE_NAME, probe->name, | |
289 | PROBE_TRIGGER, probe->trigger, | |
290 | -1); | |
291 | } | |
292 | ||
293 | /* Save device with list so that property can be set by edited | |
294 | * handler. */ | |
295 | g_object_set_data(G_OBJECT(probes), "device", device); | |
296 | ||
297 | /* Add columns to the tree view */ | |
298 | GtkTreeViewColumn *col; | |
299 | col = gtk_tree_view_column_new_with_attributes("Probe", | |
300 | gtk_cell_renderer_text_new(), | |
301 | "text", PROBE_NUMBER, NULL); | |
302 | gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col); | |
303 | GtkCellRenderer *cel = gtk_cell_renderer_toggle_new(); | |
304 | g_object_set(cel, "activatable", TRUE, NULL); | |
305 | g_signal_connect(cel, "toggled", G_CALLBACK(probe_toggled), probes); | |
306 | col = gtk_tree_view_column_new_with_attributes("En", | |
307 | cel, "active", PROBE_ENABLED, NULL); | |
308 | gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col); | |
309 | cel = gtk_cell_renderer_text_new(); | |
310 | g_object_set(cel, "editable", TRUE, NULL); | |
311 | g_signal_connect(cel, "edited", G_CALLBACK(probe_named), probes); | |
312 | col = gtk_tree_view_column_new_with_attributes("Signal Name", cel, | |
313 | "text", PROBE_NAME, | |
314 | "sensitive", PROBE_ENABLED, NULL); | |
315 | gtk_tree_view_column_set_resizable(col, TRUE); | |
316 | gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col); | |
317 | cel = gtk_cell_renderer_text_new(); | |
318 | g_object_set(cel, "editable", TRUE, NULL); | |
319 | g_signal_connect(cel, "edited", G_CALLBACK(probe_trigger_set), probes); | |
320 | col = gtk_tree_view_column_new_with_attributes("Trigger", cel, | |
321 | "text", PROBE_TRIGGER, | |
322 | "sensitive", PROBE_ENABLED, NULL); | |
323 | gtk_tree_view_append_column(GTK_TREE_VIEW(tv), col); | |
324 | ||
325 | gtk_widget_show_all(dialog); | |
326 | gtk_dialog_run(GTK_DIALOG(dialog)); | |
327 | ||
328 | gtk_widget_destroy(dialog); | |
329 | } | |
330 | ||
331 | static void capture_run(GtkAction *action, GObject *parent) | |
332 | { | |
333 | (void)action; | |
334 | ||
335 | struct sr_device *device = g_object_get_data(G_OBJECT(parent), "device"); | |
336 | GtkEntry *timesamples = g_object_get_data(parent, "timesamples"); | |
337 | GtkComboBox *timeunit = g_object_get_data(parent, "timeunit"); | |
338 | gint i = gtk_combo_box_get_active(timeunit); | |
339 | guint64 time_msec = 0; | |
340 | guint64 limit_samples = 0; | |
341 | ||
342 | switch (i) { | |
343 | case 0: /* Samples */ | |
344 | sr_parse_sizestring(gtk_entry_get_text(timesamples), | |
345 | &limit_samples); | |
346 | break; | |
347 | case 1: /* Milliseconds */ | |
348 | time_msec = strtoull(gtk_entry_get_text(timesamples), NULL, 10); | |
349 | break; | |
350 | case 2: /* Seconds */ | |
351 | time_msec = strtoull(gtk_entry_get_text(timesamples), NULL, 10) | |
352 | * 1000; | |
353 | break; | |
354 | } | |
355 | ||
356 | if (time_msec) { | |
a9f1783a | 357 | if (sr_hw_has_hwcap(device->plugin, SR_HWCAP_LIMIT_MSEC)) { |
3f63165c UH |
358 | if (device->plugin->set_configuration(device->plugin_index, |
359 | SR_HWCAP_LIMIT_MSEC, | |
360 | &time_msec) != SR_OK) { | |
361 | g_critical("Failed to configure time limit."); | |
362 | sr_session_destroy(); | |
363 | return; | |
364 | } | |
365 | } else { | |
366 | /* time limit set, but device doesn't support this... | |
367 | * convert to samples based on the samplerate. | |
368 | */ | |
369 | limit_samples = 0; | |
91a22b68 | 370 | if (sr_dev_has_hwcap(device, SR_HWCAP_SAMPLERATE)) { |
3f63165c UH |
371 | guint64 tmp_u64; |
372 | tmp_u64 = *((uint64_t *) device->plugin->get_device_info( | |
373 | device->plugin_index, | |
374 | SR_DI_CUR_SAMPLERATE)); | |
375 | limit_samples = tmp_u64 * time_msec / (uint64_t) 1000; | |
376 | } | |
377 | if (limit_samples == 0) { | |
378 | g_critical("Not enough time at this samplerate."); | |
379 | return; | |
380 | } | |
381 | ||
382 | if (device->plugin->set_configuration(device->plugin_index, | |
383 | SR_HWCAP_LIMIT_SAMPLES, | |
384 | &limit_samples) != SR_OK) { | |
385 | g_critical("Failed to configure time-based sample limit."); | |
386 | return; | |
387 | } | |
388 | } | |
389 | } | |
390 | if (limit_samples) { | |
391 | if (device->plugin->set_configuration(device->plugin_index, | |
392 | SR_HWCAP_LIMIT_SAMPLES, | |
393 | &limit_samples) != SR_OK) { | |
394 | g_critical("Failed to configure sample limit."); | |
395 | return; | |
396 | } | |
397 | } | |
398 | ||
399 | if (device->plugin->set_configuration(device->plugin_index, | |
400 | SR_HWCAP_PROBECONFIG, (char *)device->probes) != SR_OK) { | |
401 | printf("Failed to configure probes.\n"); | |
402 | sr_session_destroy(); | |
403 | return; | |
404 | } | |
405 | ||
406 | if (sr_session_start() != SR_OK) { | |
407 | g_critical("Failed to start session."); | |
408 | return; | |
409 | } | |
410 | ||
411 | sr_session_run(); | |
412 | } | |
413 | ||
414 | static void dev_file_open(GtkAction *action, GtkWindow *parent) | |
415 | { | |
416 | (void)action; | |
417 | static GtkWidget *dialog; | |
418 | const gchar *filename; | |
419 | ||
420 | if(!dialog) | |
421 | dialog = gtk_file_chooser_dialog_new("Open", parent, | |
422 | GTK_FILE_CHOOSER_ACTION_OPEN, | |
423 | GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | |
424 | GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); | |
425 | g_signal_connect(dialog, "delete-event", | |
426 | G_CALLBACK(gtk_widget_hide_on_delete), | |
427 | NULL); | |
428 | ||
429 | if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) { | |
430 | /* Dialog was cancelled or closed */ | |
431 | gtk_widget_hide(dialog); | |
432 | return; | |
433 | } | |
434 | ||
435 | gtk_widget_hide(dialog); | |
436 | ||
437 | filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); | |
438 | load_input_file(parent, filename); | |
439 | } | |
440 | ||
441 | void toggle_log(GtkToggleAction *action, GObject *parent) | |
442 | { | |
443 | GtkWidget *log = g_object_get_data(parent, "logview"); | |
444 | gtk_widget_set_visible(log, gtk_toggle_action_get_active(action)); | |
445 | } | |
446 | ||
447 | void zoom_in(GtkAction *action, GObject *parent) | |
448 | { | |
449 | (void)action; | |
450 | ||
451 | GtkWidget *sigview = g_object_get_data(parent, "sigview"); | |
452 | sigview_zoom(sigview, 1.5, 0); | |
453 | } | |
454 | ||
455 | void zoom_out(GtkAction *action, GObject *parent) | |
456 | { | |
457 | (void)action; | |
458 | ||
459 | GtkWidget *sigview = g_object_get_data(parent, "sigview"); | |
460 | sigview_zoom(sigview, 1/1.5, 0); | |
461 | } | |
462 | ||
463 | void zoom_fit(GtkAction *action, GObject *parent) | |
464 | { | |
465 | (void)action; | |
466 | ||
467 | GtkWidget *sigview = g_object_get_data(parent, "sigview"); | |
468 | sigview_zoom(sigview, 0, 0); | |
469 | } | |
470 | ||
471 | static const GtkActionEntry action_items[] = { | |
472 | /* name, stock-id, label, accel, tooltip, callback */ | |
473 | {"DevMenu", NULL, "_Device", NULL, NULL, NULL}, | |
474 | {"DevOpen", GTK_STOCK_OPEN, "_Open", "<control>O", | |
475 | "Open Session File", G_CALLBACK(dev_file_open)}, | |
476 | {"DevSelectMenu", NULL, "Select Device", NULL, NULL, NULL}, | |
477 | {"DevRescan", GTK_STOCK_REFRESH, "_Rescan", "<control>R", | |
478 | "Rescan for LA devices", G_CALLBACK(dev_select_rescan)}, | |
479 | {"DevProperties", GTK_STOCK_PROPERTIES, "_Properties", "<control>P", | |
480 | "Configure LA", G_CALLBACK(dev_set_options)}, | |
481 | {"DevProbes", GTK_STOCK_COLOR_PICKER, "_Probes", "<control>O", | |
482 | "Configure Probes", G_CALLBACK(dev_set_probes)}, | |
483 | {"DevAcquire", GTK_STOCK_EXECUTE, "_Acquire", "<control>A", | |
484 | "Acquire Samples", G_CALLBACK(capture_run)}, | |
485 | {"Exit", GTK_STOCK_QUIT, "E_xit", "<control>Q", | |
486 | "Exit the program", G_CALLBACK(gtk_main_quit) }, | |
487 | ||
488 | {"ViewMenu", NULL, "_View", NULL, NULL, NULL}, | |
489 | {"ViewZoomIn", GTK_STOCK_ZOOM_IN, "Zoom _In", "<control>z", NULL, | |
490 | G_CALLBACK(zoom_in)}, | |
491 | {"ViewZoomOut", GTK_STOCK_ZOOM_OUT, "Zoom _Out", "<control><shift>Z", | |
492 | NULL, G_CALLBACK(zoom_out)}, | |
493 | {"ViewZoomFit", GTK_STOCK_ZOOM_FIT, NULL, NULL, | |
494 | NULL, G_CALLBACK(zoom_fit)}, | |
495 | ||
496 | {"HelpMenu", NULL, "_Help", NULL, NULL, NULL}, | |
497 | {"HelpWiki", GTK_STOCK_ABOUT, "Sigrok _Wiki", NULL, NULL, | |
498 | G_CALLBACK(help_wiki)}, | |
499 | {"HelpAbout", GTK_STOCK_ABOUT, "_About", NULL, NULL, | |
500 | G_CALLBACK(help_about)}, | |
501 | }; | |
502 | ||
503 | static const GtkToggleActionEntry toggle_items[] = { | |
504 | /* name, stock-id, label, accel, tooltip, callback, isactive */ | |
505 | {"ViewLog", GTK_STOCK_JUSTIFY_LEFT, "_Log", NULL, NULL, | |
506 | G_CALLBACK(toggle_log), FALSE}, | |
507 | }; | |
508 | ||
509 | static const char ui_xml[] = | |
510 | "<ui>" | |
511 | " <menubar>" | |
512 | " <menu action='DevMenu'>" | |
513 | " <menuitem action='DevOpen'/>" | |
514 | " <separator/>" | |
515 | " <menu action='DevSelectMenu'>" | |
516 | " <separator/>" | |
517 | " <menuitem action='DevRescan'/>" | |
518 | " </menu>" | |
519 | " <menuitem action='DevProperties'/>" | |
520 | " <menuitem action='DevProbes'/>" | |
521 | " <separator/>" | |
522 | " <menuitem action='DevAcquire'/>" | |
523 | " <separator/>" | |
524 | " <menuitem action='Exit'/>" | |
525 | " </menu>" | |
526 | " <menu action='ViewMenu'>" | |
527 | " <menuitem action='ViewZoomIn'/>" | |
528 | " <menuitem action='ViewZoomOut'/>" | |
529 | " <menuitem action='ViewZoomFit'/>" | |
530 | " <separator/>" | |
531 | " <menuitem action='ViewLog'/>" | |
532 | " </menu>" | |
533 | " <menu action='HelpMenu'>" | |
534 | " <menuitem action='HelpWiki'/>" | |
535 | " <menuitem action='HelpAbout'/>" | |
536 | " </menu>" | |
537 | " </menubar>" | |
538 | " <toolbar>" | |
539 | " <placeholder name='DevSelect'/>" | |
540 | " <toolitem action='DevRescan'/>" | |
541 | " <toolitem action='DevProperties'/>" | |
542 | " <toolitem action='DevProbes'/>" | |
543 | " <separator/>" | |
544 | " <placeholder name='DevSampleCount' />" | |
545 | " <toolitem action='DevAcquire'/>" | |
546 | " <separator/>" | |
547 | " <toolitem action='ViewZoomIn'/>" | |
548 | " <toolitem action='ViewZoomOut'/>" | |
549 | " <toolitem action='ViewZoomFit'/>" | |
550 | " <separator/>" | |
551 | " </toolbar>" | |
552 | "</ui>"; | |
553 | ||
554 | GtkWidget *toolbar_init(GtkWindow *parent) | |
555 | { | |
556 | GtkWidget *vbox = gtk_vbox_new(FALSE, 0); | |
557 | GtkToolbar *toolbar; | |
558 | GtkActionGroup *ag = gtk_action_group_new("Actions"); | |
559 | gtk_action_group_add_actions(ag, action_items, | |
560 | G_N_ELEMENTS(action_items), parent); | |
561 | gtk_action_group_add_toggle_actions(ag, toggle_items, | |
562 | G_N_ELEMENTS(toggle_items), parent); | |
563 | ||
564 | GtkUIManager *ui = gtk_ui_manager_new(); | |
565 | g_object_set_data(G_OBJECT(parent), "ui_manager", ui); | |
566 | gtk_ui_manager_insert_action_group(ui, ag, 0); | |
567 | GtkAccelGroup *accel = gtk_ui_manager_get_accel_group(ui); | |
568 | gtk_window_add_accel_group(parent, accel); | |
569 | ||
570 | GError *error = NULL; | |
571 | if (!gtk_ui_manager_add_ui_from_string (ui, ui_xml, -1, &error)) { | |
572 | g_message ("building menus failed: %s", error->message); | |
573 | g_error_free (error); | |
574 | exit (-1); | |
575 | } | |
576 | ||
577 | GtkWidget *menubar = gtk_ui_manager_get_widget(ui, "/menubar"); | |
578 | gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(menubar), FALSE, TRUE, 0); | |
579 | toolbar = GTK_TOOLBAR(gtk_ui_manager_get_widget(ui, "/toolbar")); | |
580 | gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(toolbar), FALSE, TRUE, 0); | |
581 | ||
582 | /* Device selection GtkComboBox */ | |
583 | GtkToolItem *toolitem = gtk_tool_item_new(); | |
584 | GtkWidget *align = gtk_alignment_new(0.5, 0.5, 2, 0); | |
585 | GtkWidget *dev = dev_select_combo_box_new(parent); | |
586 | ||
587 | gtk_container_add(GTK_CONTAINER(align), dev); | |
588 | gtk_container_add(GTK_CONTAINER(toolitem), align); | |
589 | gtk_toolbar_insert(toolbar, toolitem, 0); | |
590 | ||
591 | /* Time/Samples entry */ | |
592 | toolitem = gtk_tool_item_new(); | |
593 | GtkWidget *timesamples = gtk_entry_new(); | |
594 | gtk_entry_set_text(GTK_ENTRY(timesamples), "100"); | |
595 | gtk_entry_set_alignment(GTK_ENTRY(timesamples), 1.0); | |
596 | gtk_widget_set_size_request(timesamples, 100, -1); | |
597 | gtk_container_add(GTK_CONTAINER(toolitem), timesamples); | |
598 | gtk_toolbar_insert(toolbar, toolitem, 7); | |
599 | ||
600 | /* Time unit combo box */ | |
601 | toolitem = gtk_tool_item_new(); | |
602 | align = gtk_alignment_new(0.5, 0.5, 2, 0); | |
603 | GtkWidget *timeunit = gtk_combo_box_new_text(); | |
604 | gtk_combo_box_append_text(GTK_COMBO_BOX(timeunit), "samples"); | |
605 | gtk_combo_box_append_text(GTK_COMBO_BOX(timeunit), "ms"); | |
606 | gtk_combo_box_append_text(GTK_COMBO_BOX(timeunit), "s"); | |
607 | gtk_combo_box_set_active(GTK_COMBO_BOX(timeunit), 0); | |
608 | gtk_container_add(GTK_CONTAINER(align), timeunit); | |
609 | gtk_container_add(GTK_CONTAINER(toolitem), align); | |
610 | gtk_toolbar_insert(toolbar, toolitem, 8); | |
611 | ||
612 | g_object_set_data(G_OBJECT(parent), "timesamples", timesamples); | |
613 | g_object_set_data(G_OBJECT(parent), "timeunit", timeunit); | |
614 | ||
615 | return GTK_WIDGET(vbox); | |
616 | } | |
617 |