mirror of
git://projects.qi-hardware.com/fped.git
synced 2024-11-18 06:59:43 +02:00
86c082f5a9
Until now, everything used the bounding box of the root frame which contains all the packages, visible or not. We now also record what ends up in which package, allowing inst_get_bbox to return the bounding box of a specific package. This is mainly useful for scaling Postscript output where only one package is printed per sheet and there is not much point in reserving space for any other packages that may be generated from the same footprint definition.
426 lines
11 KiB
C
426 lines
11 KiB
C
/*
|
|
* gui.c - Editor GUI core
|
|
*
|
|
* Written 2009-2012 by Werner Almesberger
|
|
* Copyright 2009-2012 by Werner Almesberger
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*/
|
|
|
|
|
|
#include <locale.h>
|
|
#include <gtk/gtk.h>
|
|
|
|
#include "inst.h"
|
|
#include "file.h"
|
|
#include "gui_util.h"
|
|
#include "gui_style.h"
|
|
#include "gui_status.h"
|
|
#include "gui_canvas.h"
|
|
#include "gui_tool.h"
|
|
#include "gui_frame.h"
|
|
#include "gui.h"
|
|
#include "fped.h"
|
|
|
|
#include "icons/stuff.xpm"
|
|
#include "icons/stuff_off.xpm"
|
|
#include "icons/meas.xpm"
|
|
#include "icons/meas_off.xpm"
|
|
#include "icons/all.xpm"
|
|
#include "icons/all_off.xpm"
|
|
#include "icons/bright.xpm"
|
|
#include "icons/bright_off.xpm"
|
|
|
|
|
|
GtkWidget *root;
|
|
int show_all = 1;
|
|
int show_stuff = 1;
|
|
int show_meas = 1;
|
|
int show_bright = 0;
|
|
|
|
|
|
static GtkWidget *paned;
|
|
static GtkWidget *frames_box;
|
|
static GtkWidget *ev_stuff, *ev_meas, *ev_all, *ev_bright;
|
|
static GtkWidget *stuff_image[2], *meas_image[2], *all_image[2];
|
|
static GtkWidget *bright_image[2];
|
|
|
|
static void do_build_frames(void);
|
|
|
|
|
|
/* ----- save callbacks ---------------------------------------------------- */
|
|
|
|
|
|
static void save_as_fpd(void)
|
|
{
|
|
GtkWidget *dialog;
|
|
|
|
dialog = gtk_file_chooser_dialog_new("Save File",
|
|
NULL, GTK_FILE_CHOOSER_ACTION_SAVE,
|
|
GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
|
|
GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL);
|
|
gtk_file_chooser_set_do_overwrite_confirmation(
|
|
GTK_FILE_CHOOSER(dialog), TRUE);
|
|
if (save_file_name)
|
|
gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog),
|
|
save_file_name);
|
|
if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) {
|
|
save_file_name =
|
|
gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
|
|
save_fpd();
|
|
/* @@@ we may leak save_file_name */
|
|
no_save = 0;
|
|
}
|
|
gtk_widget_destroy(dialog);
|
|
}
|
|
|
|
|
|
/* ----- view callbacks ---------------------------------------------------- */
|
|
|
|
|
|
static void swap_var_code(void)
|
|
{
|
|
extern int show_vars;
|
|
|
|
show_vars = !show_vars;
|
|
change_world();
|
|
}
|
|
|
|
|
|
/* ----- menu bar ---------------------------------------------------------- */
|
|
|
|
|
|
static GtkItemFactoryEntry menu_entries[] = {
|
|
{ "/File", NULL, NULL, 0, "<Branch>" },
|
|
{ "/File/Save", NULL, save_fpd, 0, "<Item>" },
|
|
{ "/File/Save as", NULL, save_as_fpd, 0, "<Item>" },
|
|
{ "/File/sep1", NULL, NULL, 0, "<Separator>" },
|
|
{ "/File/Write KiCad", NULL, write_kicad, 0, "<Item>" },
|
|
{ "/File/Write Postscript",
|
|
NULL, write_ps, 0, "<Item>" },
|
|
{ "/File/sep2", NULL, NULL, 0, "<Separator>" },
|
|
{ "/File/Quit", NULL, gtk_main_quit, 0, "<Item>" },
|
|
{ "/View", NULL, NULL, 0, "<Branch>" },
|
|
{ "/View/Zoom in", NULL, zoom_in_center, 0, "<Item>" },
|
|
{ "/View/Zoom out", NULL, zoom_out_center,0, "<Item>" },
|
|
{ "/View/Zoom all", NULL, zoom_to_extents,0, "<Item>" },
|
|
{ "/View/Zoom frame", NULL, zoom_to_frame, 0, "<Item>" },
|
|
{ "/View/sep1", NULL, NULL, 0, "<Separator>" },
|
|
{ "/View/Swap var&code",NULL, swap_var_code, 0, "<Item>" },
|
|
};
|
|
|
|
|
|
static void make_menu_bar(GtkWidget *hbox)
|
|
{
|
|
GtkItemFactory *factory;
|
|
GtkWidget *bar;
|
|
|
|
factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<FpedMenu>", NULL);
|
|
gtk_item_factory_create_items(factory,
|
|
sizeof(menu_entries)/sizeof(*menu_entries), menu_entries, NULL);
|
|
|
|
bar = gtk_item_factory_get_widget(factory, "<FpedMenu>");
|
|
gtk_box_pack_start(GTK_BOX(hbox), bar, TRUE, TRUE, 0);
|
|
|
|
gtk_widget_set_sensitive(
|
|
gtk_item_factory_get_item(factory, "/File/Save"), !no_save);
|
|
}
|
|
|
|
|
|
static gboolean toggle_all(GtkWidget *widget, GdkEventButton *event,
|
|
gpointer data)
|
|
{
|
|
switch (event->button) {
|
|
case 1:
|
|
show_all = !show_all;
|
|
set_image(ev_all, all_image[show_all]);
|
|
inst_deselect();
|
|
redraw();
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static gboolean toggle_stuff(GtkWidget *widget, GdkEventButton *event,
|
|
gpointer data)
|
|
{
|
|
switch (event->button) {
|
|
case 1:
|
|
show_stuff = !show_stuff;
|
|
set_image(ev_stuff, stuff_image[show_stuff]);
|
|
inst_deselect();
|
|
redraw();
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static gboolean toggle_meas(GtkWidget *widget, GdkEventButton *event,
|
|
gpointer data)
|
|
{
|
|
switch (event->button) {
|
|
case 1:
|
|
show_meas = !show_meas;
|
|
set_image(ev_meas, meas_image[show_meas]);
|
|
inst_deselect();
|
|
redraw();
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static gboolean toggle_bright(GtkWidget *widget, GdkEventButton *event,
|
|
gpointer data)
|
|
{
|
|
switch (event->button) {
|
|
case 1:
|
|
show_bright = !show_bright;
|
|
set_image(ev_bright, bright_image[show_bright]);
|
|
inst_deselect();
|
|
redraw();
|
|
break;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
static void make_tool_bar(GtkWidget *hbox, GdkDrawable *drawable)
|
|
{
|
|
GtkWidget *bar;
|
|
|
|
bar = gtk_toolbar_new();
|
|
gtk_box_pack_end(GTK_BOX(hbox), bar, TRUE, TRUE, 0);
|
|
//gtk_box_pack_end(GTK_BOX(hbox), bar, FALSE, FALSE, 0);
|
|
gtk_toolbar_set_style(GTK_TOOLBAR(bar), GTK_TOOLBAR_ICONS);
|
|
|
|
ev_all = tool_button(bar, drawable, NULL, NULL, toggle_all, NULL);
|
|
ev_stuff = tool_button(bar, drawable, NULL, NULL, toggle_stuff, NULL);
|
|
ev_meas = tool_button(bar, drawable, NULL, NULL, toggle_meas, NULL);
|
|
ev_bright = tool_button(bar, drawable, NULL, NULL, toggle_bright, NULL);
|
|
|
|
stuff_image[0] = gtk_widget_ref(make_image(drawable, xpm_stuff_off,
|
|
"Show vectors and frame references (disabled)"));
|
|
stuff_image[1] = gtk_widget_ref(make_image(drawable, xpm_stuff,
|
|
"Show vectors and frame references (enabled)"));
|
|
meas_image[0] = gtk_widget_ref(make_image(drawable, xpm_meas_off,
|
|
"Show measurements (disabled)"));
|
|
meas_image[1] = gtk_widget_ref(make_image(drawable, xpm_meas,
|
|
"Show measurements (enabled)"));
|
|
all_image[0] = gtk_widget_ref(make_image(drawable, xpm_all_off,
|
|
"Show all frames (currently showing only the active frame)"));
|
|
all_image[1] = gtk_widget_ref(make_image(drawable, xpm_all,
|
|
"Show all frames (enabled)"));
|
|
bright_image[0] = gtk_widget_ref(make_image(drawable, xpm_bright_off,
|
|
"Highlight elements (disabled)"));
|
|
bright_image[1] = gtk_widget_ref(make_image(drawable, xpm_bright,
|
|
"Highlight elements (enabled)"));
|
|
|
|
set_image(ev_stuff, stuff_image[show_stuff]);
|
|
set_image(ev_meas, meas_image[show_meas]);
|
|
set_image(ev_all, all_image[show_all]);
|
|
set_image(ev_bright, bright_image[show_bright]);
|
|
}
|
|
|
|
|
|
static void cleanup_tool_bar(void)
|
|
{
|
|
g_object_unref(stuff_image[0]);
|
|
g_object_unref(stuff_image[1]);
|
|
g_object_unref(meas_image[0]);
|
|
g_object_unref(meas_image[1]);
|
|
g_object_unref(all_image[0]);
|
|
g_object_unref(all_image[1]);
|
|
g_object_unref(bright_image[0]);
|
|
g_object_unref(bright_image[1]);
|
|
}
|
|
|
|
|
|
static void make_top_bar(GtkWidget *vbox)
|
|
{
|
|
GtkWidget *hbox;
|
|
|
|
hbox = gtk_hbox_new(FALSE, 0);
|
|
make_menu_bar(hbox);
|
|
make_tool_bar(hbox, root->window);
|
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0);
|
|
}
|
|
|
|
|
|
/* ----- central screen area ----------------------------------------------- */
|
|
|
|
|
|
static void resize_frames_area(GtkWidget *widget, GtkAllocation *allocation,
|
|
gpointer user_data)
|
|
{
|
|
static int width = 0;
|
|
|
|
if (allocation->width == width)
|
|
return;
|
|
width = allocation->width;
|
|
do_build_frames();
|
|
}
|
|
|
|
|
|
static void make_center_area(GtkWidget *vbox)
|
|
{
|
|
GtkWidget *hbox, *frames_area;//, *paned;
|
|
GtkWidget *tools;
|
|
|
|
hbox = gtk_hbox_new(FALSE, 0);
|
|
gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0);
|
|
|
|
paned = gtk_hpaned_new();
|
|
gtk_box_pack_start(GTK_BOX(hbox), paned, TRUE, TRUE, 0);
|
|
|
|
/* Frames */
|
|
|
|
frames_area = gtk_scrolled_window_new(NULL, NULL);
|
|
gtk_paned_add1(GTK_PANED(paned), frames_area);
|
|
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(frames_area),
|
|
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
|
|
gtk_widget_set_size_request(frames_area,
|
|
DEFAULT_FRAME_AREA_WIDTH, DEFAULT_FRAME_AREA_HEIGHT);
|
|
|
|
frames_box = gtk_vbox_new(FALSE, 0);
|
|
build_frames(frames_box, DEFAULT_FRAME_AREA_WIDTH);
|
|
|
|
gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(frames_area),
|
|
frames_box);
|
|
|
|
g_signal_connect(G_OBJECT(frames_area), "size-allocate",
|
|
G_CALLBACK(resize_frames_area), NULL);
|
|
|
|
/* Canvas */
|
|
|
|
gtk_paned_add2(GTK_PANED(paned), make_canvas());
|
|
|
|
/* Icon bar */
|
|
|
|
tools = gui_setup_tools(root->window);
|
|
gtk_box_pack_end(GTK_BOX(hbox), tools, FALSE, FALSE, 0);
|
|
}
|
|
|
|
|
|
/* ----- GUI construction -------------------------------------------------- */
|
|
|
|
|
|
static void do_build_frames(void)
|
|
{
|
|
int width;
|
|
|
|
width = gtk_paned_get_position(GTK_PANED(paned));
|
|
build_frames(frames_box, width > 0 ? width : DEFAULT_FRAME_AREA_WIDTH);
|
|
}
|
|
|
|
|
|
void change_world(void)
|
|
{
|
|
struct bbox before, after;
|
|
int reachable_is_active;
|
|
|
|
inst_deselect();
|
|
status_begin_reporting();
|
|
before = inst_get_bbox(NULL);
|
|
reachable_is_active = reachable_pkg && reachable_pkg == active_pkg;
|
|
instantiate();
|
|
if (reachable_is_active && reachable_pkg &&
|
|
reachable_pkg != active_pkg) {
|
|
active_pkg = reachable_pkg;
|
|
instantiate();
|
|
}
|
|
after = inst_get_bbox(NULL);
|
|
label_in_box_bg(active_frame->label, COLOR_FRAME_SELECTED);
|
|
do_build_frames();
|
|
if (after.min.x < before.min.x || after.min.y < before.min.y ||
|
|
after.max.x > before.max.x || after.max.y > before.max.y)
|
|
zoom_to_extents();
|
|
else
|
|
redraw();
|
|
}
|
|
|
|
|
|
void change_world_reselect(void)
|
|
{
|
|
struct obj *selected_obj;
|
|
|
|
/*
|
|
* We can edit an object even if it's not selected if it was picked
|
|
* via the item view. inst_select_obj tries to find an instance, but
|
|
* if there's never been a successful instantiation since creation of
|
|
* the object or if the object is unreachable for some other reason,
|
|
* then selected_inst will be NULL.
|
|
*/
|
|
if (!selected_inst) {
|
|
change_world();
|
|
return;
|
|
}
|
|
selected_obj = selected_inst->obj;
|
|
change_world();
|
|
inst_select_obj(selected_obj);
|
|
}
|
|
|
|
|
|
static void make_screen(GtkWidget *window)
|
|
{
|
|
GtkWidget *vbox;
|
|
|
|
vbox = gtk_vbox_new(FALSE, 0);
|
|
gtk_container_add(GTK_CONTAINER(window), vbox);
|
|
|
|
make_top_bar(vbox);
|
|
make_center_area(vbox);
|
|
make_status_area(vbox);
|
|
}
|
|
|
|
|
|
int gui_init(int *argc, char ***argv)
|
|
{
|
|
gtk_init(argc, argv);
|
|
setlocale(LC_ALL, "C"); /* damage control */
|
|
return 0;
|
|
}
|
|
|
|
|
|
int gui_main(void)
|
|
{
|
|
root = gtk_window_new(GTK_WINDOW_TOPLEVEL);
|
|
gtk_window_set_position(GTK_WINDOW(root), GTK_WIN_POS_CENTER);
|
|
gtk_window_set_default_size(GTK_WINDOW(root), 620, 460);
|
|
if (*VERSION)
|
|
gtk_window_set_title(GTK_WINDOW(root),
|
|
"fped (rev " VERSION ")");
|
|
else
|
|
gtk_window_set_title(GTK_WINDOW(root), "fped");
|
|
|
|
/* get root->window */
|
|
gtk_widget_show_all(root);
|
|
|
|
g_signal_connect(G_OBJECT(root), "destroy",
|
|
G_CALLBACK(gtk_main_quit), NULL);
|
|
|
|
make_screen(root);
|
|
|
|
gtk_widget_show_all(root);
|
|
|
|
gui_setup_style(root->window);
|
|
init_canvas();
|
|
edit_nothing();
|
|
select_frame(frames);
|
|
make_popups();
|
|
|
|
gtk_main();
|
|
|
|
gui_cleanup_style();
|
|
gui_cleanup_tools();
|
|
cleanup_tool_bar();
|
|
cleanup_status_area();
|
|
|
|
return 0;
|
|
}
|