Root/
Source at commit 377b7f81193685f23c93546767a059e194419446 created 8 years 7 days ago. By Werner Almesberger, fped.c: new option -m (for -p and -P) to suppress showing measurements | |
---|---|
1 | /* |
2 | * gui.c - Editor GUI core |
3 | * |
4 | * Written 2009-2012, 2015 by Werner Almesberger |
5 | * Copyright 2009-2012, 2015 by Werner Almesberger |
6 | * |
7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by |
9 | * the Free Software Foundation; either version 2 of the License, or |
10 | * (at your option) any later version. |
11 | */ |
12 | |
13 | |
14 | #include <stdlib.h> |
15 | #include <locale.h> |
16 | #include <gtk/gtk.h> |
17 | |
18 | #include "inst.h" |
19 | #include "file.h" |
20 | #include "gui_util.h" |
21 | #include "gui_style.h" |
22 | #include "gui_status.h" |
23 | #include "gui_canvas.h" |
24 | #include "gui_tool.h" |
25 | #include "gui_frame.h" |
26 | #include "gui.h" |
27 | #include "fped.h" |
28 | |
29 | #include "icons/stuff.xpm" |
30 | #include "icons/stuff_off.xpm" |
31 | #include "icons/meas.xpm" |
32 | #include "icons/meas_off.xpm" |
33 | #include "icons/all.xpm" |
34 | #include "icons/all_off.xpm" |
35 | #include "icons/bright.xpm" |
36 | #include "icons/bright_off.xpm" |
37 | |
38 | |
39 | GtkWidget *root; |
40 | int show_all = 1; |
41 | int show_stuff = 1; |
42 | int show_meas = 1; |
43 | int show_bright = 0; |
44 | |
45 | |
46 | static GtkWidget *paned; |
47 | static GtkWidget *frames_box; |
48 | static GtkWidget *ev_stuff, *ev_meas, *ev_all, *ev_bright; |
49 | static GtkWidget *stuff_image[2], *meas_image[2], *all_image[2]; |
50 | static GtkWidget *bright_image[2]; |
51 | |
52 | static void do_build_frames(void); |
53 | |
54 | |
55 | /* ----- save callbacks ---------------------------------------------------- */ |
56 | |
57 | |
58 | static void save_as_fpd(void) |
59 | { |
60 | GtkWidget *dialog; |
61 | |
62 | dialog = gtk_file_chooser_dialog_new("Save File", |
63 | NULL, GTK_FILE_CHOOSER_ACTION_SAVE, |
64 | GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, |
65 | GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); |
66 | gtk_file_chooser_set_do_overwrite_confirmation( |
67 | GTK_FILE_CHOOSER(dialog), TRUE); |
68 | if (save_file_name) |
69 | gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), |
70 | save_file_name); |
71 | if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { |
72 | save_file_name = |
73 | gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); |
74 | save_fpd(); |
75 | /* @@@ we may leak save_file_name */ |
76 | no_save = 0; |
77 | } |
78 | gtk_widget_destroy(dialog); |
79 | } |
80 | |
81 | |
82 | /* ----- view callbacks ---------------------------------------------------- */ |
83 | |
84 | |
85 | static void show_var(void) |
86 | { |
87 | sidebar = sidebar_var; |
88 | change_world(); |
89 | } |
90 | |
91 | |
92 | static void show_code(void) |
93 | { |
94 | sidebar = sidebar_code; |
95 | change_world(); |
96 | } |
97 | |
98 | |
99 | static void show_pkg(void) |
100 | { |
101 | sidebar = sidebar_pkg; |
102 | change_world(); |
103 | } |
104 | |
105 | |
106 | /* ----- menu bar ---------------------------------------------------------- */ |
107 | |
108 | |
109 | static GtkItemFactoryEntry menu_entries[] = { |
110 | { "/File", NULL, NULL, 0, "<Branch>" }, |
111 | { "/File/Save", NULL, save_fpd, 0, "<Item>" }, |
112 | { "/File/Save as", NULL, save_as_fpd, 0, "<Item>" }, |
113 | { "/File/sep1", NULL, NULL, 0, "<Separator>" }, |
114 | { "/File/Write KiCad", NULL, write_kicad, 0, "<Item>" }, |
115 | { "/File/Write Postscript", |
116 | NULL, write_ps, 0, "<Item>" }, |
117 | { "/File/sep2", NULL, NULL, 0, "<Separator>" }, |
118 | { "/File/Reload", NULL, reload, 0, "<Item>" }, |
119 | { "/File/sep3", NULL, NULL, 0, "<Separator>" }, |
120 | { "/File/Quit", NULL, gtk_main_quit, 0, "<Item>" }, |
121 | { "/View", NULL, NULL, 0, "<Branch>" }, |
122 | { "/View/Zoom in", NULL, zoom_in_center, 0, "<Item>" }, |
123 | { "/View/Zoom out", NULL, zoom_out_center,0, "<Item>" }, |
124 | { "/View/Zoom all", NULL, zoom_to_extents,0, "<Item>" }, |
125 | { "/View/Zoom frame", NULL, zoom_to_frame, 0, "<Item>" }, |
126 | { "/View/sep1", NULL, NULL, 0, "<Separator>" }, |
127 | { "/View/Show variables", |
128 | NULL, show_var, 0, "<RadioItem>" }, |
129 | { "/View/Show code", NULL, show_code, 0, |
130 | "/View/Show variables" }, |
131 | { "/View/Show packages",NULL, show_pkg, 0, |
132 | "/View/Show variables" }, |
133 | }; |
134 | |
135 | |
136 | static GtkItemFactory *menu_factory; |
137 | |
138 | |
139 | static void make_menu_bar(GtkWidget *hbox) |
140 | { |
141 | GtkWidget *bar; |
142 | |
143 | menu_factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<FpedMenu>", |
144 | NULL); |
145 | gtk_item_factory_create_items(menu_factory, |
146 | sizeof(menu_entries)/sizeof(*menu_entries), menu_entries, NULL); |
147 | |
148 | bar = gtk_item_factory_get_widget(menu_factory, "<FpedMenu>"); |
149 | gtk_box_pack_start(GTK_BOX(hbox), bar, TRUE, TRUE, 0); |
150 | |
151 | gtk_widget_set_sensitive( |
152 | gtk_item_factory_get_item(menu_factory, "/File/Save"), !no_save); |
153 | gtk_widget_set_sensitive( |
154 | gtk_item_factory_get_item(menu_factory, "/File/Reload"), |
155 | no_save && !!save_file_name); |
156 | } |
157 | |
158 | |
159 | void update_menu_bar(void) |
160 | { |
161 | const char *s; |
162 | |
163 | switch (sidebar) { |
164 | case sidebar_var: |
165 | s = "/View/Show variables"; |
166 | break; |
167 | case sidebar_code: |
168 | s = "/View/Show code"; |
169 | break; |
170 | case sidebar_pkg: |
171 | s = "/View/Show packages"; |
172 | break; |
173 | default: |
174 | abort(); |
175 | } |
176 | gtk_check_menu_item_set_active( |
177 | GTK_CHECK_MENU_ITEM(gtk_item_factory_get_item(menu_factory, s)), |
178 | TRUE); |
179 | } |
180 | |
181 | |
182 | static gboolean toggle_all(GtkWidget *widget, GdkEventButton *event, |
183 | gpointer data) |
184 | { |
185 | switch (event->button) { |
186 | case 1: |
187 | show_all = !show_all; |
188 | set_image(ev_all, all_image[show_all]); |
189 | inst_deselect(); |
190 | redraw(); |
191 | break; |
192 | } |
193 | return TRUE; |
194 | } |
195 | |
196 | |
197 | static gboolean toggle_stuff(GtkWidget *widget, GdkEventButton *event, |
198 | gpointer data) |
199 | { |
200 | switch (event->button) { |
201 | case 1: |
202 | show_stuff = !show_stuff; |
203 | set_image(ev_stuff, stuff_image[show_stuff]); |
204 | inst_deselect(); |
205 | redraw(); |
206 | break; |
207 | } |
208 | return TRUE; |
209 | } |
210 | |
211 | |
212 | static gboolean toggle_meas(GtkWidget *widget, GdkEventButton *event, |
213 | gpointer data) |
214 | { |
215 | switch (event->button) { |
216 | case 1: |
217 | show_meas = !show_meas; |
218 | set_image(ev_meas, meas_image[show_meas]); |
219 | inst_deselect(); |
220 | redraw(); |
221 | break; |
222 | } |
223 | return TRUE; |
224 | } |
225 | |
226 | |
227 | static gboolean toggle_bright(GtkWidget *widget, GdkEventButton *event, |
228 | gpointer data) |
229 | { |
230 | switch (event->button) { |
231 | case 1: |
232 | show_bright = !show_bright; |
233 | set_image(ev_bright, bright_image[show_bright]); |
234 | inst_deselect(); |
235 | redraw(); |
236 | break; |
237 | } |
238 | return TRUE; |
239 | } |
240 | |
241 | |
242 | static void make_tool_bar(GtkWidget *hbox, GdkDrawable *drawable) |
243 | { |
244 | GtkWidget *bar; |
245 | |
246 | bar = gtk_toolbar_new(); |
247 | gtk_box_pack_end(GTK_BOX(hbox), bar, TRUE, TRUE, 0); |
248 | //gtk_box_pack_end(GTK_BOX(hbox), bar, FALSE, FALSE, 0); |
249 | gtk_toolbar_set_style(GTK_TOOLBAR(bar), GTK_TOOLBAR_ICONS); |
250 | |
251 | ev_all = tool_button(bar, drawable, NULL, NULL, toggle_all, NULL); |
252 | ev_stuff = tool_button(bar, drawable, NULL, NULL, toggle_stuff, NULL); |
253 | ev_meas = tool_button(bar, drawable, NULL, NULL, toggle_meas, NULL); |
254 | ev_bright = tool_button(bar, drawable, NULL, NULL, toggle_bright, NULL); |
255 | |
256 | stuff_image[0] = gtk_widget_ref(make_image(drawable, xpm_stuff_off, |
257 | "Show vectors and frame references (disabled)")); |
258 | stuff_image[1] = gtk_widget_ref(make_image(drawable, xpm_stuff, |
259 | "Show vectors and frame references (enabled)")); |
260 | meas_image[0] = gtk_widget_ref(make_image(drawable, xpm_meas_off, |
261 | "Show measurements (disabled)")); |
262 | meas_image[1] = gtk_widget_ref(make_image(drawable, xpm_meas, |
263 | "Show measurements (enabled)")); |
264 | all_image[0] = gtk_widget_ref(make_image(drawable, xpm_all_off, |
265 | "Show all frames (currently showing only the active frame)")); |
266 | all_image[1] = gtk_widget_ref(make_image(drawable, xpm_all, |
267 | "Show all frames (enabled)")); |
268 | bright_image[0] = gtk_widget_ref(make_image(drawable, xpm_bright_off, |
269 | "Highlight elements (disabled)")); |
270 | bright_image[1] = gtk_widget_ref(make_image(drawable, xpm_bright, |
271 | "Highlight elements (enabled)")); |
272 | |
273 | set_image(ev_stuff, stuff_image[show_stuff]); |
274 | set_image(ev_meas, meas_image[show_meas]); |
275 | set_image(ev_all, all_image[show_all]); |
276 | set_image(ev_bright, bright_image[show_bright]); |
277 | } |
278 | |
279 | |
280 | static void cleanup_tool_bar(void) |
281 | { |
282 | g_object_unref(stuff_image[0]); |
283 | g_object_unref(stuff_image[1]); |
284 | g_object_unref(meas_image[0]); |
285 | g_object_unref(meas_image[1]); |
286 | g_object_unref(all_image[0]); |
287 | g_object_unref(all_image[1]); |
288 | g_object_unref(bright_image[0]); |
289 | g_object_unref(bright_image[1]); |
290 | } |
291 | |
292 | |
293 | static void make_top_bar(GtkWidget *vbox) |
294 | { |
295 | GtkWidget *hbox; |
296 | |
297 | hbox = gtk_hbox_new(FALSE, 0); |
298 | make_menu_bar(hbox); |
299 | make_tool_bar(hbox, root->window); |
300 | gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); |
301 | } |
302 | |
303 | |
304 | /* ----- central screen area ----------------------------------------------- */ |
305 | |
306 | |
307 | static void resize_frames_area(GtkWidget *widget, GtkAllocation *allocation, |
308 | gpointer user_data) |
309 | { |
310 | static int width = 0; |
311 | |
312 | if (allocation->width == width) |
313 | return; |
314 | width = allocation->width; |
315 | do_build_frames(); |
316 | } |
317 | |
318 | |
319 | static void make_center_area(GtkWidget *vbox) |
320 | { |
321 | GtkWidget *hbox, *frames_area;//, *paned; |
322 | GtkWidget *tools; |
323 | |
324 | hbox = gtk_hbox_new(FALSE, 0); |
325 | gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); |
326 | |
327 | paned = gtk_hpaned_new(); |
328 | gtk_box_pack_start(GTK_BOX(hbox), paned, TRUE, TRUE, 0); |
329 | |
330 | /* Frames */ |
331 | |
332 | frames_area = gtk_scrolled_window_new(NULL, NULL); |
333 | gtk_paned_add1(GTK_PANED(paned), frames_area); |
334 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(frames_area), |
335 | GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); |
336 | gtk_widget_set_size_request(frames_area, |
337 | DEFAULT_FRAME_AREA_WIDTH, DEFAULT_FRAME_AREA_HEIGHT); |
338 | |
339 | frames_box = gtk_vbox_new(FALSE, 0); |
340 | build_frames(frames_box, DEFAULT_FRAME_AREA_WIDTH); |
341 | |
342 | gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(frames_area), |
343 | frames_box); |
344 | |
345 | g_signal_connect(G_OBJECT(frames_area), "size-allocate", |
346 | G_CALLBACK(resize_frames_area), NULL); |
347 | |
348 | /* Canvas */ |
349 | |
350 | gtk_paned_add2(GTK_PANED(paned), make_canvas()); |
351 | |
352 | /* Icon bar */ |
353 | |
354 | tools = gui_setup_tools(root->window); |
355 | gtk_box_pack_end(GTK_BOX(hbox), tools, FALSE, FALSE, 0); |
356 | } |
357 | |
358 | |
359 | /* ----- GUI construction -------------------------------------------------- */ |
360 | |
361 | |
362 | static void do_build_frames(void) |
363 | { |
364 | int width; |
365 | |
366 | width = gtk_paned_get_position(GTK_PANED(paned)); |
367 | build_frames(frames_box, width > 0 ? width : DEFAULT_FRAME_AREA_WIDTH); |
368 | } |
369 | |
370 | |
371 | void change_world(void) |
372 | { |
373 | struct bbox before, after; |
374 | int reachable_is_active; |
375 | |
376 | inst_deselect(); |
377 | status_begin_reporting(); |
378 | before = inst_get_bbox(NULL); |
379 | reachable_is_active = reachable_pkg && reachable_pkg == active_pkg; |
380 | instantiate(); |
381 | if (reachable_is_active && reachable_pkg && |
382 | reachable_pkg != active_pkg) { |
383 | active_pkg = reachable_pkg; |
384 | instantiate(); |
385 | } |
386 | after = inst_get_bbox(NULL); |
387 | do_build_frames(); |
388 | if (after.min.x < before.min.x || after.min.y < before.min.y || |
389 | after.max.x > before.max.x || after.max.y > before.max.y) |
390 | zoom_to_extents(); |
391 | else |
392 | redraw(); |
393 | } |
394 | |
395 | |
396 | void change_world_reselect(void) |
397 | { |
398 | struct obj *selected_obj; |
399 | |
400 | /* |
401 | * We can edit an object even if it's not selected if it was picked |
402 | * via the item view. inst_select_obj tries to find an instance, but |
403 | * if there's never been a successful instantiation since creation of |
404 | * the object or if the object is unreachable for some other reason, |
405 | * then selected_inst will be NULL. |
406 | */ |
407 | if (!selected_inst) { |
408 | change_world(); |
409 | return; |
410 | } |
411 | selected_obj = selected_inst->obj; |
412 | change_world(); |
413 | inst_select_obj(selected_obj); |
414 | } |
415 | |
416 | |
417 | static void make_screen(GtkWidget *window) |
418 | { |
419 | GtkWidget *vbox; |
420 | |
421 | vbox = gtk_vbox_new(FALSE, 0); |
422 | gtk_container_add(GTK_CONTAINER(window), vbox); |
423 | |
424 | make_top_bar(vbox); |
425 | make_center_area(vbox); |
426 | make_status_area(vbox); |
427 | } |
428 | |
429 | |
430 | int gui_init(int *argc, char ***argv) |
431 | { |
432 | gtk_init(argc, argv); |
433 | setlocale(LC_ALL, "C"); /* damage control */ |
434 | return 0; |
435 | } |
436 | |
437 | |
438 | int gui_main(void) |
439 | { |
440 | root = gtk_window_new(GTK_WINDOW_TOPLEVEL); |
441 | gtk_window_set_position(GTK_WINDOW(root), GTK_WIN_POS_CENTER); |
442 | gtk_window_set_default_size(GTK_WINDOW(root), 620, 460); |
443 | if (*VERSION) |
444 | gtk_window_set_title(GTK_WINDOW(root), |
445 | "fped (rev " VERSION ")"); |
446 | else |
447 | gtk_window_set_title(GTK_WINDOW(root), "fped"); |
448 | |
449 | /* get root->window */ |
450 | gtk_widget_show_all(root); |
451 | |
452 | g_signal_connect(G_OBJECT(root), "destroy", |
453 | G_CALLBACK(gtk_main_quit), NULL); |
454 | |
455 | make_screen(root); |
456 | |
457 | gtk_widget_show_all(root); |
458 | |
459 | gui_setup_style(root->window); |
460 | init_canvas(); |
461 | edit_nothing(); |
462 | select_frame(frames); |
463 | make_popups(); |
464 | |
465 | gtk_main(); |
466 | |
467 | gui_cleanup_style(); |
468 | gui_cleanup_tools(); |
469 | cleanup_tool_bar(); |
470 | cleanup_status_area(); |
471 | |
472 | return 0; |
473 | } |
474 |
Branches:
master