Root/
Source at commit bc27b094af74a7c6f8b71ceaa63d1ba80d067cbb created 13 years 11 months ago. By werner, With a little help from m8cutils and abyss, we now have regression tests for the topological sort. "make test" or "make tests" invokes the regression tests, "make valgrind" runs them under valgrind's watchful eyes. | |
---|---|
1 | /* |
2 | * gui.c - Editor GUI core |
3 | * |
4 | * Written 2009, 2010 by Werner Almesberger |
5 | * Copyright 2009, 2010 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 <locale.h> |
15 | #include <gtk/gtk.h> |
16 | |
17 | #include "inst.h" |
18 | #include "file.h" |
19 | #include "gui_util.h" |
20 | #include "gui_style.h" |
21 | #include "gui_status.h" |
22 | #include "gui_canvas.h" |
23 | #include "gui_tool.h" |
24 | #include "gui_frame.h" |
25 | #include "gui.h" |
26 | #include "fped.h" |
27 | |
28 | #include "icons/stuff.xpm" |
29 | #include "icons/stuff_off.xpm" |
30 | #include "icons/meas.xpm" |
31 | #include "icons/meas_off.xpm" |
32 | #include "icons/all.xpm" |
33 | #include "icons/all_off.xpm" |
34 | #include "icons/bright.xpm" |
35 | #include "icons/bright_off.xpm" |
36 | |
37 | |
38 | GtkWidget *root; |
39 | int show_all = 1; |
40 | int show_stuff = 1; |
41 | int show_meas = 1; |
42 | int show_bright = 0; |
43 | |
44 | |
45 | static GtkWidget *paned; |
46 | static GtkWidget *frames_box; |
47 | static GtkWidget *ev_stuff, *ev_meas, *ev_all, *ev_bright; |
48 | static GtkWidget *stuff_image[2], *meas_image[2], *all_image[2]; |
49 | static GtkWidget *bright_image[2]; |
50 | |
51 | static void do_build_frames(void); |
52 | |
53 | |
54 | /* ----- save callbacks ---------------------------------------------------- */ |
55 | |
56 | |
57 | static void save_as_fpd(void) |
58 | { |
59 | GtkWidget *dialog; |
60 | |
61 | dialog = gtk_file_chooser_dialog_new("Save File", |
62 | NULL, GTK_FILE_CHOOSER_ACTION_SAVE, |
63 | GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, |
64 | GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, NULL); |
65 | gtk_file_chooser_set_do_overwrite_confirmation( |
66 | GTK_FILE_CHOOSER(dialog), TRUE); |
67 | if (save_file_name) |
68 | gtk_file_chooser_set_filename(GTK_FILE_CHOOSER(dialog), |
69 | save_file_name); |
70 | if (gtk_dialog_run(GTK_DIALOG (dialog)) == GTK_RESPONSE_ACCEPT) { |
71 | save_file_name = |
72 | gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog)); |
73 | save_fpd(); |
74 | /* @@@ we may leak save_file_name */ |
75 | no_save = 0; |
76 | } |
77 | gtk_widget_destroy(dialog); |
78 | } |
79 | |
80 | |
81 | /* ----- view callbacks ---------------------------------------------------- */ |
82 | |
83 | |
84 | static void swap_var_code(void) |
85 | { |
86 | extern int show_vars; |
87 | |
88 | show_vars = !show_vars; |
89 | change_world(); |
90 | } |
91 | |
92 | |
93 | /* ----- menu bar ---------------------------------------------------------- */ |
94 | |
95 | |
96 | static GtkItemFactoryEntry menu_entries[] = { |
97 | { "/File", NULL, NULL, 0, "<Branch>" }, |
98 | { "/File/Save", NULL, save_fpd, 0, "<Item>" }, |
99 | { "/File/Save as", NULL, save_as_fpd, 0, "<Item>" }, |
100 | { "/File/sep1", NULL, NULL, 0, "<Separator>" }, |
101 | { "/File/Write KiCad", NULL, write_kicad, 0, "<Item>" }, |
102 | { "/File/Write Postscript", |
103 | NULL, write_ps, 0, "<Item>" }, |
104 | { "/File/sep2", NULL, NULL, 0, "<Separator>" }, |
105 | { "/File/Quit", NULL, gtk_main_quit, 0, "<Item>" }, |
106 | { "/View", NULL, NULL, 0, "<Branch>" }, |
107 | { "/View/Zoom in", NULL, zoom_in_center, 0, "<Item>" }, |
108 | { "/View/Zoom out", NULL, zoom_out_center,0, "<Item>" }, |
109 | { "/View/Zoom all", NULL, zoom_to_extents,0, "<Item>" }, |
110 | { "/View/Zoom frame", NULL, zoom_to_frame, 0, "<Item>" }, |
111 | { "/View/sep1", NULL, NULL, 0, "<Separator>" }, |
112 | { "/View/Swap var&code",NULL, swap_var_code, 0, "<Item>" }, |
113 | }; |
114 | |
115 | |
116 | static void make_menu_bar(GtkWidget *hbox) |
117 | { |
118 | GtkItemFactory *factory; |
119 | GtkWidget *bar; |
120 | |
121 | factory = gtk_item_factory_new(GTK_TYPE_MENU_BAR, "<FpedMenu>", NULL); |
122 | gtk_item_factory_create_items(factory, |
123 | sizeof(menu_entries)/sizeof(*menu_entries), menu_entries, NULL); |
124 | |
125 | bar = gtk_item_factory_get_widget(factory, "<FpedMenu>"); |
126 | gtk_box_pack_start(GTK_BOX(hbox), bar, TRUE, TRUE, 0); |
127 | |
128 | gtk_widget_set_sensitive( |
129 | gtk_item_factory_get_item(factory, "/File/Save"), !no_save); |
130 | } |
131 | |
132 | |
133 | static gboolean toggle_all(GtkWidget *widget, GdkEventButton *event, |
134 | gpointer data) |
135 | { |
136 | switch (event->button) { |
137 | case 1: |
138 | show_all = !show_all; |
139 | set_image(ev_all, all_image[show_all]); |
140 | inst_deselect(); |
141 | redraw(); |
142 | break; |
143 | } |
144 | return TRUE; |
145 | } |
146 | |
147 | |
148 | static gboolean toggle_stuff(GtkWidget *widget, GdkEventButton *event, |
149 | gpointer data) |
150 | { |
151 | switch (event->button) { |
152 | case 1: |
153 | show_stuff = !show_stuff; |
154 | set_image(ev_stuff, stuff_image[show_stuff]); |
155 | inst_deselect(); |
156 | redraw(); |
157 | break; |
158 | } |
159 | return TRUE; |
160 | } |
161 | |
162 | |
163 | static gboolean toggle_meas(GtkWidget *widget, GdkEventButton *event, |
164 | gpointer data) |
165 | { |
166 | switch (event->button) { |
167 | case 1: |
168 | show_meas = !show_meas; |
169 | set_image(ev_meas, meas_image[show_meas]); |
170 | inst_deselect(); |
171 | redraw(); |
172 | break; |
173 | } |
174 | return TRUE; |
175 | } |
176 | |
177 | |
178 | static gboolean toggle_bright(GtkWidget *widget, GdkEventButton *event, |
179 | gpointer data) |
180 | { |
181 | switch (event->button) { |
182 | case 1: |
183 | show_bright = !show_bright; |
184 | set_image(ev_bright, bright_image[show_bright]); |
185 | inst_deselect(); |
186 | redraw(); |
187 | break; |
188 | } |
189 | return TRUE; |
190 | } |
191 | |
192 | |
193 | static void make_tool_bar(GtkWidget *hbox, GdkDrawable *drawable) |
194 | { |
195 | GtkWidget *bar; |
196 | |
197 | bar = gtk_toolbar_new(); |
198 | gtk_box_pack_end(GTK_BOX(hbox), bar, TRUE, TRUE, 0); |
199 | //gtk_box_pack_end(GTK_BOX(hbox), bar, FALSE, FALSE, 0); |
200 | gtk_toolbar_set_style(GTK_TOOLBAR(bar), GTK_TOOLBAR_ICONS); |
201 | |
202 | ev_all = tool_button(bar, drawable, NULL, NULL, toggle_all, NULL); |
203 | ev_stuff = tool_button(bar, drawable, NULL, NULL, toggle_stuff, NULL); |
204 | ev_meas = tool_button(bar, drawable, NULL, NULL, toggle_meas, NULL); |
205 | ev_bright = tool_button(bar, drawable, NULL, NULL, toggle_bright, NULL); |
206 | |
207 | stuff_image[0] = gtk_widget_ref(make_image(drawable, xpm_stuff_off, |
208 | "Show vectors and frame references (disabled)")); |
209 | stuff_image[1] = gtk_widget_ref(make_image(drawable, xpm_stuff, |
210 | "Show vectors and frame references (enabled)")); |
211 | meas_image[0] = gtk_widget_ref(make_image(drawable, xpm_meas_off, |
212 | "Show measurements (disabled)")); |
213 | meas_image[1] = gtk_widget_ref(make_image(drawable, xpm_meas, |
214 | "Show measurements (enabled)")); |
215 | all_image[0] = gtk_widget_ref(make_image(drawable, xpm_all_off, |
216 | "Show all frames (currently showing only the active frame)")); |
217 | all_image[1] = gtk_widget_ref(make_image(drawable, xpm_all, |
218 | "Show all frames (enabled)")); |
219 | bright_image[0] = gtk_widget_ref(make_image(drawable, xpm_bright_off, |
220 | "Highlight elements (disabled)")); |
221 | bright_image[1] = gtk_widget_ref(make_image(drawable, xpm_bright, |
222 | "Highlight elements (enabled)")); |
223 | |
224 | set_image(ev_stuff, stuff_image[show_stuff]); |
225 | set_image(ev_meas, meas_image[show_meas]); |
226 | set_image(ev_all, all_image[show_all]); |
227 | set_image(ev_bright, bright_image[show_bright]); |
228 | } |
229 | |
230 | |
231 | static void cleanup_tool_bar(void) |
232 | { |
233 | g_object_unref(stuff_image[0]); |
234 | g_object_unref(stuff_image[1]); |
235 | g_object_unref(meas_image[0]); |
236 | g_object_unref(meas_image[1]); |
237 | g_object_unref(all_image[0]); |
238 | g_object_unref(all_image[1]); |
239 | g_object_unref(bright_image[0]); |
240 | g_object_unref(bright_image[1]); |
241 | } |
242 | |
243 | |
244 | static void make_top_bar(GtkWidget *vbox) |
245 | { |
246 | GtkWidget *hbox; |
247 | |
248 | hbox = gtk_hbox_new(FALSE, 0); |
249 | make_menu_bar(hbox); |
250 | make_tool_bar(hbox, root->window); |
251 | gtk_box_pack_start(GTK_BOX(vbox), hbox, FALSE, FALSE, 0); |
252 | } |
253 | |
254 | |
255 | /* ----- central screen area ----------------------------------------------- */ |
256 | |
257 | |
258 | static void resize_frames_area(GtkWidget *widget, GtkAllocation *allocation, |
259 | gpointer user_data) |
260 | { |
261 | static int width = 0; |
262 | |
263 | if (allocation->width == width) |
264 | return; |
265 | width = allocation->width; |
266 | do_build_frames(); |
267 | } |
268 | |
269 | |
270 | static void make_center_area(GtkWidget *vbox) |
271 | { |
272 | GtkWidget *hbox, *frames_area;//, *paned; |
273 | GtkWidget *tools; |
274 | |
275 | hbox = gtk_hbox_new(FALSE, 0); |
276 | gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); |
277 | |
278 | paned = gtk_hpaned_new(); |
279 | gtk_box_pack_start(GTK_BOX(hbox), paned, TRUE, TRUE, 0); |
280 | |
281 | /* Frames */ |
282 | |
283 | frames_area = gtk_scrolled_window_new(NULL, NULL); |
284 | gtk_paned_add1(GTK_PANED(paned), frames_area); |
285 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(frames_area), |
286 | GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); |
287 | gtk_widget_set_size_request(frames_area, |
288 | DEFAULT_FRAME_AREA_WIDTH, DEFAULT_FRAME_AREA_HEIGHT); |
289 | |
290 | frames_box = gtk_vbox_new(FALSE, 0); |
291 | build_frames(frames_box, DEFAULT_FRAME_AREA_WIDTH); |
292 | |
293 | gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(frames_area), |
294 | frames_box); |
295 | |
296 | g_signal_connect(G_OBJECT(frames_area), "size-allocate", |
297 | G_CALLBACK(resize_frames_area), NULL); |
298 | |
299 | /* Canvas */ |
300 | |
301 | gtk_paned_add2(GTK_PANED(paned), make_canvas()); |
302 | |
303 | /* Icon bar */ |
304 | |
305 | tools = gui_setup_tools(root->window); |
306 | gtk_box_pack_end(GTK_BOX(hbox), tools, FALSE, FALSE, 0); |
307 | } |
308 | |
309 | |
310 | /* ----- GUI construction -------------------------------------------------- */ |
311 | |
312 | |
313 | static void do_build_frames(void) |
314 | { |
315 | int width; |
316 | |
317 | width = gtk_paned_get_position(GTK_PANED(paned)); |
318 | build_frames(frames_box, width > 0 ? width : DEFAULT_FRAME_AREA_WIDTH); |
319 | } |
320 | |
321 | |
322 | void change_world(void) |
323 | { |
324 | struct bbox before, after; |
325 | |
326 | inst_deselect(); |
327 | status_begin_reporting(); |
328 | before = inst_get_bbox(); |
329 | instantiate(); |
330 | after = inst_get_bbox(); |
331 | label_in_box_bg(active_frame->label, COLOR_FRAME_SELECTED); |
332 | do_build_frames(); |
333 | if (after.min.x < before.min.x || after.min.y < before.min.y || |
334 | after.max.x > before.max.x || after.max.y > before.max.y) |
335 | zoom_to_extents(); |
336 | else |
337 | redraw(); |
338 | } |
339 | |
340 | |
341 | void change_world_reselect(void) |
342 | { |
343 | struct obj *selected_obj; |
344 | |
345 | selected_obj = selected_inst->obj; |
346 | change_world(); |
347 | inst_select_obj(selected_obj); |
348 | } |
349 | |
350 | |
351 | static void make_screen(GtkWidget *window) |
352 | { |
353 | GtkWidget *vbox; |
354 | |
355 | vbox = gtk_vbox_new(FALSE, 0); |
356 | gtk_container_add(GTK_CONTAINER(window), vbox); |
357 | |
358 | make_top_bar(vbox); |
359 | make_center_area(vbox); |
360 | make_status_area(vbox); |
361 | } |
362 | |
363 | |
364 | int gui_init(int *argc, char ***argv) |
365 | { |
366 | gtk_init(argc, argv); |
367 | setlocale(LC_ALL, "C"); /* damage control */ |
368 | return 0; |
369 | } |
370 | |
371 | |
372 | int gui_main(void) |
373 | { |
374 | root = gtk_window_new(GTK_WINDOW_TOPLEVEL); |
375 | gtk_window_set_position(GTK_WINDOW(root), GTK_WIN_POS_CENTER); |
376 | gtk_window_set_default_size(GTK_WINDOW(root), 620, 460); |
377 | if (*SVN_VERSION) |
378 | gtk_window_set_title(GTK_WINDOW(root), |
379 | "fped (rev " SVN_VERSION ")"); |
380 | else |
381 | gtk_window_set_title(GTK_WINDOW(root), "fped"); |
382 | |
383 | /* get root->window */ |
384 | gtk_widget_show_all(root); |
385 | |
386 | g_signal_connect(G_OBJECT(root), "destroy", |
387 | G_CALLBACK(gtk_main_quit), NULL); |
388 | |
389 | make_screen(root); |
390 | |
391 | gtk_widget_show_all(root); |
392 | |
393 | gui_setup_style(root->window); |
394 | init_canvas(); |
395 | edit_nothing(); |
396 | select_frame(root_frame); |
397 | make_popups(); |
398 | |
399 | gtk_main(); |
400 | |
401 | gui_cleanup_style(); |
402 | gui_cleanup_tools(); |
403 | cleanup_tool_bar(); |
404 | cleanup_status_area(); |
405 | |
406 | return 0; |
407 | } |
408 |
Branches:
master