Add support for filling / thindrawing raw polygons to the HID interface
[geda-pcb/gde.git] / src / hid / lesstif / main.c
blobd2b680b5dab37c24beebbdf6e327d92568753c2f
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 "lesstif.h"
34 #ifdef HAVE_LIBDMALLOC
35 #include <dmalloc.h>
36 #endif
38 #include <sys/poll.h>
40 RCSID ("$Id$");
42 #ifndef XtRDouble
43 #define XtRDouble "Double"
44 #endif
46 typedef struct hid_gc_struct
48 HID *me_pointer;
49 Pixel color;
50 const char *colorname;
51 int width;
52 EndCapStyle cap;
53 char xor;
54 char erase;
55 } hid_gc_struct;
57 extern HID lesstif_gui;
58 extern HID lesstif_extents;
60 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented GUI function %s\n", __FUNCTION__), abort()
62 XtAppContext app_context;
63 Widget appwidget;
64 Display *display;
65 static Window window = 0;
66 static Cursor my_cursor = 0;
67 static int old_cursor_mode = -1;
68 static int over_point = 0;
70 /* The first is the "current" pixmap. The main_ is the real one we
71 usually use, the mask_ are the ones for doing polygon masks. The
72 pixmap is the saved pixels, the bitmap is for the "erase" color.
73 We set pixmap to point to main_pixmap or mask_pixmap as needed. */
74 static Pixmap pixmap = 0;
75 static Pixmap main_pixmap = 0;
76 static Pixmap mask_pixmap = 0;
77 static Pixmap mask_bitmap = 0;
78 static int use_mask = 0;
80 static int use_xrender = 0;
81 #ifdef HAVE_XRENDER
82 static Picture main_picture;
83 static Picture mask_picture;
84 static Pixmap pale_pixmap;
85 static Picture pale_picture;
86 #endif /* HAVE_XRENDER */
88 static int pixmap_w = 0, pixmap_h = 0;
89 Screen *screen_s;
90 int screen;
91 static Colormap colormap;
92 static GC my_gc = 0, bg_gc, clip_gc = 0, bset_gc = 0, bclear_gc = 0, mask_gc =
94 static Pixel bgcolor, offlimit_color, grid_color;
95 static int bgred, bggreen, bgblue;
97 static GC arc1_gc, arc2_gc;
99 /* These are for the pinout windows. */
100 typedef struct PinoutData
102 struct PinoutData *prev, *next;
103 Widget form;
104 Window window;
105 int left, right, top, bottom; /* PCB extents of item */
106 int x, y; /* PCB coordinates of upper right corner of window */
107 double zoom; /* PCB units per screen pixel */
108 int v_width, v_height; /* pixels */
109 void *item;
110 } PinoutData;
112 /* Linked list of all pinout windows. */
113 static PinoutData *pinouts = 0;
114 /* If set, we are currently updating this pinout window. */
115 static PinoutData *pinout = 0;
117 static int crosshair_x = 0, crosshair_y = 0;
118 static int in_move_event = 0, crosshair_in_window = 1;
120 Widget work_area, messages, command, hscroll, vscroll;
121 static Widget m_mark, m_crosshair, m_grid, m_zoom, m_mode, m_status;
122 static Widget m_rats;
123 Widget lesstif_m_layer;
124 Widget m_click;
126 /* This is the size, in pixels, of the viewport. */
127 static int view_width, view_height;
128 /* This is the PCB location represented by the upper left corner of
129 the viewport. Note that PCB coordinates put 0,0 in the upper left,
130 much like X does. */
131 static int view_left_x = 0, view_top_y = 0;
132 /* Denotes PCB units per screen pixel. Larger numbers mean zooming
133 out - the largest value means you are looking at the whole
134 board. */
135 static double view_zoom = 1000, prev_view_zoom = 1000;
136 static int flip_x = 0, flip_y = 0;
137 static int autofade = 0;
139 static int
140 flag_flipx (int x)
142 return flip_x;
144 static int
145 flag_flipy (int x)
147 return flip_y;
150 HID_Flag lesstif_main_flag_list[] = {
151 {"flip_x", flag_flipx, 0},
152 {"flip_y", flag_flipy, 0}
155 REGISTER_FLAGS (lesstif_main_flag_list)
157 /* This is the size of the current PCB work area. */
158 /* Use PCB->MaxWidth, PCB->MaxHeight. */
159 /* static int pcb_width, pcb_height; */
161 static Arg args[30];
162 static int n;
163 #define stdarg(t,v) XtSetArg(args[n], t, v), n++
166 static int use_private_colormap = 0;
167 static int stdin_listen = 0;
168 static char *background_image_file = 0;
170 HID_Attribute lesstif_attribute_list[] = {
171 {"install", "Install private colormap",
172 HID_Boolean, 0, 0, {0, 0, 0}, 0, &use_private_colormap},
173 #define HA_colormap 0
175 {"listen", "Listen on standard input for actions",
176 HID_Boolean, 0, 0, {0, 0, 0}, 0, &stdin_listen},
177 #define HA_listen 1
179 {"bg-image", "Background Image",
180 HID_String, 0, 0, {0, 0, 0}, 0, &background_image_file},
181 #define HA_bg_image 1
185 REGISTER_ATTRIBUTES (lesstif_attribute_list)
187 static void lesstif_use_mask (int use_it);
188 static void zoom_to (double factor, int x, int y);
189 static void zoom_by (double factor, int x, int y);
190 static void zoom_toggle (int x, int y);
191 static void pinout_callback (Widget, PinoutData *,
192 XmDrawingAreaCallbackStruct *);
193 static void pinout_unmap (Widget, PinoutData *, void *);
194 static void Pan (int mode, int x, int y);
196 /* Px converts view->pcb, Vx converts pcb->view */
198 static inline int
199 Vx (int x)
201 int rv = (x - view_left_x) / view_zoom + 0.5;
202 if (flip_x)
203 rv = view_width - rv;
204 return rv;
207 static inline int
208 Vy (int y)
210 int rv = (y - view_top_y) / view_zoom + 0.5;
211 if (flip_y)
212 rv = view_height - rv;
213 return rv;
216 static inline int
217 Vz (int z)
219 return z / view_zoom + 0.5;
222 static inline int
223 Px (int x)
225 if (flip_x)
226 x = view_width - x;
227 return x * view_zoom + view_left_x;
230 static inline int
231 Py (int y)
233 if (flip_y)
234 y = view_height - y;
235 return y * view_zoom + view_top_y;
238 static inline int
239 Pz (int z)
241 return z * view_zoom;
244 void
245 lesstif_coords_to_pcb (int vx, int vy, int *px, int *py)
247 *px = Px (vx);
248 *py = Py (vy);
251 Pixel
252 lesstif_parse_color (char *value)
254 XColor color;
255 if (XParseColor (display, colormap, value, &color))
256 if (XAllocColor (display, colormap, &color))
257 return color.pixel;
258 return 0;
261 static void
262 do_color (char *value, char *which)
264 XColor color;
265 if (XParseColor (display, colormap, value, &color))
266 if (XAllocColor (display, colormap, &color))
268 stdarg (which, color.pixel);
272 /* ------------------------------------------------------------ */
274 static char *
275 cur_clip ()
277 if (TEST_FLAG (ORTHOMOVEFLAG, PCB))
278 return "+";
279 if (TEST_FLAG (ALLDIRECTIONFLAG, PCB))
280 return "*";
281 if (PCB->Clipping == 0)
282 return "X";
283 if (PCB->Clipping == 1)
284 return "_/";
285 return "\\_";
288 /* Called from the core when it's busy doing something and we need to
289 indicate that to the user. */
290 static int
291 Busy(int argc, char **argv, int x, int y)
293 static Cursor busy_cursor = 0;
294 if (busy_cursor == 0)
295 busy_cursor = XCreateFontCursor (display, XC_watch);
296 XDefineCursor (display, window, busy_cursor);
297 XFlush(display);
298 old_cursor_mode = -1;
299 return 0;
302 /* ---------------------------------------------------------------------- */
304 /* Local actions. */
306 static int
307 PointCursor (int argc, char **argv, int x, int y)
309 if (argc > 0)
310 over_point = 1;
311 else
312 over_point = 0;
313 old_cursor_mode = -1;
314 return 0;
317 static int
318 PCBChanged (int argc, char **argv, int x, int y)
320 if (work_area == 0)
321 return 0;
322 /*printf("PCB Changed! %d x %d\n", PCB->MaxWidth, PCB->MaxHeight); */
323 n = 0;
324 stdarg (XmNminimum, 0);
325 stdarg (XmNvalue, 0);
326 stdarg (XmNsliderSize, PCB->MaxWidth ? PCB->MaxWidth : 1);
327 stdarg (XmNmaximum, PCB->MaxWidth ? PCB->MaxWidth : 1);
328 XtSetValues (hscroll, args, n);
329 n = 0;
330 stdarg (XmNminimum, 0);
331 stdarg (XmNvalue, 0);
332 stdarg (XmNsliderSize, PCB->MaxHeight ? PCB->MaxHeight : 1);
333 stdarg (XmNmaximum, PCB->MaxHeight ? PCB->MaxHeight : 1);
334 XtSetValues (vscroll, args, n);
335 zoom_by (1000000, 0, 0);
337 hid_action ("NetlistChanged");
338 hid_action ("LayersChanged");
339 hid_action ("RouteStylesChanged");
340 lesstif_sizes_reset ();
341 lesstif_update_layer_groups ();
342 while (pinouts)
343 pinout_unmap (0, pinouts, 0);
344 if (PCB->Filename)
346 char *cp = strrchr (PCB->Filename, '/');
347 n = 0;
348 stdarg (XmNtitle, cp ? cp + 1 : PCB->Filename);
349 XtSetValues (appwidget, args, n);
351 return 0;
355 static const char setunits_syntax[] =
356 "SetUnits(mm|mil)";
358 static const char setunits_help[] =
359 "Set the default measurement units.";
361 /* %start-doc actions SetUnits
363 @table @code
365 @item mil
366 Sets the display units to mils (1/1000 inch).
368 @item mm
369 Sets the display units to millimeters.
371 @end table
373 %end-doc */
375 static int
376 SetUnits (int argc, char **argv, int x, int y)
378 if (argc == 0)
379 return 0;
380 if (strcmp (argv[0], "mil") == 0)
381 Settings.grid_units_mm = 0;
382 if (strcmp (argv[0], "mm") == 0)
383 Settings.grid_units_mm = 1;
384 lesstif_sizes_reset ();
385 lesstif_styles_update_values ();
386 return 0;
389 static const char zoom_syntax[] =
390 "Zoom()\n"
391 "Zoom(factor)";
393 static const char zoom_help[] =
394 "Various zoom factor changes.";
396 /* %start-doc actions Zoom
398 Changes the zoom (magnification) of the view of the board. If no
399 arguments are passed, the view is scaled such that the board just fits
400 inside the visible window (i.e. ``view all''). Otherwise,
401 @var{factor} specifies a change in zoom factor. It may be prefixed by
402 @code{+}, @code{-}, or @code{=} to change how the zoom factor is
403 modified. The @var{factor} is a floating point number, such as
404 @code{1.5} or @code{0.75}.
406 @table @code
408 @item +@var{factor}
409 Values greater than 1.0 cause the board to be drawn smaller; more of
410 the board will be visible. Values between 0.0 and 1.0 cause the board
411 to be drawn bigger; less of the board will be visible.
413 @item -@var{factor}
414 Values greater than 1.0 cause the board to be drawn bigger; less of
415 the board will be visible. Values between 0.0 and 1.0 cause the board
416 to be drawn smaller; more of the board will be visible.
418 @item =@var{factor}
420 The @var{factor} is an absolute zoom factor; the unit for this value
421 is "PCB units per screen pixel". Since PCB units are 0.01 mil, a
422 @var{factor} of 1000 means 10 mils (0.01 in) per pixel, or 100 DPI,
423 about the actual resolution of most screens - resulting in an "actual
424 size" board. Similarly, a @var{factor} of 100 gives you a 10x actual
425 size.
427 @end table
429 Note that zoom factors of zero are silently ignored.
431 %end-doc */
433 static int
434 ZoomAction (int argc, char **argv, int x, int y)
436 const char *vp;
437 double v;
438 if (x == 0 && y == 0)
440 x = view_width / 2;
441 y = view_height / 2;
443 else
445 x = Vx (x);
446 y = Vy (y);
448 if (argc < 1)
450 zoom_to (1000000, 0, 0);
451 return 0;
453 vp = argv[0];
454 if (strcasecmp (vp, "toggle") == 0)
456 zoom_toggle (x, y);
457 return 0;
459 if (*vp == '+' || *vp == '-' || *vp == '=')
460 vp++;
461 v = strtod (vp, 0);
462 if (v <= 0)
463 return 1;
464 switch (argv[0][0])
466 case '-':
467 zoom_by (1 / v, x, y);
468 break;
469 default:
470 case '+':
471 zoom_by (v, x, y);
472 break;
473 case '=':
474 zoom_to (v, x, y);
475 break;
477 return 0;
480 static int pan_thumb_mode;
482 static int
483 PanAction (int argc, char **argv, int x, int y)
485 int mode;
487 if (argc == 2)
489 pan_thumb_mode = (strcasecmp (argv[0], "thumb") == 0) ? 1 : 0;
490 mode = atoi (argv[1]);
492 else
494 pan_thumb_mode = 0;
495 mode = atoi (argv[0]);
497 Pan (mode, Vx(x), Vy(y));
499 return 0;
502 static const char swapsides_syntax[] =
503 "SwapSides(|v|h|r)";
505 static const char swapsides_help[] =
506 "Swaps the side of the board you're looking at.";
508 /* %start-doc actions SwapSides
510 This action changes the way you view the board.
512 @table @code
514 @item v
515 Flips the board over vertically (up/down).
517 @item h
518 Flips the board over horizontally (left/right), like flipping pages in
519 a book.
521 @item r
522 Rotates the board 180 degrees without changing sides.
524 @end table
526 If no argument is given, the board isn't moved but the opposite side
527 is shown.
529 Normally, this action changes which pads and silk layer are drawn as
530 true silk, and which are drawn as the "invisible" layer. It also
531 determines which solder mask you see.
533 As a special case, if the layer group for the side you're looking at
534 is visible and currently active, and the layer group for the opposite
535 is not visible (i.e. disabled), then this action will also swap which
536 layer group is visible and active, effectively swapping the ``working
537 side'' of the board.
539 %end-doc */
541 static int
542 SwapSides (int argc, char **argv, int x, int y)
544 int old_shown_side = Settings.ShowSolderSide;
545 int comp_group = GetLayerGroupNumberByNumber (max_layer + COMPONENT_LAYER);
546 int solder_group = GetLayerGroupNumberByNumber (max_layer + SOLDER_LAYER);
547 int active_group = GetLayerGroupNumberByNumber (LayerStack[0]);
548 int comp_showing =
549 PCB->Data->Layer[PCB->LayerGroups.Entries[comp_group][0]].On;
550 int solder_showing =
551 PCB->Data->Layer[PCB->LayerGroups.Entries[solder_group][0]].On;
553 if (argc > 0)
555 switch (argv[0][0]) {
556 case 'h':
557 case 'H':
558 flip_x = ! flip_x;
559 break;
560 case 'v':
561 case 'V':
562 flip_y = ! flip_y;
563 break;
564 case 'r':
565 case 'R':
566 flip_x = ! flip_x;
567 flip_y = ! flip_y;
568 break;
569 default:
570 return 1;
572 /* SwapSides will swap this */
573 Settings.ShowSolderSide = (flip_x == flip_y);
576 n = 0;
577 if (flip_x)
578 stdarg (XmNprocessingDirection, XmMAX_ON_LEFT);
579 else
580 stdarg (XmNprocessingDirection, XmMAX_ON_RIGHT);
581 XtSetValues (hscroll, args, n);
583 n = 0;
584 if (flip_y)
585 stdarg (XmNprocessingDirection, XmMAX_ON_TOP);
586 else
587 stdarg (XmNprocessingDirection, XmMAX_ON_BOTTOM);
588 XtSetValues (vscroll, args, n);
590 Settings.ShowSolderSide = !Settings.ShowSolderSide;
592 /* The idea is that if we're looking at the front side and the front
593 layer is active (or visa versa), switching sides should switch
594 layers too. We used to only do this if the other layer wasn't
595 shown, but we now do it always. Change it back if users get
596 confused. */
597 if (Settings.ShowSolderSide != old_shown_side)
599 if (Settings.ShowSolderSide)
601 if (active_group == comp_group)
603 if (comp_showing && !solder_showing)
604 ChangeGroupVisibility (PCB->LayerGroups.Entries[comp_group][0], 0,
606 ChangeGroupVisibility (PCB->LayerGroups.Entries[solder_group][0], 1,
610 else
612 if (active_group == solder_group)
614 if (solder_showing && !comp_showing)
615 ChangeGroupVisibility (PCB->LayerGroups.Entries[solder_group][0], 0,
617 ChangeGroupVisibility (PCB->LayerGroups.Entries[comp_group][0], 1,
622 lesstif_invalidate_all ();
623 return 0;
626 static Widget m_cmd = 0, m_cmd_label;
628 static void
629 command_parse (char *s)
631 int n = 0, ws = 1;
632 char *cp;
633 char **argv;
635 for (cp = s; *cp; cp++)
637 if (isspace ((int) *cp))
638 ws = 1;
639 else
641 n += ws;
642 ws = 0;
645 argv = (char **) malloc ((n + 1) * sizeof (char *));
647 n = 0;
648 ws = 1;
649 for (cp = s; *cp; cp++)
651 if (isspace ((int) *cp))
653 ws = 1;
654 *cp = 0;
656 else
658 if (ws)
659 argv[n++] = cp;
660 ws = 0;
663 if (n == 0)
664 return;
665 argv[n] = 0;
666 lesstif_call_action (argv[0], n - 1, argv + 1);
669 static void
670 command_callback (Widget w, XtPointer uptr, XmTextVerifyCallbackStruct * cbs)
672 char *s;
673 switch (cbs->reason)
675 case XmCR_ACTIVATE:
676 s = XmTextGetString (w);
677 lesstif_show_crosshair (0);
678 if (strchr (s, '('))
679 hid_parse_actions (s, lesstif_call_action);
680 else
681 command_parse (s);
682 XtFree (s);
683 XmTextSetString (w, "");
684 case XmCR_LOSING_FOCUS:
685 XtUnmanageChild (m_cmd);
686 XtUnmanageChild (m_cmd_label);
687 break;
691 static void
692 command_event_handler (Widget w, XtPointer p, XEvent * e, Boolean * cont)
694 char buf[10];
695 KeySym sym;
696 int slen;
698 switch (e->type)
700 case KeyPress:
701 slen = XLookupString ((XKeyEvent *)e, buf, sizeof (buf), &sym, NULL);
702 switch (sym)
704 case XK_Escape:
705 XtUnmanageChild (m_cmd);
706 XtUnmanageChild (m_cmd_label);
707 XmTextSetString (w, "");
708 *cont = False;
709 break;
711 break;
715 static const char command_syntax[] =
716 "Command()";
718 static const char command_help[] =
719 "Displays the command line input window.";
721 /* %start-doc actions Command
723 The command window allows the user to manually enter actions to be
724 executed. Action syntax can be done one of two ways:
726 @table @code
728 @item
729 Follow the action name by an open parenthesis, arguments separated by
730 commas, end with a close parenthesis. Example: @code{Abc(1,2,3)}
732 @item
733 Separate the action name and arguments by spaces. Example: @code{Abc
734 1 2 3}.
736 @end table
738 The first option allows you to have arguments with spaces in them,
739 but the second is more ``natural'' to type for most people.
741 Note that action names are not case sensitive, but arguments normally
742 are. However, most actions will check for ``keywords'' in a case
743 insensitive way.
745 There are three ways to finish with the command window. If you press
746 the @code{Enter} key, the command is invoked, the window goes away,
747 and the next time you bring up the command window it's empty. If you
748 press the @code{Esc} key, the window goes away without invoking
749 anything, and the next time you bring up the command window it's
750 empty. If you change focus away from the command window (i.e. click
751 on some other window), the command window goes away but the next time
752 you bring it up it resumes entering the command you were entering
753 before.
755 %end-doc */
757 static int
758 Command (int argc, char **argv, int x, int y)
760 XtManageChild (m_cmd_label);
761 XtManageChild (m_cmd);
762 XmProcessTraversal (m_cmd, XmTRAVERSE_CURRENT);
763 return 0;
766 static const char benchmark_syntax[] =
767 "Benchmark()";
769 static const char benchmark_help[] =
770 "Benchmark the GUI speed.";
772 /* %start-doc actions Benchmark
774 This action is used to speed-test the Lesstif graphics subsystem. It
775 redraws the current screen as many times as possible in ten seconds.
776 It reports the amount of time needed to draw the screen once.
778 %end-doc */
780 static int
781 Benchmark (int argc, char **argv, int x, int y)
783 int i = 0;
784 time_t start, end;
785 BoxType region;
786 Drawable save_main;
788 save_main = main_pixmap;
789 main_pixmap = window;
791 region.X1 = 0;
792 region.Y1 = 0;
793 region.X2 = PCB->MaxWidth;
794 region.Y2 = PCB->MaxHeight;
796 pixmap = window;
797 XSync (display, 0);
798 time (&start);
801 XFillRectangle (display, pixmap, bg_gc, 0, 0, view_width, view_height);
802 hid_expose_callback (&lesstif_gui, &region, 0);
803 XSync (display, 0);
804 time (&end);
805 i++;
807 while (end - start < 10);
809 printf ("%g redraws per second\n", i / 10.0);
811 main_pixmap = save_main;
812 return 0;
815 static int
816 Center(int argc, char **argv, int x, int y)
818 x = GRIDFIT_X (x, PCB->Grid);
819 y = GRIDFIT_Y (y, PCB->Grid);
820 view_left_x = x - (view_width * view_zoom) / 2;
821 view_top_y = y - (view_height * view_zoom) / 2;
822 lesstif_pan_fixup ();
823 /* Move the pointer to the center of the window, but only if it's
824 currently within the window already. Watch out for edges,
825 though. */
826 XWarpPointer (display, window, window, 0, 0, view_width, view_height,
827 Vx(x), Vy(y));
828 return 0;
831 static const char cursor_syntax[] =
832 "Cursor(Type,DeltaUp,DeltaRight,Units)";
834 static const char cursor_help[] =
835 "Move the cursor.";
837 /* %start-doc actions Cursor
839 This action moves the mouse cursor. Unlike other actions which take
840 coordinates, this action's coordinates are always relative to the
841 user's view of the board. Thus, a positive @var{DeltaUp} may move the
842 cursor towards the board origin if the board is inverted.
844 Type is one of @samp{Pan} or @samp{Warp}. @samp{Pan} causes the
845 viewport to move such that the crosshair is under the mouse cursor.
846 @samp{Warp} causes the mouse cursor to move to be above the crosshair.
848 @var{Units} can be one of the following:
850 @table @samp
852 @item mil
853 @itemx mm
854 The cursor is moved by that amount, in board units.
856 @item grid
857 The cursor is moved by that many grid points.
859 @item view
860 The values are percentages of the viewport's view. Thus, a pan of
861 @samp{100} would scroll the viewport by exactly the width of the
862 current view.
864 @item board
865 The values are percentages of the board size. Thus, a move of
866 @samp{50,50} moves you halfway across the board.
868 @end table
870 %end-doc */
872 static int
873 CursorAction(int argc, char **argv, int x, int y)
875 int pan_warp = HID_SC_DO_NOTHING;
876 double dx, dy, xu, yu;
878 if (argc != 4)
879 AFAIL(cursor);
881 if (strcasecmp (argv[0], "pan") == 0)
882 pan_warp = HID_SC_PAN_VIEWPORT;
883 else if (strcasecmp (argv[0], "warp") == 0)
884 pan_warp = HID_SC_WARP_POINTER;
885 else
886 AFAIL(cursor);
888 dx = strtod (argv[1], 0);
889 if (flip_x)
890 dx = -dx;
891 dy = strtod (argv[2], 0);
892 if (!flip_y)
893 dy = -dy;
895 if (strncasecmp (argv[3], "mm", 2) == 0)
896 xu = yu = MM_TO_COOR;
897 else if (strncasecmp (argv[3], "mil", 3) == 0)
898 xu = yu = 100;
899 else if (strncasecmp (argv[3], "grid", 4) == 0)
900 xu = yu = PCB->Grid;
901 else if (strncasecmp (argv[3], "view", 4) == 0)
903 xu = Pz(view_width) / 100.0;
904 yu = Pz(view_height) / 100.0;
906 else if (strncasecmp (argv[3], "board", 4) == 0)
908 xu = PCB->MaxWidth / 100.0;
909 yu = PCB->MaxHeight / 100.0;
911 else
912 xu = yu = 100;
914 EventMoveCrosshair (Crosshair.X+(int)(dx*xu), Crosshair.Y+(int)(dy*yu));
915 gui->set_crosshair (Crosshair.X, Crosshair.Y, pan_warp);
917 return 0;
920 HID_Action lesstif_main_action_list[] = {
921 {"PCBChanged", 0, PCBChanged,
922 pcbchanged_help, pcbchanged_syntax},
923 {"SetUnits", 0, SetUnits,
924 setunits_help, setunits_syntax},
925 {"Zoom", 0, ZoomAction,
926 zoom_help, zoom_syntax},
927 {"Pan", 0, PanAction,
928 zoom_help, zoom_syntax},
929 {"SwapSides", 0, SwapSides,
930 swapsides_help, swapsides_syntax},
931 {"Command", 0, Command,
932 command_help, command_syntax},
933 {"Benchmark", 0, Benchmark,
934 benchmark_help, benchmark_syntax},
935 {"PointCursor", 0, PointCursor},
936 {"Center", "Click on a location to center", Center},
937 {"Busy", 0, Busy},
938 {"Cursor", 0, CursorAction,
939 cursor_help, cursor_syntax},
942 REGISTER_ACTIONS (lesstif_main_action_list)
945 /* ----------------------------------------------------------------------
946 * redraws the background image
949 static int bg_w, bg_h, bgi_w, bgi_h;
950 static Pixel **bg = 0;
951 static XImage *bgi = 0;
952 static enum {
953 PT_unknown,
954 PT_RGB565,
955 PT_RGB888
956 } pixel_type = PT_unknown;
958 static void
959 LoadBackgroundFile (FILE *f, char *filename)
961 XVisualInfo vinfot, *vinfo;
962 Visual *vis;
963 int c, r, b;
964 int i, nret;
965 int p[3], rows, cols, maxval;
967 if (fgetc(f) != 'P')
969 printf("bgimage: %s signature not P6\n", filename);
970 return;
972 if (fgetc(f) != '6')
974 printf("bgimage: %s signature not P6\n", filename);
975 return;
977 for (i=0; i<3; i++)
979 do {
980 b = fgetc(f);
981 if (feof(f))
982 return;
983 if (b == '#')
984 while (!feof(f) && b != '\n')
985 b = fgetc(f);
986 } while (!isdigit(b));
987 p[i] = b - '0';
988 while (isdigit(b = fgetc(f)))
989 p[i] = p[i]*10 + b - '0';
991 bg_w = cols = p[0];
992 bg_h = rows = p[1];
993 maxval = p[2];
995 setbuf(stdout, 0);
996 bg = (Pixel **) malloc (rows * sizeof (Pixel *));
997 if (!bg)
999 printf("Out of memory loading %s\n", filename);
1000 return;
1002 for (i=0; i<rows; i++)
1004 bg[i] = (Pixel *) malloc (cols * sizeof (Pixel));
1005 if (!bg[i])
1007 printf("Out of memory loading %s\n", filename);
1008 while (--i >= 0)
1009 free (bg[i]);
1010 free (bg);
1011 bg = 0;
1012 return;
1016 vis = DefaultVisual (display, DefaultScreen(display));
1018 vinfot.visualid = XVisualIDFromVisual(vis);
1019 vinfo = XGetVisualInfo (display, VisualIDMask, &vinfot, &nret);
1021 #if 0
1022 /* If you want to support more visuals below, you'll probably need
1023 this. */
1024 printf("vinfo: rm %04x gm %04x bm %04x depth %d class %d\n",
1025 vinfo->red_mask, vinfo->green_mask, vinfo->blue_mask,
1026 vinfo->depth, vinfo->class);
1027 #endif
1029 if (vinfo->class == TrueColor
1030 && vinfo->depth == 16
1031 && vinfo->red_mask == 0xf800
1032 && vinfo->green_mask == 0x07e0
1033 && vinfo->blue_mask == 0x001f)
1034 pixel_type = PT_RGB565;
1036 if (vinfo->class == TrueColor
1037 && vinfo->depth == 24
1038 && vinfo->red_mask == 0xff0000
1039 && vinfo->green_mask == 0x00ff00
1040 && vinfo->blue_mask == 0x0000ff)
1041 pixel_type = PT_RGB888;
1043 for (r=0; r<rows; r++)
1045 for (c=0; c<cols; c++)
1047 XColor pix;
1048 unsigned int pr = (unsigned)fgetc(f);
1049 unsigned int pg = (unsigned)fgetc(f);
1050 unsigned int pb = (unsigned)fgetc(f);
1052 switch (pixel_type)
1054 case PT_unknown:
1055 pix.red = pr * 65535 / maxval;
1056 pix.green = pg * 65535 / maxval;
1057 pix.blue = pb * 65535 / maxval;
1058 pix.flags = DoRed | DoGreen | DoBlue;
1059 XAllocColor (display, colormap, &pix);
1060 bg[r][c] = pix.pixel;
1061 break;
1062 case PT_RGB565:
1063 bg[r][c] = (pr>>3)<<11 | (pg>>2)<<5 | (pb>>3);
1064 break;
1065 case PT_RGB888:
1066 bg[r][c] = (pr << 16) | (pg << 8) | (pb);
1067 break;
1073 void
1074 LoadBackgroundImage (char *filename)
1076 FILE *f = fopen(filename, "rb");
1077 if (!f)
1079 if (NSTRCMP (filename, "pcb-background.ppm"))
1080 perror(filename);
1081 return;
1083 LoadBackgroundFile (f, filename);
1084 fclose(f);
1087 static void
1088 DrawBackgroundImage ()
1090 int x, y, w, h;
1091 double xscale, yscale;
1092 int pcbwidth = PCB->MaxWidth / view_zoom;
1093 int pcbheight = PCB->MaxHeight / view_zoom;
1095 if (!window || !bg)
1096 return;
1098 if (!bgi || view_width != bgi_w || view_height != bgi_h)
1100 if (bgi)
1101 XDestroyImage (bgi);
1102 /* Cheat - get the image, which sets up the format too. */
1103 bgi = XGetImage (XtDisplay(work_area),
1104 window,
1105 0, 0, view_width, view_height,
1106 -1, ZPixmap);
1107 bgi_w = view_width;
1108 bgi_h = view_height;
1111 w = MIN (view_width, pcbwidth);
1112 h = MIN (view_height, pcbheight);
1114 xscale = (double)bg_w / PCB->MaxWidth;
1115 yscale = (double)bg_h / PCB->MaxHeight;
1117 for (y=0; y<h; y++)
1119 int pr = Py(y);
1120 int ir = pr * yscale;
1121 for (x=0; x<w; x++)
1123 int pc = Px(x);
1124 int ic = pc * xscale;
1125 XPutPixel (bgi, x, y, bg[ir][ic]);
1128 XPutImage(display, main_pixmap, bg_gc,
1129 bgi,
1130 0, 0, 0, 0, w, h);
1132 /* ---------------------------------------------------------------------- */
1134 static HID_Attribute *
1135 lesstif_get_export_options (int *n)
1137 return 0;
1140 static void
1141 set_scroll (Widget s, int pos, int view, int pcb)
1143 int sz = view * view_zoom;
1144 if (sz > pcb)
1145 sz = pcb;
1146 n = 0;
1147 stdarg (XmNvalue, pos);
1148 stdarg (XmNsliderSize, sz);
1149 stdarg (XmNincrement, view_zoom);
1150 stdarg (XmNpageIncrement, sz);
1151 stdarg (XmNmaximum, pcb);
1152 XtSetValues (s, args, n);
1155 void
1156 lesstif_pan_fixup ()
1158 if (view_left_x > PCB->MaxWidth - (view_width * view_zoom))
1159 view_left_x = PCB->MaxWidth - (view_width * view_zoom);
1160 if (view_top_y > PCB->MaxHeight - (view_height * view_zoom))
1161 view_top_y = PCB->MaxHeight - (view_height * view_zoom);
1162 if (view_left_x < 0)
1163 view_left_x = 0;
1164 if (view_top_y < 0)
1165 view_top_y = 0;
1166 if (view_width * view_zoom > PCB->MaxWidth
1167 && view_height * view_zoom > PCB->MaxHeight)
1169 zoom_by (1, 0, 0);
1170 return;
1173 set_scroll (hscroll, view_left_x, view_width, PCB->MaxWidth);
1174 set_scroll (vscroll, view_top_y, view_height, PCB->MaxHeight);
1176 lesstif_invalidate_all ();
1179 static void
1180 zoom_to (double new_zoom, int x, int y)
1182 double max_zoom, xfrac, yfrac;
1183 int cx, cy;
1185 xfrac = (double) x / (double) view_width;
1186 yfrac = (double) y / (double) view_height;
1188 if (flip_x)
1189 xfrac = 1-xfrac;
1190 if (flip_y)
1191 yfrac = 1-yfrac;
1193 max_zoom = PCB->MaxWidth / view_width;
1194 if (max_zoom < PCB->MaxHeight / view_height)
1195 max_zoom = PCB->MaxHeight / view_height;
1197 if (new_zoom < 1)
1198 new_zoom = 1;
1199 if (new_zoom > max_zoom)
1200 new_zoom = max_zoom;
1202 cx = view_left_x + view_width * xfrac * view_zoom;
1203 cy = view_top_y + view_height * yfrac * view_zoom;
1205 if (view_zoom != new_zoom)
1207 view_zoom = new_zoom;
1208 pixel_slop = view_zoom;
1210 view_left_x = cx - view_width * xfrac * view_zoom;
1211 view_top_y = cy - view_height * yfrac * view_zoom;
1213 lesstif_pan_fixup ();
1216 static void
1217 zoom_toggle(int x, int y)
1219 double tmp;
1221 tmp = prev_view_zoom;
1222 prev_view_zoom = view_zoom;
1223 zoom_to(tmp, x, y);
1226 void
1227 zoom_by (double factor, int x, int y)
1229 zoom_to (view_zoom * factor, x, y);
1232 static int panning = 0;
1233 static int shift_pressed;
1234 static int ctrl_pressed;
1235 static int alt_pressed;
1237 /* X and Y are in screen coordinates. */
1238 static void
1239 Pan (int mode, int x, int y)
1241 static int ox, oy;
1242 static int opx, opy;
1244 panning = mode;
1245 /* This is for ctrl-pan, where the viewport's position is directly
1246 proportional to the cursor position in the window (like the Xaw
1247 thumb panner) */
1248 if (pan_thumb_mode)
1250 opx = x * PCB->MaxWidth / view_width;
1251 opy = y * PCB->MaxHeight / view_height;
1252 if (flip_x)
1253 opx = PCB->MaxWidth - opx;
1254 if (flip_y)
1255 opy = PCB->MaxHeight - opy;
1256 view_left_x = opx - view_width / 2 * view_zoom;
1257 view_top_y = opy - view_height / 2 * view_zoom;
1258 lesstif_pan_fixup ();
1260 /* This is the start of a regular pan. On the first click, we
1261 remember the coordinates where we "grabbed" the screen. */
1262 else if (mode == 1)
1264 ox = x;
1265 oy = y;
1266 opx = view_left_x;
1267 opy = view_top_y;
1269 /* continued drag, we calculate how far we've moved the cursor and
1270 set the position accordingly. */
1271 else
1273 if (flip_x)
1274 view_left_x = opx + (x - ox) * view_zoom;
1275 else
1276 view_left_x = opx - (x - ox) * view_zoom;
1277 if (flip_y)
1278 view_top_y = opy + (y - oy) * view_zoom;
1279 else
1280 view_top_y = opy - (y - oy) * view_zoom;
1281 lesstif_pan_fixup ();
1285 static void
1286 mod_changed (XKeyEvent * e, int set)
1288 switch (XKeycodeToKeysym (display, e->keycode, 0))
1290 case XK_Shift_L:
1291 case XK_Shift_R:
1292 shift_pressed = set;
1293 break;
1294 case XK_Control_L:
1295 case XK_Control_R:
1296 ctrl_pressed = set;
1297 break;
1298 default:
1299 return;
1301 in_move_event = 1;
1302 HideCrosshair (1);
1303 if (panning)
1304 Pan (2, e->x, e->y);
1305 EventMoveCrosshair (Px (e->x), Py (e->y));
1306 AdjustAttachedObjects ();
1307 RestoreCrosshair (1);
1308 in_move_event = 0;
1311 #define M_Release 8
1312 #define MAX_MOUSE_BUTTON 5
1313 Resource *mouse_actions[MAX_MOUSE_BUTTON+2][16];
1315 static void
1316 do_mouse_action (int button, int rel_mask)
1318 int i;
1319 int mods = (shift_pressed ? M_Shift : 0)
1320 + (ctrl_pressed ? M_Ctrl : 0)
1321 + (alt_pressed ? M_Alt : 0)
1322 + rel_mask;
1323 Resource *node = mouse_actions[button][mods];
1325 if (!node)
1326 return;
1328 for (i = 0; i < node->c; i++)
1329 if (node->v[i].value)
1330 if (hid_parse_actions (node->v[i].value, lesstif_call_action))
1331 return;
1334 static void
1335 work_area_input (Widget w, XtPointer v, XEvent * e, Boolean * ctd)
1337 static int pressed_button = 0;
1338 static int ignore_release = 0;
1340 show_crosshair (0);
1341 switch (e->type)
1343 case KeyPress:
1344 mod_changed (&(e->xkey), 1);
1345 if (lesstif_key_event (&(e->xkey)))
1346 return;
1347 break;
1349 case KeyRelease:
1350 mod_changed (&(e->xkey), 0);
1351 break;
1353 case ButtonPress:
1354 if (pressed_button)
1355 return;
1356 /*printf("click %d\n", e->xbutton.button); */
1357 if (lesstif_button_event (w, e))
1359 ignore_release = 1;
1360 return;
1362 ignore_release = 0;
1364 HideCrosshair (True);
1365 pressed_button = e->xbutton.button;
1366 shift_pressed = (e->xbutton.state & ShiftMask);
1367 ctrl_pressed = (e->xbutton.state & ControlMask);
1368 alt_pressed = (e->xbutton.state & Mod1Mask);
1370 do_mouse_action(e->xbutton.button, 0);
1371 RestoreCrosshair (True);
1372 break;
1374 case ButtonRelease:
1375 if (e->xbutton.button != pressed_button)
1376 return;
1377 lesstif_button_event (w, e);
1378 HideCrosshair (True);
1379 pressed_button = 0;
1380 do_mouse_action (e->xbutton.button, M_Release);
1381 RestoreCrosshair (True);
1382 break;
1384 case MotionNotify:
1386 Window root, child;
1387 unsigned int keys_buttons;
1388 int root_x, root_y, pos_x, pos_y;
1389 while (XCheckMaskEvent (display, PointerMotionMask, e));
1390 XQueryPointer (display, e->xmotion.window, &root, &child,
1391 &root_x, &root_y, &pos_x, &pos_y, &keys_buttons);
1392 shift_pressed = (keys_buttons & ShiftMask);
1393 ctrl_pressed = (keys_buttons & ControlMask);
1394 /*printf("m %d %d\n", Px(e->xmotion.x), Py(e->xmotion.y)); */
1395 crosshair_in_window = 1;
1396 in_move_event = 1;
1397 if (panning)
1398 Pan (2, pos_x, pos_y);
1399 EventMoveCrosshair (Px (pos_x), Py (pos_y));
1400 in_move_event = 0;
1402 break;
1404 case LeaveNotify:
1405 crosshair_in_window = 0;
1406 CrosshairOff (1);
1407 need_idle_proc ();
1408 break;
1410 case EnterNotify:
1411 crosshair_in_window = 1;
1412 in_move_event = 1;
1413 EventMoveCrosshair (Px (e->xcrossing.x), Py (e->xcrossing.y));
1414 CrosshairOn (1);
1415 in_move_event = 0;
1416 need_idle_proc ();
1417 break;
1419 default:
1420 printf ("work_area: unknown event %d\n", e->type);
1421 break;
1425 static Resource *
1426 res_wrap (char *value)
1428 Resource *tmp;
1429 tmp = resource_create (0);
1430 resource_add_val (tmp, 0, value, 0);
1431 return tmp;
1434 static int
1435 parse_mods (char *value)
1437 int m = 0;
1438 /* This works because "shift" and "alt" have no 'c' in them,
1439 etc. */
1440 if (strchr(value, 's') || strchr(value, 'S'))
1441 m |= M_Shift;
1442 if (strchr(value, 'c') || strchr(value, 'C'))
1443 m |= M_Ctrl;
1444 if (strchr(value, 'a') || strchr(value, 'A'))
1445 m |= M_Alt;
1446 if (strchr(value, 'u') || strchr(value, 'U'))
1447 m |= M_Release;
1448 return m;
1451 void
1452 lesstif_note_mouse_resource (Resource *res)
1454 int bi, mi;
1455 #if 0
1456 Resource *orig_actions[MAX_MOUSE_BUTTON+2][16];
1458 fprintf(stderr, "note mouse resource:\n");
1459 resource_dump (res);
1460 #endif
1462 for (bi=0; bi<res->c; bi++)
1464 int button_num;
1466 /* All mouse-related resources must be named. The name is the
1467 mouse button number. */
1468 if (!res->v[bi].name)
1469 continue;
1470 else if (strcasecmp (res->v[bi].name, "left") == 0)
1471 button_num = 1;
1472 else if (strcasecmp (res->v[bi].name, "middle") == 0)
1473 button_num = 2;
1474 else if (strcasecmp (res->v[bi].name, "right") == 0)
1475 button_num = 3;
1476 else if (strcasecmp (res->v[bi].name, "up") == 0)
1477 button_num = 4;
1478 else if (strcasecmp (res->v[bi].name, "down") == 0)
1479 button_num = 5;
1480 else
1481 button_num = atoi (res->v[bi].name);
1483 if (button_num < 1 || button_num > MAX_MOUSE_BUTTON)
1484 continue;
1486 if (res->v[bi].value)
1487 mouse_actions[button_num][0] = res_wrap (res->v[bi].value);
1489 if (res->v[bi].subres)
1491 Resource *m = res->v[bi].subres;
1492 int mods;
1494 for (mi=0; mi<m->c; mi++)
1496 switch (resource_type (m->v[mi]))
1498 case 1: /* subres only */
1499 mouse_actions[button_num][0] = m->v[mi].subres;
1500 break;
1502 case 10: /* value only */
1503 mouse_actions[button_num][0] = res_wrap (m->v[mi].value);
1504 break;
1506 case 101: /* name = subres */
1507 mods = parse_mods (m->v[mi].name);
1508 mouse_actions[button_num][mods] = m->v[mi].subres;
1509 break;
1511 case 110: /* name = value */
1512 mods = parse_mods (m->v[mi].name);
1513 mouse_actions[button_num][mods] = res_wrap (m->v[mi].value);
1514 break;
1520 #if 0
1521 printf("Configured mouse actions:\n");
1522 for (bi=1; bi<=MAX_MOUSE_BUTTON; bi++)
1523 for (mi=0; mi<16; mi++)
1524 if (mouse_actions[bi][mi])
1526 printf("\033[32m=== %c %c %c %c %d ===\033[0m\n",
1527 mi & M_Release ? 'R' : '-',
1528 mi & M_Alt ? 'A' : '-',
1529 mi & M_Ctrl ? 'C' : '-',
1530 mi & M_Shift ? 'S' : '-',
1531 bi);
1532 resource_dump (mouse_actions[bi][mi]);
1534 memcpy (orig_actions, mouse_actions, sizeof(mouse_actions));
1535 #endif
1537 for (bi=0; bi<=MAX_MOUSE_BUTTON; bi++)
1539 int i, j;
1540 for (i=15; i>0; i--)
1541 if (!mouse_actions[bi][i])
1542 for (j=i-1; j>=(i&M_Release?8:0); j--)
1543 if (((i & j) == j) && mouse_actions[bi][j])
1545 mouse_actions[bi][i] = mouse_actions[bi][j];
1546 break;
1550 #if 0
1551 printf("Active mouse actions:\n");
1552 for (bi=1; bi<=MAX_MOUSE_BUTTON; bi++)
1553 for (mi=0; mi<16; mi++)
1554 if (mouse_actions[bi][mi])
1556 printf("\033[31m=== %c %c %c %c %d ===\033[0m",
1557 mi & M_Release ? 'R' : '-',
1558 mi & M_Alt ? 'A' : '-',
1559 mi & M_Ctrl ? 'C' : '-',
1560 mi & M_Shift ? 'S' : '-',
1561 bi);
1562 if (!orig_actions[bi][mi])
1563 printf("\033[34m");
1564 resource_dump (mouse_actions[bi][mi]);
1565 if (!orig_actions[bi][mi])
1566 printf("\033[0m");
1568 #endif
1571 static void
1572 draw_right_cross (GC xor_gc, int x, int y,
1573 int view_width, int view_height)
1575 XDrawLine (display, window, xor_gc, 0, y, view_width, y);
1576 XDrawLine (display, window, xor_gc, x, 0, x, view_height);
1579 static void
1580 draw_slanted_cross (GC xor_gc, int x, int y,
1581 int view_width, int view_height)
1583 int x0, y0, x1, y1;
1585 x0 = x + (view_height - y);
1586 x0 = MAX(0, MIN (x0, view_width));
1587 x1 = x - y;
1588 x1 = MAX(0, MIN (x1, view_width));
1589 y0 = y + (view_width - x);
1590 y0 = MAX(0, MIN (y0, view_height));
1591 y1 = y - x;
1592 y1 = MAX(0, MIN (y1, view_height));
1593 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1594 x0 = x - (view_height - y);
1595 x0 = MAX(0, MIN (x0, view_width));
1596 x1 = x + y;
1597 x1 = MAX(0, MIN (x1, view_width));
1598 y0 = y + x;
1599 y0 = MAX(0, MIN (y0, view_height));
1600 y1 = y - (view_width - x);
1601 y1 = MAX(0, MIN (y1, view_height));
1602 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1605 static void
1606 draw_dozen_cross (GC xor_gc, int x, int y,
1607 int view_width, int view_height)
1609 int x0, y0, x1, y1;
1610 double tan60 = sqrt (3);
1612 x0 = x + (view_height - y) / tan60;
1613 x0 = MAX(0, MIN (x0, view_width));
1614 x1 = x - y / tan60;
1615 x1 = MAX(0, MIN (x1, view_width));
1616 y0 = y + (view_width - x) * tan60;
1617 y0 = MAX(0, MIN (y0, view_height));
1618 y1 = y - x * tan60;
1619 y1 = MAX(0, MIN (y1, view_height));
1620 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1622 x0 = x + (view_height - y) * tan60;
1623 x0 = MAX(0, MIN (x0, view_width));
1624 x1 = x - y * tan60;
1625 x1 = MAX(0, MIN (x1, view_width));
1626 y0 = y + (view_width - x) / tan60;
1627 y0 = MAX(0, MIN (y0, view_height));
1628 y1 = y - x / tan60;
1629 y1 = MAX(0, MIN (y1, view_height));
1630 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1632 x0 = x - (view_height - y) / tan60;
1633 x0 = MAX(0, MIN (x0, view_width));
1634 x1 = x + y / tan60;
1635 x1 = MAX(0, MIN (x1, view_width));
1636 y0 = y + x * tan60;
1637 y0 = MAX(0, MIN (y0, view_height));
1638 y1 = y - (view_width - x) * tan60;
1639 y1 = MAX(0, MIN (y1, view_height));
1640 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1642 x0 = x - (view_height - y) * tan60;
1643 x0 = MAX(0, MIN (x0, view_width));
1644 x1 = x + y * tan60;
1645 x1 = MAX(0, MIN (x1, view_width));
1646 y0 = y + x / tan60;
1647 y0 = MAX(0, MIN (y0, view_height));
1648 y1 = y - (view_width - x) / tan60;
1649 y1 = MAX(0, MIN (y1, view_height));
1650 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1653 static void
1654 draw_crosshair (GC xor_gc, int x, int y,
1655 int view_width, int view_height)
1657 draw_right_cross (xor_gc, x, y, view_width, view_height);
1658 if (Crosshair.shape == Union_Jack_Crosshair_Shape)
1659 draw_slanted_cross (xor_gc, x, y, view_width, view_height);
1660 if (Crosshair.shape == Dozen_Crosshair_Shape)
1661 draw_dozen_cross (xor_gc, x, y, view_width, view_height);
1663 void
1664 lesstif_show_crosshair (int show)
1666 static int showing = 0;
1667 static int sx, sy;
1668 static GC xor_gc = 0;
1669 Pixel crosshair_color;
1671 if (!crosshair_in_window || !window)
1672 return;
1673 if (xor_gc == 0)
1675 crosshair_color = lesstif_parse_color (Settings.CrosshairColor) ^ bgcolor;
1676 xor_gc = XCreateGC (display, window, 0, 0);
1677 XSetFunction (display, xor_gc, GXxor);
1678 XSetForeground (display, xor_gc, crosshair_color);
1680 if (show == showing)
1681 return;
1682 if (show)
1684 sx = Vx (crosshair_x);
1685 sy = Vy (crosshair_y);
1687 else
1688 need_idle_proc ();
1689 draw_crosshair (xor_gc, sx, sy, view_width, view_height);
1690 showing = show;
1693 static void
1694 work_area_expose (Widget work_area, void *me,
1695 XmDrawingAreaCallbackStruct * cbs)
1697 XExposeEvent *e;
1699 show_crosshair (0);
1700 e = &(cbs->event->xexpose);
1701 XSetFunction (display, my_gc, GXcopy);
1702 XCopyArea (display, main_pixmap, window, my_gc,
1703 e->x, e->y, e->width, e->height, e->x, e->y);
1704 show_crosshair (1);
1707 static void
1708 scroll_callback (Widget scroll, int *view_dim,
1709 XmScrollBarCallbackStruct * cbs)
1711 *view_dim = cbs->value;
1712 lesstif_invalidate_all ();
1715 static void
1716 work_area_make_pixmaps (Dimension width, Dimension height)
1718 if (main_pixmap)
1719 XFreePixmap (display, main_pixmap);
1720 main_pixmap =
1721 XCreatePixmap (display, window, width, height,
1722 XDefaultDepth (display, screen));
1724 if (mask_pixmap)
1725 XFreePixmap (display, mask_pixmap);
1726 mask_pixmap =
1727 XCreatePixmap (display, window, width, height,
1728 XDefaultDepth (display, screen));
1729 #ifdef HAVE_XRENDER
1730 if (main_picture)
1732 XRenderFreePicture (display, main_picture);
1733 main_picture = 0;
1735 if (mask_picture)
1737 XRenderFreePicture (display, mask_picture);
1738 mask_picture = 0;
1740 if (use_xrender)
1742 main_picture = XRenderCreatePicture (display, main_pixmap,
1743 XRenderFindVisualFormat(display,
1744 DefaultVisual(display, screen)), 0, 0);
1745 mask_picture = XRenderCreatePicture (display, mask_pixmap,
1746 XRenderFindVisualFormat(display,
1747 DefaultVisual(display, screen)), 0, 0);
1748 if (!main_picture || !mask_picture)
1749 use_xrender = 0;
1751 #endif /* HAVE_XRENDER */
1753 if (mask_bitmap)
1754 XFreePixmap (display, mask_bitmap);
1755 mask_bitmap = XCreatePixmap (display, window, width, height, 1);
1757 pixmap = use_mask ? main_pixmap : mask_pixmap;
1758 pixmap_w = width;
1759 pixmap_h = height;
1762 static void
1763 work_area_resize (Widget work_area, void *me,
1764 XmDrawingAreaCallbackStruct * cbs)
1766 XColor color;
1767 Dimension width, height;
1769 show_crosshair (0);
1771 n = 0;
1772 stdarg (XtNwidth, &width);
1773 stdarg (XtNheight, &height);
1774 stdarg (XmNbackground, &bgcolor);
1775 XtGetValues (work_area, args, n);
1776 view_width = width;
1777 view_height = height;
1779 color.pixel = bgcolor;
1780 XQueryColor (display, colormap, &color);
1781 bgred = color.red;
1782 bggreen = color.green;
1783 bgblue = color.blue;
1785 if (!window)
1786 return;
1788 work_area_make_pixmaps (view_width, view_height);
1790 zoom_by (1, 0, 0);
1793 static void
1794 work_area_first_expose (Widget work_area, void *me,
1795 XmDrawingAreaCallbackStruct * cbs)
1797 int c;
1798 Dimension width, height;
1799 static char dashes[] = { 4, 4 };
1801 window = XtWindow (work_area);
1802 my_gc = XCreateGC (display, window, 0, 0);
1804 arc1_gc = XCreateGC (display, window, 0, 0);
1805 c = lesstif_parse_color ("#804000");
1806 XSetForeground (display, arc1_gc, c);
1807 arc2_gc = XCreateGC (display, window, 0, 0);
1808 c = lesstif_parse_color ("#004080");
1809 XSetForeground (display, arc2_gc, c);
1810 XSetLineAttributes (display, arc1_gc, 1, LineOnOffDash, 0, 0);
1811 XSetLineAttributes (display, arc2_gc, 1, LineOnOffDash, 0, 0);
1812 XSetDashes (display, arc1_gc, 0, dashes, 2);
1813 XSetDashes (display, arc2_gc, 0, dashes, 2);
1815 n = 0;
1816 stdarg (XtNwidth, &width);
1817 stdarg (XtNheight, &height);
1818 stdarg (XmNbackground, &bgcolor);
1819 XtGetValues (work_area, args, n);
1820 view_width = width;
1821 view_height = height;
1823 offlimit_color = lesstif_parse_color (Settings.OffLimitColor);
1824 grid_color = lesstif_parse_color (Settings.GridColor);
1826 bg_gc = XCreateGC (display, window, 0, 0);
1827 XSetForeground (display, bg_gc, bgcolor);
1829 work_area_make_pixmaps (width, height);
1831 #ifdef HAVE_XRENDER
1832 if (use_xrender)
1834 XRenderPictureAttributes pa;
1835 XRenderColor a = {0, 0, 0, 0x8000};
1837 pale_pixmap = XCreatePixmap (display, window, 1, 1, 8);
1838 pa.repeat = True;
1839 pale_picture = XRenderCreatePicture (display, pale_pixmap,
1840 XRenderFindStandardFormat(display, PictStandardA8),
1841 CPRepeat, &pa);
1842 if (pale_picture)
1843 XRenderFillRectangle(display, PictOpSrc, pale_picture, &a, 0, 0, 1, 1);
1844 else
1845 use_xrender = 0;
1847 #endif /* HAVE_XRENDER */
1849 clip_gc = XCreateGC (display, window, 0, 0);
1850 bset_gc = XCreateGC (display, mask_bitmap, 0, 0);
1851 XSetForeground (display, bset_gc, 1);
1852 bclear_gc = XCreateGC (display, mask_bitmap, 0, 0);
1853 XSetForeground (display, bclear_gc, 0);
1855 XtRemoveCallback (work_area, XmNexposeCallback,
1856 (XtCallbackProc) work_area_first_expose, 0);
1857 XtAddCallback (work_area, XmNexposeCallback,
1858 (XtCallbackProc) work_area_expose, 0);
1859 lesstif_invalidate_all ();
1862 static Widget
1863 make_message (char *name, Widget left, int resizeable)
1865 Widget w, f;
1866 n = 0;
1867 if (left)
1869 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
1870 stdarg (XmNleftWidget, XtParent(left));
1872 else
1874 stdarg (XmNleftAttachment, XmATTACH_FORM);
1876 stdarg (XmNtopAttachment, XmATTACH_FORM);
1877 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1878 stdarg (XmNshadowType, XmSHADOW_IN);
1879 stdarg (XmNshadowThickness, 1);
1880 stdarg (XmNalignment, XmALIGNMENT_CENTER);
1881 stdarg (XmNmarginWidth, 4);
1882 stdarg (XmNmarginHeight, 1);
1883 if (!resizeable)
1884 stdarg (XmNresizePolicy, XmRESIZE_GROW);
1885 f = XmCreateForm (messages, name, args, n);
1886 XtManageChild (f);
1887 n = 0;
1888 stdarg (XmNtopAttachment, XmATTACH_FORM);
1889 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1890 stdarg (XmNleftAttachment, XmATTACH_FORM);
1891 stdarg (XmNrightAttachment, XmATTACH_FORM);
1892 w = XmCreateLabel (f, name, args, n);
1893 XtManageChild (w);
1894 return w;
1897 static void
1898 lesstif_do_export (HID_Attr_Val * options)
1900 Dimension width, height;
1901 Widget menu;
1902 Widget work_area_frame;
1904 n = 0;
1905 stdarg (XtNwidth, &width);
1906 stdarg (XtNheight, &height);
1907 XtGetValues (appwidget, args, n);
1909 if (width < 1)
1910 width = 640;
1911 if (width > XDisplayWidth (display, screen))
1912 width = XDisplayWidth (display, screen);
1913 if (height < 1)
1914 height = 480;
1915 if (height > XDisplayHeight (display, screen))
1916 height = XDisplayHeight (display, screen);
1918 n = 0;
1919 stdarg (XmNwidth, width);
1920 stdarg (XmNheight, height);
1921 XtSetValues (appwidget, args, n);
1923 stdarg (XmNspacing, 0);
1924 mainwind = XmCreateMainWindow (appwidget, "mainWind", args, n);
1925 XtManageChild (mainwind);
1927 n = 0;
1928 stdarg (XmNmarginWidth, 0);
1929 stdarg (XmNmarginHeight, 0);
1930 menu = lesstif_menu (mainwind, "menubar", args, n);
1931 XtManageChild (menu);
1933 n = 0;
1934 stdarg (XmNshadowType, XmSHADOW_IN);
1935 work_area_frame =
1936 XmCreateFrame (mainwind, "work_area_frame", args, n);
1937 XtManageChild (work_area_frame);
1939 n = 0;
1940 do_color (Settings.BackgroundColor, XmNbackground);
1941 work_area = XmCreateDrawingArea (work_area_frame, "work_area", args, n);
1942 XtManageChild (work_area);
1943 XtAddCallback (work_area, XmNexposeCallback,
1944 (XtCallbackProc) work_area_first_expose, 0);
1945 XtAddCallback (work_area, XmNresizeCallback,
1946 (XtCallbackProc) work_area_resize, 0);
1947 /* A regular callback won't work here, because lesstif swallows any
1948 Ctrl<Button>1 event. */
1949 XtAddEventHandler (work_area,
1950 ButtonPressMask | ButtonReleaseMask
1951 | PointerMotionMask | PointerMotionHintMask
1952 | KeyPressMask | KeyReleaseMask
1953 | EnterWindowMask | LeaveWindowMask,
1954 0, work_area_input, 0);
1956 n = 0;
1957 stdarg (XmNorientation, XmVERTICAL);
1958 stdarg (XmNprocessingDirection, XmMAX_ON_BOTTOM);
1959 stdarg (XmNmaximum, PCB->MaxHeight ? PCB->MaxHeight : 1);
1960 vscroll = XmCreateScrollBar (mainwind, "vscroll", args, n);
1961 XtAddCallback (vscroll, XmNvalueChangedCallback,
1962 (XtCallbackProc) scroll_callback, (XtPointer) & view_top_y);
1963 XtAddCallback (vscroll, XmNdragCallback, (XtCallbackProc) scroll_callback,
1964 (XtPointer) & view_top_y);
1965 XtManageChild (vscroll);
1967 n = 0;
1968 stdarg (XmNorientation, XmHORIZONTAL);
1969 stdarg (XmNmaximum, PCB->MaxWidth ? PCB->MaxWidth : 1);
1970 hscroll = XmCreateScrollBar (mainwind, "hscroll", args, n);
1971 XtAddCallback (hscroll, XmNvalueChangedCallback,
1972 (XtCallbackProc) scroll_callback, (XtPointer) & view_left_x);
1973 XtAddCallback (hscroll, XmNdragCallback, (XtCallbackProc) scroll_callback,
1974 (XtPointer) & view_left_x);
1975 XtManageChild (hscroll);
1977 n = 0;
1978 stdarg (XmNresize, True);
1979 stdarg (XmNresizePolicy, XmRESIZE_ANY);
1980 messages = XmCreateForm (mainwind, "messages", args, n);
1981 XtManageChild (messages);
1983 n = 0;
1984 stdarg (XmNtopAttachment, XmATTACH_FORM);
1985 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1986 stdarg (XmNleftAttachment, XmATTACH_FORM);
1987 stdarg (XmNrightAttachment, XmATTACH_FORM);
1988 stdarg (XmNalignment, XmALIGNMENT_CENTER);
1989 stdarg (XmNshadowThickness, 2);
1990 m_click = XmCreateLabel (messages, "click", args, n);
1992 n = 0;
1993 stdarg (XmNtopAttachment, XmATTACH_FORM);
1994 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1995 stdarg (XmNleftAttachment, XmATTACH_FORM);
1996 stdarg (XmNlabelString, XmStringCreateLocalized ("Command: "));
1997 m_cmd_label = XmCreateLabel (messages, "command", args, n);
1999 n = 0;
2000 stdarg (XmNtopAttachment, XmATTACH_FORM);
2001 stdarg (XmNbottomAttachment, XmATTACH_FORM);
2002 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
2003 stdarg (XmNleftWidget, m_cmd_label);
2004 stdarg (XmNrightAttachment, XmATTACH_FORM);
2005 stdarg (XmNshadowThickness, 1);
2006 stdarg (XmNhighlightThickness, 0);
2007 stdarg (XmNmarginWidth, 2);
2008 stdarg (XmNmarginHeight, 2);
2009 m_cmd = XmCreateTextField (messages, "command", args, n);
2010 XtAddCallback (m_cmd, XmNactivateCallback,
2011 (XtCallbackProc) command_callback, 0);
2012 XtAddCallback (m_cmd, XmNlosingFocusCallback,
2013 (XtCallbackProc) command_callback, 0);
2014 XtAddEventHandler (m_cmd, KeyPressMask, 0, command_event_handler, 0);
2016 m_mark = make_message ("m_mark", 0, 0);
2017 m_crosshair = make_message ("m_crosshair", m_mark, 0);
2018 m_grid = make_message ("m_grid", m_crosshair, 1);
2019 m_zoom = make_message ("m_zoom", m_grid, 1);
2020 lesstif_m_layer = make_message ("m_layer", m_zoom, 0);
2021 m_mode = make_message ("m_mode", lesstif_m_layer, 1);
2022 m_rats = make_message ("m_rats", m_mode, 1);
2023 m_status = make_message ("m_status", m_mode, 1);
2025 XtUnmanageChild (XtParent (m_mark));
2026 XtUnmanageChild (XtParent (m_rats));
2028 n = 0;
2029 stdarg (XmNrightAttachment, XmATTACH_FORM);
2030 XtSetValues (XtParent (m_status), args, n);
2032 /* We'll use this later. */
2033 n = 0;
2034 stdarg (XmNleftWidget, XtParent (m_mark));
2035 XtSetValues (XtParent (m_crosshair), args, n);
2037 n = 0;
2038 stdarg (XmNmessageWindow, messages);
2039 XtSetValues (mainwind, args, n);
2041 if (background_image_file)
2042 LoadBackgroundImage (background_image_file);
2044 XtRealizeWidget (appwidget);
2046 while (!window)
2048 XEvent e;
2049 XtAppNextEvent (app_context, &e);
2050 XtDispatchEvent (&e);
2053 PCBChanged (0, 0, 0, 0);
2055 XtAppMainLoop (app_context);
2058 #if 0
2059 XrmOptionDescRec lesstif_options[] = {
2062 XtResource lesstif_resources[] = {
2064 #endif
2066 typedef union
2068 int i;
2069 double f;
2070 char *s;
2071 } val_union;
2073 static Boolean
2074 cvtres_string_to_double (Display * d, XrmValue * args, Cardinal * num_args,
2075 XrmValue * from, XrmValue * to,
2076 XtPointer * converter_data)
2078 static double rv;
2079 rv = strtod ((char *) from->addr, 0);
2080 if (to->addr)
2081 *(double *) to->addr = rv;
2082 else
2083 to->addr = (XPointer) & rv;
2084 to->size = sizeof (rv);
2085 return True;
2088 static void
2089 mainwind_delete_cb ()
2091 hid_action ("Quit");
2094 static void
2095 lesstif_listener_cb (XtPointer client_data, int *fid, XtInputId *id)
2097 char buf[BUFSIZ];
2098 int nbytes;
2100 if ((nbytes = read (*fid, buf, BUFSIZ)) == -1)
2101 perror ("lesstif_listener_cb");
2103 if (nbytes)
2105 buf[nbytes] = '\0';
2106 hid_parse_actions (buf, NULL);
2111 static void
2112 lesstif_parse_arguments (int *argc, char ***argv)
2114 Atom close_atom;
2115 HID_AttrNode *ha;
2116 int acount = 0, amax;
2117 int rcount = 0, rmax;
2118 int i;
2119 XrmOptionDescRec *new_options;
2120 XtResource *new_resources;
2121 val_union *new_values;
2122 int render_event, render_error;
2124 XtSetTypeConverter (XtRString,
2125 XtRDouble,
2126 cvtres_string_to_double, NULL, 0, XtCacheAll, NULL);
2128 for (ha = hid_attr_nodes; ha; ha = ha->next)
2129 for (i = 0; i < ha->n; i++)
2131 HID_Attribute *a = ha->attributes + i;
2132 switch (a->type)
2134 case HID_Integer:
2135 case HID_Real:
2136 case HID_String:
2137 case HID_Path:
2138 case HID_Boolean:
2139 acount++;
2140 rcount++;
2141 break;
2142 default:
2143 break;
2147 #if 0
2148 amax = acount + XtNumber (lesstif_options);
2149 #else
2150 amax = acount;
2151 #endif
2153 new_options = malloc ((amax + 1) * sizeof (XrmOptionDescRec));
2155 #if 0
2156 memcpy (new_options + acount, lesstif_options, sizeof (lesstif_options));
2157 #endif
2158 acount = 0;
2160 #if 0
2161 rmax = rcount + XtNumber (lesstif_resources);
2162 #else
2163 rmax = rcount;
2164 #endif
2166 new_resources = malloc ((rmax + 1) * sizeof (XtResource));
2167 new_values = malloc ((rmax + 1) * sizeof (val_union));
2168 #if 0
2169 memcpy (new_resources + acount, lesstif_resources,
2170 sizeof (lesstif_resources));
2171 #endif
2172 rcount = 0;
2174 for (ha = hid_attr_nodes; ha; ha = ha->next)
2175 for (i = 0; i < ha->n; i++)
2177 HID_Attribute *a = ha->attributes + i;
2178 XrmOptionDescRec *o = new_options + acount;
2179 char *tmpopt, *tmpres;
2180 XtResource *r = new_resources + rcount;
2182 tmpopt = (char *) malloc (strlen (a->name) + 3);
2183 tmpopt[0] = tmpopt[1] = '-';
2184 strcpy (tmpopt + 2, a->name);
2185 o->option = tmpopt;
2187 tmpres = (char *) malloc (strlen (a->name) + 2);
2188 tmpres[0] = '*';
2189 strcpy (tmpres + 1, a->name);
2190 o->specifier = tmpres;
2192 switch (a->type)
2194 case HID_Integer:
2195 case HID_Real:
2196 case HID_String:
2197 case HID_Path:
2198 o->argKind = XrmoptionSepArg;
2199 o->value = 0;
2200 acount++;
2201 break;
2202 case HID_Boolean:
2203 o->argKind = XrmoptionNoArg;
2204 o->value = "True";
2205 acount++;
2206 break;
2207 default:
2208 break;
2211 r->resource_name = a->name;
2212 r->resource_class = a->name;
2213 r->resource_offset = sizeof (val_union) * rcount;
2215 switch (a->type)
2217 case HID_Integer:
2218 r->resource_type = XtRInt;
2219 r->default_type = XtRInt;
2220 r->resource_size = sizeof (int);
2221 r->default_addr = &(a->default_val.int_value);
2222 rcount++;
2223 break;
2224 case HID_Real:
2225 r->resource_type = XtRDouble;
2226 r->default_type = XtRDouble;
2227 r->resource_size = sizeof (double);
2228 r->default_addr = &(a->default_val.real_value);
2229 rcount++;
2230 break;
2231 case HID_String:
2232 case HID_Path:
2233 r->resource_type = XtRString;
2234 r->default_type = XtRString;
2235 r->resource_size = sizeof (char *);
2236 r->default_addr = a->default_val.str_value;
2237 rcount++;
2238 break;
2239 case HID_Boolean:
2240 r->resource_type = XtRBoolean;
2241 r->default_type = XtRInt;
2242 r->resource_size = sizeof (int);
2243 r->default_addr = &(a->default_val.int_value);
2244 rcount++;
2245 break;
2246 default:
2247 break;
2250 #if 0
2251 for (i = 0; i < XtNumber (lesstif_resources); i++)
2253 XtResource *r = new_resources + rcount;
2254 r->resource_offset = sizeof (val_union) * rcount;
2255 rcount++;
2257 #endif
2259 n = 0;
2260 stdarg (XmNdeleteResponse, XmDO_NOTHING);
2262 appwidget = XtAppInitialize (&app_context,
2263 "Pcb",
2264 new_options, amax, argc, *argv, 0, args, n);
2266 display = XtDisplay (appwidget);
2267 screen_s = XtScreen (appwidget);
2268 screen = XScreenNumberOfScreen (screen_s);
2269 colormap = XDefaultColormap (display, screen);
2271 close_atom = XmInternAtom (display, "WM_DELETE_WINDOW", 0);
2272 XmAddWMProtocolCallback (appwidget, close_atom,
2273 (XtCallbackProc) mainwind_delete_cb, 0);
2275 /* XSynchronize(display, True); */
2277 XtGetApplicationResources (appwidget, new_values, new_resources,
2278 rmax, 0, 0);
2280 #ifdef HAVE_XRENDER
2281 use_xrender = XRenderQueryExtension (display, &render_event, &render_error) &&
2282 XRenderFindVisualFormat (display, DefaultVisual(display, screen));
2283 #endif /* HAVE_XRENDER */
2285 rcount = 0;
2286 for (ha = hid_attr_nodes; ha; ha = ha->next)
2287 for (i = 0; i < ha->n; i++)
2289 HID_Attribute *a = ha->attributes + i;
2290 val_union *v = new_values + rcount;
2291 switch (a->type)
2293 case HID_Integer:
2294 if (a->value)
2295 *(int *) a->value = v->i;
2296 else
2297 a->default_val.int_value = v->i;
2298 rcount++;
2299 break;
2300 case HID_Boolean:
2301 if (a->value)
2302 *(char *) a->value = v->i;
2303 else
2304 a->default_val.int_value = v->i;
2305 rcount++;
2306 break;
2307 case HID_Real:
2308 if (a->value)
2309 *(double *) a->value = v->f;
2310 else
2311 a->default_val.real_value = v->f;
2312 rcount++;
2313 break;
2314 case HID_String:
2315 case HID_Path:
2316 if (a->value)
2317 *(char **) a->value = v->s;
2318 else
2319 a->default_val.str_value = v->s;
2320 rcount++;
2321 break;
2322 default:
2323 break;
2327 /* redefine colormap, if requested via "-install" */
2328 if (use_private_colormap)
2330 colormap = XCopyColormapAndFree (display, colormap);
2331 XtVaSetValues (appwidget, XtNcolormap, colormap, NULL);
2334 /* listen on standard input for actions */
2335 if (stdin_listen)
2337 XtAppAddInput (app_context, fileno (stdin), (XtPointer) XtInputReadMask,
2338 lesstif_listener_cb, NULL);
2342 static void
2343 draw_grid ()
2345 static XPoint *points = 0;
2346 static int npoints = 0;
2347 int x1, y1, x2, y2, n, prevx;
2348 double x, y;
2349 static GC grid_gc = 0;
2351 if (!Settings.DrawGrid)
2352 return;
2353 if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
2354 return;
2355 if (!grid_gc)
2357 grid_gc = XCreateGC (display, window, 0, 0);
2358 XSetFunction (display, grid_gc, GXxor);
2359 XSetForeground (display, grid_gc, grid_color);
2361 if (flip_x)
2363 x2 = GRIDFIT_X (Px (0), PCB->Grid);
2364 x1 = GRIDFIT_X (Px (view_width), PCB->Grid);
2365 if (Vx (x2) < 0)
2366 x2 -= PCB->Grid;
2367 if (Vx (x1) >= view_width)
2368 x1 += PCB->Grid;
2370 else
2372 x1 = GRIDFIT_X (Px (0), PCB->Grid);
2373 x2 = GRIDFIT_X (Px (view_width), PCB->Grid);
2374 if (Vx (x1) < 0)
2375 x1 += PCB->Grid;
2376 if (Vx (x2) >= view_width)
2377 x2 -= PCB->Grid;
2379 if (flip_y)
2381 y2 = GRIDFIT_Y (Py (0), PCB->Grid);
2382 y1 = GRIDFIT_Y (Py (view_height), PCB->Grid);
2383 if (Vy (y2) < 0)
2384 y2 -= PCB->Grid;
2385 if (Vy (y1) >= view_height)
2386 y1 += PCB->Grid;
2388 else
2390 y1 = GRIDFIT_Y (Py (0), PCB->Grid);
2391 y2 = GRIDFIT_Y (Py (view_height), PCB->Grid);
2392 if (Vy (y1) < 0)
2393 y1 += PCB->Grid;
2394 if (Vy (y2) >= view_height)
2395 y2 -= PCB->Grid;
2397 n = (int) ((x2 - x1) / PCB->Grid + 0.5) + 1;
2398 if (n > npoints)
2400 npoints = n + 10;
2401 points =
2402 MyRealloc (points, npoints * sizeof (XPoint), "lesstif_draw_grid");
2404 n = 0;
2405 prevx = 0;
2406 for (x = x1; x <= x2; x += PCB->Grid)
2408 int temp = Vx (x);
2409 points[n].x = temp;
2410 if (n)
2412 points[n].x -= prevx;
2413 points[n].y = 0;
2415 prevx = temp;
2416 n++;
2418 for (y = y1; y <= y2; y += PCB->Grid)
2420 int vy = Vy (y);
2421 points[0].y = vy;
2422 XDrawPoints (display, pixmap, grid_gc, points, n, CoordModePrevious);
2426 static int
2427 coords_to_widget (int x, int y, Widget w, int prev_state)
2429 int this_state = prev_state;
2430 static char buf[60];
2431 double dx, dy, g;
2432 int frac = 0;
2433 XmString ms;
2435 if (Settings.grid_units_mm)
2437 /* MM */
2438 dx = PCB_TO_MM (x);
2439 dy = PCB_TO_MM (y);
2440 g = PCB_TO_MM (PCB->Grid);
2442 else
2444 /* Mils */
2445 dx = PCB_TO_MIL (x);
2446 dy = PCB_TO_MIL (y);
2447 g = PCB_TO_MIL (PCB->Grid);
2449 if (x < 0 && prev_state >= 0)
2450 buf[0] = 0;
2451 else if (((int) (g * 10000 + 0.5) % 10000) == 0)
2453 const char *fmt = prev_state < 0 ? "%+d, %+d" : "%d, %d";
2454 sprintf (buf, fmt, (int) (dx + 0.5), (int) (dy + 0.5));
2455 this_state = 2 + Settings.grid_units_mm;
2456 frac = 0;
2458 else if (PCB->Grid <= 20 && Settings.grid_units_mm)
2460 const char *fmt = prev_state < 0 ? "%+.3f, %+.3f" : "%.3f, %.3f";
2461 sprintf (buf, fmt, dx, dy);
2462 this_state = 4 + Settings.grid_units_mm;
2463 frac = 1;
2465 else
2467 const char *fmt = prev_state < 0 ? "%+.2f, %+.2f" : "%.2f, %.2f";
2468 sprintf (buf, fmt, dx, dy);
2469 this_state = 4 + Settings.grid_units_mm;
2470 frac = 1;
2472 if (prev_state < 0 && (x || y))
2474 int angle = atan2 (dy, -dx) * 180 / M_PI;
2475 double dist = sqrt (dx * dx + dy * dy);
2476 if (frac)
2477 sprintf (buf + strlen (buf), " (%.2f", dist);
2478 else
2479 sprintf (buf + strlen (buf), " (%d", (int) (dist + 0.5));
2480 sprintf (buf + strlen (buf), ", %d\260)", angle);
2482 ms = XmStringCreateLocalized (buf);
2483 n = 0;
2484 stdarg (XmNlabelString, ms);
2485 XtSetValues (w, args, n);
2486 return this_state;
2489 static char *
2490 pcb2str (int pcbval)
2492 static char buf[20][20];
2493 static int bufp = 0;
2494 double d;
2496 bufp = (bufp + 1) % 20;
2497 if (Settings.grid_units_mm)
2498 d = PCB_TO_MM (pcbval);
2499 else
2500 d = PCB_TO_MIL (pcbval);
2502 if ((int) (d * 100 + 0.5) == (int) (d + 0.005) * 100)
2503 sprintf (buf[bufp], "%d", (int) d);
2504 else
2505 sprintf (buf[bufp], "%.2f", d);
2506 return buf[bufp];
2509 #define u(x) pcb2str(x)
2510 #define S Settings
2512 void
2513 lesstif_update_status_line ()
2515 char buf[100];
2516 char *s45 = cur_clip ();
2517 XmString xs;
2519 buf[0] = 0;
2520 switch (Settings.Mode)
2522 case VIA_MODE:
2523 sprintf (buf, "%s/%s \370=%s", u (S.ViaThickness),
2524 u (S.Keepaway), u (S.ViaDrillingHole));
2525 break;
2526 case LINE_MODE:
2527 case ARC_MODE:
2528 sprintf (buf, "%s/%s %s", u (S.LineThickness), u (S.Keepaway), s45);
2529 break;
2530 case RECTANGLE_MODE:
2531 case POLYGON_MODE:
2532 sprintf (buf, "%s %s", u (S.Keepaway), s45);
2533 break;
2534 case TEXT_MODE:
2535 sprintf (buf, "%s", u (S.TextScale));
2536 break;
2537 case MOVE_MODE:
2538 case COPY_MODE:
2539 case INSERTPOINT_MODE:
2540 case RUBBERBANDMOVE_MODE:
2541 sprintf (buf, "%s", s45);
2542 break;
2543 case NO_MODE:
2544 case PASTEBUFFER_MODE:
2545 case ROTATE_MODE:
2546 case REMOVE_MODE:
2547 case THERMAL_MODE:
2548 case ARROW_MODE:
2549 case LOCK_MODE:
2550 break;
2553 xs = XmStringCreateLocalized (buf);
2554 n = 0;
2555 stdarg (XmNlabelString, xs);
2556 XtSetValues (m_status, args, n);
2559 #undef u
2560 #undef S
2562 static int idle_proc_set = 0;
2563 static int need_redraw = 0;
2565 static Boolean
2566 idle_proc (XtPointer dummy)
2568 if (need_redraw)
2570 int mx, my;
2571 BoxType region;
2572 lesstif_use_mask (0);
2573 Crosshair.On = 0;
2574 pixmap = main_pixmap;
2575 mx = view_width;
2576 my = view_height;
2577 region.X1 = Px (0);
2578 region.Y1 = Py (0);
2579 region.X2 = Px (view_width);
2580 region.Y2 = Py (view_height);
2581 if (flip_x)
2583 int tmp = region.X1;
2584 region.X1 = region.X2;
2585 region.X2 = tmp;
2587 if (flip_y)
2589 int tmp = region.Y1;
2590 region.Y1 = region.Y2;
2591 region.Y2 = tmp;
2593 XSetForeground (display, bg_gc, bgcolor);
2594 XFillRectangle (display, main_pixmap, bg_gc, 0, 0, mx, my);
2595 if (region.X2 > PCB->MaxWidth || region.Y2 > PCB->MaxHeight)
2597 XSetForeground (display, bg_gc, offlimit_color);
2598 if (region.X2 > PCB->MaxWidth)
2600 mx = Vx (PCB->MaxWidth);
2601 if (flip_x)
2602 XFillRectangle (display, main_pixmap, bg_gc, 0, 0,
2603 mx-1, my);
2604 else
2605 XFillRectangle (display, main_pixmap, bg_gc, mx+1, 0,
2606 view_width - mx + 1, my);
2609 if (region.Y2 > PCB->MaxHeight)
2611 my = Vy (PCB->MaxHeight) + 1;
2612 if (flip_y)
2613 XFillRectangle (display, main_pixmap, bg_gc, 0, 0, mx,
2614 my-1);
2615 else
2616 XFillRectangle (display, main_pixmap, bg_gc, 0, my, mx,
2617 view_height - my + 1);
2620 DrawBackgroundImage();
2621 hid_expose_callback (&lesstif_gui, &region, 0);
2622 draw_grid ();
2623 lesstif_use_mask (0);
2624 XSetFunction (display, my_gc, GXcopy);
2625 XCopyArea (display, main_pixmap, window, my_gc, 0, 0, view_width,
2626 view_height, 0, 0);
2627 pixmap = window;
2628 CrosshairOn (0);
2629 need_redraw = 0;
2633 static int c_x = -2, c_y = -2;
2634 static MarkType saved_mark;
2635 if (crosshair_x != c_x || crosshair_y != c_y
2636 || memcmp (&saved_mark, &Marked, sizeof (MarkType)))
2638 static int last_state = 0;
2639 static int this_state = 0;
2641 c_x = crosshair_x;
2642 c_y = crosshair_y;
2644 this_state =
2645 coords_to_widget (crosshair_x, crosshair_y, m_crosshair,
2646 this_state);
2647 if (Marked.status)
2648 coords_to_widget (crosshair_x - Marked.X, crosshair_y - Marked.Y,
2649 m_mark, -1);
2651 if (Marked.status != saved_mark.status)
2653 if (Marked.status)
2655 XtManageChild (XtParent (m_mark));
2656 XtManageChild (m_mark);
2657 n = 0;
2658 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
2659 stdarg (XmNleftWidget, XtParent (m_mark));
2660 XtSetValues (XtParent (m_crosshair), args, n);
2662 else
2664 n = 0;
2665 stdarg (XmNleftAttachment, XmATTACH_FORM);
2666 XtSetValues (XtParent (m_crosshair), args, n);
2667 XtUnmanageChild (XtParent (m_mark));
2669 last_state = this_state + 100;
2671 memcpy (&saved_mark, &Marked, sizeof (MarkType));
2673 /* This is obtuse. We want to enable XmRESIZE_ANY long enough
2674 to shrink to fit the new format (if any), then switch it
2675 back to XmRESIZE_GROW to prevent it from shrinking due to
2676 changes in the number of actual digits printed. Thus, when
2677 you switch from a small grid and %.2f formats to a large
2678 grid and %d formats, you aren't punished with a wide and
2679 mostly white-space label widget. "this_state" indicates
2680 which of the above formats we're using. "last_state" is
2681 either zero (when resizing) or the same as "this_state"
2682 (when grow-only), or a non-zero but not "this_state" which
2683 means we need to start a resize cycle. */
2684 if (this_state != last_state && last_state)
2686 n = 0;
2687 stdarg (XmNresizePolicy, XmRESIZE_ANY);
2688 XtSetValues (XtParent (m_mark), args, n);
2689 XtSetValues (XtParent (m_crosshair), args, n);
2690 last_state = 0;
2692 else if (this_state != last_state)
2694 n = 0;
2695 stdarg (XmNresizePolicy, XmRESIZE_GROW);
2696 XtSetValues (XtParent (m_mark), args, n);
2697 XtSetValues (XtParent (m_crosshair), args, n);
2698 last_state = this_state;
2704 static double old_grid = -1;
2705 static int old_gx, old_gy, old_mm;
2706 XmString ms;
2707 if (PCB->Grid != old_grid
2708 || PCB->GridOffsetX != old_gx
2709 || PCB->GridOffsetY != old_gy || Settings.grid_units_mm != old_mm)
2711 static char buf[100];
2712 double g, x, y;
2713 char *u;
2714 old_grid = PCB->Grid;
2715 old_gx = PCB->GridOffsetX;
2716 old_gy = PCB->GridOffsetY;
2717 old_mm = Settings.grid_units_mm;
2718 if (old_grid == 1)
2720 strcpy (buf, "No Grid");
2722 else
2724 if (Settings.grid_units_mm)
2726 g = PCB_TO_MM (old_grid);
2727 x = PCB_TO_MM (old_gx);
2728 y = PCB_TO_MM (old_gy);
2729 u = "mm";
2731 else
2733 g = PCB_TO_MIL (old_grid);
2734 x = PCB_TO_MIL (old_gx);
2735 y = PCB_TO_MIL (old_gy);
2736 u = "mil";
2738 if (x || y)
2739 sprintf (buf, "%g %s @%g,%g", g, u, x, y);
2740 else
2741 sprintf (buf, "%g %s", g, u);
2743 ms = XmStringCreateLocalized (buf);
2744 n = 0;
2745 stdarg (XmNlabelString, ms);
2746 XtSetValues (m_grid, args, n);
2751 static double old_zoom = -1;
2752 static int old_zoom_units = -1;
2753 if (view_zoom != old_zoom || Settings.grid_units_mm != old_zoom_units)
2755 static char buf[100];
2756 double g;
2757 const char *units;
2758 XmString ms;
2760 old_zoom = view_zoom;
2761 old_zoom_units = Settings.grid_units_mm;
2763 if (Settings.grid_units_mm)
2765 g = PCB_TO_MM (view_zoom);
2766 units = "mm";
2768 else
2770 g = PCB_TO_MIL (view_zoom);
2771 units = "mil";
2773 if ((int) (g * 100 + 0.5) == (int) (g + 0.005) * 100)
2774 sprintf (buf, "%d %s/pix", (int) (g + 0.005), units);
2775 else
2776 sprintf (buf, "%.2f %s/pix", g, units);
2777 ms = XmStringCreateLocalized (buf);
2778 n = 0;
2779 stdarg (XmNlabelString, ms);
2780 XtSetValues (m_zoom, args, n);
2785 if (old_cursor_mode != Settings.Mode)
2787 char *s = "None";
2788 XmString ms;
2789 int cursor = -1;
2790 static int free_cursor = 0;
2792 old_cursor_mode = Settings.Mode;
2793 switch (Settings.Mode)
2795 case NO_MODE:
2796 s = "None";
2797 cursor = XC_X_cursor;
2798 break;
2799 case VIA_MODE:
2800 s = "Via";
2801 cursor = -1;
2802 break;
2803 case LINE_MODE:
2804 s = "Line";
2805 cursor = XC_pencil;
2806 break;
2807 case RECTANGLE_MODE:
2808 s = "Rectangle";
2809 cursor = XC_ul_angle;
2810 break;
2811 case POLYGON_MODE:
2812 s = "Polygon";
2813 cursor = XC_sb_up_arrow;
2814 break;
2815 case PASTEBUFFER_MODE:
2816 s = "Paste";
2817 cursor = XC_hand1;
2818 break;
2819 case TEXT_MODE:
2820 s = "Text";
2821 cursor = XC_xterm;
2822 break;
2823 case ROTATE_MODE:
2824 s = "Rotate";
2825 cursor = XC_exchange;
2826 break;
2827 case REMOVE_MODE:
2828 s = "Remove";
2829 cursor = XC_pirate;
2830 break;
2831 case MOVE_MODE:
2832 s = "Move";
2833 cursor = XC_crosshair;
2834 break;
2835 case COPY_MODE:
2836 s = "Copy";
2837 cursor = XC_crosshair;
2838 break;
2839 case INSERTPOINT_MODE:
2840 s = "Insert";
2841 cursor = XC_dotbox;
2842 break;
2843 case RUBBERBANDMOVE_MODE:
2844 s = "RBMove";
2845 cursor = XC_top_left_corner;
2846 break;
2847 case THERMAL_MODE:
2848 s = "Thermal";
2849 cursor = XC_iron_cross;
2850 break;
2851 case ARC_MODE:
2852 s = "Arc";
2853 cursor = XC_question_arrow;
2854 break;
2855 case ARROW_MODE:
2856 s = "Arrow";
2857 if (over_point)
2858 cursor = XC_draped_box;
2859 else
2860 cursor = XC_left_ptr;
2861 break;
2862 case LOCK_MODE:
2863 s = "Lock";
2864 cursor = XC_hand2;
2865 break;
2867 ms = XmStringCreateLocalized (s);
2868 n = 0;
2869 stdarg (XmNlabelString, ms);
2870 XtSetValues (m_mode, args, n);
2872 if (free_cursor)
2874 XFreeCursor (display, my_cursor);
2875 free_cursor = 0;
2877 if (cursor == -1)
2879 static Pixmap nocur_source = 0;
2880 static Pixmap nocur_mask = 0;
2881 static Cursor nocursor = 0;
2882 if (nocur_source == 0)
2884 XColor fg, bg;
2885 nocur_source =
2886 XCreateBitmapFromData (display, window, "\0", 1, 1);
2887 nocur_mask =
2888 XCreateBitmapFromData (display, window, "\0", 1, 1);
2890 fg.red = fg.green = fg.blue = 65535;
2891 bg.red = bg.green = bg.blue = 0;
2892 fg.flags = bg.flags = DoRed | DoGreen | DoBlue;
2893 nocursor = XCreatePixmapCursor (display, nocur_source,
2894 nocur_mask, &fg, &bg, 0, 0);
2896 my_cursor = nocursor;
2898 else
2900 my_cursor = XCreateFontCursor (display, cursor);
2901 free_cursor = 1;
2903 XDefineCursor (display, window, my_cursor);
2904 lesstif_update_status_line ();
2908 static char *old_clip = 0;
2909 static int old_tscale = -1;
2910 char *new_clip = cur_clip ();
2912 if (new_clip != old_clip || Settings.TextScale != old_tscale)
2914 lesstif_update_status_line ();
2915 old_clip = new_clip;
2916 old_tscale = Settings.TextScale;
2921 static int old_nrats = -1;
2922 static char buf[20];
2924 if (old_nrats != PCB->Data->RatN)
2926 old_nrats = PCB->Data->RatN;
2927 sprintf(buf, "%d rat%s", PCB->Data->RatN, PCB->Data->RatN == 1 ? "" : "s");
2928 if (PCB->Data->RatN)
2930 XtManageChild(XtParent(m_rats));
2931 XtManageChild(m_rats);
2932 n = 0;
2933 stdarg (XmNleftWidget, m_rats);
2934 XtSetValues (XtParent (m_status), args, n);
2937 n = 0;
2938 stdarg (XmNlabelString, XmStringCreateLocalized (buf));
2939 XtSetValues (m_rats, args, n);
2941 if (!PCB->Data->RatN)
2943 n = 0;
2944 stdarg (XmNleftWidget, m_mode);
2945 XtSetValues (XtParent (m_status), args, n);
2946 XtUnmanageChild(XtParent(m_rats));
2951 lesstif_update_widget_flags ();
2953 show_crosshair (1);
2954 idle_proc_set = 0;
2955 return True;
2958 void
2959 lesstif_need_idle_proc ()
2961 if (idle_proc_set || window == 0)
2962 return;
2963 XtAppAddWorkProc (app_context, idle_proc, 0);
2964 idle_proc_set = 1;
2967 static void
2968 lesstif_invalidate_wh (int x, int y, int width, int height, int last)
2970 if (!last || !window)
2971 return;
2973 need_redraw = 1;
2974 need_idle_proc ();
2977 static void
2978 lesstif_invalidate_lr (int l, int r, int t, int b, int last)
2980 lesstif_invalidate_wh (l, t, r - l + 1, b - t + 1, last);
2983 void
2984 lesstif_invalidate_all (void)
2986 lesstif_invalidate_wh (0, 0, PCB->MaxWidth, PCB->MaxHeight, 1);
2989 static int
2990 lesstif_set_layer (const char *name, int group, int empty)
2992 int idx = group;
2993 if (idx >= 0 && idx < max_layer)
2995 idx = PCB->LayerGroups.Entries[idx][0];
2996 #if 0
2997 if (idx == LayerStack[0]
2998 || GetLayerGroupNumberByNumber (idx) ==
2999 GetLayerGroupNumberByNumber (LayerStack[0]))
3000 autofade = 0;
3001 else
3002 autofade = 1;
3003 #endif
3005 #if 0
3006 else
3007 autofade = 0;
3008 #endif
3009 if (idx >= 0 && idx < max_layer + 2)
3010 return pinout ? 1 : PCB->Data->Layer[idx].On;
3011 if (idx < 0)
3013 switch (SL_TYPE (idx))
3015 case SL_INVISIBLE:
3016 return pinout ? 0 : PCB->InvisibleObjectsOn;
3017 case SL_MASK:
3018 if (SL_MYSIDE (idx) && !pinout)
3019 return TEST_FLAG (SHOWMASKFLAG, PCB);
3020 return 0;
3021 case SL_SILK:
3022 if (SL_MYSIDE (idx) || pinout)
3023 return PCB->ElementOn;
3024 return 0;
3025 case SL_ASSY:
3026 return 0;
3027 case SL_UDRILL:
3028 case SL_PDRILL:
3029 return 1;
3032 return 0;
3035 static hidGC
3036 lesstif_make_gc (void)
3038 hidGC rv = malloc (sizeof (hid_gc_struct));
3039 memset (rv, 0, sizeof (hid_gc_struct));
3040 rv->me_pointer = &lesstif_gui;
3041 return rv;
3044 static void
3045 lesstif_destroy_gc (hidGC gc)
3047 free (gc);
3050 static void
3051 lesstif_use_mask (int use_it)
3053 if ((TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) &&
3054 !use_xrender)
3055 use_it = 0;
3056 if ((use_it == 0) == (use_mask == 0))
3057 return;
3058 use_mask = use_it;
3059 if (pinout)
3060 return;
3061 if (!window)
3062 return;
3063 /* printf("use_mask(%d)\n", use_it); */
3064 if (!mask_pixmap)
3066 mask_pixmap =
3067 XCreatePixmap (display, window, pixmap_w, pixmap_h,
3068 XDefaultDepth (display, screen));
3069 mask_bitmap = XCreatePixmap (display, window, pixmap_w, pixmap_h, 1);
3071 if (use_it)
3073 pixmap = mask_pixmap;
3074 XSetForeground (display, my_gc, 0);
3075 XSetFunction (display, my_gc, GXcopy);
3076 XFillRectangle (display, mask_pixmap, my_gc,
3077 0, 0, view_width, view_height);
3078 XFillRectangle (display, mask_bitmap, bclear_gc,
3079 0, 0, view_width, view_height);
3081 else
3083 pixmap = main_pixmap;
3084 #ifdef HAVE_XRENDER
3085 if (use_xrender)
3087 XRenderPictureAttributes pa;
3089 pa.clip_mask = mask_bitmap;
3090 XRenderChangePicture(display, main_picture, CPClipMask, &pa);
3091 XRenderComposite(display, PictOpOver, mask_picture, pale_picture,
3092 main_picture, 0, 0, 0, 0, 0, 0, view_width, view_height);
3094 else
3095 #endif /* HAVE_XRENDER */
3097 XSetClipMask (display, clip_gc, mask_bitmap);
3098 XCopyArea (display, mask_pixmap, main_pixmap, clip_gc,
3099 0, 0, view_width, view_height, 0, 0);
3104 static void
3105 lesstif_set_color (hidGC gc, const char *name)
3107 static void *cache = 0;
3108 hidval cval;
3109 static XColor color, exact_color;
3111 if (!display)
3112 return;
3113 if (!name)
3114 name = "red";
3115 gc->colorname = name;
3116 if (strcmp (name, "erase") == 0)
3118 gc->color = bgcolor;
3119 gc->erase = 1;
3121 else if (strcmp (name, "drill") == 0)
3123 gc->color = offlimit_color;
3124 gc->erase = 0;
3126 else if (hid_cache_color (0, name, &cval, &cache))
3128 gc->color = cval.lval;
3129 gc->erase = 0;
3131 else
3133 if (!XAllocNamedColor (display, colormap, name, &color, &exact_color))
3134 color.pixel = WhitePixel (display, screen);
3135 #if 0
3136 printf ("lesstif_set_color `%s' %08x rgb/%d/%d/%d\n",
3137 name, color.pixel, color.red, color.green, color.blue);
3138 #endif
3139 cval.lval = gc->color = color.pixel;
3140 hid_cache_color (1, name, &cval, &cache);
3141 gc->erase = 0;
3143 if (autofade)
3145 static int lastcolor = -1, lastfade = -1;
3146 if (gc->color == lastcolor)
3147 gc->color = lastfade;
3148 else
3150 lastcolor = gc->color;
3151 color.pixel = gc->color;
3153 XQueryColor (display, colormap, &color);
3154 color.red = (bgred + color.red) / 2;
3155 color.green = (bggreen + color.green) / 2;
3156 color.blue = (bgblue + color.blue) / 2;
3157 XAllocColor (display, colormap, &color);
3158 lastfade = gc->color = color.pixel;
3163 static void
3164 set_gc (hidGC gc)
3166 int cap, join, width;
3167 if (gc->me_pointer != &lesstif_gui)
3169 fprintf (stderr, "Fatal: GC from another HID passed to lesstif HID\n");
3170 abort ();
3172 #if 0
3173 printf ("set_gc c%s %08lx w%d c%d x%d e%d\n",
3174 gc->colorname, gc->color, gc->width, gc->cap, gc->xor, gc->erase);
3175 #endif
3176 switch (gc->cap)
3178 case Square_Cap:
3179 cap = CapProjecting;
3180 join = JoinMiter;
3181 break;
3182 case Trace_Cap:
3183 case Round_Cap:
3184 cap = CapRound;
3185 join = JoinRound;
3186 break;
3187 case Beveled_Cap:
3188 cap = CapProjecting;
3189 join = JoinBevel;
3190 break;
3191 default:
3192 cap = CapProjecting;
3193 join = JoinBevel;
3194 break;
3196 if (gc->xor)
3198 XSetFunction (display, my_gc, GXxor);
3199 XSetForeground (display, my_gc, gc->color ^ bgcolor);
3201 else if (gc->erase)
3203 XSetFunction (display, my_gc, GXcopy);
3204 XSetForeground (display, my_gc, offlimit_color);
3206 else
3208 XSetFunction (display, my_gc, GXcopy);
3209 XSetForeground (display, my_gc, gc->color);
3211 width = Vz (gc->width);
3212 if (width < 0)
3213 width = 0;
3214 XSetLineAttributes (display, my_gc, width, LineSolid, cap,
3215 join);
3216 if (use_mask)
3218 if (gc->erase)
3219 mask_gc = bclear_gc;
3220 else
3221 mask_gc = bset_gc;
3222 XSetLineAttributes (display, mask_gc, Vz (gc->width), LineSolid, cap,
3223 join);
3227 static void
3228 lesstif_set_line_cap (hidGC gc, EndCapStyle style)
3230 gc->cap = style;
3233 static void
3234 lesstif_set_line_width (hidGC gc, int width)
3236 gc->width = width;
3239 static void
3240 lesstif_set_draw_xor (hidGC gc, int xor)
3242 gc->xor = xor;
3245 static void
3246 lesstif_set_draw_faded (hidGC gc, int faded)
3248 /* We don't use this */
3251 static void
3252 lesstif_set_line_cap_angle (hidGC gc, int x1, int y1, int x2, int y2)
3254 CRASH;
3257 #define ISORT(a,b) if (a>b) { a^=b; b^=a; a^=b; }
3259 static void
3260 lesstif_draw_line (hidGC gc, int x1, int y1, int x2, int y2)
3262 double dx1, dy1, dx2, dy2;
3263 int vw = Vz (gc->width);
3264 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) && gc->erase)
3265 return;
3266 #if 0
3267 printf ("draw_line %d,%d %d,%d @%d", x1, y1, x2, y2, gc->width);
3268 #endif
3269 dx1 = Vx (x1);
3270 dy1 = Vy (y1);
3271 dx2 = Vx (x2);
3272 dy2 = Vy (y2);
3273 #if 0
3274 printf (" = %d,%d %d,%d %s\n", x1, y1, x2, y2, gc->colorname);
3275 #endif
3277 #if 1
3278 if (! ClipLine (0, 0, view_width, view_height,
3279 &dx1, &dy1, &dx2, &dy2, vw))
3280 return;
3281 #endif
3283 x1 = dx1;
3284 y1 = dy1;
3285 x2 = dx2;
3286 y2 = dy2;
3288 set_gc (gc);
3289 if (gc->cap == Square_Cap && x1 == x2 && y1 == y2)
3291 XFillRectangle (display, pixmap, my_gc, x1 - vw / 2, y1 - vw / 2, vw,
3292 vw);
3293 if (use_mask)
3294 XFillRectangle (display, mask_bitmap, mask_gc, x1 - vw / 2,
3295 y1 - vw / 2, vw, vw);
3297 else
3299 XDrawLine (display, pixmap, my_gc, x1, y1, x2, y2);
3300 if (use_mask)
3301 XDrawLine (display, mask_bitmap, mask_gc, x1, y1, x2, y2);
3305 static void
3306 lesstif_draw_arc (hidGC gc, int cx, int cy, int width, int height,
3307 int start_angle, int delta_angle)
3309 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase)
3310 return;
3311 #if 0
3312 printf ("draw_arc %d,%d %dx%d s %d d %d", cx, cy, width, height, start_angle, delta_angle);
3313 #endif
3314 width = Vz (width);
3315 height = Vz (height);
3316 cx = Vx (cx) - width;
3317 cy = Vy (cy) - height;
3318 if (flip_x)
3320 start_angle = 180 - start_angle;
3321 delta_angle = - delta_angle;
3323 if (flip_y)
3325 start_angle = - start_angle;
3326 delta_angle = - delta_angle;
3328 start_angle = (start_angle + 360 + 180) % 360 - 180;
3329 #if 0
3330 printf (" = %d,%d %dx%d %d %s\n", cx, cy, width, height, gc->width,
3331 gc->colorname);
3332 #endif
3333 set_gc (gc);
3334 XDrawArc (display, pixmap, my_gc, cx, cy,
3335 width * 2, height * 2, (start_angle + 180) * 64,
3336 delta_angle * 64);
3337 if (use_mask && !TEST_FLAG (THINDRAWFLAG, PCB))
3338 XDrawArc (display, mask_bitmap, mask_gc, cx, cy,
3339 width * 2, height * 2, (start_angle + 180) * 64,
3340 delta_angle * 64);
3341 #if 0
3342 /* Enable this if you want to see the center and radii of drawn
3343 arcs, for debugging. */
3344 if (TEST_FLAG (THINDRAWFLAG, PCB)
3345 && delta_angle != 360)
3347 cx += width;
3348 cy += height;
3349 XDrawLine (display, pixmap, arc1_gc, cx, cy,
3350 cx - width*cos(start_angle*M_PI/180),
3351 cy + width*sin(start_angle*M_PI/180));
3352 XDrawLine (display, pixmap, arc2_gc, cx, cy,
3353 cx - width*cos((start_angle+delta_angle)*M_PI/180),
3354 cy + width*sin((start_angle+delta_angle)*M_PI/180));
3356 #endif
3359 static void
3360 lesstif_draw_rect (hidGC gc, int x1, int y1, int x2, int y2)
3362 int vw = Vz (gc->width);
3363 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase)
3364 return;
3365 x1 = Vx (x1);
3366 y1 = Vy (y1);
3367 x2 = Vx (x2);
3368 y2 = Vy (y2);
3369 if (x1 < -vw && x2 < -vw)
3370 return;
3371 if (y1 < -vw && y2 < -vw)
3372 return;
3373 if (x1 > view_width + vw && x2 > view_width + vw)
3374 return;
3375 if (y1 > view_height + vw && y2 > view_height + vw)
3376 return;
3377 if (x1 > x2) { int xt = x1; x1 = x2; x2 = xt; }
3378 if (y1 > y2) { int yt = y1; y1 = y2; y2 = yt; }
3379 set_gc (gc);
3380 XDrawRectangle (display, pixmap, my_gc, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
3381 if (use_mask)
3382 XDrawRectangle (display, mask_bitmap, mask_gc, x1, y1, x2 - x1 + 1,
3383 y2 - y1 + 1);
3386 static void
3387 lesstif_fill_circle (hidGC gc, int cx, int cy, int radius)
3389 if (pinout && use_mask && gc->erase)
3390 return;
3391 if ((TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) && gc->erase)
3392 return;
3393 #if 0
3394 printf ("fill_circle %d,%d %d", cx, cy, radius);
3395 #endif
3396 radius = Vz (radius);
3397 cx = Vx (cx) - radius;
3398 cy = Vy (cy) - radius;
3399 if (cx < -2 * radius || cx > view_width)
3400 return;
3401 if (cy < -2 * radius || cy > view_height)
3402 return;
3403 #if 0
3404 printf (" = %d,%d %d %lx %s\n", cx, cy, radius, gc->color, gc->colorname);
3405 #endif
3406 set_gc (gc);
3407 XFillArc (display, pixmap, my_gc, cx, cy,
3408 radius * 2, radius * 2, 0, 360 * 64);
3409 if (use_mask)
3410 XFillArc (display, mask_bitmap, mask_gc, cx, cy,
3411 radius * 2, radius * 2, 0, 360 * 64);
3414 static void
3415 lesstif_fill_polygon (hidGC gc, int n_coords, int *x, int *y)
3417 static XPoint *p = 0;
3418 static int maxp = 0;
3419 int i;
3421 if (maxp < n_coords)
3423 maxp = n_coords + 10;
3424 if (p)
3425 p = (XPoint *) realloc (p, maxp * sizeof (XPoint));
3426 else
3427 p = (XPoint *) malloc (maxp * sizeof (XPoint));
3430 for (i = 0; i < n_coords; i++)
3432 p[i].x = Vx (x[i]);
3433 p[i].y = Vy (y[i]);
3435 #if 0
3436 printf ("fill_polygon %d pts\n", n_coords);
3437 #endif
3438 set_gc (gc);
3439 XFillPolygon (display, pixmap, my_gc, p, n_coords, Complex,
3440 CoordModeOrigin);
3441 if (use_mask)
3442 XFillPolygon (display, mask_bitmap, mask_gc, p, n_coords, Complex,
3443 CoordModeOrigin);
3446 static void
3447 lesstif_fill_rect (hidGC gc, int x1, int y1, int x2, int y2)
3449 int vw = Vz (gc->width);
3450 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase)
3451 return;
3452 x1 = Vx (x1);
3453 y1 = Vy (y1);
3454 x2 = Vx (x2);
3455 y2 = Vy (y2);
3456 if (x1 < -vw && x2 < -vw)
3457 return;
3458 if (y1 < -vw && y2 < -vw)
3459 return;
3460 if (x1 > view_width + vw && x2 > view_width + vw)
3461 return;
3462 if (y1 > view_height + vw && y2 > view_height + vw)
3463 return;
3464 if (x1 > x2) { int xt = x1; x1 = x2; x2 = xt; }
3465 if (y1 > y2) { int yt = y1; y1 = y2; y2 = yt; }
3466 set_gc (gc);
3467 XFillRectangle (display, pixmap, my_gc, x1, y1, x2 - x1 + 1,
3468 y2 - y1 + 1);
3469 if (use_mask)
3470 XFillRectangle (display, mask_bitmap, mask_gc, x1, y1, x2 - x1 + 1,
3471 y2 - y1 + 1);
3474 static void
3475 lesstif_calibrate (double xval, double yval)
3477 CRASH;
3480 static int
3481 lesstif_shift_is_pressed (void)
3483 return shift_pressed;
3486 static int
3487 lesstif_control_is_pressed (void)
3489 return ctrl_pressed;
3492 extern void lesstif_get_coords (const char *msg, int *x, int *y);
3494 static void
3495 lesstif_set_crosshair (int x, int y, int action)
3497 if (crosshair_x != x || crosshair_y != y)
3499 lesstif_show_crosshair(0);
3500 crosshair_x = x;
3501 crosshair_y = y;
3502 need_idle_proc ();
3504 if (mainwind
3505 && !in_move_event
3506 && (x < view_left_x
3507 || x > view_left_x + view_width * view_zoom
3508 || y < view_top_y || y > view_top_y + view_height * view_zoom))
3510 view_left_x = x - (view_width * view_zoom) / 2;
3511 view_top_y = y - (view_height * view_zoom) / 2;
3512 lesstif_pan_fixup ();
3517 if (action == HID_SC_PAN_VIEWPORT)
3519 Window root, child;
3520 unsigned int keys_buttons;
3521 int pos_x, pos_y, root_x, root_y;
3522 XQueryPointer (display, window, &root, &child,
3523 &root_x, &root_y, &pos_x, &pos_y, &keys_buttons);
3524 if (flip_x)
3525 view_left_x = x - (view_width-pos_x) * view_zoom;
3526 else
3527 view_left_x = x - pos_x * view_zoom;
3528 if (flip_y)
3529 view_top_y = y - (view_height-pos_y) * view_zoom;
3530 else
3531 view_top_y = y - pos_y * view_zoom;
3532 lesstif_pan_fixup();
3533 action = HID_SC_WARP_POINTER;
3535 if (action == HID_SC_WARP_POINTER)
3537 in_move_event ++;
3538 XWarpPointer (display, None, window, 0, 0, 0, 0, Vx(x), Vy(y));
3539 in_move_event --;
3543 typedef struct
3545 void (*func) (hidval);
3546 hidval user_data;
3547 XtIntervalId id;
3548 } TimerStruct;
3550 static void
3551 lesstif_timer_cb (XtPointer * p, XtIntervalId * id)
3553 TimerStruct *ts = (TimerStruct *) p;
3554 ts->func (ts->user_data);
3555 free (ts);
3558 static hidval
3559 lesstif_add_timer (void (*func) (hidval user_data),
3560 unsigned long milliseconds, hidval user_data)
3562 TimerStruct *t;
3563 hidval rv;
3564 t = (TimerStruct *) malloc (sizeof (TimerStruct));
3565 rv.ptr = t;
3566 t->func = func;
3567 t->user_data = user_data;
3568 t->id = XtAppAddTimeOut (app_context, milliseconds, (XtTimerCallbackProc)lesstif_timer_cb, t);
3569 return rv;
3572 static void
3573 lesstif_stop_timer (hidval hv)
3575 TimerStruct *ts = (TimerStruct *) hv.ptr;
3576 XtRemoveTimeOut (ts->id);
3577 free (ts);
3581 typedef struct
3583 void (*func) ( hidval, int, unsigned int, hidval );
3584 hidval user_data;
3585 int fd;
3586 XtInputId id;
3588 WatchStruct;
3590 /* We need a wrapper around the hid file watch because to pass the correct flags
3592 static void
3593 lesstif_watch_cb (XtPointer client_data, int *fid, XtInputId * id)
3595 unsigned int pcb_condition = 0;
3596 struct pollfd fds;
3597 short condition;
3598 hidval x;
3599 WatchStruct *watch = (WatchStruct*)client_data;
3601 fds.fd = watch->fd;
3602 fds.events = POLLIN | POLLOUT;
3603 poll( &fds, 1, 0 );
3604 condition = fds.revents;
3606 // Should we only include those we were asked to watch?
3607 if (condition & POLLIN)
3608 pcb_condition |= PCB_WATCH_READABLE;
3609 if (condition & POLLOUT)
3610 pcb_condition |= PCB_WATCH_WRITABLE;
3611 if (condition & POLLERR)
3612 pcb_condition |= PCB_WATCH_ERROR;
3613 if (condition & POLLHUP)
3614 pcb_condition |= PCB_WATCH_HANGUP;
3616 x.ptr = (void *) watch;
3617 watch->func (x, watch->fd, pcb_condition, watch->user_data);
3619 return;
3622 hidval
3623 lesstif_watch_file (int fd, unsigned int condition, void (*func) (hidval watch, int fd, unsigned int condition, hidval user_data),
3624 hidval user_data)
3626 WatchStruct *watch = malloc (sizeof(WatchStruct));
3627 hidval ret;
3628 unsigned int xt_condition = 0;
3630 if (condition & PCB_WATCH_READABLE)
3631 xt_condition |= XtInputReadMask;
3632 if (condition & PCB_WATCH_WRITABLE)
3633 xt_condition |= XtInputWriteMask;
3634 if (condition & PCB_WATCH_ERROR)
3635 xt_condition |= XtInputExceptMask;
3636 if (condition & PCB_WATCH_HANGUP)
3637 xt_condition |= XtInputExceptMask;
3639 watch->func = func;
3640 watch->user_data = user_data;
3641 watch->fd = fd;
3642 watch->id = XtAppAddInput( app_context, fd, (XtPointer) (size_t) xt_condition, lesstif_watch_cb, watch );
3644 ret.ptr = (void *) watch;
3645 return ret;
3648 void
3649 lesstif_unwatch_file (hidval data)
3651 WatchStruct *watch = (WatchStruct*)data.ptr;
3652 XtRemoveInput( watch->id );
3653 free( watch );
3656 typedef struct
3658 XtBlockHookId id;
3659 void (*func) (hidval user_data);
3660 hidval user_data;
3661 } BlockHookStruct;
3663 static void lesstif_block_hook_cb(XtPointer user_data);
3665 static void
3666 lesstif_block_hook_cb (XtPointer user_data)
3668 BlockHookStruct *block_hook = (BlockHookStruct *)user_data;
3669 block_hook->func( block_hook->user_data );
3672 static hidval
3673 lesstif_add_block_hook (void (*func) (hidval data), hidval user_data )
3675 hidval ret;
3676 BlockHookStruct *block_hook = malloc( sizeof( BlockHookStruct ));
3678 block_hook->func = func;
3679 block_hook->user_data = user_data;
3681 block_hook->id = XtAppAddBlockHook( app_context, lesstif_block_hook_cb, (XtPointer)block_hook );
3683 ret.ptr = (void *) block_hook;
3684 return ret;
3687 static void
3688 lesstif_stop_block_hook (hidval mlpoll)
3690 BlockHookStruct *block_hook = (BlockHookStruct *)mlpoll.ptr;
3691 XtRemoveBlockHook( block_hook->id );
3692 free( block_hook );
3696 extern void lesstif_logv (const char *fmt, va_list ap);
3698 extern int lesstif_confirm_dialog (char *msg, ...);
3700 extern int lesstif_close_confirm_dialog ();
3702 extern void lesstif_report_dialog (char *title, char *msg);
3704 extern int
3705 lesstif_attribute_dialog (HID_Attribute * attrs,
3706 int n_attrs, HID_Attr_Val * results,
3707 const char * title, const char * descr);
3709 static void
3710 pinout_callback (Widget da, PinoutData * pd,
3711 XmDrawingAreaCallbackStruct * cbs)
3713 BoxType region;
3714 int save_vx, save_vy, save_vw, save_vh;
3715 int save_fx, save_fy;
3716 double save_vz;
3717 Pixmap save_px;
3718 int reason = cbs ? cbs->reason : 0;
3720 if (pd->window == 0 && reason == XmCR_RESIZE)
3721 return;
3722 if (pd->window == 0 || reason == XmCR_RESIZE)
3724 Dimension w, h;
3725 double z;
3727 n = 0;
3728 stdarg (XmNwidth, &w);
3729 stdarg (XmNheight, &h);
3730 XtGetValues (da, args, n);
3732 pd->window = XtWindow (da);
3733 pd->v_width = w;
3734 pd->v_height = h;
3735 pd->zoom = (pd->right - pd->left + 1) / (double) w;
3736 z = (pd->bottom - pd->top + 1) / (double) h;
3737 if (pd->zoom < z)
3738 pd->zoom = z;
3740 pd->x = (pd->left + pd->right) / 2 - pd->v_width * pd->zoom / 2;
3741 pd->y = (pd->top + pd->bottom) / 2 - pd->v_height * pd->zoom / 2;
3744 save_vx = view_left_x;
3745 save_vy = view_top_y;
3746 save_vz = view_zoom;
3747 save_vw = view_width;
3748 save_vh = view_height;
3749 save_fx = flip_x;
3750 save_fy = flip_y;
3751 save_px = pixmap;
3752 pinout = pd;
3753 pixmap = pd->window;
3754 view_left_x = pd->x;
3755 view_top_y = pd->y;
3756 view_zoom = pd->zoom;
3757 view_width = pd->v_width;
3758 view_height = pd->v_height;
3759 use_mask = 0;
3760 flip_x = flip_y = 0;
3762 region.X1 = 0;
3763 region.Y1 = 0;
3764 region.X2 = PCB->MaxWidth;
3765 region.Y2 = PCB->MaxHeight;
3767 XFillRectangle (display, pixmap, bg_gc, 0, 0, pd->v_width, pd->v_height);
3768 hid_expose_callback (&lesstif_gui, &region, pd->item);
3770 pinout = 0;
3771 view_left_x = save_vx;
3772 view_top_y = save_vy;
3773 view_zoom = save_vz;
3774 view_width = save_vw;
3775 view_height = save_vh;
3776 pixmap = save_px;
3777 flip_x = save_fx;
3778 flip_y = save_fy;
3781 static void
3782 pinout_unmap (Widget w, PinoutData * pd, void *v)
3784 if (pd->prev)
3785 pd->prev->next = pd->next;
3786 else
3787 pinouts = pd->next;
3788 if (pd->next)
3789 pd->next->prev = pd->prev;
3790 XtDestroyWidget (XtParent (pd->form));
3791 free (pd);
3794 static void
3795 lesstif_show_item (void *item)
3797 double scale;
3798 Widget da;
3799 BoxType *extents;
3800 PinoutData *pd;
3802 for (pd = pinouts; pd; pd = pd->next)
3803 if (pd->item == item)
3804 return;
3805 if (!mainwind)
3806 return;
3808 pd = (PinoutData *) MyCalloc (1, sizeof (PinoutData), "lesstif_show_item");
3810 pd->item = item;
3812 extents = hid_get_extents (item);
3813 pd->left = extents->X1;
3814 pd->right = extents->X2;
3815 pd->top = extents->Y1;
3816 pd->bottom = extents->Y2;
3818 if (pd->left > pd->right)
3820 free (&pd);
3821 return;
3823 pd->prev = 0;
3824 pd->next = pinouts;
3825 if (pd->next)
3826 pd->next->prev = pd;
3827 pinouts = pd;
3828 pd->zoom = 0;
3830 n = 0;
3831 pd->form = XmCreateFormDialog (mainwind, "pinout", args, n);
3832 pd->window = 0;
3833 XtAddCallback (pd->form, XmNunmapCallback, (XtCallbackProc) pinout_unmap,
3834 (XtPointer) pd);
3836 scale =
3837 sqrt (200.0 * 200.0 /
3838 ((pd->right - pd->left + 1.0) * (pd->bottom - pd->top + 1.0)));
3840 n = 0;
3841 stdarg (XmNwidth, (int) (scale * (pd->right - pd->left + 1)));
3842 stdarg (XmNheight, (int) (scale * (pd->bottom - pd->top + 1)));
3843 stdarg (XmNleftAttachment, XmATTACH_FORM);
3844 stdarg (XmNrightAttachment, XmATTACH_FORM);
3845 stdarg (XmNtopAttachment, XmATTACH_FORM);
3846 stdarg (XmNbottomAttachment, XmATTACH_FORM);
3847 da = XmCreateDrawingArea (pd->form, "pinout", args, n);
3848 XtManageChild (da);
3850 XtAddCallback (da, XmNexposeCallback, (XtCallbackProc) pinout_callback,
3851 (XtPointer) pd);
3852 XtAddCallback (da, XmNresizeCallback, (XtCallbackProc) pinout_callback,
3853 (XtPointer) pd);
3855 XtManageChild (pd->form);
3856 pinout = 0;
3859 static void
3860 lesstif_beep (void)
3862 putchar (7);
3863 fflush (stdout);
3866 static int
3867 lesstif_progress (int so_far, int total, const char *message)
3869 return 0;
3872 HID lesstif_gui = {
3873 sizeof (HID),
3874 "lesstif",
3875 "LessTif - a Motif clone for X/Unix",
3876 1, /* gui */
3877 0, /* printer */
3878 0, /* exporter */
3879 1, /* poly before */
3880 0, /* poly after */
3881 0, /* poly dicer */
3883 lesstif_get_export_options,
3884 lesstif_do_export,
3885 lesstif_parse_arguments,
3887 lesstif_invalidate_wh,
3888 lesstif_invalidate_lr,
3889 lesstif_invalidate_all,
3890 lesstif_set_layer,
3891 lesstif_make_gc,
3892 lesstif_destroy_gc,
3893 lesstif_use_mask,
3894 lesstif_set_color,
3895 lesstif_set_line_cap,
3896 lesstif_set_line_width,
3897 lesstif_set_draw_xor,
3898 lesstif_set_draw_faded,
3899 lesstif_set_line_cap_angle,
3900 lesstif_draw_line,
3901 lesstif_draw_arc,
3902 lesstif_draw_rect,
3903 lesstif_fill_circle,
3904 lesstif_fill_polygon,
3905 common_fill_pcb_polygon,
3906 common_thindraw_pcb_polygon,
3907 lesstif_fill_rect,
3909 lesstif_calibrate,
3910 lesstif_shift_is_pressed,
3911 lesstif_control_is_pressed,
3912 lesstif_get_coords,
3913 lesstif_set_crosshair,
3914 lesstif_add_timer,
3915 lesstif_stop_timer,
3916 lesstif_watch_file,
3917 lesstif_unwatch_file,
3918 lesstif_add_block_hook,
3919 lesstif_stop_block_hook,
3921 lesstif_log,
3922 lesstif_logv,
3923 lesstif_confirm_dialog,
3924 lesstif_close_confirm_dialog,
3925 lesstif_report_dialog,
3926 lesstif_prompt_for,
3927 lesstif_fileselect,
3928 lesstif_attribute_dialog,
3929 lesstif_show_item,
3930 lesstif_beep,
3931 lesstif_progress
3934 #include "dolists.h"
3936 void
3937 hid_lesstif_init ()
3939 hid_register_hid (&lesstif_gui);
3940 #include "lesstif_lists.h"