Move some fields from the HID* structure to HID_DRAW* and HID_DRAW_CLASS*
[geda-pcb/pcjc2.git] / src / hid / lesstif / main.c
blob698dd63e3e2e67072d4625b3bb26dbb5bab28857
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <time.h>
8 #include <string.h>
9 #include <math.h>
10 #include <unistd.h>
11 #include <signal.h>
12 #include <sys/time.h>
14 #include "xincludes.h"
16 #include "global.h"
17 #include "data.h"
18 #include "action.h"
19 #include "crosshair.h"
20 #include "mymem.h"
21 #include "misc.h"
22 #include "pcb-printf.h"
23 #include "resource.h"
24 #include "clip.h"
25 #include "error.h"
27 #include "hid.h"
28 #include "hid_draw.h"
29 #include "../hidint.h"
30 #include "hid/common/hidnogui.h"
31 #include "hid/common/draw_helpers.h"
32 #include "hid/common/hid_resource.h"
33 #include "lesstif.h"
35 #ifdef HAVE_LIBDMALLOC
36 #include <dmalloc.h>
37 #endif
39 #include <sys/poll.h>
41 #ifndef XtRDouble
42 #define XtRDouble "Double"
43 #endif
45 /* How big the viewport can be relative to the pcb size. */
46 #define MAX_ZOOM_SCALE 10
47 #define UUNIT Settings.grid_unit->allow
49 typedef struct lesstif_gc_struct
51 struct hid_gc_struct hid_gc /* Parent */;
53 Pixel color;
54 const char *colorname;
55 int width;
56 EndCapStyle cap;
57 char xor_set;
58 char erase;
59 } *lesstifGC;
61 static HID lesstif_hid;
62 static HID_DRAW lesstif_graphics;
63 static HID_DRAW_CLASS lesstif_graphics_class;
65 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented GUI function %s\n", __FUNCTION__), abort()
67 XtAppContext app_context;
68 Widget appwidget;
69 Display *display;
70 static Window window = 0;
71 static Cursor my_cursor = 0;
72 static int old_cursor_mode = -1;
73 static int over_point = 0;
75 /* The first is the "current" pixmap. The main_ is the real one we
76 usually use, the mask_ are the ones for doing polygon masks. The
77 pixmap is the saved pixels, the bitmap is for the "erase" color.
78 We set pixmap to point to main_pixmap or mask_pixmap as needed. */
79 static Pixmap pixmap = 0;
80 static Pixmap main_pixmap = 0;
81 static Pixmap mask_pixmap = 0;
82 static Pixmap mask_bitmap = 0;
83 static enum mask_mode use_mask = HID_MASK_OFF;
85 static int use_xrender = 0;
86 #ifdef HAVE_XRENDER
87 static Picture main_picture;
88 static Picture mask_picture;
89 static Pixmap pale_pixmap;
90 static Picture pale_picture;
91 #endif /* HAVE_XRENDER */
93 static int pixmap_w = 0, pixmap_h = 0;
94 Screen *screen_s;
95 int screen;
96 static Colormap colormap;
97 static GC my_gc = 0, bg_gc, clip_gc = 0, bset_gc = 0, bclear_gc = 0, mask_gc =
99 static Pixel bgcolor, offlimit_color, grid_color;
100 static int bgred, bggreen, bgblue;
102 static GC arc1_gc, arc2_gc;
104 static hidGC crosshair_gc;
106 /* These are for the pinout windows. */
107 typedef struct PinoutData
109 struct PinoutData *prev, *next;
110 Widget form;
111 Window window;
112 Coord left, right, top, bottom; /* PCB extents of item */
113 Coord x, y; /* PCB coordinates of upper right corner of window */
114 double zoom; /* PCB units per screen pixel */
115 int v_width, v_height; /* pixels */
116 void *item;
117 } PinoutData;
119 /* Linked list of all pinout windows. */
120 static PinoutData *pinouts = 0;
121 /* If set, we are currently updating this pinout window. */
122 static PinoutData *pinout = 0;
124 static int crosshair_x = 0, crosshair_y = 0;
125 static int in_move_event = 0, crosshair_in_window = 1;
127 Widget mainwind;
128 Widget work_area, messages, command, hscroll, vscroll;
129 static Widget m_mark, m_crosshair, m_grid, m_zoom, m_mode, m_status;
130 static Widget m_rats;
131 Widget lesstif_m_layer;
132 Widget m_click;
134 /* This is the size, in pixels, of the viewport. */
135 static int view_width, view_height;
136 /* This is the PCB location represented by the upper left corner of
137 the viewport. Note that PCB coordinates put 0,0 in the upper left,
138 much like X does. */
139 static int view_left_x = 0, view_top_y = 0;
140 /* Denotes PCB units per screen pixel. Larger numbers mean zooming
141 out - the largest value means you are looking at the whole
142 board. */
143 static double view_zoom = MIL_TO_COORD (10), prev_view_zoom = MIL_TO_COORD (10);
144 static bool flip_x = 0, flip_y = 0;
145 static bool autofade = 0;
146 static bool crosshair_on = true;
148 /* ---------------------------------------------------------------------------
149 * some local prototypes
151 static hidGC lesstif_make_gc (void);
153 static void
154 ShowCrosshair (bool show)
156 if (crosshair_on == show)
157 return;
159 notify_crosshair_change (false);
160 if (Marked.status)
161 notify_mark_change (false);
163 crosshair_on = show;
165 notify_crosshair_change (true);
166 if (Marked.status)
167 notify_mark_change (true);
170 static int
171 flag_flipx (void *data)
173 return flip_x;
175 static int
176 flag_flipy (void *data)
178 return flip_y;
181 HID_Flag lesstif_main_flag_list[] = {
182 {"flip_x", flag_flipx, NULL},
183 {"flip_y", flag_flipy, NULL}
186 REGISTER_FLAGS (lesstif_main_flag_list)
188 /* This is the size of the current PCB work area. */
189 /* Use PCB->MaxWidth, PCB->MaxHeight. */
190 /* static int pcb_width, pcb_height; */
192 static Arg args[30];
193 static int n;
194 #define stdarg(t,v) XtSetArg(args[n], t, v), n++
197 static int use_private_colormap = 0;
198 static int stdin_listen = 0;
199 static char *background_image_file = 0;
200 char *lesstif_pcbmenu_path = "pcb-menu.res";
202 HID_Attribute lesstif_attribute_list[] = {
203 {"install", "Install private colormap",
204 HID_Boolean, 0, 0, {0, 0, 0}, 0, &use_private_colormap},
205 #define HA_colormap 0
207 /* %start-doc options "22 lesstif GUI Options"
208 @ftable @code
209 @item --listen
210 Listen for actions on stdin.
211 @end ftable
212 %end-doc
214 {"listen", "Listen on standard input for actions",
215 HID_Boolean, 0, 0, {0, 0, 0}, 0, &stdin_listen},
216 #define HA_listen 1
218 /* %start-doc options "22 lesstif GUI Options"
219 @ftable @code
220 @item --bg-image <string>
221 File name of an image to put into the background of the GUI canvas. The image must
222 be a color PPM image, in binary (not ASCII) format. It can be any size, and will be
223 automatically scaled to fit the canvas.
224 @end ftable
225 %end-doc
227 {"bg-image", "Background Image",
228 HID_String, 0, 0, {0, 0, 0}, 0, &background_image_file},
229 #define HA_bg_image 2
231 /* %start-doc options "22 lesstif GUI Options"
232 @ftable @code
233 @item --pcb-menu <string>
234 Location of the @file{pcb-menu.res} file which defines the menu for the lesstif GUI.
235 @end ftable
236 %end-doc
238 {"pcb-menu", "Location of pcb-menu.res file",
239 HID_String, 0, 0, {0, PCBLIBDIR "/pcb-menu.res", 0}, 0, &lesstif_pcbmenu_path}
240 #define HA_pcbmenu 3
243 REGISTER_ATTRIBUTES (lesstif_attribute_list)
245 static void lesstif_use_mask (enum mask_mode mode);
246 static void zoom_max ();
247 static void zoom_to (double factor, int x, int y);
248 static void zoom_by (double factor, int x, int y);
249 static void zoom_toggle (int x, int y);
250 static void pinout_callback (Widget, PinoutData *,
251 XmDrawingAreaCallbackStruct *);
252 static void pinout_unmap (Widget, PinoutData *, void *);
253 static void Pan (int mode, int x, int y);
255 /* Px converts view->pcb, Vx converts pcb->view */
257 static inline int
258 Vx (Coord x)
260 int rv = (x - view_left_x) / view_zoom + 0.5;
261 if (flip_x)
262 rv = view_width - rv;
263 return rv;
266 static inline int
267 Vy (Coord y)
269 int rv = (y - view_top_y) / view_zoom + 0.5;
270 if (flip_y)
271 rv = view_height - rv;
272 return rv;
275 static inline int
276 Vz (Coord z)
278 return z / view_zoom + 0.5;
281 static inline Coord
282 Px (int x)
284 if (flip_x)
285 x = view_width - x;
286 return x * view_zoom + view_left_x;
289 static inline Coord
290 Py (int y)
292 if (flip_y)
293 y = view_height - y;
294 return y * view_zoom + view_top_y;
297 static inline Coord
298 Pz (int z)
300 return z * view_zoom;
303 void
304 lesstif_coords_to_pcb (int vx, int vy, Coord *px, Coord *py)
306 *px = Px (vx);
307 *py = Py (vy);
310 Pixel
311 lesstif_parse_color (char *value)
313 XColor color;
314 if (XParseColor (display, colormap, value, &color))
315 if (XAllocColor (display, colormap, &color))
316 return color.pixel;
317 return 0;
320 static void
321 do_color (char *value, char *which)
323 XColor color;
324 if (XParseColor (display, colormap, value, &color))
325 if (XAllocColor (display, colormap, &color))
327 stdarg (which, color.pixel);
331 /* ------------------------------------------------------------ */
333 static char *
334 cur_clip ()
336 if (TEST_FLAG (ORTHOMOVEFLAG, PCB))
337 return "+";
338 if (TEST_FLAG (ALLDIRECTIONFLAG, PCB))
339 return "*";
340 if (PCB->Clipping == 0)
341 return "X";
342 if (PCB->Clipping == 1)
343 return "_/";
344 return "\\_";
347 /* Called from the core when it's busy doing something and we need to
348 indicate that to the user. */
349 static int
350 Busy(int argc, char **argv, Coord x, Coord y)
352 static Cursor busy_cursor = 0;
353 if (busy_cursor == 0)
354 busy_cursor = XCreateFontCursor (display, XC_watch);
355 XDefineCursor (display, window, busy_cursor);
356 XFlush(display);
357 old_cursor_mode = -1;
358 return 0;
361 /* ---------------------------------------------------------------------- */
363 /* Local actions. */
365 static int
366 PointCursor (int argc, char **argv, Coord x, Coord y)
368 if (argc > 0)
369 over_point = 1;
370 else
371 over_point = 0;
372 old_cursor_mode = -1;
373 return 0;
376 static int
377 PCBChanged (int argc, char **argv, Coord x, Coord y)
379 if (work_area == 0)
380 return 0;
381 /*pcb_printf("PCB Changed! %$mD\n", PCB->MaxWidth, PCB->MaxHeight); */
382 n = 0;
383 stdarg (XmNminimum, 0);
384 stdarg (XmNvalue, 0);
385 stdarg (XmNsliderSize, PCB->MaxWidth ? PCB->MaxWidth : 1);
386 stdarg (XmNmaximum, PCB->MaxWidth ? PCB->MaxWidth : 1);
387 XtSetValues (hscroll, args, n);
388 n = 0;
389 stdarg (XmNminimum, 0);
390 stdarg (XmNvalue, 0);
391 stdarg (XmNsliderSize, PCB->MaxHeight ? PCB->MaxHeight : 1);
392 stdarg (XmNmaximum, PCB->MaxHeight ? PCB->MaxHeight : 1);
393 XtSetValues (vscroll, args, n);
394 zoom_max ();
396 hid_action ("NetlistChanged");
397 hid_action ("LayersChanged");
398 hid_action ("RouteStylesChanged");
399 lesstif_sizes_reset ();
400 lesstif_update_layer_groups ();
401 while (pinouts)
402 pinout_unmap (0, pinouts, 0);
403 if (PCB->Filename)
405 char *cp = strrchr (PCB->Filename, '/');
406 n = 0;
407 stdarg (XmNtitle, cp ? cp + 1 : PCB->Filename);
408 XtSetValues (appwidget, args, n);
410 return 0;
414 static const char setunits_syntax[] =
415 "SetUnits(mm|mil)";
417 static const char setunits_help[] =
418 "Set the default measurement units.";
420 /* %start-doc actions SetUnits
422 @table @code
424 @item mil
425 Sets the display units to mils (1/1000 inch).
427 @item mm
428 Sets the display units to millimeters.
430 @end table
432 %end-doc */
434 static int
435 SetUnits (int argc, char **argv, Coord x, Coord y)
437 const Unit *new_unit;
438 if (argc == 0)
439 return 0;
440 new_unit = get_unit_struct (argv[0]);
441 if (new_unit != NULL && new_unit->allow != NO_PRINT)
443 Settings.grid_unit = new_unit;
444 Settings.increments = get_increments_struct (Settings.grid_unit->family);
445 AttributePut (PCB, "PCB::grid::unit", argv[0]);
447 lesstif_sizes_reset ();
448 lesstif_styles_update_values ();
449 return 0;
452 static const char zoom_syntax[] =
453 "Zoom()\n"
454 "Zoom(factor)";
456 static const char zoom_help[] =
457 "Various zoom factor changes.";
459 /* %start-doc actions Zoom
461 Changes the zoom (magnification) of the view of the board. If no
462 arguments are passed, the view is scaled such that the board just fits
463 inside the visible window (i.e. ``view all''). Otherwise,
464 @var{factor} specifies a change in zoom factor. It may be prefixed by
465 @code{+}, @code{-}, or @code{=} to change how the zoom factor is
466 modified. The @var{factor} is a floating point number, such as
467 @code{1.5} or @code{0.75}.
469 @table @code
471 @item +@var{factor}
472 Values greater than 1.0 cause the board to be drawn smaller; more of
473 the board will be visible. Values between 0.0 and 1.0 cause the board
474 to be drawn bigger; less of the board will be visible.
476 @item -@var{factor}
477 Values greater than 1.0 cause the board to be drawn bigger; less of
478 the board will be visible. Values between 0.0 and 1.0 cause the board
479 to be drawn smaller; more of the board will be visible.
481 @item =@var{factor}
483 The @var{factor} is an absolute zoom factor; the unit for this value
484 is "PCB units per screen pixel". Since PCB units are 0.01 mil, a
485 @var{factor} of 1000 means 10 mils (0.01 in) per pixel, or 100 DPI,
486 about the actual resolution of most screens - resulting in an "actual
487 size" board. Similarly, a @var{factor} of 100 gives you a 10x actual
488 size.
490 @end table
492 Note that zoom factors of zero are silently ignored.
494 %end-doc */
496 static int
497 ZoomAction (int argc, char **argv, Coord x, Coord y)
499 const char *vp;
500 double v;
501 if (x == 0 && y == 0)
503 x = view_width / 2;
504 y = view_height / 2;
506 else
508 x = Vx (x);
509 y = Vy (y);
511 if (argc < 1)
513 zoom_max ();
514 return 0;
516 vp = argv[0];
517 if (strcasecmp (vp, "toggle") == 0)
519 zoom_toggle (x, y);
520 return 0;
522 if (*vp == '+' || *vp == '-' || *vp == '=')
523 vp++;
524 v = g_ascii_strtod (vp, 0);
525 if (v <= 0)
526 return 1;
527 switch (argv[0][0])
529 case '-':
530 zoom_by (1 / v, x, y);
531 break;
532 default:
533 case '+':
534 zoom_by (v, x, y);
535 break;
536 case '=':
537 zoom_to (v, x, y);
538 break;
540 return 0;
543 static int pan_thumb_mode;
545 static int
546 PanAction (int argc, char **argv, Coord x, Coord y)
548 int mode;
550 if (argc < 1)
551 return 1;
553 if (argc == 2)
555 pan_thumb_mode = (strcasecmp (argv[0], "thumb") == 0) ? 1 : 0;
556 mode = atoi (argv[1]);
558 else
560 pan_thumb_mode = 0;
561 mode = atoi (argv[0]);
563 Pan (mode, Vx(x), Vy(y));
565 return 0;
568 static const char swapsides_syntax[] =
569 "SwapSides(|v|h|r)";
571 static const char swapsides_help[] =
572 "Swaps the side of the board you're looking at.";
574 /* %start-doc actions SwapSides
576 This action changes the way you view the board.
578 @table @code
580 @item v
581 Flips the board over vertically (up/down).
583 @item h
584 Flips the board over horizontally (left/right), like flipping pages in
585 a book.
587 @item r
588 Rotates the board 180 degrees without changing sides.
590 @end table
592 If no argument is given, the board isn't moved but the opposite side
593 is shown.
595 Normally, this action changes which pads and silk layer are drawn as
596 true silk, and which are drawn as the "invisible" layer. It also
597 determines which solder mask you see.
599 As a special case, if the layer group for the side you're looking at
600 is visible and currently active, and the layer group for the opposite
601 is not visible (i.e. disabled), then this action will also swap which
602 layer group is visible and active, effectively swapping the ``working
603 side'' of the board.
605 %end-doc */
607 static int
608 group_showing (int g, int *c)
610 int i, l;
611 *c = PCB->LayerGroups.Entries[g][0];
612 for (i=0; i<PCB->LayerGroups.Number[g]; i++)
614 l = PCB->LayerGroups.Entries[g][i];
615 if (l >= 0 && l < max_copper_layer)
617 *c = l;
618 if (PCB->Data->Layer[l].On)
619 return 1;
622 return 0;
625 static int
626 SwapSides (int argc, char **argv, Coord x, Coord y)
628 int old_shown_side = Settings.ShowBottomSide;
629 int top_group = GetLayerGroupNumberBySide (TOP_SIDE);
630 int bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
631 int active_group = GetLayerGroupNumberByNumber (LayerStack[0]);
632 int top_layer;
633 int bottom_layer;
634 int top_showing = group_showing (top_group, &top_layer);
635 int bottom_showing = group_showing (bottom_group, &bottom_layer);
637 if (argc > 0)
639 switch (argv[0][0]) {
640 case 'h':
641 case 'H':
642 flip_x = ! flip_x;
643 break;
644 case 'v':
645 case 'V':
646 flip_y = ! flip_y;
647 break;
648 case 'r':
649 case 'R':
650 flip_x = ! flip_x;
651 flip_y = ! flip_y;
652 break;
653 default:
654 return 1;
656 /* SwapSides will swap this */
657 Settings.ShowBottomSide = (flip_x == flip_y);
660 n = 0;
661 if (flip_x)
662 stdarg (XmNprocessingDirection, XmMAX_ON_LEFT);
663 else
664 stdarg (XmNprocessingDirection, XmMAX_ON_RIGHT);
665 XtSetValues (hscroll, args, n);
667 n = 0;
668 if (flip_y)
669 stdarg (XmNprocessingDirection, XmMAX_ON_TOP);
670 else
671 stdarg (XmNprocessingDirection, XmMAX_ON_BOTTOM);
672 XtSetValues (vscroll, args, n);
674 Settings.ShowBottomSide = !Settings.ShowBottomSide;
676 /* The idea is that if we're looking at the front side and the front
677 layer is active (or visa versa), switching sides should switch
678 layers too. We used to only do this if the other layer wasn't
679 shown, but we now do it always. Change it back if users get
680 confused. */
681 if (Settings.ShowBottomSide != old_shown_side)
683 if (Settings.ShowBottomSide)
685 if (active_group == top_group)
687 if (top_showing && !bottom_showing)
688 ChangeGroupVisibility (top_layer, 0, 0);
689 ChangeGroupVisibility (bottom_layer, 1, 1);
692 else
694 if (active_group == bottom_group)
696 if (bottom_showing && !top_showing)
697 ChangeGroupVisibility (bottom_layer, 0, 0);
698 ChangeGroupVisibility (top_layer, 1, 1);
702 lesstif_invalidate_all ();
703 return 0;
706 static Widget m_cmd = 0, m_cmd_label;
708 static void
709 command_callback (Widget w, XtPointer uptr, XmTextVerifyCallbackStruct * cbs)
711 char *s;
712 switch (cbs->reason)
714 case XmCR_ACTIVATE:
715 s = XmTextGetString (w);
716 lesstif_show_crosshair (0);
717 hid_parse_command (s);
718 XtFree (s);
719 XmTextSetString (w, "");
720 case XmCR_LOSING_FOCUS:
721 XtUnmanageChild (m_cmd);
722 XtUnmanageChild (m_cmd_label);
723 break;
727 static void
728 command_event_handler (Widget w, XtPointer p, XEvent * e, Boolean * cont)
730 char buf[10];
731 KeySym sym;
733 switch (e->type)
735 case KeyPress:
736 XLookupString ((XKeyEvent *)e, buf, sizeof (buf), &sym, NULL);
737 switch (sym)
739 case XK_Escape:
740 XtUnmanageChild (m_cmd);
741 XtUnmanageChild (m_cmd_label);
742 XmTextSetString (w, "");
743 *cont = False;
744 break;
746 break;
750 static const char command_syntax[] =
751 "Command()";
753 static const char command_help[] =
754 "Displays the command line input window.";
756 /* %start-doc actions Command
758 The command window allows the user to manually enter actions to be
759 executed. Action syntax can be done one of two ways:
761 @itemize @bullet
763 @item
764 Follow the action name by an open parenthesis, arguments separated by
765 commas, end with a close parenthesis. Example: @code{Abc(1,2,3)}
767 @item
768 Separate the action name and arguments by spaces. Example: @code{Abc
769 1 2 3}.
771 @end itemize
773 The first option allows you to have arguments with spaces in them,
774 but the second is more ``natural'' to type for most people.
776 Note that action names are not case sensitive, but arguments normally
777 are. However, most actions will check for ``keywords'' in a case
778 insensitive way.
780 There are three ways to finish with the command window. If you press
781 the @code{Enter} key, the command is invoked, the window goes away,
782 and the next time you bring up the command window it's empty. If you
783 press the @code{Esc} key, the window goes away without invoking
784 anything, and the next time you bring up the command window it's
785 empty. If you change focus away from the command window (i.e. click
786 on some other window), the command window goes away but the next time
787 you bring it up it resumes entering the command you were entering
788 before.
790 %end-doc */
792 static int
793 Command (int argc, char **argv, Coord x, Coord y)
795 XtManageChild (m_cmd_label);
796 XtManageChild (m_cmd);
797 XmProcessTraversal (m_cmd, XmTRAVERSE_CURRENT);
798 return 0;
801 static const char benchmark_syntax[] =
802 "Benchmark()";
804 static const char benchmark_help[] =
805 "Benchmark the GUI speed.";
807 /* %start-doc actions Benchmark
809 This action is used to speed-test the Lesstif graphics subsystem. It
810 redraws the current screen as many times as possible in ten seconds.
811 It reports the amount of time needed to draw the screen once.
813 %end-doc */
815 static int
816 Benchmark (int argc, char **argv, Coord x, Coord y)
818 int i = 0;
819 time_t start, end;
820 BoxType region;
821 Drawable save_main;
823 save_main = main_pixmap;
824 main_pixmap = window;
826 region.X1 = 0;
827 region.Y1 = 0;
828 region.X2 = PCB->MaxWidth;
829 region.Y2 = PCB->MaxHeight;
831 pixmap = window;
832 XSync (display, 0);
833 time (&start);
836 XFillRectangle (display, pixmap, bg_gc, 0, 0, view_width, view_height);
837 hid_expose_callback (&lesstif_hid, &region, 0);
838 XSync (display, 0);
839 time (&end);
840 i++;
842 while (end - start < 10);
844 printf ("%g redraws per second\n", i / 10.0);
846 main_pixmap = save_main;
847 return 0;
850 static int
851 Center(int argc, char **argv, Coord x, Coord y)
853 x = GridFit (x, PCB->Grid, PCB->GridOffsetX);
854 y = GridFit (y, PCB->Grid, PCB->GridOffsetY);
855 view_left_x = x - (view_width * view_zoom) / 2;
856 view_top_y = y - (view_height * view_zoom) / 2;
857 lesstif_pan_fixup ();
858 /* Move the pointer to the center of the window, but only if it's
859 currently within the window already. Watch out for edges,
860 though. */
861 XWarpPointer (display, window, window, 0, 0, view_width, view_height,
862 Vx(x), Vy(y));
863 return 0;
866 static const char cursor_syntax[] =
867 "Cursor(Type,DeltaUp,DeltaRight,Units)";
869 static const char cursor_help[] =
870 "Move the cursor.";
872 /* %start-doc actions Cursor
874 This action moves the mouse cursor. Unlike other actions which take
875 coordinates, this action's coordinates are always relative to the
876 user's view of the board. Thus, a positive @var{DeltaUp} may move the
877 cursor towards the board origin if the board is inverted.
879 Type is one of @samp{Pan} or @samp{Warp}. @samp{Pan} causes the
880 viewport to move such that the crosshair is under the mouse cursor.
881 @samp{Warp} causes the mouse cursor to move to be above the crosshair.
883 @var{Units} can be one of the following:
885 @table @samp
887 @item mil
888 @itemx mm
889 The cursor is moved by that amount, in board units.
891 @item grid
892 The cursor is moved by that many grid points.
894 @item view
895 The values are percentages of the viewport's view. Thus, a pan of
896 @samp{100} would scroll the viewport by exactly the width of the
897 current view.
899 @item board
900 The values are percentages of the board size. Thus, a move of
901 @samp{50,50} moves you halfway across the board.
903 @end table
905 %end-doc */
907 static int
908 CursorAction(int argc, char **argv, Coord x, Coord y)
910 UnitList extra_units_x = {
911 { "grid", PCB->Grid, 0 },
912 { "view", Pz(view_width), UNIT_PERCENT },
913 { "board", PCB->MaxWidth, UNIT_PERCENT },
914 { "", 0, 0 }
916 UnitList extra_units_y = {
917 { "grid", PCB->Grid, 0 },
918 { "view", Pz(view_height), UNIT_PERCENT },
919 { "board", PCB->MaxHeight, UNIT_PERCENT },
920 { "", 0, 0 }
922 int pan_warp = HID_SC_DO_NOTHING;
923 double dx, dy;
925 if (argc != 4)
926 AFAIL(cursor);
928 if (strcasecmp (argv[0], "pan") == 0)
929 pan_warp = HID_SC_PAN_VIEWPORT;
930 else if (strcasecmp (argv[0], "warp") == 0)
931 pan_warp = HID_SC_WARP_POINTER;
932 else
933 AFAIL(cursor);
935 dx = GetValueEx (argv[1], argv[3], NULL, extra_units_x, "mil");
936 if (flip_x)
937 dx = -dx;
938 dy = GetValueEx (argv[2], argv[3], NULL, extra_units_y, "mil");
939 if (!flip_y)
940 dy = -dy;
942 EventMoveCrosshair (Crosshair.X + dx, Crosshair.Y + dy);
943 gui->set_crosshair (Crosshair.X, Crosshair.Y, pan_warp);
945 return 0;
948 HID_Action lesstif_main_action_list[] = {
949 {"PCBChanged", 0, PCBChanged,
950 pcbchanged_help, pcbchanged_syntax},
951 {"SetUnits", 0, SetUnits,
952 setunits_help, setunits_syntax},
953 {"Zoom", "Click on a place to zoom in", ZoomAction,
954 zoom_help, zoom_syntax},
955 {"Pan", "Click on a place to pan", PanAction,
956 zoom_help, zoom_syntax},
957 {"SwapSides", 0, SwapSides,
958 swapsides_help, swapsides_syntax},
959 {"Command", 0, Command,
960 command_help, command_syntax},
961 {"Benchmark", 0, Benchmark,
962 benchmark_help, benchmark_syntax},
963 {"PointCursor", 0, PointCursor},
964 {"Center", "Click on a location to center", Center},
965 {"Busy", 0, Busy},
966 {"Cursor", 0, CursorAction,
967 cursor_help, cursor_syntax},
970 REGISTER_ACTIONS (lesstif_main_action_list)
973 /* ----------------------------------------------------------------------
974 * redraws the background image
977 static int bg_w, bg_h, bgi_w, bgi_h;
978 static Pixel **bg = 0;
979 static XImage *bgi = 0;
980 static enum {
981 PT_unknown,
982 PT_RGB565,
983 PT_RGB888
984 } pixel_type = PT_unknown;
986 static void
987 LoadBackgroundFile (FILE *f, char *filename)
989 XVisualInfo vinfot, *vinfo;
990 Visual *vis;
991 int c, r, b;
992 int i, nret;
993 int p[3], rows, cols, maxval;
995 if (fgetc(f) != 'P')
997 printf("bgimage: %s signature not P6\n", filename);
998 return;
1000 if (fgetc(f) != '6')
1002 printf("bgimage: %s signature not P6\n", filename);
1003 return;
1005 for (i=0; i<3; i++)
1007 do {
1008 b = fgetc(f);
1009 if (feof(f))
1010 return;
1011 if (b == '#')
1012 while (!feof(f) && b != '\n')
1013 b = fgetc(f);
1014 } while (!isdigit(b));
1015 p[i] = b - '0';
1016 while (isdigit(b = fgetc(f)))
1017 p[i] = p[i]*10 + b - '0';
1019 bg_w = cols = p[0];
1020 bg_h = rows = p[1];
1021 maxval = p[2];
1023 setbuf(stdout, 0);
1024 bg = (Pixel **) malloc (rows * sizeof (Pixel *));
1025 if (!bg)
1027 printf("Out of memory loading %s\n", filename);
1028 return;
1030 for (i=0; i<rows; i++)
1032 bg[i] = (Pixel *) malloc (cols * sizeof (Pixel));
1033 if (!bg[i])
1035 printf("Out of memory loading %s\n", filename);
1036 while (--i >= 0)
1037 free (bg[i]);
1038 free (bg);
1039 bg = 0;
1040 return;
1044 vis = DefaultVisual (display, DefaultScreen(display));
1046 vinfot.visualid = XVisualIDFromVisual(vis);
1047 vinfo = XGetVisualInfo (display, VisualIDMask, &vinfot, &nret);
1049 #if 0
1050 /* If you want to support more visuals below, you'll probably need
1051 this. */
1052 printf("vinfo: rm %04x gm %04x bm %04x depth %d class %d\n",
1053 vinfo->red_mask, vinfo->green_mask, vinfo->blue_mask,
1054 vinfo->depth, vinfo->class);
1055 #endif
1057 #if !defined(__cplusplus)
1058 #define c_class class
1059 #endif
1061 if (vinfo->c_class == TrueColor
1062 && vinfo->depth == 16
1063 && vinfo->red_mask == 0xf800
1064 && vinfo->green_mask == 0x07e0
1065 && vinfo->blue_mask == 0x001f)
1066 pixel_type = PT_RGB565;
1068 if (vinfo->c_class == TrueColor
1069 && vinfo->depth == 24
1070 && vinfo->red_mask == 0xff0000
1071 && vinfo->green_mask == 0x00ff00
1072 && vinfo->blue_mask == 0x0000ff)
1073 pixel_type = PT_RGB888;
1075 for (r=0; r<rows; r++)
1077 for (c=0; c<cols; c++)
1079 XColor pix;
1080 unsigned int pr = (unsigned)fgetc(f);
1081 unsigned int pg = (unsigned)fgetc(f);
1082 unsigned int pb = (unsigned)fgetc(f);
1084 switch (pixel_type)
1086 case PT_unknown:
1087 pix.red = pr * 65535 / maxval;
1088 pix.green = pg * 65535 / maxval;
1089 pix.blue = pb * 65535 / maxval;
1090 pix.flags = DoRed | DoGreen | DoBlue;
1091 XAllocColor (display, colormap, &pix);
1092 bg[r][c] = pix.pixel;
1093 break;
1094 case PT_RGB565:
1095 bg[r][c] = (pr>>3)<<11 | (pg>>2)<<5 | (pb>>3);
1096 break;
1097 case PT_RGB888:
1098 bg[r][c] = (pr << 16) | (pg << 8) | (pb);
1099 break;
1105 void
1106 LoadBackgroundImage (char *filename)
1108 FILE *f = fopen(filename, "rb");
1109 if (!f)
1111 if (NSTRCMP (filename, "pcb-background.ppm"))
1112 perror(filename);
1113 return;
1115 LoadBackgroundFile (f, filename);
1116 fclose(f);
1119 static void
1120 DrawBackgroundImage ()
1122 int x, y, w, h;
1123 double xscale, yscale;
1124 int pcbwidth = PCB->MaxWidth / view_zoom;
1125 int pcbheight = PCB->MaxHeight / view_zoom;
1127 if (!window || !bg)
1128 return;
1130 if (!bgi || view_width != bgi_w || view_height != bgi_h)
1132 if (bgi)
1133 XDestroyImage (bgi);
1134 /* Cheat - get the image, which sets up the format too. */
1135 bgi = XGetImage (XtDisplay(work_area),
1136 window,
1137 0, 0, view_width, view_height,
1138 -1, ZPixmap);
1139 bgi_w = view_width;
1140 bgi_h = view_height;
1143 w = MIN (view_width, pcbwidth);
1144 h = MIN (view_height, pcbheight);
1146 xscale = (double)bg_w / PCB->MaxWidth;
1147 yscale = (double)bg_h / PCB->MaxHeight;
1149 for (y=0; y<h; y++)
1151 int pr = Py(y);
1152 int ir = pr * yscale;
1153 for (x=0; x<w; x++)
1155 int pc = Px(x);
1156 int ic = pc * xscale;
1157 XPutPixel (bgi, x, y, bg[ir][ic]);
1160 XPutImage(display, main_pixmap, bg_gc,
1161 bgi,
1162 0, 0, 0, 0, w, h);
1164 /* ---------------------------------------------------------------------- */
1166 static HID_Attribute *
1167 lesstif_get_export_options (int *n)
1169 *n = sizeof (lesstif_attribute_list) / sizeof (HID_Attribute);
1170 return lesstif_attribute_list;
1173 static void
1174 set_scroll (Widget s, int pos, int view, int pcb)
1176 int sz = view * view_zoom;
1177 if (sz > pcb)
1178 sz = pcb;
1179 n = 0;
1180 stdarg (XmNvalue, pos);
1181 stdarg (XmNsliderSize, sz);
1182 stdarg (XmNincrement, view_zoom);
1183 stdarg (XmNpageIncrement, sz);
1184 stdarg (XmNmaximum, pcb);
1185 XtSetValues (s, args, n);
1188 void
1189 lesstif_pan_fixup ()
1191 #if 0
1192 if (view_left_x > PCB->MaxWidth - (view_width * view_zoom))
1193 view_left_x = PCB->MaxWidth - (view_width * view_zoom);
1194 if (view_top_y > PCB->MaxHeight - (view_height * view_zoom))
1195 view_top_y = PCB->MaxHeight - (view_height * view_zoom);
1196 if (view_left_x < 0)
1197 view_left_x = 0;
1198 if (view_top_y < 0)
1199 view_top_y = 0;
1200 if (view_width * view_zoom > PCB->MaxWidth
1201 && view_height * view_zoom > PCB->MaxHeight)
1203 zoom_by (1, 0, 0);
1204 return;
1206 #endif
1208 set_scroll (hscroll, view_left_x, view_width, PCB->MaxWidth);
1209 set_scroll (vscroll, view_top_y, view_height, PCB->MaxHeight);
1211 lesstif_invalidate_all ();
1214 static void
1215 zoom_max ()
1217 double new_zoom = PCB->MaxWidth / view_width;
1218 if (new_zoom < PCB->MaxHeight / view_height)
1219 new_zoom = PCB->MaxHeight / view_height;
1221 view_left_x = -(view_width * new_zoom - PCB->MaxWidth) / 2;
1222 view_top_y = -(view_height * new_zoom - PCB->MaxHeight) / 2;
1223 view_zoom = new_zoom;
1224 pixel_slop = view_zoom;
1225 lesstif_pan_fixup ();
1228 static void
1229 zoom_to (double new_zoom, int x, int y)
1231 double max_zoom, xfrac, yfrac;
1232 int cx, cy;
1234 xfrac = (double) x / (double) view_width;
1235 yfrac = (double) y / (double) view_height;
1237 if (flip_x)
1238 xfrac = 1-xfrac;
1239 if (flip_y)
1240 yfrac = 1-yfrac;
1242 max_zoom = PCB->MaxWidth / view_width;
1243 if (max_zoom < PCB->MaxHeight / view_height)
1244 max_zoom = PCB->MaxHeight / view_height;
1246 max_zoom *= MAX_ZOOM_SCALE;
1248 if (new_zoom < 1)
1249 new_zoom = 1;
1250 if (new_zoom > max_zoom)
1251 new_zoom = max_zoom;
1253 cx = view_left_x + view_width * xfrac * view_zoom;
1254 cy = view_top_y + view_height * yfrac * view_zoom;
1256 if (view_zoom != new_zoom)
1258 view_zoom = new_zoom;
1259 pixel_slop = view_zoom;
1261 view_left_x = cx - view_width * xfrac * view_zoom;
1262 view_top_y = cy - view_height * yfrac * view_zoom;
1264 lesstif_pan_fixup ();
1267 static void
1268 zoom_toggle(int x, int y)
1270 double tmp;
1272 tmp = prev_view_zoom;
1273 prev_view_zoom = view_zoom;
1274 zoom_to(tmp, x, y);
1277 void
1278 zoom_by (double factor, int x, int y)
1280 zoom_to (view_zoom * factor, x, y);
1283 static int panning = 0;
1284 static int shift_pressed;
1285 static int ctrl_pressed;
1286 static int alt_pressed;
1288 /* X and Y are in screen coordinates. */
1289 static void
1290 Pan (int mode, int x, int y)
1292 static int ox, oy;
1293 static int opx, opy;
1295 panning = mode;
1296 /* This is for ctrl-pan, where the viewport's position is directly
1297 proportional to the cursor position in the window (like the Xaw
1298 thumb panner) */
1299 if (pan_thumb_mode)
1301 opx = x * PCB->MaxWidth / view_width;
1302 opy = y * PCB->MaxHeight / view_height;
1303 if (flip_x)
1304 opx = PCB->MaxWidth - opx;
1305 if (flip_y)
1306 opy = PCB->MaxHeight - opy;
1307 view_left_x = opx - view_width / 2 * view_zoom;
1308 view_top_y = opy - view_height / 2 * view_zoom;
1309 lesstif_pan_fixup ();
1311 /* This is the start of a regular pan. On the first click, we
1312 remember the coordinates where we "grabbed" the screen. */
1313 else if (mode == 1)
1315 ox = x;
1316 oy = y;
1317 opx = view_left_x;
1318 opy = view_top_y;
1320 /* continued drag, we calculate how far we've moved the cursor and
1321 set the position accordingly. */
1322 else
1324 if (flip_x)
1325 view_left_x = opx + (x - ox) * view_zoom;
1326 else
1327 view_left_x = opx - (x - ox) * view_zoom;
1328 if (flip_y)
1329 view_top_y = opy + (y - oy) * view_zoom;
1330 else
1331 view_top_y = opy - (y - oy) * view_zoom;
1332 lesstif_pan_fixup ();
1336 static void
1337 mod_changed (XKeyEvent * e, int set)
1339 switch (XKeycodeToKeysym (display, e->keycode, 0))
1341 case XK_Shift_L:
1342 case XK_Shift_R:
1343 shift_pressed = set;
1344 break;
1345 case XK_Control_L:
1346 case XK_Control_R:
1347 ctrl_pressed = set;
1348 break;
1349 #ifdef __APPLE__
1350 case XK_Mode_switch:
1351 #else
1352 case XK_Alt_L:
1353 case XK_Alt_R:
1354 #endif
1355 alt_pressed = set;
1356 break;
1357 default:
1358 // to include the Apple keyboard left and right command keys use XK_Meta_L and XK_Meta_R respectivly.
1359 return;
1361 in_move_event = 1;
1362 notify_crosshair_change (false);
1363 if (panning)
1364 Pan (2, e->x, e->y);
1365 EventMoveCrosshair (Px (e->x), Py (e->y));
1366 AdjustAttachedObjects ();
1367 notify_crosshair_change (true);
1368 in_move_event = 0;
1371 static void
1372 work_area_input (Widget w, XtPointer v, XEvent * e, Boolean * ctd)
1374 static int pressed_button = 0;
1376 show_crosshair (0);
1377 switch (e->type)
1379 case KeyPress:
1380 mod_changed (&(e->xkey), 1);
1381 if (lesstif_key_event (&(e->xkey)))
1382 return;
1383 break;
1385 case KeyRelease:
1386 mod_changed (&(e->xkey), 0);
1387 break;
1389 case ButtonPress:
1391 int mods;
1392 if (pressed_button)
1393 return;
1394 /*printf("click %d\n", e->xbutton.button); */
1395 if (lesstif_button_event (w, e))
1396 return;
1398 notify_crosshair_change (false);
1399 pressed_button = e->xbutton.button;
1400 mods = ((e->xbutton.state & ShiftMask) ? M_Shift : 0)
1401 + ((e->xbutton.state & ControlMask) ? M_Ctrl : 0)
1402 #ifdef __APPLE__
1403 + ((e->xbutton.state & (1<<13)) ? M_Alt : 0);
1404 #else
1405 + ((e->xbutton.state & Mod1Mask) ? M_Alt : 0);
1406 #endif
1407 do_mouse_action(e->xbutton.button, mods);
1408 notify_crosshair_change (true);
1409 break;
1412 case ButtonRelease:
1414 int mods;
1415 if (e->xbutton.button != pressed_button)
1416 return;
1417 lesstif_button_event (w, e);
1418 notify_crosshair_change (false);
1419 pressed_button = 0;
1420 mods = ((e->xbutton.state & ShiftMask) ? M_Shift : 0)
1421 + ((e->xbutton.state & ControlMask) ? M_Ctrl : 0)
1422 #ifdef __APPLE__
1423 + ((e->xbutton.state & (1<<13)) ? M_Alt : 0)
1424 #else
1425 + ((e->xbutton.state & Mod1Mask) ? M_Alt : 0)
1426 #endif
1427 + M_Release;
1428 do_mouse_action (e->xbutton.button, mods);
1429 notify_crosshair_change (true);
1430 break;
1433 case MotionNotify:
1435 Window root, child;
1436 unsigned int keys_buttons;
1437 int root_x, root_y, pos_x, pos_y;
1438 while (XCheckMaskEvent (display, PointerMotionMask, e));
1439 XQueryPointer (display, e->xmotion.window, &root, &child,
1440 &root_x, &root_y, &pos_x, &pos_y, &keys_buttons);
1441 shift_pressed = (keys_buttons & ShiftMask);
1442 ctrl_pressed = (keys_buttons & ControlMask);
1443 #ifdef __APPLE__
1444 alt_pressed = (keys_buttons & (1<<13));
1445 #else
1446 alt_pressed = (keys_buttons & Mod1Mask);
1447 #endif
1448 /*pcb_printf("m %#mS %#mS\n", Px(e->xmotion.x), Py(e->xmotion.y)); */
1449 crosshair_in_window = 1;
1450 in_move_event = 1;
1451 if (panning)
1452 Pan (2, pos_x, pos_y);
1453 EventMoveCrosshair (Px (pos_x), Py (pos_y));
1454 in_move_event = 0;
1456 break;
1458 case LeaveNotify:
1459 crosshair_in_window = 0;
1460 ShowCrosshair (false);
1461 need_idle_proc ();
1462 break;
1464 case EnterNotify:
1465 crosshair_in_window = 1;
1466 in_move_event = 1;
1467 EventMoveCrosshair (Px (e->xcrossing.x), Py (e->xcrossing.y));
1468 ShowCrosshair (true);
1469 in_move_event = 0;
1470 need_idle_proc ();
1471 break;
1473 default:
1474 printf ("work_area: unknown event %d\n", e->type);
1475 break;
1479 static void
1480 draw_right_cross (GC xor_gc, int x, int y,
1481 int view_width, int view_height)
1483 XDrawLine (display, window, xor_gc, 0, y, view_width, y);
1484 XDrawLine (display, window, xor_gc, x, 0, x, view_height);
1487 static void
1488 draw_slanted_cross (GC xor_gc, int x, int y,
1489 int view_width, int view_height)
1491 int x0, y0, x1, y1;
1493 x0 = x + (view_height - y);
1494 x0 = MAX(0, MIN (x0, view_width));
1495 x1 = x - y;
1496 x1 = MAX(0, MIN (x1, view_width));
1497 y0 = y + (view_width - x);
1498 y0 = MAX(0, MIN (y0, view_height));
1499 y1 = y - x;
1500 y1 = MAX(0, MIN (y1, view_height));
1501 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1502 x0 = x - (view_height - y);
1503 x0 = MAX(0, MIN (x0, view_width));
1504 x1 = x + y;
1505 x1 = MAX(0, MIN (x1, view_width));
1506 y0 = y + x;
1507 y0 = MAX(0, MIN (y0, view_height));
1508 y1 = y - (view_width - x);
1509 y1 = MAX(0, MIN (y1, view_height));
1510 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1513 static void
1514 draw_dozen_cross (GC xor_gc, int x, int y,
1515 int view_width, int view_height)
1517 int x0, y0, x1, y1;
1518 double tan60 = sqrt (3);
1520 x0 = x + (view_height - y) / tan60;
1521 x0 = MAX(0, MIN (x0, view_width));
1522 x1 = x - y / tan60;
1523 x1 = MAX(0, MIN (x1, view_width));
1524 y0 = y + (view_width - x) * tan60;
1525 y0 = MAX(0, MIN (y0, view_height));
1526 y1 = y - x * tan60;
1527 y1 = MAX(0, MIN (y1, view_height));
1528 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1530 x0 = x + (view_height - y) * tan60;
1531 x0 = MAX(0, MIN (x0, view_width));
1532 x1 = x - y * tan60;
1533 x1 = MAX(0, MIN (x1, view_width));
1534 y0 = y + (view_width - x) / tan60;
1535 y0 = MAX(0, MIN (y0, view_height));
1536 y1 = y - x / tan60;
1537 y1 = MAX(0, MIN (y1, view_height));
1538 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1540 x0 = x - (view_height - y) / tan60;
1541 x0 = MAX(0, MIN (x0, view_width));
1542 x1 = x + y / tan60;
1543 x1 = MAX(0, MIN (x1, view_width));
1544 y0 = y + x * tan60;
1545 y0 = MAX(0, MIN (y0, view_height));
1546 y1 = y - (view_width - x) * tan60;
1547 y1 = MAX(0, MIN (y1, view_height));
1548 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1550 x0 = x - (view_height - y) * tan60;
1551 x0 = MAX(0, MIN (x0, view_width));
1552 x1 = x + y * tan60;
1553 x1 = MAX(0, MIN (x1, view_width));
1554 y0 = y + x / tan60;
1555 y0 = MAX(0, MIN (y0, view_height));
1556 y1 = y - (view_width - x) / tan60;
1557 y1 = MAX(0, MIN (y1, view_height));
1558 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1561 static void
1562 draw_crosshair (GC xor_gc, int x, int y,
1563 int view_width, int view_height)
1565 draw_right_cross (xor_gc, x, y, view_width, view_height);
1566 if (Crosshair.shape == Union_Jack_Crosshair_Shape)
1567 draw_slanted_cross (xor_gc, x, y, view_width, view_height);
1568 if (Crosshair.shape == Dozen_Crosshair_Shape)
1569 draw_dozen_cross (xor_gc, x, y, view_width, view_height);
1571 void
1572 lesstif_show_crosshair (int show)
1574 static int showing = 0;
1575 static int sx, sy;
1576 static GC xor_gc = 0;
1577 Pixel crosshair_color;
1579 if (!crosshair_in_window || !window)
1580 return;
1581 if (xor_gc == 0)
1583 crosshair_color = lesstif_parse_color (Settings.CrosshairColor) ^ bgcolor;
1584 xor_gc = XCreateGC (display, window, 0, 0);
1585 XSetFunction (display, xor_gc, GXxor);
1586 XSetForeground (display, xor_gc, crosshair_color);
1588 if (show == showing)
1589 return;
1590 if (show)
1592 sx = Vx (crosshair_x);
1593 sy = Vy (crosshair_y);
1595 else
1596 need_idle_proc ();
1597 draw_crosshair (xor_gc, sx, sy, view_width, view_height);
1598 showing = show;
1601 static void
1602 work_area_expose (Widget work_area, void *me,
1603 XmDrawingAreaCallbackStruct * cbs)
1605 XExposeEvent *e;
1607 show_crosshair (0);
1608 e = &(cbs->event->xexpose);
1609 XSetFunction (display, my_gc, GXcopy);
1610 XCopyArea (display, main_pixmap, window, my_gc,
1611 e->x, e->y, e->width, e->height, e->x, e->y);
1612 show_crosshair (1);
1615 static void
1616 scroll_callback (Widget scroll, int *view_dim,
1617 XmScrollBarCallbackStruct * cbs)
1619 *view_dim = cbs->value;
1620 lesstif_invalidate_all ();
1623 static void
1624 work_area_make_pixmaps (Dimension width, Dimension height)
1626 if (main_pixmap)
1627 XFreePixmap (display, main_pixmap);
1628 main_pixmap =
1629 XCreatePixmap (display, window, width, height,
1630 XDefaultDepth (display, screen));
1632 if (mask_pixmap)
1633 XFreePixmap (display, mask_pixmap);
1634 mask_pixmap =
1635 XCreatePixmap (display, window, width, height,
1636 XDefaultDepth (display, screen));
1637 #ifdef HAVE_XRENDER
1638 if (main_picture)
1640 XRenderFreePicture (display, main_picture);
1641 main_picture = 0;
1643 if (mask_picture)
1645 XRenderFreePicture (display, mask_picture);
1646 mask_picture = 0;
1648 if (use_xrender)
1650 main_picture = XRenderCreatePicture (display, main_pixmap,
1651 XRenderFindVisualFormat(display,
1652 DefaultVisual(display, screen)), 0, 0);
1653 mask_picture = XRenderCreatePicture (display, mask_pixmap,
1654 XRenderFindVisualFormat(display,
1655 DefaultVisual(display, screen)), 0, 0);
1656 if (!main_picture || !mask_picture)
1657 use_xrender = 0;
1659 #endif /* HAVE_XRENDER */
1661 if (mask_bitmap)
1662 XFreePixmap (display, mask_bitmap);
1663 mask_bitmap = XCreatePixmap (display, window, width, height, 1);
1665 pixmap = use_mask ? main_pixmap : mask_pixmap;
1666 pixmap_w = width;
1667 pixmap_h = height;
1670 static void
1671 work_area_resize (Widget work_area, void *me,
1672 XmDrawingAreaCallbackStruct * cbs)
1674 XColor color;
1675 Dimension width, height;
1677 show_crosshair (0);
1679 n = 0;
1680 stdarg (XtNwidth, &width);
1681 stdarg (XtNheight, &height);
1682 stdarg (XmNbackground, &bgcolor);
1683 XtGetValues (work_area, args, n);
1684 view_width = width;
1685 view_height = height;
1687 color.pixel = bgcolor;
1688 XQueryColor (display, colormap, &color);
1689 bgred = color.red;
1690 bggreen = color.green;
1691 bgblue = color.blue;
1693 if (!window)
1694 return;
1696 work_area_make_pixmaps (view_width, view_height);
1698 zoom_by (1, 0, 0);
1701 static void
1702 work_area_first_expose (Widget work_area, void *me,
1703 XmDrawingAreaCallbackStruct * cbs)
1705 int c;
1706 Dimension width, height;
1707 static char dashes[] = { 4, 4 };
1709 window = XtWindow (work_area);
1710 my_gc = XCreateGC (display, window, 0, 0);
1712 arc1_gc = XCreateGC (display, window, 0, 0);
1713 c = lesstif_parse_color ("#804000");
1714 XSetForeground (display, arc1_gc, c);
1715 arc2_gc = XCreateGC (display, window, 0, 0);
1716 c = lesstif_parse_color ("#004080");
1717 XSetForeground (display, arc2_gc, c);
1718 XSetLineAttributes (display, arc1_gc, 1, LineOnOffDash, 0, 0);
1719 XSetLineAttributes (display, arc2_gc, 1, LineOnOffDash, 0, 0);
1720 XSetDashes (display, arc1_gc, 0, dashes, 2);
1721 XSetDashes (display, arc2_gc, 0, dashes, 2);
1723 n = 0;
1724 stdarg (XtNwidth, &width);
1725 stdarg (XtNheight, &height);
1726 stdarg (XmNbackground, &bgcolor);
1727 XtGetValues (work_area, args, n);
1728 view_width = width;
1729 view_height = height;
1731 offlimit_color = lesstif_parse_color (Settings.OffLimitColor);
1732 grid_color = lesstif_parse_color (Settings.GridColor);
1734 bg_gc = XCreateGC (display, window, 0, 0);
1735 XSetForeground (display, bg_gc, bgcolor);
1737 work_area_make_pixmaps (width, height);
1739 #ifdef HAVE_XRENDER
1740 if (use_xrender)
1742 XRenderPictureAttributes pa;
1743 XRenderColor a = {0, 0, 0, 0x8000};
1745 pale_pixmap = XCreatePixmap (display, window, 1, 1, 8);
1746 pa.repeat = True;
1747 pale_picture = XRenderCreatePicture (display, pale_pixmap,
1748 XRenderFindStandardFormat(display, PictStandardA8),
1749 CPRepeat, &pa);
1750 if (pale_picture)
1751 XRenderFillRectangle(display, PictOpSrc, pale_picture, &a, 0, 0, 1, 1);
1752 else
1753 use_xrender = 0;
1755 #endif /* HAVE_XRENDER */
1757 clip_gc = XCreateGC (display, window, 0, 0);
1758 bset_gc = XCreateGC (display, mask_bitmap, 0, 0);
1759 XSetForeground (display, bset_gc, 1);
1760 bclear_gc = XCreateGC (display, mask_bitmap, 0, 0);
1761 XSetForeground (display, bclear_gc, 0);
1763 XtRemoveCallback (work_area, XmNexposeCallback,
1764 (XtCallbackProc) work_area_first_expose, 0);
1765 XtAddCallback (work_area, XmNexposeCallback,
1766 (XtCallbackProc) work_area_expose, 0);
1767 lesstif_invalidate_all ();
1770 static Widget
1771 make_message (char *name, Widget left, int resizeable)
1773 Widget w, f;
1774 n = 0;
1775 if (left)
1777 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
1778 stdarg (XmNleftWidget, XtParent(left));
1780 else
1782 stdarg (XmNleftAttachment, XmATTACH_FORM);
1784 stdarg (XmNtopAttachment, XmATTACH_FORM);
1785 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1786 stdarg (XmNshadowType, XmSHADOW_IN);
1787 stdarg (XmNshadowThickness, 1);
1788 stdarg (XmNalignment, XmALIGNMENT_CENTER);
1789 stdarg (XmNmarginWidth, 4);
1790 stdarg (XmNmarginHeight, 1);
1791 if (!resizeable)
1792 stdarg (XmNresizePolicy, XmRESIZE_GROW);
1793 f = XmCreateForm (messages, name, args, n);
1794 XtManageChild (f);
1795 n = 0;
1796 stdarg (XmNtopAttachment, XmATTACH_FORM);
1797 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1798 stdarg (XmNleftAttachment, XmATTACH_FORM);
1799 stdarg (XmNrightAttachment, XmATTACH_FORM);
1800 w = XmCreateLabel (f, name, args, n);
1801 XtManageChild (w);
1802 return w;
1805 static void
1806 lesstif_do_export (HID_Attr_Val * options)
1808 Dimension width, height;
1809 Widget menu;
1810 Widget work_area_frame;
1812 crosshair_gc = lesstif_make_gc ();
1814 n = 0;
1815 stdarg (XtNwidth, &width);
1816 stdarg (XtNheight, &height);
1817 XtGetValues (appwidget, args, n);
1819 if (width < 1)
1820 width = 640;
1821 if (width > XDisplayWidth (display, screen))
1822 width = XDisplayWidth (display, screen);
1823 if (height < 1)
1824 height = 480;
1825 if (height > XDisplayHeight (display, screen))
1826 height = XDisplayHeight (display, screen);
1828 n = 0;
1829 stdarg (XmNwidth, width);
1830 stdarg (XmNheight, height);
1831 XtSetValues (appwidget, args, n);
1833 stdarg (XmNspacing, 0);
1834 mainwind = XmCreateMainWindow (appwidget, "mainWind", args, n);
1835 XtManageChild (mainwind);
1837 n = 0;
1838 stdarg (XmNmarginWidth, 0);
1839 stdarg (XmNmarginHeight, 0);
1840 menu = lesstif_menu (mainwind, "menubar", args, n);
1841 XtManageChild (menu);
1843 n = 0;
1844 stdarg (XmNshadowType, XmSHADOW_IN);
1845 work_area_frame =
1846 XmCreateFrame (mainwind, "work_area_frame", args, n);
1847 XtManageChild (work_area_frame);
1849 n = 0;
1850 do_color (Settings.BackgroundColor, XmNbackground);
1851 work_area = XmCreateDrawingArea (work_area_frame, "work_area", args, n);
1852 XtManageChild (work_area);
1853 XtAddCallback (work_area, XmNexposeCallback,
1854 (XtCallbackProc) work_area_first_expose, 0);
1855 XtAddCallback (work_area, XmNresizeCallback,
1856 (XtCallbackProc) work_area_resize, 0);
1857 /* A regular callback won't work here, because lesstif swallows any
1858 Ctrl<Button>1 event. */
1859 XtAddEventHandler (work_area,
1860 ButtonPressMask | ButtonReleaseMask
1861 | PointerMotionMask | PointerMotionHintMask
1862 | KeyPressMask | KeyReleaseMask
1863 | EnterWindowMask | LeaveWindowMask,
1864 0, work_area_input, 0);
1866 n = 0;
1867 stdarg (XmNorientation, XmVERTICAL);
1868 stdarg (XmNprocessingDirection, XmMAX_ON_BOTTOM);
1869 stdarg (XmNmaximum, PCB->MaxHeight ? PCB->MaxHeight : 1);
1870 vscroll = XmCreateScrollBar (mainwind, "vscroll", args, n);
1871 XtAddCallback (vscroll, XmNvalueChangedCallback,
1872 (XtCallbackProc) scroll_callback, (XtPointer) & view_top_y);
1873 XtAddCallback (vscroll, XmNdragCallback, (XtCallbackProc) scroll_callback,
1874 (XtPointer) & view_top_y);
1875 XtManageChild (vscroll);
1877 n = 0;
1878 stdarg (XmNorientation, XmHORIZONTAL);
1879 stdarg (XmNmaximum, PCB->MaxWidth ? PCB->MaxWidth : 1);
1880 hscroll = XmCreateScrollBar (mainwind, "hscroll", args, n);
1881 XtAddCallback (hscroll, XmNvalueChangedCallback,
1882 (XtCallbackProc) scroll_callback, (XtPointer) & view_left_x);
1883 XtAddCallback (hscroll, XmNdragCallback, (XtCallbackProc) scroll_callback,
1884 (XtPointer) & view_left_x);
1885 XtManageChild (hscroll);
1887 n = 0;
1888 stdarg (XmNresize, True);
1889 stdarg (XmNresizePolicy, XmRESIZE_ANY);
1890 messages = XmCreateForm (mainwind, "messages", args, n);
1891 XtManageChild (messages);
1893 n = 0;
1894 stdarg (XmNtopAttachment, XmATTACH_FORM);
1895 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1896 stdarg (XmNleftAttachment, XmATTACH_FORM);
1897 stdarg (XmNrightAttachment, XmATTACH_FORM);
1898 stdarg (XmNalignment, XmALIGNMENT_CENTER);
1899 stdarg (XmNshadowThickness, 2);
1900 m_click = XmCreateLabel (messages, "click", args, n);
1902 n = 0;
1903 stdarg (XmNtopAttachment, XmATTACH_FORM);
1904 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1905 stdarg (XmNleftAttachment, XmATTACH_FORM);
1906 stdarg (XmNlabelString, XmStringCreatePCB ("Command: "));
1907 m_cmd_label = XmCreateLabel (messages, "command", args, n);
1909 n = 0;
1910 stdarg (XmNtopAttachment, XmATTACH_FORM);
1911 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1912 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
1913 stdarg (XmNleftWidget, m_cmd_label);
1914 stdarg (XmNrightAttachment, XmATTACH_FORM);
1915 stdarg (XmNshadowThickness, 1);
1916 stdarg (XmNhighlightThickness, 0);
1917 stdarg (XmNmarginWidth, 2);
1918 stdarg (XmNmarginHeight, 2);
1919 m_cmd = XmCreateTextField (messages, "command", args, n);
1920 XtAddCallback (m_cmd, XmNactivateCallback,
1921 (XtCallbackProc) command_callback, 0);
1922 XtAddCallback (m_cmd, XmNlosingFocusCallback,
1923 (XtCallbackProc) command_callback, 0);
1924 XtAddEventHandler (m_cmd, KeyPressMask, 0, command_event_handler, 0);
1926 m_mark = make_message ("m_mark", 0, 0);
1927 m_crosshair = make_message ("m_crosshair", m_mark, 0);
1928 m_grid = make_message ("m_grid", m_crosshair, 1);
1929 m_zoom = make_message ("m_zoom", m_grid, 1);
1930 lesstif_m_layer = make_message ("m_layer", m_zoom, 0);
1931 m_mode = make_message ("m_mode", lesstif_m_layer, 1);
1932 m_rats = make_message ("m_rats", m_mode, 1);
1933 m_status = make_message ("m_status", m_mode, 1);
1935 XtUnmanageChild (XtParent (m_mark));
1936 XtUnmanageChild (XtParent (m_rats));
1938 n = 0;
1939 stdarg (XmNrightAttachment, XmATTACH_FORM);
1940 XtSetValues (XtParent (m_status), args, n);
1942 /* We'll use this later. */
1943 n = 0;
1944 stdarg (XmNleftWidget, XtParent (m_mark));
1945 XtSetValues (XtParent (m_crosshair), args, n);
1947 n = 0;
1948 stdarg (XmNmessageWindow, messages);
1949 XtSetValues (mainwind, args, n);
1951 if (background_image_file)
1952 LoadBackgroundImage (background_image_file);
1954 XtRealizeWidget (appwidget);
1956 while (!window)
1958 XEvent e;
1959 XtAppNextEvent (app_context, &e);
1960 XtDispatchEvent (&e);
1963 PCBChanged (0, 0, 0, 0);
1965 XtAppMainLoop (app_context);
1968 #if 0
1969 XrmOptionDescRec lesstif_options[] = {
1972 XtResource lesstif_resources[] = {
1974 #endif
1976 typedef union
1978 int i;
1979 double f;
1980 char *s;
1981 Coord c;
1982 } val_union;
1984 static Boolean
1985 pcb_cvt_string_to_double (Display * d, XrmValue * args, Cardinal * num_args,
1986 XrmValue * from, XrmValue * to, XtPointer * data)
1988 static double rv;
1989 rv = strtod ((char *) from->addr, 0);
1990 if (to->addr)
1991 *(double *) to->addr = rv;
1992 else
1993 to->addr = (XPointer) & rv;
1994 to->size = sizeof (rv);
1995 return True;
1998 static Boolean
1999 pcb_cvt_string_to_coord (Display * d, XrmValue * args, Cardinal * num_args,
2000 XrmValue * from, XrmValue * to, XtPointer *data)
2002 static Coord rv;
2003 rv = GetValue ((char *) from->addr, NULL, NULL);
2004 if (to->addr)
2005 *(Coord *) to->addr = rv;
2006 else
2007 to->addr = (XPointer) &rv;
2008 to->size = sizeof (rv);
2009 return TRUE;
2012 static void
2013 mainwind_delete_cb ()
2015 hid_action ("Quit");
2018 static void
2019 lesstif_listener_cb (XtPointer client_data, int *fid, XtInputId *id)
2021 char buf[BUFSIZ];
2022 int nbytes;
2024 if ((nbytes = read (*fid, buf, BUFSIZ)) == -1)
2025 perror ("lesstif_listener_cb");
2027 if (nbytes)
2029 buf[nbytes] = '\0';
2030 hid_parse_actions (buf);
2034 static void
2035 lesstif_parse_arguments (int *argc, char ***argv)
2037 Atom close_atom;
2038 HID_AttrNode *ha;
2039 int acount = 0, amax;
2040 int rcount = 0, rmax;
2041 int i;
2042 XrmOptionDescRec *new_options;
2043 XtResource *new_resources;
2044 val_union *new_values;
2045 int render_event, render_error;
2047 XtSetTypeConverter (XtRString,
2048 XtRDouble,
2049 pcb_cvt_string_to_double, NULL, 0, XtCacheAll, NULL);
2050 XtSetTypeConverter (XtRString,
2051 XtRPCBCoord,
2052 pcb_cvt_string_to_coord, NULL, 0, XtCacheAll, NULL);
2055 for (ha = hid_attr_nodes; ha; ha = ha->next)
2056 for (i = 0; i < ha->n; i++)
2058 HID_Attribute *a = ha->attributes + i;
2059 switch (a->type)
2061 case HID_Integer:
2062 case HID_Coord:
2063 case HID_Real:
2064 case HID_String:
2065 case HID_Path:
2066 case HID_Boolean:
2067 acount++;
2068 rcount++;
2069 break;
2070 default:
2071 break;
2075 #if 0
2076 amax = acount + XtNumber (lesstif_options);
2077 #else
2078 amax = acount;
2079 #endif
2081 new_options = (XrmOptionDescRec *) malloc ((amax + 1) * sizeof (XrmOptionDescRec));
2083 #if 0
2084 memcpy (new_options + acount, lesstif_options, sizeof (lesstif_options));
2085 #endif
2086 acount = 0;
2088 #if 0
2089 rmax = rcount + XtNumber (lesstif_resources);
2090 #else
2091 rmax = rcount;
2092 #endif
2094 new_resources = (XtResource *) malloc ((rmax + 1) * sizeof (XtResource));
2095 new_values = (val_union *) malloc ((rmax + 1) * sizeof (val_union));
2096 #if 0
2097 memcpy (new_resources + acount, lesstif_resources,
2098 sizeof (lesstif_resources));
2099 #endif
2100 rcount = 0;
2102 for (ha = hid_attr_nodes; ha; ha = ha->next)
2103 for (i = 0; i < ha->n; i++)
2105 HID_Attribute *a = ha->attributes + i;
2106 XrmOptionDescRec *o = new_options + acount;
2107 char *tmpopt, *tmpres;
2108 XtResource *r = new_resources + rcount;
2110 tmpopt = (char *) malloc (strlen (a->name) + 3);
2111 tmpopt[0] = tmpopt[1] = '-';
2112 strcpy (tmpopt + 2, a->name);
2113 o->option = tmpopt;
2115 tmpres = (char *) malloc (strlen (a->name) + 2);
2116 tmpres[0] = '*';
2117 strcpy (tmpres + 1, a->name);
2118 o->specifier = tmpres;
2120 switch (a->type)
2122 case HID_Integer:
2123 case HID_Coord:
2124 case HID_Real:
2125 case HID_String:
2126 case HID_Path:
2127 o->argKind = XrmoptionSepArg;
2128 o->value = 0;
2129 acount++;
2130 break;
2131 case HID_Boolean:
2132 o->argKind = XrmoptionNoArg;
2133 o->value = "True";
2134 acount++;
2135 break;
2136 default:
2137 break;
2140 r->resource_name = a->name;
2141 r->resource_class = a->name;
2142 r->resource_offset = sizeof (val_union) * rcount;
2144 switch (a->type)
2146 case HID_Integer:
2147 r->resource_type = XtRInt;
2148 r->default_type = XtRInt;
2149 r->resource_size = sizeof (int);
2150 r->default_addr = &(a->default_val.int_value);
2151 rcount++;
2152 break;
2153 case HID_Coord:
2154 r->resource_type = XtRPCBCoord;
2155 r->default_type = XtRPCBCoord;
2156 r->resource_size = sizeof (Coord);
2157 r->default_addr = &(a->default_val.coord_value);
2158 rcount++;
2159 break;
2160 case HID_Real:
2161 r->resource_type = XtRDouble;
2162 r->default_type = XtRDouble;
2163 r->resource_size = sizeof (double);
2164 r->default_addr = &(a->default_val.real_value);
2165 rcount++;
2166 break;
2167 case HID_String:
2168 case HID_Path:
2169 r->resource_type = XtRString;
2170 r->default_type = XtRString;
2171 r->resource_size = sizeof (char *);
2172 r->default_addr = (char *) a->default_val.str_value;
2173 rcount++;
2174 break;
2175 case HID_Boolean:
2176 r->resource_type = XtRBoolean;
2177 r->default_type = XtRInt;
2178 r->resource_size = sizeof (int);
2179 r->default_addr = &(a->default_val.int_value);
2180 rcount++;
2181 break;
2182 default:
2183 break;
2186 #if 0
2187 for (i = 0; i < XtNumber (lesstif_resources); i++)
2189 XtResource *r = new_resources + rcount;
2190 r->resource_offset = sizeof (val_union) * rcount;
2191 rcount++;
2193 #endif
2195 n = 0;
2196 stdarg (XmNdeleteResponse, XmDO_NOTHING);
2198 appwidget = XtAppInitialize (&app_context,
2199 "Pcb",
2200 new_options, amax, argc, *argv, 0, args, n);
2202 display = XtDisplay (appwidget);
2203 screen_s = XtScreen (appwidget);
2204 screen = XScreenNumberOfScreen (screen_s);
2205 colormap = XDefaultColormap (display, screen);
2207 close_atom = XmInternAtom (display, "WM_DELETE_WINDOW", 0);
2208 XmAddWMProtocolCallback (appwidget, close_atom,
2209 (XtCallbackProc) mainwind_delete_cb, 0);
2211 /* XSynchronize(display, True); */
2213 XtGetApplicationResources (appwidget, new_values, new_resources,
2214 rmax, 0, 0);
2216 #ifdef HAVE_XRENDER
2217 use_xrender = XRenderQueryExtension (display, &render_event, &render_error) &&
2218 XRenderFindVisualFormat (display, DefaultVisual(display, screen));
2219 #ifdef HAVE_XINERAMA
2220 /* Xinerama and XRender don't get along well */
2221 if (XineramaQueryExtension (display, &render_event, &render_error)
2222 && XineramaIsActive (display))
2223 use_xrender = 0;
2224 #endif /* HAVE_XINERAMA */
2225 #endif /* HAVE_XRENDER */
2227 rcount = 0;
2228 for (ha = hid_attr_nodes; ha; ha = ha->next)
2229 for (i = 0; i < ha->n; i++)
2231 HID_Attribute *a = ha->attributes + i;
2232 val_union *v = new_values + rcount;
2233 switch (a->type)
2235 case HID_Integer:
2236 if (a->value)
2237 *(int *) a->value = v->i;
2238 else
2239 a->default_val.int_value = v->i;
2240 rcount++;
2241 break;
2242 case HID_Coord:
2243 if (a->value)
2244 *(Coord *) a->value = v->c;
2245 else
2246 a->default_val.coord_value = v->c;
2247 rcount++;
2248 break;
2249 case HID_Boolean:
2250 if (a->value)
2251 *(char *) a->value = v->i;
2252 else
2253 a->default_val.int_value = v->i;
2254 rcount++;
2255 break;
2256 case HID_Real:
2257 if (a->value)
2258 *(double *) a->value = v->f;
2259 else
2260 a->default_val.real_value = v->f;
2261 rcount++;
2262 break;
2263 case HID_String:
2264 case HID_Path:
2265 if (a->value)
2266 *(char **) a->value = v->s;
2267 else
2268 a->default_val.str_value = v->s;
2269 rcount++;
2270 break;
2271 default:
2272 break;
2276 /* redefine colormap, if requested via "-install" */
2277 if (use_private_colormap)
2279 colormap = XCopyColormapAndFree (display, colormap);
2280 XtVaSetValues (appwidget, XtNcolormap, colormap, NULL);
2283 /* listen on standard input for actions */
2284 if (stdin_listen)
2286 XtAppAddInput (app_context, fileno (stdin), (XtPointer) XtInputReadMask,
2287 lesstif_listener_cb, NULL);
2291 static void
2292 draw_grid ()
2294 static XPoint *points = 0;
2295 static int npoints = 0;
2296 Coord x1, y1, x2, y2, prevx;
2297 Coord x, y;
2298 int n;
2299 static GC grid_gc = 0;
2301 if (!Settings.DrawGrid)
2302 return;
2303 if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
2304 return;
2305 if (!grid_gc)
2307 grid_gc = XCreateGC (display, window, 0, 0);
2308 XSetFunction (display, grid_gc, GXxor);
2309 XSetForeground (display, grid_gc, grid_color);
2311 if (flip_x)
2313 x2 = GridFit (Px (0), PCB->Grid, PCB->GridOffsetX);
2314 x1 = GridFit (Px (view_width), PCB->Grid, PCB->GridOffsetX);
2315 if (Vx (x2) < 0)
2316 x2 -= PCB->Grid;
2317 if (Vx (x1) >= view_width)
2318 x1 += PCB->Grid;
2320 else
2322 x1 = GridFit (Px (0), PCB->Grid, PCB->GridOffsetX);
2323 x2 = GridFit (Px (view_width), PCB->Grid, PCB->GridOffsetX);
2324 if (Vx (x1) < 0)
2325 x1 += PCB->Grid;
2326 if (Vx (x2) >= view_width)
2327 x2 -= PCB->Grid;
2329 if (flip_y)
2331 y2 = GridFit (Py (0), PCB->Grid, PCB->GridOffsetY);
2332 y1 = GridFit (Py (view_height), PCB->Grid, PCB->GridOffsetY);
2333 if (Vy (y2) < 0)
2334 y2 -= PCB->Grid;
2335 if (Vy (y1) >= view_height)
2336 y1 += PCB->Grid;
2338 else
2340 y1 = GridFit (Py (0), PCB->Grid, PCB->GridOffsetY);
2341 y2 = GridFit (Py (view_height), PCB->Grid, PCB->GridOffsetY);
2342 if (Vy (y1) < 0)
2343 y1 += PCB->Grid;
2344 if (Vy (y2) >= view_height)
2345 y2 -= PCB->Grid;
2347 n = (x2 - x1) / PCB->Grid + 1;
2348 if (n > npoints)
2350 npoints = n + 10;
2351 points = (XPoint *) realloc (points, npoints * sizeof (XPoint));
2353 n = 0;
2354 prevx = 0;
2355 for (x = x1; x <= x2; x += PCB->Grid)
2357 int temp = Vx (x);
2358 points[n].x = temp;
2359 if (n)
2361 points[n].x -= prevx;
2362 points[n].y = 0;
2364 prevx = temp;
2365 n++;
2367 for (y = y1; y <= y2; y += PCB->Grid)
2369 int vy = Vy (y);
2370 points[0].y = vy;
2371 XDrawPoints (display, pixmap, grid_gc, points, n, CoordModePrevious);
2375 static void
2376 mark_delta_to_widget (Coord dx, Coord dy, Widget w)
2378 char *buf;
2379 double g = coord_to_unit (Settings.grid_unit, PCB->Grid);
2380 int prec;
2381 XmString ms;
2383 /* Integer-sized grid? */
2384 if (((int) (g * 10000 + 0.5) % 10000) == 0)
2385 prec = 0;
2386 else
2387 prec = Settings.grid_unit->default_prec;
2389 if (dx == 0 && dy == 0)
2390 buf = pcb_g_strdup_printf ("%m+%+.*mS, %+.*mS", UUNIT, prec, dx, prec, dy);
2391 else
2393 Angle angle = atan2 (dy, -dx) * 180 / M_PI;
2394 Coord dist = Distance (0, 0, dx, dy);
2396 buf = pcb_g_strdup_printf ("%m+%+.*mS, %+.*mS (%.*mS, %d\260)", UUNIT,
2397 prec, dx, prec, dy, prec, dist, angle);
2400 ms = XmStringCreatePCB (buf);
2401 n = 0;
2402 stdarg (XmNlabelString, ms);
2403 XtSetValues (w, args, n);
2404 g_free (buf);
2407 static int
2408 cursor_pos_to_widget (Coord x, Coord y, Widget w, int prev_state)
2410 int this_state = prev_state;
2411 static char *buf;
2412 double g = coord_to_unit (Settings.grid_unit, PCB->Grid);
2413 XmString ms;
2414 int prec;
2416 /* Determine necessary precision (and state) based
2417 * on the user's grid setting */
2418 if (((int) (g * 10000 + 0.5) % 10000) == 0)
2420 prec = 0;
2421 this_state = Settings.grid_unit->allow;
2423 else
2425 prec = Settings.grid_unit->default_prec;
2426 this_state = -Settings.grid_unit->allow;
2429 if (x < 0)
2430 buf = g_strdup ("");
2431 else
2432 buf = pcb_g_strdup_printf ("%m+%.*mS, %.*mS", UUNIT, prec, x, prec, y);
2434 ms = XmStringCreatePCB (buf);
2435 n = 0;
2436 stdarg (XmNlabelString, ms);
2437 XtSetValues (w, args, n);
2438 g_free (buf);
2439 return this_state;
2442 #define S Settings
2444 void
2445 lesstif_update_status_line ()
2447 char *buf = NULL;
2448 char *s45 = cur_clip ();
2449 XmString xs;
2451 switch (Settings.Mode)
2453 case VIA_MODE:
2454 buf = pcb_g_strdup_printf ("%m+%.2mS/%.2mS \370=%.2mS", UUNIT,
2455 S.ViaThickness, S.Keepaway, S.ViaDrillingHole);
2456 break;
2457 case LINE_MODE:
2458 case ARC_MODE:
2459 buf = pcb_g_strdup_printf ("%m+%.2mS/%.2mS %s", UUNIT,
2460 S.LineThickness, S.Keepaway, s45);
2461 break;
2462 case RECTANGLE_MODE:
2463 case POLYGON_MODE:
2464 buf = pcb_g_strdup_printf ("%m+%.2mS %s", UUNIT, S.Keepaway, s45);
2465 break;
2466 case TEXT_MODE:
2467 buf = g_strdup_printf ("%d %%", S.TextScale);
2468 break;
2469 case MOVE_MODE:
2470 case COPY_MODE:
2471 case INSERTPOINT_MODE:
2472 case RUBBERBANDMOVE_MODE:
2473 buf = g_strdup_printf ("%s", s45);
2474 break;
2475 case NO_MODE:
2476 case PASTEBUFFER_MODE:
2477 case ROTATE_MODE:
2478 case REMOVE_MODE:
2479 case THERMAL_MODE:
2480 case ARROW_MODE:
2481 case LOCK_MODE:
2482 default:
2483 buf = g_strdup("");
2484 break;
2487 xs = XmStringCreatePCB (buf);
2488 n = 0;
2489 stdarg (XmNlabelString, xs);
2490 XtSetValues (m_status, args, n);
2491 g_free (buf);
2494 #undef S
2496 static int idle_proc_set = 0;
2497 static int need_redraw = 0;
2499 static Boolean
2500 idle_proc (XtPointer dummy)
2502 if (need_redraw)
2504 int mx, my;
2505 BoxType region;
2506 lesstif_use_mask (HID_MASK_OFF);
2507 pixmap = main_pixmap;
2508 mx = view_width;
2509 my = view_height;
2510 region.X1 = Px (0);
2511 region.Y1 = Py (0);
2512 region.X2 = Px (view_width);
2513 region.Y2 = Py (view_height);
2514 if (flip_x)
2516 Coord tmp = region.X1;
2517 region.X1 = region.X2;
2518 region.X2 = tmp;
2520 if (flip_y)
2522 Coord tmp = region.Y1;
2523 region.Y1 = region.Y2;
2524 region.Y2 = tmp;
2526 XSetForeground (display, bg_gc, bgcolor);
2527 XFillRectangle (display, main_pixmap, bg_gc, 0, 0, mx, my);
2529 if (region.X1 < 0 || region.Y1 < 0
2530 || region.X2 > PCB->MaxWidth || region.Y2 > PCB->MaxHeight)
2532 int leftmost, rightmost, topmost, bottommost;
2534 leftmost = Vx (0);
2535 rightmost = Vx (PCB->MaxWidth);
2536 topmost = Vy (0);
2537 bottommost = Vy (PCB->MaxHeight);
2538 if (leftmost > rightmost) {
2539 int t = leftmost;
2540 leftmost = rightmost;
2541 rightmost = t;
2543 if (topmost > bottommost) {
2544 int t = topmost;
2545 topmost = bottommost;
2546 bottommost = t;
2548 if (leftmost < 0)
2549 leftmost = 0;
2550 if (topmost < 0)
2551 topmost = 0;
2552 if (rightmost > view_width)
2553 rightmost = view_width;
2554 if (bottommost > view_height)
2555 bottommost = view_height;
2557 XSetForeground (display, bg_gc, offlimit_color);
2559 /* L T R
2560 L x R
2561 L B R */
2563 if (leftmost > 0)
2565 XFillRectangle (display, main_pixmap, bg_gc, 0, 0,
2566 leftmost, view_height);
2568 if (rightmost < view_width)
2570 XFillRectangle (display, main_pixmap, bg_gc, rightmost+1, 0,
2571 view_width-rightmost+1, view_height);
2573 if (topmost > 0)
2575 XFillRectangle (display, main_pixmap, bg_gc, leftmost, 0,
2576 rightmost-leftmost+1, topmost);
2578 if (bottommost < view_height)
2580 XFillRectangle (display, main_pixmap, bg_gc, leftmost, bottommost+1,
2581 rightmost-leftmost+1, view_height-bottommost+1);
2584 DrawBackgroundImage();
2585 hid_expose_callback (&lesstif_hid, &region, 0);
2586 draw_grid ();
2587 lesstif_use_mask (HID_MASK_OFF);
2588 show_crosshair (0); /* To keep the drawn / not drawn info correct */
2589 XSetFunction (display, my_gc, GXcopy);
2590 XCopyArea (display, main_pixmap, window, my_gc, 0, 0, view_width,
2591 view_height, 0, 0);
2592 pixmap = window;
2593 if (crosshair_on)
2595 DrawAttached (crosshair_gc);
2596 DrawMark (crosshair_gc);
2598 need_redraw = 0;
2602 static int c_x = -2, c_y = -2;
2603 static MarkType saved_mark;
2604 static const Unit *old_grid_unit = NULL;
2605 if (crosshair_x != c_x || crosshair_y != c_y
2606 || Settings.grid_unit != old_grid_unit
2607 || memcmp (&saved_mark, &Marked, sizeof (MarkType)))
2609 static int last_state = 0;
2610 static int this_state = 0;
2612 c_x = crosshair_x;
2613 c_y = crosshair_y;
2615 this_state =
2616 cursor_pos_to_widget (crosshair_x, crosshair_y, m_crosshair,
2617 this_state);
2618 if (Marked.status)
2619 mark_delta_to_widget (crosshair_x - Marked.X, crosshair_y - Marked.Y,
2620 m_mark);
2622 if (Marked.status != saved_mark.status)
2624 if (Marked.status)
2626 XtManageChild (XtParent (m_mark));
2627 XtManageChild (m_mark);
2628 n = 0;
2629 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
2630 stdarg (XmNleftWidget, XtParent (m_mark));
2631 XtSetValues (XtParent (m_crosshair), args, n);
2633 else
2635 n = 0;
2636 stdarg (XmNleftAttachment, XmATTACH_FORM);
2637 XtSetValues (XtParent (m_crosshair), args, n);
2638 XtUnmanageChild (XtParent (m_mark));
2640 last_state = this_state + 100;
2642 memcpy (&saved_mark, &Marked, sizeof (MarkType));
2644 if (old_grid_unit != Settings.grid_unit)
2646 old_grid_unit = Settings.grid_unit;
2647 /* Force a resize on units change. */
2648 last_state ++;
2651 /* This is obtuse. We want to enable XmRESIZE_ANY long enough
2652 to shrink to fit the new format (if any), then switch it
2653 back to XmRESIZE_GROW to prevent it from shrinking due to
2654 changes in the number of actual digits printed. Thus, when
2655 you switch from a small grid and %.2f formats to a large
2656 grid and %d formats, you aren't punished with a wide and
2657 mostly white-space label widget. "this_state" indicates
2658 which of the above formats we're using. "last_state" is
2659 either zero (when resizing) or the same as "this_state"
2660 (when grow-only), or a non-zero but not "this_state" which
2661 means we need to start a resize cycle. */
2662 if (this_state != last_state && last_state)
2664 n = 0;
2665 stdarg (XmNresizePolicy, XmRESIZE_ANY);
2666 XtSetValues (XtParent (m_mark), args, n);
2667 XtSetValues (XtParent (m_crosshair), args, n);
2668 last_state = 0;
2670 else if (this_state != last_state)
2672 n = 0;
2673 stdarg (XmNresizePolicy, XmRESIZE_GROW);
2674 XtSetValues (XtParent (m_mark), args, n);
2675 XtSetValues (XtParent (m_crosshair), args, n);
2676 last_state = this_state;
2682 static Coord old_grid = -1;
2683 static Coord old_gx, old_gy;
2684 static const Unit *old_unit;
2685 XmString ms;
2686 if (PCB->Grid != old_grid
2687 || PCB->GridOffsetX != old_gx
2688 || PCB->GridOffsetY != old_gy || Settings.grid_unit != old_unit)
2690 static char buf[100];
2691 old_grid = PCB->Grid;
2692 old_unit = Settings.grid_unit;
2693 old_gx = PCB->GridOffsetX;
2694 old_gy = PCB->GridOffsetY;
2695 if (old_grid == 1)
2697 strcpy (buf, "No Grid");
2699 else
2701 if (old_gx || old_gy)
2702 pcb_snprintf (buf, sizeof (buf), "%m+%$mS @%mS,%mS",
2703 UUNIT, old_grid, old_gx, old_gy);
2704 else
2705 pcb_snprintf (buf, sizeof (buf), "%m+%$mS", UUNIT, old_grid);
2707 ms = XmStringCreatePCB (buf);
2708 n = 0;
2709 stdarg (XmNlabelString, ms);
2710 XtSetValues (m_grid, args, n);
2715 static double old_zoom = -1;
2716 static const Unit *old_grid_unit = NULL;
2717 if (view_zoom != old_zoom || Settings.grid_unit != old_grid_unit)
2719 gchar *buf = pcb_g_strdup_printf ("%m+%$mS/pix",
2720 Settings.grid_unit->allow, (Coord) view_zoom);
2721 XmString ms;
2723 old_zoom = view_zoom;
2724 old_grid_unit = Settings.grid_unit;
2726 ms = XmStringCreatePCB (buf);
2727 n = 0;
2728 stdarg (XmNlabelString, ms);
2729 XtSetValues (m_zoom, args, n);
2730 g_free (buf);
2735 if (old_cursor_mode != Settings.Mode)
2737 char *s = "None";
2738 XmString ms;
2739 int cursor = -1;
2740 static int free_cursor = 0;
2742 old_cursor_mode = Settings.Mode;
2743 switch (Settings.Mode)
2745 case NO_MODE:
2746 s = "None";
2747 cursor = XC_X_cursor;
2748 break;
2749 case VIA_MODE:
2750 s = "Via";
2751 cursor = -1;
2752 break;
2753 case LINE_MODE:
2754 s = "Line";
2755 cursor = XC_pencil;
2756 break;
2757 case RECTANGLE_MODE:
2758 s = "Rectangle";
2759 cursor = XC_ul_angle;
2760 break;
2761 case POLYGON_MODE:
2762 s = "Polygon";
2763 cursor = XC_sb_up_arrow;
2764 break;
2765 case POLYGONHOLE_MODE:
2766 s = "Polygon Hole";
2767 cursor = XC_sb_up_arrow;
2768 break;
2769 case PASTEBUFFER_MODE:
2770 s = "Paste";
2771 cursor = XC_hand1;
2772 break;
2773 case TEXT_MODE:
2774 s = "Text";
2775 cursor = XC_xterm;
2776 break;
2777 case ROTATE_MODE:
2778 s = "Rotate";
2779 cursor = XC_exchange;
2780 break;
2781 case REMOVE_MODE:
2782 s = "Remove";
2783 cursor = XC_pirate;
2784 break;
2785 case MOVE_MODE:
2786 s = "Move";
2787 cursor = XC_crosshair;
2788 break;
2789 case COPY_MODE:
2790 s = "Copy";
2791 cursor = XC_crosshair;
2792 break;
2793 case INSERTPOINT_MODE:
2794 s = "Insert";
2795 cursor = XC_dotbox;
2796 break;
2797 case RUBBERBANDMOVE_MODE:
2798 s = "RBMove";
2799 cursor = XC_top_left_corner;
2800 break;
2801 case THERMAL_MODE:
2802 s = "Thermal";
2803 cursor = XC_iron_cross;
2804 break;
2805 case ARC_MODE:
2806 s = "Arc";
2807 cursor = XC_question_arrow;
2808 break;
2809 case ARROW_MODE:
2810 s = "Arrow";
2811 if (over_point)
2812 cursor = XC_draped_box;
2813 else
2814 cursor = XC_left_ptr;
2815 break;
2816 case LOCK_MODE:
2817 s = "Lock";
2818 cursor = XC_hand2;
2819 break;
2821 ms = XmStringCreatePCB (s);
2822 n = 0;
2823 stdarg (XmNlabelString, ms);
2824 XtSetValues (m_mode, args, n);
2826 if (free_cursor)
2828 XFreeCursor (display, my_cursor);
2829 free_cursor = 0;
2831 if (cursor == -1)
2833 static Pixmap nocur_source = 0;
2834 static Pixmap nocur_mask = 0;
2835 static Cursor nocursor = 0;
2836 if (nocur_source == 0)
2838 XColor fg, bg;
2839 nocur_source =
2840 XCreateBitmapFromData (display, window, "\0", 1, 1);
2841 nocur_mask =
2842 XCreateBitmapFromData (display, window, "\0", 1, 1);
2844 fg.red = fg.green = fg.blue = 65535;
2845 bg.red = bg.green = bg.blue = 0;
2846 fg.flags = bg.flags = DoRed | DoGreen | DoBlue;
2847 nocursor = XCreatePixmapCursor (display, nocur_source,
2848 nocur_mask, &fg, &bg, 0, 0);
2850 my_cursor = nocursor;
2852 else
2854 my_cursor = XCreateFontCursor (display, cursor);
2855 free_cursor = 1;
2857 XDefineCursor (display, window, my_cursor);
2858 lesstif_update_status_line ();
2862 static char *old_clip = 0;
2863 static int old_tscale = -1;
2864 char *new_clip = cur_clip ();
2866 if (new_clip != old_clip || Settings.TextScale != old_tscale)
2868 lesstif_update_status_line ();
2869 old_clip = new_clip;
2870 old_tscale = Settings.TextScale;
2875 static int old_nrats = -1;
2876 static char buf[20];
2878 if (old_nrats != PCB->Data->RatN)
2880 old_nrats = PCB->Data->RatN;
2881 sprintf(buf, "%d rat%s", PCB->Data->RatN, PCB->Data->RatN == 1 ? "" : "s");
2882 if (PCB->Data->RatN)
2884 XtManageChild(XtParent(m_rats));
2885 XtManageChild(m_rats);
2886 n = 0;
2887 stdarg (XmNleftWidget, m_rats);
2888 XtSetValues (XtParent (m_status), args, n);
2891 n = 0;
2892 stdarg (XmNlabelString, XmStringCreatePCB (buf));
2893 XtSetValues (m_rats, args, n);
2895 if (!PCB->Data->RatN)
2897 n = 0;
2898 stdarg (XmNleftWidget, m_mode);
2899 XtSetValues (XtParent (m_status), args, n);
2900 XtUnmanageChild(XtParent(m_rats));
2905 lesstif_update_widget_flags ();
2907 show_crosshair (1);
2908 idle_proc_set = 0;
2909 return True;
2912 void
2913 lesstif_need_idle_proc ()
2915 if (idle_proc_set || window == 0)
2916 return;
2917 XtAppAddWorkProc (app_context, idle_proc, 0);
2918 idle_proc_set = 1;
2921 static void
2922 lesstif_invalidate_lr (int l, int r, int t, int b)
2924 if (!window)
2925 return;
2927 need_redraw = 1;
2928 need_idle_proc ();
2931 void
2932 lesstif_invalidate_all (void)
2934 lesstif_invalidate_lr (0, PCB->MaxWidth, 0, PCB->MaxHeight);
2937 static void
2938 lesstif_notify_crosshair_change (bool changes_complete)
2940 static int invalidate_depth = 0;
2941 Pixmap save_pixmap;
2943 if (! my_gc)
2944 return;
2946 if (changes_complete)
2947 invalidate_depth --;
2949 if (invalidate_depth < 0)
2951 invalidate_depth = 0;
2952 /* A mismatch of changes_complete == false and == true notifications
2953 * is not expected to occur, but we will try to handle it gracefully.
2954 * As we know the crosshair will have been shown already, we must
2955 * repaint the entire view to be sure not to leave an artaefact.
2957 need_idle_proc ();
2958 return;
2961 if (invalidate_depth == 0 && crosshair_on)
2963 save_pixmap = pixmap;
2964 pixmap = window;
2965 DrawAttached (crosshair_gc);
2966 pixmap = save_pixmap;
2969 if (!changes_complete)
2970 invalidate_depth ++;
2973 static void
2974 lesstif_notify_mark_change (bool changes_complete)
2976 static int invalidate_depth = 0;
2977 Pixmap save_pixmap;
2979 if (changes_complete)
2980 invalidate_depth --;
2982 if (invalidate_depth < 0)
2984 invalidate_depth = 0;
2985 /* A mismatch of changes_complete == false and == true notifications
2986 * is not expected to occur, but we will try to handle it gracefully.
2987 * As we know the mark will have been shown already, we must
2988 * repaint the entire view to be sure not to leave an artaefact.
2990 need_idle_proc ();
2991 return;
2994 if (invalidate_depth == 0 && crosshair_on)
2996 save_pixmap = pixmap;
2997 pixmap = window;
2998 DrawMark (crosshair_gc);
2999 pixmap = save_pixmap;
3002 if (!changes_complete)
3003 invalidate_depth ++;
3006 static int
3007 lesstif_set_layer (const char *name, int group, int empty)
3009 int idx = group;
3010 if (idx >= 0 && idx < max_group)
3012 int n = PCB->LayerGroups.Number[group];
3013 for (idx = 0; idx < n-1; idx ++)
3015 int ni = PCB->LayerGroups.Entries[group][idx];
3016 if (ni >= 0 && ni < max_copper_layer + 2
3017 && PCB->Data->Layer[ni].On)
3018 break;
3020 idx = PCB->LayerGroups.Entries[group][idx];
3021 #if 0
3022 if (idx == LayerStack[0]
3023 || GetLayerGroupNumberByNumber (idx) ==
3024 GetLayerGroupNumberByNumber (LayerStack[0]))
3025 autofade = 0;
3026 else
3027 autofade = 1;
3028 #endif
3030 #if 0
3031 else
3032 autofade = 0;
3033 #endif
3034 if (idx >= 0 && idx < max_copper_layer + 2)
3035 return pinout ? 1 : PCB->Data->Layer[idx].On;
3036 if (idx < 0)
3038 switch (SL_TYPE (idx))
3040 case SL_INVISIBLE:
3041 return pinout ? 0 : PCB->InvisibleObjectsOn;
3042 case SL_MASK:
3043 if (SL_MYSIDE (idx) && !pinout)
3044 return TEST_FLAG (SHOWMASKFLAG, PCB);
3045 return 0;
3046 case SL_SILK:
3047 if (SL_MYSIDE (idx) || pinout)
3048 return PCB->ElementOn;
3049 return 0;
3050 case SL_ASSY:
3051 return 0;
3052 case SL_UDRILL:
3053 case SL_PDRILL:
3054 return 1;
3055 case SL_RATS:
3056 return PCB->RatOn;
3059 return 0;
3062 static hidGC
3063 lesstif_make_gc (void)
3065 hidGC gc = (hidGC)calloc (1, sizeof (struct lesstif_gc_struct));
3067 gc->hid = &lesstif_hid;
3068 gc->hid_draw = &lesstif_graphics;
3070 return gc;
3073 static void
3074 lesstif_destroy_gc (hidGC gc)
3076 free (gc);
3079 static void
3080 lesstif_use_mask (enum mask_mode mode)
3082 if ((TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) &&
3083 !use_xrender)
3084 mode = HID_MASK_OFF;
3085 if ((mode == HID_MASK_OFF) == (use_mask == HID_MASK_OFF))
3086 return;
3087 use_mask = mode;
3088 if (pinout)
3089 return;
3090 if (!window)
3091 return;
3092 /* printf("use_mask(%d)\n", use_it); */
3093 if (!mask_pixmap)
3095 mask_pixmap =
3096 XCreatePixmap (display, window, pixmap_w, pixmap_h,
3097 XDefaultDepth (display, screen));
3098 mask_bitmap = XCreatePixmap (display, window, pixmap_w, pixmap_h, 1);
3100 if (mode != HID_MASK_OFF)
3102 pixmap = mask_pixmap;
3103 XSetForeground (display, my_gc, 0);
3104 XSetFunction (display, my_gc, GXcopy);
3105 XFillRectangle (display, mask_pixmap, my_gc,
3106 0, 0, view_width, view_height);
3107 XFillRectangle (display, mask_bitmap, bclear_gc,
3108 0, 0, view_width, view_height);
3110 else
3112 pixmap = main_pixmap;
3113 #ifdef HAVE_XRENDER
3114 if (use_xrender)
3116 XRenderPictureAttributes pa;
3118 pa.clip_mask = mask_bitmap;
3119 XRenderChangePicture(display, main_picture, CPClipMask, &pa);
3120 XRenderComposite(display, PictOpOver, mask_picture, pale_picture,
3121 main_picture, 0, 0, 0, 0, 0, 0, view_width, view_height);
3123 else
3124 #endif /* HAVE_XRENDER */
3126 XSetClipMask (display, clip_gc, mask_bitmap);
3127 XCopyArea (display, mask_pixmap, main_pixmap, clip_gc,
3128 0, 0, view_width, view_height, 0, 0);
3133 static void
3134 lesstif_set_color (hidGC gc, const char *name)
3136 lesstifGC lesstif_gc = (lesstifGC)gc;
3137 static void *cache = 0;
3138 hidval cval;
3139 static XColor color, exact_color;
3141 if (!display)
3142 return;
3143 if (!name)
3144 name = "red";
3145 lesstif_gc->colorname = name;
3146 if (strcmp (name, "erase") == 0)
3148 lesstif_gc->color = bgcolor;
3149 lesstif_gc->erase = 1;
3151 else if (strcmp (name, "drill") == 0)
3153 lesstif_gc->color = offlimit_color;
3154 lesstif_gc->erase = 0;
3156 else if (hid_cache_color (0, name, &cval, &cache))
3158 lesstif_gc->color = cval.lval;
3159 lesstif_gc->erase = 0;
3161 else
3163 if (!XAllocNamedColor (display, colormap, name, &color, &exact_color))
3164 color.pixel = WhitePixel (display, screen);
3165 #if 0
3166 printf ("lesstif_set_color `%s' %08x rgb/%d/%d/%d\n",
3167 name, color.pixel, color.red, color.green, color.blue);
3168 #endif
3169 cval.lval = lesstif_gc->color = color.pixel;
3170 hid_cache_color (1, name, &cval, &cache);
3171 lesstif_gc->erase = 0;
3173 if (autofade)
3175 static int lastcolor = -1, lastfade = -1;
3176 if (lesstif_gc->color == lastcolor)
3177 lesstif_gc->color = lastfade;
3178 else
3180 lastcolor = lesstif_gc->color;
3181 color.pixel = lesstif_gc->color;
3183 XQueryColor (display, colormap, &color);
3184 color.red = (bgred + color.red) / 2;
3185 color.green = (bggreen + color.green) / 2;
3186 color.blue = (bgblue + color.blue) / 2;
3187 XAllocColor (display, colormap, &color);
3188 lastfade = lesstif_gc->color = color.pixel;
3193 static void
3194 set_gc (hidGC gc)
3196 lesstifGC lesstif_gc = (lesstifGC)gc;
3197 int cap, join, width;
3198 if (gc->hid != &lesstif_hid)
3200 fprintf (stderr, "Fatal: GC from another HID passed to lesstif HID\n");
3201 abort ();
3203 #if 0
3204 pcb_printf ("set_gc c%s %08lx w%#mS c%d x%d e%d\n",
3205 lesstif_gc->colorname, lesstif_gc->color, lesstif_gc->width, lesstif_gc->cap, lesstif_gc->xor_set, lesstif_gc->erase);
3206 #endif
3207 switch (lesstif_gc->cap)
3209 case Square_Cap:
3210 cap = CapProjecting;
3211 join = JoinMiter;
3212 break;
3213 case Trace_Cap:
3214 case Round_Cap:
3215 cap = CapRound;
3216 join = JoinRound;
3217 break;
3218 case Beveled_Cap:
3219 cap = CapProjecting;
3220 join = JoinBevel;
3221 break;
3222 default:
3223 cap = CapProjecting;
3224 join = JoinBevel;
3225 break;
3227 if (lesstif_gc->xor_set)
3229 XSetFunction (display, my_gc, GXxor);
3230 XSetForeground (display, my_gc, lesstif_gc->color ^ bgcolor);
3232 else if (lesstif_gc->erase)
3234 XSetFunction (display, my_gc, GXcopy);
3235 XSetForeground (display, my_gc, offlimit_color);
3237 else
3239 XSetFunction (display, my_gc, GXcopy);
3240 XSetForeground (display, my_gc, lesstif_gc->color);
3242 width = Vz (lesstif_gc->width);
3243 if (width < 0)
3244 width = 0;
3245 XSetLineAttributes (display, my_gc, width, LineSolid, cap,
3246 join);
3247 if (use_mask)
3249 if (lesstif_gc->erase)
3250 mask_gc = bclear_gc;
3251 else
3252 mask_gc = bset_gc;
3253 XSetLineAttributes (display, mask_gc, Vz (lesstif_gc->width), LineSolid, cap,
3254 join);
3258 static void
3259 lesstif_set_line_cap (hidGC gc, EndCapStyle style)
3261 lesstifGC lesstif_gc = (lesstifGC)gc;
3263 lesstif_gc->cap = style;
3266 static void
3267 lesstif_set_line_width (hidGC gc, Coord width)
3269 lesstifGC lesstif_gc = (lesstifGC)gc;
3271 lesstif_gc->width = width;
3274 static void
3275 lesstif_set_draw_xor (hidGC gc, int xor_set)
3277 lesstifGC lesstif_gc = (lesstifGC)gc;
3279 lesstif_gc->xor_set = xor_set;
3282 #define ISORT(a,b) if (a>b) { a^=b; b^=a; a^=b; }
3284 static void
3285 lesstif_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
3287 lesstifGC lesstif_gc = (lesstifGC)gc;
3288 double dx1, dy1, dx2, dy2;
3289 int vw = Vz (lesstif_gc->width);
3290 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) && lesstif_gc->erase)
3291 return;
3292 #if 0
3293 pcb_printf ("draw_line %#mD-%#mD @%#mS", x1, y1, x2, y2, lesstif_gc->width);
3294 #endif
3295 dx1 = Vx (x1);
3296 dy1 = Vy (y1);
3297 dx2 = Vx (x2);
3298 dy2 = Vy (y2);
3299 #if 0
3300 pcb_printf (" = %#mD-%#mD %s\n", x1, y1, x2, y2, lesstif_gc->colorname);
3301 #endif
3303 #if 1
3304 if (! ClipLine (0, 0, view_width, view_height,
3305 &dx1, &dy1, &dx2, &dy2, vw))
3306 return;
3307 #endif
3309 x1 = dx1;
3310 y1 = dy1;
3311 x2 = dx2;
3312 y2 = dy2;
3314 set_gc (gc);
3315 if (lesstif_gc->cap == Square_Cap && x1 == x2 && y1 == y2)
3317 XFillRectangle (display, pixmap, my_gc, x1 - vw / 2, y1 - vw / 2, vw,
3318 vw);
3319 if (use_mask)
3320 XFillRectangle (display, mask_bitmap, mask_gc, x1 - vw / 2,
3321 y1 - vw / 2, vw, vw);
3323 else
3325 XDrawLine (display, pixmap, my_gc, x1, y1, x2, y2);
3326 if (use_mask)
3327 XDrawLine (display, mask_bitmap, mask_gc, x1, y1, x2, y2);
3331 static void
3332 lesstif_draw_arc (hidGC gc, Coord cx, Coord cy, Coord width, Coord height,
3333 Angle start_angle, Angle delta_angle)
3335 lesstifGC lesstif_gc = (lesstifGC)gc;
3337 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && lesstif_gc->erase)
3338 return;
3339 #if 0
3340 pcb_printf ("draw_arc %#mD %#mSx%#mS s %d d %d", cx, cy, width, height, start_angle, delta_angle);
3341 #endif
3342 width = Vz (width);
3343 height = Vz (height);
3344 cx = Vx (cx) - width;
3345 cy = Vy (cy) - height;
3346 if (flip_x)
3348 start_angle = 180 - start_angle;
3349 delta_angle = - delta_angle;
3351 if (flip_y)
3353 start_angle = - start_angle;
3354 delta_angle = - delta_angle;
3356 start_angle = NormalizeAngle (start_angle);
3357 if (start_angle >= 180)
3358 start_angle -= 360;
3359 #if 0
3360 pcb_printf (" = %#mD %#mSx%#mS %d %s\n", cx, cy, width, height, lesstif_gc->width,
3361 lesstif_gc->colorname);
3362 #endif
3363 set_gc (gc);
3364 XDrawArc (display, pixmap, my_gc, cx, cy,
3365 width * 2, height * 2, (start_angle + 180) * 64,
3366 delta_angle * 64);
3367 if (use_mask && !TEST_FLAG (THINDRAWFLAG, PCB))
3368 XDrawArc (display, mask_bitmap, mask_gc, cx, cy,
3369 width * 2, height * 2, (start_angle + 180) * 64,
3370 delta_angle * 64);
3371 #if 0
3372 /* Enable this if you want to see the center and radii of drawn
3373 arcs, for debugging. */
3374 if (TEST_FLAG (THINDRAWFLAG, PCB)
3375 && delta_angle != 360)
3377 cx += width;
3378 cy += height;
3379 XDrawLine (display, pixmap, arc1_gc, cx, cy,
3380 cx - width*cos(start_angle*M_PI/180),
3381 cy + width*sin(start_angle*M_PI/180));
3382 XDrawLine (display, pixmap, arc2_gc, cx, cy,
3383 cx - width*cos((start_angle+delta_angle)*M_PI/180),
3384 cy + width*sin((start_angle+delta_angle)*M_PI/180));
3386 #endif
3389 static void
3390 lesstif_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
3392 lesstifGC lesstif_gc = (lesstifGC)gc;
3393 int vw = Vz (lesstif_gc->width);
3395 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && lesstif_gc->erase)
3396 return;
3397 x1 = Vx (x1);
3398 y1 = Vy (y1);
3399 x2 = Vx (x2);
3400 y2 = Vy (y2);
3401 if (x1 < -vw && x2 < -vw)
3402 return;
3403 if (y1 < -vw && y2 < -vw)
3404 return;
3405 if (x1 > view_width + vw && x2 > view_width + vw)
3406 return;
3407 if (y1 > view_height + vw && y2 > view_height + vw)
3408 return;
3409 if (x1 > x2) { int xt = x1; x1 = x2; x2 = xt; }
3410 if (y1 > y2) { int yt = y1; y1 = y2; y2 = yt; }
3411 set_gc (gc);
3412 XDrawRectangle (display, pixmap, my_gc, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
3413 if (use_mask)
3414 XDrawRectangle (display, mask_bitmap, mask_gc, x1, y1, x2 - x1 + 1,
3415 y2 - y1 + 1);
3418 static void
3419 lesstif_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius)
3421 lesstifGC lesstif_gc = (lesstifGC)gc;
3423 if (pinout && use_mask && lesstif_gc->erase)
3424 return;
3425 if ((TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) && lesstif_gc->erase)
3426 return;
3427 #if 0
3428 pcb_printf ("fill_circle %#mD %#mS", cx, cy, radius);
3429 #endif
3430 radius = Vz (radius);
3431 cx = Vx (cx) - radius;
3432 cy = Vy (cy) - radius;
3433 if (cx < -2 * radius || cx > view_width)
3434 return;
3435 if (cy < -2 * radius || cy > view_height)
3436 return;
3437 #if 0
3438 pcb_printf (" = %#mD %#mS %lx %s\n", cx, cy, radius, lesstif_gc->color, lesstif_gc->colorname);
3439 #endif
3440 set_gc (gc);
3441 XFillArc (display, pixmap, my_gc, cx, cy,
3442 radius * 2, radius * 2, 0, 360 * 64);
3443 if (use_mask)
3444 XFillArc (display, mask_bitmap, mask_gc, cx, cy,
3445 radius * 2, radius * 2, 0, 360 * 64);
3448 static void
3449 lesstif_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y)
3451 static XPoint *p = 0;
3452 static int maxp = 0;
3453 int i;
3455 if (maxp < n_coords)
3457 maxp = n_coords + 10;
3458 if (p)
3459 p = (XPoint *) realloc (p, maxp * sizeof (XPoint));
3460 else
3461 p = (XPoint *) malloc (maxp * sizeof (XPoint));
3464 for (i = 0; i < n_coords; i++)
3466 p[i].x = Vx (x[i]);
3467 p[i].y = Vy (y[i]);
3469 #if 0
3470 printf ("fill_polygon %d pts\n", n_coords);
3471 #endif
3472 set_gc (gc);
3473 XFillPolygon (display, pixmap, my_gc, p, n_coords, Complex,
3474 CoordModeOrigin);
3475 if (use_mask)
3476 XFillPolygon (display, mask_bitmap, mask_gc, p, n_coords, Complex,
3477 CoordModeOrigin);
3480 static void
3481 lesstif_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
3483 lesstifGC lesstif_gc = (lesstifGC)gc;
3484 int vw = Vz (lesstif_gc->width);
3486 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && lesstif_gc->erase)
3487 return;
3488 x1 = Vx (x1);
3489 y1 = Vy (y1);
3490 x2 = Vx (x2);
3491 y2 = Vy (y2);
3492 if (x1 < -vw && x2 < -vw)
3493 return;
3494 if (y1 < -vw && y2 < -vw)
3495 return;
3496 if (x1 > view_width + vw && x2 > view_width + vw)
3497 return;
3498 if (y1 > view_height + vw && y2 > view_height + vw)
3499 return;
3500 if (x1 > x2) { int xt = x1; x1 = x2; x2 = xt; }
3501 if (y1 > y2) { int yt = y1; y1 = y2; y2 = yt; }
3502 set_gc (gc);
3503 XFillRectangle (display, pixmap, my_gc, x1, y1, x2 - x1 + 1,
3504 y2 - y1 + 1);
3505 if (use_mask)
3506 XFillRectangle (display, mask_bitmap, mask_gc, x1, y1, x2 - x1 + 1,
3507 y2 - y1 + 1);
3510 static void
3511 lesstif_calibrate (double xval, double yval)
3513 CRASH;
3516 static int
3517 lesstif_shift_is_pressed (void)
3519 return shift_pressed;
3522 static int
3523 lesstif_control_is_pressed (void)
3525 return ctrl_pressed;
3528 static int
3529 lesstif_mod1_is_pressed (void)
3531 return alt_pressed;
3534 extern void lesstif_get_coords (const char *msg, Coord *x, Coord *y);
3536 static void
3537 lesstif_set_crosshair (int x, int y, int action)
3539 if (crosshair_x != x || crosshair_y != y)
3541 lesstif_show_crosshair(0);
3542 crosshair_x = x;
3543 crosshair_y = y;
3544 need_idle_proc ();
3546 if (mainwind
3547 && !in_move_event
3548 && (x < view_left_x
3549 || x > view_left_x + view_width * view_zoom
3550 || y < view_top_y || y > view_top_y + view_height * view_zoom))
3552 view_left_x = x - (view_width * view_zoom) / 2;
3553 view_top_y = y - (view_height * view_zoom) / 2;
3554 lesstif_pan_fixup ();
3559 if (action == HID_SC_PAN_VIEWPORT)
3561 Window root, child;
3562 unsigned int keys_buttons;
3563 int pos_x, pos_y, root_x, root_y;
3564 XQueryPointer (display, window, &root, &child,
3565 &root_x, &root_y, &pos_x, &pos_y, &keys_buttons);
3566 if (flip_x)
3567 view_left_x = x - (view_width-pos_x) * view_zoom;
3568 else
3569 view_left_x = x - pos_x * view_zoom;
3570 if (flip_y)
3571 view_top_y = y - (view_height-pos_y) * view_zoom;
3572 else
3573 view_top_y = y - pos_y * view_zoom;
3574 lesstif_pan_fixup();
3575 action = HID_SC_WARP_POINTER;
3577 if (action == HID_SC_WARP_POINTER)
3579 in_move_event ++;
3580 XWarpPointer (display, None, window, 0, 0, 0, 0, Vx(x), Vy(y));
3581 in_move_event --;
3585 typedef struct
3587 void (*func) (hidval);
3588 hidval user_data;
3589 XtIntervalId id;
3590 } TimerStruct;
3592 static void
3593 lesstif_timer_cb (XtPointer * p, XtIntervalId * id)
3595 TimerStruct *ts = (TimerStruct *) p;
3596 ts->func (ts->user_data);
3597 free (ts);
3600 static hidval
3601 lesstif_add_timer (void (*func) (hidval user_data),
3602 unsigned long milliseconds, hidval user_data)
3604 TimerStruct *t;
3605 hidval rv;
3606 t = (TimerStruct *) malloc (sizeof (TimerStruct));
3607 rv.ptr = t;
3608 t->func = func;
3609 t->user_data = user_data;
3610 t->id = XtAppAddTimeOut (app_context, milliseconds, (XtTimerCallbackProc)lesstif_timer_cb, t);
3611 return rv;
3614 static void
3615 lesstif_stop_timer (hidval hv)
3617 TimerStruct *ts = (TimerStruct *) hv.ptr;
3618 XtRemoveTimeOut (ts->id);
3619 free (ts);
3623 typedef struct
3625 void (*func) ( hidval, int, unsigned int, hidval );
3626 hidval user_data;
3627 int fd;
3628 XtInputId id;
3630 WatchStruct;
3632 /* We need a wrapper around the hid file watch because to pass the correct flags
3634 static void
3635 lesstif_watch_cb (XtPointer client_data, int *fid, XtInputId * id)
3637 unsigned int pcb_condition = 0;
3638 struct pollfd fds;
3639 short condition;
3640 hidval x;
3641 WatchStruct *watch = (WatchStruct*)client_data;
3643 fds.fd = watch->fd;
3644 fds.events = POLLIN | POLLOUT;
3645 poll( &fds, 1, 0 );
3646 condition = fds.revents;
3648 // Should we only include those we were asked to watch?
3649 if (condition & POLLIN)
3650 pcb_condition |= PCB_WATCH_READABLE;
3651 if (condition & POLLOUT)
3652 pcb_condition |= PCB_WATCH_WRITABLE;
3653 if (condition & POLLERR)
3654 pcb_condition |= PCB_WATCH_ERROR;
3655 if (condition & POLLHUP)
3656 pcb_condition |= PCB_WATCH_HANGUP;
3658 x.ptr = (void *) watch;
3659 watch->func (x, watch->fd, pcb_condition, watch->user_data);
3661 return;
3664 hidval
3665 lesstif_watch_file (int fd, unsigned int condition, void (*func) (hidval watch, int fd, unsigned int condition, hidval user_data),
3666 hidval user_data)
3668 WatchStruct *watch = (WatchStruct *) malloc (sizeof(WatchStruct));
3669 hidval ret;
3670 unsigned int xt_condition = 0;
3672 if (condition & PCB_WATCH_READABLE)
3673 xt_condition |= XtInputReadMask;
3674 if (condition & PCB_WATCH_WRITABLE)
3675 xt_condition |= XtInputWriteMask;
3676 if (condition & PCB_WATCH_ERROR)
3677 xt_condition |= XtInputExceptMask;
3678 if (condition & PCB_WATCH_HANGUP)
3679 xt_condition |= XtInputExceptMask;
3681 watch->func = func;
3682 watch->user_data = user_data;
3683 watch->fd = fd;
3684 watch->id = XtAppAddInput( app_context, fd, (XtPointer) (size_t) xt_condition, lesstif_watch_cb, watch );
3686 ret.ptr = (void *) watch;
3687 return ret;
3690 void
3691 lesstif_unwatch_file (hidval data)
3693 WatchStruct *watch = (WatchStruct*)data.ptr;
3694 XtRemoveInput( watch->id );
3695 free( watch );
3698 typedef struct
3700 XtBlockHookId id;
3701 void (*func) (hidval user_data);
3702 hidval user_data;
3703 } BlockHookStruct;
3705 static void lesstif_block_hook_cb(XtPointer user_data);
3707 static void
3708 lesstif_block_hook_cb (XtPointer user_data)
3710 BlockHookStruct *block_hook = (BlockHookStruct *)user_data;
3711 block_hook->func( block_hook->user_data );
3714 static hidval
3715 lesstif_add_block_hook (void (*func) (hidval data), hidval user_data )
3717 hidval ret;
3718 BlockHookStruct *block_hook = (BlockHookStruct *) malloc( sizeof( BlockHookStruct ));
3720 block_hook->func = func;
3721 block_hook->user_data = user_data;
3723 block_hook->id = XtAppAddBlockHook( app_context, lesstif_block_hook_cb, (XtPointer)block_hook );
3725 ret.ptr = (void *) block_hook;
3726 return ret;
3729 static void
3730 lesstif_stop_block_hook (hidval mlpoll)
3732 BlockHookStruct *block_hook = (BlockHookStruct *)mlpoll.ptr;
3733 XtRemoveBlockHook( block_hook->id );
3734 free( block_hook );
3738 extern void lesstif_logv (const char *fmt, va_list ap);
3740 extern int lesstif_confirm_dialog (char *msg, ...);
3742 extern int lesstif_close_confirm_dialog ();
3744 extern void lesstif_report_dialog (char *title, char *msg);
3746 extern int
3747 lesstif_attribute_dialog (HID_Attribute * attrs,
3748 int n_attrs, HID_Attr_Val * results,
3749 const char * title, const char * descr);
3751 static void
3752 pinout_callback (Widget da, PinoutData * pd,
3753 XmDrawingAreaCallbackStruct * cbs)
3755 BoxType region;
3756 int save_vx, save_vy, save_vw, save_vh;
3757 int save_fx, save_fy;
3758 double save_vz;
3759 Pixmap save_px;
3760 int reason = cbs ? cbs->reason : 0;
3762 if (pd->window == 0 && reason == XmCR_RESIZE)
3763 return;
3764 if (pd->window == 0 || reason == XmCR_RESIZE)
3766 Dimension w, h;
3767 double z;
3769 n = 0;
3770 stdarg (XmNwidth, &w);
3771 stdarg (XmNheight, &h);
3772 XtGetValues (da, args, n);
3774 pd->window = XtWindow (da);
3775 pd->v_width = w;
3776 pd->v_height = h;
3777 pd->zoom = (pd->right - pd->left + 1) / (double) w;
3778 z = (pd->bottom - pd->top + 1) / (double) h;
3779 if (pd->zoom < z)
3780 pd->zoom = z;
3782 pd->x = (pd->left + pd->right) / 2 - pd->v_width * pd->zoom / 2;
3783 pd->y = (pd->top + pd->bottom) / 2 - pd->v_height * pd->zoom / 2;
3786 save_vx = view_left_x;
3787 save_vy = view_top_y;
3788 save_vz = view_zoom;
3789 save_vw = view_width;
3790 save_vh = view_height;
3791 save_fx = flip_x;
3792 save_fy = flip_y;
3793 save_px = pixmap;
3794 pinout = pd;
3795 pixmap = pd->window;
3796 view_left_x = pd->x;
3797 view_top_y = pd->y;
3798 view_zoom = pd->zoom;
3799 view_width = pd->v_width;
3800 view_height = pd->v_height;
3801 use_mask = 0;
3802 flip_x = flip_y = 0;
3804 region.X1 = 0;
3805 region.Y1 = 0;
3806 region.X2 = PCB->MaxWidth;
3807 region.Y2 = PCB->MaxHeight;
3809 XFillRectangle (display, pixmap, bg_gc, 0, 0, pd->v_width, pd->v_height);
3810 hid_expose_callback (&lesstif_hid, &region, pd->item);
3812 pinout = 0;
3813 view_left_x = save_vx;
3814 view_top_y = save_vy;
3815 view_zoom = save_vz;
3816 view_width = save_vw;
3817 view_height = save_vh;
3818 pixmap = save_px;
3819 flip_x = save_fx;
3820 flip_y = save_fy;
3823 static void
3824 pinout_unmap (Widget w, PinoutData * pd, void *v)
3826 if (pd->prev)
3827 pd->prev->next = pd->next;
3828 else
3829 pinouts = pd->next;
3830 if (pd->next)
3831 pd->next->prev = pd->prev;
3832 XtDestroyWidget (XtParent (pd->form));
3833 free (pd);
3836 static void
3837 lesstif_show_item (void *item)
3839 double scale;
3840 Widget da;
3841 BoxType *extents;
3842 PinoutData *pd;
3844 for (pd = pinouts; pd; pd = pd->next)
3845 if (pd->item == item)
3846 return;
3847 if (!mainwind)
3848 return;
3850 pd = (PinoutData *) calloc (1, sizeof (PinoutData));
3852 pd->item = item;
3854 extents = hid_get_extents (item);
3855 pd->left = extents->X1;
3856 pd->right = extents->X2;
3857 pd->top = extents->Y1;
3858 pd->bottom = extents->Y2;
3860 if (pd->left > pd->right)
3862 free (pd);
3863 return;
3865 pd->prev = 0;
3866 pd->next = pinouts;
3867 if (pd->next)
3868 pd->next->prev = pd;
3869 pinouts = pd;
3870 pd->zoom = 0;
3872 n = 0;
3873 pd->form = XmCreateFormDialog (mainwind, "pinout", args, n);
3874 pd->window = 0;
3875 XtAddCallback (pd->form, XmNunmapCallback, (XtCallbackProc) pinout_unmap,
3876 (XtPointer) pd);
3878 scale =
3879 sqrt (200.0 * 200.0 /
3880 ((pd->right - pd->left + 1.0) * (pd->bottom - pd->top + 1.0)));
3882 n = 0;
3883 stdarg (XmNwidth, (int) (scale * (pd->right - pd->left + 1)));
3884 stdarg (XmNheight, (int) (scale * (pd->bottom - pd->top + 1)));
3885 stdarg (XmNleftAttachment, XmATTACH_FORM);
3886 stdarg (XmNrightAttachment, XmATTACH_FORM);
3887 stdarg (XmNtopAttachment, XmATTACH_FORM);
3888 stdarg (XmNbottomAttachment, XmATTACH_FORM);
3889 da = XmCreateDrawingArea (pd->form, "pinout", args, n);
3890 XtManageChild (da);
3892 XtAddCallback (da, XmNexposeCallback, (XtCallbackProc) pinout_callback,
3893 (XtPointer) pd);
3894 XtAddCallback (da, XmNresizeCallback, (XtCallbackProc) pinout_callback,
3895 (XtPointer) pd);
3897 XtManageChild (pd->form);
3898 pinout = 0;
3901 static void
3902 lesstif_beep (void)
3904 putchar (7);
3905 fflush (stdout);
3909 static bool progress_cancelled = false;
3911 static void
3912 progress_cancel_callback (Widget w, void *v, void *cbs)
3914 progress_cancelled = true;
3917 static Widget progress_dialog = 0;
3918 static Widget progress_cancel, progress_label;
3919 static Widget progress_scale;
3921 static void
3922 lesstif_progress_dialog (int so_far, int total, const char *msg)
3924 XmString xs;
3926 if (mainwind == 0)
3927 return;
3929 if (progress_dialog == 0)
3931 Atom close_atom;
3933 n = 0;
3934 stdarg (XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON);
3935 stdarg (XmNtitle, "Progress");
3936 stdarg (XmNdialogStyle, XmDIALOG_APPLICATION_MODAL);
3937 stdarg (XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
3938 progress_dialog = XmCreateInformationDialog (mainwind, "progress", args, n);
3939 XtAddCallback (progress_dialog, XmNcancelCallback,
3940 (XtCallbackProc) progress_cancel_callback, NULL);
3942 progress_cancel = XmMessageBoxGetChild (progress_dialog, XmDIALOG_CANCEL_BUTTON);
3943 progress_label = XmMessageBoxGetChild (progress_dialog, XmDIALOG_MESSAGE_LABEL);
3945 XtUnmanageChild (XmMessageBoxGetChild (progress_dialog, XmDIALOG_OK_BUTTON));
3946 XtUnmanageChild (XmMessageBoxGetChild (progress_dialog, XmDIALOG_HELP_BUTTON));
3948 stdarg (XmNdefaultPosition, False);
3949 XtSetValues (progress_dialog, args, n);
3951 n = 0;
3952 stdarg(XmNminimum, 0);
3953 stdarg(XmNvalue, 0);
3954 stdarg(XmNmaximum, total > 0 ? total : 1);
3955 stdarg(XmNorientation, XmHORIZONTAL);
3956 stdarg(XmNshowArrows, false);
3957 progress_scale = XmCreateScrollBar (progress_dialog, "scale", args, n);
3958 XtManageChild (progress_scale);
3960 close_atom = XmInternAtom (display, "WM_DELETE_WINDOW", 0);
3961 XmAddWMProtocolCallback (XtParent (progress_dialog), close_atom,
3962 (XtCallbackProc) progress_cancel_callback, 0);
3965 n = 0;
3966 stdarg(XmNvalue, 0);
3967 stdarg(XmNsliderSize, (so_far <= total) ? (so_far < 0) ? 0 : so_far : total);
3968 stdarg(XmNmaximum, total > 0 ? total : 1);
3969 XtSetValues (progress_scale, args, n);
3971 n = 0;
3972 xs = XmStringCreatePCB ((char *)msg);
3973 stdarg (XmNmessageString, xs);
3974 XtSetValues (progress_dialog, args, n);
3976 return;
3979 #define MIN_TIME_SEPARATION 0.1 /* seconds */
3981 static int
3982 lesstif_progress (int so_far, int total, const char *message)
3984 static bool started = false;
3985 XEvent e;
3986 struct timeval time;
3987 double time_delta, time_now;
3988 static double time_then = 0.0;
3989 int retval = 0;
3991 if (so_far == 0 && total == 0 && message == NULL)
3993 XtUnmanageChild (progress_dialog);
3994 started = false;
3995 progress_cancelled = false;
3996 return retval;
3999 gettimeofday (&time, NULL);
4000 time_now = time.tv_sec + time.tv_usec / 1000000.0;
4002 time_delta = time_now - time_then;
4004 if (started && time_delta < MIN_TIME_SEPARATION)
4005 return retval;
4007 /* Create or update the progress dialog */
4008 lesstif_progress_dialog (so_far, total, message);
4010 if (!started)
4012 XtManageChild (progress_dialog);
4013 started = true;
4016 /* Dispatch pending events */
4017 while (XtAppPending (app_context))
4019 XtAppNextEvent (app_context, &e);
4020 XtDispatchEvent (&e);
4022 idle_proc (NULL);
4024 /* If rendering takes a while, make sure the core has enough time to
4025 do work. */
4026 gettimeofday (&time, NULL);
4027 time_then = time.tv_sec + time.tv_usec / 1000000.0;
4029 return progress_cancelled;
4032 static HID_DRAW *
4033 lesstif_request_debug_draw (void)
4035 /* Send drawing to the backing pixmap */
4036 pixmap = main_pixmap;
4037 return lesstif_hid.graphics;
4040 static void
4041 lesstif_flush_debug_draw (void)
4043 /* Copy the backing pixmap to the display and redraw any attached objects */
4044 XSetFunction (display, my_gc, GXcopy);
4045 XCopyArea (display, main_pixmap, window, my_gc, 0, 0, view_width,
4046 view_height, 0, 0);
4047 pixmap = window;
4048 if (crosshair_on)
4050 DrawAttached (crosshair_gc);
4051 DrawMark (crosshair_gc);
4053 pixmap = main_pixmap;
4056 static void
4057 lesstif_finish_debug_draw (void)
4059 lesstif_flush_debug_draw ();
4060 /* No special tear down requirements
4064 #include "dolists.h"
4066 void
4067 hid_lesstif_init ()
4069 memset (&lesstif_hid, 0, sizeof (HID));
4070 memset (&lesstif_graphics, 0, sizeof (HID_DRAW));
4071 memset (&lesstif_graphics_class, 0, sizeof (HID_DRAW_CLASS));
4073 common_nogui_init (&lesstif_hid);
4075 lesstif_hid.struct_size = sizeof (HID);
4076 lesstif_hid.name = "lesstif";
4077 lesstif_hid.description = "LessTif - a Motif clone for X/Unix";
4078 lesstif_hid.gui = 1;
4080 lesstif_hid.get_export_options = lesstif_get_export_options;
4081 lesstif_hid.do_export = lesstif_do_export;
4082 lesstif_hid.parse_arguments = lesstif_parse_arguments;
4083 lesstif_hid.invalidate_lr = lesstif_invalidate_lr;
4084 lesstif_hid.invalidate_all = lesstif_invalidate_all;
4085 lesstif_hid.notify_crosshair_change = lesstif_notify_crosshair_change;
4086 lesstif_hid.notify_mark_change = lesstif_notify_mark_change;
4088 lesstif_hid.calibrate = lesstif_calibrate;
4089 lesstif_hid.shift_is_pressed = lesstif_shift_is_pressed;
4090 lesstif_hid.control_is_pressed = lesstif_control_is_pressed;
4091 lesstif_hid.mod1_is_pressed = lesstif_mod1_is_pressed;
4092 lesstif_hid.get_coords = lesstif_get_coords;
4093 lesstif_hid.set_crosshair = lesstif_set_crosshair;
4094 lesstif_hid.add_timer = lesstif_add_timer;
4095 lesstif_hid.stop_timer = lesstif_stop_timer;
4096 lesstif_hid.watch_file = lesstif_watch_file;
4097 lesstif_hid.unwatch_file = lesstif_unwatch_file;
4098 lesstif_hid.add_block_hook = lesstif_add_block_hook;
4099 lesstif_hid.stop_block_hook = lesstif_stop_block_hook;
4101 lesstif_hid.log = lesstif_log;
4102 lesstif_hid.logv = lesstif_logv;
4103 lesstif_hid.confirm_dialog = lesstif_confirm_dialog;
4104 lesstif_hid.close_confirm_dialog = lesstif_close_confirm_dialog;
4105 lesstif_hid.report_dialog = lesstif_report_dialog;
4106 lesstif_hid.prompt_for = lesstif_prompt_for;
4107 lesstif_hid.fileselect = lesstif_fileselect;
4108 lesstif_hid.attribute_dialog = lesstif_attribute_dialog;
4109 lesstif_hid.show_item = lesstif_show_item;
4110 lesstif_hid.beep = lesstif_beep;
4111 lesstif_hid.progress = lesstif_progress;
4112 lesstif_hid.edit_attributes = lesstif_attributes_dialog;
4114 lesstif_hid.request_debug_draw = lesstif_request_debug_draw;
4115 lesstif_hid.flush_debug_draw = lesstif_flush_debug_draw;
4116 lesstif_hid.finish_debug_draw = lesstif_finish_debug_draw;
4118 lesstif_hid.graphics = &lesstif_graphics;
4120 common_draw_helpers_class_init (&lesstif_graphics_class);
4122 lesstif_graphics_class.set_layer = lesstif_set_layer;
4123 lesstif_graphics_class.make_gc = lesstif_make_gc;
4124 lesstif_graphics_class.destroy_gc = lesstif_destroy_gc;
4125 lesstif_graphics_class.use_mask = lesstif_use_mask;
4126 lesstif_graphics_class.set_color = lesstif_set_color;
4127 lesstif_graphics_class.set_line_cap = lesstif_set_line_cap;
4128 lesstif_graphics_class.set_line_width = lesstif_set_line_width;
4129 lesstif_graphics_class.set_draw_xor = lesstif_set_draw_xor;
4130 lesstif_graphics_class.draw_line = lesstif_draw_line;
4131 lesstif_graphics_class.draw_arc = lesstif_draw_arc;
4132 lesstif_graphics_class.draw_rect = lesstif_draw_rect;
4133 lesstif_graphics_class.fill_circle = lesstif_fill_circle;
4134 lesstif_graphics_class.fill_polygon = lesstif_fill_polygon;
4135 lesstif_graphics_class.fill_rect = lesstif_fill_rect;
4137 lesstif_graphics_class.draw_pcb_polygon = common_gui_draw_pcb_polygon;
4139 lesstif_graphics.klass = &lesstif_graphics_class;
4140 lesstif_graphics.poly_before = true;
4141 common_draw_helpers_init (&lesstif_graphics);
4143 hid_register_hid (&lesstif_hid);
4144 #include "lesstif_lists.h"