Root/gui.c

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

Archive Download this file

Branches:
master



interactive