gui.c 13 KB

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