Convert argument in HID_Flags to (void *) rather than (int)
[geda-pcb/pcjc2.git] / src / hid / lesstif / main.c
blob04d9f6c375345ac339d4dc84f7035eb5ddebf5ba
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 "../hidint.h"
29 #include "hid/common/hidnogui.h"
30 #include "hid/common/draw_helpers.h"
31 #include "hid/common/hid_resource.h"
32 #include "lesstif.h"
34 #ifdef HAVE_LIBDMALLOC
35 #include <dmalloc.h>
36 #endif
38 #include <sys/poll.h>
40 #ifndef XtRDouble
41 #define XtRDouble "Double"
42 #endif
44 /* How big the viewport can be relative to the pcb size. */
45 #define MAX_ZOOM_SCALE 10
46 #define UUNIT Settings.grid_unit->allow
48 typedef struct hid_gc_struct
50 HID *me_pointer;
51 Pixel color;
52 const char *colorname;
53 int width;
54 EndCapStyle cap;
55 char xor_set;
56 char erase;
57 } hid_gc_struct;
59 static HID lesstif_hid;
61 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented GUI function %s\n", __FUNCTION__), abort()
63 XtAppContext app_context;
64 Widget appwidget;
65 Display *display;
66 static Window window = 0;
67 static Cursor my_cursor = 0;
68 static int old_cursor_mode = -1;
69 static int over_point = 0;
71 /* The first is the "current" pixmap. The main_ is the real one we
72 usually use, the mask_ are the ones for doing polygon masks. The
73 pixmap is the saved pixels, the bitmap is for the "erase" color.
74 We set pixmap to point to main_pixmap or mask_pixmap as needed. */
75 static Pixmap pixmap = 0;
76 static Pixmap main_pixmap = 0;
77 static Pixmap mask_pixmap = 0;
78 static Pixmap mask_bitmap = 0;
79 static int use_mask = 0;
81 static int use_xrender = 0;
82 #ifdef HAVE_XRENDER
83 static Picture main_picture;
84 static Picture mask_picture;
85 static Pixmap pale_pixmap;
86 static Picture pale_picture;
87 #endif /* HAVE_XRENDER */
89 static int pixmap_w = 0, pixmap_h = 0;
90 Screen *screen_s;
91 int screen;
92 static Colormap colormap;
93 static GC my_gc = 0, bg_gc, clip_gc = 0, bset_gc = 0, bclear_gc = 0, mask_gc =
95 static Pixel bgcolor, offlimit_color, grid_color;
96 static int bgred, bggreen, bgblue;
98 static GC arc1_gc, arc2_gc;
100 /* These are for the pinout windows. */
101 typedef struct PinoutData
103 struct PinoutData *prev, *next;
104 Widget form;
105 Window window;
106 Coord left, right, top, bottom; /* PCB extents of item */
107 Coord x, y; /* PCB coordinates of upper right corner of window */
108 double zoom; /* PCB units per screen pixel */
109 int v_width, v_height; /* pixels */
110 void *item;
111 } PinoutData;
113 /* Linked list of all pinout windows. */
114 static PinoutData *pinouts = 0;
115 /* If set, we are currently updating this pinout window. */
116 static PinoutData *pinout = 0;
118 static int crosshair_x = 0, crosshair_y = 0;
119 static int in_move_event = 0, crosshair_in_window = 1;
121 Widget mainwind;
122 Widget work_area, messages, command, hscroll, vscroll;
123 static Widget m_mark, m_crosshair, m_grid, m_zoom, m_mode, m_status;
124 static Widget m_rats;
125 Widget lesstif_m_layer;
126 Widget m_click;
128 /* This is the size, in pixels, of the viewport. */
129 static int view_width, view_height;
130 /* This is the PCB location represented by the upper left corner of
131 the viewport. Note that PCB coordinates put 0,0 in the upper left,
132 much like X does. */
133 static int view_left_x = 0, view_top_y = 0;
134 /* Denotes PCB units per screen pixel. Larger numbers mean zooming
135 out - the largest value means you are looking at the whole
136 board. */
137 static double view_zoom = MIL_TO_COORD (10), prev_view_zoom = MIL_TO_COORD (10);
138 static bool flip_x = 0, flip_y = 0;
139 static bool autofade = 0;
140 static bool crosshair_on = true;
142 static void
143 ShowCrosshair (bool show)
145 if (crosshair_on == show)
146 return;
148 notify_crosshair_change (false);
149 if (Marked.status)
150 notify_mark_change (false);
152 crosshair_on = show;
154 notify_crosshair_change (true);
155 if (Marked.status)
156 notify_mark_change (true);
159 static int
160 flag_flipx (void *data)
162 return flip_x;
164 static int
165 flag_flipy (void *data)
167 return flip_y;
170 HID_Flag lesstif_main_flag_list[] = {
171 {"flip_x", flag_flipx, NULL},
172 {"flip_y", flag_flipy, NULL}
175 REGISTER_FLAGS (lesstif_main_flag_list)
177 /* This is the size of the current PCB work area. */
178 /* Use PCB->MaxWidth, PCB->MaxHeight. */
179 /* static int pcb_width, pcb_height; */
181 static Arg args[30];
182 static int n;
183 #define stdarg(t,v) XtSetArg(args[n], t, v), n++
186 static int use_private_colormap = 0;
187 static int stdin_listen = 0;
188 static char *background_image_file = 0;
189 char *lesstif_pcbmenu_path = "pcb-menu.res";
191 HID_Attribute lesstif_attribute_list[] = {
192 {"install", "Install private colormap",
193 HID_Boolean, 0, 0, {0, 0, 0}, 0, &use_private_colormap},
194 #define HA_colormap 0
196 /* %start-doc options "22 lesstif GUI Options"
197 @ftable @code
198 @item --listen
199 Listen for actions on stdin.
200 @end ftable
201 %end-doc
203 {"listen", "Listen on standard input for actions",
204 HID_Boolean, 0, 0, {0, 0, 0}, 0, &stdin_listen},
205 #define HA_listen 1
207 /* %start-doc options "22 lesstif GUI Options"
208 @ftable @code
209 @item --bg-image <string>
210 File name of an image to put into the background of the GUI canvas. The image must
211 be a color PPM image, in binary (not ASCII) format. It can be any size, and will be
212 automatically scaled to fit the canvas.
213 @end ftable
214 %end-doc
216 {"bg-image", "Background Image",
217 HID_String, 0, 0, {0, 0, 0}, 0, &background_image_file},
218 #define HA_bg_image 2
220 /* %start-doc options "22 lesstif GUI Options"
221 @ftable @code
222 @item --pcb-menu <string>
223 Location of the @file{pcb-menu.res} file which defines the menu for the lesstif GUI.
224 @end ftable
225 %end-doc
227 {"pcb-menu", "Location of pcb-menu.res file",
228 HID_String, 0, 0, {0, PCBLIBDIR "/pcb-menu.res", 0}, 0, &lesstif_pcbmenu_path}
229 #define HA_pcbmenu 3
232 REGISTER_ATTRIBUTES (lesstif_attribute_list)
234 static void lesstif_use_mask (int use_it);
235 static void zoom_max ();
236 static void zoom_to (double factor, int x, int y);
237 static void zoom_by (double factor, int x, int y);
238 static void zoom_toggle (int x, int y);
239 static void pinout_callback (Widget, PinoutData *,
240 XmDrawingAreaCallbackStruct *);
241 static void pinout_unmap (Widget, PinoutData *, void *);
242 static void Pan (int mode, int x, int y);
244 /* Px converts view->pcb, Vx converts pcb->view */
246 static inline int
247 Vx (Coord x)
249 int rv = (x - view_left_x) / view_zoom + 0.5;
250 if (flip_x)
251 rv = view_width - rv;
252 return rv;
255 static inline int
256 Vy (Coord y)
258 int rv = (y - view_top_y) / view_zoom + 0.5;
259 if (flip_y)
260 rv = view_height - rv;
261 return rv;
264 static inline int
265 Vz (Coord z)
267 return z / view_zoom + 0.5;
270 static inline Coord
271 Px (int x)
273 if (flip_x)
274 x = view_width - x;
275 return x * view_zoom + view_left_x;
278 static inline Coord
279 Py (int y)
281 if (flip_y)
282 y = view_height - y;
283 return y * view_zoom + view_top_y;
286 static inline Coord
287 Pz (int z)
289 return z * view_zoom;
292 void
293 lesstif_coords_to_pcb (int vx, int vy, Coord *px, Coord *py)
295 *px = Px (vx);
296 *py = Py (vy);
299 Pixel
300 lesstif_parse_color (char *value)
302 XColor color;
303 if (XParseColor (display, colormap, value, &color))
304 if (XAllocColor (display, colormap, &color))
305 return color.pixel;
306 return 0;
309 static void
310 do_color (char *value, char *which)
312 XColor color;
313 if (XParseColor (display, colormap, value, &color))
314 if (XAllocColor (display, colormap, &color))
316 stdarg (which, color.pixel);
320 /* ------------------------------------------------------------ */
322 static char *
323 cur_clip ()
325 if (TEST_FLAG (ORTHOMOVEFLAG, PCB))
326 return "+";
327 if (TEST_FLAG (ALLDIRECTIONFLAG, PCB))
328 return "*";
329 if (PCB->Clipping == 0)
330 return "X";
331 if (PCB->Clipping == 1)
332 return "_/";
333 return "\\_";
336 /* Called from the core when it's busy doing something and we need to
337 indicate that to the user. */
338 static int
339 Busy(int argc, char **argv, Coord x, Coord y)
341 static Cursor busy_cursor = 0;
342 if (busy_cursor == 0)
343 busy_cursor = XCreateFontCursor (display, XC_watch);
344 XDefineCursor (display, window, busy_cursor);
345 XFlush(display);
346 old_cursor_mode = -1;
347 return 0;
350 /* ---------------------------------------------------------------------- */
352 /* Local actions. */
354 static int
355 PointCursor (int argc, char **argv, Coord x, Coord y)
357 if (argc > 0)
358 over_point = 1;
359 else
360 over_point = 0;
361 old_cursor_mode = -1;
362 return 0;
365 static int
366 PCBChanged (int argc, char **argv, Coord x, Coord y)
368 if (work_area == 0)
369 return 0;
370 /*pcb_printf("PCB Changed! %$mD\n", PCB->MaxWidth, PCB->MaxHeight); */
371 n = 0;
372 stdarg (XmNminimum, 0);
373 stdarg (XmNvalue, 0);
374 stdarg (XmNsliderSize, PCB->MaxWidth ? PCB->MaxWidth : 1);
375 stdarg (XmNmaximum, PCB->MaxWidth ? PCB->MaxWidth : 1);
376 XtSetValues (hscroll, args, n);
377 n = 0;
378 stdarg (XmNminimum, 0);
379 stdarg (XmNvalue, 0);
380 stdarg (XmNsliderSize, PCB->MaxHeight ? PCB->MaxHeight : 1);
381 stdarg (XmNmaximum, PCB->MaxHeight ? PCB->MaxHeight : 1);
382 XtSetValues (vscroll, args, n);
383 zoom_max ();
385 hid_action ("NetlistChanged");
386 hid_action ("LayersChanged");
387 hid_action ("RouteStylesChanged");
388 lesstif_sizes_reset ();
389 lesstif_update_layer_groups ();
390 while (pinouts)
391 pinout_unmap (0, pinouts, 0);
392 if (PCB->Filename)
394 char *cp = strrchr (PCB->Filename, '/');
395 n = 0;
396 stdarg (XmNtitle, cp ? cp + 1 : PCB->Filename);
397 XtSetValues (appwidget, args, n);
399 return 0;
403 static const char setunits_syntax[] =
404 "SetUnits(mm|mil)";
406 static const char setunits_help[] =
407 "Set the default measurement units.";
409 /* %start-doc actions SetUnits
411 @table @code
413 @item mil
414 Sets the display units to mils (1/1000 inch).
416 @item mm
417 Sets the display units to millimeters.
419 @end table
421 %end-doc */
423 static int
424 SetUnits (int argc, char **argv, Coord x, Coord y)
426 const Unit *new_unit;
427 if (argc == 0)
428 return 0;
429 new_unit = get_unit_struct (argv[0]);
430 if (new_unit != NULL && new_unit->allow != NO_PRINT)
432 Settings.grid_unit = new_unit;
433 Settings.increments = get_increments_struct (Settings.grid_unit->family);
434 AttributePut (PCB, "PCB::grid::unit", argv[0]);
436 lesstif_sizes_reset ();
437 lesstif_styles_update_values ();
438 return 0;
441 static const char zoom_syntax[] =
442 "Zoom()\n"
443 "Zoom(factor)";
445 static const char zoom_help[] =
446 "Various zoom factor changes.";
448 /* %start-doc actions Zoom
450 Changes the zoom (magnification) of the view of the board. If no
451 arguments are passed, the view is scaled such that the board just fits
452 inside the visible window (i.e. ``view all''). Otherwise,
453 @var{factor} specifies a change in zoom factor. It may be prefixed by
454 @code{+}, @code{-}, or @code{=} to change how the zoom factor is
455 modified. The @var{factor} is a floating point number, such as
456 @code{1.5} or @code{0.75}.
458 @table @code
460 @item +@var{factor}
461 Values greater than 1.0 cause the board to be drawn smaller; more of
462 the board will be visible. Values between 0.0 and 1.0 cause the board
463 to be drawn bigger; less of the board will be visible.
465 @item -@var{factor}
466 Values greater than 1.0 cause the board to be drawn bigger; less of
467 the board will be visible. Values between 0.0 and 1.0 cause the board
468 to be drawn smaller; more of the board will be visible.
470 @item =@var{factor}
472 The @var{factor} is an absolute zoom factor; the unit for this value
473 is "PCB units per screen pixel". Since PCB units are 0.01 mil, a
474 @var{factor} of 1000 means 10 mils (0.01 in) per pixel, or 100 DPI,
475 about the actual resolution of most screens - resulting in an "actual
476 size" board. Similarly, a @var{factor} of 100 gives you a 10x actual
477 size.
479 @end table
481 Note that zoom factors of zero are silently ignored.
483 %end-doc */
485 static int
486 ZoomAction (int argc, char **argv, Coord x, Coord y)
488 const char *vp;
489 double v;
490 if (x == 0 && y == 0)
492 x = view_width / 2;
493 y = view_height / 2;
495 else
497 x = Vx (x);
498 y = Vy (y);
500 if (argc < 1)
502 zoom_max ();
503 return 0;
505 vp = argv[0];
506 if (strcasecmp (vp, "toggle") == 0)
508 zoom_toggle (x, y);
509 return 0;
511 if (*vp == '+' || *vp == '-' || *vp == '=')
512 vp++;
513 v = g_ascii_strtod (vp, 0);
514 if (v <= 0)
515 return 1;
516 switch (argv[0][0])
518 case '-':
519 zoom_by (1 / v, x, y);
520 break;
521 default:
522 case '+':
523 zoom_by (v, x, y);
524 break;
525 case '=':
526 zoom_to (v, x, y);
527 break;
529 return 0;
532 static int pan_thumb_mode;
534 static int
535 PanAction (int argc, char **argv, Coord x, Coord y)
537 int mode;
539 if (argc == 2)
541 pan_thumb_mode = (strcasecmp (argv[0], "thumb") == 0) ? 1 : 0;
542 mode = atoi (argv[1]);
544 else
546 pan_thumb_mode = 0;
547 mode = atoi (argv[0]);
549 Pan (mode, Vx(x), Vy(y));
551 return 0;
554 static const char swapsides_syntax[] =
555 "SwapSides(|v|h|r)";
557 static const char swapsides_help[] =
558 "Swaps the side of the board you're looking at.";
560 /* %start-doc actions SwapSides
562 This action changes the way you view the board.
564 @table @code
566 @item v
567 Flips the board over vertically (up/down).
569 @item h
570 Flips the board over horizontally (left/right), like flipping pages in
571 a book.
573 @item r
574 Rotates the board 180 degrees without changing sides.
576 @end table
578 If no argument is given, the board isn't moved but the opposite side
579 is shown.
581 Normally, this action changes which pads and silk layer are drawn as
582 true silk, and which are drawn as the "invisible" layer. It also
583 determines which solder mask you see.
585 As a special case, if the layer group for the side you're looking at
586 is visible and currently active, and the layer group for the opposite
587 is not visible (i.e. disabled), then this action will also swap which
588 layer group is visible and active, effectively swapping the ``working
589 side'' of the board.
591 %end-doc */
593 static int
594 group_showing (int g, int *c)
596 int i, l;
597 *c = PCB->LayerGroups.Entries[g][0];
598 for (i=0; i<PCB->LayerGroups.Number[g]; i++)
600 l = PCB->LayerGroups.Entries[g][i];
601 if (l >= 0 && l < max_copper_layer)
603 *c = l;
604 if (PCB->Data->Layer[l].On)
605 return 1;
608 return 0;
611 static int
612 SwapSides (int argc, char **argv, Coord x, Coord y)
614 int old_shown_side = Settings.ShowSolderSide;
615 int comp_group = GetLayerGroupNumberByNumber (component_silk_layer);
616 int solder_group = GetLayerGroupNumberByNumber (solder_silk_layer);
617 int active_group = GetLayerGroupNumberByNumber (LayerStack[0]);
618 int comp_layer;
619 int solder_layer;
620 int comp_showing = group_showing (comp_group, &comp_layer);
621 int solder_showing = group_showing (solder_group, &solder_layer);
623 if (argc > 0)
625 switch (argv[0][0]) {
626 case 'h':
627 case 'H':
628 flip_x = ! flip_x;
629 break;
630 case 'v':
631 case 'V':
632 flip_y = ! flip_y;
633 break;
634 case 'r':
635 case 'R':
636 flip_x = ! flip_x;
637 flip_y = ! flip_y;
638 break;
639 default:
640 return 1;
642 /* SwapSides will swap this */
643 Settings.ShowSolderSide = (flip_x == flip_y);
646 n = 0;
647 if (flip_x)
648 stdarg (XmNprocessingDirection, XmMAX_ON_LEFT);
649 else
650 stdarg (XmNprocessingDirection, XmMAX_ON_RIGHT);
651 XtSetValues (hscroll, args, n);
653 n = 0;
654 if (flip_y)
655 stdarg (XmNprocessingDirection, XmMAX_ON_TOP);
656 else
657 stdarg (XmNprocessingDirection, XmMAX_ON_BOTTOM);
658 XtSetValues (vscroll, args, n);
660 Settings.ShowSolderSide = !Settings.ShowSolderSide;
662 /* The idea is that if we're looking at the front side and the front
663 layer is active (or visa versa), switching sides should switch
664 layers too. We used to only do this if the other layer wasn't
665 shown, but we now do it always. Change it back if users get
666 confused. */
667 if (Settings.ShowSolderSide != old_shown_side)
669 if (Settings.ShowSolderSide)
671 if (active_group == comp_group)
673 if (comp_showing && !solder_showing)
674 ChangeGroupVisibility (comp_layer, 0, 0);
675 ChangeGroupVisibility (solder_layer, 1, 1);
678 else
680 if (active_group == solder_group)
682 if (solder_showing && !comp_showing)
683 ChangeGroupVisibility (solder_layer, 0, 0);
684 ChangeGroupVisibility (comp_layer, 1, 1);
688 lesstif_invalidate_all ();
689 return 0;
692 static Widget m_cmd = 0, m_cmd_label;
694 static void
695 command_callback (Widget w, XtPointer uptr, XmTextVerifyCallbackStruct * cbs)
697 char *s;
698 switch (cbs->reason)
700 case XmCR_ACTIVATE:
701 s = XmTextGetString (w);
702 lesstif_show_crosshair (0);
703 hid_parse_command (s);
704 XtFree (s);
705 XmTextSetString (w, "");
706 case XmCR_LOSING_FOCUS:
707 XtUnmanageChild (m_cmd);
708 XtUnmanageChild (m_cmd_label);
709 break;
713 static void
714 command_event_handler (Widget w, XtPointer p, XEvent * e, Boolean * cont)
716 char buf[10];
717 KeySym sym;
718 int slen;
720 switch (e->type)
722 case KeyPress:
723 slen = XLookupString ((XKeyEvent *)e, buf, sizeof (buf), &sym, NULL);
724 switch (sym)
726 case XK_Escape:
727 XtUnmanageChild (m_cmd);
728 XtUnmanageChild (m_cmd_label);
729 XmTextSetString (w, "");
730 *cont = False;
731 break;
733 break;
737 static const char command_syntax[] =
738 "Command()";
740 static const char command_help[] =
741 "Displays the command line input window.";
743 /* %start-doc actions Command
745 The command window allows the user to manually enter actions to be
746 executed. Action syntax can be done one of two ways:
748 @table @code
750 @item
751 Follow the action name by an open parenthesis, arguments separated by
752 commas, end with a close parenthesis. Example: @code{Abc(1,2,3)}
754 @item
755 Separate the action name and arguments by spaces. Example: @code{Abc
756 1 2 3}.
758 @end table
760 The first option allows you to have arguments with spaces in them,
761 but the second is more ``natural'' to type for most people.
763 Note that action names are not case sensitive, but arguments normally
764 are. However, most actions will check for ``keywords'' in a case
765 insensitive way.
767 There are three ways to finish with the command window. If you press
768 the @code{Enter} key, the command is invoked, the window goes away,
769 and the next time you bring up the command window it's empty. If you
770 press the @code{Esc} key, the window goes away without invoking
771 anything, and the next time you bring up the command window it's
772 empty. If you change focus away from the command window (i.e. click
773 on some other window), the command window goes away but the next time
774 you bring it up it resumes entering the command you were entering
775 before.
777 %end-doc */
779 static int
780 Command (int argc, char **argv, Coord x, Coord y)
782 XtManageChild (m_cmd_label);
783 XtManageChild (m_cmd);
784 XmProcessTraversal (m_cmd, XmTRAVERSE_CURRENT);
785 return 0;
788 static const char benchmark_syntax[] =
789 "Benchmark()";
791 static const char benchmark_help[] =
792 "Benchmark the GUI speed.";
794 /* %start-doc actions Benchmark
796 This action is used to speed-test the Lesstif graphics subsystem. It
797 redraws the current screen as many times as possible in ten seconds.
798 It reports the amount of time needed to draw the screen once.
800 %end-doc */
802 static int
803 Benchmark (int argc, char **argv, Coord x, Coord y)
805 int i = 0;
806 time_t start, end;
807 BoxType region;
808 Drawable save_main;
810 save_main = main_pixmap;
811 main_pixmap = window;
813 region.X1 = 0;
814 region.Y1 = 0;
815 region.X2 = PCB->MaxWidth;
816 region.Y2 = PCB->MaxHeight;
818 pixmap = window;
819 XSync (display, 0);
820 time (&start);
823 XFillRectangle (display, pixmap, bg_gc, 0, 0, view_width, view_height);
824 hid_expose_callback (&lesstif_hid, &region, 0);
825 XSync (display, 0);
826 time (&end);
827 i++;
829 while (end - start < 10);
831 printf ("%g redraws per second\n", i / 10.0);
833 main_pixmap = save_main;
834 return 0;
837 static int
838 Center(int argc, char **argv, Coord x, Coord y)
840 x = GridFit (x, PCB->Grid, PCB->GridOffsetX);
841 y = GridFit (y, PCB->Grid, PCB->GridOffsetY);
842 view_left_x = x - (view_width * view_zoom) / 2;
843 view_top_y = y - (view_height * view_zoom) / 2;
844 lesstif_pan_fixup ();
845 /* Move the pointer to the center of the window, but only if it's
846 currently within the window already. Watch out for edges,
847 though. */
848 XWarpPointer (display, window, window, 0, 0, view_width, view_height,
849 Vx(x), Vy(y));
850 return 0;
853 static const char cursor_syntax[] =
854 "Cursor(Type,DeltaUp,DeltaRight,Units)";
856 static const char cursor_help[] =
857 "Move the cursor.";
859 /* %start-doc actions Cursor
861 This action moves the mouse cursor. Unlike other actions which take
862 coordinates, this action's coordinates are always relative to the
863 user's view of the board. Thus, a positive @var{DeltaUp} may move the
864 cursor towards the board origin if the board is inverted.
866 Type is one of @samp{Pan} or @samp{Warp}. @samp{Pan} causes the
867 viewport to move such that the crosshair is under the mouse cursor.
868 @samp{Warp} causes the mouse cursor to move to be above the crosshair.
870 @var{Units} can be one of the following:
872 @table @samp
874 @item mil
875 @itemx mm
876 The cursor is moved by that amount, in board units.
878 @item grid
879 The cursor is moved by that many grid points.
881 @item view
882 The values are percentages of the viewport's view. Thus, a pan of
883 @samp{100} would scroll the viewport by exactly the width of the
884 current view.
886 @item board
887 The values are percentages of the board size. Thus, a move of
888 @samp{50,50} moves you halfway across the board.
890 @end table
892 %end-doc */
894 static int
895 CursorAction(int argc, char **argv, Coord x, Coord y)
897 UnitList extra_units_x = {
898 { "grid", PCB->Grid, 0 },
899 { "view", Pz(view_width), UNIT_PERCENT },
900 { "board", PCB->MaxWidth, UNIT_PERCENT },
901 { "", 0, 0 }
903 UnitList extra_units_y = {
904 { "grid", PCB->Grid, 0 },
905 { "view", Pz(view_height), UNIT_PERCENT },
906 { "board", PCB->MaxHeight, UNIT_PERCENT },
907 { "", 0, 0 }
909 int pan_warp = HID_SC_DO_NOTHING;
910 double dx, dy;
912 if (argc != 4)
913 AFAIL(cursor);
915 if (strcasecmp (argv[0], "pan") == 0)
916 pan_warp = HID_SC_PAN_VIEWPORT;
917 else if (strcasecmp (argv[0], "warp") == 0)
918 pan_warp = HID_SC_WARP_POINTER;
919 else
920 AFAIL(cursor);
922 dx = GetValueEx (argv[1], argv[3], NULL, extra_units_x, "mil");
923 if (flip_x)
924 dx = -dx;
925 dy = GetValueEx (argv[2], argv[3], NULL, extra_units_y, "mil");
926 if (!flip_y)
927 dy = -dy;
929 EventMoveCrosshair (Crosshair.X + dx, Crosshair.Y + dy);
930 gui->set_crosshair (Crosshair.X, Crosshair.Y, pan_warp);
932 return 0;
935 HID_Action lesstif_main_action_list[] = {
936 {"PCBChanged", 0, PCBChanged,
937 pcbchanged_help, pcbchanged_syntax},
938 {"SetUnits", 0, SetUnits,
939 setunits_help, setunits_syntax},
940 {"Zoom", "Click on a place to zoom in", ZoomAction,
941 zoom_help, zoom_syntax},
942 {"Pan", "Click on a place to pan", PanAction,
943 zoom_help, zoom_syntax},
944 {"SwapSides", 0, SwapSides,
945 swapsides_help, swapsides_syntax},
946 {"Command", 0, Command,
947 command_help, command_syntax},
948 {"Benchmark", 0, Benchmark,
949 benchmark_help, benchmark_syntax},
950 {"PointCursor", 0, PointCursor},
951 {"Center", "Click on a location to center", Center},
952 {"Busy", 0, Busy},
953 {"Cursor", 0, CursorAction,
954 cursor_help, cursor_syntax},
957 REGISTER_ACTIONS (lesstif_main_action_list)
960 /* ----------------------------------------------------------------------
961 * redraws the background image
964 static int bg_w, bg_h, bgi_w, bgi_h;
965 static Pixel **bg = 0;
966 static XImage *bgi = 0;
967 static enum {
968 PT_unknown,
969 PT_RGB565,
970 PT_RGB888
971 } pixel_type = PT_unknown;
973 static void
974 LoadBackgroundFile (FILE *f, char *filename)
976 XVisualInfo vinfot, *vinfo;
977 Visual *vis;
978 int c, r, b;
979 int i, nret;
980 int p[3], rows, cols, maxval;
982 if (fgetc(f) != 'P')
984 printf("bgimage: %s signature not P6\n", filename);
985 return;
987 if (fgetc(f) != '6')
989 printf("bgimage: %s signature not P6\n", filename);
990 return;
992 for (i=0; i<3; i++)
994 do {
995 b = fgetc(f);
996 if (feof(f))
997 return;
998 if (b == '#')
999 while (!feof(f) && b != '\n')
1000 b = fgetc(f);
1001 } while (!isdigit(b));
1002 p[i] = b - '0';
1003 while (isdigit(b = fgetc(f)))
1004 p[i] = p[i]*10 + b - '0';
1006 bg_w = cols = p[0];
1007 bg_h = rows = p[1];
1008 maxval = p[2];
1010 setbuf(stdout, 0);
1011 bg = (Pixel **) malloc (rows * sizeof (Pixel *));
1012 if (!bg)
1014 printf("Out of memory loading %s\n", filename);
1015 return;
1017 for (i=0; i<rows; i++)
1019 bg[i] = (Pixel *) malloc (cols * sizeof (Pixel));
1020 if (!bg[i])
1022 printf("Out of memory loading %s\n", filename);
1023 while (--i >= 0)
1024 free (bg[i]);
1025 free (bg);
1026 bg = 0;
1027 return;
1031 vis = DefaultVisual (display, DefaultScreen(display));
1033 vinfot.visualid = XVisualIDFromVisual(vis);
1034 vinfo = XGetVisualInfo (display, VisualIDMask, &vinfot, &nret);
1036 #if 0
1037 /* If you want to support more visuals below, you'll probably need
1038 this. */
1039 printf("vinfo: rm %04x gm %04x bm %04x depth %d class %d\n",
1040 vinfo->red_mask, vinfo->green_mask, vinfo->blue_mask,
1041 vinfo->depth, vinfo->class);
1042 #endif
1044 #if !defined(__cplusplus)
1045 #define c_class class
1046 #endif
1048 if (vinfo->c_class == TrueColor
1049 && vinfo->depth == 16
1050 && vinfo->red_mask == 0xf800
1051 && vinfo->green_mask == 0x07e0
1052 && vinfo->blue_mask == 0x001f)
1053 pixel_type = PT_RGB565;
1055 if (vinfo->c_class == TrueColor
1056 && vinfo->depth == 24
1057 && vinfo->red_mask == 0xff0000
1058 && vinfo->green_mask == 0x00ff00
1059 && vinfo->blue_mask == 0x0000ff)
1060 pixel_type = PT_RGB888;
1062 for (r=0; r<rows; r++)
1064 for (c=0; c<cols; c++)
1066 XColor pix;
1067 unsigned int pr = (unsigned)fgetc(f);
1068 unsigned int pg = (unsigned)fgetc(f);
1069 unsigned int pb = (unsigned)fgetc(f);
1071 switch (pixel_type)
1073 case PT_unknown:
1074 pix.red = pr * 65535 / maxval;
1075 pix.green = pg * 65535 / maxval;
1076 pix.blue = pb * 65535 / maxval;
1077 pix.flags = DoRed | DoGreen | DoBlue;
1078 XAllocColor (display, colormap, &pix);
1079 bg[r][c] = pix.pixel;
1080 break;
1081 case PT_RGB565:
1082 bg[r][c] = (pr>>3)<<11 | (pg>>2)<<5 | (pb>>3);
1083 break;
1084 case PT_RGB888:
1085 bg[r][c] = (pr << 16) | (pg << 8) | (pb);
1086 break;
1092 void
1093 LoadBackgroundImage (char *filename)
1095 FILE *f = fopen(filename, "rb");
1096 if (!f)
1098 if (NSTRCMP (filename, "pcb-background.ppm"))
1099 perror(filename);
1100 return;
1102 LoadBackgroundFile (f, filename);
1103 fclose(f);
1106 static void
1107 DrawBackgroundImage ()
1109 int x, y, w, h;
1110 double xscale, yscale;
1111 int pcbwidth = PCB->MaxWidth / view_zoom;
1112 int pcbheight = PCB->MaxHeight / view_zoom;
1114 if (!window || !bg)
1115 return;
1117 if (!bgi || view_width != bgi_w || view_height != bgi_h)
1119 if (bgi)
1120 XDestroyImage (bgi);
1121 /* Cheat - get the image, which sets up the format too. */
1122 bgi = XGetImage (XtDisplay(work_area),
1123 window,
1124 0, 0, view_width, view_height,
1125 -1, ZPixmap);
1126 bgi_w = view_width;
1127 bgi_h = view_height;
1130 w = MIN (view_width, pcbwidth);
1131 h = MIN (view_height, pcbheight);
1133 xscale = (double)bg_w / PCB->MaxWidth;
1134 yscale = (double)bg_h / PCB->MaxHeight;
1136 for (y=0; y<h; y++)
1138 int pr = Py(y);
1139 int ir = pr * yscale;
1140 for (x=0; x<w; x++)
1142 int pc = Px(x);
1143 int ic = pc * xscale;
1144 XPutPixel (bgi, x, y, bg[ir][ic]);
1147 XPutImage(display, main_pixmap, bg_gc,
1148 bgi,
1149 0, 0, 0, 0, w, h);
1151 /* ---------------------------------------------------------------------- */
1153 static HID_Attribute *
1154 lesstif_get_export_options (int *n)
1156 *n = sizeof (lesstif_attribute_list) / sizeof (HID_Attribute);
1157 return lesstif_attribute_list;
1160 static void
1161 set_scroll (Widget s, int pos, int view, int pcb)
1163 int sz = view * view_zoom;
1164 if (sz > pcb)
1165 sz = pcb;
1166 n = 0;
1167 stdarg (XmNvalue, pos);
1168 stdarg (XmNsliderSize, sz);
1169 stdarg (XmNincrement, view_zoom);
1170 stdarg (XmNpageIncrement, sz);
1171 stdarg (XmNmaximum, pcb);
1172 XtSetValues (s, args, n);
1175 void
1176 lesstif_pan_fixup ()
1178 #if 0
1179 if (view_left_x > PCB->MaxWidth - (view_width * view_zoom))
1180 view_left_x = PCB->MaxWidth - (view_width * view_zoom);
1181 if (view_top_y > PCB->MaxHeight - (view_height * view_zoom))
1182 view_top_y = PCB->MaxHeight - (view_height * view_zoom);
1183 if (view_left_x < 0)
1184 view_left_x = 0;
1185 if (view_top_y < 0)
1186 view_top_y = 0;
1187 if (view_width * view_zoom > PCB->MaxWidth
1188 && view_height * view_zoom > PCB->MaxHeight)
1190 zoom_by (1, 0, 0);
1191 return;
1193 #endif
1195 set_scroll (hscroll, view_left_x, view_width, PCB->MaxWidth);
1196 set_scroll (vscroll, view_top_y, view_height, PCB->MaxHeight);
1198 lesstif_invalidate_all ();
1201 static void
1202 zoom_max ()
1204 double new_zoom = PCB->MaxWidth / view_width;
1205 if (new_zoom < PCB->MaxHeight / view_height)
1206 new_zoom = PCB->MaxHeight / view_height;
1208 view_left_x = -(view_width * new_zoom - PCB->MaxWidth) / 2;
1209 view_top_y = -(view_height * new_zoom - PCB->MaxHeight) / 2;
1210 view_zoom = new_zoom;
1211 pixel_slop = view_zoom;
1212 lesstif_pan_fixup ();
1215 static void
1216 zoom_to (double new_zoom, int x, int y)
1218 double max_zoom, xfrac, yfrac;
1219 int cx, cy;
1221 xfrac = (double) x / (double) view_width;
1222 yfrac = (double) y / (double) view_height;
1224 if (flip_x)
1225 xfrac = 1-xfrac;
1226 if (flip_y)
1227 yfrac = 1-yfrac;
1229 max_zoom = PCB->MaxWidth / view_width;
1230 if (max_zoom < PCB->MaxHeight / view_height)
1231 max_zoom = PCB->MaxHeight / view_height;
1233 max_zoom *= MAX_ZOOM_SCALE;
1235 if (new_zoom < 1)
1236 new_zoom = 1;
1237 if (new_zoom > max_zoom)
1238 new_zoom = max_zoom;
1240 cx = view_left_x + view_width * xfrac * view_zoom;
1241 cy = view_top_y + view_height * yfrac * view_zoom;
1243 if (view_zoom != new_zoom)
1245 view_zoom = new_zoom;
1246 pixel_slop = view_zoom;
1248 view_left_x = cx - view_width * xfrac * view_zoom;
1249 view_top_y = cy - view_height * yfrac * view_zoom;
1251 lesstif_pan_fixup ();
1254 static void
1255 zoom_toggle(int x, int y)
1257 double tmp;
1259 tmp = prev_view_zoom;
1260 prev_view_zoom = view_zoom;
1261 zoom_to(tmp, x, y);
1264 void
1265 zoom_by (double factor, int x, int y)
1267 zoom_to (view_zoom * factor, x, y);
1270 static int panning = 0;
1271 static int shift_pressed;
1272 static int ctrl_pressed;
1273 static int alt_pressed;
1275 /* X and Y are in screen coordinates. */
1276 static void
1277 Pan (int mode, int x, int y)
1279 static int ox, oy;
1280 static int opx, opy;
1282 panning = mode;
1283 /* This is for ctrl-pan, where the viewport's position is directly
1284 proportional to the cursor position in the window (like the Xaw
1285 thumb panner) */
1286 if (pan_thumb_mode)
1288 opx = x * PCB->MaxWidth / view_width;
1289 opy = y * PCB->MaxHeight / view_height;
1290 if (flip_x)
1291 opx = PCB->MaxWidth - opx;
1292 if (flip_y)
1293 opy = PCB->MaxHeight - opy;
1294 view_left_x = opx - view_width / 2 * view_zoom;
1295 view_top_y = opy - view_height / 2 * view_zoom;
1296 lesstif_pan_fixup ();
1298 /* This is the start of a regular pan. On the first click, we
1299 remember the coordinates where we "grabbed" the screen. */
1300 else if (mode == 1)
1302 ox = x;
1303 oy = y;
1304 opx = view_left_x;
1305 opy = view_top_y;
1307 /* continued drag, we calculate how far we've moved the cursor and
1308 set the position accordingly. */
1309 else
1311 if (flip_x)
1312 view_left_x = opx + (x - ox) * view_zoom;
1313 else
1314 view_left_x = opx - (x - ox) * view_zoom;
1315 if (flip_y)
1316 view_top_y = opy + (y - oy) * view_zoom;
1317 else
1318 view_top_y = opy - (y - oy) * view_zoom;
1319 lesstif_pan_fixup ();
1323 static void
1324 mod_changed (XKeyEvent * e, int set)
1326 switch (XKeycodeToKeysym (display, e->keycode, 0))
1328 case XK_Shift_L:
1329 case XK_Shift_R:
1330 shift_pressed = set;
1331 break;
1332 case XK_Control_L:
1333 case XK_Control_R:
1334 ctrl_pressed = set;
1335 break;
1336 #ifdef __APPLE__
1337 case XK_Mode_switch:
1338 #else
1339 case XK_Alt_L:
1340 case XK_Alt_R:
1341 #endif
1342 alt_pressed = set;
1343 break;
1344 default:
1345 // to include the Apple keyboard left and right command keys use XK_Meta_L and XK_Meta_R respectivly.
1346 return;
1348 in_move_event = 1;
1349 notify_crosshair_change (false);
1350 if (panning)
1351 Pan (2, e->x, e->y);
1352 EventMoveCrosshair (Px (e->x), Py (e->y));
1353 AdjustAttachedObjects ();
1354 notify_crosshair_change (true);
1355 in_move_event = 0;
1358 static void
1359 work_area_input (Widget w, XtPointer v, XEvent * e, Boolean * ctd)
1361 static int pressed_button = 0;
1362 static int ignore_release = 0;
1364 show_crosshair (0);
1365 switch (e->type)
1367 case KeyPress:
1368 mod_changed (&(e->xkey), 1);
1369 if (lesstif_key_event (&(e->xkey)))
1370 return;
1371 break;
1373 case KeyRelease:
1374 mod_changed (&(e->xkey), 0);
1375 break;
1377 case ButtonPress:
1379 int mods;
1380 if (pressed_button)
1381 return;
1382 /*printf("click %d\n", e->xbutton.button); */
1383 if (lesstif_button_event (w, e))
1385 ignore_release = 1;
1386 return;
1388 ignore_release = 0;
1390 notify_crosshair_change (false);
1391 pressed_button = e->xbutton.button;
1392 mods = ((e->xbutton.state & ShiftMask) ? M_Shift : 0)
1393 + ((e->xbutton.state & ControlMask) ? M_Ctrl : 0)
1394 #ifdef __APPLE__
1395 + ((e->xbutton.state & (1<<13)) ? M_Alt : 0);
1396 #else
1397 + ((e->xbutton.state & Mod1Mask) ? M_Alt : 0);
1398 #endif
1399 do_mouse_action(e->xbutton.button, mods);
1400 notify_crosshair_change (true);
1401 break;
1404 case ButtonRelease:
1406 int mods;
1407 if (e->xbutton.button != pressed_button)
1408 return;
1409 lesstif_button_event (w, e);
1410 notify_crosshair_change (false);
1411 pressed_button = 0;
1412 mods = ((e->xbutton.state & ShiftMask) ? M_Shift : 0)
1413 + ((e->xbutton.state & ControlMask) ? M_Ctrl : 0)
1414 #ifdef __APPLE__
1415 + ((e->xbutton.state & (1<<13)) ? M_Alt : 0)
1416 #else
1417 + ((e->xbutton.state & Mod1Mask) ? M_Alt : 0)
1418 #endif
1419 + M_Release;
1420 do_mouse_action (e->xbutton.button, mods);
1421 notify_crosshair_change (true);
1422 break;
1425 case MotionNotify:
1427 Window root, child;
1428 unsigned int keys_buttons;
1429 int root_x, root_y, pos_x, pos_y;
1430 while (XCheckMaskEvent (display, PointerMotionMask, e));
1431 XQueryPointer (display, e->xmotion.window, &root, &child,
1432 &root_x, &root_y, &pos_x, &pos_y, &keys_buttons);
1433 shift_pressed = (keys_buttons & ShiftMask);
1434 ctrl_pressed = (keys_buttons & ControlMask);
1435 #ifdef __APPLE__
1436 alt_pressed = (keys_buttons & (1<<13));
1437 #else
1438 alt_pressed = (keys_buttons & Mod1Mask);
1439 #endif
1440 /*pcb_printf("m %#mS %#mS\n", Px(e->xmotion.x), Py(e->xmotion.y)); */
1441 crosshair_in_window = 1;
1442 in_move_event = 1;
1443 if (panning)
1444 Pan (2, pos_x, pos_y);
1445 EventMoveCrosshair (Px (pos_x), Py (pos_y));
1446 in_move_event = 0;
1448 break;
1450 case LeaveNotify:
1451 crosshair_in_window = 0;
1452 ShowCrosshair (false);
1453 need_idle_proc ();
1454 break;
1456 case EnterNotify:
1457 crosshair_in_window = 1;
1458 in_move_event = 1;
1459 EventMoveCrosshair (Px (e->xcrossing.x), Py (e->xcrossing.y));
1460 ShowCrosshair (true);
1461 in_move_event = 0;
1462 need_idle_proc ();
1463 break;
1465 default:
1466 printf ("work_area: unknown event %d\n", e->type);
1467 break;
1471 static void
1472 draw_right_cross (GC xor_gc, int x, int y,
1473 int view_width, int view_height)
1475 XDrawLine (display, window, xor_gc, 0, y, view_width, y);
1476 XDrawLine (display, window, xor_gc, x, 0, x, view_height);
1479 static void
1480 draw_slanted_cross (GC xor_gc, int x, int y,
1481 int view_width, int view_height)
1483 int x0, y0, x1, y1;
1485 x0 = x + (view_height - y);
1486 x0 = MAX(0, MIN (x0, view_width));
1487 x1 = x - y;
1488 x1 = MAX(0, MIN (x1, view_width));
1489 y0 = y + (view_width - x);
1490 y0 = MAX(0, MIN (y0, view_height));
1491 y1 = y - x;
1492 y1 = MAX(0, MIN (y1, view_height));
1493 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1494 x0 = x - (view_height - y);
1495 x0 = MAX(0, MIN (x0, view_width));
1496 x1 = x + y;
1497 x1 = MAX(0, MIN (x1, view_width));
1498 y0 = y + x;
1499 y0 = MAX(0, MIN (y0, view_height));
1500 y1 = y - (view_width - x);
1501 y1 = MAX(0, MIN (y1, view_height));
1502 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1505 static void
1506 draw_dozen_cross (GC xor_gc, int x, int y,
1507 int view_width, int view_height)
1509 int x0, y0, x1, y1;
1510 double tan60 = sqrt (3);
1512 x0 = x + (view_height - y) / tan60;
1513 x0 = MAX(0, MIN (x0, view_width));
1514 x1 = x - y / tan60;
1515 x1 = MAX(0, MIN (x1, view_width));
1516 y0 = y + (view_width - x) * tan60;
1517 y0 = MAX(0, MIN (y0, view_height));
1518 y1 = y - x * tan60;
1519 y1 = MAX(0, MIN (y1, view_height));
1520 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1522 x0 = x + (view_height - y) * tan60;
1523 x0 = MAX(0, MIN (x0, view_width));
1524 x1 = x - y * tan60;
1525 x1 = MAX(0, MIN (x1, view_width));
1526 y0 = y + (view_width - x) / tan60;
1527 y0 = MAX(0, MIN (y0, view_height));
1528 y1 = y - x / tan60;
1529 y1 = MAX(0, MIN (y1, view_height));
1530 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1532 x0 = x - (view_height - y) / tan60;
1533 x0 = MAX(0, MIN (x0, view_width));
1534 x1 = x + y / tan60;
1535 x1 = MAX(0, MIN (x1, view_width));
1536 y0 = y + x * tan60;
1537 y0 = MAX(0, MIN (y0, view_height));
1538 y1 = y - (view_width - x) * tan60;
1539 y1 = MAX(0, MIN (y1, view_height));
1540 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1542 x0 = x - (view_height - y) * tan60;
1543 x0 = MAX(0, MIN (x0, view_width));
1544 x1 = x + y * tan60;
1545 x1 = MAX(0, MIN (x1, view_width));
1546 y0 = y + x / tan60;
1547 y0 = MAX(0, MIN (y0, view_height));
1548 y1 = y - (view_width - x) / tan60;
1549 y1 = MAX(0, MIN (y1, view_height));
1550 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1553 static void
1554 draw_crosshair (GC xor_gc, int x, int y,
1555 int view_width, int view_height)
1557 draw_right_cross (xor_gc, x, y, view_width, view_height);
1558 if (Crosshair.shape == Union_Jack_Crosshair_Shape)
1559 draw_slanted_cross (xor_gc, x, y, view_width, view_height);
1560 if (Crosshair.shape == Dozen_Crosshair_Shape)
1561 draw_dozen_cross (xor_gc, x, y, view_width, view_height);
1563 void
1564 lesstif_show_crosshair (int show)
1566 static int showing = 0;
1567 static int sx, sy;
1568 static GC xor_gc = 0;
1569 Pixel crosshair_color;
1571 if (!crosshair_in_window || !window)
1572 return;
1573 if (xor_gc == 0)
1575 crosshair_color = lesstif_parse_color (Settings.CrosshairColor) ^ bgcolor;
1576 xor_gc = XCreateGC (display, window, 0, 0);
1577 XSetFunction (display, xor_gc, GXxor);
1578 XSetForeground (display, xor_gc, crosshair_color);
1580 if (show == showing)
1581 return;
1582 if (show)
1584 sx = Vx (crosshair_x);
1585 sy = Vy (crosshair_y);
1587 else
1588 need_idle_proc ();
1589 draw_crosshair (xor_gc, sx, sy, view_width, view_height);
1590 showing = show;
1593 static void
1594 work_area_expose (Widget work_area, void *me,
1595 XmDrawingAreaCallbackStruct * cbs)
1597 XExposeEvent *e;
1599 show_crosshair (0);
1600 e = &(cbs->event->xexpose);
1601 XSetFunction (display, my_gc, GXcopy);
1602 XCopyArea (display, main_pixmap, window, my_gc,
1603 e->x, e->y, e->width, e->height, e->x, e->y);
1604 show_crosshair (1);
1607 static void
1608 scroll_callback (Widget scroll, int *view_dim,
1609 XmScrollBarCallbackStruct * cbs)
1611 *view_dim = cbs->value;
1612 lesstif_invalidate_all ();
1615 static void
1616 work_area_make_pixmaps (Dimension width, Dimension height)
1618 if (main_pixmap)
1619 XFreePixmap (display, main_pixmap);
1620 main_pixmap =
1621 XCreatePixmap (display, window, width, height,
1622 XDefaultDepth (display, screen));
1624 if (mask_pixmap)
1625 XFreePixmap (display, mask_pixmap);
1626 mask_pixmap =
1627 XCreatePixmap (display, window, width, height,
1628 XDefaultDepth (display, screen));
1629 #ifdef HAVE_XRENDER
1630 if (main_picture)
1632 XRenderFreePicture (display, main_picture);
1633 main_picture = 0;
1635 if (mask_picture)
1637 XRenderFreePicture (display, mask_picture);
1638 mask_picture = 0;
1640 if (use_xrender)
1642 main_picture = XRenderCreatePicture (display, main_pixmap,
1643 XRenderFindVisualFormat(display,
1644 DefaultVisual(display, screen)), 0, 0);
1645 mask_picture = XRenderCreatePicture (display, mask_pixmap,
1646 XRenderFindVisualFormat(display,
1647 DefaultVisual(display, screen)), 0, 0);
1648 if (!main_picture || !mask_picture)
1649 use_xrender = 0;
1651 #endif /* HAVE_XRENDER */
1653 if (mask_bitmap)
1654 XFreePixmap (display, mask_bitmap);
1655 mask_bitmap = XCreatePixmap (display, window, width, height, 1);
1657 pixmap = use_mask ? main_pixmap : mask_pixmap;
1658 pixmap_w = width;
1659 pixmap_h = height;
1662 static void
1663 work_area_resize (Widget work_area, void *me,
1664 XmDrawingAreaCallbackStruct * cbs)
1666 XColor color;
1667 Dimension width, height;
1669 show_crosshair (0);
1671 n = 0;
1672 stdarg (XtNwidth, &width);
1673 stdarg (XtNheight, &height);
1674 stdarg (XmNbackground, &bgcolor);
1675 XtGetValues (work_area, args, n);
1676 view_width = width;
1677 view_height = height;
1679 color.pixel = bgcolor;
1680 XQueryColor (display, colormap, &color);
1681 bgred = color.red;
1682 bggreen = color.green;
1683 bgblue = color.blue;
1685 if (!window)
1686 return;
1688 work_area_make_pixmaps (view_width, view_height);
1690 zoom_by (1, 0, 0);
1693 static void
1694 work_area_first_expose (Widget work_area, void *me,
1695 XmDrawingAreaCallbackStruct * cbs)
1697 int c;
1698 Dimension width, height;
1699 static char dashes[] = { 4, 4 };
1701 window = XtWindow (work_area);
1702 my_gc = XCreateGC (display, window, 0, 0);
1704 arc1_gc = XCreateGC (display, window, 0, 0);
1705 c = lesstif_parse_color ("#804000");
1706 XSetForeground (display, arc1_gc, c);
1707 arc2_gc = XCreateGC (display, window, 0, 0);
1708 c = lesstif_parse_color ("#004080");
1709 XSetForeground (display, arc2_gc, c);
1710 XSetLineAttributes (display, arc1_gc, 1, LineOnOffDash, 0, 0);
1711 XSetLineAttributes (display, arc2_gc, 1, LineOnOffDash, 0, 0);
1712 XSetDashes (display, arc1_gc, 0, dashes, 2);
1713 XSetDashes (display, arc2_gc, 0, dashes, 2);
1715 n = 0;
1716 stdarg (XtNwidth, &width);
1717 stdarg (XtNheight, &height);
1718 stdarg (XmNbackground, &bgcolor);
1719 XtGetValues (work_area, args, n);
1720 view_width = width;
1721 view_height = height;
1723 offlimit_color = lesstif_parse_color (Settings.OffLimitColor);
1724 grid_color = lesstif_parse_color (Settings.GridColor);
1726 bg_gc = XCreateGC (display, window, 0, 0);
1727 XSetForeground (display, bg_gc, bgcolor);
1729 work_area_make_pixmaps (width, height);
1731 #ifdef HAVE_XRENDER
1732 if (use_xrender)
1734 XRenderPictureAttributes pa;
1735 XRenderColor a = {0, 0, 0, 0x8000};
1737 pale_pixmap = XCreatePixmap (display, window, 1, 1, 8);
1738 pa.repeat = True;
1739 pale_picture = XRenderCreatePicture (display, pale_pixmap,
1740 XRenderFindStandardFormat(display, PictStandardA8),
1741 CPRepeat, &pa);
1742 if (pale_picture)
1743 XRenderFillRectangle(display, PictOpSrc, pale_picture, &a, 0, 0, 1, 1);
1744 else
1745 use_xrender = 0;
1747 #endif /* HAVE_XRENDER */
1749 clip_gc = XCreateGC (display, window, 0, 0);
1750 bset_gc = XCreateGC (display, mask_bitmap, 0, 0);
1751 XSetForeground (display, bset_gc, 1);
1752 bclear_gc = XCreateGC (display, mask_bitmap, 0, 0);
1753 XSetForeground (display, bclear_gc, 0);
1755 XtRemoveCallback (work_area, XmNexposeCallback,
1756 (XtCallbackProc) work_area_first_expose, 0);
1757 XtAddCallback (work_area, XmNexposeCallback,
1758 (XtCallbackProc) work_area_expose, 0);
1759 lesstif_invalidate_all ();
1762 static Widget
1763 make_message (char *name, Widget left, int resizeable)
1765 Widget w, f;
1766 n = 0;
1767 if (left)
1769 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
1770 stdarg (XmNleftWidget, XtParent(left));
1772 else
1774 stdarg (XmNleftAttachment, XmATTACH_FORM);
1776 stdarg (XmNtopAttachment, XmATTACH_FORM);
1777 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1778 stdarg (XmNshadowType, XmSHADOW_IN);
1779 stdarg (XmNshadowThickness, 1);
1780 stdarg (XmNalignment, XmALIGNMENT_CENTER);
1781 stdarg (XmNmarginWidth, 4);
1782 stdarg (XmNmarginHeight, 1);
1783 if (!resizeable)
1784 stdarg (XmNresizePolicy, XmRESIZE_GROW);
1785 f = XmCreateForm (messages, name, args, n);
1786 XtManageChild (f);
1787 n = 0;
1788 stdarg (XmNtopAttachment, XmATTACH_FORM);
1789 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1790 stdarg (XmNleftAttachment, XmATTACH_FORM);
1791 stdarg (XmNrightAttachment, XmATTACH_FORM);
1792 w = XmCreateLabel (f, name, args, n);
1793 XtManageChild (w);
1794 return w;
1797 static void
1798 lesstif_do_export (HID_Attr_Val * options)
1800 Dimension width, height;
1801 Widget menu;
1802 Widget work_area_frame;
1804 n = 0;
1805 stdarg (XtNwidth, &width);
1806 stdarg (XtNheight, &height);
1807 XtGetValues (appwidget, args, n);
1809 if (width < 1)
1810 width = 640;
1811 if (width > XDisplayWidth (display, screen))
1812 width = XDisplayWidth (display, screen);
1813 if (height < 1)
1814 height = 480;
1815 if (height > XDisplayHeight (display, screen))
1816 height = XDisplayHeight (display, screen);
1818 n = 0;
1819 stdarg (XmNwidth, width);
1820 stdarg (XmNheight, height);
1821 XtSetValues (appwidget, args, n);
1823 stdarg (XmNspacing, 0);
1824 mainwind = XmCreateMainWindow (appwidget, "mainWind", args, n);
1825 XtManageChild (mainwind);
1827 n = 0;
1828 stdarg (XmNmarginWidth, 0);
1829 stdarg (XmNmarginHeight, 0);
1830 menu = lesstif_menu (mainwind, "menubar", args, n);
1831 XtManageChild (menu);
1833 n = 0;
1834 stdarg (XmNshadowType, XmSHADOW_IN);
1835 work_area_frame =
1836 XmCreateFrame (mainwind, "work_area_frame", args, n);
1837 XtManageChild (work_area_frame);
1839 n = 0;
1840 do_color (Settings.BackgroundColor, XmNbackground);
1841 work_area = XmCreateDrawingArea (work_area_frame, "work_area", args, n);
1842 XtManageChild (work_area);
1843 XtAddCallback (work_area, XmNexposeCallback,
1844 (XtCallbackProc) work_area_first_expose, 0);
1845 XtAddCallback (work_area, XmNresizeCallback,
1846 (XtCallbackProc) work_area_resize, 0);
1847 /* A regular callback won't work here, because lesstif swallows any
1848 Ctrl<Button>1 event. */
1849 XtAddEventHandler (work_area,
1850 ButtonPressMask | ButtonReleaseMask
1851 | PointerMotionMask | PointerMotionHintMask
1852 | KeyPressMask | KeyReleaseMask
1853 | EnterWindowMask | LeaveWindowMask,
1854 0, work_area_input, 0);
1856 n = 0;
1857 stdarg (XmNorientation, XmVERTICAL);
1858 stdarg (XmNprocessingDirection, XmMAX_ON_BOTTOM);
1859 stdarg (XmNmaximum, PCB->MaxHeight ? PCB->MaxHeight : 1);
1860 vscroll = XmCreateScrollBar (mainwind, "vscroll", args, n);
1861 XtAddCallback (vscroll, XmNvalueChangedCallback,
1862 (XtCallbackProc) scroll_callback, (XtPointer) & view_top_y);
1863 XtAddCallback (vscroll, XmNdragCallback, (XtCallbackProc) scroll_callback,
1864 (XtPointer) & view_top_y);
1865 XtManageChild (vscroll);
1867 n = 0;
1868 stdarg (XmNorientation, XmHORIZONTAL);
1869 stdarg (XmNmaximum, PCB->MaxWidth ? PCB->MaxWidth : 1);
1870 hscroll = XmCreateScrollBar (mainwind, "hscroll", args, n);
1871 XtAddCallback (hscroll, XmNvalueChangedCallback,
1872 (XtCallbackProc) scroll_callback, (XtPointer) & view_left_x);
1873 XtAddCallback (hscroll, XmNdragCallback, (XtCallbackProc) scroll_callback,
1874 (XtPointer) & view_left_x);
1875 XtManageChild (hscroll);
1877 n = 0;
1878 stdarg (XmNresize, True);
1879 stdarg (XmNresizePolicy, XmRESIZE_ANY);
1880 messages = XmCreateForm (mainwind, "messages", args, n);
1881 XtManageChild (messages);
1883 n = 0;
1884 stdarg (XmNtopAttachment, XmATTACH_FORM);
1885 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1886 stdarg (XmNleftAttachment, XmATTACH_FORM);
1887 stdarg (XmNrightAttachment, XmATTACH_FORM);
1888 stdarg (XmNalignment, XmALIGNMENT_CENTER);
1889 stdarg (XmNshadowThickness, 2);
1890 m_click = XmCreateLabel (messages, "click", args, n);
1892 n = 0;
1893 stdarg (XmNtopAttachment, XmATTACH_FORM);
1894 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1895 stdarg (XmNleftAttachment, XmATTACH_FORM);
1896 stdarg (XmNlabelString, XmStringCreatePCB ("Command: "));
1897 m_cmd_label = XmCreateLabel (messages, "command", args, n);
1899 n = 0;
1900 stdarg (XmNtopAttachment, XmATTACH_FORM);
1901 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1902 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
1903 stdarg (XmNleftWidget, m_cmd_label);
1904 stdarg (XmNrightAttachment, XmATTACH_FORM);
1905 stdarg (XmNshadowThickness, 1);
1906 stdarg (XmNhighlightThickness, 0);
1907 stdarg (XmNmarginWidth, 2);
1908 stdarg (XmNmarginHeight, 2);
1909 m_cmd = XmCreateTextField (messages, "command", args, n);
1910 XtAddCallback (m_cmd, XmNactivateCallback,
1911 (XtCallbackProc) command_callback, 0);
1912 XtAddCallback (m_cmd, XmNlosingFocusCallback,
1913 (XtCallbackProc) command_callback, 0);
1914 XtAddEventHandler (m_cmd, KeyPressMask, 0, command_event_handler, 0);
1916 m_mark = make_message ("m_mark", 0, 0);
1917 m_crosshair = make_message ("m_crosshair", m_mark, 0);
1918 m_grid = make_message ("m_grid", m_crosshair, 1);
1919 m_zoom = make_message ("m_zoom", m_grid, 1);
1920 lesstif_m_layer = make_message ("m_layer", m_zoom, 0);
1921 m_mode = make_message ("m_mode", lesstif_m_layer, 1);
1922 m_rats = make_message ("m_rats", m_mode, 1);
1923 m_status = make_message ("m_status", m_mode, 1);
1925 XtUnmanageChild (XtParent (m_mark));
1926 XtUnmanageChild (XtParent (m_rats));
1928 n = 0;
1929 stdarg (XmNrightAttachment, XmATTACH_FORM);
1930 XtSetValues (XtParent (m_status), args, n);
1932 /* We'll use this later. */
1933 n = 0;
1934 stdarg (XmNleftWidget, XtParent (m_mark));
1935 XtSetValues (XtParent (m_crosshair), args, n);
1937 n = 0;
1938 stdarg (XmNmessageWindow, messages);
1939 XtSetValues (mainwind, args, n);
1941 if (background_image_file)
1942 LoadBackgroundImage (background_image_file);
1944 XtRealizeWidget (appwidget);
1946 while (!window)
1948 XEvent e;
1949 XtAppNextEvent (app_context, &e);
1950 XtDispatchEvent (&e);
1953 PCBChanged (0, 0, 0, 0);
1955 XtAppMainLoop (app_context);
1958 #if 0
1959 XrmOptionDescRec lesstif_options[] = {
1962 XtResource lesstif_resources[] = {
1964 #endif
1966 typedef union
1968 int i;
1969 double f;
1970 char *s;
1971 Coord c;
1972 } val_union;
1974 static Boolean
1975 pcb_cvt_string_to_double (Display * d, XrmValue * args, Cardinal * num_args,
1976 XrmValue * from, XrmValue * to, XtPointer * data)
1978 static double rv;
1979 rv = strtod ((char *) from->addr, 0);
1980 if (to->addr)
1981 *(double *) to->addr = rv;
1982 else
1983 to->addr = (XPointer) & rv;
1984 to->size = sizeof (rv);
1985 return True;
1988 static Boolean
1989 pcb_cvt_string_to_coord (Display * d, XrmValue * args, Cardinal * num_args,
1990 XrmValue * from, XrmValue * to, XtPointer *data)
1992 static Coord rv;
1993 rv = GetValue ((char *) from->addr, NULL, NULL);
1994 if (to->addr)
1995 *(Coord *) to->addr = rv;
1996 else
1997 to->addr = (XPointer) &rv;
1998 to->size = sizeof (rv);
1999 return TRUE;
2002 static void
2003 mainwind_delete_cb ()
2005 hid_action ("Quit");
2008 static void
2009 lesstif_listener_cb (XtPointer client_data, int *fid, XtInputId *id)
2011 char buf[BUFSIZ];
2012 int nbytes;
2014 if ((nbytes = read (*fid, buf, BUFSIZ)) == -1)
2015 perror ("lesstif_listener_cb");
2017 if (nbytes)
2019 buf[nbytes] = '\0';
2020 hid_parse_actions (buf);
2024 static void
2025 lesstif_parse_arguments (int *argc, char ***argv)
2027 Atom close_atom;
2028 HID_AttrNode *ha;
2029 int acount = 0, amax;
2030 int rcount = 0, rmax;
2031 int i;
2032 XrmOptionDescRec *new_options;
2033 XtResource *new_resources;
2034 val_union *new_values;
2035 int render_event, render_error;
2037 XtSetTypeConverter (XtRString,
2038 XtRDouble,
2039 pcb_cvt_string_to_double, NULL, 0, XtCacheAll, NULL);
2040 XtSetTypeConverter (XtRString,
2041 XtRPCBCoord,
2042 pcb_cvt_string_to_coord, NULL, 0, XtCacheAll, NULL);
2045 for (ha = hid_attr_nodes; ha; ha = ha->next)
2046 for (i = 0; i < ha->n; i++)
2048 HID_Attribute *a = ha->attributes + i;
2049 switch (a->type)
2051 case HID_Integer:
2052 case HID_Coord:
2053 case HID_Real:
2054 case HID_String:
2055 case HID_Path:
2056 case HID_Boolean:
2057 acount++;
2058 rcount++;
2059 break;
2060 default:
2061 break;
2065 #if 0
2066 amax = acount + XtNumber (lesstif_options);
2067 #else
2068 amax = acount;
2069 #endif
2071 new_options = (XrmOptionDescRec *) malloc ((amax + 1) * sizeof (XrmOptionDescRec));
2073 #if 0
2074 memcpy (new_options + acount, lesstif_options, sizeof (lesstif_options));
2075 #endif
2076 acount = 0;
2078 #if 0
2079 rmax = rcount + XtNumber (lesstif_resources);
2080 #else
2081 rmax = rcount;
2082 #endif
2084 new_resources = (XtResource *) malloc ((rmax + 1) * sizeof (XtResource));
2085 new_values = (val_union *) malloc ((rmax + 1) * sizeof (val_union));
2086 #if 0
2087 memcpy (new_resources + acount, lesstif_resources,
2088 sizeof (lesstif_resources));
2089 #endif
2090 rcount = 0;
2092 for (ha = hid_attr_nodes; ha; ha = ha->next)
2093 for (i = 0; i < ha->n; i++)
2095 HID_Attribute *a = ha->attributes + i;
2096 XrmOptionDescRec *o = new_options + acount;
2097 char *tmpopt, *tmpres;
2098 XtResource *r = new_resources + rcount;
2100 tmpopt = (char *) malloc (strlen (a->name) + 3);
2101 tmpopt[0] = tmpopt[1] = '-';
2102 strcpy (tmpopt + 2, a->name);
2103 o->option = tmpopt;
2105 tmpres = (char *) malloc (strlen (a->name) + 2);
2106 tmpres[0] = '*';
2107 strcpy (tmpres + 1, a->name);
2108 o->specifier = tmpres;
2110 switch (a->type)
2112 case HID_Integer:
2113 case HID_Coord:
2114 case HID_Real:
2115 case HID_String:
2116 case HID_Path:
2117 o->argKind = XrmoptionSepArg;
2118 o->value = 0;
2119 acount++;
2120 break;
2121 case HID_Boolean:
2122 o->argKind = XrmoptionNoArg;
2123 o->value = "True";
2124 acount++;
2125 break;
2126 default:
2127 break;
2130 r->resource_name = a->name;
2131 r->resource_class = a->name;
2132 r->resource_offset = sizeof (val_union) * rcount;
2134 switch (a->type)
2136 case HID_Integer:
2137 r->resource_type = XtRInt;
2138 r->default_type = XtRInt;
2139 r->resource_size = sizeof (int);
2140 r->default_addr = &(a->default_val.int_value);
2141 rcount++;
2142 break;
2143 case HID_Coord:
2144 r->resource_type = XtRPCBCoord;
2145 r->default_type = XtRPCBCoord;
2146 r->resource_size = sizeof (Coord);
2147 r->default_addr = &(a->default_val.coord_value);
2148 rcount++;
2149 break;
2150 case HID_Real:
2151 r->resource_type = XtRDouble;
2152 r->default_type = XtRDouble;
2153 r->resource_size = sizeof (double);
2154 r->default_addr = &(a->default_val.real_value);
2155 rcount++;
2156 break;
2157 case HID_String:
2158 case HID_Path:
2159 r->resource_type = XtRString;
2160 r->default_type = XtRString;
2161 r->resource_size = sizeof (char *);
2162 r->default_addr = (char *) a->default_val.str_value;
2163 rcount++;
2164 break;
2165 case HID_Boolean:
2166 r->resource_type = XtRBoolean;
2167 r->default_type = XtRInt;
2168 r->resource_size = sizeof (int);
2169 r->default_addr = &(a->default_val.int_value);
2170 rcount++;
2171 break;
2172 default:
2173 break;
2176 #if 0
2177 for (i = 0; i < XtNumber (lesstif_resources); i++)
2179 XtResource *r = new_resources + rcount;
2180 r->resource_offset = sizeof (val_union) * rcount;
2181 rcount++;
2183 #endif
2185 n = 0;
2186 stdarg (XmNdeleteResponse, XmDO_NOTHING);
2188 appwidget = XtAppInitialize (&app_context,
2189 "Pcb",
2190 new_options, amax, argc, *argv, 0, args, n);
2192 display = XtDisplay (appwidget);
2193 screen_s = XtScreen (appwidget);
2194 screen = XScreenNumberOfScreen (screen_s);
2195 colormap = XDefaultColormap (display, screen);
2197 close_atom = XmInternAtom (display, "WM_DELETE_WINDOW", 0);
2198 XmAddWMProtocolCallback (appwidget, close_atom,
2199 (XtCallbackProc) mainwind_delete_cb, 0);
2201 /* XSynchronize(display, True); */
2203 XtGetApplicationResources (appwidget, new_values, new_resources,
2204 rmax, 0, 0);
2206 #ifdef HAVE_XRENDER
2207 use_xrender = XRenderQueryExtension (display, &render_event, &render_error) &&
2208 XRenderFindVisualFormat (display, DefaultVisual(display, screen));
2209 #ifdef HAVE_XINERAMA
2210 /* Xinerama and XRender don't get along well */
2211 if (XineramaQueryExtension (display, &render_event, &render_error)
2212 && XineramaIsActive (display))
2213 use_xrender = 0;
2214 #endif /* HAVE_XINERAMA */
2215 #endif /* HAVE_XRENDER */
2217 rcount = 0;
2218 for (ha = hid_attr_nodes; ha; ha = ha->next)
2219 for (i = 0; i < ha->n; i++)
2221 HID_Attribute *a = ha->attributes + i;
2222 val_union *v = new_values + rcount;
2223 switch (a->type)
2225 case HID_Integer:
2226 if (a->value)
2227 *(int *) a->value = v->i;
2228 else
2229 a->default_val.int_value = v->i;
2230 rcount++;
2231 break;
2232 case HID_Coord:
2233 if (a->value)
2234 *(Coord *) a->value = v->c;
2235 else
2236 a->default_val.coord_value = v->c;
2237 rcount++;
2238 break;
2239 case HID_Boolean:
2240 if (a->value)
2241 *(char *) a->value = v->i;
2242 else
2243 a->default_val.int_value = v->i;
2244 rcount++;
2245 break;
2246 case HID_Real:
2247 if (a->value)
2248 *(double *) a->value = v->f;
2249 else
2250 a->default_val.real_value = v->f;
2251 rcount++;
2252 break;
2253 case HID_String:
2254 case HID_Path:
2255 if (a->value)
2256 *(char **) a->value = v->s;
2257 else
2258 a->default_val.str_value = v->s;
2259 rcount++;
2260 break;
2261 default:
2262 break;
2266 /* redefine colormap, if requested via "-install" */
2267 if (use_private_colormap)
2269 colormap = XCopyColormapAndFree (display, colormap);
2270 XtVaSetValues (appwidget, XtNcolormap, colormap, NULL);
2273 /* listen on standard input for actions */
2274 if (stdin_listen)
2276 XtAppAddInput (app_context, fileno (stdin), (XtPointer) XtInputReadMask,
2277 lesstif_listener_cb, NULL);
2281 static void
2282 draw_grid ()
2284 static XPoint *points = 0;
2285 static int npoints = 0;
2286 Coord x1, y1, x2, y2, prevx;
2287 Coord x, y;
2288 int n;
2289 static GC grid_gc = 0;
2291 if (!Settings.DrawGrid)
2292 return;
2293 if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
2294 return;
2295 if (!grid_gc)
2297 grid_gc = XCreateGC (display, window, 0, 0);
2298 XSetFunction (display, grid_gc, GXxor);
2299 XSetForeground (display, grid_gc, grid_color);
2301 if (flip_x)
2303 x2 = GridFit (Px (0), PCB->Grid, PCB->GridOffsetX);
2304 x1 = GridFit (Px (view_width), PCB->Grid, PCB->GridOffsetX);
2305 if (Vx (x2) < 0)
2306 x2 -= PCB->Grid;
2307 if (Vx (x1) >= view_width)
2308 x1 += PCB->Grid;
2310 else
2312 x1 = GridFit (Px (0), PCB->Grid, PCB->GridOffsetX);
2313 x2 = GridFit (Px (view_width), PCB->Grid, PCB->GridOffsetX);
2314 if (Vx (x1) < 0)
2315 x1 += PCB->Grid;
2316 if (Vx (x2) >= view_width)
2317 x2 -= PCB->Grid;
2319 if (flip_y)
2321 y2 = GridFit (Py (0), PCB->Grid, PCB->GridOffsetY);
2322 y1 = GridFit (Py (view_height), PCB->Grid, PCB->GridOffsetY);
2323 if (Vy (y2) < 0)
2324 y2 -= PCB->Grid;
2325 if (Vy (y1) >= view_height)
2326 y1 += PCB->Grid;
2328 else
2330 y1 = GridFit (Py (0), PCB->Grid, PCB->GridOffsetY);
2331 y2 = GridFit (Py (view_height), PCB->Grid, PCB->GridOffsetY);
2332 if (Vy (y1) < 0)
2333 y1 += PCB->Grid;
2334 if (Vy (y2) >= view_height)
2335 y2 -= PCB->Grid;
2337 n = (x2 - x1) / PCB->Grid + 1;
2338 if (n > npoints)
2340 npoints = n + 10;
2341 points = (XPoint *) realloc (points, npoints * sizeof (XPoint));
2343 n = 0;
2344 prevx = 0;
2345 for (x = x1; x <= x2; x += PCB->Grid)
2347 int temp = Vx (x);
2348 points[n].x = temp;
2349 if (n)
2351 points[n].x -= prevx;
2352 points[n].y = 0;
2354 prevx = temp;
2355 n++;
2357 for (y = y1; y <= y2; y += PCB->Grid)
2359 int vy = Vy (y);
2360 points[0].y = vy;
2361 XDrawPoints (display, pixmap, grid_gc, points, n, CoordModePrevious);
2365 static void
2366 mark_delta_to_widget (Coord dx, Coord dy, Widget w)
2368 char *buf;
2369 double g = coord_to_unit (Settings.grid_unit, PCB->Grid);
2370 int prec;
2371 XmString ms;
2373 /* Integer-sized grid? */
2374 if (((int) (g * 10000 + 0.5) % 10000) == 0)
2375 prec = 0;
2376 else
2377 prec = Settings.grid_unit->default_prec;
2379 if (dx == 0 && dy == 0)
2380 buf = pcb_g_strdup_printf ("%m+%+.*mS, %+.*mS", UUNIT, prec, dx, prec, dy);
2381 else
2383 Angle angle = atan2 (dy, -dx) * 180 / M_PI;
2384 Coord dist = Distance (0, 0, dx, dy);
2386 buf = pcb_g_strdup_printf ("%m+%+.*mS, %+.*mS (%.*mS, %d\260)", UUNIT,
2387 prec, dx, prec, dy, prec, dist, angle);
2390 ms = XmStringCreatePCB (buf);
2391 n = 0;
2392 stdarg (XmNlabelString, ms);
2393 XtSetValues (w, args, n);
2394 g_free (buf);
2397 static int
2398 cursor_pos_to_widget (Coord x, Coord y, Widget w, int prev_state)
2400 int this_state = prev_state;
2401 static char *buf;
2402 double g = coord_to_unit (Settings.grid_unit, PCB->Grid);
2403 XmString ms;
2404 int prec;
2406 /* Determine necessary precision (and state) based
2407 * on the user's grid setting */
2408 if (((int) (g * 10000 + 0.5) % 10000) == 0)
2410 prec = 0;
2411 this_state = Settings.grid_unit->allow;
2413 else
2415 prec = Settings.grid_unit->default_prec;
2416 this_state = -Settings.grid_unit->allow;
2419 if (x < 0)
2420 buf = g_strdup ("");
2421 else
2422 buf = pcb_g_strdup_printf ("%m+%.*mS, %.*mS", UUNIT, prec, x, prec, y);
2424 ms = XmStringCreatePCB (buf);
2425 n = 0;
2426 stdarg (XmNlabelString, ms);
2427 XtSetValues (w, args, n);
2428 g_free (buf);
2429 return this_state;
2432 #define S Settings
2434 void
2435 lesstif_update_status_line ()
2437 char *buf = NULL;
2438 char *s45 = cur_clip ();
2439 XmString xs;
2441 switch (Settings.Mode)
2443 case VIA_MODE:
2444 buf = pcb_g_strdup_printf ("%m+%.2mS/%.2mS \370=%.2mS", UUNIT,
2445 S.ViaThickness, S.Keepaway, S.ViaDrillingHole);
2446 break;
2447 case LINE_MODE:
2448 case ARC_MODE:
2449 buf = pcb_g_strdup_printf ("%m+%.2mS/%.2mS %s", UUNIT,
2450 S.LineThickness, S.Keepaway, s45);
2451 break;
2452 case RECTANGLE_MODE:
2453 case POLYGON_MODE:
2454 buf = pcb_g_strdup_printf ("%m+%.2mS %s", UUNIT, S.Keepaway, s45);
2455 break;
2456 case TEXT_MODE:
2457 buf = g_strdup_printf ("%d %%", S.TextScale);
2458 break;
2459 case MOVE_MODE:
2460 case COPY_MODE:
2461 case INSERTPOINT_MODE:
2462 case RUBBERBANDMOVE_MODE:
2463 buf = g_strdup_printf ("%s", s45);
2464 break;
2465 case NO_MODE:
2466 case PASTEBUFFER_MODE:
2467 case ROTATE_MODE:
2468 case REMOVE_MODE:
2469 case THERMAL_MODE:
2470 case ARROW_MODE:
2471 case LOCK_MODE:
2472 default:
2473 buf = g_strdup("");
2474 break;
2477 xs = XmStringCreatePCB (buf);
2478 n = 0;
2479 stdarg (XmNlabelString, xs);
2480 XtSetValues (m_status, args, n);
2481 g_free (buf);
2484 #undef S
2486 static int idle_proc_set = 0;
2487 static int need_redraw = 0;
2489 static Boolean
2490 idle_proc (XtPointer dummy)
2492 if (need_redraw)
2494 int mx, my;
2495 BoxType region;
2496 lesstif_use_mask (0);
2497 pixmap = main_pixmap;
2498 mx = view_width;
2499 my = view_height;
2500 region.X1 = Px (0);
2501 region.Y1 = Py (0);
2502 region.X2 = Px (view_width);
2503 region.Y2 = Py (view_height);
2504 if (flip_x)
2506 Coord tmp = region.X1;
2507 region.X1 = region.X2;
2508 region.X2 = tmp;
2510 if (flip_y)
2512 Coord tmp = region.Y1;
2513 region.Y1 = region.Y2;
2514 region.Y2 = tmp;
2516 XSetForeground (display, bg_gc, bgcolor);
2517 XFillRectangle (display, main_pixmap, bg_gc, 0, 0, mx, my);
2519 if (region.X1 < 0 || region.Y1 < 0
2520 || region.X2 > PCB->MaxWidth || region.Y2 > PCB->MaxHeight)
2522 int leftmost, rightmost, topmost, bottommost;
2524 leftmost = Vx (0);
2525 rightmost = Vx (PCB->MaxWidth);
2526 topmost = Vy (0);
2527 bottommost = Vy (PCB->MaxHeight);
2528 if (leftmost > rightmost) {
2529 int t = leftmost;
2530 leftmost = rightmost;
2531 rightmost = t;
2533 if (topmost > bottommost) {
2534 int t = topmost;
2535 topmost = bottommost;
2536 bottommost = t;
2538 if (leftmost < 0)
2539 leftmost = 0;
2540 if (topmost < 0)
2541 topmost = 0;
2542 if (rightmost > view_width)
2543 rightmost = view_width;
2544 if (bottommost > view_height)
2545 bottommost = view_height;
2547 XSetForeground (display, bg_gc, offlimit_color);
2549 /* L T R
2550 L x R
2551 L B R */
2553 if (leftmost > 0)
2555 XFillRectangle (display, main_pixmap, bg_gc, 0, 0,
2556 leftmost, view_height);
2558 if (rightmost < view_width)
2560 XFillRectangle (display, main_pixmap, bg_gc, rightmost+1, 0,
2561 view_width-rightmost+1, view_height);
2563 if (topmost > 0)
2565 XFillRectangle (display, main_pixmap, bg_gc, leftmost, 0,
2566 rightmost-leftmost+1, topmost);
2568 if (bottommost < view_height)
2570 XFillRectangle (display, main_pixmap, bg_gc, leftmost, bottommost+1,
2571 rightmost-leftmost+1, view_height-bottommost+1);
2574 DrawBackgroundImage();
2575 hid_expose_callback (&lesstif_hid, &region, 0);
2576 draw_grid ();
2577 lesstif_use_mask (0);
2578 show_crosshair (0); /* To keep the drawn / not drawn info correct */
2579 XSetFunction (display, my_gc, GXcopy);
2580 XCopyArea (display, main_pixmap, window, my_gc, 0, 0, view_width,
2581 view_height, 0, 0);
2582 pixmap = window;
2583 if (crosshair_on)
2585 DrawAttached ();
2586 DrawMark ();
2588 need_redraw = 0;
2592 static int c_x = -2, c_y = -2;
2593 static MarkType saved_mark;
2594 static const Unit *old_grid_unit = NULL;
2595 if (crosshair_x != c_x || crosshair_y != c_y
2596 || Settings.grid_unit != old_grid_unit
2597 || memcmp (&saved_mark, &Marked, sizeof (MarkType)))
2599 static int last_state = 0;
2600 static int this_state = 0;
2602 c_x = crosshair_x;
2603 c_y = crosshair_y;
2605 this_state =
2606 cursor_pos_to_widget (crosshair_x, crosshair_y, m_crosshair,
2607 this_state);
2608 if (Marked.status)
2609 mark_delta_to_widget (crosshair_x - Marked.X, crosshair_y - Marked.Y,
2610 m_mark);
2612 if (Marked.status != saved_mark.status)
2614 if (Marked.status)
2616 XtManageChild (XtParent (m_mark));
2617 XtManageChild (m_mark);
2618 n = 0;
2619 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
2620 stdarg (XmNleftWidget, XtParent (m_mark));
2621 XtSetValues (XtParent (m_crosshair), args, n);
2623 else
2625 n = 0;
2626 stdarg (XmNleftAttachment, XmATTACH_FORM);
2627 XtSetValues (XtParent (m_crosshair), args, n);
2628 XtUnmanageChild (XtParent (m_mark));
2630 last_state = this_state + 100;
2632 memcpy (&saved_mark, &Marked, sizeof (MarkType));
2634 if (old_grid_unit != Settings.grid_unit)
2636 old_grid_unit = Settings.grid_unit;
2637 /* Force a resize on units change. */
2638 last_state ++;
2641 /* This is obtuse. We want to enable XmRESIZE_ANY long enough
2642 to shrink to fit the new format (if any), then switch it
2643 back to XmRESIZE_GROW to prevent it from shrinking due to
2644 changes in the number of actual digits printed. Thus, when
2645 you switch from a small grid and %.2f formats to a large
2646 grid and %d formats, you aren't punished with a wide and
2647 mostly white-space label widget. "this_state" indicates
2648 which of the above formats we're using. "last_state" is
2649 either zero (when resizing) or the same as "this_state"
2650 (when grow-only), or a non-zero but not "this_state" which
2651 means we need to start a resize cycle. */
2652 if (this_state != last_state && last_state)
2654 n = 0;
2655 stdarg (XmNresizePolicy, XmRESIZE_ANY);
2656 XtSetValues (XtParent (m_mark), args, n);
2657 XtSetValues (XtParent (m_crosshair), args, n);
2658 last_state = 0;
2660 else if (this_state != last_state)
2662 n = 0;
2663 stdarg (XmNresizePolicy, XmRESIZE_GROW);
2664 XtSetValues (XtParent (m_mark), args, n);
2665 XtSetValues (XtParent (m_crosshair), args, n);
2666 last_state = this_state;
2672 static Coord old_grid = -1;
2673 static Coord old_gx, old_gy;
2674 static const Unit *old_unit;
2675 XmString ms;
2676 if (PCB->Grid != old_grid
2677 || PCB->GridOffsetX != old_gx
2678 || PCB->GridOffsetY != old_gy || Settings.grid_unit != old_unit)
2680 static char buf[100];
2681 old_grid = PCB->Grid;
2682 old_unit = Settings.grid_unit;
2683 old_gx = PCB->GridOffsetX;
2684 old_gy = PCB->GridOffsetY;
2685 if (old_grid == 1)
2687 strcpy (buf, "No Grid");
2689 else
2691 if (old_gx || old_gy)
2692 pcb_sprintf (buf, "%m+%$mS @%mS,%mS", UUNIT, old_grid, old_gx, old_gy);
2693 else
2694 pcb_sprintf (buf, "%m+%$mS", UUNIT, old_grid);
2696 ms = XmStringCreatePCB (buf);
2697 n = 0;
2698 stdarg (XmNlabelString, ms);
2699 XtSetValues (m_grid, args, n);
2704 static double old_zoom = -1;
2705 static const Unit *old_grid_unit = NULL;
2706 if (view_zoom != old_zoom || Settings.grid_unit != old_grid_unit)
2708 gchar *buf = pcb_g_strdup_printf ("%m+%$mS/pix",
2709 Settings.grid_unit->allow, (Coord) view_zoom);
2710 XmString ms;
2712 old_zoom = view_zoom;
2713 old_grid_unit = Settings.grid_unit;
2715 ms = XmStringCreatePCB (buf);
2716 n = 0;
2717 stdarg (XmNlabelString, ms);
2718 XtSetValues (m_zoom, args, n);
2719 g_free (buf);
2724 if (old_cursor_mode != Settings.Mode)
2726 char *s = "None";
2727 XmString ms;
2728 int cursor = -1;
2729 static int free_cursor = 0;
2731 old_cursor_mode = Settings.Mode;
2732 switch (Settings.Mode)
2734 case NO_MODE:
2735 s = "None";
2736 cursor = XC_X_cursor;
2737 break;
2738 case VIA_MODE:
2739 s = "Via";
2740 cursor = -1;
2741 break;
2742 case LINE_MODE:
2743 s = "Line";
2744 cursor = XC_pencil;
2745 break;
2746 case RECTANGLE_MODE:
2747 s = "Rectangle";
2748 cursor = XC_ul_angle;
2749 break;
2750 case POLYGON_MODE:
2751 s = "Polygon";
2752 cursor = XC_sb_up_arrow;
2753 break;
2754 case POLYGONHOLE_MODE:
2755 s = "Polygon Hole";
2756 cursor = XC_sb_up_arrow;
2757 break;
2758 case PASTEBUFFER_MODE:
2759 s = "Paste";
2760 cursor = XC_hand1;
2761 break;
2762 case TEXT_MODE:
2763 s = "Text";
2764 cursor = XC_xterm;
2765 break;
2766 case ROTATE_MODE:
2767 s = "Rotate";
2768 cursor = XC_exchange;
2769 break;
2770 case REMOVE_MODE:
2771 s = "Remove";
2772 cursor = XC_pirate;
2773 break;
2774 case MOVE_MODE:
2775 s = "Move";
2776 cursor = XC_crosshair;
2777 break;
2778 case COPY_MODE:
2779 s = "Copy";
2780 cursor = XC_crosshair;
2781 break;
2782 case INSERTPOINT_MODE:
2783 s = "Insert";
2784 cursor = XC_dotbox;
2785 break;
2786 case RUBBERBANDMOVE_MODE:
2787 s = "RBMove";
2788 cursor = XC_top_left_corner;
2789 break;
2790 case THERMAL_MODE:
2791 s = "Thermal";
2792 cursor = XC_iron_cross;
2793 break;
2794 case ARC_MODE:
2795 s = "Arc";
2796 cursor = XC_question_arrow;
2797 break;
2798 case ARROW_MODE:
2799 s = "Arrow";
2800 if (over_point)
2801 cursor = XC_draped_box;
2802 else
2803 cursor = XC_left_ptr;
2804 break;
2805 case LOCK_MODE:
2806 s = "Lock";
2807 cursor = XC_hand2;
2808 break;
2810 ms = XmStringCreatePCB (s);
2811 n = 0;
2812 stdarg (XmNlabelString, ms);
2813 XtSetValues (m_mode, args, n);
2815 if (free_cursor)
2817 XFreeCursor (display, my_cursor);
2818 free_cursor = 0;
2820 if (cursor == -1)
2822 static Pixmap nocur_source = 0;
2823 static Pixmap nocur_mask = 0;
2824 static Cursor nocursor = 0;
2825 if (nocur_source == 0)
2827 XColor fg, bg;
2828 nocur_source =
2829 XCreateBitmapFromData (display, window, "\0", 1, 1);
2830 nocur_mask =
2831 XCreateBitmapFromData (display, window, "\0", 1, 1);
2833 fg.red = fg.green = fg.blue = 65535;
2834 bg.red = bg.green = bg.blue = 0;
2835 fg.flags = bg.flags = DoRed | DoGreen | DoBlue;
2836 nocursor = XCreatePixmapCursor (display, nocur_source,
2837 nocur_mask, &fg, &bg, 0, 0);
2839 my_cursor = nocursor;
2841 else
2843 my_cursor = XCreateFontCursor (display, cursor);
2844 free_cursor = 1;
2846 XDefineCursor (display, window, my_cursor);
2847 lesstif_update_status_line ();
2851 static char *old_clip = 0;
2852 static int old_tscale = -1;
2853 char *new_clip = cur_clip ();
2855 if (new_clip != old_clip || Settings.TextScale != old_tscale)
2857 lesstif_update_status_line ();
2858 old_clip = new_clip;
2859 old_tscale = Settings.TextScale;
2864 static int old_nrats = -1;
2865 static char buf[20];
2867 if (old_nrats != PCB->Data->RatN)
2869 old_nrats = PCB->Data->RatN;
2870 sprintf(buf, "%d rat%s", PCB->Data->RatN, PCB->Data->RatN == 1 ? "" : "s");
2871 if (PCB->Data->RatN)
2873 XtManageChild(XtParent(m_rats));
2874 XtManageChild(m_rats);
2875 n = 0;
2876 stdarg (XmNleftWidget, m_rats);
2877 XtSetValues (XtParent (m_status), args, n);
2880 n = 0;
2881 stdarg (XmNlabelString, XmStringCreatePCB (buf));
2882 XtSetValues (m_rats, args, n);
2884 if (!PCB->Data->RatN)
2886 n = 0;
2887 stdarg (XmNleftWidget, m_mode);
2888 XtSetValues (XtParent (m_status), args, n);
2889 XtUnmanageChild(XtParent(m_rats));
2894 lesstif_update_widget_flags ();
2896 show_crosshair (1);
2897 idle_proc_set = 0;
2898 return True;
2901 void
2902 lesstif_need_idle_proc ()
2904 if (idle_proc_set || window == 0)
2905 return;
2906 XtAppAddWorkProc (app_context, idle_proc, 0);
2907 idle_proc_set = 1;
2910 static void
2911 lesstif_invalidate_lr (int l, int r, int t, int b)
2913 if (!window)
2914 return;
2916 need_redraw = 1;
2917 need_idle_proc ();
2920 void
2921 lesstif_invalidate_all (void)
2923 lesstif_invalidate_lr (0, PCB->MaxWidth, 0, PCB->MaxHeight);
2926 static void
2927 lesstif_notify_crosshair_change (bool changes_complete)
2929 static int invalidate_depth = 0;
2930 Pixmap save_pixmap;
2932 if (! my_gc)
2933 return;
2935 if (changes_complete)
2936 invalidate_depth --;
2938 if (invalidate_depth < 0)
2940 invalidate_depth = 0;
2941 /* A mismatch of changes_complete == false and == true notifications
2942 * is not expected to occur, but we will try to handle it gracefully.
2943 * As we know the crosshair will have been shown already, we must
2944 * repaint the entire view to be sure not to leave an artaefact.
2946 need_idle_proc ();
2947 return;
2950 if (invalidate_depth == 0 && crosshair_on)
2952 save_pixmap = pixmap;
2953 pixmap = window;
2954 DrawAttached ();
2955 pixmap = save_pixmap;
2958 if (!changes_complete)
2959 invalidate_depth ++;
2962 static void
2963 lesstif_notify_mark_change (bool changes_complete)
2965 static int invalidate_depth = 0;
2966 Pixmap save_pixmap;
2968 if (changes_complete)
2969 invalidate_depth --;
2971 if (invalidate_depth < 0)
2973 invalidate_depth = 0;
2974 /* A mismatch of changes_complete == false and == true notifications
2975 * is not expected to occur, but we will try to handle it gracefully.
2976 * As we know the mark will have been shown already, we must
2977 * repaint the entire view to be sure not to leave an artaefact.
2979 need_idle_proc ();
2980 return;
2983 if (invalidate_depth == 0 && crosshair_on)
2985 save_pixmap = pixmap;
2986 pixmap = window;
2987 DrawMark ();
2988 pixmap = save_pixmap;
2991 if (!changes_complete)
2992 invalidate_depth ++;
2995 static int
2996 lesstif_set_layer (const char *name, int group, int empty)
2998 int idx = group;
2999 if (idx >= 0 && idx < max_group)
3001 int n = PCB->LayerGroups.Number[group];
3002 for (idx = 0; idx < n-1; idx ++)
3004 int ni = PCB->LayerGroups.Entries[group][idx];
3005 if (ni >= 0 && ni < max_copper_layer + 2
3006 && PCB->Data->Layer[ni].On)
3007 break;
3009 idx = PCB->LayerGroups.Entries[group][idx];
3010 #if 0
3011 if (idx == LayerStack[0]
3012 || GetLayerGroupNumberByNumber (idx) ==
3013 GetLayerGroupNumberByNumber (LayerStack[0]))
3014 autofade = 0;
3015 else
3016 autofade = 1;
3017 #endif
3019 #if 0
3020 else
3021 autofade = 0;
3022 #endif
3023 if (idx >= 0 && idx < max_copper_layer + 2)
3024 return pinout ? 1 : PCB->Data->Layer[idx].On;
3025 if (idx < 0)
3027 switch (SL_TYPE (idx))
3029 case SL_INVISIBLE:
3030 return pinout ? 0 : PCB->InvisibleObjectsOn;
3031 case SL_MASK:
3032 if (SL_MYSIDE (idx) && !pinout)
3033 return TEST_FLAG (SHOWMASKFLAG, PCB);
3034 return 0;
3035 case SL_SILK:
3036 if (SL_MYSIDE (idx) || pinout)
3037 return PCB->ElementOn;
3038 return 0;
3039 case SL_ASSY:
3040 return 0;
3041 case SL_UDRILL:
3042 case SL_PDRILL:
3043 return 1;
3044 case SL_RATS:
3045 return PCB->RatOn;
3048 return 0;
3051 static hidGC
3052 lesstif_make_gc (void)
3054 hidGC rv = (hid_gc_struct *) malloc (sizeof (hid_gc_struct));
3055 memset (rv, 0, sizeof (hid_gc_struct));
3056 rv->me_pointer = &lesstif_hid;
3057 return rv;
3060 static void
3061 lesstif_destroy_gc (hidGC gc)
3063 free (gc);
3066 static void
3067 lesstif_use_mask (int use_it)
3069 if ((TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) &&
3070 !use_xrender)
3071 use_it = 0;
3072 if ((use_it == 0) == (use_mask == 0))
3073 return;
3074 use_mask = use_it;
3075 if (pinout)
3076 return;
3077 if (!window)
3078 return;
3079 /* printf("use_mask(%d)\n", use_it); */
3080 if (!mask_pixmap)
3082 mask_pixmap =
3083 XCreatePixmap (display, window, pixmap_w, pixmap_h,
3084 XDefaultDepth (display, screen));
3085 mask_bitmap = XCreatePixmap (display, window, pixmap_w, pixmap_h, 1);
3087 if (use_it)
3089 pixmap = mask_pixmap;
3090 XSetForeground (display, my_gc, 0);
3091 XSetFunction (display, my_gc, GXcopy);
3092 XFillRectangle (display, mask_pixmap, my_gc,
3093 0, 0, view_width, view_height);
3094 XFillRectangle (display, mask_bitmap, bclear_gc,
3095 0, 0, view_width, view_height);
3097 else
3099 pixmap = main_pixmap;
3100 #ifdef HAVE_XRENDER
3101 if (use_xrender)
3103 XRenderPictureAttributes pa;
3105 pa.clip_mask = mask_bitmap;
3106 XRenderChangePicture(display, main_picture, CPClipMask, &pa);
3107 XRenderComposite(display, PictOpOver, mask_picture, pale_picture,
3108 main_picture, 0, 0, 0, 0, 0, 0, view_width, view_height);
3110 else
3111 #endif /* HAVE_XRENDER */
3113 XSetClipMask (display, clip_gc, mask_bitmap);
3114 XCopyArea (display, mask_pixmap, main_pixmap, clip_gc,
3115 0, 0, view_width, view_height, 0, 0);
3120 static void
3121 lesstif_set_color (hidGC gc, const char *name)
3123 static void *cache = 0;
3124 hidval cval;
3125 static XColor color, exact_color;
3127 if (!display)
3128 return;
3129 if (!name)
3130 name = "red";
3131 gc->colorname = name;
3132 if (strcmp (name, "erase") == 0)
3134 gc->color = bgcolor;
3135 gc->erase = 1;
3137 else if (strcmp (name, "drill") == 0)
3139 gc->color = offlimit_color;
3140 gc->erase = 0;
3142 else if (hid_cache_color (0, name, &cval, &cache))
3144 gc->color = cval.lval;
3145 gc->erase = 0;
3147 else
3149 if (!XAllocNamedColor (display, colormap, name, &color, &exact_color))
3150 color.pixel = WhitePixel (display, screen);
3151 #if 0
3152 printf ("lesstif_set_color `%s' %08x rgb/%d/%d/%d\n",
3153 name, color.pixel, color.red, color.green, color.blue);
3154 #endif
3155 cval.lval = gc->color = color.pixel;
3156 hid_cache_color (1, name, &cval, &cache);
3157 gc->erase = 0;
3159 if (autofade)
3161 static int lastcolor = -1, lastfade = -1;
3162 if (gc->color == lastcolor)
3163 gc->color = lastfade;
3164 else
3166 lastcolor = gc->color;
3167 color.pixel = gc->color;
3169 XQueryColor (display, colormap, &color);
3170 color.red = (bgred + color.red) / 2;
3171 color.green = (bggreen + color.green) / 2;
3172 color.blue = (bgblue + color.blue) / 2;
3173 XAllocColor (display, colormap, &color);
3174 lastfade = gc->color = color.pixel;
3179 static void
3180 set_gc (hidGC gc)
3182 int cap, join, width;
3183 if (gc->me_pointer != &lesstif_hid)
3185 fprintf (stderr, "Fatal: GC from another HID passed to lesstif HID\n");
3186 abort ();
3188 #if 0
3189 pcb_printf ("set_gc c%s %08lx w%#mS c%d x%d e%d\n",
3190 gc->colorname, gc->color, gc->width, gc->cap, gc->xor_set, gc->erase);
3191 #endif
3192 switch (gc->cap)
3194 case Square_Cap:
3195 cap = CapProjecting;
3196 join = JoinMiter;
3197 break;
3198 case Trace_Cap:
3199 case Round_Cap:
3200 cap = CapRound;
3201 join = JoinRound;
3202 break;
3203 case Beveled_Cap:
3204 cap = CapProjecting;
3205 join = JoinBevel;
3206 break;
3207 default:
3208 cap = CapProjecting;
3209 join = JoinBevel;
3210 break;
3212 if (gc->xor_set)
3214 XSetFunction (display, my_gc, GXxor);
3215 XSetForeground (display, my_gc, gc->color ^ bgcolor);
3217 else if (gc->erase)
3219 XSetFunction (display, my_gc, GXcopy);
3220 XSetForeground (display, my_gc, offlimit_color);
3222 else
3224 XSetFunction (display, my_gc, GXcopy);
3225 XSetForeground (display, my_gc, gc->color);
3227 width = Vz (gc->width);
3228 if (width < 0)
3229 width = 0;
3230 XSetLineAttributes (display, my_gc, width, LineSolid, cap,
3231 join);
3232 if (use_mask)
3234 if (gc->erase)
3235 mask_gc = bclear_gc;
3236 else
3237 mask_gc = bset_gc;
3238 XSetLineAttributes (display, mask_gc, Vz (gc->width), LineSolid, cap,
3239 join);
3243 static void
3244 lesstif_set_line_cap (hidGC gc, EndCapStyle style)
3246 gc->cap = style;
3249 static void
3250 lesstif_set_line_width (hidGC gc, Coord width)
3252 gc->width = width;
3255 static void
3256 lesstif_set_draw_xor (hidGC gc, int xor_set)
3258 gc->xor_set = xor_set;
3261 #define ISORT(a,b) if (a>b) { a^=b; b^=a; a^=b; }
3263 static void
3264 lesstif_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
3266 double dx1, dy1, dx2, dy2;
3267 int vw = Vz (gc->width);
3268 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) && gc->erase)
3269 return;
3270 #if 0
3271 pcb_printf ("draw_line %#mD-%#mD @%#mS", x1, y1, x2, y2, gc->width);
3272 #endif
3273 dx1 = Vx (x1);
3274 dy1 = Vy (y1);
3275 dx2 = Vx (x2);
3276 dy2 = Vy (y2);
3277 #if 0
3278 pcb_printf (" = %#mD-%#mD %s\n", x1, y1, x2, y2, gc->colorname);
3279 #endif
3281 #if 1
3282 if (! ClipLine (0, 0, view_width, view_height,
3283 &dx1, &dy1, &dx2, &dy2, vw))
3284 return;
3285 #endif
3287 x1 = dx1;
3288 y1 = dy1;
3289 x2 = dx2;
3290 y2 = dy2;
3292 set_gc (gc);
3293 if (gc->cap == Square_Cap && x1 == x2 && y1 == y2)
3295 XFillRectangle (display, pixmap, my_gc, x1 - vw / 2, y1 - vw / 2, vw,
3296 vw);
3297 if (use_mask)
3298 XFillRectangle (display, mask_bitmap, mask_gc, x1 - vw / 2,
3299 y1 - vw / 2, vw, vw);
3301 else
3303 XDrawLine (display, pixmap, my_gc, x1, y1, x2, y2);
3304 if (use_mask)
3305 XDrawLine (display, mask_bitmap, mask_gc, x1, y1, x2, y2);
3309 static void
3310 lesstif_draw_arc (hidGC gc, Coord cx, Coord cy, Coord width, Coord height,
3311 Angle start_angle, Angle delta_angle)
3313 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase)
3314 return;
3315 #if 0
3316 pcb_printf ("draw_arc %#mD %#mSx%#mS s %d d %d", cx, cy, width, height, start_angle, delta_angle);
3317 #endif
3318 width = Vz (width);
3319 height = Vz (height);
3320 cx = Vx (cx) - width;
3321 cy = Vy (cy) - height;
3322 if (flip_x)
3324 start_angle = 180 - start_angle;
3325 delta_angle = - delta_angle;
3327 if (flip_y)
3329 start_angle = - start_angle;
3330 delta_angle = - delta_angle;
3332 start_angle = NormalizeAngle (start_angle);
3333 if (start_angle >= 180)
3334 start_angle -= 360;
3335 #if 0
3336 pcb_printf (" = %#mD %#mSx%#mS %d %s\n", cx, cy, width, height, gc->width,
3337 gc->colorname);
3338 #endif
3339 set_gc (gc);
3340 XDrawArc (display, pixmap, my_gc, cx, cy,
3341 width * 2, height * 2, (start_angle + 180) * 64,
3342 delta_angle * 64);
3343 if (use_mask && !TEST_FLAG (THINDRAWFLAG, PCB))
3344 XDrawArc (display, mask_bitmap, mask_gc, cx, cy,
3345 width * 2, height * 2, (start_angle + 180) * 64,
3346 delta_angle * 64);
3347 #if 0
3348 /* Enable this if you want to see the center and radii of drawn
3349 arcs, for debugging. */
3350 if (TEST_FLAG (THINDRAWFLAG, PCB)
3351 && delta_angle != 360)
3353 cx += width;
3354 cy += height;
3355 XDrawLine (display, pixmap, arc1_gc, cx, cy,
3356 cx - width*cos(start_angle*M_PI/180),
3357 cy + width*sin(start_angle*M_PI/180));
3358 XDrawLine (display, pixmap, arc2_gc, cx, cy,
3359 cx - width*cos((start_angle+delta_angle)*M_PI/180),
3360 cy + width*sin((start_angle+delta_angle)*M_PI/180));
3362 #endif
3365 static void
3366 lesstif_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
3368 int vw = Vz (gc->width);
3369 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase)
3370 return;
3371 x1 = Vx (x1);
3372 y1 = Vy (y1);
3373 x2 = Vx (x2);
3374 y2 = Vy (y2);
3375 if (x1 < -vw && x2 < -vw)
3376 return;
3377 if (y1 < -vw && y2 < -vw)
3378 return;
3379 if (x1 > view_width + vw && x2 > view_width + vw)
3380 return;
3381 if (y1 > view_height + vw && y2 > view_height + vw)
3382 return;
3383 if (x1 > x2) { int xt = x1; x1 = x2; x2 = xt; }
3384 if (y1 > y2) { int yt = y1; y1 = y2; y2 = yt; }
3385 set_gc (gc);
3386 XDrawRectangle (display, pixmap, my_gc, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
3387 if (use_mask)
3388 XDrawRectangle (display, mask_bitmap, mask_gc, x1, y1, x2 - x1 + 1,
3389 y2 - y1 + 1);
3392 static void
3393 lesstif_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius)
3395 if (pinout && use_mask && gc->erase)
3396 return;
3397 if ((TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) && gc->erase)
3398 return;
3399 #if 0
3400 pcb_printf ("fill_circle %#mD %#mS", cx, cy, radius);
3401 #endif
3402 radius = Vz (radius);
3403 cx = Vx (cx) - radius;
3404 cy = Vy (cy) - radius;
3405 if (cx < -2 * radius || cx > view_width)
3406 return;
3407 if (cy < -2 * radius || cy > view_height)
3408 return;
3409 #if 0
3410 pcb_printf (" = %#mD %#mS %lx %s\n", cx, cy, radius, gc->color, gc->colorname);
3411 #endif
3412 set_gc (gc);
3413 XFillArc (display, pixmap, my_gc, cx, cy,
3414 radius * 2, radius * 2, 0, 360 * 64);
3415 if (use_mask)
3416 XFillArc (display, mask_bitmap, mask_gc, cx, cy,
3417 radius * 2, radius * 2, 0, 360 * 64);
3420 static void
3421 lesstif_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y)
3423 static XPoint *p = 0;
3424 static int maxp = 0;
3425 int i;
3427 if (maxp < n_coords)
3429 maxp = n_coords + 10;
3430 if (p)
3431 p = (XPoint *) realloc (p, maxp * sizeof (XPoint));
3432 else
3433 p = (XPoint *) malloc (maxp * sizeof (XPoint));
3436 for (i = 0; i < n_coords; i++)
3438 p[i].x = Vx (x[i]);
3439 p[i].y = Vy (y[i]);
3441 #if 0
3442 printf ("fill_polygon %d pts\n", n_coords);
3443 #endif
3444 set_gc (gc);
3445 XFillPolygon (display, pixmap, my_gc, p, n_coords, Complex,
3446 CoordModeOrigin);
3447 if (use_mask)
3448 XFillPolygon (display, mask_bitmap, mask_gc, p, n_coords, Complex,
3449 CoordModeOrigin);
3452 static void
3453 lesstif_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
3455 int vw = Vz (gc->width);
3456 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase)
3457 return;
3458 x1 = Vx (x1);
3459 y1 = Vy (y1);
3460 x2 = Vx (x2);
3461 y2 = Vy (y2);
3462 if (x1 < -vw && x2 < -vw)
3463 return;
3464 if (y1 < -vw && y2 < -vw)
3465 return;
3466 if (x1 > view_width + vw && x2 > view_width + vw)
3467 return;
3468 if (y1 > view_height + vw && y2 > view_height + vw)
3469 return;
3470 if (x1 > x2) { int xt = x1; x1 = x2; x2 = xt; }
3471 if (y1 > y2) { int yt = y1; y1 = y2; y2 = yt; }
3472 set_gc (gc);
3473 XFillRectangle (display, pixmap, my_gc, x1, y1, x2 - x1 + 1,
3474 y2 - y1 + 1);
3475 if (use_mask)
3476 XFillRectangle (display, mask_bitmap, mask_gc, x1, y1, x2 - x1 + 1,
3477 y2 - y1 + 1);
3480 static void
3481 lesstif_calibrate (double xval, double yval)
3483 CRASH;
3486 static int
3487 lesstif_shift_is_pressed (void)
3489 return shift_pressed;
3492 static int
3493 lesstif_control_is_pressed (void)
3495 return ctrl_pressed;
3498 static int
3499 lesstif_mod1_is_pressed (void)
3501 return alt_pressed;
3504 extern void lesstif_get_coords (const char *msg, Coord *x, Coord *y);
3506 static void
3507 lesstif_set_crosshair (int x, int y, int action)
3509 if (crosshair_x != x || crosshair_y != y)
3511 lesstif_show_crosshair(0);
3512 crosshair_x = x;
3513 crosshair_y = y;
3514 need_idle_proc ();
3516 if (mainwind
3517 && !in_move_event
3518 && (x < view_left_x
3519 || x > view_left_x + view_width * view_zoom
3520 || y < view_top_y || y > view_top_y + view_height * view_zoom))
3522 view_left_x = x - (view_width * view_zoom) / 2;
3523 view_top_y = y - (view_height * view_zoom) / 2;
3524 lesstif_pan_fixup ();
3529 if (action == HID_SC_PAN_VIEWPORT)
3531 Window root, child;
3532 unsigned int keys_buttons;
3533 int pos_x, pos_y, root_x, root_y;
3534 XQueryPointer (display, window, &root, &child,
3535 &root_x, &root_y, &pos_x, &pos_y, &keys_buttons);
3536 if (flip_x)
3537 view_left_x = x - (view_width-pos_x) * view_zoom;
3538 else
3539 view_left_x = x - pos_x * view_zoom;
3540 if (flip_y)
3541 view_top_y = y - (view_height-pos_y) * view_zoom;
3542 else
3543 view_top_y = y - pos_y * view_zoom;
3544 lesstif_pan_fixup();
3545 action = HID_SC_WARP_POINTER;
3547 if (action == HID_SC_WARP_POINTER)
3549 in_move_event ++;
3550 XWarpPointer (display, None, window, 0, 0, 0, 0, Vx(x), Vy(y));
3551 in_move_event --;
3555 typedef struct
3557 void (*func) (hidval);
3558 hidval user_data;
3559 XtIntervalId id;
3560 } TimerStruct;
3562 static void
3563 lesstif_timer_cb (XtPointer * p, XtIntervalId * id)
3565 TimerStruct *ts = (TimerStruct *) p;
3566 ts->func (ts->user_data);
3567 free (ts);
3570 static hidval
3571 lesstif_add_timer (void (*func) (hidval user_data),
3572 unsigned long milliseconds, hidval user_data)
3574 TimerStruct *t;
3575 hidval rv;
3576 t = (TimerStruct *) malloc (sizeof (TimerStruct));
3577 rv.ptr = t;
3578 t->func = func;
3579 t->user_data = user_data;
3580 t->id = XtAppAddTimeOut (app_context, milliseconds, (XtTimerCallbackProc)lesstif_timer_cb, t);
3581 return rv;
3584 static void
3585 lesstif_stop_timer (hidval hv)
3587 TimerStruct *ts = (TimerStruct *) hv.ptr;
3588 XtRemoveTimeOut (ts->id);
3589 free (ts);
3593 typedef struct
3595 void (*func) ( hidval, int, unsigned int, hidval );
3596 hidval user_data;
3597 int fd;
3598 XtInputId id;
3600 WatchStruct;
3602 /* We need a wrapper around the hid file watch because to pass the correct flags
3604 static void
3605 lesstif_watch_cb (XtPointer client_data, int *fid, XtInputId * id)
3607 unsigned int pcb_condition = 0;
3608 struct pollfd fds;
3609 short condition;
3610 hidval x;
3611 WatchStruct *watch = (WatchStruct*)client_data;
3613 fds.fd = watch->fd;
3614 fds.events = POLLIN | POLLOUT;
3615 poll( &fds, 1, 0 );
3616 condition = fds.revents;
3618 // Should we only include those we were asked to watch?
3619 if (condition & POLLIN)
3620 pcb_condition |= PCB_WATCH_READABLE;
3621 if (condition & POLLOUT)
3622 pcb_condition |= PCB_WATCH_WRITABLE;
3623 if (condition & POLLERR)
3624 pcb_condition |= PCB_WATCH_ERROR;
3625 if (condition & POLLHUP)
3626 pcb_condition |= PCB_WATCH_HANGUP;
3628 x.ptr = (void *) watch;
3629 watch->func (x, watch->fd, pcb_condition, watch->user_data);
3631 return;
3634 hidval
3635 lesstif_watch_file (int fd, unsigned int condition, void (*func) (hidval watch, int fd, unsigned int condition, hidval user_data),
3636 hidval user_data)
3638 WatchStruct *watch = (WatchStruct *) malloc (sizeof(WatchStruct));
3639 hidval ret;
3640 unsigned int xt_condition = 0;
3642 if (condition & PCB_WATCH_READABLE)
3643 xt_condition |= XtInputReadMask;
3644 if (condition & PCB_WATCH_WRITABLE)
3645 xt_condition |= XtInputWriteMask;
3646 if (condition & PCB_WATCH_ERROR)
3647 xt_condition |= XtInputExceptMask;
3648 if (condition & PCB_WATCH_HANGUP)
3649 xt_condition |= XtInputExceptMask;
3651 watch->func = func;
3652 watch->user_data = user_data;
3653 watch->fd = fd;
3654 watch->id = XtAppAddInput( app_context, fd, (XtPointer) (size_t) xt_condition, lesstif_watch_cb, watch );
3656 ret.ptr = (void *) watch;
3657 return ret;
3660 void
3661 lesstif_unwatch_file (hidval data)
3663 WatchStruct *watch = (WatchStruct*)data.ptr;
3664 XtRemoveInput( watch->id );
3665 free( watch );
3668 typedef struct
3670 XtBlockHookId id;
3671 void (*func) (hidval user_data);
3672 hidval user_data;
3673 } BlockHookStruct;
3675 static void lesstif_block_hook_cb(XtPointer user_data);
3677 static void
3678 lesstif_block_hook_cb (XtPointer user_data)
3680 BlockHookStruct *block_hook = (BlockHookStruct *)user_data;
3681 block_hook->func( block_hook->user_data );
3684 static hidval
3685 lesstif_add_block_hook (void (*func) (hidval data), hidval user_data )
3687 hidval ret;
3688 BlockHookStruct *block_hook = (BlockHookStruct *) malloc( sizeof( BlockHookStruct ));
3690 block_hook->func = func;
3691 block_hook->user_data = user_data;
3693 block_hook->id = XtAppAddBlockHook( app_context, lesstif_block_hook_cb, (XtPointer)block_hook );
3695 ret.ptr = (void *) block_hook;
3696 return ret;
3699 static void
3700 lesstif_stop_block_hook (hidval mlpoll)
3702 BlockHookStruct *block_hook = (BlockHookStruct *)mlpoll.ptr;
3703 XtRemoveBlockHook( block_hook->id );
3704 free( block_hook );
3708 extern void lesstif_logv (const char *fmt, va_list ap);
3710 extern int lesstif_confirm_dialog (char *msg, ...);
3712 extern int lesstif_close_confirm_dialog ();
3714 extern void lesstif_report_dialog (char *title, char *msg);
3716 extern int
3717 lesstif_attribute_dialog (HID_Attribute * attrs,
3718 int n_attrs, HID_Attr_Val * results,
3719 const char * title, const char * descr);
3721 static void
3722 pinout_callback (Widget da, PinoutData * pd,
3723 XmDrawingAreaCallbackStruct * cbs)
3725 BoxType region;
3726 int save_vx, save_vy, save_vw, save_vh;
3727 int save_fx, save_fy;
3728 double save_vz;
3729 Pixmap save_px;
3730 int reason = cbs ? cbs->reason : 0;
3732 if (pd->window == 0 && reason == XmCR_RESIZE)
3733 return;
3734 if (pd->window == 0 || reason == XmCR_RESIZE)
3736 Dimension w, h;
3737 double z;
3739 n = 0;
3740 stdarg (XmNwidth, &w);
3741 stdarg (XmNheight, &h);
3742 XtGetValues (da, args, n);
3744 pd->window = XtWindow (da);
3745 pd->v_width = w;
3746 pd->v_height = h;
3747 pd->zoom = (pd->right - pd->left + 1) / (double) w;
3748 z = (pd->bottom - pd->top + 1) / (double) h;
3749 if (pd->zoom < z)
3750 pd->zoom = z;
3752 pd->x = (pd->left + pd->right) / 2 - pd->v_width * pd->zoom / 2;
3753 pd->y = (pd->top + pd->bottom) / 2 - pd->v_height * pd->zoom / 2;
3756 save_vx = view_left_x;
3757 save_vy = view_top_y;
3758 save_vz = view_zoom;
3759 save_vw = view_width;
3760 save_vh = view_height;
3761 save_fx = flip_x;
3762 save_fy = flip_y;
3763 save_px = pixmap;
3764 pinout = pd;
3765 pixmap = pd->window;
3766 view_left_x = pd->x;
3767 view_top_y = pd->y;
3768 view_zoom = pd->zoom;
3769 view_width = pd->v_width;
3770 view_height = pd->v_height;
3771 use_mask = 0;
3772 flip_x = flip_y = 0;
3774 region.X1 = 0;
3775 region.Y1 = 0;
3776 region.X2 = PCB->MaxWidth;
3777 region.Y2 = PCB->MaxHeight;
3779 XFillRectangle (display, pixmap, bg_gc, 0, 0, pd->v_width, pd->v_height);
3780 hid_expose_callback (&lesstif_hid, &region, pd->item);
3782 pinout = 0;
3783 view_left_x = save_vx;
3784 view_top_y = save_vy;
3785 view_zoom = save_vz;
3786 view_width = save_vw;
3787 view_height = save_vh;
3788 pixmap = save_px;
3789 flip_x = save_fx;
3790 flip_y = save_fy;
3793 static void
3794 pinout_unmap (Widget w, PinoutData * pd, void *v)
3796 if (pd->prev)
3797 pd->prev->next = pd->next;
3798 else
3799 pinouts = pd->next;
3800 if (pd->next)
3801 pd->next->prev = pd->prev;
3802 XtDestroyWidget (XtParent (pd->form));
3803 free (pd);
3806 static void
3807 lesstif_show_item (void *item)
3809 double scale;
3810 Widget da;
3811 BoxType *extents;
3812 PinoutData *pd;
3814 for (pd = pinouts; pd; pd = pd->next)
3815 if (pd->item == item)
3816 return;
3817 if (!mainwind)
3818 return;
3820 pd = (PinoutData *) calloc (1, sizeof (PinoutData));
3822 pd->item = item;
3824 extents = hid_get_extents (item);
3825 pd->left = extents->X1;
3826 pd->right = extents->X2;
3827 pd->top = extents->Y1;
3828 pd->bottom = extents->Y2;
3830 if (pd->left > pd->right)
3832 free (pd);
3833 return;
3835 pd->prev = 0;
3836 pd->next = pinouts;
3837 if (pd->next)
3838 pd->next->prev = pd;
3839 pinouts = pd;
3840 pd->zoom = 0;
3842 n = 0;
3843 pd->form = XmCreateFormDialog (mainwind, "pinout", args, n);
3844 pd->window = 0;
3845 XtAddCallback (pd->form, XmNunmapCallback, (XtCallbackProc) pinout_unmap,
3846 (XtPointer) pd);
3848 scale =
3849 sqrt (200.0 * 200.0 /
3850 ((pd->right - pd->left + 1.0) * (pd->bottom - pd->top + 1.0)));
3852 n = 0;
3853 stdarg (XmNwidth, (int) (scale * (pd->right - pd->left + 1)));
3854 stdarg (XmNheight, (int) (scale * (pd->bottom - pd->top + 1)));
3855 stdarg (XmNleftAttachment, XmATTACH_FORM);
3856 stdarg (XmNrightAttachment, XmATTACH_FORM);
3857 stdarg (XmNtopAttachment, XmATTACH_FORM);
3858 stdarg (XmNbottomAttachment, XmATTACH_FORM);
3859 da = XmCreateDrawingArea (pd->form, "pinout", args, n);
3860 XtManageChild (da);
3862 XtAddCallback (da, XmNexposeCallback, (XtCallbackProc) pinout_callback,
3863 (XtPointer) pd);
3864 XtAddCallback (da, XmNresizeCallback, (XtCallbackProc) pinout_callback,
3865 (XtPointer) pd);
3867 XtManageChild (pd->form);
3868 pinout = 0;
3871 static void
3872 lesstif_beep (void)
3874 putchar (7);
3875 fflush (stdout);
3879 static bool progress_cancelled = false;
3881 static void
3882 progress_cancel_callback (Widget w, void *v, void *cbs)
3884 progress_cancelled = true;
3887 static Widget progress_dialog = 0;
3888 static Widget progress_cancel, progress_label;
3889 static Widget progress_scale;
3891 static void
3892 lesstif_progress_dialog (int so_far, int total, const char *msg)
3894 XmString xs;
3896 if (mainwind == 0)
3897 return;
3899 if (progress_dialog == 0)
3901 Atom close_atom;
3903 n = 0;
3904 stdarg (XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON);
3905 stdarg (XmNtitle, "Progress");
3906 stdarg (XmNdialogStyle, XmDIALOG_APPLICATION_MODAL);
3907 stdarg (XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
3908 progress_dialog = XmCreateInformationDialog (mainwind, "progress", args, n);
3909 XtAddCallback (progress_dialog, XmNcancelCallback,
3910 (XtCallbackProc) progress_cancel_callback, NULL);
3912 progress_cancel = XmMessageBoxGetChild (progress_dialog, XmDIALOG_CANCEL_BUTTON);
3913 progress_label = XmMessageBoxGetChild (progress_dialog, XmDIALOG_MESSAGE_LABEL);
3915 XtUnmanageChild (XmMessageBoxGetChild (progress_dialog, XmDIALOG_OK_BUTTON));
3916 XtUnmanageChild (XmMessageBoxGetChild (progress_dialog, XmDIALOG_HELP_BUTTON));
3918 stdarg (XmNdefaultPosition, False);
3919 XtSetValues (progress_dialog, args, n);
3921 n = 0;
3922 stdarg(XmNminimum, 0);
3923 stdarg(XmNvalue, 0);
3924 stdarg(XmNmaximum, total > 0 ? total : 1);
3925 stdarg(XmNorientation, XmHORIZONTAL);
3926 stdarg(XmNshowArrows, false);
3927 progress_scale = XmCreateScrollBar (progress_dialog, "scale", args, n);
3928 XtManageChild (progress_scale);
3930 close_atom = XmInternAtom (display, "WM_DELETE_WINDOW", 0);
3931 XmAddWMProtocolCallback (XtParent (progress_dialog), close_atom,
3932 (XtCallbackProc) progress_cancel_callback, 0);
3935 n = 0;
3936 stdarg(XmNvalue, 0);
3937 stdarg(XmNsliderSize, (so_far <= total) ? (so_far < 0) ? 0 : so_far : total);
3938 stdarg(XmNmaximum, total > 0 ? total : 1);
3939 XtSetValues (progress_scale, args, n);
3941 n = 0;
3942 xs = XmStringCreatePCB ((char *)msg);
3943 stdarg (XmNmessageString, xs);
3944 XtSetValues (progress_dialog, args, n);
3946 return;
3949 #define MIN_TIME_SEPARATION 0.1 /* seconds */
3951 static int
3952 lesstif_progress (int so_far, int total, const char *message)
3954 static bool visible = false;
3955 static bool started = false;
3956 XEvent e;
3957 struct timeval time;
3958 double time_delta, time_now;
3959 static double time_then = 0.0;
3960 int retval = 0;
3962 if (so_far == 0 && total == 0 && message == NULL)
3964 XtUnmanageChild (progress_dialog);
3965 visible = false;
3966 started = false;
3967 progress_cancelled = false;
3968 return retval;
3971 gettimeofday (&time, NULL);
3972 time_now = time.tv_sec + time.tv_usec / 1000000.0;
3974 time_delta = time_now - time_then;
3976 if (started && time_delta < MIN_TIME_SEPARATION)
3977 return retval;
3979 /* Create or update the progress dialog */
3980 lesstif_progress_dialog (so_far, total, message);
3982 if (!started)
3984 XtManageChild (progress_dialog);
3985 started = true;
3988 /* Dispatch pending events */
3989 while (XtAppPending (app_context))
3991 XtAppNextEvent (app_context, &e);
3992 XtDispatchEvent (&e);
3994 idle_proc (NULL);
3996 /* If rendering takes a while, make sure the core has enough time to
3997 do work. */
3998 gettimeofday (&time, NULL);
3999 time_then = time.tv_sec + time.tv_usec / 1000000.0;
4001 return progress_cancelled;
4004 static HID *
4005 lesstif_request_debug_draw (void)
4007 /* Send drawing to the backing pixmap */
4008 pixmap = main_pixmap;
4009 return &lesstif_hid;
4012 static void
4013 lesstif_flush_debug_draw (void)
4015 /* Copy the backing pixmap to the display and redraw any attached objects */
4016 XSetFunction (display, my_gc, GXcopy);
4017 XCopyArea (display, main_pixmap, window, my_gc, 0, 0, view_width,
4018 view_height, 0, 0);
4019 pixmap = window;
4020 if (crosshair_on)
4022 DrawAttached ();
4023 DrawMark ();
4025 pixmap = main_pixmap;
4028 static void
4029 lesstif_finish_debug_draw (void)
4031 lesstif_flush_debug_draw ();
4032 /* No special tear down requirements
4036 #include "dolists.h"
4038 void
4039 hid_lesstif_init ()
4041 memset (&lesstif_hid, 0, sizeof (HID));
4043 common_nogui_init (&lesstif_hid);
4044 common_draw_helpers_init (&lesstif_hid);
4046 lesstif_hid.struct_size = sizeof (HID);
4047 lesstif_hid.name = "lesstif";
4048 lesstif_hid.description = "LessTif - a Motif clone for X/Unix";
4049 lesstif_hid.gui = 1;
4050 lesstif_hid.poly_before = 1;
4052 lesstif_hid.get_export_options = lesstif_get_export_options;
4053 lesstif_hid.do_export = lesstif_do_export;
4054 lesstif_hid.parse_arguments = lesstif_parse_arguments;
4055 lesstif_hid.invalidate_lr = lesstif_invalidate_lr;
4056 lesstif_hid.invalidate_all = lesstif_invalidate_all;
4057 lesstif_hid.notify_crosshair_change = lesstif_notify_crosshair_change;
4058 lesstif_hid.notify_mark_change = lesstif_notify_mark_change;
4059 lesstif_hid.set_layer = lesstif_set_layer;
4060 lesstif_hid.make_gc = lesstif_make_gc;
4061 lesstif_hid.destroy_gc = lesstif_destroy_gc;
4062 lesstif_hid.use_mask = lesstif_use_mask;
4063 lesstif_hid.set_color = lesstif_set_color;
4064 lesstif_hid.set_line_cap = lesstif_set_line_cap;
4065 lesstif_hid.set_line_width = lesstif_set_line_width;
4066 lesstif_hid.set_draw_xor = lesstif_set_draw_xor;
4067 lesstif_hid.draw_line = lesstif_draw_line;
4068 lesstif_hid.draw_arc = lesstif_draw_arc;
4069 lesstif_hid.draw_rect = lesstif_draw_rect;
4070 lesstif_hid.fill_circle = lesstif_fill_circle;
4071 lesstif_hid.fill_polygon = lesstif_fill_polygon;
4072 lesstif_hid.fill_rect = lesstif_fill_rect;
4074 lesstif_hid.calibrate = lesstif_calibrate;
4075 lesstif_hid.shift_is_pressed = lesstif_shift_is_pressed;
4076 lesstif_hid.control_is_pressed = lesstif_control_is_pressed;
4077 lesstif_hid.mod1_is_pressed = lesstif_mod1_is_pressed;
4078 lesstif_hid.get_coords = lesstif_get_coords;
4079 lesstif_hid.set_crosshair = lesstif_set_crosshair;
4080 lesstif_hid.add_timer = lesstif_add_timer;
4081 lesstif_hid.stop_timer = lesstif_stop_timer;
4082 lesstif_hid.watch_file = lesstif_watch_file;
4083 lesstif_hid.unwatch_file = lesstif_unwatch_file;
4084 lesstif_hid.add_block_hook = lesstif_add_block_hook;
4085 lesstif_hid.stop_block_hook = lesstif_stop_block_hook;
4087 lesstif_hid.log = lesstif_log;
4088 lesstif_hid.logv = lesstif_logv;
4089 lesstif_hid.confirm_dialog = lesstif_confirm_dialog;
4090 lesstif_hid.close_confirm_dialog = lesstif_close_confirm_dialog;
4091 lesstif_hid.report_dialog = lesstif_report_dialog;
4092 lesstif_hid.prompt_for = lesstif_prompt_for;
4093 lesstif_hid.fileselect = lesstif_fileselect;
4094 lesstif_hid.attribute_dialog = lesstif_attribute_dialog;
4095 lesstif_hid.show_item = lesstif_show_item;
4096 lesstif_hid.beep = lesstif_beep;
4097 lesstif_hid.progress = lesstif_progress;
4098 lesstif_hid.edit_attributes = lesstif_attributes_dialog;
4100 lesstif_hid.request_debug_draw = lesstif_request_debug_draw;
4101 lesstif_hid.flush_debug_draw = lesstif_flush_debug_draw;
4102 lesstif_hid.finish_debug_draw = lesstif_finish_debug_draw;
4104 hid_register_hid (&lesstif_hid);
4105 #include "lesstif_lists.h"