1 /*
2 * FIG : Facility for Interactive Generation of figures
3 * Copyright (c) 1985-1988 by Supoj Sutanthavibul
4 * Parts Copyright (c) 1989-2015 by Brian V. Smith
5 * Parts Copyright (c) 1991 by Paul King
6 * Parts Copyright (c) 2016-2020 by Thomas Loimer
7 *
8 * Any party obtaining a copy of these files is granted, free of charge, a
9 * full and unrestricted irrevocable, world-wide, paid up, royalty-free,
10 * nonexclusive right and license to deal in this software and documentation
11 * files (the "Software"), including without limitation the rights to use,
12 * copy, modify, merge, publish, distribute, sublicense and/or sell copies of
13 * the Software, and to permit persons who receive copies from any such
14 * party to do so, with the only requirement being that the above copyright
15 * and this permission notice remain intact.
16 *
17 */
18
19 #include "d_line.h"
20
21 #include <stdlib.h>
22 #include <X11/Xlib.h>
23
24 #include "resources.h"
25 #include "mode.h"
26 #include "object.h"
27 #include "paintop.h"
28 #include "e_edit.h"
29 #include "u_create.h"
30 #include "u_elastic.h"
31 #include "u_free.h"
32 #include "u_list.h"
33 #include "u_redraw.h"
34 #include "w_canvas.h"
35 #include "w_cursor.h"
36 #include "w_drawprim.h"
37 #include "w_mousefun.h"
38 #include "w_msgpanel.h"
39
40
41 Boolean freehand_line;
42
43 /* LOCAL */
44
45 static Boolean dimension_line;
46
47 static void init_line_drawing(int x, int y, int shift);
48 static void init_line_freehand_drawing(int x, int y);
49
50 /********************** polyline and polygon section **********************/
51
52
53 void
line_drawing_selected(void)54 line_drawing_selected(void)
55 {
56 canvas_kbd_proc = null_proc;
57 canvas_locmove_proc = null_proc;
58 canvas_leftbut_proc = init_line_drawing;
59 canvas_middlebut_proc = init_line_freehand_drawing;
60 set_cursor(crosshair_cursor);
61 reset_action_on();
62 if (cur_mode == F_POLYGON) {
63 set_mousefun("first point", "freehand", "", "", "", "");
64 min_num_points = 3;
65 canvas_rightbut_proc = null_proc;
66 } else {
67 set_mousefun("first point", "freehand", "single point", "dimension line", "", "");
68 min_num_points = 1;
69 num_point = 0;
70 fix_x = fix_y = -1;
71 canvas_rightbut_proc = create_lineobject;
72 }
73 }
74
75 static void
init_line_freehand_drawing(int x,int y)76 init_line_freehand_drawing(int x, int y)
77 {
78 freehand_line = True;
79 /* not a dimension line */
80 dimension_line = False;
81 init_trace_drawing(x, y);
82 }
83
84 static void
init_line_drawing(int x,int y,int shift)85 init_line_drawing(int x, int y, int shift)
86 {
87 freehand_line = False;
88 /* if the user pressed shift then make a dimension line */
89 dimension_line = shift;
90 if (shift) {
91 min_num_points = 2;
92 }
93 canvas_middlebut_proc = null_proc;
94 init_trace_drawing(x, y);
95 }
96
97 void
cancel_line_drawing(void)98 cancel_line_drawing(void)
99 {
100 elastic_line();
101 /* erase last lengths if appres.showlengths is true */
102 erase_lengths();
103 cur_x = fix_x;
104 cur_y = fix_y;
105 if (cur_point != first_point)
106 elastic_moveline(first_point); /* erase control vector */
107 free_points(first_point);
108 first_point = NULL;
109 return_proc();
110 draw_mousefun_canvas();
111 }
112
113 void
init_trace_drawing(int x,int y)114 init_trace_drawing(int x, int y)
115 {
116 if ((first_point = create_point()) == NULL)
117 return;
118
119 cur_point = first_point;
120 set_action_on();
121 cur_point->x = fix_x = cur_x = x;
122 cur_point->y = fix_y = cur_y = y;
123 cur_point->next = NULL;
124 canvas_leftbut_proc = get_intermediatepoint;
125 if (freehand_line) {
126 canvas_locmove_proc = freehand_get_intermediatepoint;
127 } else {
128 /* only two points in a dimension line */
129 if (dimension_line)
130 canvas_leftbut_proc = create_lineobject;
131 if (latexline_mode || latexarrow_mode) {
132 canvas_locmove_proc = latex_line;
133 } else if (manhattan_mode || mountain_mode) {
134 canvas_locmove_proc = constrainedangle_line;
135 } else {
136 canvas_locmove_proc = unconstrained_line;
137 }
138 }
139 canvas_middlebut_save = create_lineobject;
140 canvas_rightbut_proc = cancel_line_drawing;
141 return_proc = line_drawing_selected;
142 num_point = 1;
143 set_mousefun("next point", "", "cancel", "del point", "", "");
144 if (dimension_line) {
145 set_mousefun("final point", "", "cancel", "del point", "", "");
146 canvas_middlebut_proc = null_proc;
147 } else if (num_point >= min_num_points - 1) {
148 set_mousefun("next point", "final point", "cancel", "del point", "", "");
149 canvas_middlebut_proc = canvas_middlebut_save;
150 }
151
152 draw_mousefun_canvas();
153 set_cursor(null_cursor);
154 elastic_line();
155 }
156
157 /* we have this extra proc to call get_intermediatepoint() because we come
158 here from a canvas_locmove_proc which doesn't have a shift value (its
159 not a keypress event)
160 */
161
162 void
freehand_get_intermediatepoint(int x,int y)163 freehand_get_intermediatepoint(int x, int y)
164 {
165 /* if shift key is pressed user wants to delete points with
166 left button press, return now */
167 if (shift) {
168 unconstrained_line(x,y);
169 return;
170 }
171 get_intermediatepoint(x, y, 0);
172 }
173
174 void
get_intermediatepoint(int x,int y,int shift)175 get_intermediatepoint(int x, int y, int shift)
176 {
177 /* in freehand mode call unconstrained_line explicitely to move the mouse */
178 if (freehand_line) {
179 unconstrained_line(x,y);
180 /* pointer must move by at least freehand_resolution in any direction */
181 if (abs(fix_x-cur_x) < appres.freehand_resolution &&
182 (abs(fix_y-cur_y) < appres.freehand_resolution))
183 return;
184 } else {
185 /* otherwise call the (possibly) constrained movement procedure */
186 (*canvas_locmove_proc) (x, y);
187 }
188
189 /* don't allow coincident consecutive points */
190 if (fix_x == cur_x && fix_y == cur_y)
191 return;
192
193 num_point++;
194 fix_x = cur_x;
195 fix_y = cur_y;
196 elastic_line();
197 if (cur_cursor != null_cursor) {
198 set_cursor(null_cursor);
199 }
200 if (shift && num_point > 2) {
201 F_point *p;
202
203 num_point -= 2;
204 p = prev_point(first_point, cur_point);
205 p->next = NULL;
206 /* erase the newest segment */
207 pw_vector(canvas_win, fix_x, fix_y, cur_point->x, cur_point->y,
208 INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
209 /* and segment drawn before */
210 pw_vector(canvas_win, p->x, p->y, cur_point->x, cur_point->y,
211 INV_PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
212 /* and draw new elastic segment */
213 pw_vector(canvas_win, fix_x, fix_y, p->x, p->y,
214 PAINT, 1, RUBBER_LINE, 0.0, DEFAULT);
215 fix_x = p->x;
216 fix_y = p->y;
217 free_points(cur_point);
218 cur_point = p;
219 } else {
220 append_point(fix_x, fix_y, &cur_point);
221 }
222 if (num_point == min_num_points - 1) {
223 if (freehand_line)
224 set_mousefun("", "final point", "cancel", "del point", "", "");
225 else
226 set_mousefun("next point", "final point", "cancel", "del point", "", "");
227 draw_mousefun_canvas();
228 canvas_middlebut_proc = canvas_middlebut_save;
229 }
230 }
231
232 /* come here upon pressing middle button (last point of lineobject) */
233 /* or the second point of a dimension line */
234
235 void
create_lineobject(int x,int y)236 create_lineobject(int x, int y)
237 {
238 F_line *line;
239 F_compound *comp;
240 int dot;
241
242 if (num_point == 0) {
243 if ((first_point = create_point()) == NULL) {
244 line_drawing_selected();
245 draw_mousefun_canvas();
246 return;
247 }
248 cur_point = first_point;
249 first_point->x = fix_x = cur_x = x;
250 first_point->y = fix_y = cur_y = y;
251 first_point->next = NULL;
252 num_point++;
253 } else if (x != fix_x || y != fix_y) {
254 get_intermediatepoint(x, y, 0);
255 }
256 /* dimension line must have 2 different points */
257 if (dimension_line && first_point->x == x && first_point->y == y)
258 return;
259
260 dot = (num_point == 1);
261 elastic_line();
262 /* erase any length info if appres.showlengths is true */
263 erase_lengths();
264 if ((line = create_line()) == NULL) {
265 line_drawing_selected();
266 draw_mousefun_canvas();
267 return;
268 }
269 line->type = T_POLYLINE;
270 line->style = cur_linestyle;
271 line->thickness = cur_linewidth;
272 line->pen_color = cur_pencolor;
273 line->fill_color = cur_fillcolor;
274 line->depth = cur_depth;
275 line->pen_style = -1;
276 line->join_style = cur_joinstyle;
277 line->cap_style = cur_capstyle;
278 line->fill_style = cur_fillstyle;
279 line->style_val = cur_styleval * (cur_linewidth + 1) / 2;
280 line->points = first_point;
281 if (!dot) {
282 if (cur_mode == F_POLYGON) { /* close off polygon */
283 line->type = T_POLYGON;
284 num_point++;
285 append_point(first_point->x, first_point->y, &cur_point);
286 elastic_line();
287 fix_x = first_point->x;
288 fix_y = first_point->y;
289 elastic_line(); /* fix last elastic line */
290 } else { /* polyline; draw any arrows */
291 if (autoforwardarrow_mode && !dimension_line)
292 line->for_arrow = forward_arrow();
293 /* arrow will be drawn in draw_line below */
294 if (autobackwardarrow_mode && !dimension_line)
295 line->back_arrow = backward_arrow();
296 /* arrow will be drawn in draw_line below */
297 }
298 cur_x = fix_x;
299 cur_y = fix_y;
300 elastic_moveline(first_point); /* erase temporary outline */
301 }
302 if (dimension_line) {
303 comp = create_dimension_line(line, True);
304 reset_action_on(); /* this signals redisplay_curobj() not to refresh */
305 /* draw it and anything on top of it */
306 redisplay_compound(comp);
307 } else {
308 add_line(line);
309 reset_action_on(); /* this signals redisplay_curobj() not to refresh */
310 /* draw it and anything on top of it */
311 redisplay_line(line);
312 }
313 line_drawing_selected();
314 if (!edit_remember_dimline_mode)
315 draw_mousefun_canvas();
316 }
317
318