Introduce POLYGONHOLE_MODE for creating holes in polygons
[geda-pcb/gde.git] / src / hid / lesstif / main.c
blobe16397ebabcf498184fcb281c2fb6f3d6c25a393
1 /* $Id$ */
2 /* 15 Oct 2008 Ineiev: add different crosshair shapes */
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <time.h>
11 #include <string.h>
12 #include <math.h>
13 #include <unistd.h>
14 #include <signal.h>
15 #include <sys/time.h>
17 #include "xincludes.h"
19 #include "global.h"
20 #include "data.h"
21 #include "action.h"
22 #include "crosshair.h"
23 #include "mymem.h"
24 #include "misc.h"
25 #include "resource.h"
26 #include "clip.h"
27 #include "error.h"
29 #include "hid.h"
30 #include "../hidint.h"
31 #include "hid/common/draw_helpers.h"
32 #include "hid/common/hid_resource.h"
33 #include "lesstif.h"
35 #ifdef HAVE_LIBDMALLOC
36 #include <dmalloc.h>
37 #endif
39 #include <sys/poll.h>
41 RCSID ("$Id$");
43 #ifndef XtRDouble
44 #define XtRDouble "Double"
45 #endif
47 typedef struct hid_gc_struct
49 HID *me_pointer;
50 Pixel color;
51 const char *colorname;
52 int width;
53 EndCapStyle cap;
54 char xor;
55 char erase;
56 } hid_gc_struct;
58 extern HID lesstif_gui;
59 extern HID lesstif_extents;
61 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented GUI function %s\n", __FUNCTION__), abort()
63 XtAppContext app_context;
64 Widget appwidget;
65 Display *display;
66 static Window window = 0;
67 static Cursor my_cursor = 0;
68 static int old_cursor_mode = -1;
69 static int over_point = 0;
71 /* The first is the "current" pixmap. The main_ is the real one we
72 usually use, the mask_ are the ones for doing polygon masks. The
73 pixmap is the saved pixels, the bitmap is for the "erase" color.
74 We set pixmap to point to main_pixmap or mask_pixmap as needed. */
75 static Pixmap pixmap = 0;
76 static Pixmap main_pixmap = 0;
77 static Pixmap mask_pixmap = 0;
78 static Pixmap mask_bitmap = 0;
79 static int use_mask = 0;
81 static int use_xrender = 0;
82 #ifdef HAVE_XRENDER
83 static Picture main_picture;
84 static Picture mask_picture;
85 static Pixmap pale_pixmap;
86 static Picture pale_picture;
87 #endif /* HAVE_XRENDER */
89 static int pixmap_w = 0, pixmap_h = 0;
90 Screen *screen_s;
91 int screen;
92 static Colormap colormap;
93 static GC my_gc = 0, bg_gc, clip_gc = 0, bset_gc = 0, bclear_gc = 0, mask_gc =
95 static Pixel bgcolor, offlimit_color, grid_color;
96 static int bgred, bggreen, bgblue;
98 static GC arc1_gc, arc2_gc;
100 /* These are for the pinout windows. */
101 typedef struct PinoutData
103 struct PinoutData *prev, *next;
104 Widget form;
105 Window window;
106 int left, right, top, bottom; /* PCB extents of item */
107 int x, y; /* PCB coordinates of upper right corner of window */
108 double zoom; /* PCB units per screen pixel */
109 int v_width, v_height; /* pixels */
110 void *item;
111 } PinoutData;
113 /* Linked list of all pinout windows. */
114 static PinoutData *pinouts = 0;
115 /* If set, we are currently updating this pinout window. */
116 static PinoutData *pinout = 0;
118 static int crosshair_x = 0, crosshair_y = 0;
119 static int in_move_event = 0, crosshair_in_window = 1;
121 Widget work_area, messages, command, hscroll, vscroll;
122 static Widget m_mark, m_crosshair, m_grid, m_zoom, m_mode, m_status;
123 static Widget m_rats;
124 Widget lesstif_m_layer;
125 Widget m_click;
127 /* This is the size, in pixels, of the viewport. */
128 static int view_width, view_height;
129 /* This is the PCB location represented by the upper left corner of
130 the viewport. Note that PCB coordinates put 0,0 in the upper left,
131 much like X does. */
132 static int view_left_x = 0, view_top_y = 0;
133 /* Denotes PCB units per screen pixel. Larger numbers mean zooming
134 out - the largest value means you are looking at the whole
135 board. */
136 static double view_zoom = 1000, prev_view_zoom = 1000;
137 static int flip_x = 0, flip_y = 0;
138 static int autofade = 0;
140 static int
141 flag_flipx (int x)
143 return flip_x;
145 static int
146 flag_flipy (int x)
148 return flip_y;
151 HID_Flag lesstif_main_flag_list[] = {
152 {"flip_x", flag_flipx, 0},
153 {"flip_y", flag_flipy, 0}
156 REGISTER_FLAGS (lesstif_main_flag_list)
158 /* This is the size of the current PCB work area. */
159 /* Use PCB->MaxWidth, PCB->MaxHeight. */
160 /* static int pcb_width, pcb_height; */
162 static Arg args[30];
163 static int n;
164 #define stdarg(t,v) XtSetArg(args[n], t, v), n++
167 static int use_private_colormap = 0;
168 static int stdin_listen = 0;
169 static char *background_image_file = 0;
171 HID_Attribute lesstif_attribute_list[] = {
172 {"install", "Install private colormap",
173 HID_Boolean, 0, 0, {0, 0, 0}, 0, &use_private_colormap},
174 #define HA_colormap 0
176 {"listen", "Listen on standard input for actions",
177 HID_Boolean, 0, 0, {0, 0, 0}, 0, &stdin_listen},
178 #define HA_listen 1
180 {"bg-image", "Background Image",
181 HID_String, 0, 0, {0, 0, 0}, 0, &background_image_file},
182 #define HA_bg_image 1
186 REGISTER_ATTRIBUTES (lesstif_attribute_list)
188 static void lesstif_use_mask (int use_it);
189 static void zoom_to (double factor, int x, int y);
190 static void zoom_by (double factor, int x, int y);
191 static void zoom_toggle (int x, int y);
192 static void pinout_callback (Widget, PinoutData *,
193 XmDrawingAreaCallbackStruct *);
194 static void pinout_unmap (Widget, PinoutData *, void *);
195 static void Pan (int mode, int x, int y);
197 /* Px converts view->pcb, Vx converts pcb->view */
199 static inline int
200 Vx (int x)
202 int rv = (x - view_left_x) / view_zoom + 0.5;
203 if (flip_x)
204 rv = view_width - rv;
205 return rv;
208 static inline int
209 Vy (int y)
211 int rv = (y - view_top_y) / view_zoom + 0.5;
212 if (flip_y)
213 rv = view_height - rv;
214 return rv;
217 static inline int
218 Vz (int z)
220 return z / view_zoom + 0.5;
223 static inline int
224 Px (int x)
226 if (flip_x)
227 x = view_width - x;
228 return x * view_zoom + view_left_x;
231 static inline int
232 Py (int y)
234 if (flip_y)
235 y = view_height - y;
236 return y * view_zoom + view_top_y;
239 static inline int
240 Pz (int z)
242 return z * view_zoom;
245 void
246 lesstif_coords_to_pcb (int vx, int vy, int *px, int *py)
248 *px = Px (vx);
249 *py = Py (vy);
252 Pixel
253 lesstif_parse_color (char *value)
255 XColor color;
256 if (XParseColor (display, colormap, value, &color))
257 if (XAllocColor (display, colormap, &color))
258 return color.pixel;
259 return 0;
262 static void
263 do_color (char *value, char *which)
265 XColor color;
266 if (XParseColor (display, colormap, value, &color))
267 if (XAllocColor (display, colormap, &color))
269 stdarg (which, color.pixel);
273 /* ------------------------------------------------------------ */
275 static char *
276 cur_clip ()
278 if (TEST_FLAG (ORTHOMOVEFLAG, PCB))
279 return "+";
280 if (TEST_FLAG (ALLDIRECTIONFLAG, PCB))
281 return "*";
282 if (PCB->Clipping == 0)
283 return "X";
284 if (PCB->Clipping == 1)
285 return "_/";
286 return "\\_";
289 /* Called from the core when it's busy doing something and we need to
290 indicate that to the user. */
291 static int
292 Busy(int argc, char **argv, int x, int y)
294 static Cursor busy_cursor = 0;
295 if (busy_cursor == 0)
296 busy_cursor = XCreateFontCursor (display, XC_watch);
297 XDefineCursor (display, window, busy_cursor);
298 XFlush(display);
299 old_cursor_mode = -1;
300 return 0;
303 /* ---------------------------------------------------------------------- */
305 /* Local actions. */
307 static int
308 PointCursor (int argc, char **argv, int x, int y)
310 if (argc > 0)
311 over_point = 1;
312 else
313 over_point = 0;
314 old_cursor_mode = -1;
315 return 0;
318 static int
319 PCBChanged (int argc, char **argv, int x, int y)
321 if (work_area == 0)
322 return 0;
323 /*printf("PCB Changed! %d x %d\n", PCB->MaxWidth, PCB->MaxHeight); */
324 n = 0;
325 stdarg (XmNminimum, 0);
326 stdarg (XmNvalue, 0);
327 stdarg (XmNsliderSize, PCB->MaxWidth ? PCB->MaxWidth : 1);
328 stdarg (XmNmaximum, PCB->MaxWidth ? PCB->MaxWidth : 1);
329 XtSetValues (hscroll, args, n);
330 n = 0;
331 stdarg (XmNminimum, 0);
332 stdarg (XmNvalue, 0);
333 stdarg (XmNsliderSize, PCB->MaxHeight ? PCB->MaxHeight : 1);
334 stdarg (XmNmaximum, PCB->MaxHeight ? PCB->MaxHeight : 1);
335 XtSetValues (vscroll, args, n);
336 zoom_by (1000000, 0, 0);
338 hid_action ("NetlistChanged");
339 hid_action ("LayersChanged");
340 hid_action ("RouteStylesChanged");
341 lesstif_sizes_reset ();
342 lesstif_update_layer_groups ();
343 while (pinouts)
344 pinout_unmap (0, pinouts, 0);
345 if (PCB->Filename)
347 char *cp = strrchr (PCB->Filename, '/');
348 n = 0;
349 stdarg (XmNtitle, cp ? cp + 1 : PCB->Filename);
350 XtSetValues (appwidget, args, n);
352 return 0;
356 static const char setunits_syntax[] =
357 "SetUnits(mm|mil)";
359 static const char setunits_help[] =
360 "Set the default measurement units.";
362 /* %start-doc actions SetUnits
364 @table @code
366 @item mil
367 Sets the display units to mils (1/1000 inch).
369 @item mm
370 Sets the display units to millimeters.
372 @end table
374 %end-doc */
376 static int
377 SetUnits (int argc, char **argv, int x, int y)
379 if (argc == 0)
380 return 0;
381 if (strcmp (argv[0], "mil") == 0)
382 Settings.grid_units_mm = 0;
383 if (strcmp (argv[0], "mm") == 0)
384 Settings.grid_units_mm = 1;
385 lesstif_sizes_reset ();
386 lesstif_styles_update_values ();
387 return 0;
390 static const char zoom_syntax[] =
391 "Zoom()\n"
392 "Zoom(factor)";
394 static const char zoom_help[] =
395 "Various zoom factor changes.";
397 /* %start-doc actions Zoom
399 Changes the zoom (magnification) of the view of the board. If no
400 arguments are passed, the view is scaled such that the board just fits
401 inside the visible window (i.e. ``view all''). Otherwise,
402 @var{factor} specifies a change in zoom factor. It may be prefixed by
403 @code{+}, @code{-}, or @code{=} to change how the zoom factor is
404 modified. The @var{factor} is a floating point number, such as
405 @code{1.5} or @code{0.75}.
407 @table @code
409 @item +@var{factor}
410 Values greater than 1.0 cause the board to be drawn smaller; more of
411 the board will be visible. Values between 0.0 and 1.0 cause the board
412 to be drawn bigger; less of the board will be visible.
414 @item -@var{factor}
415 Values greater than 1.0 cause the board to be drawn bigger; less of
416 the board will be visible. Values between 0.0 and 1.0 cause the board
417 to be drawn smaller; more of the board will be visible.
419 @item =@var{factor}
421 The @var{factor} is an absolute zoom factor; the unit for this value
422 is "PCB units per screen pixel". Since PCB units are 0.01 mil, a
423 @var{factor} of 1000 means 10 mils (0.01 in) per pixel, or 100 DPI,
424 about the actual resolution of most screens - resulting in an "actual
425 size" board. Similarly, a @var{factor} of 100 gives you a 10x actual
426 size.
428 @end table
430 Note that zoom factors of zero are silently ignored.
432 %end-doc */
434 static int
435 ZoomAction (int argc, char **argv, int x, int y)
437 const char *vp;
438 double v;
439 if (x == 0 && y == 0)
441 x = view_width / 2;
442 y = view_height / 2;
444 else
446 x = Vx (x);
447 y = Vy (y);
449 if (argc < 1)
451 zoom_to (1000000, 0, 0);
452 return 0;
454 vp = argv[0];
455 if (strcasecmp (vp, "toggle") == 0)
457 zoom_toggle (x, y);
458 return 0;
460 if (*vp == '+' || *vp == '-' || *vp == '=')
461 vp++;
462 v = strtod (vp, 0);
463 if (v <= 0)
464 return 1;
465 switch (argv[0][0])
467 case '-':
468 zoom_by (1 / v, x, y);
469 break;
470 default:
471 case '+':
472 zoom_by (v, x, y);
473 break;
474 case '=':
475 zoom_to (v, x, y);
476 break;
478 return 0;
481 static int pan_thumb_mode;
483 static int
484 PanAction (int argc, char **argv, int x, int y)
486 int mode;
488 if (argc == 2)
490 pan_thumb_mode = (strcasecmp (argv[0], "thumb") == 0) ? 1 : 0;
491 mode = atoi (argv[1]);
493 else
495 pan_thumb_mode = 0;
496 mode = atoi (argv[0]);
498 Pan (mode, Vx(x), Vy(y));
500 return 0;
503 static const char swapsides_syntax[] =
504 "SwapSides(|v|h|r)";
506 static const char swapsides_help[] =
507 "Swaps the side of the board you're looking at.";
509 /* %start-doc actions SwapSides
511 This action changes the way you view the board.
513 @table @code
515 @item v
516 Flips the board over vertically (up/down).
518 @item h
519 Flips the board over horizontally (left/right), like flipping pages in
520 a book.
522 @item r
523 Rotates the board 180 degrees without changing sides.
525 @end table
527 If no argument is given, the board isn't moved but the opposite side
528 is shown.
530 Normally, this action changes which pads and silk layer are drawn as
531 true silk, and which are drawn as the "invisible" layer. It also
532 determines which solder mask you see.
534 As a special case, if the layer group for the side you're looking at
535 is visible and currently active, and the layer group for the opposite
536 is not visible (i.e. disabled), then this action will also swap which
537 layer group is visible and active, effectively swapping the ``working
538 side'' of the board.
540 %end-doc */
542 static int
543 SwapSides (int argc, char **argv, int x, int y)
545 int old_shown_side = Settings.ShowSolderSide;
546 int comp_group = GetLayerGroupNumberByNumber (max_layer + COMPONENT_LAYER);
547 int solder_group = GetLayerGroupNumberByNumber (max_layer + SOLDER_LAYER);
548 int active_group = GetLayerGroupNumberByNumber (LayerStack[0]);
549 int comp_showing =
550 PCB->Data->Layer[PCB->LayerGroups.Entries[comp_group][0]].On;
551 int solder_showing =
552 PCB->Data->Layer[PCB->LayerGroups.Entries[solder_group][0]].On;
554 if (argc > 0)
556 switch (argv[0][0]) {
557 case 'h':
558 case 'H':
559 flip_x = ! flip_x;
560 break;
561 case 'v':
562 case 'V':
563 flip_y = ! flip_y;
564 break;
565 case 'r':
566 case 'R':
567 flip_x = ! flip_x;
568 flip_y = ! flip_y;
569 break;
570 default:
571 return 1;
573 /* SwapSides will swap this */
574 Settings.ShowSolderSide = (flip_x == flip_y);
577 n = 0;
578 if (flip_x)
579 stdarg (XmNprocessingDirection, XmMAX_ON_LEFT);
580 else
581 stdarg (XmNprocessingDirection, XmMAX_ON_RIGHT);
582 XtSetValues (hscroll, args, n);
584 n = 0;
585 if (flip_y)
586 stdarg (XmNprocessingDirection, XmMAX_ON_TOP);
587 else
588 stdarg (XmNprocessingDirection, XmMAX_ON_BOTTOM);
589 XtSetValues (vscroll, args, n);
591 Settings.ShowSolderSide = !Settings.ShowSolderSide;
593 /* The idea is that if we're looking at the front side and the front
594 layer is active (or visa versa), switching sides should switch
595 layers too. We used to only do this if the other layer wasn't
596 shown, but we now do it always. Change it back if users get
597 confused. */
598 if (Settings.ShowSolderSide != old_shown_side)
600 if (Settings.ShowSolderSide)
602 if (active_group == comp_group)
604 if (comp_showing && !solder_showing)
605 ChangeGroupVisibility (PCB->LayerGroups.Entries[comp_group][0], 0,
607 ChangeGroupVisibility (PCB->LayerGroups.Entries[solder_group][0], 1,
611 else
613 if (active_group == solder_group)
615 if (solder_showing && !comp_showing)
616 ChangeGroupVisibility (PCB->LayerGroups.Entries[solder_group][0], 0,
618 ChangeGroupVisibility (PCB->LayerGroups.Entries[comp_group][0], 1,
623 lesstif_invalidate_all ();
624 return 0;
627 static Widget m_cmd = 0, m_cmd_label;
629 static void
630 command_callback (Widget w, XtPointer uptr, XmTextVerifyCallbackStruct * cbs)
632 char *s;
633 switch (cbs->reason)
635 case XmCR_ACTIVATE:
636 s = XmTextGetString (w);
637 lesstif_show_crosshair (0);
638 hid_parse_command (s);
639 XtFree (s);
640 XmTextSetString (w, "");
641 case XmCR_LOSING_FOCUS:
642 XtUnmanageChild (m_cmd);
643 XtUnmanageChild (m_cmd_label);
644 break;
648 static void
649 command_event_handler (Widget w, XtPointer p, XEvent * e, bool * cont)
651 char buf[10];
652 KeySym sym;
653 int slen;
655 switch (e->type)
657 case KeyPress:
658 slen = XLookupString ((XKeyEvent *)e, buf, sizeof (buf), &sym, NULL);
659 switch (sym)
661 case XK_Escape:
662 XtUnmanageChild (m_cmd);
663 XtUnmanageChild (m_cmd_label);
664 XmTextSetString (w, "");
665 *cont = false;
666 break;
668 break;
672 static const char command_syntax[] =
673 "Command()";
675 static const char command_help[] =
676 "Displays the command line input window.";
678 /* %start-doc actions Command
680 The command window allows the user to manually enter actions to be
681 executed. Action syntax can be done one of two ways:
683 @table @code
685 @item
686 Follow the action name by an open parenthesis, arguments separated by
687 commas, end with a close parenthesis. Example: @code{Abc(1,2,3)}
689 @item
690 Separate the action name and arguments by spaces. Example: @code{Abc
691 1 2 3}.
693 @end table
695 The first option allows you to have arguments with spaces in them,
696 but the second is more ``natural'' to type for most people.
698 Note that action names are not case sensitive, but arguments normally
699 are. However, most actions will check for ``keywords'' in a case
700 insensitive way.
702 There are three ways to finish with the command window. If you press
703 the @code{Enter} key, the command is invoked, the window goes away,
704 and the next time you bring up the command window it's empty. If you
705 press the @code{Esc} key, the window goes away without invoking
706 anything, and the next time you bring up the command window it's
707 empty. If you change focus away from the command window (i.e. click
708 on some other window), the command window goes away but the next time
709 you bring it up it resumes entering the command you were entering
710 before.
712 %end-doc */
714 static int
715 Command (int argc, char **argv, int x, int y)
717 XtManageChild (m_cmd_label);
718 XtManageChild (m_cmd);
719 XmProcessTraversal (m_cmd, XmTRAVERSE_CURRENT);
720 return 0;
723 static const char benchmark_syntax[] =
724 "Benchmark()";
726 static const char benchmark_help[] =
727 "Benchmark the GUI speed.";
729 /* %start-doc actions Benchmark
731 This action is used to speed-test the Lesstif graphics subsystem. It
732 redraws the current screen as many times as possible in ten seconds.
733 It reports the amount of time needed to draw the screen once.
735 %end-doc */
737 static int
738 Benchmark (int argc, char **argv, int x, int y)
740 int i = 0;
741 time_t start, end;
742 BoxType region;
743 Drawable save_main;
745 save_main = main_pixmap;
746 main_pixmap = window;
748 region.X1 = 0;
749 region.Y1 = 0;
750 region.X2 = PCB->MaxWidth;
751 region.Y2 = PCB->MaxHeight;
753 pixmap = window;
754 XSync (display, 0);
755 time (&start);
758 XFillRectangle (display, pixmap, bg_gc, 0, 0, view_width, view_height);
759 hid_expose_callback (&lesstif_gui, &region, 0);
760 XSync (display, 0);
761 time (&end);
762 i++;
764 while (end - start < 10);
766 printf ("%g redraws per second\n", i / 10.0);
768 main_pixmap = save_main;
769 return 0;
772 static int
773 Center(int argc, char **argv, int x, int y)
775 x = GRIDFIT_X (x, PCB->Grid);
776 y = GRIDFIT_Y (y, PCB->Grid);
777 view_left_x = x - (view_width * view_zoom) / 2;
778 view_top_y = y - (view_height * view_zoom) / 2;
779 lesstif_pan_fixup ();
780 /* Move the pointer to the center of the window, but only if it's
781 currently within the window already. Watch out for edges,
782 though. */
783 XWarpPointer (display, window, window, 0, 0, view_width, view_height,
784 Vx(x), Vy(y));
785 return 0;
788 static const char cursor_syntax[] =
789 "Cursor(Type,DeltaUp,DeltaRight,Units)";
791 static const char cursor_help[] =
792 "Move the cursor.";
794 /* %start-doc actions Cursor
796 This action moves the mouse cursor. Unlike other actions which take
797 coordinates, this action's coordinates are always relative to the
798 user's view of the board. Thus, a positive @var{DeltaUp} may move the
799 cursor towards the board origin if the board is inverted.
801 Type is one of @samp{Pan} or @samp{Warp}. @samp{Pan} causes the
802 viewport to move such that the crosshair is under the mouse cursor.
803 @samp{Warp} causes the mouse cursor to move to be above the crosshair.
805 @var{Units} can be one of the following:
807 @table @samp
809 @item mil
810 @itemx mm
811 The cursor is moved by that amount, in board units.
813 @item grid
814 The cursor is moved by that many grid points.
816 @item view
817 The values are percentages of the viewport's view. Thus, a pan of
818 @samp{100} would scroll the viewport by exactly the width of the
819 current view.
821 @item board
822 The values are percentages of the board size. Thus, a move of
823 @samp{50,50} moves you halfway across the board.
825 @end table
827 %end-doc */
829 static int
830 CursorAction(int argc, char **argv, int x, int y)
832 int pan_warp = HID_SC_DO_NOTHING;
833 double dx, dy, xu, yu;
835 if (argc != 4)
836 AFAIL(cursor);
838 if (strcasecmp (argv[0], "pan") == 0)
839 pan_warp = HID_SC_PAN_VIEWPORT;
840 else if (strcasecmp (argv[0], "warp") == 0)
841 pan_warp = HID_SC_WARP_POINTER;
842 else
843 AFAIL(cursor);
845 dx = strtod (argv[1], 0);
846 if (flip_x)
847 dx = -dx;
848 dy = strtod (argv[2], 0);
849 if (!flip_y)
850 dy = -dy;
852 if (strncasecmp (argv[3], "mm", 2) == 0)
853 xu = yu = MM_TO_COOR;
854 else if (strncasecmp (argv[3], "mil", 3) == 0)
855 xu = yu = 100;
856 else if (strncasecmp (argv[3], "grid", 4) == 0)
857 xu = yu = PCB->Grid;
858 else if (strncasecmp (argv[3], "view", 4) == 0)
860 xu = Pz(view_width) / 100.0;
861 yu = Pz(view_height) / 100.0;
863 else if (strncasecmp (argv[3], "board", 4) == 0)
865 xu = PCB->MaxWidth / 100.0;
866 yu = PCB->MaxHeight / 100.0;
868 else
869 xu = yu = 100;
871 EventMoveCrosshair (Crosshair.X+(int)(dx*xu), Crosshair.Y+(int)(dy*yu));
872 gui->set_crosshair (Crosshair.X, Crosshair.Y, pan_warp);
874 return 0;
877 HID_Action lesstif_main_action_list[] = {
878 {"PCBChanged", 0, PCBChanged,
879 pcbchanged_help, pcbchanged_syntax},
880 {"SetUnits", 0, SetUnits,
881 setunits_help, setunits_syntax},
882 {"Zoom", "Click on a place to zoom in", ZoomAction,
883 zoom_help, zoom_syntax},
884 {"Pan", "Click on a place to pan", PanAction,
885 zoom_help, zoom_syntax},
886 {"SwapSides", 0, SwapSides,
887 swapsides_help, swapsides_syntax},
888 {"Command", 0, Command,
889 command_help, command_syntax},
890 {"Benchmark", 0, Benchmark,
891 benchmark_help, benchmark_syntax},
892 {"PointCursor", 0, PointCursor},
893 {"Center", "Click on a location to center", Center},
894 {"Busy", 0, Busy},
895 {"Cursor", 0, CursorAction,
896 cursor_help, cursor_syntax},
899 REGISTER_ACTIONS (lesstif_main_action_list)
902 /* ----------------------------------------------------------------------
903 * redraws the background image
906 static int bg_w, bg_h, bgi_w, bgi_h;
907 static Pixel **bg = 0;
908 static XImage *bgi = 0;
909 static enum {
910 PT_unknown,
911 PT_RGB565,
912 PT_RGB888
913 } pixel_type = PT_unknown;
915 static void
916 LoadBackgroundFile (FILE *f, char *filename)
918 XVisualInfo vinfot, *vinfo;
919 Visual *vis;
920 int c, r, b;
921 int i, nret;
922 int p[3], rows, cols, maxval;
924 if (fgetc(f) != 'P')
926 printf("bgimage: %s signature not P6\n", filename);
927 return;
929 if (fgetc(f) != '6')
931 printf("bgimage: %s signature not P6\n", filename);
932 return;
934 for (i=0; i<3; i++)
936 do {
937 b = fgetc(f);
938 if (feof(f))
939 return;
940 if (b == '#')
941 while (!feof(f) && b != '\n')
942 b = fgetc(f);
943 } while (!isdigit(b));
944 p[i] = b - '0';
945 while (isdigit(b = fgetc(f)))
946 p[i] = p[i]*10 + b - '0';
948 bg_w = cols = p[0];
949 bg_h = rows = p[1];
950 maxval = p[2];
952 setbuf(stdout, 0);
953 bg = (Pixel **) malloc (rows * sizeof (Pixel *));
954 if (!bg)
956 printf("Out of memory loading %s\n", filename);
957 return;
959 for (i=0; i<rows; i++)
961 bg[i] = (Pixel *) malloc (cols * sizeof (Pixel));
962 if (!bg[i])
964 printf("Out of memory loading %s\n", filename);
965 while (--i >= 0)
966 free (bg[i]);
967 free (bg);
968 bg = 0;
969 return;
973 vis = DefaultVisual (display, DefaultScreen(display));
975 vinfot.visualid = XVisualIDFromVisual(vis);
976 vinfo = XGetVisualInfo (display, VisualIDMask, &vinfot, &nret);
978 #if 0
979 /* If you want to support more visuals below, you'll probably need
980 this. */
981 printf("vinfo: rm %04x gm %04x bm %04x depth %d class %d\n",
982 vinfo->red_mask, vinfo->green_mask, vinfo->blue_mask,
983 vinfo->depth, vinfo->class);
984 #endif
986 if (vinfo->class == TrueColor
987 && vinfo->depth == 16
988 && vinfo->red_mask == 0xf800
989 && vinfo->green_mask == 0x07e0
990 && vinfo->blue_mask == 0x001f)
991 pixel_type = PT_RGB565;
993 if (vinfo->class == TrueColor
994 && vinfo->depth == 24
995 && vinfo->red_mask == 0xff0000
996 && vinfo->green_mask == 0x00ff00
997 && vinfo->blue_mask == 0x0000ff)
998 pixel_type = PT_RGB888;
1000 for (r=0; r<rows; r++)
1002 for (c=0; c<cols; c++)
1004 XColor pix;
1005 unsigned int pr = (unsigned)fgetc(f);
1006 unsigned int pg = (unsigned)fgetc(f);
1007 unsigned int pb = (unsigned)fgetc(f);
1009 switch (pixel_type)
1011 case PT_unknown:
1012 pix.red = pr * 65535 / maxval;
1013 pix.green = pg * 65535 / maxval;
1014 pix.blue = pb * 65535 / maxval;
1015 pix.flags = DoRed | DoGreen | DoBlue;
1016 XAllocColor (display, colormap, &pix);
1017 bg[r][c] = pix.pixel;
1018 break;
1019 case PT_RGB565:
1020 bg[r][c] = (pr>>3)<<11 | (pg>>2)<<5 | (pb>>3);
1021 break;
1022 case PT_RGB888:
1023 bg[r][c] = (pr << 16) | (pg << 8) | (pb);
1024 break;
1030 void
1031 LoadBackgroundImage (char *filename)
1033 FILE *f = fopen(filename, "rb");
1034 if (!f)
1036 if (NSTRCMP (filename, "pcb-background.ppm"))
1037 perror(filename);
1038 return;
1040 LoadBackgroundFile (f, filename);
1041 fclose(f);
1044 static void
1045 DrawBackgroundImage ()
1047 int x, y, w, h;
1048 double xscale, yscale;
1049 int pcbwidth = PCB->MaxWidth / view_zoom;
1050 int pcbheight = PCB->MaxHeight / view_zoom;
1052 if (!window || !bg)
1053 return;
1055 if (!bgi || view_width != bgi_w || view_height != bgi_h)
1057 if (bgi)
1058 XDestroyImage (bgi);
1059 /* Cheat - get the image, which sets up the format too. */
1060 bgi = XGetImage (XtDisplay(work_area),
1061 window,
1062 0, 0, view_width, view_height,
1063 -1, ZPixmap);
1064 bgi_w = view_width;
1065 bgi_h = view_height;
1068 w = MIN (view_width, pcbwidth);
1069 h = MIN (view_height, pcbheight);
1071 xscale = (double)bg_w / PCB->MaxWidth;
1072 yscale = (double)bg_h / PCB->MaxHeight;
1074 for (y=0; y<h; y++)
1076 int pr = Py(y);
1077 int ir = pr * yscale;
1078 for (x=0; x<w; x++)
1080 int pc = Px(x);
1081 int ic = pc * xscale;
1082 XPutPixel (bgi, x, y, bg[ir][ic]);
1085 XPutImage(display, main_pixmap, bg_gc,
1086 bgi,
1087 0, 0, 0, 0, w, h);
1089 /* ---------------------------------------------------------------------- */
1091 static HID_Attribute *
1092 lesstif_get_export_options (int *n)
1094 return 0;
1097 static void
1098 set_scroll (Widget s, int pos, int view, int pcb)
1100 int sz = view * view_zoom;
1101 if (sz > pcb)
1102 sz = pcb;
1103 n = 0;
1104 stdarg (XmNvalue, pos);
1105 stdarg (XmNsliderSize, sz);
1106 stdarg (XmNincrement, view_zoom);
1107 stdarg (XmNpageIncrement, sz);
1108 stdarg (XmNmaximum, pcb);
1109 XtSetValues (s, args, n);
1112 void
1113 lesstif_pan_fixup ()
1115 if (view_left_x > PCB->MaxWidth - (view_width * view_zoom))
1116 view_left_x = PCB->MaxWidth - (view_width * view_zoom);
1117 if (view_top_y > PCB->MaxHeight - (view_height * view_zoom))
1118 view_top_y = PCB->MaxHeight - (view_height * view_zoom);
1119 if (view_left_x < 0)
1120 view_left_x = 0;
1121 if (view_top_y < 0)
1122 view_top_y = 0;
1123 if (view_width * view_zoom > PCB->MaxWidth
1124 && view_height * view_zoom > PCB->MaxHeight)
1126 zoom_by (1, 0, 0);
1127 return;
1130 set_scroll (hscroll, view_left_x, view_width, PCB->MaxWidth);
1131 set_scroll (vscroll, view_top_y, view_height, PCB->MaxHeight);
1133 lesstif_invalidate_all ();
1136 static void
1137 zoom_to (double new_zoom, int x, int y)
1139 double max_zoom, xfrac, yfrac;
1140 int cx, cy;
1142 xfrac = (double) x / (double) view_width;
1143 yfrac = (double) y / (double) view_height;
1145 if (flip_x)
1146 xfrac = 1-xfrac;
1147 if (flip_y)
1148 yfrac = 1-yfrac;
1150 max_zoom = PCB->MaxWidth / view_width;
1151 if (max_zoom < PCB->MaxHeight / view_height)
1152 max_zoom = PCB->MaxHeight / view_height;
1154 if (new_zoom < 1)
1155 new_zoom = 1;
1156 if (new_zoom > max_zoom)
1157 new_zoom = max_zoom;
1159 cx = view_left_x + view_width * xfrac * view_zoom;
1160 cy = view_top_y + view_height * yfrac * view_zoom;
1162 if (view_zoom != new_zoom)
1164 view_zoom = new_zoom;
1165 pixel_slop = view_zoom;
1167 view_left_x = cx - view_width * xfrac * view_zoom;
1168 view_top_y = cy - view_height * yfrac * view_zoom;
1170 lesstif_pan_fixup ();
1173 static void
1174 zoom_toggle(int x, int y)
1176 double tmp;
1178 tmp = prev_view_zoom;
1179 prev_view_zoom = view_zoom;
1180 zoom_to(tmp, x, y);
1183 void
1184 zoom_by (double factor, int x, int y)
1186 zoom_to (view_zoom * factor, x, y);
1189 static int panning = 0;
1190 static int shift_pressed;
1191 static int ctrl_pressed;
1192 static int alt_pressed;
1194 /* X and Y are in screen coordinates. */
1195 static void
1196 Pan (int mode, int x, int y)
1198 static int ox, oy;
1199 static int opx, opy;
1201 panning = mode;
1202 /* This is for ctrl-pan, where the viewport's position is directly
1203 proportional to the cursor position in the window (like the Xaw
1204 thumb panner) */
1205 if (pan_thumb_mode)
1207 opx = x * PCB->MaxWidth / view_width;
1208 opy = y * PCB->MaxHeight / view_height;
1209 if (flip_x)
1210 opx = PCB->MaxWidth - opx;
1211 if (flip_y)
1212 opy = PCB->MaxHeight - opy;
1213 view_left_x = opx - view_width / 2 * view_zoom;
1214 view_top_y = opy - view_height / 2 * view_zoom;
1215 lesstif_pan_fixup ();
1217 /* This is the start of a regular pan. On the first click, we
1218 remember the coordinates where we "grabbed" the screen. */
1219 else if (mode == 1)
1221 ox = x;
1222 oy = y;
1223 opx = view_left_x;
1224 opy = view_top_y;
1226 /* continued drag, we calculate how far we've moved the cursor and
1227 set the position accordingly. */
1228 else
1230 if (flip_x)
1231 view_left_x = opx + (x - ox) * view_zoom;
1232 else
1233 view_left_x = opx - (x - ox) * view_zoom;
1234 if (flip_y)
1235 view_top_y = opy + (y - oy) * view_zoom;
1236 else
1237 view_top_y = opy - (y - oy) * view_zoom;
1238 lesstif_pan_fixup ();
1242 static void
1243 mod_changed (XKeyEvent * e, int set)
1245 switch (XKeycodeToKeysym (display, e->keycode, 0))
1247 case XK_Shift_L:
1248 case XK_Shift_R:
1249 shift_pressed = set;
1250 break;
1251 case XK_Control_L:
1252 case XK_Control_R:
1253 ctrl_pressed = set;
1254 break;
1255 #ifdef __APPLE__
1256 case XK_Mode_switch:
1257 #else
1258 case XK_Alt_L:
1259 case XK_Alt_R:
1260 #endif
1261 alt_pressed = set;
1262 break;
1263 default:
1264 // to include the Apple keyboard left and right command keys use XK_Meta_L and XK_Meta_R respectivly.
1265 return;
1267 in_move_event = 1;
1268 HideCrosshair (1);
1269 if (panning)
1270 Pan (2, e->x, e->y);
1271 EventMoveCrosshair (Px (e->x), Py (e->y));
1272 AdjustAttachedObjects ();
1273 RestoreCrosshair (1);
1274 in_move_event = 0;
1277 static void
1278 work_area_input (Widget w, XtPointer v, XEvent * e, bool * ctd)
1280 static int pressed_button = 0;
1281 static int ignore_release = 0;
1283 show_crosshair (0);
1284 switch (e->type)
1286 case KeyPress:
1287 mod_changed (&(e->xkey), 1);
1288 if (lesstif_key_event (&(e->xkey)))
1289 return;
1290 break;
1292 case KeyRelease:
1293 mod_changed (&(e->xkey), 0);
1294 break;
1296 case ButtonPress:
1298 int mods;
1299 if (pressed_button)
1300 return;
1301 /*printf("click %d\n", e->xbutton.button); */
1302 if (lesstif_button_event (w, e))
1304 ignore_release = 1;
1305 return;
1307 ignore_release = 0;
1309 HideCrosshair (true);
1310 pressed_button = e->xbutton.button;
1311 mods = ((e->xbutton.state & ShiftMask) ? M_Shift : 0)
1312 + ((e->xbutton.state & ControlMask) ? M_Ctrl : 0)
1313 #ifdef __APPLE__
1314 + ((e->xbutton.state & (1<<13)) ? M_Alt : 0);
1315 #else
1316 + ((e->xbutton.state & Mod1Mask) ? M_Alt : 0);
1317 #endif
1318 do_mouse_action(e->xbutton.button, mods);
1319 RestoreCrosshair (true);
1320 break;
1323 case ButtonRelease:
1325 int mods;
1326 if (e->xbutton.button != pressed_button)
1327 return;
1328 lesstif_button_event (w, e);
1329 HideCrosshair (true);
1330 pressed_button = 0;
1331 mods = ((e->xbutton.state & ShiftMask) ? M_Shift : 0)
1332 + ((e->xbutton.state & ControlMask) ? M_Ctrl : 0)
1333 #ifdef __APPLE__
1334 + ((e->xbutton.state & (1<<13)) ? M_Alt : 0)
1335 #else
1336 + ((e->xbutton.state & Mod1Mask) ? M_Alt : 0)
1337 #endif
1338 + M_Release;
1339 do_mouse_action (e->xbutton.button, mods);
1340 RestoreCrosshair (true);
1341 break;
1344 case MotionNotify:
1346 Window root, child;
1347 unsigned int keys_buttons;
1348 int root_x, root_y, pos_x, pos_y;
1349 while (XCheckMaskEvent (display, PointerMotionMask, e));
1350 XQueryPointer (display, e->xmotion.window, &root, &child,
1351 &root_x, &root_y, &pos_x, &pos_y, &keys_buttons);
1352 shift_pressed = (keys_buttons & ShiftMask);
1353 ctrl_pressed = (keys_buttons & ControlMask);
1354 #ifdef __APPLE__
1355 alt_pressed = (keys_buttons & (1<<13));
1356 #else
1357 alt_pressed = (keys_buttons & Mod1Mask);
1358 #endif
1359 /*printf("m %d %d\n", Px(e->xmotion.x), Py(e->xmotion.y)); */
1360 crosshair_in_window = 1;
1361 in_move_event = 1;
1362 if (panning)
1363 Pan (2, pos_x, pos_y);
1364 EventMoveCrosshair (Px (pos_x), Py (pos_y));
1365 in_move_event = 0;
1367 break;
1369 case LeaveNotify:
1370 crosshair_in_window = 0;
1371 CrosshairOff (1);
1372 need_idle_proc ();
1373 break;
1375 case EnterNotify:
1376 crosshair_in_window = 1;
1377 in_move_event = 1;
1378 EventMoveCrosshair (Px (e->xcrossing.x), Py (e->xcrossing.y));
1379 CrosshairOn (1);
1380 in_move_event = 0;
1381 need_idle_proc ();
1382 break;
1384 default:
1385 printf ("work_area: unknown event %d\n", e->type);
1386 break;
1390 static void
1391 draw_right_cross (GC xor_gc, int x, int y,
1392 int view_width, int view_height)
1394 XDrawLine (display, window, xor_gc, 0, y, view_width, y);
1395 XDrawLine (display, window, xor_gc, x, 0, x, view_height);
1398 static void
1399 draw_slanted_cross (GC xor_gc, int x, int y,
1400 int view_width, int view_height)
1402 int x0, y0, x1, y1;
1404 x0 = x + (view_height - y);
1405 x0 = MAX(0, MIN (x0, view_width));
1406 x1 = x - y;
1407 x1 = MAX(0, MIN (x1, view_width));
1408 y0 = y + (view_width - x);
1409 y0 = MAX(0, MIN (y0, view_height));
1410 y1 = y - x;
1411 y1 = MAX(0, MIN (y1, view_height));
1412 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1413 x0 = x - (view_height - y);
1414 x0 = MAX(0, MIN (x0, view_width));
1415 x1 = x + y;
1416 x1 = MAX(0, MIN (x1, view_width));
1417 y0 = y + x;
1418 y0 = MAX(0, MIN (y0, view_height));
1419 y1 = y - (view_width - x);
1420 y1 = MAX(0, MIN (y1, view_height));
1421 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1424 static void
1425 draw_dozen_cross (GC xor_gc, int x, int y,
1426 int view_width, int view_height)
1428 int x0, y0, x1, y1;
1429 double tan60 = sqrt (3);
1431 x0 = x + (view_height - y) / tan60;
1432 x0 = MAX(0, MIN (x0, view_width));
1433 x1 = x - y / tan60;
1434 x1 = MAX(0, MIN (x1, view_width));
1435 y0 = y + (view_width - x) * tan60;
1436 y0 = MAX(0, MIN (y0, view_height));
1437 y1 = y - x * tan60;
1438 y1 = MAX(0, MIN (y1, view_height));
1439 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1441 x0 = x + (view_height - y) * tan60;
1442 x0 = MAX(0, MIN (x0, view_width));
1443 x1 = x - y * tan60;
1444 x1 = MAX(0, MIN (x1, view_width));
1445 y0 = y + (view_width - x) / tan60;
1446 y0 = MAX(0, MIN (y0, view_height));
1447 y1 = y - x / tan60;
1448 y1 = MAX(0, MIN (y1, view_height));
1449 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1451 x0 = x - (view_height - y) / tan60;
1452 x0 = MAX(0, MIN (x0, view_width));
1453 x1 = x + y / tan60;
1454 x1 = MAX(0, MIN (x1, view_width));
1455 y0 = y + x * tan60;
1456 y0 = MAX(0, MIN (y0, view_height));
1457 y1 = y - (view_width - x) * tan60;
1458 y1 = MAX(0, MIN (y1, view_height));
1459 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1461 x0 = x - (view_height - y) * tan60;
1462 x0 = MAX(0, MIN (x0, view_width));
1463 x1 = x + y * tan60;
1464 x1 = MAX(0, MIN (x1, view_width));
1465 y0 = y + x / tan60;
1466 y0 = MAX(0, MIN (y0, view_height));
1467 y1 = y - (view_width - x) / tan60;
1468 y1 = MAX(0, MIN (y1, view_height));
1469 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1472 static void
1473 draw_crosshair (GC xor_gc, int x, int y,
1474 int view_width, int view_height)
1476 draw_right_cross (xor_gc, x, y, view_width, view_height);
1477 if (Crosshair.shape == Union_Jack_Crosshair_Shape)
1478 draw_slanted_cross (xor_gc, x, y, view_width, view_height);
1479 if (Crosshair.shape == Dozen_Crosshair_Shape)
1480 draw_dozen_cross (xor_gc, x, y, view_width, view_height);
1482 void
1483 lesstif_show_crosshair (int show)
1485 static int showing = 0;
1486 static int sx, sy;
1487 static GC xor_gc = 0;
1488 Pixel crosshair_color;
1490 if (!crosshair_in_window || !window)
1491 return;
1492 if (xor_gc == 0)
1494 crosshair_color = lesstif_parse_color (Settings.CrosshairColor) ^ bgcolor;
1495 xor_gc = XCreateGC (display, window, 0, 0);
1496 XSetFunction (display, xor_gc, GXxor);
1497 XSetForeground (display, xor_gc, crosshair_color);
1499 if (show == showing)
1500 return;
1501 if (show)
1503 sx = Vx (crosshair_x);
1504 sy = Vy (crosshair_y);
1506 else
1507 need_idle_proc ();
1508 draw_crosshair (xor_gc, sx, sy, view_width, view_height);
1509 showing = show;
1512 static void
1513 work_area_expose (Widget work_area, void *me,
1514 XmDrawingAreaCallbackStruct * cbs)
1516 XExposeEvent *e;
1518 show_crosshair (0);
1519 e = &(cbs->event->xexpose);
1520 XSetFunction (display, my_gc, GXcopy);
1521 XCopyArea (display, main_pixmap, window, my_gc,
1522 e->x, e->y, e->width, e->height, e->x, e->y);
1523 show_crosshair (1);
1526 static void
1527 scroll_callback (Widget scroll, int *view_dim,
1528 XmScrollBarCallbackStruct * cbs)
1530 *view_dim = cbs->value;
1531 lesstif_invalidate_all ();
1534 static void
1535 work_area_make_pixmaps (Dimension width, Dimension height)
1537 if (main_pixmap)
1538 XFreePixmap (display, main_pixmap);
1539 main_pixmap =
1540 XCreatePixmap (display, window, width, height,
1541 XDefaultDepth (display, screen));
1543 if (mask_pixmap)
1544 XFreePixmap (display, mask_pixmap);
1545 mask_pixmap =
1546 XCreatePixmap (display, window, width, height,
1547 XDefaultDepth (display, screen));
1548 #ifdef HAVE_XRENDER
1549 if (main_picture)
1551 XRenderFreePicture (display, main_picture);
1552 main_picture = 0;
1554 if (mask_picture)
1556 XRenderFreePicture (display, mask_picture);
1557 mask_picture = 0;
1559 if (use_xrender)
1561 main_picture = XRenderCreatePicture (display, main_pixmap,
1562 XRenderFindVisualFormat(display,
1563 DefaultVisual(display, screen)), 0, 0);
1564 mask_picture = XRenderCreatePicture (display, mask_pixmap,
1565 XRenderFindVisualFormat(display,
1566 DefaultVisual(display, screen)), 0, 0);
1567 if (!main_picture || !mask_picture)
1568 use_xrender = 0;
1570 #endif /* HAVE_XRENDER */
1572 if (mask_bitmap)
1573 XFreePixmap (display, mask_bitmap);
1574 mask_bitmap = XCreatePixmap (display, window, width, height, 1);
1576 pixmap = use_mask ? main_pixmap : mask_pixmap;
1577 pixmap_w = width;
1578 pixmap_h = height;
1581 static void
1582 work_area_resize (Widget work_area, void *me,
1583 XmDrawingAreaCallbackStruct * cbs)
1585 XColor color;
1586 Dimension width, height;
1588 show_crosshair (0);
1590 n = 0;
1591 stdarg (XtNwidth, &width);
1592 stdarg (XtNheight, &height);
1593 stdarg (XmNbackground, &bgcolor);
1594 XtGetValues (work_area, args, n);
1595 view_width = width;
1596 view_height = height;
1598 color.pixel = bgcolor;
1599 XQueryColor (display, colormap, &color);
1600 bgred = color.red;
1601 bggreen = color.green;
1602 bgblue = color.blue;
1604 if (!window)
1605 return;
1607 work_area_make_pixmaps (view_width, view_height);
1609 zoom_by (1, 0, 0);
1612 static void
1613 work_area_first_expose (Widget work_area, void *me,
1614 XmDrawingAreaCallbackStruct * cbs)
1616 int c;
1617 Dimension width, height;
1618 static char dashes[] = { 4, 4 };
1620 window = XtWindow (work_area);
1621 my_gc = XCreateGC (display, window, 0, 0);
1623 arc1_gc = XCreateGC (display, window, 0, 0);
1624 c = lesstif_parse_color ("#804000");
1625 XSetForeground (display, arc1_gc, c);
1626 arc2_gc = XCreateGC (display, window, 0, 0);
1627 c = lesstif_parse_color ("#004080");
1628 XSetForeground (display, arc2_gc, c);
1629 XSetLineAttributes (display, arc1_gc, 1, LineOnOffDash, 0, 0);
1630 XSetLineAttributes (display, arc2_gc, 1, LineOnOffDash, 0, 0);
1631 XSetDashes (display, arc1_gc, 0, dashes, 2);
1632 XSetDashes (display, arc2_gc, 0, dashes, 2);
1634 n = 0;
1635 stdarg (XtNwidth, &width);
1636 stdarg (XtNheight, &height);
1637 stdarg (XmNbackground, &bgcolor);
1638 XtGetValues (work_area, args, n);
1639 view_width = width;
1640 view_height = height;
1642 offlimit_color = lesstif_parse_color (Settings.OffLimitColor);
1643 grid_color = lesstif_parse_color (Settings.GridColor);
1645 bg_gc = XCreateGC (display, window, 0, 0);
1646 XSetForeground (display, bg_gc, bgcolor);
1648 work_area_make_pixmaps (width, height);
1650 #ifdef HAVE_XRENDER
1651 if (use_xrender)
1653 XRenderPictureAttributes pa;
1654 XRenderColor a = {0, 0, 0, 0x8000};
1656 pale_pixmap = XCreatePixmap (display, window, 1, 1, 8);
1657 pa.repeat = true;
1658 pale_picture = XRenderCreatePicture (display, pale_pixmap,
1659 XRenderFindStandardFormat(display, PictStandardA8),
1660 CPRepeat, &pa);
1661 if (pale_picture)
1662 XRenderFillRectangle(display, PictOpSrc, pale_picture, &a, 0, 0, 1, 1);
1663 else
1664 use_xrender = 0;
1666 #endif /* HAVE_XRENDER */
1668 clip_gc = XCreateGC (display, window, 0, 0);
1669 bset_gc = XCreateGC (display, mask_bitmap, 0, 0);
1670 XSetForeground (display, bset_gc, 1);
1671 bclear_gc = XCreateGC (display, mask_bitmap, 0, 0);
1672 XSetForeground (display, bclear_gc, 0);
1674 XtRemoveCallback (work_area, XmNexposeCallback,
1675 (XtCallbackProc) work_area_first_expose, 0);
1676 XtAddCallback (work_area, XmNexposeCallback,
1677 (XtCallbackProc) work_area_expose, 0);
1678 lesstif_invalidate_all ();
1681 static Widget
1682 make_message (char *name, Widget left, int resizeable)
1684 Widget w, f;
1685 n = 0;
1686 if (left)
1688 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
1689 stdarg (XmNleftWidget, XtParent(left));
1691 else
1693 stdarg (XmNleftAttachment, XmATTACH_FORM);
1695 stdarg (XmNtopAttachment, XmATTACH_FORM);
1696 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1697 stdarg (XmNshadowType, XmSHADOW_IN);
1698 stdarg (XmNshadowThickness, 1);
1699 stdarg (XmNalignment, XmALIGNMENT_CENTER);
1700 stdarg (XmNmarginWidth, 4);
1701 stdarg (XmNmarginHeight, 1);
1702 if (!resizeable)
1703 stdarg (XmNresizePolicy, XmRESIZE_GROW);
1704 f = XmCreateForm (messages, name, args, n);
1705 XtManageChild (f);
1706 n = 0;
1707 stdarg (XmNtopAttachment, XmATTACH_FORM);
1708 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1709 stdarg (XmNleftAttachment, XmATTACH_FORM);
1710 stdarg (XmNrightAttachment, XmATTACH_FORM);
1711 w = XmCreateLabel (f, name, args, n);
1712 XtManageChild (w);
1713 return w;
1716 static void
1717 lesstif_do_export (HID_Attr_Val * options)
1719 Dimension width, height;
1720 Widget menu;
1721 Widget work_area_frame;
1723 n = 0;
1724 stdarg (XtNwidth, &width);
1725 stdarg (XtNheight, &height);
1726 XtGetValues (appwidget, args, n);
1728 if (width < 1)
1729 width = 640;
1730 if (width > XDisplayWidth (display, screen))
1731 width = XDisplayWidth (display, screen);
1732 if (height < 1)
1733 height = 480;
1734 if (height > XDisplayHeight (display, screen))
1735 height = XDisplayHeight (display, screen);
1737 n = 0;
1738 stdarg (XmNwidth, width);
1739 stdarg (XmNheight, height);
1740 XtSetValues (appwidget, args, n);
1742 stdarg (XmNspacing, 0);
1743 mainwind = XmCreateMainWindow (appwidget, "mainWind", args, n);
1744 XtManageChild (mainwind);
1746 n = 0;
1747 stdarg (XmNmarginWidth, 0);
1748 stdarg (XmNmarginHeight, 0);
1749 menu = lesstif_menu (mainwind, "menubar", args, n);
1750 XtManageChild (menu);
1752 n = 0;
1753 stdarg (XmNshadowType, XmSHADOW_IN);
1754 work_area_frame =
1755 XmCreateFrame (mainwind, "work_area_frame", args, n);
1756 XtManageChild (work_area_frame);
1758 n = 0;
1759 do_color (Settings.BackgroundColor, XmNbackground);
1760 work_area = XmCreateDrawingArea (work_area_frame, "work_area", args, n);
1761 XtManageChild (work_area);
1762 XtAddCallback (work_area, XmNexposeCallback,
1763 (XtCallbackProc) work_area_first_expose, 0);
1764 XtAddCallback (work_area, XmNresizeCallback,
1765 (XtCallbackProc) work_area_resize, 0);
1766 /* A regular callback won't work here, because lesstif swallows any
1767 Ctrl<Button>1 event. */
1768 XtAddEventHandler (work_area,
1769 ButtonPressMask | ButtonReleaseMask
1770 | PointerMotionMask | PointerMotionHintMask
1771 | KeyPressMask | KeyReleaseMask
1772 | EnterWindowMask | LeaveWindowMask,
1773 0, work_area_input, 0);
1775 n = 0;
1776 stdarg (XmNorientation, XmVERTICAL);
1777 stdarg (XmNprocessingDirection, XmMAX_ON_BOTTOM);
1778 stdarg (XmNmaximum, PCB->MaxHeight ? PCB->MaxHeight : 1);
1779 vscroll = XmCreateScrollBar (mainwind, "vscroll", args, n);
1780 XtAddCallback (vscroll, XmNvalueChangedCallback,
1781 (XtCallbackProc) scroll_callback, (XtPointer) & view_top_y);
1782 XtAddCallback (vscroll, XmNdragCallback, (XtCallbackProc) scroll_callback,
1783 (XtPointer) & view_top_y);
1784 XtManageChild (vscroll);
1786 n = 0;
1787 stdarg (XmNorientation, XmHORIZONTAL);
1788 stdarg (XmNmaximum, PCB->MaxWidth ? PCB->MaxWidth : 1);
1789 hscroll = XmCreateScrollBar (mainwind, "hscroll", args, n);
1790 XtAddCallback (hscroll, XmNvalueChangedCallback,
1791 (XtCallbackProc) scroll_callback, (XtPointer) & view_left_x);
1792 XtAddCallback (hscroll, XmNdragCallback, (XtCallbackProc) scroll_callback,
1793 (XtPointer) & view_left_x);
1794 XtManageChild (hscroll);
1796 n = 0;
1797 stdarg (XmNresize, true);
1798 stdarg (XmNresizePolicy, XmRESIZE_ANY);
1799 messages = XmCreateForm (mainwind, "messages", args, n);
1800 XtManageChild (messages);
1802 n = 0;
1803 stdarg (XmNtopAttachment, XmATTACH_FORM);
1804 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1805 stdarg (XmNleftAttachment, XmATTACH_FORM);
1806 stdarg (XmNrightAttachment, XmATTACH_FORM);
1807 stdarg (XmNalignment, XmALIGNMENT_CENTER);
1808 stdarg (XmNshadowThickness, 2);
1809 m_click = XmCreateLabel (messages, "click", args, n);
1811 n = 0;
1812 stdarg (XmNtopAttachment, XmATTACH_FORM);
1813 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1814 stdarg (XmNleftAttachment, XmATTACH_FORM);
1815 stdarg (XmNlabelString, XmStringCreateLocalized ("Command: "));
1816 m_cmd_label = XmCreateLabel (messages, "command", args, n);
1818 n = 0;
1819 stdarg (XmNtopAttachment, XmATTACH_FORM);
1820 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1821 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
1822 stdarg (XmNleftWidget, m_cmd_label);
1823 stdarg (XmNrightAttachment, XmATTACH_FORM);
1824 stdarg (XmNshadowThickness, 1);
1825 stdarg (XmNhighlightThickness, 0);
1826 stdarg (XmNmarginWidth, 2);
1827 stdarg (XmNmarginHeight, 2);
1828 m_cmd = XmCreateTextField (messages, "command", args, n);
1829 XtAddCallback (m_cmd, XmNactivateCallback,
1830 (XtCallbackProc) command_callback, 0);
1831 XtAddCallback (m_cmd, XmNlosingFocusCallback,
1832 (XtCallbackProc) command_callback, 0);
1833 XtAddEventHandler (m_cmd, KeyPressMask, 0, command_event_handler, 0);
1835 m_mark = make_message ("m_mark", 0, 0);
1836 m_crosshair = make_message ("m_crosshair", m_mark, 0);
1837 m_grid = make_message ("m_grid", m_crosshair, 1);
1838 m_zoom = make_message ("m_zoom", m_grid, 1);
1839 lesstif_m_layer = make_message ("m_layer", m_zoom, 0);
1840 m_mode = make_message ("m_mode", lesstif_m_layer, 1);
1841 m_rats = make_message ("m_rats", m_mode, 1);
1842 m_status = make_message ("m_status", m_mode, 1);
1844 XtUnmanageChild (XtParent (m_mark));
1845 XtUnmanageChild (XtParent (m_rats));
1847 n = 0;
1848 stdarg (XmNrightAttachment, XmATTACH_FORM);
1849 XtSetValues (XtParent (m_status), args, n);
1851 /* We'll use this later. */
1852 n = 0;
1853 stdarg (XmNleftWidget, XtParent (m_mark));
1854 XtSetValues (XtParent (m_crosshair), args, n);
1856 n = 0;
1857 stdarg (XmNmessageWindow, messages);
1858 XtSetValues (mainwind, args, n);
1860 if (background_image_file)
1861 LoadBackgroundImage (background_image_file);
1863 XtRealizeWidget (appwidget);
1865 while (!window)
1867 XEvent e;
1868 XtAppNextEvent (app_context, &e);
1869 XtDispatchEvent (&e);
1872 PCBChanged (0, 0, 0, 0);
1874 XtAppMainLoop (app_context);
1877 #if 0
1878 XrmOptionDescRec lesstif_options[] = {
1881 XtResource lesstif_resources[] = {
1883 #endif
1885 typedef union
1887 int i;
1888 double f;
1889 char *s;
1890 } val_union;
1892 static bool
1893 cvtres_string_to_double (Display * d, XrmValue * args, Cardinal * num_args,
1894 XrmValue * from, XrmValue * to,
1895 XtPointer * converter_data)
1897 static double rv;
1898 rv = strtod ((char *) from->addr, 0);
1899 if (to->addr)
1900 *(double *) to->addr = rv;
1901 else
1902 to->addr = (XPointer) & rv;
1903 to->size = sizeof (rv);
1904 return true;
1907 static void
1908 mainwind_delete_cb ()
1910 hid_action ("Quit");
1913 static void
1914 lesstif_listener_cb (XtPointer client_data, int *fid, XtInputId *id)
1916 char buf[BUFSIZ];
1917 int nbytes;
1919 if ((nbytes = read (*fid, buf, BUFSIZ)) == -1)
1920 perror ("lesstif_listener_cb");
1922 if (nbytes)
1924 buf[nbytes] = '\0';
1925 hid_parse_actions (buf);
1930 static void
1931 lesstif_parse_arguments (int *argc, char ***argv)
1933 Atom close_atom;
1934 HID_AttrNode *ha;
1935 int acount = 0, amax;
1936 int rcount = 0, rmax;
1937 int i;
1938 XrmOptionDescRec *new_options;
1939 XtResource *new_resources;
1940 val_union *new_values;
1941 int render_event, render_error;
1943 XtSetTypeConverter (XtRString,
1944 XtRDouble,
1945 cvtres_string_to_double, NULL, 0, XtCacheAll, NULL);
1947 for (ha = hid_attr_nodes; ha; ha = ha->next)
1948 for (i = 0; i < ha->n; i++)
1950 HID_Attribute *a = ha->attributes + i;
1951 switch (a->type)
1953 case HID_Integer:
1954 case HID_Real:
1955 case HID_String:
1956 case HID_Path:
1957 case HID_Boolean:
1958 acount++;
1959 rcount++;
1960 break;
1961 default:
1962 break;
1966 #if 0
1967 amax = acount + XtNumber (lesstif_options);
1968 #else
1969 amax = acount;
1970 #endif
1972 new_options = malloc ((amax + 1) * sizeof (XrmOptionDescRec));
1974 #if 0
1975 memcpy (new_options + acount, lesstif_options, sizeof (lesstif_options));
1976 #endif
1977 acount = 0;
1979 #if 0
1980 rmax = rcount + XtNumber (lesstif_resources);
1981 #else
1982 rmax = rcount;
1983 #endif
1985 new_resources = malloc ((rmax + 1) * sizeof (XtResource));
1986 new_values = malloc ((rmax + 1) * sizeof (val_union));
1987 #if 0
1988 memcpy (new_resources + acount, lesstif_resources,
1989 sizeof (lesstif_resources));
1990 #endif
1991 rcount = 0;
1993 for (ha = hid_attr_nodes; ha; ha = ha->next)
1994 for (i = 0; i < ha->n; i++)
1996 HID_Attribute *a = ha->attributes + i;
1997 XrmOptionDescRec *o = new_options + acount;
1998 char *tmpopt, *tmpres;
1999 XtResource *r = new_resources + rcount;
2001 tmpopt = (char *) malloc (strlen (a->name) + 3);
2002 tmpopt[0] = tmpopt[1] = '-';
2003 strcpy (tmpopt + 2, a->name);
2004 o->option = tmpopt;
2006 tmpres = (char *) malloc (strlen (a->name) + 2);
2007 tmpres[0] = '*';
2008 strcpy (tmpres + 1, a->name);
2009 o->specifier = tmpres;
2011 switch (a->type)
2013 case HID_Integer:
2014 case HID_Real:
2015 case HID_String:
2016 case HID_Path:
2017 o->argKind = XrmoptionSepArg;
2018 o->value = 0;
2019 acount++;
2020 break;
2021 case HID_Boolean:
2022 o->argKind = XrmoptionNoArg;
2023 o->value = "True";
2024 acount++;
2025 break;
2026 default:
2027 break;
2030 r->resource_name = a->name;
2031 r->resource_class = a->name;
2032 r->resource_offset = sizeof (val_union) * rcount;
2034 switch (a->type)
2036 case HID_Integer:
2037 r->resource_type = XtRInt;
2038 r->default_type = XtRInt;
2039 r->resource_size = sizeof (int);
2040 r->default_addr = &(a->default_val.int_value);
2041 rcount++;
2042 break;
2043 case HID_Real:
2044 r->resource_type = XtRDouble;
2045 r->default_type = XtRDouble;
2046 r->resource_size = sizeof (double);
2047 r->default_addr = &(a->default_val.real_value);
2048 rcount++;
2049 break;
2050 case HID_String:
2051 case HID_Path:
2052 r->resource_type = XtRString;
2053 r->default_type = XtRString;
2054 r->resource_size = sizeof (char *);
2055 r->default_addr = a->default_val.str_value;
2056 rcount++;
2057 break;
2058 case HID_Boolean:
2059 r->resource_type = XtRBoolean;
2060 r->default_type = XtRInt;
2061 r->resource_size = sizeof (int);
2062 r->default_addr = &(a->default_val.int_value);
2063 rcount++;
2064 break;
2065 default:
2066 break;
2069 #if 0
2070 for (i = 0; i < XtNumber (lesstif_resources); i++)
2072 XtResource *r = new_resources + rcount;
2073 r->resource_offset = sizeof (val_union) * rcount;
2074 rcount++;
2076 #endif
2078 n = 0;
2079 stdarg (XmNdeleteResponse, XmDO_NOTHING);
2081 appwidget = XtAppInitialize (&app_context,
2082 "Pcb",
2083 new_options, amax, argc, *argv, 0, args, n);
2085 display = XtDisplay (appwidget);
2086 screen_s = XtScreen (appwidget);
2087 screen = XScreenNumberOfScreen (screen_s);
2088 colormap = XDefaultColormap (display, screen);
2090 close_atom = XmInternAtom (display, "WM_DELETE_WINDOW", 0);
2091 XmAddWMProtocolCallback (appwidget, close_atom,
2092 (XtCallbackProc) mainwind_delete_cb, 0);
2094 /* XSynchronize(display, true); */
2096 XtGetApplicationResources (appwidget, new_values, new_resources,
2097 rmax, 0, 0);
2099 #ifdef HAVE_XRENDER
2100 use_xrender = XRenderQueryExtension (display, &render_event, &render_error) &&
2101 XRenderFindVisualFormat (display, DefaultVisual(display, screen));
2102 #endif /* HAVE_XRENDER */
2104 rcount = 0;
2105 for (ha = hid_attr_nodes; ha; ha = ha->next)
2106 for (i = 0; i < ha->n; i++)
2108 HID_Attribute *a = ha->attributes + i;
2109 val_union *v = new_values + rcount;
2110 switch (a->type)
2112 case HID_Integer:
2113 if (a->value)
2114 *(int *) a->value = v->i;
2115 else
2116 a->default_val.int_value = v->i;
2117 rcount++;
2118 break;
2119 case HID_Boolean:
2120 if (a->value)
2121 *(char *) a->value = v->i;
2122 else
2123 a->default_val.int_value = v->i;
2124 rcount++;
2125 break;
2126 case HID_Real:
2127 if (a->value)
2128 *(double *) a->value = v->f;
2129 else
2130 a->default_val.real_value = v->f;
2131 rcount++;
2132 break;
2133 case HID_String:
2134 case HID_Path:
2135 if (a->value)
2136 *(char **) a->value = v->s;
2137 else
2138 a->default_val.str_value = v->s;
2139 rcount++;
2140 break;
2141 default:
2142 break;
2146 /* redefine colormap, if requested via "-install" */
2147 if (use_private_colormap)
2149 colormap = XCopyColormapAndFree (display, colormap);
2150 XtVaSetValues (appwidget, XtNcolormap, colormap, NULL);
2153 /* listen on standard input for actions */
2154 if (stdin_listen)
2156 XtAppAddInput (app_context, fileno (stdin), (XtPointer) XtInputReadMask,
2157 lesstif_listener_cb, NULL);
2161 static void
2162 draw_grid ()
2164 static XPoint *points = 0;
2165 static int npoints = 0;
2166 int x1, y1, x2, y2, n, prevx;
2167 double x, y;
2168 static GC grid_gc = 0;
2170 if (!Settings.DrawGrid)
2171 return;
2172 if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
2173 return;
2174 if (!grid_gc)
2176 grid_gc = XCreateGC (display, window, 0, 0);
2177 XSetFunction (display, grid_gc, GXxor);
2178 XSetForeground (display, grid_gc, grid_color);
2180 if (flip_x)
2182 x2 = GRIDFIT_X (Px (0), PCB->Grid);
2183 x1 = GRIDFIT_X (Px (view_width), PCB->Grid);
2184 if (Vx (x2) < 0)
2185 x2 -= PCB->Grid;
2186 if (Vx (x1) >= view_width)
2187 x1 += PCB->Grid;
2189 else
2191 x1 = GRIDFIT_X (Px (0), PCB->Grid);
2192 x2 = GRIDFIT_X (Px (view_width), PCB->Grid);
2193 if (Vx (x1) < 0)
2194 x1 += PCB->Grid;
2195 if (Vx (x2) >= view_width)
2196 x2 -= PCB->Grid;
2198 if (flip_y)
2200 y2 = GRIDFIT_Y (Py (0), PCB->Grid);
2201 y1 = GRIDFIT_Y (Py (view_height), PCB->Grid);
2202 if (Vy (y2) < 0)
2203 y2 -= PCB->Grid;
2204 if (Vy (y1) >= view_height)
2205 y1 += PCB->Grid;
2207 else
2209 y1 = GRIDFIT_Y (Py (0), PCB->Grid);
2210 y2 = GRIDFIT_Y (Py (view_height), PCB->Grid);
2211 if (Vy (y1) < 0)
2212 y1 += PCB->Grid;
2213 if (Vy (y2) >= view_height)
2214 y2 -= PCB->Grid;
2216 n = (int) ((x2 - x1) / PCB->Grid + 0.5) + 1;
2217 if (n > npoints)
2219 npoints = n + 10;
2220 points =
2221 MyRealloc (points, npoints * sizeof (XPoint), "lesstif_draw_grid");
2223 n = 0;
2224 prevx = 0;
2225 for (x = x1; x <= x2; x += PCB->Grid)
2227 int temp = Vx (x);
2228 points[n].x = temp;
2229 if (n)
2231 points[n].x -= prevx;
2232 points[n].y = 0;
2234 prevx = temp;
2235 n++;
2237 for (y = y1; y <= y2; y += PCB->Grid)
2239 int vy = Vy (y);
2240 points[0].y = vy;
2241 XDrawPoints (display, pixmap, grid_gc, points, n, CoordModePrevious);
2245 static int
2246 coords_to_widget (int x, int y, Widget w, int prev_state)
2248 int this_state = prev_state;
2249 static char buf[60];
2250 double dx, dy, g;
2251 int frac = 0;
2252 XmString ms;
2254 if (Settings.grid_units_mm)
2256 /* MM */
2257 dx = PCB_TO_MM (x);
2258 dy = PCB_TO_MM (y);
2259 g = PCB_TO_MM (PCB->Grid);
2261 else
2263 /* Mils */
2264 dx = PCB_TO_MIL (x);
2265 dy = PCB_TO_MIL (y);
2266 g = PCB_TO_MIL (PCB->Grid);
2268 if (x < 0 && prev_state >= 0)
2269 buf[0] = 0;
2270 else if (((int) (g * 10000 + 0.5) % 10000) == 0)
2272 const char *fmt = prev_state < 0 ? "%+d, %+d" : "%d, %d";
2273 sprintf (buf, fmt, (int) (dx + 0.5), (int) (dy + 0.5));
2274 this_state = 2 + Settings.grid_units_mm;
2275 frac = 0;
2277 else if (PCB->Grid <= 20 && Settings.grid_units_mm)
2279 const char *fmt = prev_state < 0 ? "%+.3f, %+.3f" : "%.3f, %.3f";
2280 sprintf (buf, fmt, dx, dy);
2281 this_state = 4 + Settings.grid_units_mm;
2282 frac = 1;
2284 else
2286 const char *fmt = prev_state < 0 ? "%+.2f, %+.2f" : "%.2f, %.2f";
2287 sprintf (buf, fmt, dx, dy);
2288 this_state = 4 + Settings.grid_units_mm;
2289 frac = 1;
2291 if (prev_state < 0 && (x || y))
2293 int angle = atan2 (dy, -dx) * 180 / M_PI;
2294 double dist = sqrt (dx * dx + dy * dy);
2295 if (frac)
2296 sprintf (buf + strlen (buf), " (%.2f", dist);
2297 else
2298 sprintf (buf + strlen (buf), " (%d", (int) (dist + 0.5));
2299 sprintf (buf + strlen (buf), ", %d\260)", angle);
2301 ms = XmStringCreateLocalized (buf);
2302 n = 0;
2303 stdarg (XmNlabelString, ms);
2304 XtSetValues (w, args, n);
2305 return this_state;
2308 static char *
2309 pcb2str (int pcbval)
2311 static char buf[20][20];
2312 static int bufp = 0;
2313 double d;
2315 bufp = (bufp + 1) % 20;
2316 if (Settings.grid_units_mm)
2317 d = PCB_TO_MM (pcbval);
2318 else
2319 d = PCB_TO_MIL (pcbval);
2321 if ((int) (d * 100 + 0.5) == (int) (d + 0.005) * 100)
2322 sprintf (buf[bufp], "%d", (int) d);
2323 else
2324 sprintf (buf[bufp], "%.2f", d);
2325 return buf[bufp];
2328 #define u(x) pcb2str(x)
2329 #define S Settings
2331 void
2332 lesstif_update_status_line ()
2334 char buf[100];
2335 char *s45 = cur_clip ();
2336 XmString xs;
2338 buf[0] = 0;
2339 switch (Settings.Mode)
2341 case VIA_MODE:
2342 sprintf (buf, "%s/%s \370=%s", u (S.ViaThickness),
2343 u (S.Keepaway), u (S.ViaDrillingHole));
2344 break;
2345 case LINE_MODE:
2346 case ARC_MODE:
2347 sprintf (buf, "%s/%s %s", u (S.LineThickness), u (S.Keepaway), s45);
2348 break;
2349 case RECTANGLE_MODE:
2350 case POLYGON_MODE:
2351 sprintf (buf, "%s %s", u (S.Keepaway), s45);
2352 break;
2353 case TEXT_MODE:
2354 sprintf (buf, "%s", u (S.TextScale));
2355 break;
2356 case MOVE_MODE:
2357 case COPY_MODE:
2358 case INSERTPOINT_MODE:
2359 case RUBBERBANDMOVE_MODE:
2360 sprintf (buf, "%s", s45);
2361 break;
2362 case NO_MODE:
2363 case PASTEBUFFER_MODE:
2364 case ROTATE_MODE:
2365 case REMOVE_MODE:
2366 case THERMAL_MODE:
2367 case ARROW_MODE:
2368 case LOCK_MODE:
2369 break;
2372 xs = XmStringCreateLocalized (buf);
2373 n = 0;
2374 stdarg (XmNlabelString, xs);
2375 XtSetValues (m_status, args, n);
2378 #undef u
2379 #undef S
2381 static int idle_proc_set = 0;
2382 static int need_redraw = 0;
2384 static bool
2385 idle_proc (XtPointer dummy)
2387 if (need_redraw)
2389 int mx, my;
2390 BoxType region;
2391 lesstif_use_mask (0);
2392 Crosshair.On = 0;
2393 pixmap = main_pixmap;
2394 mx = view_width;
2395 my = view_height;
2396 region.X1 = Px (0);
2397 region.Y1 = Py (0);
2398 region.X2 = Px (view_width);
2399 region.Y2 = Py (view_height);
2400 if (flip_x)
2402 int tmp = region.X1;
2403 region.X1 = region.X2;
2404 region.X2 = tmp;
2406 if (flip_y)
2408 int tmp = region.Y1;
2409 region.Y1 = region.Y2;
2410 region.Y2 = tmp;
2412 XSetForeground (display, bg_gc, bgcolor);
2413 XFillRectangle (display, main_pixmap, bg_gc, 0, 0, mx, my);
2414 if (region.X2 > PCB->MaxWidth || region.Y2 > PCB->MaxHeight)
2416 XSetForeground (display, bg_gc, offlimit_color);
2417 if (region.X2 > PCB->MaxWidth)
2419 mx = Vx (PCB->MaxWidth);
2420 if (flip_x)
2421 XFillRectangle (display, main_pixmap, bg_gc, 0, 0,
2422 mx-1, my);
2423 else
2424 XFillRectangle (display, main_pixmap, bg_gc, mx+1, 0,
2425 view_width - mx + 1, my);
2428 if (region.Y2 > PCB->MaxHeight)
2430 my = Vy (PCB->MaxHeight) + 1;
2431 if (flip_y)
2432 XFillRectangle (display, main_pixmap, bg_gc, 0, 0, mx,
2433 my-1);
2434 else
2435 XFillRectangle (display, main_pixmap, bg_gc, 0, my, mx,
2436 view_height - my + 1);
2439 DrawBackgroundImage();
2440 hid_expose_callback (&lesstif_gui, &region, 0);
2441 draw_grid ();
2442 lesstif_use_mask (0);
2443 XSetFunction (display, my_gc, GXcopy);
2444 XCopyArea (display, main_pixmap, window, my_gc, 0, 0, view_width,
2445 view_height, 0, 0);
2446 pixmap = window;
2447 CrosshairOn (0);
2448 need_redraw = 0;
2452 static int c_x = -2, c_y = -2;
2453 static MarkType saved_mark;
2454 if (crosshair_x != c_x || crosshair_y != c_y
2455 || memcmp (&saved_mark, &Marked, sizeof (MarkType)))
2457 static int last_state = 0;
2458 static int this_state = 0;
2460 c_x = crosshair_x;
2461 c_y = crosshair_y;
2463 this_state =
2464 coords_to_widget (crosshair_x, crosshair_y, m_crosshair,
2465 this_state);
2466 if (Marked.status)
2467 coords_to_widget (crosshair_x - Marked.X, crosshair_y - Marked.Y,
2468 m_mark, -1);
2470 if (Marked.status != saved_mark.status)
2472 if (Marked.status)
2474 XtManageChild (XtParent (m_mark));
2475 XtManageChild (m_mark);
2476 n = 0;
2477 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
2478 stdarg (XmNleftWidget, XtParent (m_mark));
2479 XtSetValues (XtParent (m_crosshair), args, n);
2481 else
2483 n = 0;
2484 stdarg (XmNleftAttachment, XmATTACH_FORM);
2485 XtSetValues (XtParent (m_crosshair), args, n);
2486 XtUnmanageChild (XtParent (m_mark));
2488 last_state = this_state + 100;
2490 memcpy (&saved_mark, &Marked, sizeof (MarkType));
2492 /* This is obtuse. We want to enable XmRESIZE_ANY long enough
2493 to shrink to fit the new format (if any), then switch it
2494 back to XmRESIZE_GROW to prevent it from shrinking due to
2495 changes in the number of actual digits printed. Thus, when
2496 you switch from a small grid and %.2f formats to a large
2497 grid and %d formats, you aren't punished with a wide and
2498 mostly white-space label widget. "this_state" indicates
2499 which of the above formats we're using. "last_state" is
2500 either zero (when resizing) or the same as "this_state"
2501 (when grow-only), or a non-zero but not "this_state" which
2502 means we need to start a resize cycle. */
2503 if (this_state != last_state && last_state)
2505 n = 0;
2506 stdarg (XmNresizePolicy, XmRESIZE_ANY);
2507 XtSetValues (XtParent (m_mark), args, n);
2508 XtSetValues (XtParent (m_crosshair), args, n);
2509 last_state = 0;
2511 else if (this_state != last_state)
2513 n = 0;
2514 stdarg (XmNresizePolicy, XmRESIZE_GROW);
2515 XtSetValues (XtParent (m_mark), args, n);
2516 XtSetValues (XtParent (m_crosshair), args, n);
2517 last_state = this_state;
2523 static double old_grid = -1;
2524 static int old_gx, old_gy, old_mm;
2525 XmString ms;
2526 if (PCB->Grid != old_grid
2527 || PCB->GridOffsetX != old_gx
2528 || PCB->GridOffsetY != old_gy || Settings.grid_units_mm != old_mm)
2530 static char buf[100];
2531 double g, x, y;
2532 char *u;
2533 old_grid = PCB->Grid;
2534 old_gx = PCB->GridOffsetX;
2535 old_gy = PCB->GridOffsetY;
2536 old_mm = Settings.grid_units_mm;
2537 if (old_grid == 1)
2539 strcpy (buf, "No Grid");
2541 else
2543 if (Settings.grid_units_mm)
2545 g = PCB_TO_MM (old_grid);
2546 x = PCB_TO_MM (old_gx);
2547 y = PCB_TO_MM (old_gy);
2548 u = "mm";
2550 else
2552 g = PCB_TO_MIL (old_grid);
2553 x = PCB_TO_MIL (old_gx);
2554 y = PCB_TO_MIL (old_gy);
2555 u = "mil";
2557 if (x || y)
2558 sprintf (buf, "%g %s @%g,%g", g, u, x, y);
2559 else
2560 sprintf (buf, "%g %s", g, u);
2562 ms = XmStringCreateLocalized (buf);
2563 n = 0;
2564 stdarg (XmNlabelString, ms);
2565 XtSetValues (m_grid, args, n);
2570 static double old_zoom = -1;
2571 static int old_zoom_units = -1;
2572 if (view_zoom != old_zoom || Settings.grid_units_mm != old_zoom_units)
2574 static char buf[100];
2575 double g;
2576 const char *units;
2577 XmString ms;
2579 old_zoom = view_zoom;
2580 old_zoom_units = Settings.grid_units_mm;
2582 if (Settings.grid_units_mm)
2584 g = PCB_TO_MM (view_zoom);
2585 units = "mm";
2587 else
2589 g = PCB_TO_MIL (view_zoom);
2590 units = "mil";
2592 if ((int) (g * 100 + 0.5) == (int) (g + 0.005) * 100)
2593 sprintf (buf, "%d %s/pix", (int) (g + 0.005), units);
2594 else
2595 sprintf (buf, "%.2f %s/pix", g, units);
2596 ms = XmStringCreateLocalized (buf);
2597 n = 0;
2598 stdarg (XmNlabelString, ms);
2599 XtSetValues (m_zoom, args, n);
2604 if (old_cursor_mode != Settings.Mode)
2606 char *s = "None";
2607 XmString ms;
2608 int cursor = -1;
2609 static int free_cursor = 0;
2611 old_cursor_mode = Settings.Mode;
2612 switch (Settings.Mode)
2614 case NO_MODE:
2615 s = "None";
2616 cursor = XC_X_cursor;
2617 break;
2618 case VIA_MODE:
2619 s = "Via";
2620 cursor = -1;
2621 break;
2622 case LINE_MODE:
2623 s = "Line";
2624 cursor = XC_pencil;
2625 break;
2626 case RECTANGLE_MODE:
2627 s = "Rectangle";
2628 cursor = XC_ul_angle;
2629 break;
2630 case POLYGON_MODE:
2631 s = "Polygon";
2632 cursor = XC_sb_up_arrow;
2633 break;
2634 case POLYGONHOLE_MODE:
2635 s = "Polygon Hole";
2636 cursor = XC_sb_up_arrow;
2637 break;
2638 case PASTEBUFFER_MODE:
2639 s = "Paste";
2640 cursor = XC_hand1;
2641 break;
2642 case TEXT_MODE:
2643 s = "Text";
2644 cursor = XC_xterm;
2645 break;
2646 case ROTATE_MODE:
2647 s = "Rotate";
2648 cursor = XC_exchange;
2649 break;
2650 case REMOVE_MODE:
2651 s = "Remove";
2652 cursor = XC_pirate;
2653 break;
2654 case MOVE_MODE:
2655 s = "Move";
2656 cursor = XC_crosshair;
2657 break;
2658 case COPY_MODE:
2659 s = "Copy";
2660 cursor = XC_crosshair;
2661 break;
2662 case INSERTPOINT_MODE:
2663 s = "Insert";
2664 cursor = XC_dotbox;
2665 break;
2666 case RUBBERBANDMOVE_MODE:
2667 s = "RBMove";
2668 cursor = XC_top_left_corner;
2669 break;
2670 case THERMAL_MODE:
2671 s = "Thermal";
2672 cursor = XC_iron_cross;
2673 break;
2674 case ARC_MODE:
2675 s = "Arc";
2676 cursor = XC_question_arrow;
2677 break;
2678 case ARROW_MODE:
2679 s = "Arrow";
2680 if (over_point)
2681 cursor = XC_draped_box;
2682 else
2683 cursor = XC_left_ptr;
2684 break;
2685 case LOCK_MODE:
2686 s = "Lock";
2687 cursor = XC_hand2;
2688 break;
2690 ms = XmStringCreateLocalized (s);
2691 n = 0;
2692 stdarg (XmNlabelString, ms);
2693 XtSetValues (m_mode, args, n);
2695 if (free_cursor)
2697 XFreeCursor (display, my_cursor);
2698 free_cursor = 0;
2700 if (cursor == -1)
2702 static Pixmap nocur_source = 0;
2703 static Pixmap nocur_mask = 0;
2704 static Cursor nocursor = 0;
2705 if (nocur_source == 0)
2707 XColor fg, bg;
2708 nocur_source =
2709 XCreateBitmapFromData (display, window, "\0", 1, 1);
2710 nocur_mask =
2711 XCreateBitmapFromData (display, window, "\0", 1, 1);
2713 fg.red = fg.green = fg.blue = 65535;
2714 bg.red = bg.green = bg.blue = 0;
2715 fg.flags = bg.flags = DoRed | DoGreen | DoBlue;
2716 nocursor = XCreatePixmapCursor (display, nocur_source,
2717 nocur_mask, &fg, &bg, 0, 0);
2719 my_cursor = nocursor;
2721 else
2723 my_cursor = XCreateFontCursor (display, cursor);
2724 free_cursor = 1;
2726 XDefineCursor (display, window, my_cursor);
2727 lesstif_update_status_line ();
2731 static char *old_clip = 0;
2732 static int old_tscale = -1;
2733 char *new_clip = cur_clip ();
2735 if (new_clip != old_clip || Settings.TextScale != old_tscale)
2737 lesstif_update_status_line ();
2738 old_clip = new_clip;
2739 old_tscale = Settings.TextScale;
2744 static int old_nrats = -1;
2745 static char buf[20];
2747 if (old_nrats != PCB->Data->RatN)
2749 old_nrats = PCB->Data->RatN;
2750 sprintf(buf, "%d rat%s", PCB->Data->RatN, PCB->Data->RatN == 1 ? "" : "s");
2751 if (PCB->Data->RatN)
2753 XtManageChild(XtParent(m_rats));
2754 XtManageChild(m_rats);
2755 n = 0;
2756 stdarg (XmNleftWidget, m_rats);
2757 XtSetValues (XtParent (m_status), args, n);
2760 n = 0;
2761 stdarg (XmNlabelString, XmStringCreateLocalized (buf));
2762 XtSetValues (m_rats, args, n);
2764 if (!PCB->Data->RatN)
2766 n = 0;
2767 stdarg (XmNleftWidget, m_mode);
2768 XtSetValues (XtParent (m_status), args, n);
2769 XtUnmanageChild(XtParent(m_rats));
2774 lesstif_update_widget_flags ();
2776 show_crosshair (1);
2777 idle_proc_set = 0;
2778 return true;
2781 void
2782 lesstif_need_idle_proc ()
2784 if (idle_proc_set || window == 0)
2785 return;
2786 XtAppAddWorkProc (app_context, idle_proc, 0);
2787 idle_proc_set = 1;
2790 static void
2791 lesstif_invalidate_lr (int l, int r, int t, int b)
2793 if (!window)
2794 return;
2796 need_redraw = 1;
2797 need_idle_proc ();
2800 void
2801 lesstif_invalidate_all (void)
2803 lesstif_invalidate_lr (0, PCB->MaxWidth, 0, PCB->MaxHeight);
2806 static int
2807 lesstif_set_layer (const char *name, int group, int empty)
2809 int idx = group;
2810 if (idx >= 0 && idx < max_layer)
2812 idx = PCB->LayerGroups.Entries[idx][0];
2813 #if 0
2814 if (idx == LayerStack[0]
2815 || GetLayerGroupNumberByNumber (idx) ==
2816 GetLayerGroupNumberByNumber (LayerStack[0]))
2817 autofade = 0;
2818 else
2819 autofade = 1;
2820 #endif
2822 #if 0
2823 else
2824 autofade = 0;
2825 #endif
2826 if (idx >= 0 && idx < max_layer + 2)
2827 return pinout ? 1 : PCB->Data->Layer[idx].On;
2828 if (idx < 0)
2830 switch (SL_TYPE (idx))
2832 case SL_INVISIBLE:
2833 return pinout ? 0 : PCB->InvisibleObjectsOn;
2834 case SL_MASK:
2835 if (SL_MYSIDE (idx) && !pinout)
2836 return TEST_FLAG (SHOWMASKFLAG, PCB);
2837 return 0;
2838 case SL_SILK:
2839 if (SL_MYSIDE (idx) || pinout)
2840 return PCB->ElementOn;
2841 return 0;
2842 case SL_ASSY:
2843 return 0;
2844 case SL_UDRILL:
2845 case SL_PDRILL:
2846 return 1;
2847 case SL_RATS:
2848 return PCB->RatOn;
2851 return 0;
2854 static hidGC
2855 lesstif_make_gc (void)
2857 hidGC rv = malloc (sizeof (hid_gc_struct));
2858 memset (rv, 0, sizeof (hid_gc_struct));
2859 rv->me_pointer = &lesstif_gui;
2860 return rv;
2863 static void
2864 lesstif_destroy_gc (hidGC gc)
2866 free (gc);
2869 static void
2870 lesstif_use_mask (int use_it)
2872 static Window old;
2874 if (use_it == HID_FLUSH_DRAW_Q)
2876 XFlush (display);
2877 return;
2879 else if (use_it == HID_LIVE_DRAWING)
2881 old = pixmap;
2882 pixmap = window;
2883 return;
2885 else if (use_it == HID_LIVE_DRAWING_OFF)
2887 pixmap = old;
2888 return;
2890 if ((TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) &&
2891 !use_xrender)
2892 use_it = 0;
2893 if ((use_it == 0) == (use_mask == 0))
2894 return;
2895 use_mask = use_it;
2896 if (pinout)
2897 return;
2898 if (!window)
2899 return;
2900 /* printf("use_mask(%d)\n", use_it); */
2901 if (!mask_pixmap)
2903 mask_pixmap =
2904 XCreatePixmap (display, window, pixmap_w, pixmap_h,
2905 XDefaultDepth (display, screen));
2906 mask_bitmap = XCreatePixmap (display, window, pixmap_w, pixmap_h, 1);
2908 if (use_it)
2910 pixmap = mask_pixmap;
2911 XSetForeground (display, my_gc, 0);
2912 XSetFunction (display, my_gc, GXcopy);
2913 XFillRectangle (display, mask_pixmap, my_gc,
2914 0, 0, view_width, view_height);
2915 XFillRectangle (display, mask_bitmap, bclear_gc,
2916 0, 0, view_width, view_height);
2918 else
2920 pixmap = main_pixmap;
2921 #ifdef HAVE_XRENDER
2922 if (use_xrender)
2924 XRenderPictureAttributes pa;
2926 pa.clip_mask = mask_bitmap;
2927 XRenderChangePicture(display, main_picture, CPClipMask, &pa);
2928 XRenderComposite(display, PictOpOver, mask_picture, pale_picture,
2929 main_picture, 0, 0, 0, 0, 0, 0, view_width, view_height);
2931 else
2932 #endif /* HAVE_XRENDER */
2934 XSetClipMask (display, clip_gc, mask_bitmap);
2935 XCopyArea (display, mask_pixmap, main_pixmap, clip_gc,
2936 0, 0, view_width, view_height, 0, 0);
2941 static void
2942 lesstif_set_color (hidGC gc, const char *name)
2944 static void *cache = 0;
2945 hidval cval;
2946 static XColor color, exact_color;
2948 if (!display)
2949 return;
2950 if (!name)
2951 name = "red";
2952 gc->colorname = name;
2953 if (strcmp (name, "erase") == 0)
2955 gc->color = bgcolor;
2956 gc->erase = 1;
2958 else if (strcmp (name, "drill") == 0)
2960 gc->color = offlimit_color;
2961 gc->erase = 0;
2963 else if (hid_cache_color (0, name, &cval, &cache))
2965 gc->color = cval.lval;
2966 gc->erase = 0;
2968 else
2970 if (!XAllocNamedColor (display, colormap, name, &color, &exact_color))
2971 color.pixel = WhitePixel (display, screen);
2972 #if 0
2973 printf ("lesstif_set_color `%s' %08x rgb/%d/%d/%d\n",
2974 name, color.pixel, color.red, color.green, color.blue);
2975 #endif
2976 cval.lval = gc->color = color.pixel;
2977 hid_cache_color (1, name, &cval, &cache);
2978 gc->erase = 0;
2980 if (autofade)
2982 static int lastcolor = -1, lastfade = -1;
2983 if (gc->color == lastcolor)
2984 gc->color = lastfade;
2985 else
2987 lastcolor = gc->color;
2988 color.pixel = gc->color;
2990 XQueryColor (display, colormap, &color);
2991 color.red = (bgred + color.red) / 2;
2992 color.green = (bggreen + color.green) / 2;
2993 color.blue = (bgblue + color.blue) / 2;
2994 XAllocColor (display, colormap, &color);
2995 lastfade = gc->color = color.pixel;
3000 static void
3001 set_gc (hidGC gc)
3003 int cap, join, width;
3004 if (gc->me_pointer != &lesstif_gui)
3006 fprintf (stderr, "Fatal: GC from another HID passed to lesstif HID\n");
3007 abort ();
3009 #if 0
3010 printf ("set_gc c%s %08lx w%d c%d x%d e%d\n",
3011 gc->colorname, gc->color, gc->width, gc->cap, gc->xor, gc->erase);
3012 #endif
3013 switch (gc->cap)
3015 case Square_Cap:
3016 cap = CapProjecting;
3017 join = JoinMiter;
3018 break;
3019 case Trace_Cap:
3020 case Round_Cap:
3021 cap = CapRound;
3022 join = JoinRound;
3023 break;
3024 case Beveled_Cap:
3025 cap = CapProjecting;
3026 join = JoinBevel;
3027 break;
3028 default:
3029 cap = CapProjecting;
3030 join = JoinBevel;
3031 break;
3033 if (gc->xor)
3035 XSetFunction (display, my_gc, GXxor);
3036 XSetForeground (display, my_gc, gc->color ^ bgcolor);
3038 else if (gc->erase)
3040 XSetFunction (display, my_gc, GXcopy);
3041 XSetForeground (display, my_gc, offlimit_color);
3043 else
3045 XSetFunction (display, my_gc, GXcopy);
3046 XSetForeground (display, my_gc, gc->color);
3048 width = Vz (gc->width);
3049 if (width < 0)
3050 width = 0;
3051 XSetLineAttributes (display, my_gc, width, LineSolid, cap,
3052 join);
3053 if (use_mask)
3055 if (gc->erase)
3056 mask_gc = bclear_gc;
3057 else
3058 mask_gc = bset_gc;
3059 XSetLineAttributes (display, mask_gc, Vz (gc->width), LineSolid, cap,
3060 join);
3064 static void
3065 lesstif_set_line_cap (hidGC gc, EndCapStyle style)
3067 gc->cap = style;
3070 static void
3071 lesstif_set_line_width (hidGC gc, int width)
3073 gc->width = width;
3076 static void
3077 lesstif_set_draw_xor (hidGC gc, int xor)
3079 gc->xor = xor;
3082 static void
3083 lesstif_set_draw_faded (hidGC gc, int faded)
3085 /* We don't use this */
3088 static void
3089 lesstif_set_line_cap_angle (hidGC gc, int x1, int y1, int x2, int y2)
3091 CRASH;
3094 #define ISORT(a,b) if (a>b) { a^=b; b^=a; a^=b; }
3096 static void
3097 lesstif_draw_line (hidGC gc, int x1, int y1, int x2, int y2)
3099 double dx1, dy1, dx2, dy2;
3100 int vw = Vz (gc->width);
3101 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) && gc->erase)
3102 return;
3103 #if 0
3104 printf ("draw_line %d,%d %d,%d @%d", x1, y1, x2, y2, gc->width);
3105 #endif
3106 dx1 = Vx (x1);
3107 dy1 = Vy (y1);
3108 dx2 = Vx (x2);
3109 dy2 = Vy (y2);
3110 #if 0
3111 printf (" = %d,%d %d,%d %s\n", x1, y1, x2, y2, gc->colorname);
3112 #endif
3114 #if 1
3115 if (! ClipLine (0, 0, view_width, view_height,
3116 &dx1, &dy1, &dx2, &dy2, vw))
3117 return;
3118 #endif
3120 x1 = dx1;
3121 y1 = dy1;
3122 x2 = dx2;
3123 y2 = dy2;
3125 set_gc (gc);
3126 if (gc->cap == Square_Cap && x1 == x2 && y1 == y2)
3128 XFillRectangle (display, pixmap, my_gc, x1 - vw / 2, y1 - vw / 2, vw,
3129 vw);
3130 if (use_mask)
3131 XFillRectangle (display, mask_bitmap, mask_gc, x1 - vw / 2,
3132 y1 - vw / 2, vw, vw);
3134 else
3136 XDrawLine (display, pixmap, my_gc, x1, y1, x2, y2);
3137 if (use_mask)
3138 XDrawLine (display, mask_bitmap, mask_gc, x1, y1, x2, y2);
3142 static void
3143 lesstif_draw_arc (hidGC gc, int cx, int cy, int width, int height,
3144 int start_angle, int delta_angle)
3146 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase)
3147 return;
3148 #if 0
3149 printf ("draw_arc %d,%d %dx%d s %d d %d", cx, cy, width, height, start_angle, delta_angle);
3150 #endif
3151 width = Vz (width);
3152 height = Vz (height);
3153 cx = Vx (cx) - width;
3154 cy = Vy (cy) - height;
3155 if (flip_x)
3157 start_angle = 180 - start_angle;
3158 delta_angle = - delta_angle;
3160 if (flip_y)
3162 start_angle = - start_angle;
3163 delta_angle = - delta_angle;
3165 start_angle = (start_angle + 360 + 180) % 360 - 180;
3166 #if 0
3167 printf (" = %d,%d %dx%d %d %s\n", cx, cy, width, height, gc->width,
3168 gc->colorname);
3169 #endif
3170 set_gc (gc);
3171 XDrawArc (display, pixmap, my_gc, cx, cy,
3172 width * 2, height * 2, (start_angle + 180) * 64,
3173 delta_angle * 64);
3174 if (use_mask && !TEST_FLAG (THINDRAWFLAG, PCB))
3175 XDrawArc (display, mask_bitmap, mask_gc, cx, cy,
3176 width * 2, height * 2, (start_angle + 180) * 64,
3177 delta_angle * 64);
3178 #if 0
3179 /* Enable this if you want to see the center and radii of drawn
3180 arcs, for debugging. */
3181 if (TEST_FLAG (THINDRAWFLAG, PCB)
3182 && delta_angle != 360)
3184 cx += width;
3185 cy += height;
3186 XDrawLine (display, pixmap, arc1_gc, cx, cy,
3187 cx - width*cos(start_angle*M_PI/180),
3188 cy + width*sin(start_angle*M_PI/180));
3189 XDrawLine (display, pixmap, arc2_gc, cx, cy,
3190 cx - width*cos((start_angle+delta_angle)*M_PI/180),
3191 cy + width*sin((start_angle+delta_angle)*M_PI/180));
3193 #endif
3196 static void
3197 lesstif_draw_rect (hidGC gc, int x1, int y1, int x2, int y2)
3199 int vw = Vz (gc->width);
3200 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase)
3201 return;
3202 x1 = Vx (x1);
3203 y1 = Vy (y1);
3204 x2 = Vx (x2);
3205 y2 = Vy (y2);
3206 if (x1 < -vw && x2 < -vw)
3207 return;
3208 if (y1 < -vw && y2 < -vw)
3209 return;
3210 if (x1 > view_width + vw && x2 > view_width + vw)
3211 return;
3212 if (y1 > view_height + vw && y2 > view_height + vw)
3213 return;
3214 if (x1 > x2) { int xt = x1; x1 = x2; x2 = xt; }
3215 if (y1 > y2) { int yt = y1; y1 = y2; y2 = yt; }
3216 set_gc (gc);
3217 XDrawRectangle (display, pixmap, my_gc, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
3218 if (use_mask)
3219 XDrawRectangle (display, mask_bitmap, mask_gc, x1, y1, x2 - x1 + 1,
3220 y2 - y1 + 1);
3223 static void
3224 lesstif_fill_circle (hidGC gc, int cx, int cy, int radius)
3226 if (pinout && use_mask && gc->erase)
3227 return;
3228 if ((TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) && gc->erase)
3229 return;
3230 #if 0
3231 printf ("fill_circle %d,%d %d", cx, cy, radius);
3232 #endif
3233 radius = Vz (radius);
3234 cx = Vx (cx) - radius;
3235 cy = Vy (cy) - radius;
3236 if (cx < -2 * radius || cx > view_width)
3237 return;
3238 if (cy < -2 * radius || cy > view_height)
3239 return;
3240 #if 0
3241 printf (" = %d,%d %d %lx %s\n", cx, cy, radius, gc->color, gc->colorname);
3242 #endif
3243 set_gc (gc);
3244 XFillArc (display, pixmap, my_gc, cx, cy,
3245 radius * 2, radius * 2, 0, 360 * 64);
3246 if (use_mask)
3247 XFillArc (display, mask_bitmap, mask_gc, cx, cy,
3248 radius * 2, radius * 2, 0, 360 * 64);
3251 static void
3252 lesstif_fill_polygon (hidGC gc, int n_coords, int *x, int *y)
3254 static XPoint *p = 0;
3255 static int maxp = 0;
3256 int i;
3258 if (maxp < n_coords)
3260 maxp = n_coords + 10;
3261 if (p)
3262 p = (XPoint *) realloc (p, maxp * sizeof (XPoint));
3263 else
3264 p = (XPoint *) malloc (maxp * sizeof (XPoint));
3267 for (i = 0; i < n_coords; i++)
3269 p[i].x = Vx (x[i]);
3270 p[i].y = Vy (y[i]);
3272 #if 0
3273 printf ("fill_polygon %d pts\n", n_coords);
3274 #endif
3275 set_gc (gc);
3276 XFillPolygon (display, pixmap, my_gc, p, n_coords, Complex,
3277 CoordModeOrigin);
3278 if (use_mask)
3279 XFillPolygon (display, mask_bitmap, mask_gc, p, n_coords, Complex,
3280 CoordModeOrigin);
3283 static void
3284 lesstif_fill_rect (hidGC gc, int x1, int y1, int x2, int y2)
3286 int vw = Vz (gc->width);
3287 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase)
3288 return;
3289 x1 = Vx (x1);
3290 y1 = Vy (y1);
3291 x2 = Vx (x2);
3292 y2 = Vy (y2);
3293 if (x1 < -vw && x2 < -vw)
3294 return;
3295 if (y1 < -vw && y2 < -vw)
3296 return;
3297 if (x1 > view_width + vw && x2 > view_width + vw)
3298 return;
3299 if (y1 > view_height + vw && y2 > view_height + vw)
3300 return;
3301 if (x1 > x2) { int xt = x1; x1 = x2; x2 = xt; }
3302 if (y1 > y2) { int yt = y1; y1 = y2; y2 = yt; }
3303 set_gc (gc);
3304 XFillRectangle (display, pixmap, my_gc, x1, y1, x2 - x1 + 1,
3305 y2 - y1 + 1);
3306 if (use_mask)
3307 XFillRectangle (display, mask_bitmap, mask_gc, x1, y1, x2 - x1 + 1,
3308 y2 - y1 + 1);
3311 static void
3312 lesstif_calibrate (double xval, double yval)
3314 CRASH;
3317 static int
3318 lesstif_shift_is_pressed (void)
3320 return shift_pressed;
3323 static int
3324 lesstif_control_is_pressed (void)
3326 return ctrl_pressed;
3329 static int
3330 lesstif_mod1_is_pressed (void)
3332 return alt_pressed;
3335 extern void lesstif_get_coords (const char *msg, int *x, int *y);
3337 static void
3338 lesstif_set_crosshair (int x, int y, int action)
3340 if (crosshair_x != x || crosshair_y != y)
3342 lesstif_show_crosshair(0);
3343 crosshair_x = x;
3344 crosshair_y = y;
3345 need_idle_proc ();
3347 if (mainwind
3348 && !in_move_event
3349 && (x < view_left_x
3350 || x > view_left_x + view_width * view_zoom
3351 || y < view_top_y || y > view_top_y + view_height * view_zoom))
3353 view_left_x = x - (view_width * view_zoom) / 2;
3354 view_top_y = y - (view_height * view_zoom) / 2;
3355 lesstif_pan_fixup ();
3360 if (action == HID_SC_PAN_VIEWPORT)
3362 Window root, child;
3363 unsigned int keys_buttons;
3364 int pos_x, pos_y, root_x, root_y;
3365 XQueryPointer (display, window, &root, &child,
3366 &root_x, &root_y, &pos_x, &pos_y, &keys_buttons);
3367 if (flip_x)
3368 view_left_x = x - (view_width-pos_x) * view_zoom;
3369 else
3370 view_left_x = x - pos_x * view_zoom;
3371 if (flip_y)
3372 view_top_y = y - (view_height-pos_y) * view_zoom;
3373 else
3374 view_top_y = y - pos_y * view_zoom;
3375 lesstif_pan_fixup();
3376 action = HID_SC_WARP_POINTER;
3378 if (action == HID_SC_WARP_POINTER)
3380 in_move_event ++;
3381 XWarpPointer (display, None, window, 0, 0, 0, 0, Vx(x), Vy(y));
3382 in_move_event --;
3386 typedef struct
3388 void (*func) (hidval);
3389 hidval user_data;
3390 XtIntervalId id;
3391 } TimerStruct;
3393 static void
3394 lesstif_timer_cb (XtPointer * p, XtIntervalId * id)
3396 TimerStruct *ts = (TimerStruct *) p;
3397 ts->func (ts->user_data);
3398 free (ts);
3401 static hidval
3402 lesstif_add_timer (void (*func) (hidval user_data),
3403 unsigned long milliseconds, hidval user_data)
3405 TimerStruct *t;
3406 hidval rv;
3407 t = (TimerStruct *) malloc (sizeof (TimerStruct));
3408 rv.ptr = t;
3409 t->func = func;
3410 t->user_data = user_data;
3411 t->id = XtAppAddTimeOut (app_context, milliseconds, (XtTimerCallbackProc)lesstif_timer_cb, t);
3412 return rv;
3415 static void
3416 lesstif_stop_timer (hidval hv)
3418 TimerStruct *ts = (TimerStruct *) hv.ptr;
3419 XtRemoveTimeOut (ts->id);
3420 free (ts);
3424 typedef struct
3426 void (*func) ( hidval, int, unsigned int, hidval );
3427 hidval user_data;
3428 int fd;
3429 XtInputId id;
3431 WatchStruct;
3433 /* We need a wrapper around the hid file watch because to pass the correct flags
3435 static void
3436 lesstif_watch_cb (XtPointer client_data, int *fid, XtInputId * id)
3438 unsigned int pcb_condition = 0;
3439 struct pollfd fds;
3440 short condition;
3441 hidval x;
3442 WatchStruct *watch = (WatchStruct*)client_data;
3444 fds.fd = watch->fd;
3445 fds.events = POLLIN | POLLOUT;
3446 poll( &fds, 1, 0 );
3447 condition = fds.revents;
3449 // Should we only include those we were asked to watch?
3450 if (condition & POLLIN)
3451 pcb_condition |= PCB_WATCH_READABLE;
3452 if (condition & POLLOUT)
3453 pcb_condition |= PCB_WATCH_WRITABLE;
3454 if (condition & POLLERR)
3455 pcb_condition |= PCB_WATCH_ERROR;
3456 if (condition & POLLHUP)
3457 pcb_condition |= PCB_WATCH_HANGUP;
3459 x.ptr = (void *) watch;
3460 watch->func (x, watch->fd, pcb_condition, watch->user_data);
3462 return;
3465 hidval
3466 lesstif_watch_file (int fd, unsigned int condition, void (*func) (hidval watch, int fd, unsigned int condition, hidval user_data),
3467 hidval user_data)
3469 WatchStruct *watch = malloc (sizeof(WatchStruct));
3470 hidval ret;
3471 unsigned int xt_condition = 0;
3473 if (condition & PCB_WATCH_READABLE)
3474 xt_condition |= XtInputReadMask;
3475 if (condition & PCB_WATCH_WRITABLE)
3476 xt_condition |= XtInputWriteMask;
3477 if (condition & PCB_WATCH_ERROR)
3478 xt_condition |= XtInputExceptMask;
3479 if (condition & PCB_WATCH_HANGUP)
3480 xt_condition |= XtInputExceptMask;
3482 watch->func = func;
3483 watch->user_data = user_data;
3484 watch->fd = fd;
3485 watch->id = XtAppAddInput( app_context, fd, (XtPointer) (size_t) xt_condition, lesstif_watch_cb, watch );
3487 ret.ptr = (void *) watch;
3488 return ret;
3491 void
3492 lesstif_unwatch_file (hidval data)
3494 WatchStruct *watch = (WatchStruct*)data.ptr;
3495 XtRemoveInput( watch->id );
3496 free( watch );
3499 typedef struct
3501 XtBlockHookId id;
3502 void (*func) (hidval user_data);
3503 hidval user_data;
3504 } BlockHookStruct;
3506 static void lesstif_block_hook_cb(XtPointer user_data);
3508 static void
3509 lesstif_block_hook_cb (XtPointer user_data)
3511 BlockHookStruct *block_hook = (BlockHookStruct *)user_data;
3512 block_hook->func( block_hook->user_data );
3515 static hidval
3516 lesstif_add_block_hook (void (*func) (hidval data), hidval user_data )
3518 hidval ret;
3519 BlockHookStruct *block_hook = malloc( sizeof( BlockHookStruct ));
3521 block_hook->func = func;
3522 block_hook->user_data = user_data;
3524 block_hook->id = XtAppAddBlockHook( app_context, lesstif_block_hook_cb, (XtPointer)block_hook );
3526 ret.ptr = (void *) block_hook;
3527 return ret;
3530 static void
3531 lesstif_stop_block_hook (hidval mlpoll)
3533 BlockHookStruct *block_hook = (BlockHookStruct *)mlpoll.ptr;
3534 XtRemoveBlockHook( block_hook->id );
3535 free( block_hook );
3539 extern void lesstif_logv (const char *fmt, va_list ap);
3541 extern int lesstif_confirm_dialog (char *msg, ...);
3543 extern int lesstif_close_confirm_dialog ();
3545 extern void lesstif_report_dialog (char *title, char *msg);
3547 extern int
3548 lesstif_attribute_dialog (HID_Attribute * attrs,
3549 int n_attrs, HID_Attr_Val * results,
3550 const char * title, const char * descr);
3552 static void
3553 pinout_callback (Widget da, PinoutData * pd,
3554 XmDrawingAreaCallbackStruct * cbs)
3556 BoxType region;
3557 int save_vx, save_vy, save_vw, save_vh;
3558 int save_fx, save_fy;
3559 double save_vz;
3560 Pixmap save_px;
3561 int reason = cbs ? cbs->reason : 0;
3563 if (pd->window == 0 && reason == XmCR_RESIZE)
3564 return;
3565 if (pd->window == 0 || reason == XmCR_RESIZE)
3567 Dimension w, h;
3568 double z;
3570 n = 0;
3571 stdarg (XmNwidth, &w);
3572 stdarg (XmNheight, &h);
3573 XtGetValues (da, args, n);
3575 pd->window = XtWindow (da);
3576 pd->v_width = w;
3577 pd->v_height = h;
3578 pd->zoom = (pd->right - pd->left + 1) / (double) w;
3579 z = (pd->bottom - pd->top + 1) / (double) h;
3580 if (pd->zoom < z)
3581 pd->zoom = z;
3583 pd->x = (pd->left + pd->right) / 2 - pd->v_width * pd->zoom / 2;
3584 pd->y = (pd->top + pd->bottom) / 2 - pd->v_height * pd->zoom / 2;
3587 save_vx = view_left_x;
3588 save_vy = view_top_y;
3589 save_vz = view_zoom;
3590 save_vw = view_width;
3591 save_vh = view_height;
3592 save_fx = flip_x;
3593 save_fy = flip_y;
3594 save_px = pixmap;
3595 pinout = pd;
3596 pixmap = pd->window;
3597 view_left_x = pd->x;
3598 view_top_y = pd->y;
3599 view_zoom = pd->zoom;
3600 view_width = pd->v_width;
3601 view_height = pd->v_height;
3602 use_mask = 0;
3603 flip_x = flip_y = 0;
3605 region.X1 = 0;
3606 region.Y1 = 0;
3607 region.X2 = PCB->MaxWidth;
3608 region.Y2 = PCB->MaxHeight;
3610 XFillRectangle (display, pixmap, bg_gc, 0, 0, pd->v_width, pd->v_height);
3611 hid_expose_callback (&lesstif_gui, &region, pd->item);
3613 pinout = 0;
3614 view_left_x = save_vx;
3615 view_top_y = save_vy;
3616 view_zoom = save_vz;
3617 view_width = save_vw;
3618 view_height = save_vh;
3619 pixmap = save_px;
3620 flip_x = save_fx;
3621 flip_y = save_fy;
3624 static void
3625 pinout_unmap (Widget w, PinoutData * pd, void *v)
3627 if (pd->prev)
3628 pd->prev->next = pd->next;
3629 else
3630 pinouts = pd->next;
3631 if (pd->next)
3632 pd->next->prev = pd->prev;
3633 XtDestroyWidget (XtParent (pd->form));
3634 free (pd);
3637 static void
3638 lesstif_show_item (void *item)
3640 double scale;
3641 Widget da;
3642 BoxType *extents;
3643 PinoutData *pd;
3645 for (pd = pinouts; pd; pd = pd->next)
3646 if (pd->item == item)
3647 return;
3648 if (!mainwind)
3649 return;
3651 pd = (PinoutData *) MyCalloc (1, sizeof (PinoutData), "lesstif_show_item");
3653 pd->item = item;
3655 extents = hid_get_extents (item);
3656 pd->left = extents->X1;
3657 pd->right = extents->X2;
3658 pd->top = extents->Y1;
3659 pd->bottom = extents->Y2;
3661 if (pd->left > pd->right)
3663 free (pd);
3664 return;
3666 pd->prev = 0;
3667 pd->next = pinouts;
3668 if (pd->next)
3669 pd->next->prev = pd;
3670 pinouts = pd;
3671 pd->zoom = 0;
3673 n = 0;
3674 pd->form = XmCreateFormDialog (mainwind, "pinout", args, n);
3675 pd->window = 0;
3676 XtAddCallback (pd->form, XmNunmapCallback, (XtCallbackProc) pinout_unmap,
3677 (XtPointer) pd);
3679 scale =
3680 sqrt (200.0 * 200.0 /
3681 ((pd->right - pd->left + 1.0) * (pd->bottom - pd->top + 1.0)));
3683 n = 0;
3684 stdarg (XmNwidth, (int) (scale * (pd->right - pd->left + 1)));
3685 stdarg (XmNheight, (int) (scale * (pd->bottom - pd->top + 1)));
3686 stdarg (XmNleftAttachment, XmATTACH_FORM);
3687 stdarg (XmNrightAttachment, XmATTACH_FORM);
3688 stdarg (XmNtopAttachment, XmATTACH_FORM);
3689 stdarg (XmNbottomAttachment, XmATTACH_FORM);
3690 da = XmCreateDrawingArea (pd->form, "pinout", args, n);
3691 XtManageChild (da);
3693 XtAddCallback (da, XmNexposeCallback, (XtCallbackProc) pinout_callback,
3694 (XtPointer) pd);
3695 XtAddCallback (da, XmNresizeCallback, (XtCallbackProc) pinout_callback,
3696 (XtPointer) pd);
3698 XtManageChild (pd->form);
3699 pinout = 0;
3702 static void
3703 lesstif_beep (void)
3705 putchar (7);
3706 fflush (stdout);
3709 static int
3710 lesstif_progress (int so_far, int total, const char *message)
3712 return 0;
3715 HID lesstif_gui = {
3716 sizeof (HID),
3717 "lesstif",
3718 "LessTif - a Motif clone for X/Unix",
3719 1, /* gui */
3720 0, /* printer */
3721 0, /* exporter */
3722 1, /* poly before */
3723 0, /* poly after */
3724 0, /* poly dicer */
3726 lesstif_get_export_options,
3727 lesstif_do_export,
3728 lesstif_parse_arguments,
3729 lesstif_invalidate_lr,
3730 lesstif_invalidate_all,
3731 lesstif_set_layer,
3732 lesstif_make_gc,
3733 lesstif_destroy_gc,
3734 lesstif_use_mask,
3735 lesstif_set_color,
3736 lesstif_set_line_cap,
3737 lesstif_set_line_width,
3738 lesstif_set_draw_xor,
3739 lesstif_set_draw_faded,
3740 lesstif_set_line_cap_angle,
3741 lesstif_draw_line,
3742 lesstif_draw_arc,
3743 lesstif_draw_rect,
3744 lesstif_fill_circle,
3745 lesstif_fill_polygon,
3746 common_fill_pcb_polygon,
3747 common_thindraw_pcb_polygon,
3748 lesstif_fill_rect,
3750 lesstif_calibrate,
3751 lesstif_shift_is_pressed,
3752 lesstif_control_is_pressed,
3753 lesstif_mod1_is_pressed,
3754 lesstif_get_coords,
3755 lesstif_set_crosshair,
3756 lesstif_add_timer,
3757 lesstif_stop_timer,
3758 lesstif_watch_file,
3759 lesstif_unwatch_file,
3760 lesstif_add_block_hook,
3761 lesstif_stop_block_hook,
3763 lesstif_log,
3764 lesstif_logv,
3765 lesstif_confirm_dialog,
3766 lesstif_close_confirm_dialog,
3767 lesstif_report_dialog,
3768 lesstif_prompt_for,
3769 lesstif_fileselect,
3770 lesstif_attribute_dialog,
3771 lesstif_show_item,
3772 lesstif_beep,
3773 lesstif_progress,
3774 0, /* lesstif_drc_gui */
3775 lesstif_attributes_dialog
3778 #include "dolists.h"
3780 void
3781 hid_lesstif_init ()
3783 hid_register_hid (&lesstif_gui);
3784 #include "lesstif_lists.h"