Root/
Source at commit 0fb83ed27446be7bc114945ca6e74895ac4e65b6 created 13 years 5 months ago. By Xiangfu Liu, use usual name for orig tarball top-level directory | |
---|---|
1 | /* |
2 | * gui_tool.c - GUI, tool bar |
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 <stdlib.h> |
15 | #include <math.h> |
16 | #include <assert.h> |
17 | #include <gtk/gtk.h> |
18 | |
19 | #include "util.h" |
20 | #include "inst.h" |
21 | #include "meas.h" |
22 | #include "obj.h" |
23 | #include "gui_util.h" |
24 | #include "gui_style.h" |
25 | #include "gui_inst.h" |
26 | #include "gui_over.h" |
27 | #include "gui_canvas.h" |
28 | #include "gui_status.h" |
29 | #include "gui.h" |
30 | #include "gui_meas.h" |
31 | #include "gui_tool.h" |
32 | |
33 | |
34 | #include "icons/arc.xpm" |
35 | #include "icons/circ.xpm" |
36 | #include "icons/frame.xpm" |
37 | #include "icons/line.xpm" |
38 | #include "icons/meas.xpm" |
39 | #include "icons/meas_x.xpm" |
40 | #include "icons/meas_y.xpm" |
41 | #include "icons/pad.xpm" |
42 | #include "icons/rpad.xpm" |
43 | #include "icons/hole.xpm" |
44 | #include "icons/point.xpm" |
45 | #include "icons/delete.xpm" |
46 | #include "icons/delete_off.xpm" |
47 | #include "icons/rect.xpm" |
48 | #include "icons/vec.xpm" |
49 | |
50 | |
51 | static GtkWidget *ev_point, *ev_delete; |
52 | static GtkWidget *active_tool; |
53 | static struct tool_ops *active_ops = NULL; |
54 | static struct inst *hover_inst = NULL; |
55 | static GtkWidget *delete_image[2]; |
56 | |
57 | static struct drag_state { |
58 | struct inst *inst; /* non-NULL if dragging an existing object */ |
59 | struct inst *new; /* non-NULL if dragging a new object */ |
60 | int anchors_n; /* number of anchors, 0 if no moving */ |
61 | int anchor_i; /* current anchor */ |
62 | struct vec **anchors[3]; |
63 | } drag = { |
64 | .new = NULL, |
65 | .anchors_n = 0, |
66 | }; |
67 | |
68 | static struct coord last_canvas_pos; |
69 | |
70 | |
71 | static struct vec *new_vec(struct inst *base) |
72 | { |
73 | struct vec *vec, **walk; |
74 | |
75 | vec = alloc_type(struct vec); |
76 | vec->name = NULL; |
77 | vec->base = inst_get_vec(base); |
78 | vec->next = NULL; |
79 | vec->frame = active_frame; |
80 | for (walk = &active_frame->vecs; *walk; walk = &(*walk)->next); |
81 | *walk = vec; |
82 | return vec; |
83 | } |
84 | |
85 | |
86 | struct obj *new_obj_unconnected(enum obj_type type, struct inst *base) |
87 | { |
88 | struct obj *obj; |
89 | |
90 | obj = alloc_type(struct obj); |
91 | obj->type = type; |
92 | obj->name = NULL; |
93 | obj->frame = active_frame; |
94 | obj->base = inst_get_vec(base); |
95 | obj->next = NULL; |
96 | obj->lineno = 0; |
97 | return obj; |
98 | } |
99 | |
100 | |
101 | void connect_obj(struct frame *frame, struct obj *obj) |
102 | { |
103 | struct obj **walk; |
104 | |
105 | obj->frame = frame; |
106 | for (walk = &frame->objs; *walk; walk = &(*walk)->next); |
107 | *walk = obj; |
108 | } |
109 | |
110 | |
111 | static struct obj *new_obj(enum obj_type type, struct inst *base) |
112 | { |
113 | struct obj *obj; |
114 | |
115 | obj = new_obj_unconnected(type, base); |
116 | connect_obj(active_frame, obj); |
117 | return obj; |
118 | } |
119 | |
120 | |
121 | /* ----- shared functions -------------------------------------------------- */ |
122 | |
123 | |
124 | struct pix_buf *draw_move_line_common(struct inst *inst, |
125 | struct coord end, struct coord pos, int i) |
126 | { |
127 | struct coord from, to; |
128 | struct pix_buf *buf; |
129 | |
130 | from = translate(inst->base); |
131 | to = translate(end); |
132 | pos = translate(pos); |
133 | switch (i) { |
134 | case 0: |
135 | from = pos; |
136 | break; |
137 | case 1: |
138 | to = pos; |
139 | break; |
140 | default: |
141 | abort(); |
142 | } |
143 | buf = save_pix_buf(DA, from.x, from.y, to.x, to.y, 1); |
144 | gdk_draw_line(DA, gc_drag, from.x, from.y, to.x, to.y); |
145 | return buf; |
146 | } |
147 | |
148 | |
149 | static struct pix_buf *draw_move_rect_common(struct inst *inst, |
150 | struct coord other, struct coord pos, int i) |
151 | { |
152 | struct coord min, max; |
153 | struct pix_buf *buf; |
154 | |
155 | min = translate(inst->base); |
156 | max = translate(other); |
157 | pos = translate(pos); |
158 | switch (i) { |
159 | case 0: |
160 | min = pos; |
161 | break; |
162 | case 1: |
163 | max = pos; |
164 | break; |
165 | default: |
166 | abort(); |
167 | } |
168 | sort_coord(&min, &max); |
169 | buf = save_pix_buf(DA, min.x, min.y, max.x, max.y, 1); |
170 | gdk_draw_rectangle(DA, gc_drag, FALSE, |
171 | min.x, min.y, max.x-min.x, max.y-min.y); |
172 | return buf; |
173 | } |
174 | |
175 | |
176 | static struct pix_buf *hover_common(GdkGC *gc, struct coord center, unit_type r) |
177 | { |
178 | struct pix_buf *buf; |
179 | |
180 | center = translate(center); |
181 | buf = save_pix_buf(DA, |
182 | center.x-r, center.y-r, center.x+r, center.y+r, 2); |
183 | draw_circle(DA, gc, FALSE, center.x, center.y, VEC_EYE_R); |
184 | return buf; |
185 | } |
186 | |
187 | |
188 | /* ----- delete ------------------------------------------------------------ */ |
189 | |
190 | |
191 | static void tool_selected_delete(void) |
192 | { |
193 | if (selected_inst) { |
194 | tool_dehover(); |
195 | inst_delete(selected_inst); |
196 | change_world(); |
197 | } |
198 | tool_reset(); |
199 | } |
200 | |
201 | |
202 | static struct tool_ops delete_ops = { |
203 | .tool_selected = tool_selected_delete, |
204 | }; |
205 | |
206 | |
207 | void tool_selected_inst(struct inst *inst) |
208 | { |
209 | set_image(ev_delete, delete_image[inst != NULL]); |
210 | } |
211 | |
212 | |
213 | /* ----- vec --------------------------------------------------------------- */ |
214 | |
215 | |
216 | static struct coord gridify(struct coord base, struct coord pos) |
217 | { |
218 | struct coord new; |
219 | unit_type unit; |
220 | |
221 | switch (curr_unit) { |
222 | case curr_unit_mm: |
223 | case curr_unit_auto: |
224 | unit = mm_to_units(0.1); |
225 | break; |
226 | case curr_unit_mil: |
227 | unit = mil_to_units(10); |
228 | break; |
229 | default: |
230 | abort(); |
231 | } |
232 | new.x = pos.x-((pos.x-base.x) % unit); |
233 | new.y = pos.y-((pos.y-base.y) % unit); |
234 | if (new.x != base.x || new.y != base.y) |
235 | return new; |
236 | if (fabs(pos.x-base.x) > fabs(pos.y-base.y)) |
237 | new.x += pos.x > base.x ? unit : -unit; |
238 | else |
239 | new.y += pos.y > base.y ? unit : -unit; |
240 | return new; |
241 | } |
242 | |
243 | |
244 | static struct pix_buf *drag_new_vec(struct inst *from, struct coord to) |
245 | { |
246 | struct coord pos; |
247 | struct pix_buf *buf; |
248 | |
249 | pos = inst_get_point(from); |
250 | to = gridify(pos, to); |
251 | status_set_type_x(NULL, "dX ="); |
252 | status_set_type_y(NULL, "dX ="); |
253 | /* @@@ use status_set_xy */ |
254 | switch (curr_unit) { |
255 | case curr_unit_mm: |
256 | case curr_unit_auto: |
257 | status_set_x(NULL, "%lg mm", units_to_mm(to.x-pos.x)); |
258 | status_set_y(NULL, "%lg mm", units_to_mm(to.y-pos.y)); |
259 | break; |
260 | case curr_unit_mil: |
261 | status_set_x(NULL, "%lg mil", units_to_mil(to.x-pos.x)); |
262 | status_set_y(NULL, "%lg mil", units_to_mil(to.y-pos.y)); |
263 | break; |
264 | default: |
265 | abort(); |
266 | } |
267 | pos = translate(pos); |
268 | to = translate(to); |
269 | buf = save_pix_buf(DA, pos.x, pos.y, to.x, to.y, 1); |
270 | gdk_draw_line(DA, gc_drag, pos.x, pos.y, to.x, to.y); |
271 | return buf; |
272 | } |
273 | |
274 | |
275 | struct pix_buf *draw_move_vec(struct inst *inst, struct coord pos, int i) |
276 | { |
277 | return draw_move_line_common(inst, |
278 | add_vec(sub_vec(inst->u.vec.end, inst->base), pos), pos, i); |
279 | } |
280 | |
281 | |
282 | struct pix_buf *gui_hover_vec(struct inst *self) |
283 | { |
284 | return hover_common(gc_vec[mode_hover], |
285 | self->u.vec.end, VEC_EYE_R); |
286 | } |
287 | |
288 | |
289 | static int end_new_raw_vec(struct inst *from, struct coord to) |
290 | { |
291 | struct vec *vec; |
292 | struct coord pos; |
293 | |
294 | vec = new_vec(from); |
295 | pos = inst_get_point(from); |
296 | to = gridify(pos, to); |
297 | switch (curr_unit) { |
298 | case curr_unit_mm: |
299 | case curr_unit_auto: |
300 | vec->x = new_num(make_mm(units_to_mm(to.x-pos.x))); |
301 | vec->y = new_num(make_mm(units_to_mm(to.y-pos.y))); |
302 | break; |
303 | case curr_unit_mil: |
304 | vec->x = new_num(make_mil(units_to_mil(to.x-pos.x))); |
305 | vec->y = new_num(make_mil(units_to_mil(to.y-pos.y))); |
306 | break; |
307 | default: |
308 | abort(); |
309 | } |
310 | return 1; |
311 | } |
312 | |
313 | |
314 | static struct tool_ops vec_ops = { |
315 | .drag_new = drag_new_vec, |
316 | .end_new_raw = end_new_raw_vec, |
317 | }; |
318 | |
319 | |
320 | /* ----- line -------------------------------------------------------------- */ |
321 | |
322 | |
323 | struct pix_buf *drag_new_line(struct inst *from, struct coord to) |
324 | { |
325 | struct coord pos; |
326 | struct pix_buf *buf; |
327 | |
328 | pos = translate(inst_get_point(from)); |
329 | to = translate(to); |
330 | buf = save_pix_buf(DA, pos.x, pos.y, to.x, to.y, 1); |
331 | gdk_draw_line(DA, gc_drag, pos.x, pos.y, to.x, to.y); |
332 | return buf; |
333 | } |
334 | |
335 | |
336 | struct pix_buf *draw_move_line(struct inst *inst, struct coord pos, int i) |
337 | { |
338 | return draw_move_line_common(inst, inst->u.rect.end, pos, i); |
339 | } |
340 | |
341 | |
342 | static int end_new_line(struct inst *from, struct inst *to) |
343 | { |
344 | struct obj *obj; |
345 | |
346 | if (from == to) |
347 | return 0; |
348 | obj = new_obj(ot_line, from); |
349 | obj->u.line.other = inst_get_vec(to); |
350 | obj->u.line.width = NULL; |
351 | return 1; |
352 | } |
353 | |
354 | |
355 | static struct tool_ops line_ops = { |
356 | .drag_new = drag_new_line, |
357 | .end_new = end_new_line, |
358 | }; |
359 | |
360 | |
361 | /* ----- rect -------------------------------------------------------------- */ |
362 | |
363 | |
364 | static struct pix_buf *drag_new_rect(struct inst *from, struct coord to) |
365 | { |
366 | struct coord pos; |
367 | struct pix_buf *buf; |
368 | |
369 | pos = translate(inst_get_point(from)); |
370 | to = translate(to); |
371 | sort_coord(&pos, &to); |
372 | buf = save_pix_buf(DA, pos.x, pos.y, to.x, to.y, 1); |
373 | gdk_draw_rectangle(DA, gc_drag, FALSE, |
374 | pos.x, pos.y, to.x-pos.x, to.y-pos.y); |
375 | return buf; |
376 | } |
377 | |
378 | |
379 | struct pix_buf *draw_move_rect(struct inst *inst, struct coord pos, int i) |
380 | { |
381 | return draw_move_rect_common(inst, inst->u.rect.end, pos, i); |
382 | } |
383 | |
384 | |
385 | static int end_new_rect(struct inst *from, struct inst *to) |
386 | { |
387 | struct obj *obj; |
388 | |
389 | if (from == to) |
390 | return 0; |
391 | obj = new_obj(ot_rect, from); |
392 | obj->u.rect.other = inst_get_vec(to); |
393 | obj->u.rect.width = NULL; |
394 | return 1; |
395 | } |
396 | |
397 | |
398 | static struct tool_ops rect_ops = { |
399 | .drag_new = drag_new_rect, |
400 | .end_new = end_new_rect, |
401 | }; |
402 | |
403 | |
404 | /* ----- pad --------------------------------------------------------------- */ |
405 | |
406 | |
407 | static int end_new_pad(struct inst *from, struct inst *to) |
408 | { |
409 | struct obj *obj; |
410 | |
411 | if (from == to) |
412 | return 0; |
413 | obj = new_obj(ot_pad, from); |
414 | obj->u.pad.other = inst_get_vec(to); |
415 | obj->u.pad.name = stralloc("?"); |
416 | obj->u.pad.rounded = 0; |
417 | obj->u.pad.type = pt_normal; |
418 | return 1; |
419 | } |
420 | |
421 | |
422 | struct pix_buf *draw_move_pad(struct inst *inst, struct coord pos, int i) |
423 | { |
424 | return draw_move_rect_common(inst, inst->u.pad.other, pos, i); |
425 | } |
426 | |
427 | |
428 | static struct tool_ops pad_ops = { |
429 | .drag_new = drag_new_rect, |
430 | .end_new = end_new_pad, |
431 | }; |
432 | |
433 | |
434 | /* ----- rounded pad ------------------------------------------------------- */ |
435 | |
436 | |
437 | static int end_new_rpad(struct inst *from, struct inst *to) |
438 | { |
439 | struct obj *obj; |
440 | |
441 | if (from == to) |
442 | return 0; |
443 | obj = new_obj(ot_pad, from); |
444 | obj->u.pad.other = inst_get_vec(to); |
445 | obj->u.pad.name = stralloc("?"); |
446 | obj->u.pad.rounded = 1; |
447 | obj->u.pad.type = pt_normal; |
448 | return 1; |
449 | } |
450 | |
451 | |
452 | struct pix_buf *draw_move_rpad(struct inst *inst, struct coord pos, int i) |
453 | { |
454 | return draw_move_rect_common(inst, inst->u.pad.other, pos, i); |
455 | } |
456 | |
457 | |
458 | static struct tool_ops rpad_ops = { |
459 | .drag_new = drag_new_rect, |
460 | .end_new = end_new_rpad, |
461 | }; |
462 | |
463 | |
464 | /* ----- hole -------------------------------------------------------------- */ |
465 | |
466 | |
467 | static int end_new_hole(struct inst *from, struct inst *to) |
468 | { |
469 | struct obj *obj; |
470 | |
471 | if (from == to) |
472 | return 0; |
473 | obj = new_obj(ot_hole, from); |
474 | obj->u.hole.other = inst_get_vec(to); |
475 | return 1; |
476 | } |
477 | |
478 | |
479 | struct pix_buf *draw_move_hole(struct inst *inst, struct coord pos, int i) |
480 | { |
481 | return draw_move_rect_common(inst, inst->u.hole.other, pos, i); |
482 | } |
483 | |
484 | |
485 | static struct tool_ops hole_ops = { |
486 | .drag_new = drag_new_rect, |
487 | .end_new = end_new_hole, |
488 | }; |
489 | |
490 | |
491 | /* ----- circ -------------------------------------------------------------- */ |
492 | |
493 | |
494 | static struct pix_buf *drag_new_circ(struct inst *from, struct coord to) |
495 | { |
496 | struct coord pos; |
497 | struct pix_buf *buf; |
498 | double r; |
499 | |
500 | pos = translate(inst_get_point(from)); |
501 | to = translate(to); |
502 | r = hypot(to.x-pos.x, to.y-pos.y); |
503 | buf = save_pix_buf(DA, pos.x-r, pos.y-r, pos.x+r, pos.y+r, 1); |
504 | draw_circle(DA, gc_drag, FALSE, pos.x, pos.y, r); |
505 | return buf; |
506 | } |
507 | |
508 | |
509 | static int end_new_circ(struct inst *from, struct inst *to) |
510 | { |
511 | struct obj *obj; |
512 | |
513 | if (from == to) |
514 | return 0; |
515 | obj = new_obj(ot_arc, from); |
516 | obj->u.arc.start = inst_get_vec(to); |
517 | obj->u.arc.end = inst_get_vec(to); |
518 | obj->u.arc.width = NULL; |
519 | return 1; |
520 | } |
521 | |
522 | |
523 | struct pix_buf *draw_move_arc(struct inst *inst, struct coord pos, int i) |
524 | { |
525 | struct coord c, from, to, end; |
526 | double r, r_save, a1, a2; |
527 | struct pix_buf *buf; |
528 | |
529 | c = translate(inst->base); |
530 | from = |
531 | translate(rotate_r(inst->base, inst->u.arc.r, inst->u.arc.a1)); |
532 | to = |
533 | translate(rotate_r(inst->base, inst->u.arc.r, inst->u.arc.a2)); |
534 | pos = translate(pos); |
535 | switch (i) { |
536 | case 0: |
537 | c = pos; |
538 | break; |
539 | case 2: |
540 | from = pos; |
541 | break; |
542 | case 1: |
543 | to = pos; |
544 | break; |
545 | default: |
546 | abort(); |
547 | } |
548 | r = hypot(from.x-c.x, from.y-c.y); |
549 | /* |
550 | * the screen coordinate system is reversed with y growing downward, |
551 | * so we have to negate the angles. |
552 | */ |
553 | a1 = -theta(c, from); |
554 | a2 = -theta(c, to); |
555 | if (a2 < a1) |
556 | a2 += 360.0; |
557 | |
558 | if (i != 2) |
559 | r_save = r; |
560 | else { |
561 | r_save = hypot(to.x-c.x, to.y-c.y); |
562 | if (r > r_save) |
563 | r_save = r; |
564 | } |
565 | buf = save_pix_buf(DA, |
566 | c.x-r_save, c.y-r_save, c.x+r_save, c.y+r_save, 1); |
567 | draw_arc(DA, gc_drag, FALSE, c.x, c.y, r, a1, a2); |
568 | if (i == 1) { |
569 | end = rotate_r(c, r_save, -a2); |
570 | gdk_draw_line(DA, gc_drag, c.x, c.y, end.x, end.y); |
571 | } |
572 | return buf; |
573 | } |
574 | |
575 | |
576 | void do_move_to_arc(struct inst *inst, struct inst *to, int i) |
577 | { |
578 | struct vec *vec = inst_get_vec(to); |
579 | struct obj *obj = inst->obj; |
580 | |
581 | switch (i) { |
582 | case 0: |
583 | obj->base = vec; |
584 | break; |
585 | case 2: |
586 | obj->u.arc.start = vec; |
587 | break; |
588 | case 1: |
589 | obj->u.arc.end = vec; |
590 | break; |
591 | default: |
592 | abort(); |
593 | } |
594 | } |
595 | |
596 | |
597 | static struct tool_ops circ_ops = { |
598 | .drag_new = drag_new_circ, |
599 | .end_new = end_new_circ, |
600 | }; |
601 | |
602 | |
603 | /* ----- frame helper ------------------------------------------------------ */ |
604 | |
605 | |
606 | int is_parent_of(const struct frame *p, const struct frame *c) |
607 | { |
608 | const struct obj *obj; |
609 | |
610 | if (p == c) |
611 | return 1; |
612 | for (obj = p->objs; obj; obj = obj->next) |
613 | if (obj->type == ot_frame) |
614 | if (is_parent_of(obj->u.frame.ref, c)) |
615 | return 1; |
616 | return 0; |
617 | } |
618 | |
619 | |
620 | /* ----- frame ------------------------------------------------------------- */ |
621 | |
622 | |
623 | static struct frame *locked_frame = NULL; |
624 | |
625 | |
626 | struct pix_buf *draw_move_frame(struct inst *inst, struct coord pos, int i) |
627 | { |
628 | struct pix_buf *buf; |
629 | int r = FRAME_EYE_R2; |
630 | |
631 | pos = translate(pos); |
632 | buf = save_pix_buf(DA, pos.x-r, pos.y-r, pos.x+r, pos.y+r, 1); |
633 | draw_arc(DA, gc_drag, FALSE, pos.x, pos.y, r, 0, 360); |
634 | return buf; |
635 | } |
636 | |
637 | |
638 | struct pix_buf *gui_hover_frame(struct inst *self) |
639 | { |
640 | return hover_common(gc_frame[mode_hover], |
641 | self->base, FRAME_EYE_R2); |
642 | } |
643 | |
644 | |
645 | static int end_new_frame(struct inst *from, struct inst *to) |
646 | { |
647 | struct obj *obj; |
648 | |
649 | if (!locked_frame || is_parent_of(locked_frame, active_frame)) |
650 | return 0; |
651 | obj = new_obj(ot_frame, from); |
652 | obj->u.frame.ref = locked_frame; |
653 | obj->u.frame.lineno = 0; |
654 | if (!locked_frame->active_ref) |
655 | locked_frame->active_ref = obj; |
656 | locked_frame = NULL; |
657 | tool_reset(); |
658 | return 1; |
659 | } |
660 | |
661 | |
662 | static struct tool_ops frame_ops = { |
663 | .tool_selected = NULL, |
664 | .drag_new = NULL, |
665 | .end_new = end_new_frame, |
666 | }; |
667 | |
668 | |
669 | /* ----- moving references ------------------------------------------------- */ |
670 | |
671 | |
672 | #if 0 |
673 | static int may_move(struct inst *curr) |
674 | { |
675 | if (!selected_inst) |
676 | return 0; |
677 | if (drag.anchors_n) |
678 | return 0; /* already moving something else */ |
679 | drag.anchors_n = inst_anchors(selected_inst, drag.anchors); |
680 | for (drag.anchor_i = 0; drag.anchor_i != drag.anchors_n; |
681 | drag.anchor_i++) |
682 | if (*drag.anchors[drag.anchor_i] == inst_get_vec(curr)) |
683 | return 1; |
684 | drag.anchors_n = 0; |
685 | return 0; |
686 | } |
687 | #endif |
688 | |
689 | |
690 | static int would_be_equal(const struct drag_state *state, |
691 | int a, int b, struct inst *curr) |
692 | { |
693 | const struct vec *va; |
694 | const struct vec *vb; |
695 | |
696 | va = a == state->anchor_i ? inst_get_vec(curr) : *state->anchors[a]; |
697 | vb = b == state->anchor_i ? inst_get_vec(curr) : *state->anchors[b]; |
698 | return va == vb; |
699 | } |
700 | |
701 | |
702 | static int may_move_to(const struct drag_state *state, struct inst *curr) |
703 | { |
704 | assert(drag.inst); |
705 | assert(state->anchors_n); |
706 | switch (state->anchors_n) { |
707 | case 3: |
708 | if (would_be_equal(state, 0, 2, curr)) |
709 | return 0; |
710 | /* fall through */ |
711 | case 2: |
712 | if (would_be_equal(state, 0, 1, curr)) |
713 | return 0; |
714 | /* fall through */ |
715 | case 1: |
716 | return 1; |
717 | default: |
718 | abort(); |
719 | } |
720 | } |
721 | |
722 | |
723 | static void do_move_to(struct drag_state *state, struct inst *curr) |
724 | { |
725 | assert(state->inst->ops->find_point || may_move_to(state, curr)); |
726 | *state->anchors[state->anchor_i] = inst_get_vec(curr); |
727 | } |
728 | |
729 | |
730 | /* ----- hover ------------------------------------------------------------- */ |
731 | |
732 | |
733 | static struct pix_buf *hover_save_and_draw(void *user) |
734 | { |
735 | return inst_hover(hover_inst); |
736 | } |
737 | |
738 | |
739 | void tool_dehover(void) |
740 | { |
741 | if (!hover_inst) |
742 | return; |
743 | over_leave(); |
744 | hover_inst = NULL; |
745 | } |
746 | |
747 | |
748 | /* |
749 | * When hovering, we have to consider the following states: |
750 | * |
751 | * selected (selected_inst != NULL) |
752 | * | dragging new (drag.new != NULL) |
753 | * | | dragging existing (drag.anchors_n != 0) |
754 | * | | | tool selected (active_ops) |
755 | * | | | | |
756 | * Y N N N highlight if inst_find_point_selected else don't |
757 | * Y N N Y highlight if inst_find_point_selected else fall over to tool |
758 | * - Y N - highlight if inst_find_point / active_ops->find_point else don't |
759 | * - N Y - highlight if may_move_to else don't |
760 | * - Y Y - invalid state |
761 | * N N N Y highlight if inst_find_point / active_ops->find_point else don't |
762 | * N N N N don't highlight |
763 | */ |
764 | |
765 | static struct inst *get_hover_inst(struct coord pos) |
766 | { |
767 | struct inst *inst; |
768 | int i; |
769 | |
770 | if (drag.new) { |
771 | if (active_ops->find_point) |
772 | return active_ops->find_point(pos); |
773 | return inst_find_point(pos); |
774 | } |
775 | if (drag.anchors_n) { |
776 | if (drag.inst->ops->find_point) |
777 | return drag.inst->ops->find_point(drag.inst, pos); |
778 | inst = inst_find_point(pos); |
779 | if (!inst) |
780 | return NULL; |
781 | return may_move_to(&drag, inst) ? inst : NULL; |
782 | } |
783 | if (selected_inst) { |
784 | i = inst_find_point_selected(pos, &inst); |
785 | if (i != -1) |
786 | return inst; |
787 | } |
788 | if (!active_ops) |
789 | return NULL; |
790 | if (active_ops->find_point) |
791 | return active_ops->find_point(pos); |
792 | return inst_find_point(pos); |
793 | } |
794 | |
795 | |
796 | int tool_hover(struct coord pos) |
797 | { |
798 | struct inst *curr; |
799 | |
800 | curr = get_hover_inst(pos); |
801 | #if 0 |
802 | if ((drag.new && curr == drag.new) || (drag.inst && curr == drag.inst)) |
803 | return; |
804 | if (curr && !active_ops) { |
805 | if (drag.anchors_n) { |
806 | if (!may_move_to(&drag, curr)) |
807 | curr = NULL; |
808 | } else { |
809 | if (!may_move(curr)) |
810 | curr = NULL; |
811 | drag.anchors_n = 0; |
812 | } |
813 | } |
814 | got: |
815 | #endif |
816 | |
817 | if (curr == hover_inst) |
818 | return !!curr; |
819 | if (hover_inst) { |
820 | over_leave(); |
821 | hover_inst = NULL; |
822 | } |
823 | if (!curr) |
824 | return 0; |
825 | hover_inst = curr; |
826 | over_enter(hover_save_and_draw, NULL); |
827 | return 1; |
828 | } |
829 | |
830 | |
831 | /* ----- frame drag and drop ----------------------------------------------- */ |
832 | |
833 | |
834 | /* |
835 | * When dragging a frame, we temporarily replace the selected tool (if any) |
836 | * with the frame tool. |
837 | */ |
838 | |
839 | |
840 | static struct tool_ops *pushed_ops; |
841 | |
842 | |
843 | void tool_push_frame(struct frame *frame) |
844 | { |
845 | pushed_ops = active_ops; |
846 | locked_frame = frame; |
847 | active_ops = &frame_ops; |
848 | /* |
849 | * We don't need to call tool_selected since, with drag and drop, the |
850 | * frame tools doesn't need activation anymore. |
851 | */ |
852 | } |
853 | |
854 | |
855 | static int do_place_frame(struct frame *frame, struct coord pos) |
856 | { |
857 | if (!get_hover_inst(pos)) |
858 | return 0; |
859 | tool_consider_drag(pos); |
860 | return 1; |
861 | } |
862 | |
863 | |
864 | /* |
865 | * Gtk calls drag-leave, drag-end, and only then drag-drop. So we'll already |
866 | * have cleaned up in tool_pop_frame before we get here. In order to place the |
867 | * frame, we need to activate the frame tool again. |
868 | * |
869 | * @@@ bug: there's a tool_reset in this path, so we'll lose the widget of the |
870 | * tool that's really active. This problem will vanish when scrapping the |
871 | * old-style frame referenes. |
872 | */ |
873 | |
874 | int tool_place_frame(struct frame *frame, struct coord pos) |
875 | { |
876 | int ok; |
877 | |
878 | active_ops = &frame_ops; |
879 | ok = do_place_frame(frame, pos); |
880 | active_ops = pushed_ops; |
881 | return ok; |
882 | } |
883 | |
884 | |
885 | void tool_pop_frame(void) |
886 | { |
887 | if (!active_tool) |
888 | return; |
889 | active_ops = pushed_ops; |
890 | /* |
891 | * We don't need to call tool_selected since the only tool that could |
892 | * use this would be the delete tool, and there the semantics would be |
893 | * undesirable. Also, the delete tool never stays active, so it can't |
894 | * appear together with drag and drop anyway. |
895 | */ |
896 | } |
897 | |
898 | |
899 | /* ----- tooltip ----------------------------------------------------------- */ |
900 | |
901 | |
902 | const char *tool_tip(struct coord pos) |
903 | { |
904 | struct inst *inst; |
905 | |
906 | inst = get_hover_inst(pos); |
907 | if (!inst) |
908 | return NULL; |
909 | |
910 | /* |
911 | * The logic below follows exactly what happens in get_hover_inst. |
912 | */ |
913 | |
914 | if (drag.new) |
915 | return "End here"; |
916 | if (drag.anchors_n) |
917 | return "Move here"; |
918 | if (selected_inst) |
919 | return "Move this point"; |
920 | return "Start here"; |
921 | } |
922 | |
923 | |
924 | /* ----- mouse actions ----------------------------------------------------- */ |
925 | |
926 | |
927 | static struct pix_buf *drag_save_and_draw(void *user, struct coord to) |
928 | { |
929 | if (drag.new) { |
930 | assert(active_ops); |
931 | return active_ops->drag_new(drag.new, to); |
932 | } else { |
933 | return inst_draw_move(drag.inst, to, drag.anchor_i); |
934 | } |
935 | } |
936 | |
937 | |
938 | /* |
939 | * When considering dragging, we have the following states: |
940 | * |
941 | * selected (selected_inst != NULL) |
942 | * | tool selected (active_ops) |
943 | * | | |
944 | * N N don't |
945 | * Y - if we could drag, drag_new/end_new, else fall over to tool |
946 | * N Y else single-click creation, else drag_new/end_new |
947 | */ |
948 | |
949 | int tool_consider_drag(struct coord pos) |
950 | { |
951 | struct inst *curr; |
952 | |
953 | assert(!drag.new); |
954 | assert(!drag.anchors_n); |
955 | last_canvas_pos = translate(pos); |
956 | |
957 | if (!selected_inst && !active_ops) |
958 | return 0; |
959 | if (selected_inst) { |
960 | drag.anchor_i = inst_find_point_selected(pos, NULL); |
961 | if (drag.anchor_i != -1) { |
962 | tool_dehover(); |
963 | drag.inst = selected_inst; |
964 | drag.new = NULL; |
965 | drag.anchors_n = |
966 | inst_anchors(selected_inst, drag.anchors); |
967 | over_begin(drag_save_and_draw, NULL, pos); |
968 | inst_begin_drag_move(selected_inst, drag.anchor_i); |
969 | return 1; |
970 | } |
971 | } |
972 | if (!active_ops) |
973 | return 0; |
974 | |
975 | curr = get_hover_inst(pos); |
976 | if (!curr) |
977 | return 0; |
978 | |
979 | tool_dehover(); |
980 | |
981 | if (active_ops->drag_new) { |
982 | if (active_ops->begin_drag_new) |
983 | active_ops->begin_drag_new(curr); |
984 | drag.inst = NULL; |
985 | drag.new = curr; |
986 | over_begin(drag_save_and_draw, NULL, pos); |
987 | return 1; |
988 | } |
989 | |
990 | /* object is created without dragging */ |
991 | if (active_ops->end_new(curr, NULL)) |
992 | return -1; |
993 | return 0; |
994 | |
995 | } |
996 | |
997 | |
998 | void tool_drag(struct coord to) |
999 | { |
1000 | last_canvas_pos = translate(to); |
1001 | over_move(to); |
1002 | } |
1003 | |
1004 | |
1005 | void tool_cancel_drag(void) |
1006 | { |
1007 | if (drag.anchors_n && drag.inst->ops->end_drag_move) |
1008 | drag.inst->ops->end_drag_move(); |
1009 | drag.new = NULL; |
1010 | active_ops = NULL; |
1011 | drag.anchors_n = 0; |
1012 | over_end(); |
1013 | tool_dehover(); |
1014 | tool_reset(); |
1015 | } |
1016 | |
1017 | |
1018 | int tool_end_drag(struct coord to) |
1019 | { |
1020 | struct drag_state state = drag; |
1021 | struct inst *end; |
1022 | struct tool_ops *ops = active_ops; |
1023 | |
1024 | tool_cancel_drag(); |
1025 | if (state.new && ops->end_new_raw) |
1026 | return ops->end_new_raw(state.new, to); |
1027 | if (state.new && ops->find_point) |
1028 | end = ops->find_point(to); |
1029 | else { |
1030 | if (state.inst && state.inst->ops->find_point) |
1031 | end = state.inst->ops->find_point(state.inst, to); |
1032 | else |
1033 | end = inst_find_point(to); |
1034 | } |
1035 | if (!end) { |
1036 | if (state.new && ops->cancel_drag_new) |
1037 | ops->cancel_drag_new(); |
1038 | return 0; |
1039 | } |
1040 | if (state.new) |
1041 | return ops->end_new(state.new, end); |
1042 | |
1043 | /* if we got the point from find_point, it's authoritative */ |
1044 | if (!state.inst->ops->find_point && !may_move_to(&state, end)) |
1045 | return 0; |
1046 | if (!inst_do_move_to(state.inst, end, state.anchor_i)) |
1047 | do_move_to(&state, end); |
1048 | return 1; |
1049 | } |
1050 | |
1051 | |
1052 | void tool_redraw(void) |
1053 | { |
1054 | struct coord pos; |
1055 | |
1056 | over_reset(); |
1057 | hover_inst = NULL; |
1058 | if (!drag.new && !drag.anchors_n) |
1059 | return; |
1060 | pos = canvas_to_coord(last_canvas_pos.x, last_canvas_pos.y); |
1061 | tool_hover(pos); |
1062 | over_begin(drag_save_and_draw, NULL, pos); |
1063 | } |
1064 | |
1065 | |
1066 | /* ----- Retrieve icons by instance characteristics ------------------------ */ |
1067 | |
1068 | |
1069 | GtkWidget *get_icon_by_inst(const struct inst *inst) |
1070 | { |
1071 | char **image; |
1072 | |
1073 | switch (inst->prio) { |
1074 | case ip_frame: |
1075 | image = xpm_frame; |
1076 | break; |
1077 | case ip_pad_copper: |
1078 | case ip_pad_special: |
1079 | image = inst->obj->u.pad.rounded ? xpm_rpad : xpm_pad; |
1080 | break; |
1081 | case ip_hole: |
1082 | image = xpm_hole; |
1083 | break; |
1084 | case ip_circ: |
1085 | image = xpm_circ; |
1086 | break; |
1087 | case ip_arc: |
1088 | image = xpm_arc; |
1089 | break; |
1090 | case ip_rect: |
1091 | image = xpm_rect; |
1092 | break; |
1093 | case ip_meas: |
1094 | switch (inst->obj->u.meas.type) { |
1095 | case mt_xy_next: |
1096 | case mt_xy_max: |
1097 | image = xpm_meas; |
1098 | break; |
1099 | case mt_x_next: |
1100 | case mt_x_max: |
1101 | image = xpm_meas_x; |
1102 | break; |
1103 | case mt_y_next: |
1104 | case mt_y_max: |
1105 | image = xpm_meas_y; |
1106 | break; |
1107 | default: |
1108 | abort(); |
1109 | } |
1110 | break; |
1111 | case ip_line: |
1112 | image = xpm_line; |
1113 | break; |
1114 | case ip_vec: |
1115 | image = xpm_vec; |
1116 | break; |
1117 | default: |
1118 | abort(); |
1119 | } |
1120 | return make_transparent_image(DA, image, NULL); |
1121 | } |
1122 | |
1123 | |
1124 | /* ----- tool bar creation ------------------------------------------------- */ |
1125 | |
1126 | |
1127 | static void tool_select(GtkWidget *evbox, struct tool_ops *ops) |
1128 | { |
1129 | GdkColor col; |
1130 | |
1131 | if (active_tool) { |
1132 | if (active_ops && active_ops->tool_deselected) |
1133 | active_ops->tool_deselected(); |
1134 | col = get_color(COLOR_TOOL_UNSELECTED); |
1135 | gtk_widget_modify_bg(active_tool, GTK_STATE_NORMAL, &col); |
1136 | active_tool = NULL; |
1137 | } |
1138 | col = get_color(COLOR_TOOL_SELECTED); |
1139 | gtk_widget_modify_bg(evbox, GTK_STATE_NORMAL, &col); |
1140 | active_tool = evbox; |
1141 | active_ops = ops; |
1142 | if (ops && ops->tool_selected) |
1143 | ops->tool_selected(); |
1144 | } |
1145 | |
1146 | |
1147 | void tool_reset(void) |
1148 | { |
1149 | over_reset(); |
1150 | hover_inst = NULL; |
1151 | tool_select(ev_point, NULL); |
1152 | } |
1153 | |
1154 | |
1155 | static gboolean tool_button_press_event(GtkWidget *widget, |
1156 | GdkEventButton *event, gpointer data) |
1157 | { |
1158 | switch (event->button) { |
1159 | case 1: |
1160 | tool_select(widget, data); |
1161 | break; |
1162 | } |
1163 | return TRUE; |
1164 | } |
1165 | |
1166 | |
1167 | static void tool_separator(GtkWidget *bar) |
1168 | { |
1169 | GtkToolItem *item; |
1170 | |
1171 | item = gtk_separator_tool_item_new(); |
1172 | gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(item), FALSE); |
1173 | gtk_toolbar_insert(GTK_TOOLBAR(bar), item, -1); |
1174 | } |
1175 | |
1176 | |
1177 | GtkWidget *gui_setup_tools(GdkDrawable *drawable) |
1178 | { |
1179 | GtkWidget *bar; |
1180 | |
1181 | bar = gtk_toolbar_new(); |
1182 | gtk_toolbar_set_style(GTK_TOOLBAR(bar), GTK_TOOLBAR_ICONS); |
1183 | gtk_toolbar_set_orientation(GTK_TOOLBAR(bar), |
1184 | GTK_ORIENTATION_VERTICAL); |
1185 | |
1186 | ev_point = tool_button(bar, drawable, xpm_point, |
1187 | "Select and move items", |
1188 | tool_button_press_event, NULL); |
1189 | ev_delete = tool_button(bar, drawable, NULL, NULL, |
1190 | tool_button_press_event, &delete_ops); |
1191 | tool_separator(bar); |
1192 | tool_button(bar, drawable, xpm_vec, |
1193 | "Add a vector", |
1194 | tool_button_press_event, &vec_ops); |
1195 | tool_button(bar, drawable, xpm_pad, |
1196 | "Add a rectangular pad", |
1197 | tool_button_press_event, &pad_ops); |
1198 | tool_button(bar, drawable, xpm_rpad, |
1199 | "Add a rounded pad", |
1200 | tool_button_press_event, &rpad_ops); |
1201 | tool_button(bar, drawable, xpm_hole, |
1202 | "Add a hole", |
1203 | tool_button_press_event, &hole_ops); |
1204 | tool_button(bar, drawable, xpm_line, |
1205 | "Add a silk screen line", |
1206 | tool_button_press_event, &line_ops); |
1207 | tool_button(bar, drawable, xpm_rect, |
1208 | "Add a silk screen rectangle", |
1209 | tool_button_press_event, &rect_ops); |
1210 | tool_button(bar, drawable, xpm_circ, |
1211 | "Add a silk screen circle or arc", |
1212 | tool_button_press_event, &circ_ops); |
1213 | tool_separator(bar); |
1214 | tool_button(bar, drawable, xpm_meas, |
1215 | "Add a measurement", |
1216 | tool_button_press_event, &tool_meas_ops); |
1217 | tool_button(bar, drawable, xpm_meas_x, |
1218 | "Add a horizontal measurement", |
1219 | tool_button_press_event, &tool_meas_ops_x); |
1220 | tool_button(bar, drawable, xpm_meas_y, |
1221 | "Add a vertical measurement", |
1222 | tool_button_press_event, &tool_meas_ops_y); |
1223 | |
1224 | delete_image[0] = gtk_widget_ref(make_image(drawable, xpm_delete_off, |
1225 | NULL)); |
1226 | delete_image[1] = gtk_widget_ref(make_image(drawable, xpm_delete, |
1227 | "Delete the selected item")); |
1228 | set_image(ev_delete, delete_image[0]); |
1229 | |
1230 | tool_reset(); |
1231 | |
1232 | return bar; |
1233 | } |
1234 | |
1235 | |
1236 | void gui_cleanup_tools(void) |
1237 | { |
1238 | g_object_unref(delete_image[0]); |
1239 | g_object_unref(delete_image[1]); |
1240 | } |
1241 |
Branches:
master