]>
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; | |
146 | if (!(hwo = sr_find_hwcap_option(capabilities[cap]))) | |
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); | |
217 | probe = sr_device_probe_find(device, i); | |
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); | |
234 | sr_device_probe_name(device, i, text); | |
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); | |
249 | sr_device_trigger_set(device, i, text); | |
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) { | |
357 | int *capabilities = device->plugin->get_capabilities(); | |
358 | if (sr_find_hwcap(capabilities, SR_HWCAP_LIMIT_MSEC)) { | |
359 | if (device->plugin->set_configuration(device->plugin_index, | |
360 | SR_HWCAP_LIMIT_MSEC, | |
361 | &time_msec) != SR_OK) { | |
362 | g_critical("Failed to configure time limit."); | |
363 | sr_session_destroy(); | |
364 | return; | |
365 | } | |
366 | } else { | |
367 | /* time limit set, but device doesn't support this... | |
368 | * convert to samples based on the samplerate. | |
369 | */ | |
370 | limit_samples = 0; | |
371 | if (sr_device_has_hwcap(device, SR_HWCAP_SAMPLERATE)) { | |
372 | guint64 tmp_u64; | |
373 | tmp_u64 = *((uint64_t *) device->plugin->get_device_info( | |
374 | device->plugin_index, | |
375 | SR_DI_CUR_SAMPLERATE)); | |
376 | limit_samples = tmp_u64 * time_msec / (uint64_t) 1000; | |
377 | } | |
378 | if (limit_samples == 0) { | |
379 | g_critical("Not enough time at this samplerate."); | |
380 | return; | |
381 | } | |
382 | ||
383 | if (device->plugin->set_configuration(device->plugin_index, | |
384 | SR_HWCAP_LIMIT_SAMPLES, | |
385 | &limit_samples) != SR_OK) { | |
386 | g_critical("Failed to configure time-based sample limit."); | |
387 | return; | |
388 | } | |
389 | } | |
390 | } | |
391 | if (limit_samples) { | |
392 | if (device->plugin->set_configuration(device->plugin_index, | |
393 | SR_HWCAP_LIMIT_SAMPLES, | |
394 | &limit_samples) != SR_OK) { | |
395 | g_critical("Failed to configure sample limit."); | |
396 | return; | |
397 | } | |
398 | } | |
399 | ||
400 | if (device->plugin->set_configuration(device->plugin_index, | |
401 | SR_HWCAP_PROBECONFIG, (char *)device->probes) != SR_OK) { | |
402 | printf("Failed to configure probes.\n"); | |
403 | sr_session_destroy(); | |
404 | return; | |
405 | } | |
406 | ||
407 | if (sr_session_start() != SR_OK) { | |
408 | g_critical("Failed to start session."); | |
409 | return; | |
410 | } | |
411 | ||
412 | sr_session_run(); | |
413 | } | |
414 | ||
415 | static void dev_file_open(GtkAction *action, GtkWindow *parent) | |
416 | { | |
417 | (void)action; | |
418 | static GtkWidget *dialog; | |
419 | const gchar *filename; | |
420 | ||
421 | if(!dialog) | |
422 | dialog = gtk_file_chooser_dialog_new("Open", parent, | |
423 | GTK_FILE_CHOOSER_ACTION_OPEN, | |
424 | GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, | |
425 | GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL); | |
426 | g_signal_connect(dialog, "delete-event", | |
427 | G_CALLBACK(gtk_widget_hide_on_delete), | |
428 | NULL); | |
429 | ||
430 | if (gtk_dialog_run(GTK_DIALOG(dialog)) != GTK_RESPONSE_ACCEPT) { | |
431 | /* Dialog was cancelled or closed */ | |
432 | gtk_widget_hide(dialog); | |
433 | return; | |
434 | } | |
435 | ||
436 | gtk_widget_hide(dialog); | |
437 | ||
438 | filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); | |
439 | load_input_file(parent, filename); | |
440 | } | |
441 | ||
442 | void toggle_log(GtkToggleAction *action, GObject *parent) | |
443 | { | |
444 | GtkWidget *log = g_object_get_data(parent, "logview"); | |
445 | gtk_widget_set_visible(log, gtk_toggle_action_get_active(action)); | |
446 | } | |
447 | ||
448 | void zoom_in(GtkAction *action, GObject *parent) | |
449 | { | |
450 | (void)action; | |
451 | ||
452 | GtkWidget *sigview = g_object_get_data(parent, "sigview"); | |
453 | sigview_zoom(sigview, 1.5, 0); | |
454 | } | |
455 | ||
456 | void zoom_out(GtkAction *action, GObject *parent) | |
457 | { | |
458 | (void)action; | |
459 | ||
460 | GtkWidget *sigview = g_object_get_data(parent, "sigview"); | |
461 | sigview_zoom(sigview, 1/1.5, 0); | |
462 | } | |
463 | ||
464 | void zoom_fit(GtkAction *action, GObject *parent) | |
465 | { | |
466 | (void)action; | |
467 | ||
468 | GtkWidget *sigview = g_object_get_data(parent, "sigview"); | |
469 | sigview_zoom(sigview, 0, 0); | |
470 | } | |
471 | ||
472 | static const GtkActionEntry action_items[] = { | |
473 | /* name, stock-id, label, accel, tooltip, callback */ | |
474 | {"DevMenu", NULL, "_Device", NULL, NULL, NULL}, | |
475 | {"DevOpen", GTK_STOCK_OPEN, "_Open", "<control>O", | |
476 | "Open Session File", G_CALLBACK(dev_file_open)}, | |
477 | {"DevSelectMenu", NULL, "Select Device", NULL, NULL, NULL}, | |
478 | {"DevRescan", GTK_STOCK_REFRESH, "_Rescan", "<control>R", | |
479 | "Rescan for LA devices", G_CALLBACK(dev_select_rescan)}, | |
480 | {"DevProperties", GTK_STOCK_PROPERTIES, "_Properties", "<control>P", | |
481 | "Configure LA", G_CALLBACK(dev_set_options)}, | |
482 | {"DevProbes", GTK_STOCK_COLOR_PICKER, "_Probes", "<control>O", | |
483 | "Configure Probes", G_CALLBACK(dev_set_probes)}, | |
484 | {"DevAcquire", GTK_STOCK_EXECUTE, "_Acquire", "<control>A", | |
485 | "Acquire Samples", G_CALLBACK(capture_run)}, | |
486 | {"Exit", GTK_STOCK_QUIT, "E_xit", "<control>Q", | |
487 | "Exit the program", G_CALLBACK(gtk_main_quit) }, | |
488 | ||
489 | {"ViewMenu", NULL, "_View", NULL, NULL, NULL}, | |
490 | {"ViewZoomIn", GTK_STOCK_ZOOM_IN, "Zoom _In", "<control>z", NULL, | |
491 | G_CALLBACK(zoom_in)}, | |
492 | {"ViewZoomOut", GTK_STOCK_ZOOM_OUT, "Zoom _Out", "<control><shift>Z", | |
493 | NULL, G_CALLBACK(zoom_out)}, | |
494 | {"ViewZoomFit", GTK_STOCK_ZOOM_FIT, NULL, NULL, | |
495 | NULL, G_CALLBACK(zoom_fit)}, | |
496 | ||
497 | {"HelpMenu", NULL, "_Help", NULL, NULL, NULL}, | |
498 | {"HelpWiki", GTK_STOCK_ABOUT, "Sigrok _Wiki", NULL, NULL, | |
499 | G_CALLBACK(help_wiki)}, | |
500 | {"HelpAbout", GTK_STOCK_ABOUT, "_About", NULL, NULL, | |
501 | G_CALLBACK(help_about)}, | |
502 | }; | |
503 | ||
504 | static const GtkToggleActionEntry toggle_items[] = { | |
505 | /* name, stock-id, label, accel, tooltip, callback, isactive */ | |
506 | {"ViewLog", GTK_STOCK_JUSTIFY_LEFT, "_Log", NULL, NULL, | |
507 | G_CALLBACK(toggle_log), FALSE}, | |
508 | }; | |
509 | ||
510 | static const char ui_xml[] = | |
511 | "<ui>" | |
512 | " <menubar>" | |
513 | " <menu action='DevMenu'>" | |
514 | " <menuitem action='DevOpen'/>" | |
515 | " <separator/>" | |
516 | " <menu action='DevSelectMenu'>" | |
517 | " <separator/>" | |
518 | " <menuitem action='DevRescan'/>" | |
519 | " </menu>" | |
520 | " <menuitem action='DevProperties'/>" | |
521 | " <menuitem action='DevProbes'/>" | |
522 | " <separator/>" | |
523 | " <menuitem action='DevAcquire'/>" | |
524 | " <separator/>" | |
525 | " <menuitem action='Exit'/>" | |
526 | " </menu>" | |
527 | " <menu action='ViewMenu'>" | |
528 | " <menuitem action='ViewZoomIn'/>" | |
529 | " <menuitem action='ViewZoomOut'/>" | |
530 | " <menuitem action='ViewZoomFit'/>" | |
531 | " <separator/>" | |
532 | " <menuitem action='ViewLog'/>" | |
533 | " </menu>" | |
534 | " <menu action='HelpMenu'>" | |
535 | " <menuitem action='HelpWiki'/>" | |
536 | " <menuitem action='HelpAbout'/>" | |
537 | " </menu>" | |
538 | " </menubar>" | |
539 | " <toolbar>" | |
540 | " <placeholder name='DevSelect'/>" | |
541 | " <toolitem action='DevRescan'/>" | |
542 | " <toolitem action='DevProperties'/>" | |
543 | " <toolitem action='DevProbes'/>" | |
544 | " <separator/>" | |
545 | " <placeholder name='DevSampleCount' />" | |
546 | " <toolitem action='DevAcquire'/>" | |
547 | " <separator/>" | |
548 | " <toolitem action='ViewZoomIn'/>" | |
549 | " <toolitem action='ViewZoomOut'/>" | |
550 | " <toolitem action='ViewZoomFit'/>" | |
551 | " <separator/>" | |
552 | " </toolbar>" | |
553 | "</ui>"; | |
554 | ||
555 | GtkWidget *toolbar_init(GtkWindow *parent) | |
556 | { | |
557 | GtkWidget *vbox = gtk_vbox_new(FALSE, 0); | |
558 | GtkToolbar *toolbar; | |
559 | GtkActionGroup *ag = gtk_action_group_new("Actions"); | |
560 | gtk_action_group_add_actions(ag, action_items, | |
561 | G_N_ELEMENTS(action_items), parent); | |
562 | gtk_action_group_add_toggle_actions(ag, toggle_items, | |
563 | G_N_ELEMENTS(toggle_items), parent); | |
564 | ||
565 | GtkUIManager *ui = gtk_ui_manager_new(); | |
566 | g_object_set_data(G_OBJECT(parent), "ui_manager", ui); | |
567 | gtk_ui_manager_insert_action_group(ui, ag, 0); | |
568 | GtkAccelGroup *accel = gtk_ui_manager_get_accel_group(ui); | |
569 | gtk_window_add_accel_group(parent, accel); | |
570 | ||
571 | GError *error = NULL; | |
572 | if (!gtk_ui_manager_add_ui_from_string (ui, ui_xml, -1, &error)) { | |
573 | g_message ("building menus failed: %s", error->message); | |
574 | g_error_free (error); | |
575 | exit (-1); | |
576 | } | |
577 | ||
578 | GtkWidget *menubar = gtk_ui_manager_get_widget(ui, "/menubar"); | |
579 | gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(menubar), FALSE, TRUE, 0); | |
580 | toolbar = GTK_TOOLBAR(gtk_ui_manager_get_widget(ui, "/toolbar")); | |
581 | gtk_box_pack_start(GTK_BOX(vbox), GTK_WIDGET(toolbar), FALSE, TRUE, 0); | |
582 | ||
583 | /* Device selection GtkComboBox */ | |
584 | GtkToolItem *toolitem = gtk_tool_item_new(); | |
585 | GtkWidget *align = gtk_alignment_new(0.5, 0.5, 2, 0); | |
586 | GtkWidget *dev = dev_select_combo_box_new(parent); | |
587 | ||
588 | gtk_container_add(GTK_CONTAINER(align), dev); | |
589 | gtk_container_add(GTK_CONTAINER(toolitem), align); | |
590 | gtk_toolbar_insert(toolbar, toolitem, 0); | |
591 | ||
592 | /* Time/Samples entry */ | |
593 | toolitem = gtk_tool_item_new(); | |
594 | GtkWidget *timesamples = gtk_entry_new(); | |
595 | gtk_entry_set_text(GTK_ENTRY(timesamples), "100"); | |
596 | gtk_entry_set_alignment(GTK_ENTRY(timesamples), 1.0); | |
597 | gtk_widget_set_size_request(timesamples, 100, -1); | |
598 | gtk_container_add(GTK_CONTAINER(toolitem), timesamples); | |
599 | gtk_toolbar_insert(toolbar, toolitem, 7); | |
600 | ||
601 | /* Time unit combo box */ | |
602 | toolitem = gtk_tool_item_new(); | |
603 | align = gtk_alignment_new(0.5, 0.5, 2, 0); | |
604 | GtkWidget *timeunit = gtk_combo_box_new_text(); | |
605 | gtk_combo_box_append_text(GTK_COMBO_BOX(timeunit), "samples"); | |
606 | gtk_combo_box_append_text(GTK_COMBO_BOX(timeunit), "ms"); | |
607 | gtk_combo_box_append_text(GTK_COMBO_BOX(timeunit), "s"); | |
608 | gtk_combo_box_set_active(GTK_COMBO_BOX(timeunit), 0); | |
609 | gtk_container_add(GTK_CONTAINER(align), timeunit); | |
610 | gtk_container_add(GTK_CONTAINER(toolitem), align); | |
611 | gtk_toolbar_insert(toolbar, toolitem, 8); | |
612 | ||
613 | g_object_set_data(G_OBJECT(parent), "timesamples", timesamples); | |
614 | g_object_set_data(G_OBJECT(parent), "timeunit", timeunit); | |
615 | ||
616 | return GTK_WIDGET(vbox); | |
617 | } | |
618 |