gui_inst.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  1. /*
  2. * gui_inst.c - GUI, instance functions
  3. *
  4. * Written 2009-2012 by Werner Almesberger
  5. * Copyright 2009-2012 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. #include <stdlib.h>
  13. #include <math.h>
  14. #include <gtk/gtk.h>
  15. #include "util.h"
  16. #include "coord.h"
  17. #include "inst.h"
  18. #include "gui.h"
  19. #include "gui_util.h"
  20. #include "gui_style.h"
  21. #include "gui_status.h"
  22. #include "gui_inst.h"
  23. /* ----- coordinate translation -------------------------------------------- */
  24. struct coord translate(struct coord pos)
  25. {
  26. pos.x -= draw_ctx.center.x;
  27. pos.y -= draw_ctx.center.y;
  28. pos.x /= draw_ctx.scale;
  29. pos.y /= draw_ctx.scale;
  30. pos.y = -pos.y;
  31. pos.x += draw_ctx.widget->allocation.width/2;
  32. pos.y += draw_ctx.widget->allocation.height/2;
  33. return pos;
  34. }
  35. struct coord canvas_to_coord(int x, int y)
  36. {
  37. struct coord pos;
  38. x -= draw_ctx.widget->allocation.width/2;
  39. y -= draw_ctx.widget->allocation.height/2;
  40. y = -y;
  41. pos.x = x*draw_ctx.scale+draw_ctx.center.x;
  42. pos.y = y*draw_ctx.scale+draw_ctx.center.y;
  43. return pos;
  44. }
  45. /* ----- drawing primitives ------------------------------------------------ */
  46. static void draw_eye(GdkGC *gc, struct coord center, int r1, int r2)
  47. {
  48. draw_circle(DA, gc, TRUE, center.x, center.y, r1);
  49. draw_circle(DA, gc, FALSE, center.x, center.y, r2);
  50. }
  51. #define MAX_POINTS 10
  52. static void draw_poly(GdkGC *gc, int fill,
  53. const struct coord *points, int n_points)
  54. {
  55. GdkPoint gp[MAX_POINTS];
  56. int i;
  57. if (n_points > MAX_POINTS)
  58. abort();
  59. for (i = 0; i != n_points; i++) {
  60. gp[i].x = points[i].x;
  61. gp[i].y = points[i].y;
  62. }
  63. if (fill) {
  64. gdk_draw_polygon(DA, gc, fill, gp, n_points);
  65. } else {
  66. gdk_draw_line(DA, gc, gp[0].x, gp[0].y, gp[1].x, gp[1].y);
  67. gdk_draw_line(DA, gc, gp[1].x, gp[1].y, gp[2].x, gp[2].y);
  68. }
  69. }
  70. static void draw_arrow(GdkGC *gc, int fill,
  71. struct coord from, struct coord to, int len, double angle)
  72. {
  73. struct coord p[3];
  74. struct coord side;
  75. if (from.x == to.x && from.y == to.y) {
  76. side.x = 0;
  77. side.y = -len;
  78. } else {
  79. side = normalize(sub_vec(to, from), len);
  80. }
  81. p[0] = add_vec(to, rotate(side, 180-angle));
  82. p[1] = to;
  83. p[2] = add_vec(to, rotate(side, 180+angle));
  84. draw_poly(gc, fill, p, 3);
  85. }
  86. static enum mode get_mode(const struct inst *self)
  87. {
  88. if (selected_inst == self)
  89. return mode_selected;
  90. return self->active || bright(self) ? mode_active : mode_inactive;
  91. }
  92. /* ----- vec --------------------------------------------------------------- */
  93. unit_type gui_dist_vec(struct inst *self, struct coord pos, unit_type scale)
  94. {
  95. unit_type d;
  96. d = dist_point(pos, self->u.vec.end)/scale;
  97. return d > VEC_EYE_R ? -1 : d;
  98. }
  99. /*
  100. * The circles at a vector's tip enjoy the highest selection priority. However,
  101. * users will probably also expected a click on a nicely exposed stem to work.
  102. * So we give it second look after having exhausted all other options.
  103. */
  104. unit_type gui_dist_vec_fallback(struct inst *self, struct coord pos,
  105. unit_type scale)
  106. {
  107. unit_type d;
  108. d = dist_line(pos, self->base, self->u.vec.end)/scale;
  109. return d > SELECT_R ? -1 : d;
  110. }
  111. void gui_highlight_vec(struct inst *self)
  112. {
  113. struct coord center = translate(self->u.vec.end);
  114. draw_circle(DA, gc_highlight, FALSE, center.x, center.y, VEC_EYE_R);
  115. }
  116. void gui_draw_vec(struct inst *self)
  117. {
  118. struct coord from = translate(self->base);
  119. struct coord to = translate(self->u.vec.end);
  120. GdkGC *gc;
  121. gc = gc_vec[get_mode(self)];
  122. draw_arrow(gc, TRUE, from, to, VEC_ARROW_LEN, VEC_ARROW_ANGLE);
  123. gdk_draw_line(DA, gc, from.x, from.y, to.x, to.y);
  124. draw_circle(DA, gc, FALSE, to.x, to.y, VEC_EYE_R);
  125. }
  126. /* ----- line -------------------------------------------------------------- */
  127. unit_type gui_dist_line(struct inst *self, struct coord pos, unit_type scale)
  128. {
  129. unit_type r, d;
  130. r = self->u.rect.width/scale/2;
  131. if (r < SELECT_R)
  132. r = SELECT_R;
  133. d = dist_line(pos, self->base, self->u.rect.end)/scale;
  134. return d > r ? -1 : d;
  135. }
  136. void gui_draw_line(struct inst *self)
  137. {
  138. struct coord min = translate(self->base);
  139. struct coord max = translate(self->u.rect.end);
  140. GdkGC *gc;
  141. gc = gc_obj[get_mode(self)];
  142. set_width(gc, self->u.rect.width/draw_ctx.scale);
  143. gdk_draw_line(DA, gc, min.x, min.y, max.x, max.y);
  144. }
  145. /* ----- rect -------------------------------------------------------------- */
  146. unit_type gui_dist_rect(struct inst *self, struct coord pos, unit_type scale)
  147. {
  148. unit_type r, d;
  149. r = self->u.rect.width/scale/2;
  150. if (r < SELECT_R)
  151. r = SELECT_R;
  152. d = dist_rect(pos, self->base, self->u.rect.end)/scale;
  153. return d > r ? -1 : d;
  154. }
  155. void gui_draw_rect(struct inst *self)
  156. {
  157. struct coord min = translate(self->base);
  158. struct coord max = translate(self->u.rect.end);
  159. GdkGC *gc;
  160. sort_coord(&min, &max);
  161. gc = gc_obj[get_mode(self)];
  162. set_width(gc, self->u.rect.width/draw_ctx.scale);
  163. gdk_draw_rectangle(DA, gc, FALSE,
  164. min.x, min.y, max.x-min.x, max.y-min.y);
  165. }
  166. /* ----- pad --------------------------------------------------------------- */
  167. unit_type gui_dist_pad(struct inst *self, struct coord pos, unit_type scale)
  168. {
  169. unit_type d;
  170. if (inside_rect(pos, self->base, self->u.pad.other))
  171. return SELECT_R;
  172. d = dist_rect(pos, self->base, self->u.pad.other)/scale;
  173. return d > SELECT_R ? -1 : d;
  174. }
  175. static void pad_text_in_rect(struct inst *self,
  176. struct coord min, struct coord max)
  177. {
  178. GdkGC *gc;
  179. struct coord c;
  180. unit_type h, w;
  181. int rot;
  182. w = max.x-min.x;
  183. h = max.y-min.y;
  184. rot = w/1.1 < h;
  185. gc = gc_ptext[get_mode(self)];
  186. c = add_vec(min, max);
  187. h = max.y-min.y;
  188. w = max.x-min.x;
  189. render_text(DA, gc, c.x/2, c.y/2, rot ? 0 : 90,
  190. self->u.pad.name, PAD_FONT, 0.5, 0.5,
  191. w-2*PAD_BORDER, h-2*PAD_BORDER);
  192. }
  193. static void maximize_box(struct coord *min_box, struct coord *max_box,
  194. unit_type x_min, unit_type y_min, unit_type x_max, unit_type y_max)
  195. {
  196. unit_type d_box, d_new, d;
  197. d_box = max_box->x-min_box->x;
  198. d = max_box->y-min_box->y;
  199. if (d < d_box)
  200. d_box = d;
  201. d_new = x_max-x_min;
  202. d = y_max-y_min;
  203. if (d < d_new)
  204. d_new = d;
  205. if (d_new < d_box)
  206. return;
  207. min_box->x = x_min;
  208. min_box->y = y_min;
  209. max_box->x = x_max;
  210. max_box->y = y_max;
  211. }
  212. static void gui_draw_pad_text(struct inst *self)
  213. {
  214. struct coord pad_min = translate(self->base);
  215. struct coord pad_max = translate(self->u.pad.other);
  216. struct coord hole_min, hole_max;
  217. struct coord box_min, box_max;
  218. sort_coord(&pad_min, &pad_max);
  219. if (!self->u.pad.hole) {
  220. pad_text_in_rect(self, pad_min, pad_max);
  221. return;
  222. }
  223. hole_min = translate(self->u.pad.hole->base);
  224. hole_max = translate(self->u.pad.hole->u.hole.other);
  225. sort_coord(&hole_min, &hole_max);
  226. box_min.x = pad_min.x; /* top */
  227. box_min.y = pad_min.y;
  228. box_max.x = pad_max.x;
  229. box_max.y = hole_min.y;
  230. maximize_box(&box_min, &box_max,
  231. pad_min.x, hole_max.y, pad_max.x, pad_max.y); /* bottom */
  232. maximize_box(&box_min, &box_max,
  233. pad_min.x, pad_min.y, hole_min.x, pad_max.y); /* left */
  234. maximize_box(&box_min, &box_max,
  235. hole_max.x, pad_min.y, pad_max.x, pad_max.y); /* right */
  236. pad_text_in_rect(self, box_min, box_max);
  237. }
  238. static GdkGC *pad_gc(const struct inst *inst, int *fill)
  239. {
  240. *fill = TRUE;
  241. switch (layers_to_pad_type(inst->u.pad.layers)) {
  242. case pt_bare:
  243. return gc_pad_bare[get_mode(inst)];
  244. case pt_trace:
  245. return gc_pad_trace[get_mode(inst)];
  246. case pt_mask:
  247. *fill = FALSE;
  248. return gc_pad_mask[get_mode(inst)];
  249. default:
  250. return gc_pad[get_mode(inst)];
  251. }
  252. }
  253. void gui_draw_pad(struct inst *self)
  254. {
  255. struct coord min = translate(self->base);
  256. struct coord max = translate(self->u.pad.other);
  257. GdkGC *gc;
  258. int fill;
  259. gc = pad_gc(self, &fill);
  260. sort_coord(&min, &max);
  261. gdk_draw_rectangle(DA, gc, fill,
  262. min.x, min.y, max.x-min.x, max.y-min.y);
  263. gui_draw_pad_text(self);
  264. }
  265. static void draw_rounded_rect(GdkGC *gc, struct coord a, struct coord b,
  266. int fill)
  267. {
  268. struct coord min = translate(a);
  269. struct coord max = translate(b);
  270. unit_type h, w, r;
  271. sort_coord(&min, &max);
  272. h = max.y-min.y;
  273. w = max.x-min.x;
  274. if (h > w) {
  275. r = w/2;
  276. draw_arc(DA, gc, fill, min.x+r, max.y-r, r, 180, 0);
  277. if (fill) {
  278. gdk_draw_rectangle(DA, gc, fill,
  279. min.x, min.y+r, w, h-2*r);
  280. } else {
  281. gdk_draw_line(DA, gc, min.x, min.y+r, min.x, max.y-r);
  282. gdk_draw_line(DA, gc, max.x, min.y+r, max.x, max.y-r);
  283. }
  284. draw_arc(DA, gc, fill, min.x+r, min.y+r, r, 0, 180);
  285. } else {
  286. r = h/2;
  287. draw_arc(DA, gc, fill, min.x+r, min.y+r, r, 90, 270);
  288. if (fill) {
  289. gdk_draw_rectangle(DA, gc, fill,
  290. min.x+r, min.y, w-2*r, h);
  291. } else {
  292. gdk_draw_line(DA, gc, min.x+r, min.y, max.x-r, min.y);
  293. gdk_draw_line(DA, gc, min.x+r, max.y, max.x-r, max.y);
  294. }
  295. draw_arc(DA, gc, fill, max.x-r, min.y+r, r, 270, 90);
  296. }
  297. }
  298. void gui_draw_rpad(struct inst *self)
  299. {
  300. GdkGC *gc;
  301. int fill;
  302. gc = pad_gc(self, &fill);
  303. draw_rounded_rect(gc, self->base, self->u.pad.other, fill);
  304. gui_draw_pad_text(self);
  305. }
  306. /* ----- hole -------------------------------------------------------------- */
  307. unit_type gui_dist_hole(struct inst *self, struct coord pos, unit_type scale)
  308. {
  309. unit_type d;
  310. /* @@@ not quite right ... */
  311. if (inside_rect(pos, self->base, self->u.hole.other))
  312. return SELECT_R;
  313. d = dist_rect(pos, self->base, self->u.hole.other)/scale;
  314. return d > SELECT_R ? -1 : d;
  315. }
  316. void gui_draw_hole(struct inst *self)
  317. {
  318. draw_rounded_rect(gc_hole[get_mode(self)],
  319. self->base, self->u.hole.other, 1);
  320. draw_rounded_rect(gc_rim[get_mode(self)],
  321. self->base, self->u.hole.other, 0);
  322. }
  323. /* ----- arc --------------------------------------------------------------- */
  324. unit_type gui_dist_arc(struct inst *self, struct coord pos, unit_type scale)
  325. {
  326. struct coord c = self->base;
  327. struct coord p;
  328. unit_type r, d_min, d;
  329. double angle, a1, a2;
  330. r = self->u.arc.width/scale/2;
  331. if (r < SELECT_R)
  332. r = SELECT_R;
  333. /* check endpoints */
  334. p = rotate_r(c, self->u.arc.r, self->u.arc.a1);
  335. d_min = hypot(pos.x-p.x, pos.y-p.y);
  336. p = rotate_r(c, self->u.arc.r, self->u.arc.a2);
  337. d = hypot(pos.x-p.x, pos.y-p.y);
  338. if (d < d_min)
  339. d_min = d;
  340. if (d_min/scale <= r)
  341. return d;
  342. /* distance from the circle containing the arc */
  343. d = dist_circle(pos, c, self->u.arc.r)/scale;
  344. if (d > r)
  345. return -1;
  346. if (self->u.arc.a1 == self->u.arc.a2)
  347. return d;
  348. /* see if we're close to the part that's actually drawn */
  349. angle = theta(c, pos);
  350. a1 = self->u.arc.a1;
  351. a2 = self->u.arc.a2;
  352. if (angle < 0)
  353. angle += 360;
  354. if (a2 < a1)
  355. a2 += 360;
  356. if (angle < a1)
  357. angle += 360;
  358. return angle >= a1 && angle <= a2 ? d : -1;
  359. }
  360. void gui_draw_arc(struct inst *self)
  361. {
  362. struct coord center = translate(self->base);
  363. GdkGC *gc;
  364. gc = gc_obj[get_mode(self)];
  365. set_width(gc, self->u.arc.width/draw_ctx.scale);
  366. draw_arc(DA, gc, FALSE, center.x, center.y,
  367. self->u.arc.r/draw_ctx.scale, self->u.arc.a1, self->u.arc.a2);
  368. }
  369. /* ----- meas -------------------------------------------------------------- */
  370. static struct coord offset_vec(struct coord a, struct coord b,
  371. const struct inst *self)
  372. {
  373. struct coord res;
  374. double f;
  375. res.x = a.y-b.y;
  376. res.y = b.x-a.x;
  377. if (res.x == 0 && res.y == 0)
  378. return res;
  379. f = self->u.meas.offset/hypot(res.x, res.y);
  380. res.x *= f;
  381. res.y *= f;
  382. return res;
  383. }
  384. void project_meas(const struct inst *inst, struct coord *a1, struct coord *b1)
  385. {
  386. const struct meas *meas = &inst->obj->u.meas;
  387. struct coord off;
  388. *a1 = inst->base;
  389. *b1 = inst->u.meas.end;
  390. switch (meas->type) {
  391. case mt_xy_next:
  392. case mt_xy_max:
  393. break;
  394. case mt_x_next:
  395. case mt_x_max:
  396. b1->y = a1->y;
  397. break;
  398. case mt_y_next:
  399. case mt_y_max:
  400. b1->x = a1->x;
  401. break;
  402. default:
  403. abort();
  404. }
  405. off = offset_vec(*a1, *b1, inst);
  406. *a1 = add_vec(*a1, off);
  407. *b1 = add_vec(*b1, off);
  408. }
  409. unit_type gui_dist_meas(struct inst *self, struct coord pos, unit_type scale)
  410. {
  411. struct coord a1, b1;
  412. unit_type d;
  413. project_meas(self, &a1, &b1);
  414. d = dist_line(pos, a1, b1)/scale;
  415. return d > SELECT_R ? -1 : d;
  416. }
  417. char *format_len(const char *label, unit_type len, enum curr_unit unit)
  418. {
  419. const char *u = "";
  420. double n;
  421. int mm;
  422. switch (unit) {
  423. case curr_unit_mm:
  424. n = units_to_mm(len);
  425. mm = 1;
  426. break;
  427. case curr_unit_mil:
  428. n = units_to_mil(len);
  429. mm = 0;
  430. break;
  431. case curr_unit_auto:
  432. n = units_to_best(len, &mm);
  433. u = mm ? "mm" : "mil";
  434. break;
  435. default:
  436. abort();
  437. }
  438. return stralloc_printf(mm ?
  439. "%s" MM_FORMAT_SHORT "%s" :
  440. "%s" MIL_FORMAT_SHORT "%s",
  441. label, n, u);
  442. }
  443. void gui_draw_meas(struct inst *self)
  444. {
  445. const struct meas *meas = &self->obj->u.meas;
  446. struct coord a0, b0, a1, b1, c, d;
  447. GdkGC *gc;
  448. double len;
  449. char *s;
  450. a0 = translate(self->base);
  451. b0 = translate(self->u.meas.end);
  452. project_meas(self, &a1, &b1);
  453. len = dist_point(a1, b1);
  454. a1 = translate(a1);
  455. b1 = translate(b1);
  456. gc = gc_meas[get_mode(self)];
  457. gdk_draw_line(DA, gc, a0.x, a0.y, a1.x, a1.y);
  458. gdk_draw_line(DA, gc, b0.x, b0.y, b1.x, b1.y);
  459. gdk_draw_line(DA, gc, a1.x, a1.y, b1.x, b1.y);
  460. draw_arrow(gc, FALSE, a1, b1, MEAS_ARROW_LEN, MEAS_ARROW_ANGLE);
  461. draw_arrow(gc, FALSE, b1, a1, MEAS_ARROW_LEN, MEAS_ARROW_ANGLE);
  462. c = add_vec(a1, b1);
  463. d = sub_vec(b1, a1);
  464. s = format_len(meas->label ? meas->label : "", len, curr_unit);
  465. render_text(DA, gc, c.x/2, c.y/2, -atan2(d.y, d.x)/M_PI*180, s,
  466. MEAS_FONT, 0.5, -MEAS_BASELINE_OFFSET,
  467. dist_point(a1, b1)-1.5*MEAS_ARROW_LEN, 0);
  468. free(s);
  469. }
  470. /* ----- frame ------------------------------------------------------------- */
  471. unit_type gui_dist_frame_eye(struct inst *self, struct coord pos,
  472. unit_type scale)
  473. {
  474. unit_type d;
  475. d = dist_point(pos, self->base)/scale;
  476. return d > FRAME_EYE_R2 ? -1 : d;
  477. }
  478. static unit_type dist_from_corner_line(struct inst *self, struct coord pos,
  479. struct coord vec, unit_type scale)
  480. {
  481. struct coord ref;
  482. ref.x = self->bbox.min.x;
  483. ref.y = self->bbox.max.y;
  484. return dist_line(pos, ref, add_vec(ref, vec))/scale;
  485. }
  486. unit_type gui_dist_frame(struct inst *self, struct coord pos, unit_type scale)
  487. {
  488. unit_type d_min, d;
  489. struct coord vec;
  490. d_min = dist_point(pos, self->base)/scale;
  491. vec.x = FRAME_SHORT_X*scale;
  492. vec.y = 0;
  493. d = dist_from_corner_line(self, pos, vec, scale);
  494. if (d < d_min)
  495. d_min = d;
  496. vec.x = 0;
  497. vec.y = FRAME_SHORT_Y*scale;
  498. d = dist_from_corner_line(self, pos, vec, scale);
  499. if (d < d_min)
  500. d_min = d;
  501. return d_min > SELECT_R ? -1 : d_min;
  502. }
  503. void gui_draw_frame(struct inst *self)
  504. {
  505. struct coord center = translate(self->base);
  506. struct coord corner = { self->bbox.min.x, self->bbox.max.y };
  507. GdkGC *gc;
  508. gc = self->u.frame.active ? gc_active_frame : gc_frame[get_mode(self)];
  509. draw_eye(gc, center, FRAME_EYE_R1, FRAME_EYE_R2);
  510. if (self->u.frame.ref == frames)
  511. return;
  512. corner = translate(corner);
  513. corner.x -= FRAME_CLEARANCE;
  514. corner.y -= FRAME_CLEARANCE;
  515. gdk_draw_line(DA, gc, corner.x, corner.y,
  516. corner.x+FRAME_SHORT_X, corner.y);
  517. gdk_draw_line(DA, gc, corner.x, corner.y,
  518. corner.x, corner.y+FRAME_SHORT_Y);
  519. render_text(DA, gc, corner.x, corner.y, 0, self->u.frame.ref->name,
  520. FRAME_FONT, 0, -FRAME_BASELINE_OFFSET, 0, 0);
  521. }