Pass an explicit graphics context to DrawAttached and DrawMark
[geda-pcb/pcjc2.git] / src / hid / lesstif / main.c
blobc351a48b09331e895838e29ff36ef5d4fe23cae6
1 #ifdef HAVE_CONFIG_H
2 #include "config.h"
3 #endif
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <time.h>
8 #include <string.h>
9 #include <math.h>
10 #include <unistd.h>
11 #include <signal.h>
12 #include <sys/time.h>
14 #include "xincludes.h"
16 #include "global.h"
17 #include "data.h"
18 #include "action.h"
19 #include "crosshair.h"
20 #include "mymem.h"
21 #include "misc.h"
22 #include "pcb-printf.h"
23 #include "resource.h"
24 #include "clip.h"
25 #include "error.h"
27 #include "hid.h"
28 #include "hid_draw.h"
29 #include "../hidint.h"
30 #include "hid/common/hidnogui.h"
31 #include "hid/common/draw_helpers.h"
32 #include "hid/common/hid_resource.h"
33 #include "lesstif.h"
35 #ifdef HAVE_LIBDMALLOC
36 #include <dmalloc.h>
37 #endif
39 #include <sys/poll.h>
41 #ifndef XtRDouble
42 #define XtRDouble "Double"
43 #endif
45 /* How big the viewport can be relative to the pcb size. */
46 #define MAX_ZOOM_SCALE 10
47 #define UUNIT Settings.grid_unit->allow
49 typedef struct hid_gc_struct
51 HID *me_pointer;
52 Pixel color;
53 const char *colorname;
54 int width;
55 EndCapStyle cap;
56 char xor_set;
57 char erase;
58 } hid_gc_struct;
60 static HID lesstif_hid;
61 static HID_DRAW lesstif_graphics;
63 #define CRASH fprintf(stderr, "HID error: pcb called unimplemented GUI function %s\n", __FUNCTION__), abort()
65 XtAppContext app_context;
66 Widget appwidget;
67 Display *display;
68 static Window window = 0;
69 static Cursor my_cursor = 0;
70 static int old_cursor_mode = -1;
71 static int over_point = 0;
73 /* The first is the "current" pixmap. The main_ is the real one we
74 usually use, the mask_ are the ones for doing polygon masks. The
75 pixmap is the saved pixels, the bitmap is for the "erase" color.
76 We set pixmap to point to main_pixmap or mask_pixmap as needed. */
77 static Pixmap pixmap = 0;
78 static Pixmap main_pixmap = 0;
79 static Pixmap mask_pixmap = 0;
80 static Pixmap mask_bitmap = 0;
81 static enum mask_mode use_mask = HID_MASK_OFF;
83 static int use_xrender = 0;
84 #ifdef HAVE_XRENDER
85 static Picture main_picture;
86 static Picture mask_picture;
87 static Pixmap pale_pixmap;
88 static Picture pale_picture;
89 #endif /* HAVE_XRENDER */
91 static int pixmap_w = 0, pixmap_h = 0;
92 Screen *screen_s;
93 int screen;
94 static Colormap colormap;
95 static GC my_gc = 0, bg_gc, clip_gc = 0, bset_gc = 0, bclear_gc = 0, mask_gc =
97 static Pixel bgcolor, offlimit_color, grid_color;
98 static int bgred, bggreen, bgblue;
100 static GC arc1_gc, arc2_gc;
102 static hidGC crosshair_gc;
104 /* These are for the pinout windows. */
105 typedef struct PinoutData
107 struct PinoutData *prev, *next;
108 Widget form;
109 Window window;
110 Coord left, right, top, bottom; /* PCB extents of item */
111 Coord x, y; /* PCB coordinates of upper right corner of window */
112 double zoom; /* PCB units per screen pixel */
113 int v_width, v_height; /* pixels */
114 void *item;
115 } PinoutData;
117 /* Linked list of all pinout windows. */
118 static PinoutData *pinouts = 0;
119 /* If set, we are currently updating this pinout window. */
120 static PinoutData *pinout = 0;
122 static int crosshair_x = 0, crosshair_y = 0;
123 static int in_move_event = 0, crosshair_in_window = 1;
125 Widget mainwind;
126 Widget work_area, messages, command, hscroll, vscroll;
127 static Widget m_mark, m_crosshair, m_grid, m_zoom, m_mode, m_status;
128 static Widget m_rats;
129 Widget lesstif_m_layer;
130 Widget m_click;
132 /* This is the size, in pixels, of the viewport. */
133 static int view_width, view_height;
134 /* This is the PCB location represented by the upper left corner of
135 the viewport. Note that PCB coordinates put 0,0 in the upper left,
136 much like X does. */
137 static int view_left_x = 0, view_top_y = 0;
138 /* Denotes PCB units per screen pixel. Larger numbers mean zooming
139 out - the largest value means you are looking at the whole
140 board. */
141 static double view_zoom = MIL_TO_COORD (10), prev_view_zoom = MIL_TO_COORD (10);
142 static bool flip_x = 0, flip_y = 0;
143 static bool autofade = 0;
144 static bool crosshair_on = true;
146 /* ---------------------------------------------------------------------------
147 * some local prototypes
149 static hidGC lesstif_make_gc (void);
151 static void
152 ShowCrosshair (bool show)
154 if (crosshair_on == show)
155 return;
157 notify_crosshair_change (false);
158 if (Marked.status)
159 notify_mark_change (false);
161 crosshair_on = show;
163 notify_crosshair_change (true);
164 if (Marked.status)
165 notify_mark_change (true);
168 static int
169 flag_flipx (void *data)
171 return flip_x;
173 static int
174 flag_flipy (void *data)
176 return flip_y;
179 HID_Flag lesstif_main_flag_list[] = {
180 {"flip_x", flag_flipx, NULL},
181 {"flip_y", flag_flipy, NULL}
184 REGISTER_FLAGS (lesstif_main_flag_list)
186 /* This is the size of the current PCB work area. */
187 /* Use PCB->MaxWidth, PCB->MaxHeight. */
188 /* static int pcb_width, pcb_height; */
190 static Arg args[30];
191 static int n;
192 #define stdarg(t,v) XtSetArg(args[n], t, v), n++
195 static int use_private_colormap = 0;
196 static int stdin_listen = 0;
197 static char *background_image_file = 0;
198 char *lesstif_pcbmenu_path = "pcb-menu.res";
200 HID_Attribute lesstif_attribute_list[] = {
201 {"install", "Install private colormap",
202 HID_Boolean, 0, 0, {0, 0, 0}, 0, &use_private_colormap},
203 #define HA_colormap 0
205 /* %start-doc options "22 lesstif GUI Options"
206 @ftable @code
207 @item --listen
208 Listen for actions on stdin.
209 @end ftable
210 %end-doc
212 {"listen", "Listen on standard input for actions",
213 HID_Boolean, 0, 0, {0, 0, 0}, 0, &stdin_listen},
214 #define HA_listen 1
216 /* %start-doc options "22 lesstif GUI Options"
217 @ftable @code
218 @item --bg-image <string>
219 File name of an image to put into the background of the GUI canvas. The image must
220 be a color PPM image, in binary (not ASCII) format. It can be any size, and will be
221 automatically scaled to fit the canvas.
222 @end ftable
223 %end-doc
225 {"bg-image", "Background Image",
226 HID_String, 0, 0, {0, 0, 0}, 0, &background_image_file},
227 #define HA_bg_image 2
229 /* %start-doc options "22 lesstif GUI Options"
230 @ftable @code
231 @item --pcb-menu <string>
232 Location of the @file{pcb-menu.res} file which defines the menu for the lesstif GUI.
233 @end ftable
234 %end-doc
236 {"pcb-menu", "Location of pcb-menu.res file",
237 HID_String, 0, 0, {0, PCBLIBDIR "/pcb-menu.res", 0}, 0, &lesstif_pcbmenu_path}
238 #define HA_pcbmenu 3
241 REGISTER_ATTRIBUTES (lesstif_attribute_list)
243 static void lesstif_use_mask (enum mask_mode mode);
244 static void zoom_max ();
245 static void zoom_to (double factor, int x, int y);
246 static void zoom_by (double factor, int x, int y);
247 static void zoom_toggle (int x, int y);
248 static void pinout_callback (Widget, PinoutData *,
249 XmDrawingAreaCallbackStruct *);
250 static void pinout_unmap (Widget, PinoutData *, void *);
251 static void Pan (int mode, int x, int y);
253 /* Px converts view->pcb, Vx converts pcb->view */
255 static inline int
256 Vx (Coord x)
258 int rv = (x - view_left_x) / view_zoom + 0.5;
259 if (flip_x)
260 rv = view_width - rv;
261 return rv;
264 static inline int
265 Vy (Coord y)
267 int rv = (y - view_top_y) / view_zoom + 0.5;
268 if (flip_y)
269 rv = view_height - rv;
270 return rv;
273 static inline int
274 Vz (Coord z)
276 return z / view_zoom + 0.5;
279 static inline Coord
280 Px (int x)
282 if (flip_x)
283 x = view_width - x;
284 return x * view_zoom + view_left_x;
287 static inline Coord
288 Py (int y)
290 if (flip_y)
291 y = view_height - y;
292 return y * view_zoom + view_top_y;
295 static inline Coord
296 Pz (int z)
298 return z * view_zoom;
301 void
302 lesstif_coords_to_pcb (int vx, int vy, Coord *px, Coord *py)
304 *px = Px (vx);
305 *py = Py (vy);
308 Pixel
309 lesstif_parse_color (char *value)
311 XColor color;
312 if (XParseColor (display, colormap, value, &color))
313 if (XAllocColor (display, colormap, &color))
314 return color.pixel;
315 return 0;
318 static void
319 do_color (char *value, char *which)
321 XColor color;
322 if (XParseColor (display, colormap, value, &color))
323 if (XAllocColor (display, colormap, &color))
325 stdarg (which, color.pixel);
329 /* ------------------------------------------------------------ */
331 static char *
332 cur_clip ()
334 if (TEST_FLAG (ORTHOMOVEFLAG, PCB))
335 return "+";
336 if (TEST_FLAG (ALLDIRECTIONFLAG, PCB))
337 return "*";
338 if (PCB->Clipping == 0)
339 return "X";
340 if (PCB->Clipping == 1)
341 return "_/";
342 return "\\_";
345 /* Called from the core when it's busy doing something and we need to
346 indicate that to the user. */
347 static int
348 Busy(int argc, char **argv, Coord x, Coord y)
350 static Cursor busy_cursor = 0;
351 if (busy_cursor == 0)
352 busy_cursor = XCreateFontCursor (display, XC_watch);
353 XDefineCursor (display, window, busy_cursor);
354 XFlush(display);
355 old_cursor_mode = -1;
356 return 0;
359 /* ---------------------------------------------------------------------- */
361 /* Local actions. */
363 static int
364 PointCursor (int argc, char **argv, Coord x, Coord y)
366 if (argc > 0)
367 over_point = 1;
368 else
369 over_point = 0;
370 old_cursor_mode = -1;
371 return 0;
374 static int
375 PCBChanged (int argc, char **argv, Coord x, Coord y)
377 if (work_area == 0)
378 return 0;
379 /*pcb_printf("PCB Changed! %$mD\n", PCB->MaxWidth, PCB->MaxHeight); */
380 n = 0;
381 stdarg (XmNminimum, 0);
382 stdarg (XmNvalue, 0);
383 stdarg (XmNsliderSize, PCB->MaxWidth ? PCB->MaxWidth : 1);
384 stdarg (XmNmaximum, PCB->MaxWidth ? PCB->MaxWidth : 1);
385 XtSetValues (hscroll, args, n);
386 n = 0;
387 stdarg (XmNminimum, 0);
388 stdarg (XmNvalue, 0);
389 stdarg (XmNsliderSize, PCB->MaxHeight ? PCB->MaxHeight : 1);
390 stdarg (XmNmaximum, PCB->MaxHeight ? PCB->MaxHeight : 1);
391 XtSetValues (vscroll, args, n);
392 zoom_max ();
394 hid_action ("NetlistChanged");
395 hid_action ("LayersChanged");
396 hid_action ("RouteStylesChanged");
397 lesstif_sizes_reset ();
398 lesstif_update_layer_groups ();
399 while (pinouts)
400 pinout_unmap (0, pinouts, 0);
401 if (PCB->Filename)
403 char *cp = strrchr (PCB->Filename, '/');
404 n = 0;
405 stdarg (XmNtitle, cp ? cp + 1 : PCB->Filename);
406 XtSetValues (appwidget, args, n);
408 return 0;
412 static const char setunits_syntax[] =
413 "SetUnits(mm|mil)";
415 static const char setunits_help[] =
416 "Set the default measurement units.";
418 /* %start-doc actions SetUnits
420 @table @code
422 @item mil
423 Sets the display units to mils (1/1000 inch).
425 @item mm
426 Sets the display units to millimeters.
428 @end table
430 %end-doc */
432 static int
433 SetUnits (int argc, char **argv, Coord x, Coord y)
435 const Unit *new_unit;
436 if (argc == 0)
437 return 0;
438 new_unit = get_unit_struct (argv[0]);
439 if (new_unit != NULL && new_unit->allow != NO_PRINT)
441 Settings.grid_unit = new_unit;
442 Settings.increments = get_increments_struct (Settings.grid_unit->family);
443 AttributePut (PCB, "PCB::grid::unit", argv[0]);
445 lesstif_sizes_reset ();
446 lesstif_styles_update_values ();
447 return 0;
450 static const char zoom_syntax[] =
451 "Zoom()\n"
452 "Zoom(factor)";
454 static const char zoom_help[] =
455 "Various zoom factor changes.";
457 /* %start-doc actions Zoom
459 Changes the zoom (magnification) of the view of the board. If no
460 arguments are passed, the view is scaled such that the board just fits
461 inside the visible window (i.e. ``view all''). Otherwise,
462 @var{factor} specifies a change in zoom factor. It may be prefixed by
463 @code{+}, @code{-}, or @code{=} to change how the zoom factor is
464 modified. The @var{factor} is a floating point number, such as
465 @code{1.5} or @code{0.75}.
467 @table @code
469 @item +@var{factor}
470 Values greater than 1.0 cause the board to be drawn smaller; more of
471 the board will be visible. Values between 0.0 and 1.0 cause the board
472 to be drawn bigger; less of the board will be visible.
474 @item -@var{factor}
475 Values greater than 1.0 cause the board to be drawn bigger; less of
476 the board will be visible. Values between 0.0 and 1.0 cause the board
477 to be drawn smaller; more of the board will be visible.
479 @item =@var{factor}
481 The @var{factor} is an absolute zoom factor; the unit for this value
482 is "PCB units per screen pixel". Since PCB units are 0.01 mil, a
483 @var{factor} of 1000 means 10 mils (0.01 in) per pixel, or 100 DPI,
484 about the actual resolution of most screens - resulting in an "actual
485 size" board. Similarly, a @var{factor} of 100 gives you a 10x actual
486 size.
488 @end table
490 Note that zoom factors of zero are silently ignored.
492 %end-doc */
494 static int
495 ZoomAction (int argc, char **argv, Coord x, Coord y)
497 const char *vp;
498 double v;
499 if (x == 0 && y == 0)
501 x = view_width / 2;
502 y = view_height / 2;
504 else
506 x = Vx (x);
507 y = Vy (y);
509 if (argc < 1)
511 zoom_max ();
512 return 0;
514 vp = argv[0];
515 if (strcasecmp (vp, "toggle") == 0)
517 zoom_toggle (x, y);
518 return 0;
520 if (*vp == '+' || *vp == '-' || *vp == '=')
521 vp++;
522 v = g_ascii_strtod (vp, 0);
523 if (v <= 0)
524 return 1;
525 switch (argv[0][0])
527 case '-':
528 zoom_by (1 / v, x, y);
529 break;
530 default:
531 case '+':
532 zoom_by (v, x, y);
533 break;
534 case '=':
535 zoom_to (v, x, y);
536 break;
538 return 0;
541 static int pan_thumb_mode;
543 static int
544 PanAction (int argc, char **argv, Coord x, Coord y)
546 int mode;
548 if (argc == 2)
550 pan_thumb_mode = (strcasecmp (argv[0], "thumb") == 0) ? 1 : 0;
551 mode = atoi (argv[1]);
553 else
555 pan_thumb_mode = 0;
556 mode = atoi (argv[0]);
558 Pan (mode, Vx(x), Vy(y));
560 return 0;
563 static const char swapsides_syntax[] =
564 "SwapSides(|v|h|r)";
566 static const char swapsides_help[] =
567 "Swaps the side of the board you're looking at.";
569 /* %start-doc actions SwapSides
571 This action changes the way you view the board.
573 @table @code
575 @item v
576 Flips the board over vertically (up/down).
578 @item h
579 Flips the board over horizontally (left/right), like flipping pages in
580 a book.
582 @item r
583 Rotates the board 180 degrees without changing sides.
585 @end table
587 If no argument is given, the board isn't moved but the opposite side
588 is shown.
590 Normally, this action changes which pads and silk layer are drawn as
591 true silk, and which are drawn as the "invisible" layer. It also
592 determines which solder mask you see.
594 As a special case, if the layer group for the side you're looking at
595 is visible and currently active, and the layer group for the opposite
596 is not visible (i.e. disabled), then this action will also swap which
597 layer group is visible and active, effectively swapping the ``working
598 side'' of the board.
600 %end-doc */
602 static int
603 group_showing (int g, int *c)
605 int i, l;
606 *c = PCB->LayerGroups.Entries[g][0];
607 for (i=0; i<PCB->LayerGroups.Number[g]; i++)
609 l = PCB->LayerGroups.Entries[g][i];
610 if (l >= 0 && l < max_copper_layer)
612 *c = l;
613 if (PCB->Data->Layer[l].On)
614 return 1;
617 return 0;
620 static int
621 SwapSides (int argc, char **argv, Coord x, Coord y)
623 int old_shown_side = Settings.ShowBottomSide;
624 int top_group = GetLayerGroupNumberBySide (TOP_SIDE);
625 int bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
626 int active_group = GetLayerGroupNumberByNumber (LayerStack[0]);
627 int top_layer;
628 int bottom_layer;
629 int top_showing = group_showing (top_group, &top_layer);
630 int bottom_showing = group_showing (bottom_group, &bottom_layer);
632 if (argc > 0)
634 switch (argv[0][0]) {
635 case 'h':
636 case 'H':
637 flip_x = ! flip_x;
638 break;
639 case 'v':
640 case 'V':
641 flip_y = ! flip_y;
642 break;
643 case 'r':
644 case 'R':
645 flip_x = ! flip_x;
646 flip_y = ! flip_y;
647 break;
648 default:
649 return 1;
651 /* SwapSides will swap this */
652 Settings.ShowBottomSide = (flip_x == flip_y);
655 n = 0;
656 if (flip_x)
657 stdarg (XmNprocessingDirection, XmMAX_ON_LEFT);
658 else
659 stdarg (XmNprocessingDirection, XmMAX_ON_RIGHT);
660 XtSetValues (hscroll, args, n);
662 n = 0;
663 if (flip_y)
664 stdarg (XmNprocessingDirection, XmMAX_ON_TOP);
665 else
666 stdarg (XmNprocessingDirection, XmMAX_ON_BOTTOM);
667 XtSetValues (vscroll, args, n);
669 Settings.ShowBottomSide = !Settings.ShowBottomSide;
671 /* The idea is that if we're looking at the front side and the front
672 layer is active (or visa versa), switching sides should switch
673 layers too. We used to only do this if the other layer wasn't
674 shown, but we now do it always. Change it back if users get
675 confused. */
676 if (Settings.ShowBottomSide != old_shown_side)
678 if (Settings.ShowBottomSide)
680 if (active_group == top_group)
682 if (top_showing && !bottom_showing)
683 ChangeGroupVisibility (top_layer, 0, 0);
684 ChangeGroupVisibility (bottom_layer, 1, 1);
687 else
689 if (active_group == bottom_group)
691 if (bottom_showing && !top_showing)
692 ChangeGroupVisibility (bottom_layer, 0, 0);
693 ChangeGroupVisibility (top_layer, 1, 1);
697 lesstif_invalidate_all ();
698 return 0;
701 static Widget m_cmd = 0, m_cmd_label;
703 static void
704 command_callback (Widget w, XtPointer uptr, XmTextVerifyCallbackStruct * cbs)
706 char *s;
707 switch (cbs->reason)
709 case XmCR_ACTIVATE:
710 s = XmTextGetString (w);
711 lesstif_show_crosshair (0);
712 hid_parse_command (s);
713 XtFree (s);
714 XmTextSetString (w, "");
715 case XmCR_LOSING_FOCUS:
716 XtUnmanageChild (m_cmd);
717 XtUnmanageChild (m_cmd_label);
718 break;
722 static void
723 command_event_handler (Widget w, XtPointer p, XEvent * e, Boolean * cont)
725 char buf[10];
726 KeySym sym;
728 switch (e->type)
730 case KeyPress:
731 XLookupString ((XKeyEvent *)e, buf, sizeof (buf), &sym, NULL);
732 switch (sym)
734 case XK_Escape:
735 XtUnmanageChild (m_cmd);
736 XtUnmanageChild (m_cmd_label);
737 XmTextSetString (w, "");
738 *cont = False;
739 break;
741 break;
745 static const char command_syntax[] =
746 "Command()";
748 static const char command_help[] =
749 "Displays the command line input window.";
751 /* %start-doc actions Command
753 The command window allows the user to manually enter actions to be
754 executed. Action syntax can be done one of two ways:
756 @itemize @bullet
758 @item
759 Follow the action name by an open parenthesis, arguments separated by
760 commas, end with a close parenthesis. Example: @code{Abc(1,2,3)}
762 @item
763 Separate the action name and arguments by spaces. Example: @code{Abc
764 1 2 3}.
766 @end itemize
768 The first option allows you to have arguments with spaces in them,
769 but the second is more ``natural'' to type for most people.
771 Note that action names are not case sensitive, but arguments normally
772 are. However, most actions will check for ``keywords'' in a case
773 insensitive way.
775 There are three ways to finish with the command window. If you press
776 the @code{Enter} key, the command is invoked, the window goes away,
777 and the next time you bring up the command window it's empty. If you
778 press the @code{Esc} key, the window goes away without invoking
779 anything, and the next time you bring up the command window it's
780 empty. If you change focus away from the command window (i.e. click
781 on some other window), the command window goes away but the next time
782 you bring it up it resumes entering the command you were entering
783 before.
785 %end-doc */
787 static int
788 Command (int argc, char **argv, Coord x, Coord y)
790 XtManageChild (m_cmd_label);
791 XtManageChild (m_cmd);
792 XmProcessTraversal (m_cmd, XmTRAVERSE_CURRENT);
793 return 0;
796 static const char benchmark_syntax[] =
797 "Benchmark()";
799 static const char benchmark_help[] =
800 "Benchmark the GUI speed.";
802 /* %start-doc actions Benchmark
804 This action is used to speed-test the Lesstif graphics subsystem. It
805 redraws the current screen as many times as possible in ten seconds.
806 It reports the amount of time needed to draw the screen once.
808 %end-doc */
810 static int
811 Benchmark (int argc, char **argv, Coord x, Coord y)
813 int i = 0;
814 time_t start, end;
815 BoxType region;
816 Drawable save_main;
818 save_main = main_pixmap;
819 main_pixmap = window;
821 region.X1 = 0;
822 region.Y1 = 0;
823 region.X2 = PCB->MaxWidth;
824 region.Y2 = PCB->MaxHeight;
826 pixmap = window;
827 XSync (display, 0);
828 time (&start);
831 XFillRectangle (display, pixmap, bg_gc, 0, 0, view_width, view_height);
832 hid_expose_callback (&lesstif_hid, &region, 0);
833 XSync (display, 0);
834 time (&end);
835 i++;
837 while (end - start < 10);
839 printf ("%g redraws per second\n", i / 10.0);
841 main_pixmap = save_main;
842 return 0;
845 static int
846 Center(int argc, char **argv, Coord x, Coord y)
848 x = GridFit (x, PCB->Grid, PCB->GridOffsetX);
849 y = GridFit (y, PCB->Grid, PCB->GridOffsetY);
850 view_left_x = x - (view_width * view_zoom) / 2;
851 view_top_y = y - (view_height * view_zoom) / 2;
852 lesstif_pan_fixup ();
853 /* Move the pointer to the center of the window, but only if it's
854 currently within the window already. Watch out for edges,
855 though. */
856 XWarpPointer (display, window, window, 0, 0, view_width, view_height,
857 Vx(x), Vy(y));
858 return 0;
861 static const char cursor_syntax[] =
862 "Cursor(Type,DeltaUp,DeltaRight,Units)";
864 static const char cursor_help[] =
865 "Move the cursor.";
867 /* %start-doc actions Cursor
869 This action moves the mouse cursor. Unlike other actions which take
870 coordinates, this action's coordinates are always relative to the
871 user's view of the board. Thus, a positive @var{DeltaUp} may move the
872 cursor towards the board origin if the board is inverted.
874 Type is one of @samp{Pan} or @samp{Warp}. @samp{Pan} causes the
875 viewport to move such that the crosshair is under the mouse cursor.
876 @samp{Warp} causes the mouse cursor to move to be above the crosshair.
878 @var{Units} can be one of the following:
880 @table @samp
882 @item mil
883 @itemx mm
884 The cursor is moved by that amount, in board units.
886 @item grid
887 The cursor is moved by that many grid points.
889 @item view
890 The values are percentages of the viewport's view. Thus, a pan of
891 @samp{100} would scroll the viewport by exactly the width of the
892 current view.
894 @item board
895 The values are percentages of the board size. Thus, a move of
896 @samp{50,50} moves you halfway across the board.
898 @end table
900 %end-doc */
902 static int
903 CursorAction(int argc, char **argv, Coord x, Coord y)
905 UnitList extra_units_x = {
906 { "grid", PCB->Grid, 0 },
907 { "view", Pz(view_width), UNIT_PERCENT },
908 { "board", PCB->MaxWidth, UNIT_PERCENT },
909 { "", 0, 0 }
911 UnitList extra_units_y = {
912 { "grid", PCB->Grid, 0 },
913 { "view", Pz(view_height), UNIT_PERCENT },
914 { "board", PCB->MaxHeight, UNIT_PERCENT },
915 { "", 0, 0 }
917 int pan_warp = HID_SC_DO_NOTHING;
918 double dx, dy;
920 if (argc != 4)
921 AFAIL(cursor);
923 if (strcasecmp (argv[0], "pan") == 0)
924 pan_warp = HID_SC_PAN_VIEWPORT;
925 else if (strcasecmp (argv[0], "warp") == 0)
926 pan_warp = HID_SC_WARP_POINTER;
927 else
928 AFAIL(cursor);
930 dx = GetValueEx (argv[1], argv[3], NULL, extra_units_x, "mil");
931 if (flip_x)
932 dx = -dx;
933 dy = GetValueEx (argv[2], argv[3], NULL, extra_units_y, "mil");
934 if (!flip_y)
935 dy = -dy;
937 EventMoveCrosshair (Crosshair.X + dx, Crosshair.Y + dy);
938 gui->set_crosshair (Crosshair.X, Crosshair.Y, pan_warp);
940 return 0;
943 HID_Action lesstif_main_action_list[] = {
944 {"PCBChanged", 0, PCBChanged,
945 pcbchanged_help, pcbchanged_syntax},
946 {"SetUnits", 0, SetUnits,
947 setunits_help, setunits_syntax},
948 {"Zoom", "Click on a place to zoom in", ZoomAction,
949 zoom_help, zoom_syntax},
950 {"Pan", "Click on a place to pan", PanAction,
951 zoom_help, zoom_syntax},
952 {"SwapSides", 0, SwapSides,
953 swapsides_help, swapsides_syntax},
954 {"Command", 0, Command,
955 command_help, command_syntax},
956 {"Benchmark", 0, Benchmark,
957 benchmark_help, benchmark_syntax},
958 {"PointCursor", 0, PointCursor},
959 {"Center", "Click on a location to center", Center},
960 {"Busy", 0, Busy},
961 {"Cursor", 0, CursorAction,
962 cursor_help, cursor_syntax},
965 REGISTER_ACTIONS (lesstif_main_action_list)
968 /* ----------------------------------------------------------------------
969 * redraws the background image
972 static int bg_w, bg_h, bgi_w, bgi_h;
973 static Pixel **bg = 0;
974 static XImage *bgi = 0;
975 static enum {
976 PT_unknown,
977 PT_RGB565,
978 PT_RGB888
979 } pixel_type = PT_unknown;
981 static void
982 LoadBackgroundFile (FILE *f, char *filename)
984 XVisualInfo vinfot, *vinfo;
985 Visual *vis;
986 int c, r, b;
987 int i, nret;
988 int p[3], rows, cols, maxval;
990 if (fgetc(f) != 'P')
992 printf("bgimage: %s signature not P6\n", filename);
993 return;
995 if (fgetc(f) != '6')
997 printf("bgimage: %s signature not P6\n", filename);
998 return;
1000 for (i=0; i<3; i++)
1002 do {
1003 b = fgetc(f);
1004 if (feof(f))
1005 return;
1006 if (b == '#')
1007 while (!feof(f) && b != '\n')
1008 b = fgetc(f);
1009 } while (!isdigit(b));
1010 p[i] = b - '0';
1011 while (isdigit(b = fgetc(f)))
1012 p[i] = p[i]*10 + b - '0';
1014 bg_w = cols = p[0];
1015 bg_h = rows = p[1];
1016 maxval = p[2];
1018 setbuf(stdout, 0);
1019 bg = (Pixel **) malloc (rows * sizeof (Pixel *));
1020 if (!bg)
1022 printf("Out of memory loading %s\n", filename);
1023 return;
1025 for (i=0; i<rows; i++)
1027 bg[i] = (Pixel *) malloc (cols * sizeof (Pixel));
1028 if (!bg[i])
1030 printf("Out of memory loading %s\n", filename);
1031 while (--i >= 0)
1032 free (bg[i]);
1033 free (bg);
1034 bg = 0;
1035 return;
1039 vis = DefaultVisual (display, DefaultScreen(display));
1041 vinfot.visualid = XVisualIDFromVisual(vis);
1042 vinfo = XGetVisualInfo (display, VisualIDMask, &vinfot, &nret);
1044 #if 0
1045 /* If you want to support more visuals below, you'll probably need
1046 this. */
1047 printf("vinfo: rm %04x gm %04x bm %04x depth %d class %d\n",
1048 vinfo->red_mask, vinfo->green_mask, vinfo->blue_mask,
1049 vinfo->depth, vinfo->class);
1050 #endif
1052 #if !defined(__cplusplus)
1053 #define c_class class
1054 #endif
1056 if (vinfo->c_class == TrueColor
1057 && vinfo->depth == 16
1058 && vinfo->red_mask == 0xf800
1059 && vinfo->green_mask == 0x07e0
1060 && vinfo->blue_mask == 0x001f)
1061 pixel_type = PT_RGB565;
1063 if (vinfo->c_class == TrueColor
1064 && vinfo->depth == 24
1065 && vinfo->red_mask == 0xff0000
1066 && vinfo->green_mask == 0x00ff00
1067 && vinfo->blue_mask == 0x0000ff)
1068 pixel_type = PT_RGB888;
1070 for (r=0; r<rows; r++)
1072 for (c=0; c<cols; c++)
1074 XColor pix;
1075 unsigned int pr = (unsigned)fgetc(f);
1076 unsigned int pg = (unsigned)fgetc(f);
1077 unsigned int pb = (unsigned)fgetc(f);
1079 switch (pixel_type)
1081 case PT_unknown:
1082 pix.red = pr * 65535 / maxval;
1083 pix.green = pg * 65535 / maxval;
1084 pix.blue = pb * 65535 / maxval;
1085 pix.flags = DoRed | DoGreen | DoBlue;
1086 XAllocColor (display, colormap, &pix);
1087 bg[r][c] = pix.pixel;
1088 break;
1089 case PT_RGB565:
1090 bg[r][c] = (pr>>3)<<11 | (pg>>2)<<5 | (pb>>3);
1091 break;
1092 case PT_RGB888:
1093 bg[r][c] = (pr << 16) | (pg << 8) | (pb);
1094 break;
1100 void
1101 LoadBackgroundImage (char *filename)
1103 FILE *f = fopen(filename, "rb");
1104 if (!f)
1106 if (NSTRCMP (filename, "pcb-background.ppm"))
1107 perror(filename);
1108 return;
1110 LoadBackgroundFile (f, filename);
1111 fclose(f);
1114 static void
1115 DrawBackgroundImage ()
1117 int x, y, w, h;
1118 double xscale, yscale;
1119 int pcbwidth = PCB->MaxWidth / view_zoom;
1120 int pcbheight = PCB->MaxHeight / view_zoom;
1122 if (!window || !bg)
1123 return;
1125 if (!bgi || view_width != bgi_w || view_height != bgi_h)
1127 if (bgi)
1128 XDestroyImage (bgi);
1129 /* Cheat - get the image, which sets up the format too. */
1130 bgi = XGetImage (XtDisplay(work_area),
1131 window,
1132 0, 0, view_width, view_height,
1133 -1, ZPixmap);
1134 bgi_w = view_width;
1135 bgi_h = view_height;
1138 w = MIN (view_width, pcbwidth);
1139 h = MIN (view_height, pcbheight);
1141 xscale = (double)bg_w / PCB->MaxWidth;
1142 yscale = (double)bg_h / PCB->MaxHeight;
1144 for (y=0; y<h; y++)
1146 int pr = Py(y);
1147 int ir = pr * yscale;
1148 for (x=0; x<w; x++)
1150 int pc = Px(x);
1151 int ic = pc * xscale;
1152 XPutPixel (bgi, x, y, bg[ir][ic]);
1155 XPutImage(display, main_pixmap, bg_gc,
1156 bgi,
1157 0, 0, 0, 0, w, h);
1159 /* ---------------------------------------------------------------------- */
1161 static HID_Attribute *
1162 lesstif_get_export_options (int *n)
1164 *n = sizeof (lesstif_attribute_list) / sizeof (HID_Attribute);
1165 return lesstif_attribute_list;
1168 static void
1169 set_scroll (Widget s, int pos, int view, int pcb)
1171 int sz = view * view_zoom;
1172 if (sz > pcb)
1173 sz = pcb;
1174 n = 0;
1175 stdarg (XmNvalue, pos);
1176 stdarg (XmNsliderSize, sz);
1177 stdarg (XmNincrement, view_zoom);
1178 stdarg (XmNpageIncrement, sz);
1179 stdarg (XmNmaximum, pcb);
1180 XtSetValues (s, args, n);
1183 void
1184 lesstif_pan_fixup ()
1186 #if 0
1187 if (view_left_x > PCB->MaxWidth - (view_width * view_zoom))
1188 view_left_x = PCB->MaxWidth - (view_width * view_zoom);
1189 if (view_top_y > PCB->MaxHeight - (view_height * view_zoom))
1190 view_top_y = PCB->MaxHeight - (view_height * view_zoom);
1191 if (view_left_x < 0)
1192 view_left_x = 0;
1193 if (view_top_y < 0)
1194 view_top_y = 0;
1195 if (view_width * view_zoom > PCB->MaxWidth
1196 && view_height * view_zoom > PCB->MaxHeight)
1198 zoom_by (1, 0, 0);
1199 return;
1201 #endif
1203 set_scroll (hscroll, view_left_x, view_width, PCB->MaxWidth);
1204 set_scroll (vscroll, view_top_y, view_height, PCB->MaxHeight);
1206 lesstif_invalidate_all ();
1209 static void
1210 zoom_max ()
1212 double new_zoom = PCB->MaxWidth / view_width;
1213 if (new_zoom < PCB->MaxHeight / view_height)
1214 new_zoom = PCB->MaxHeight / view_height;
1216 view_left_x = -(view_width * new_zoom - PCB->MaxWidth) / 2;
1217 view_top_y = -(view_height * new_zoom - PCB->MaxHeight) / 2;
1218 view_zoom = new_zoom;
1219 pixel_slop = view_zoom;
1220 lesstif_pan_fixup ();
1223 static void
1224 zoom_to (double new_zoom, int x, int y)
1226 double max_zoom, xfrac, yfrac;
1227 int cx, cy;
1229 xfrac = (double) x / (double) view_width;
1230 yfrac = (double) y / (double) view_height;
1232 if (flip_x)
1233 xfrac = 1-xfrac;
1234 if (flip_y)
1235 yfrac = 1-yfrac;
1237 max_zoom = PCB->MaxWidth / view_width;
1238 if (max_zoom < PCB->MaxHeight / view_height)
1239 max_zoom = PCB->MaxHeight / view_height;
1241 max_zoom *= MAX_ZOOM_SCALE;
1243 if (new_zoom < 1)
1244 new_zoom = 1;
1245 if (new_zoom > max_zoom)
1246 new_zoom = max_zoom;
1248 cx = view_left_x + view_width * xfrac * view_zoom;
1249 cy = view_top_y + view_height * yfrac * view_zoom;
1251 if (view_zoom != new_zoom)
1253 view_zoom = new_zoom;
1254 pixel_slop = view_zoom;
1256 view_left_x = cx - view_width * xfrac * view_zoom;
1257 view_top_y = cy - view_height * yfrac * view_zoom;
1259 lesstif_pan_fixup ();
1262 static void
1263 zoom_toggle(int x, int y)
1265 double tmp;
1267 tmp = prev_view_zoom;
1268 prev_view_zoom = view_zoom;
1269 zoom_to(tmp, x, y);
1272 void
1273 zoom_by (double factor, int x, int y)
1275 zoom_to (view_zoom * factor, x, y);
1278 static int panning = 0;
1279 static int shift_pressed;
1280 static int ctrl_pressed;
1281 static int alt_pressed;
1283 /* X and Y are in screen coordinates. */
1284 static void
1285 Pan (int mode, int x, int y)
1287 static int ox, oy;
1288 static int opx, opy;
1290 panning = mode;
1291 /* This is for ctrl-pan, where the viewport's position is directly
1292 proportional to the cursor position in the window (like the Xaw
1293 thumb panner) */
1294 if (pan_thumb_mode)
1296 opx = x * PCB->MaxWidth / view_width;
1297 opy = y * PCB->MaxHeight / view_height;
1298 if (flip_x)
1299 opx = PCB->MaxWidth - opx;
1300 if (flip_y)
1301 opy = PCB->MaxHeight - opy;
1302 view_left_x = opx - view_width / 2 * view_zoom;
1303 view_top_y = opy - view_height / 2 * view_zoom;
1304 lesstif_pan_fixup ();
1306 /* This is the start of a regular pan. On the first click, we
1307 remember the coordinates where we "grabbed" the screen. */
1308 else if (mode == 1)
1310 ox = x;
1311 oy = y;
1312 opx = view_left_x;
1313 opy = view_top_y;
1315 /* continued drag, we calculate how far we've moved the cursor and
1316 set the position accordingly. */
1317 else
1319 if (flip_x)
1320 view_left_x = opx + (x - ox) * view_zoom;
1321 else
1322 view_left_x = opx - (x - ox) * view_zoom;
1323 if (flip_y)
1324 view_top_y = opy + (y - oy) * view_zoom;
1325 else
1326 view_top_y = opy - (y - oy) * view_zoom;
1327 lesstif_pan_fixup ();
1331 static void
1332 mod_changed (XKeyEvent * e, int set)
1334 switch (XKeycodeToKeysym (display, e->keycode, 0))
1336 case XK_Shift_L:
1337 case XK_Shift_R:
1338 shift_pressed = set;
1339 break;
1340 case XK_Control_L:
1341 case XK_Control_R:
1342 ctrl_pressed = set;
1343 break;
1344 #ifdef __APPLE__
1345 case XK_Mode_switch:
1346 #else
1347 case XK_Alt_L:
1348 case XK_Alt_R:
1349 #endif
1350 alt_pressed = set;
1351 break;
1352 default:
1353 // to include the Apple keyboard left and right command keys use XK_Meta_L and XK_Meta_R respectivly.
1354 return;
1356 in_move_event = 1;
1357 notify_crosshair_change (false);
1358 if (panning)
1359 Pan (2, e->x, e->y);
1360 EventMoveCrosshair (Px (e->x), Py (e->y));
1361 AdjustAttachedObjects ();
1362 notify_crosshair_change (true);
1363 in_move_event = 0;
1366 static void
1367 work_area_input (Widget w, XtPointer v, XEvent * e, Boolean * ctd)
1369 static int pressed_button = 0;
1371 show_crosshair (0);
1372 switch (e->type)
1374 case KeyPress:
1375 mod_changed (&(e->xkey), 1);
1376 if (lesstif_key_event (&(e->xkey)))
1377 return;
1378 break;
1380 case KeyRelease:
1381 mod_changed (&(e->xkey), 0);
1382 break;
1384 case ButtonPress:
1386 int mods;
1387 if (pressed_button)
1388 return;
1389 /*printf("click %d\n", e->xbutton.button); */
1390 if (lesstif_button_event (w, e))
1391 return;
1393 notify_crosshair_change (false);
1394 pressed_button = e->xbutton.button;
1395 mods = ((e->xbutton.state & ShiftMask) ? M_Shift : 0)
1396 + ((e->xbutton.state & ControlMask) ? M_Ctrl : 0)
1397 #ifdef __APPLE__
1398 + ((e->xbutton.state & (1<<13)) ? M_Alt : 0);
1399 #else
1400 + ((e->xbutton.state & Mod1Mask) ? M_Alt : 0);
1401 #endif
1402 do_mouse_action(e->xbutton.button, mods);
1403 notify_crosshair_change (true);
1404 break;
1407 case ButtonRelease:
1409 int mods;
1410 if (e->xbutton.button != pressed_button)
1411 return;
1412 lesstif_button_event (w, e);
1413 notify_crosshair_change (false);
1414 pressed_button = 0;
1415 mods = ((e->xbutton.state & ShiftMask) ? M_Shift : 0)
1416 + ((e->xbutton.state & ControlMask) ? M_Ctrl : 0)
1417 #ifdef __APPLE__
1418 + ((e->xbutton.state & (1<<13)) ? M_Alt : 0)
1419 #else
1420 + ((e->xbutton.state & Mod1Mask) ? M_Alt : 0)
1421 #endif
1422 + M_Release;
1423 do_mouse_action (e->xbutton.button, mods);
1424 notify_crosshair_change (true);
1425 break;
1428 case MotionNotify:
1430 Window root, child;
1431 unsigned int keys_buttons;
1432 int root_x, root_y, pos_x, pos_y;
1433 while (XCheckMaskEvent (display, PointerMotionMask, e));
1434 XQueryPointer (display, e->xmotion.window, &root, &child,
1435 &root_x, &root_y, &pos_x, &pos_y, &keys_buttons);
1436 shift_pressed = (keys_buttons & ShiftMask);
1437 ctrl_pressed = (keys_buttons & ControlMask);
1438 #ifdef __APPLE__
1439 alt_pressed = (keys_buttons & (1<<13));
1440 #else
1441 alt_pressed = (keys_buttons & Mod1Mask);
1442 #endif
1443 /*pcb_printf("m %#mS %#mS\n", Px(e->xmotion.x), Py(e->xmotion.y)); */
1444 crosshair_in_window = 1;
1445 in_move_event = 1;
1446 if (panning)
1447 Pan (2, pos_x, pos_y);
1448 EventMoveCrosshair (Px (pos_x), Py (pos_y));
1449 in_move_event = 0;
1451 break;
1453 case LeaveNotify:
1454 crosshair_in_window = 0;
1455 ShowCrosshair (false);
1456 need_idle_proc ();
1457 break;
1459 case EnterNotify:
1460 crosshair_in_window = 1;
1461 in_move_event = 1;
1462 EventMoveCrosshair (Px (e->xcrossing.x), Py (e->xcrossing.y));
1463 ShowCrosshair (true);
1464 in_move_event = 0;
1465 need_idle_proc ();
1466 break;
1468 default:
1469 printf ("work_area: unknown event %d\n", e->type);
1470 break;
1474 static void
1475 draw_right_cross (GC xor_gc, int x, int y,
1476 int view_width, int view_height)
1478 XDrawLine (display, window, xor_gc, 0, y, view_width, y);
1479 XDrawLine (display, window, xor_gc, x, 0, x, view_height);
1482 static void
1483 draw_slanted_cross (GC xor_gc, int x, int y,
1484 int view_width, int view_height)
1486 int x0, y0, x1, y1;
1488 x0 = x + (view_height - y);
1489 x0 = MAX(0, MIN (x0, view_width));
1490 x1 = x - y;
1491 x1 = MAX(0, MIN (x1, view_width));
1492 y0 = y + (view_width - x);
1493 y0 = MAX(0, MIN (y0, view_height));
1494 y1 = y - x;
1495 y1 = MAX(0, MIN (y1, view_height));
1496 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1497 x0 = x - (view_height - y);
1498 x0 = MAX(0, MIN (x0, view_width));
1499 x1 = x + y;
1500 x1 = MAX(0, MIN (x1, view_width));
1501 y0 = y + x;
1502 y0 = MAX(0, MIN (y0, view_height));
1503 y1 = y - (view_width - x);
1504 y1 = MAX(0, MIN (y1, view_height));
1505 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1508 static void
1509 draw_dozen_cross (GC xor_gc, int x, int y,
1510 int view_width, int view_height)
1512 int x0, y0, x1, y1;
1513 double tan60 = sqrt (3);
1515 x0 = x + (view_height - y) / tan60;
1516 x0 = MAX(0, MIN (x0, view_width));
1517 x1 = x - y / tan60;
1518 x1 = MAX(0, MIN (x1, view_width));
1519 y0 = y + (view_width - x) * tan60;
1520 y0 = MAX(0, MIN (y0, view_height));
1521 y1 = y - x * tan60;
1522 y1 = MAX(0, MIN (y1, view_height));
1523 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1525 x0 = x + (view_height - y) * tan60;
1526 x0 = MAX(0, MIN (x0, view_width));
1527 x1 = x - y * tan60;
1528 x1 = MAX(0, MIN (x1, view_width));
1529 y0 = y + (view_width - x) / tan60;
1530 y0 = MAX(0, MIN (y0, view_height));
1531 y1 = y - x / tan60;
1532 y1 = MAX(0, MIN (y1, view_height));
1533 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1535 x0 = x - (view_height - y) / tan60;
1536 x0 = MAX(0, MIN (x0, view_width));
1537 x1 = x + y / tan60;
1538 x1 = MAX(0, MIN (x1, view_width));
1539 y0 = y + x * tan60;
1540 y0 = MAX(0, MIN (y0, view_height));
1541 y1 = y - (view_width - x) * tan60;
1542 y1 = MAX(0, MIN (y1, view_height));
1543 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1545 x0 = x - (view_height - y) * tan60;
1546 x0 = MAX(0, MIN (x0, view_width));
1547 x1 = x + y * tan60;
1548 x1 = MAX(0, MIN (x1, view_width));
1549 y0 = y + x / tan60;
1550 y0 = MAX(0, MIN (y0, view_height));
1551 y1 = y - (view_width - x) / tan60;
1552 y1 = MAX(0, MIN (y1, view_height));
1553 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1556 static void
1557 draw_crosshair (GC xor_gc, int x, int y,
1558 int view_width, int view_height)
1560 draw_right_cross (xor_gc, x, y, view_width, view_height);
1561 if (Crosshair.shape == Union_Jack_Crosshair_Shape)
1562 draw_slanted_cross (xor_gc, x, y, view_width, view_height);
1563 if (Crosshair.shape == Dozen_Crosshair_Shape)
1564 draw_dozen_cross (xor_gc, x, y, view_width, view_height);
1566 void
1567 lesstif_show_crosshair (int show)
1569 static int showing = 0;
1570 static int sx, sy;
1571 static GC xor_gc = 0;
1572 Pixel crosshair_color;
1574 if (!crosshair_in_window || !window)
1575 return;
1576 if (xor_gc == 0)
1578 crosshair_color = lesstif_parse_color (Settings.CrosshairColor) ^ bgcolor;
1579 xor_gc = XCreateGC (display, window, 0, 0);
1580 XSetFunction (display, xor_gc, GXxor);
1581 XSetForeground (display, xor_gc, crosshair_color);
1583 if (show == showing)
1584 return;
1585 if (show)
1587 sx = Vx (crosshair_x);
1588 sy = Vy (crosshair_y);
1590 else
1591 need_idle_proc ();
1592 draw_crosshair (xor_gc, sx, sy, view_width, view_height);
1593 showing = show;
1596 static void
1597 work_area_expose (Widget work_area, void *me,
1598 XmDrawingAreaCallbackStruct * cbs)
1600 XExposeEvent *e;
1602 show_crosshair (0);
1603 e = &(cbs->event->xexpose);
1604 XSetFunction (display, my_gc, GXcopy);
1605 XCopyArea (display, main_pixmap, window, my_gc,
1606 e->x, e->y, e->width, e->height, e->x, e->y);
1607 show_crosshair (1);
1610 static void
1611 scroll_callback (Widget scroll, int *view_dim,
1612 XmScrollBarCallbackStruct * cbs)
1614 *view_dim = cbs->value;
1615 lesstif_invalidate_all ();
1618 static void
1619 work_area_make_pixmaps (Dimension width, Dimension height)
1621 if (main_pixmap)
1622 XFreePixmap (display, main_pixmap);
1623 main_pixmap =
1624 XCreatePixmap (display, window, width, height,
1625 XDefaultDepth (display, screen));
1627 if (mask_pixmap)
1628 XFreePixmap (display, mask_pixmap);
1629 mask_pixmap =
1630 XCreatePixmap (display, window, width, height,
1631 XDefaultDepth (display, screen));
1632 #ifdef HAVE_XRENDER
1633 if (main_picture)
1635 XRenderFreePicture (display, main_picture);
1636 main_picture = 0;
1638 if (mask_picture)
1640 XRenderFreePicture (display, mask_picture);
1641 mask_picture = 0;
1643 if (use_xrender)
1645 main_picture = XRenderCreatePicture (display, main_pixmap,
1646 XRenderFindVisualFormat(display,
1647 DefaultVisual(display, screen)), 0, 0);
1648 mask_picture = XRenderCreatePicture (display, mask_pixmap,
1649 XRenderFindVisualFormat(display,
1650 DefaultVisual(display, screen)), 0, 0);
1651 if (!main_picture || !mask_picture)
1652 use_xrender = 0;
1654 #endif /* HAVE_XRENDER */
1656 if (mask_bitmap)
1657 XFreePixmap (display, mask_bitmap);
1658 mask_bitmap = XCreatePixmap (display, window, width, height, 1);
1660 pixmap = use_mask ? main_pixmap : mask_pixmap;
1661 pixmap_w = width;
1662 pixmap_h = height;
1665 static void
1666 work_area_resize (Widget work_area, void *me,
1667 XmDrawingAreaCallbackStruct * cbs)
1669 XColor color;
1670 Dimension width, height;
1672 show_crosshair (0);
1674 n = 0;
1675 stdarg (XtNwidth, &width);
1676 stdarg (XtNheight, &height);
1677 stdarg (XmNbackground, &bgcolor);
1678 XtGetValues (work_area, args, n);
1679 view_width = width;
1680 view_height = height;
1682 color.pixel = bgcolor;
1683 XQueryColor (display, colormap, &color);
1684 bgred = color.red;
1685 bggreen = color.green;
1686 bgblue = color.blue;
1688 if (!window)
1689 return;
1691 work_area_make_pixmaps (view_width, view_height);
1693 zoom_by (1, 0, 0);
1696 static void
1697 work_area_first_expose (Widget work_area, void *me,
1698 XmDrawingAreaCallbackStruct * cbs)
1700 int c;
1701 Dimension width, height;
1702 static char dashes[] = { 4, 4 };
1704 window = XtWindow (work_area);
1705 my_gc = XCreateGC (display, window, 0, 0);
1707 arc1_gc = XCreateGC (display, window, 0, 0);
1708 c = lesstif_parse_color ("#804000");
1709 XSetForeground (display, arc1_gc, c);
1710 arc2_gc = XCreateGC (display, window, 0, 0);
1711 c = lesstif_parse_color ("#004080");
1712 XSetForeground (display, arc2_gc, c);
1713 XSetLineAttributes (display, arc1_gc, 1, LineOnOffDash, 0, 0);
1714 XSetLineAttributes (display, arc2_gc, 1, LineOnOffDash, 0, 0);
1715 XSetDashes (display, arc1_gc, 0, dashes, 2);
1716 XSetDashes (display, arc2_gc, 0, dashes, 2);
1718 n = 0;
1719 stdarg (XtNwidth, &width);
1720 stdarg (XtNheight, &height);
1721 stdarg (XmNbackground, &bgcolor);
1722 XtGetValues (work_area, args, n);
1723 view_width = width;
1724 view_height = height;
1726 offlimit_color = lesstif_parse_color (Settings.OffLimitColor);
1727 grid_color = lesstif_parse_color (Settings.GridColor);
1729 bg_gc = XCreateGC (display, window, 0, 0);
1730 XSetForeground (display, bg_gc, bgcolor);
1732 work_area_make_pixmaps (width, height);
1734 #ifdef HAVE_XRENDER
1735 if (use_xrender)
1737 XRenderPictureAttributes pa;
1738 XRenderColor a = {0, 0, 0, 0x8000};
1740 pale_pixmap = XCreatePixmap (display, window, 1, 1, 8);
1741 pa.repeat = True;
1742 pale_picture = XRenderCreatePicture (display, pale_pixmap,
1743 XRenderFindStandardFormat(display, PictStandardA8),
1744 CPRepeat, &pa);
1745 if (pale_picture)
1746 XRenderFillRectangle(display, PictOpSrc, pale_picture, &a, 0, 0, 1, 1);
1747 else
1748 use_xrender = 0;
1750 #endif /* HAVE_XRENDER */
1752 clip_gc = XCreateGC (display, window, 0, 0);
1753 bset_gc = XCreateGC (display, mask_bitmap, 0, 0);
1754 XSetForeground (display, bset_gc, 1);
1755 bclear_gc = XCreateGC (display, mask_bitmap, 0, 0);
1756 XSetForeground (display, bclear_gc, 0);
1758 XtRemoveCallback (work_area, XmNexposeCallback,
1759 (XtCallbackProc) work_area_first_expose, 0);
1760 XtAddCallback (work_area, XmNexposeCallback,
1761 (XtCallbackProc) work_area_expose, 0);
1762 lesstif_invalidate_all ();
1765 static Widget
1766 make_message (char *name, Widget left, int resizeable)
1768 Widget w, f;
1769 n = 0;
1770 if (left)
1772 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
1773 stdarg (XmNleftWidget, XtParent(left));
1775 else
1777 stdarg (XmNleftAttachment, XmATTACH_FORM);
1779 stdarg (XmNtopAttachment, XmATTACH_FORM);
1780 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1781 stdarg (XmNshadowType, XmSHADOW_IN);
1782 stdarg (XmNshadowThickness, 1);
1783 stdarg (XmNalignment, XmALIGNMENT_CENTER);
1784 stdarg (XmNmarginWidth, 4);
1785 stdarg (XmNmarginHeight, 1);
1786 if (!resizeable)
1787 stdarg (XmNresizePolicy, XmRESIZE_GROW);
1788 f = XmCreateForm (messages, name, args, n);
1789 XtManageChild (f);
1790 n = 0;
1791 stdarg (XmNtopAttachment, XmATTACH_FORM);
1792 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1793 stdarg (XmNleftAttachment, XmATTACH_FORM);
1794 stdarg (XmNrightAttachment, XmATTACH_FORM);
1795 w = XmCreateLabel (f, name, args, n);
1796 XtManageChild (w);
1797 return w;
1800 static void
1801 lesstif_do_export (HID_Attr_Val * options)
1803 Dimension width, height;
1804 Widget menu;
1805 Widget work_area_frame;
1807 crosshair_gc = lesstif_make_gc ();
1809 n = 0;
1810 stdarg (XtNwidth, &width);
1811 stdarg (XtNheight, &height);
1812 XtGetValues (appwidget, args, n);
1814 if (width < 1)
1815 width = 640;
1816 if (width > XDisplayWidth (display, screen))
1817 width = XDisplayWidth (display, screen);
1818 if (height < 1)
1819 height = 480;
1820 if (height > XDisplayHeight (display, screen))
1821 height = XDisplayHeight (display, screen);
1823 n = 0;
1824 stdarg (XmNwidth, width);
1825 stdarg (XmNheight, height);
1826 XtSetValues (appwidget, args, n);
1828 stdarg (XmNspacing, 0);
1829 mainwind = XmCreateMainWindow (appwidget, "mainWind", args, n);
1830 XtManageChild (mainwind);
1832 n = 0;
1833 stdarg (XmNmarginWidth, 0);
1834 stdarg (XmNmarginHeight, 0);
1835 menu = lesstif_menu (mainwind, "menubar", args, n);
1836 XtManageChild (menu);
1838 n = 0;
1839 stdarg (XmNshadowType, XmSHADOW_IN);
1840 work_area_frame =
1841 XmCreateFrame (mainwind, "work_area_frame", args, n);
1842 XtManageChild (work_area_frame);
1844 n = 0;
1845 do_color (Settings.BackgroundColor, XmNbackground);
1846 work_area = XmCreateDrawingArea (work_area_frame, "work_area", args, n);
1847 XtManageChild (work_area);
1848 XtAddCallback (work_area, XmNexposeCallback,
1849 (XtCallbackProc) work_area_first_expose, 0);
1850 XtAddCallback (work_area, XmNresizeCallback,
1851 (XtCallbackProc) work_area_resize, 0);
1852 /* A regular callback won't work here, because lesstif swallows any
1853 Ctrl<Button>1 event. */
1854 XtAddEventHandler (work_area,
1855 ButtonPressMask | ButtonReleaseMask
1856 | PointerMotionMask | PointerMotionHintMask
1857 | KeyPressMask | KeyReleaseMask
1858 | EnterWindowMask | LeaveWindowMask,
1859 0, work_area_input, 0);
1861 n = 0;
1862 stdarg (XmNorientation, XmVERTICAL);
1863 stdarg (XmNprocessingDirection, XmMAX_ON_BOTTOM);
1864 stdarg (XmNmaximum, PCB->MaxHeight ? PCB->MaxHeight : 1);
1865 vscroll = XmCreateScrollBar (mainwind, "vscroll", args, n);
1866 XtAddCallback (vscroll, XmNvalueChangedCallback,
1867 (XtCallbackProc) scroll_callback, (XtPointer) & view_top_y);
1868 XtAddCallback (vscroll, XmNdragCallback, (XtCallbackProc) scroll_callback,
1869 (XtPointer) & view_top_y);
1870 XtManageChild (vscroll);
1872 n = 0;
1873 stdarg (XmNorientation, XmHORIZONTAL);
1874 stdarg (XmNmaximum, PCB->MaxWidth ? PCB->MaxWidth : 1);
1875 hscroll = XmCreateScrollBar (mainwind, "hscroll", args, n);
1876 XtAddCallback (hscroll, XmNvalueChangedCallback,
1877 (XtCallbackProc) scroll_callback, (XtPointer) & view_left_x);
1878 XtAddCallback (hscroll, XmNdragCallback, (XtCallbackProc) scroll_callback,
1879 (XtPointer) & view_left_x);
1880 XtManageChild (hscroll);
1882 n = 0;
1883 stdarg (XmNresize, True);
1884 stdarg (XmNresizePolicy, XmRESIZE_ANY);
1885 messages = XmCreateForm (mainwind, "messages", args, n);
1886 XtManageChild (messages);
1888 n = 0;
1889 stdarg (XmNtopAttachment, XmATTACH_FORM);
1890 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1891 stdarg (XmNleftAttachment, XmATTACH_FORM);
1892 stdarg (XmNrightAttachment, XmATTACH_FORM);
1893 stdarg (XmNalignment, XmALIGNMENT_CENTER);
1894 stdarg (XmNshadowThickness, 2);
1895 m_click = XmCreateLabel (messages, "click", args, n);
1897 n = 0;
1898 stdarg (XmNtopAttachment, XmATTACH_FORM);
1899 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1900 stdarg (XmNleftAttachment, XmATTACH_FORM);
1901 stdarg (XmNlabelString, XmStringCreatePCB ("Command: "));
1902 m_cmd_label = XmCreateLabel (messages, "command", args, n);
1904 n = 0;
1905 stdarg (XmNtopAttachment, XmATTACH_FORM);
1906 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1907 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
1908 stdarg (XmNleftWidget, m_cmd_label);
1909 stdarg (XmNrightAttachment, XmATTACH_FORM);
1910 stdarg (XmNshadowThickness, 1);
1911 stdarg (XmNhighlightThickness, 0);
1912 stdarg (XmNmarginWidth, 2);
1913 stdarg (XmNmarginHeight, 2);
1914 m_cmd = XmCreateTextField (messages, "command", args, n);
1915 XtAddCallback (m_cmd, XmNactivateCallback,
1916 (XtCallbackProc) command_callback, 0);
1917 XtAddCallback (m_cmd, XmNlosingFocusCallback,
1918 (XtCallbackProc) command_callback, 0);
1919 XtAddEventHandler (m_cmd, KeyPressMask, 0, command_event_handler, 0);
1921 m_mark = make_message ("m_mark", 0, 0);
1922 m_crosshair = make_message ("m_crosshair", m_mark, 0);
1923 m_grid = make_message ("m_grid", m_crosshair, 1);
1924 m_zoom = make_message ("m_zoom", m_grid, 1);
1925 lesstif_m_layer = make_message ("m_layer", m_zoom, 0);
1926 m_mode = make_message ("m_mode", lesstif_m_layer, 1);
1927 m_rats = make_message ("m_rats", m_mode, 1);
1928 m_status = make_message ("m_status", m_mode, 1);
1930 XtUnmanageChild (XtParent (m_mark));
1931 XtUnmanageChild (XtParent (m_rats));
1933 n = 0;
1934 stdarg (XmNrightAttachment, XmATTACH_FORM);
1935 XtSetValues (XtParent (m_status), args, n);
1937 /* We'll use this later. */
1938 n = 0;
1939 stdarg (XmNleftWidget, XtParent (m_mark));
1940 XtSetValues (XtParent (m_crosshair), args, n);
1942 n = 0;
1943 stdarg (XmNmessageWindow, messages);
1944 XtSetValues (mainwind, args, n);
1946 if (background_image_file)
1947 LoadBackgroundImage (background_image_file);
1949 XtRealizeWidget (appwidget);
1951 while (!window)
1953 XEvent e;
1954 XtAppNextEvent (app_context, &e);
1955 XtDispatchEvent (&e);
1958 PCBChanged (0, 0, 0, 0);
1960 XtAppMainLoop (app_context);
1963 #if 0
1964 XrmOptionDescRec lesstif_options[] = {
1967 XtResource lesstif_resources[] = {
1969 #endif
1971 typedef union
1973 int i;
1974 double f;
1975 char *s;
1976 Coord c;
1977 } val_union;
1979 static Boolean
1980 pcb_cvt_string_to_double (Display * d, XrmValue * args, Cardinal * num_args,
1981 XrmValue * from, XrmValue * to, XtPointer * data)
1983 static double rv;
1984 rv = strtod ((char *) from->addr, 0);
1985 if (to->addr)
1986 *(double *) to->addr = rv;
1987 else
1988 to->addr = (XPointer) & rv;
1989 to->size = sizeof (rv);
1990 return True;
1993 static Boolean
1994 pcb_cvt_string_to_coord (Display * d, XrmValue * args, Cardinal * num_args,
1995 XrmValue * from, XrmValue * to, XtPointer *data)
1997 static Coord rv;
1998 rv = GetValue ((char *) from->addr, NULL, NULL);
1999 if (to->addr)
2000 *(Coord *) to->addr = rv;
2001 else
2002 to->addr = (XPointer) &rv;
2003 to->size = sizeof (rv);
2004 return TRUE;
2007 static void
2008 mainwind_delete_cb ()
2010 hid_action ("Quit");
2013 static void
2014 lesstif_listener_cb (XtPointer client_data, int *fid, XtInputId *id)
2016 char buf[BUFSIZ];
2017 int nbytes;
2019 if ((nbytes = read (*fid, buf, BUFSIZ)) == -1)
2020 perror ("lesstif_listener_cb");
2022 if (nbytes)
2024 buf[nbytes] = '\0';
2025 hid_parse_actions (buf);
2029 static void
2030 lesstif_parse_arguments (int *argc, char ***argv)
2032 Atom close_atom;
2033 HID_AttrNode *ha;
2034 int acount = 0, amax;
2035 int rcount = 0, rmax;
2036 int i;
2037 XrmOptionDescRec *new_options;
2038 XtResource *new_resources;
2039 val_union *new_values;
2040 int render_event, render_error;
2042 XtSetTypeConverter (XtRString,
2043 XtRDouble,
2044 pcb_cvt_string_to_double, NULL, 0, XtCacheAll, NULL);
2045 XtSetTypeConverter (XtRString,
2046 XtRPCBCoord,
2047 pcb_cvt_string_to_coord, NULL, 0, XtCacheAll, NULL);
2050 for (ha = hid_attr_nodes; ha; ha = ha->next)
2051 for (i = 0; i < ha->n; i++)
2053 HID_Attribute *a = ha->attributes + i;
2054 switch (a->type)
2056 case HID_Integer:
2057 case HID_Coord:
2058 case HID_Real:
2059 case HID_String:
2060 case HID_Path:
2061 case HID_Boolean:
2062 acount++;
2063 rcount++;
2064 break;
2065 default:
2066 break;
2070 #if 0
2071 amax = acount + XtNumber (lesstif_options);
2072 #else
2073 amax = acount;
2074 #endif
2076 new_options = (XrmOptionDescRec *) malloc ((amax + 1) * sizeof (XrmOptionDescRec));
2078 #if 0
2079 memcpy (new_options + acount, lesstif_options, sizeof (lesstif_options));
2080 #endif
2081 acount = 0;
2083 #if 0
2084 rmax = rcount + XtNumber (lesstif_resources);
2085 #else
2086 rmax = rcount;
2087 #endif
2089 new_resources = (XtResource *) malloc ((rmax + 1) * sizeof (XtResource));
2090 new_values = (val_union *) malloc ((rmax + 1) * sizeof (val_union));
2091 #if 0
2092 memcpy (new_resources + acount, lesstif_resources,
2093 sizeof (lesstif_resources));
2094 #endif
2095 rcount = 0;
2097 for (ha = hid_attr_nodes; ha; ha = ha->next)
2098 for (i = 0; i < ha->n; i++)
2100 HID_Attribute *a = ha->attributes + i;
2101 XrmOptionDescRec *o = new_options + acount;
2102 char *tmpopt, *tmpres;
2103 XtResource *r = new_resources + rcount;
2105 tmpopt = (char *) malloc (strlen (a->name) + 3);
2106 tmpopt[0] = tmpopt[1] = '-';
2107 strcpy (tmpopt + 2, a->name);
2108 o->option = tmpopt;
2110 tmpres = (char *) malloc (strlen (a->name) + 2);
2111 tmpres[0] = '*';
2112 strcpy (tmpres + 1, a->name);
2113 o->specifier = tmpres;
2115 switch (a->type)
2117 case HID_Integer:
2118 case HID_Coord:
2119 case HID_Real:
2120 case HID_String:
2121 case HID_Path:
2122 o->argKind = XrmoptionSepArg;
2123 o->value = 0;
2124 acount++;
2125 break;
2126 case HID_Boolean:
2127 o->argKind = XrmoptionNoArg;
2128 o->value = "True";
2129 acount++;
2130 break;
2131 default:
2132 break;
2135 r->resource_name = a->name;
2136 r->resource_class = a->name;
2137 r->resource_offset = sizeof (val_union) * rcount;
2139 switch (a->type)
2141 case HID_Integer:
2142 r->resource_type = XtRInt;
2143 r->default_type = XtRInt;
2144 r->resource_size = sizeof (int);
2145 r->default_addr = &(a->default_val.int_value);
2146 rcount++;
2147 break;
2148 case HID_Coord:
2149 r->resource_type = XtRPCBCoord;
2150 r->default_type = XtRPCBCoord;
2151 r->resource_size = sizeof (Coord);
2152 r->default_addr = &(a->default_val.coord_value);
2153 rcount++;
2154 break;
2155 case HID_Real:
2156 r->resource_type = XtRDouble;
2157 r->default_type = XtRDouble;
2158 r->resource_size = sizeof (double);
2159 r->default_addr = &(a->default_val.real_value);
2160 rcount++;
2161 break;
2162 case HID_String:
2163 case HID_Path:
2164 r->resource_type = XtRString;
2165 r->default_type = XtRString;
2166 r->resource_size = sizeof (char *);
2167 r->default_addr = (char *) a->default_val.str_value;
2168 rcount++;
2169 break;
2170 case HID_Boolean:
2171 r->resource_type = XtRBoolean;
2172 r->default_type = XtRInt;
2173 r->resource_size = sizeof (int);
2174 r->default_addr = &(a->default_val.int_value);
2175 rcount++;
2176 break;
2177 default:
2178 break;
2181 #if 0
2182 for (i = 0; i < XtNumber (lesstif_resources); i++)
2184 XtResource *r = new_resources + rcount;
2185 r->resource_offset = sizeof (val_union) * rcount;
2186 rcount++;
2188 #endif
2190 n = 0;
2191 stdarg (XmNdeleteResponse, XmDO_NOTHING);
2193 appwidget = XtAppInitialize (&app_context,
2194 "Pcb",
2195 new_options, amax, argc, *argv, 0, args, n);
2197 display = XtDisplay (appwidget);
2198 screen_s = XtScreen (appwidget);
2199 screen = XScreenNumberOfScreen (screen_s);
2200 colormap = XDefaultColormap (display, screen);
2202 close_atom = XmInternAtom (display, "WM_DELETE_WINDOW", 0);
2203 XmAddWMProtocolCallback (appwidget, close_atom,
2204 (XtCallbackProc) mainwind_delete_cb, 0);
2206 /* XSynchronize(display, True); */
2208 XtGetApplicationResources (appwidget, new_values, new_resources,
2209 rmax, 0, 0);
2211 #ifdef HAVE_XRENDER
2212 use_xrender = XRenderQueryExtension (display, &render_event, &render_error) &&
2213 XRenderFindVisualFormat (display, DefaultVisual(display, screen));
2214 #ifdef HAVE_XINERAMA
2215 /* Xinerama and XRender don't get along well */
2216 if (XineramaQueryExtension (display, &render_event, &render_error)
2217 && XineramaIsActive (display))
2218 use_xrender = 0;
2219 #endif /* HAVE_XINERAMA */
2220 #endif /* HAVE_XRENDER */
2222 rcount = 0;
2223 for (ha = hid_attr_nodes; ha; ha = ha->next)
2224 for (i = 0; i < ha->n; i++)
2226 HID_Attribute *a = ha->attributes + i;
2227 val_union *v = new_values + rcount;
2228 switch (a->type)
2230 case HID_Integer:
2231 if (a->value)
2232 *(int *) a->value = v->i;
2233 else
2234 a->default_val.int_value = v->i;
2235 rcount++;
2236 break;
2237 case HID_Coord:
2238 if (a->value)
2239 *(Coord *) a->value = v->c;
2240 else
2241 a->default_val.coord_value = v->c;
2242 rcount++;
2243 break;
2244 case HID_Boolean:
2245 if (a->value)
2246 *(char *) a->value = v->i;
2247 else
2248 a->default_val.int_value = v->i;
2249 rcount++;
2250 break;
2251 case HID_Real:
2252 if (a->value)
2253 *(double *) a->value = v->f;
2254 else
2255 a->default_val.real_value = v->f;
2256 rcount++;
2257 break;
2258 case HID_String:
2259 case HID_Path:
2260 if (a->value)
2261 *(char **) a->value = v->s;
2262 else
2263 a->default_val.str_value = v->s;
2264 rcount++;
2265 break;
2266 default:
2267 break;
2271 /* redefine colormap, if requested via "-install" */
2272 if (use_private_colormap)
2274 colormap = XCopyColormapAndFree (display, colormap);
2275 XtVaSetValues (appwidget, XtNcolormap, colormap, NULL);
2278 /* listen on standard input for actions */
2279 if (stdin_listen)
2281 XtAppAddInput (app_context, fileno (stdin), (XtPointer) XtInputReadMask,
2282 lesstif_listener_cb, NULL);
2286 static void
2287 draw_grid ()
2289 static XPoint *points = 0;
2290 static int npoints = 0;
2291 Coord x1, y1, x2, y2, prevx;
2292 Coord x, y;
2293 int n;
2294 static GC grid_gc = 0;
2296 if (!Settings.DrawGrid)
2297 return;
2298 if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
2299 return;
2300 if (!grid_gc)
2302 grid_gc = XCreateGC (display, window, 0, 0);
2303 XSetFunction (display, grid_gc, GXxor);
2304 XSetForeground (display, grid_gc, grid_color);
2306 if (flip_x)
2308 x2 = GridFit (Px (0), PCB->Grid, PCB->GridOffsetX);
2309 x1 = GridFit (Px (view_width), PCB->Grid, PCB->GridOffsetX);
2310 if (Vx (x2) < 0)
2311 x2 -= PCB->Grid;
2312 if (Vx (x1) >= view_width)
2313 x1 += PCB->Grid;
2315 else
2317 x1 = GridFit (Px (0), PCB->Grid, PCB->GridOffsetX);
2318 x2 = GridFit (Px (view_width), PCB->Grid, PCB->GridOffsetX);
2319 if (Vx (x1) < 0)
2320 x1 += PCB->Grid;
2321 if (Vx (x2) >= view_width)
2322 x2 -= PCB->Grid;
2324 if (flip_y)
2326 y2 = GridFit (Py (0), PCB->Grid, PCB->GridOffsetY);
2327 y1 = GridFit (Py (view_height), PCB->Grid, PCB->GridOffsetY);
2328 if (Vy (y2) < 0)
2329 y2 -= PCB->Grid;
2330 if (Vy (y1) >= view_height)
2331 y1 += PCB->Grid;
2333 else
2335 y1 = GridFit (Py (0), PCB->Grid, PCB->GridOffsetY);
2336 y2 = GridFit (Py (view_height), PCB->Grid, PCB->GridOffsetY);
2337 if (Vy (y1) < 0)
2338 y1 += PCB->Grid;
2339 if (Vy (y2) >= view_height)
2340 y2 -= PCB->Grid;
2342 n = (x2 - x1) / PCB->Grid + 1;
2343 if (n > npoints)
2345 npoints = n + 10;
2346 points = (XPoint *) realloc (points, npoints * sizeof (XPoint));
2348 n = 0;
2349 prevx = 0;
2350 for (x = x1; x <= x2; x += PCB->Grid)
2352 int temp = Vx (x);
2353 points[n].x = temp;
2354 if (n)
2356 points[n].x -= prevx;
2357 points[n].y = 0;
2359 prevx = temp;
2360 n++;
2362 for (y = y1; y <= y2; y += PCB->Grid)
2364 int vy = Vy (y);
2365 points[0].y = vy;
2366 XDrawPoints (display, pixmap, grid_gc, points, n, CoordModePrevious);
2370 static void
2371 mark_delta_to_widget (Coord dx, Coord dy, Widget w)
2373 char *buf;
2374 double g = coord_to_unit (Settings.grid_unit, PCB->Grid);
2375 int prec;
2376 XmString ms;
2378 /* Integer-sized grid? */
2379 if (((int) (g * 10000 + 0.5) % 10000) == 0)
2380 prec = 0;
2381 else
2382 prec = Settings.grid_unit->default_prec;
2384 if (dx == 0 && dy == 0)
2385 buf = pcb_g_strdup_printf ("%m+%+.*mS, %+.*mS", UUNIT, prec, dx, prec, dy);
2386 else
2388 Angle angle = atan2 (dy, -dx) * 180 / M_PI;
2389 Coord dist = Distance (0, 0, dx, dy);
2391 buf = pcb_g_strdup_printf ("%m+%+.*mS, %+.*mS (%.*mS, %d\260)", UUNIT,
2392 prec, dx, prec, dy, prec, dist, angle);
2395 ms = XmStringCreatePCB (buf);
2396 n = 0;
2397 stdarg (XmNlabelString, ms);
2398 XtSetValues (w, args, n);
2399 g_free (buf);
2402 static int
2403 cursor_pos_to_widget (Coord x, Coord y, Widget w, int prev_state)
2405 int this_state = prev_state;
2406 static char *buf;
2407 double g = coord_to_unit (Settings.grid_unit, PCB->Grid);
2408 XmString ms;
2409 int prec;
2411 /* Determine necessary precision (and state) based
2412 * on the user's grid setting */
2413 if (((int) (g * 10000 + 0.5) % 10000) == 0)
2415 prec = 0;
2416 this_state = Settings.grid_unit->allow;
2418 else
2420 prec = Settings.grid_unit->default_prec;
2421 this_state = -Settings.grid_unit->allow;
2424 if (x < 0)
2425 buf = g_strdup ("");
2426 else
2427 buf = pcb_g_strdup_printf ("%m+%.*mS, %.*mS", UUNIT, prec, x, prec, y);
2429 ms = XmStringCreatePCB (buf);
2430 n = 0;
2431 stdarg (XmNlabelString, ms);
2432 XtSetValues (w, args, n);
2433 g_free (buf);
2434 return this_state;
2437 #define S Settings
2439 void
2440 lesstif_update_status_line ()
2442 char *buf = NULL;
2443 char *s45 = cur_clip ();
2444 XmString xs;
2446 switch (Settings.Mode)
2448 case VIA_MODE:
2449 buf = pcb_g_strdup_printf ("%m+%.2mS/%.2mS \370=%.2mS", UUNIT,
2450 S.ViaThickness, S.Keepaway, S.ViaDrillingHole);
2451 break;
2452 case LINE_MODE:
2453 case ARC_MODE:
2454 buf = pcb_g_strdup_printf ("%m+%.2mS/%.2mS %s", UUNIT,
2455 S.LineThickness, S.Keepaway, s45);
2456 break;
2457 case RECTANGLE_MODE:
2458 case POLYGON_MODE:
2459 buf = pcb_g_strdup_printf ("%m+%.2mS %s", UUNIT, S.Keepaway, s45);
2460 break;
2461 case TEXT_MODE:
2462 buf = g_strdup_printf ("%d %%", S.TextScale);
2463 break;
2464 case MOVE_MODE:
2465 case COPY_MODE:
2466 case INSERTPOINT_MODE:
2467 case RUBBERBANDMOVE_MODE:
2468 buf = g_strdup_printf ("%s", s45);
2469 break;
2470 case NO_MODE:
2471 case PASTEBUFFER_MODE:
2472 case ROTATE_MODE:
2473 case REMOVE_MODE:
2474 case THERMAL_MODE:
2475 case ARROW_MODE:
2476 case LOCK_MODE:
2477 default:
2478 buf = g_strdup("");
2479 break;
2482 xs = XmStringCreatePCB (buf);
2483 n = 0;
2484 stdarg (XmNlabelString, xs);
2485 XtSetValues (m_status, args, n);
2486 g_free (buf);
2489 #undef S
2491 static int idle_proc_set = 0;
2492 static int need_redraw = 0;
2494 static Boolean
2495 idle_proc (XtPointer dummy)
2497 if (need_redraw)
2499 int mx, my;
2500 BoxType region;
2501 lesstif_use_mask (HID_MASK_OFF);
2502 pixmap = main_pixmap;
2503 mx = view_width;
2504 my = view_height;
2505 region.X1 = Px (0);
2506 region.Y1 = Py (0);
2507 region.X2 = Px (view_width);
2508 region.Y2 = Py (view_height);
2509 if (flip_x)
2511 Coord tmp = region.X1;
2512 region.X1 = region.X2;
2513 region.X2 = tmp;
2515 if (flip_y)
2517 Coord tmp = region.Y1;
2518 region.Y1 = region.Y2;
2519 region.Y2 = tmp;
2521 XSetForeground (display, bg_gc, bgcolor);
2522 XFillRectangle (display, main_pixmap, bg_gc, 0, 0, mx, my);
2524 if (region.X1 < 0 || region.Y1 < 0
2525 || region.X2 > PCB->MaxWidth || region.Y2 > PCB->MaxHeight)
2527 int leftmost, rightmost, topmost, bottommost;
2529 leftmost = Vx (0);
2530 rightmost = Vx (PCB->MaxWidth);
2531 topmost = Vy (0);
2532 bottommost = Vy (PCB->MaxHeight);
2533 if (leftmost > rightmost) {
2534 int t = leftmost;
2535 leftmost = rightmost;
2536 rightmost = t;
2538 if (topmost > bottommost) {
2539 int t = topmost;
2540 topmost = bottommost;
2541 bottommost = t;
2543 if (leftmost < 0)
2544 leftmost = 0;
2545 if (topmost < 0)
2546 topmost = 0;
2547 if (rightmost > view_width)
2548 rightmost = view_width;
2549 if (bottommost > view_height)
2550 bottommost = view_height;
2552 XSetForeground (display, bg_gc, offlimit_color);
2554 /* L T R
2555 L x R
2556 L B R */
2558 if (leftmost > 0)
2560 XFillRectangle (display, main_pixmap, bg_gc, 0, 0,
2561 leftmost, view_height);
2563 if (rightmost < view_width)
2565 XFillRectangle (display, main_pixmap, bg_gc, rightmost+1, 0,
2566 view_width-rightmost+1, view_height);
2568 if (topmost > 0)
2570 XFillRectangle (display, main_pixmap, bg_gc, leftmost, 0,
2571 rightmost-leftmost+1, topmost);
2573 if (bottommost < view_height)
2575 XFillRectangle (display, main_pixmap, bg_gc, leftmost, bottommost+1,
2576 rightmost-leftmost+1, view_height-bottommost+1);
2579 DrawBackgroundImage();
2580 hid_expose_callback (&lesstif_hid, &region, 0);
2581 draw_grid ();
2582 lesstif_use_mask (HID_MASK_OFF);
2583 show_crosshair (0); /* To keep the drawn / not drawn info correct */
2584 XSetFunction (display, my_gc, GXcopy);
2585 XCopyArea (display, main_pixmap, window, my_gc, 0, 0, view_width,
2586 view_height, 0, 0);
2587 pixmap = window;
2588 if (crosshair_on)
2590 DrawAttached (crosshair_gc);
2591 DrawMark (crosshair_gc);
2593 need_redraw = 0;
2597 static int c_x = -2, c_y = -2;
2598 static MarkType saved_mark;
2599 static const Unit *old_grid_unit = NULL;
2600 if (crosshair_x != c_x || crosshair_y != c_y
2601 || Settings.grid_unit != old_grid_unit
2602 || memcmp (&saved_mark, &Marked, sizeof (MarkType)))
2604 static int last_state = 0;
2605 static int this_state = 0;
2607 c_x = crosshair_x;
2608 c_y = crosshair_y;
2610 this_state =
2611 cursor_pos_to_widget (crosshair_x, crosshair_y, m_crosshair,
2612 this_state);
2613 if (Marked.status)
2614 mark_delta_to_widget (crosshair_x - Marked.X, crosshair_y - Marked.Y,
2615 m_mark);
2617 if (Marked.status != saved_mark.status)
2619 if (Marked.status)
2621 XtManageChild (XtParent (m_mark));
2622 XtManageChild (m_mark);
2623 n = 0;
2624 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
2625 stdarg (XmNleftWidget, XtParent (m_mark));
2626 XtSetValues (XtParent (m_crosshair), args, n);
2628 else
2630 n = 0;
2631 stdarg (XmNleftAttachment, XmATTACH_FORM);
2632 XtSetValues (XtParent (m_crosshair), args, n);
2633 XtUnmanageChild (XtParent (m_mark));
2635 last_state = this_state + 100;
2637 memcpy (&saved_mark, &Marked, sizeof (MarkType));
2639 if (old_grid_unit != Settings.grid_unit)
2641 old_grid_unit = Settings.grid_unit;
2642 /* Force a resize on units change. */
2643 last_state ++;
2646 /* This is obtuse. We want to enable XmRESIZE_ANY long enough
2647 to shrink to fit the new format (if any), then switch it
2648 back to XmRESIZE_GROW to prevent it from shrinking due to
2649 changes in the number of actual digits printed. Thus, when
2650 you switch from a small grid and %.2f formats to a large
2651 grid and %d formats, you aren't punished with a wide and
2652 mostly white-space label widget. "this_state" indicates
2653 which of the above formats we're using. "last_state" is
2654 either zero (when resizing) or the same as "this_state"
2655 (when grow-only), or a non-zero but not "this_state" which
2656 means we need to start a resize cycle. */
2657 if (this_state != last_state && last_state)
2659 n = 0;
2660 stdarg (XmNresizePolicy, XmRESIZE_ANY);
2661 XtSetValues (XtParent (m_mark), args, n);
2662 XtSetValues (XtParent (m_crosshair), args, n);
2663 last_state = 0;
2665 else if (this_state != last_state)
2667 n = 0;
2668 stdarg (XmNresizePolicy, XmRESIZE_GROW);
2669 XtSetValues (XtParent (m_mark), args, n);
2670 XtSetValues (XtParent (m_crosshair), args, n);
2671 last_state = this_state;
2677 static Coord old_grid = -1;
2678 static Coord old_gx, old_gy;
2679 static const Unit *old_unit;
2680 XmString ms;
2681 if (PCB->Grid != old_grid
2682 || PCB->GridOffsetX != old_gx
2683 || PCB->GridOffsetY != old_gy || Settings.grid_unit != old_unit)
2685 static char buf[100];
2686 old_grid = PCB->Grid;
2687 old_unit = Settings.grid_unit;
2688 old_gx = PCB->GridOffsetX;
2689 old_gy = PCB->GridOffsetY;
2690 if (old_grid == 1)
2692 strcpy (buf, "No Grid");
2694 else
2696 if (old_gx || old_gy)
2697 pcb_sprintf (buf, "%m+%$mS @%mS,%mS", UUNIT, old_grid, old_gx, old_gy);
2698 else
2699 pcb_sprintf (buf, "%m+%$mS", UUNIT, old_grid);
2701 ms = XmStringCreatePCB (buf);
2702 n = 0;
2703 stdarg (XmNlabelString, ms);
2704 XtSetValues (m_grid, args, n);
2709 static double old_zoom = -1;
2710 static const Unit *old_grid_unit = NULL;
2711 if (view_zoom != old_zoom || Settings.grid_unit != old_grid_unit)
2713 gchar *buf = pcb_g_strdup_printf ("%m+%$mS/pix",
2714 Settings.grid_unit->allow, (Coord) view_zoom);
2715 XmString ms;
2717 old_zoom = view_zoom;
2718 old_grid_unit = Settings.grid_unit;
2720 ms = XmStringCreatePCB (buf);
2721 n = 0;
2722 stdarg (XmNlabelString, ms);
2723 XtSetValues (m_zoom, args, n);
2724 g_free (buf);
2729 if (old_cursor_mode != Settings.Mode)
2731 char *s = "None";
2732 XmString ms;
2733 int cursor = -1;
2734 static int free_cursor = 0;
2736 old_cursor_mode = Settings.Mode;
2737 switch (Settings.Mode)
2739 case NO_MODE:
2740 s = "None";
2741 cursor = XC_X_cursor;
2742 break;
2743 case VIA_MODE:
2744 s = "Via";
2745 cursor = -1;
2746 break;
2747 case LINE_MODE:
2748 s = "Line";
2749 cursor = XC_pencil;
2750 break;
2751 case RECTANGLE_MODE:
2752 s = "Rectangle";
2753 cursor = XC_ul_angle;
2754 break;
2755 case POLYGON_MODE:
2756 s = "Polygon";
2757 cursor = XC_sb_up_arrow;
2758 break;
2759 case POLYGONHOLE_MODE:
2760 s = "Polygon Hole";
2761 cursor = XC_sb_up_arrow;
2762 break;
2763 case PASTEBUFFER_MODE:
2764 s = "Paste";
2765 cursor = XC_hand1;
2766 break;
2767 case TEXT_MODE:
2768 s = "Text";
2769 cursor = XC_xterm;
2770 break;
2771 case ROTATE_MODE:
2772 s = "Rotate";
2773 cursor = XC_exchange;
2774 break;
2775 case REMOVE_MODE:
2776 s = "Remove";
2777 cursor = XC_pirate;
2778 break;
2779 case MOVE_MODE:
2780 s = "Move";
2781 cursor = XC_crosshair;
2782 break;
2783 case COPY_MODE:
2784 s = "Copy";
2785 cursor = XC_crosshair;
2786 break;
2787 case INSERTPOINT_MODE:
2788 s = "Insert";
2789 cursor = XC_dotbox;
2790 break;
2791 case RUBBERBANDMOVE_MODE:
2792 s = "RBMove";
2793 cursor = XC_top_left_corner;
2794 break;
2795 case THERMAL_MODE:
2796 s = "Thermal";
2797 cursor = XC_iron_cross;
2798 break;
2799 case ARC_MODE:
2800 s = "Arc";
2801 cursor = XC_question_arrow;
2802 break;
2803 case ARROW_MODE:
2804 s = "Arrow";
2805 if (over_point)
2806 cursor = XC_draped_box;
2807 else
2808 cursor = XC_left_ptr;
2809 break;
2810 case LOCK_MODE:
2811 s = "Lock";
2812 cursor = XC_hand2;
2813 break;
2815 ms = XmStringCreatePCB (s);
2816 n = 0;
2817 stdarg (XmNlabelString, ms);
2818 XtSetValues (m_mode, args, n);
2820 if (free_cursor)
2822 XFreeCursor (display, my_cursor);
2823 free_cursor = 0;
2825 if (cursor == -1)
2827 static Pixmap nocur_source = 0;
2828 static Pixmap nocur_mask = 0;
2829 static Cursor nocursor = 0;
2830 if (nocur_source == 0)
2832 XColor fg, bg;
2833 nocur_source =
2834 XCreateBitmapFromData (display, window, "\0", 1, 1);
2835 nocur_mask =
2836 XCreateBitmapFromData (display, window, "\0", 1, 1);
2838 fg.red = fg.green = fg.blue = 65535;
2839 bg.red = bg.green = bg.blue = 0;
2840 fg.flags = bg.flags = DoRed | DoGreen | DoBlue;
2841 nocursor = XCreatePixmapCursor (display, nocur_source,
2842 nocur_mask, &fg, &bg, 0, 0);
2844 my_cursor = nocursor;
2846 else
2848 my_cursor = XCreateFontCursor (display, cursor);
2849 free_cursor = 1;
2851 XDefineCursor (display, window, my_cursor);
2852 lesstif_update_status_line ();
2856 static char *old_clip = 0;
2857 static int old_tscale = -1;
2858 char *new_clip = cur_clip ();
2860 if (new_clip != old_clip || Settings.TextScale != old_tscale)
2862 lesstif_update_status_line ();
2863 old_clip = new_clip;
2864 old_tscale = Settings.TextScale;
2869 static int old_nrats = -1;
2870 static char buf[20];
2872 if (old_nrats != PCB->Data->RatN)
2874 old_nrats = PCB->Data->RatN;
2875 sprintf(buf, "%d rat%s", PCB->Data->RatN, PCB->Data->RatN == 1 ? "" : "s");
2876 if (PCB->Data->RatN)
2878 XtManageChild(XtParent(m_rats));
2879 XtManageChild(m_rats);
2880 n = 0;
2881 stdarg (XmNleftWidget, m_rats);
2882 XtSetValues (XtParent (m_status), args, n);
2885 n = 0;
2886 stdarg (XmNlabelString, XmStringCreatePCB (buf));
2887 XtSetValues (m_rats, args, n);
2889 if (!PCB->Data->RatN)
2891 n = 0;
2892 stdarg (XmNleftWidget, m_mode);
2893 XtSetValues (XtParent (m_status), args, n);
2894 XtUnmanageChild(XtParent(m_rats));
2899 lesstif_update_widget_flags ();
2901 show_crosshair (1);
2902 idle_proc_set = 0;
2903 return True;
2906 void
2907 lesstif_need_idle_proc ()
2909 if (idle_proc_set || window == 0)
2910 return;
2911 XtAppAddWorkProc (app_context, idle_proc, 0);
2912 idle_proc_set = 1;
2915 static void
2916 lesstif_invalidate_lr (int l, int r, int t, int b)
2918 if (!window)
2919 return;
2921 need_redraw = 1;
2922 need_idle_proc ();
2925 void
2926 lesstif_invalidate_all (void)
2928 lesstif_invalidate_lr (0, PCB->MaxWidth, 0, PCB->MaxHeight);
2931 static void
2932 lesstif_notify_crosshair_change (bool changes_complete)
2934 static int invalidate_depth = 0;
2935 Pixmap save_pixmap;
2937 if (! my_gc)
2938 return;
2940 if (changes_complete)
2941 invalidate_depth --;
2943 if (invalidate_depth < 0)
2945 invalidate_depth = 0;
2946 /* A mismatch of changes_complete == false and == true notifications
2947 * is not expected to occur, but we will try to handle it gracefully.
2948 * As we know the crosshair will have been shown already, we must
2949 * repaint the entire view to be sure not to leave an artaefact.
2951 need_idle_proc ();
2952 return;
2955 if (invalidate_depth == 0 && crosshair_on)
2957 save_pixmap = pixmap;
2958 pixmap = window;
2959 DrawAttached (crosshair_gc);
2960 pixmap = save_pixmap;
2963 if (!changes_complete)
2964 invalidate_depth ++;
2967 static void
2968 lesstif_notify_mark_change (bool changes_complete)
2970 static int invalidate_depth = 0;
2971 Pixmap save_pixmap;
2973 if (changes_complete)
2974 invalidate_depth --;
2976 if (invalidate_depth < 0)
2978 invalidate_depth = 0;
2979 /* A mismatch of changes_complete == false and == true notifications
2980 * is not expected to occur, but we will try to handle it gracefully.
2981 * As we know the mark will have been shown already, we must
2982 * repaint the entire view to be sure not to leave an artaefact.
2984 need_idle_proc ();
2985 return;
2988 if (invalidate_depth == 0 && crosshair_on)
2990 save_pixmap = pixmap;
2991 pixmap = window;
2992 DrawMark (crosshair_gc);
2993 pixmap = save_pixmap;
2996 if (!changes_complete)
2997 invalidate_depth ++;
3000 static int
3001 lesstif_set_layer (const char *name, int group, int empty)
3003 int idx = group;
3004 if (idx >= 0 && idx < max_group)
3006 int n = PCB->LayerGroups.Number[group];
3007 for (idx = 0; idx < n-1; idx ++)
3009 int ni = PCB->LayerGroups.Entries[group][idx];
3010 if (ni >= 0 && ni < max_copper_layer + 2
3011 && PCB->Data->Layer[ni].On)
3012 break;
3014 idx = PCB->LayerGroups.Entries[group][idx];
3015 #if 0
3016 if (idx == LayerStack[0]
3017 || GetLayerGroupNumberByNumber (idx) ==
3018 GetLayerGroupNumberByNumber (LayerStack[0]))
3019 autofade = 0;
3020 else
3021 autofade = 1;
3022 #endif
3024 #if 0
3025 else
3026 autofade = 0;
3027 #endif
3028 if (idx >= 0 && idx < max_copper_layer + 2)
3029 return pinout ? 1 : PCB->Data->Layer[idx].On;
3030 if (idx < 0)
3032 switch (SL_TYPE (idx))
3034 case SL_INVISIBLE:
3035 return pinout ? 0 : PCB->InvisibleObjectsOn;
3036 case SL_MASK:
3037 if (SL_MYSIDE (idx) && !pinout)
3038 return TEST_FLAG (SHOWMASKFLAG, PCB);
3039 return 0;
3040 case SL_SILK:
3041 if (SL_MYSIDE (idx) || pinout)
3042 return PCB->ElementOn;
3043 return 0;
3044 case SL_ASSY:
3045 return 0;
3046 case SL_UDRILL:
3047 case SL_PDRILL:
3048 return 1;
3049 case SL_RATS:
3050 return PCB->RatOn;
3053 return 0;
3056 static hidGC
3057 lesstif_make_gc (void)
3059 hidGC rv = (hid_gc_struct *) malloc (sizeof (hid_gc_struct));
3060 memset (rv, 0, sizeof (hid_gc_struct));
3061 rv->me_pointer = &lesstif_hid;
3062 return rv;
3065 static void
3066 lesstif_destroy_gc (hidGC gc)
3068 free (gc);
3071 static void
3072 lesstif_use_mask (enum mask_mode mode)
3074 if ((TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) &&
3075 !use_xrender)
3076 mode = HID_MASK_OFF;
3077 if ((mode == HID_MASK_OFF) == (use_mask == HID_MASK_OFF))
3078 return;
3079 use_mask = mode;
3080 if (pinout)
3081 return;
3082 if (!window)
3083 return;
3084 /* printf("use_mask(%d)\n", use_it); */
3085 if (!mask_pixmap)
3087 mask_pixmap =
3088 XCreatePixmap (display, window, pixmap_w, pixmap_h,
3089 XDefaultDepth (display, screen));
3090 mask_bitmap = XCreatePixmap (display, window, pixmap_w, pixmap_h, 1);
3092 if (mode != HID_MASK_OFF)
3094 pixmap = mask_pixmap;
3095 XSetForeground (display, my_gc, 0);
3096 XSetFunction (display, my_gc, GXcopy);
3097 XFillRectangle (display, mask_pixmap, my_gc,
3098 0, 0, view_width, view_height);
3099 XFillRectangle (display, mask_bitmap, bclear_gc,
3100 0, 0, view_width, view_height);
3102 else
3104 pixmap = main_pixmap;
3105 #ifdef HAVE_XRENDER
3106 if (use_xrender)
3108 XRenderPictureAttributes pa;
3110 pa.clip_mask = mask_bitmap;
3111 XRenderChangePicture(display, main_picture, CPClipMask, &pa);
3112 XRenderComposite(display, PictOpOver, mask_picture, pale_picture,
3113 main_picture, 0, 0, 0, 0, 0, 0, view_width, view_height);
3115 else
3116 #endif /* HAVE_XRENDER */
3118 XSetClipMask (display, clip_gc, mask_bitmap);
3119 XCopyArea (display, mask_pixmap, main_pixmap, clip_gc,
3120 0, 0, view_width, view_height, 0, 0);
3125 static void
3126 lesstif_set_color (hidGC gc, const char *name)
3128 static void *cache = 0;
3129 hidval cval;
3130 static XColor color, exact_color;
3132 if (!display)
3133 return;
3134 if (!name)
3135 name = "red";
3136 gc->colorname = name;
3137 if (strcmp (name, "erase") == 0)
3139 gc->color = bgcolor;
3140 gc->erase = 1;
3142 else if (strcmp (name, "drill") == 0)
3144 gc->color = offlimit_color;
3145 gc->erase = 0;
3147 else if (hid_cache_color (0, name, &cval, &cache))
3149 gc->color = cval.lval;
3150 gc->erase = 0;
3152 else
3154 if (!XAllocNamedColor (display, colormap, name, &color, &exact_color))
3155 color.pixel = WhitePixel (display, screen);
3156 #if 0
3157 printf ("lesstif_set_color `%s' %08x rgb/%d/%d/%d\n",
3158 name, color.pixel, color.red, color.green, color.blue);
3159 #endif
3160 cval.lval = gc->color = color.pixel;
3161 hid_cache_color (1, name, &cval, &cache);
3162 gc->erase = 0;
3164 if (autofade)
3166 static int lastcolor = -1, lastfade = -1;
3167 if (gc->color == lastcolor)
3168 gc->color = lastfade;
3169 else
3171 lastcolor = gc->color;
3172 color.pixel = gc->color;
3174 XQueryColor (display, colormap, &color);
3175 color.red = (bgred + color.red) / 2;
3176 color.green = (bggreen + color.green) / 2;
3177 color.blue = (bgblue + color.blue) / 2;
3178 XAllocColor (display, colormap, &color);
3179 lastfade = gc->color = color.pixel;
3184 static void
3185 set_gc (hidGC gc)
3187 int cap, join, width;
3188 if (gc->me_pointer != &lesstif_hid)
3190 fprintf (stderr, "Fatal: GC from another HID passed to lesstif HID\n");
3191 abort ();
3193 #if 0
3194 pcb_printf ("set_gc c%s %08lx w%#mS c%d x%d e%d\n",
3195 gc->colorname, gc->color, gc->width, gc->cap, gc->xor_set, gc->erase);
3196 #endif
3197 switch (gc->cap)
3199 case Square_Cap:
3200 cap = CapProjecting;
3201 join = JoinMiter;
3202 break;
3203 case Trace_Cap:
3204 case Round_Cap:
3205 cap = CapRound;
3206 join = JoinRound;
3207 break;
3208 case Beveled_Cap:
3209 cap = CapProjecting;
3210 join = JoinBevel;
3211 break;
3212 default:
3213 cap = CapProjecting;
3214 join = JoinBevel;
3215 break;
3217 if (gc->xor_set)
3219 XSetFunction (display, my_gc, GXxor);
3220 XSetForeground (display, my_gc, gc->color ^ bgcolor);
3222 else if (gc->erase)
3224 XSetFunction (display, my_gc, GXcopy);
3225 XSetForeground (display, my_gc, offlimit_color);
3227 else
3229 XSetFunction (display, my_gc, GXcopy);
3230 XSetForeground (display, my_gc, gc->color);
3232 width = Vz (gc->width);
3233 if (width < 0)
3234 width = 0;
3235 XSetLineAttributes (display, my_gc, width, LineSolid, cap,
3236 join);
3237 if (use_mask)
3239 if (gc->erase)
3240 mask_gc = bclear_gc;
3241 else
3242 mask_gc = bset_gc;
3243 XSetLineAttributes (display, mask_gc, Vz (gc->width), LineSolid, cap,
3244 join);
3248 static void
3249 lesstif_set_line_cap (hidGC gc, EndCapStyle style)
3251 gc->cap = style;
3254 static void
3255 lesstif_set_line_width (hidGC gc, Coord width)
3257 gc->width = width;
3260 static void
3261 lesstif_set_draw_xor (hidGC gc, int xor_set)
3263 gc->xor_set = xor_set;
3266 #define ISORT(a,b) if (a>b) { a^=b; b^=a; a^=b; }
3268 static void
3269 lesstif_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
3271 double dx1, dy1, dx2, dy2;
3272 int vw = Vz (gc->width);
3273 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) && gc->erase)
3274 return;
3275 #if 0
3276 pcb_printf ("draw_line %#mD-%#mD @%#mS", x1, y1, x2, y2, gc->width);
3277 #endif
3278 dx1 = Vx (x1);
3279 dy1 = Vy (y1);
3280 dx2 = Vx (x2);
3281 dy2 = Vy (y2);
3282 #if 0
3283 pcb_printf (" = %#mD-%#mD %s\n", x1, y1, x2, y2, gc->colorname);
3284 #endif
3286 #if 1
3287 if (! ClipLine (0, 0, view_width, view_height,
3288 &dx1, &dy1, &dx2, &dy2, vw))
3289 return;
3290 #endif
3292 x1 = dx1;
3293 y1 = dy1;
3294 x2 = dx2;
3295 y2 = dy2;
3297 set_gc (gc);
3298 if (gc->cap == Square_Cap && x1 == x2 && y1 == y2)
3300 XFillRectangle (display, pixmap, my_gc, x1 - vw / 2, y1 - vw / 2, vw,
3301 vw);
3302 if (use_mask)
3303 XFillRectangle (display, mask_bitmap, mask_gc, x1 - vw / 2,
3304 y1 - vw / 2, vw, vw);
3306 else
3308 XDrawLine (display, pixmap, my_gc, x1, y1, x2, y2);
3309 if (use_mask)
3310 XDrawLine (display, mask_bitmap, mask_gc, x1, y1, x2, y2);
3314 static void
3315 lesstif_draw_arc (hidGC gc, Coord cx, Coord cy, Coord width, Coord height,
3316 Angle start_angle, Angle delta_angle)
3318 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase)
3319 return;
3320 #if 0
3321 pcb_printf ("draw_arc %#mD %#mSx%#mS s %d d %d", cx, cy, width, height, start_angle, delta_angle);
3322 #endif
3323 width = Vz (width);
3324 height = Vz (height);
3325 cx = Vx (cx) - width;
3326 cy = Vy (cy) - height;
3327 if (flip_x)
3329 start_angle = 180 - start_angle;
3330 delta_angle = - delta_angle;
3332 if (flip_y)
3334 start_angle = - start_angle;
3335 delta_angle = - delta_angle;
3337 start_angle = NormalizeAngle (start_angle);
3338 if (start_angle >= 180)
3339 start_angle -= 360;
3340 #if 0
3341 pcb_printf (" = %#mD %#mSx%#mS %d %s\n", cx, cy, width, height, gc->width,
3342 gc->colorname);
3343 #endif
3344 set_gc (gc);
3345 XDrawArc (display, pixmap, my_gc, cx, cy,
3346 width * 2, height * 2, (start_angle + 180) * 64,
3347 delta_angle * 64);
3348 if (use_mask && !TEST_FLAG (THINDRAWFLAG, PCB))
3349 XDrawArc (display, mask_bitmap, mask_gc, cx, cy,
3350 width * 2, height * 2, (start_angle + 180) * 64,
3351 delta_angle * 64);
3352 #if 0
3353 /* Enable this if you want to see the center and radii of drawn
3354 arcs, for debugging. */
3355 if (TEST_FLAG (THINDRAWFLAG, PCB)
3356 && delta_angle != 360)
3358 cx += width;
3359 cy += height;
3360 XDrawLine (display, pixmap, arc1_gc, cx, cy,
3361 cx - width*cos(start_angle*M_PI/180),
3362 cy + width*sin(start_angle*M_PI/180));
3363 XDrawLine (display, pixmap, arc2_gc, cx, cy,
3364 cx - width*cos((start_angle+delta_angle)*M_PI/180),
3365 cy + width*sin((start_angle+delta_angle)*M_PI/180));
3367 #endif
3370 static void
3371 lesstif_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
3373 int vw = Vz (gc->width);
3374 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase)
3375 return;
3376 x1 = Vx (x1);
3377 y1 = Vy (y1);
3378 x2 = Vx (x2);
3379 y2 = Vy (y2);
3380 if (x1 < -vw && x2 < -vw)
3381 return;
3382 if (y1 < -vw && y2 < -vw)
3383 return;
3384 if (x1 > view_width + vw && x2 > view_width + vw)
3385 return;
3386 if (y1 > view_height + vw && y2 > view_height + vw)
3387 return;
3388 if (x1 > x2) { int xt = x1; x1 = x2; x2 = xt; }
3389 if (y1 > y2) { int yt = y1; y1 = y2; y2 = yt; }
3390 set_gc (gc);
3391 XDrawRectangle (display, pixmap, my_gc, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
3392 if (use_mask)
3393 XDrawRectangle (display, mask_bitmap, mask_gc, x1, y1, x2 - x1 + 1,
3394 y2 - y1 + 1);
3397 static void
3398 lesstif_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius)
3400 if (pinout && use_mask && gc->erase)
3401 return;
3402 if ((TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) && gc->erase)
3403 return;
3404 #if 0
3405 pcb_printf ("fill_circle %#mD %#mS", cx, cy, radius);
3406 #endif
3407 radius = Vz (radius);
3408 cx = Vx (cx) - radius;
3409 cy = Vy (cy) - radius;
3410 if (cx < -2 * radius || cx > view_width)
3411 return;
3412 if (cy < -2 * radius || cy > view_height)
3413 return;
3414 #if 0
3415 pcb_printf (" = %#mD %#mS %lx %s\n", cx, cy, radius, gc->color, gc->colorname);
3416 #endif
3417 set_gc (gc);
3418 XFillArc (display, pixmap, my_gc, cx, cy,
3419 radius * 2, radius * 2, 0, 360 * 64);
3420 if (use_mask)
3421 XFillArc (display, mask_bitmap, mask_gc, cx, cy,
3422 radius * 2, radius * 2, 0, 360 * 64);
3425 static void
3426 lesstif_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y)
3428 static XPoint *p = 0;
3429 static int maxp = 0;
3430 int i;
3432 if (maxp < n_coords)
3434 maxp = n_coords + 10;
3435 if (p)
3436 p = (XPoint *) realloc (p, maxp * sizeof (XPoint));
3437 else
3438 p = (XPoint *) malloc (maxp * sizeof (XPoint));
3441 for (i = 0; i < n_coords; i++)
3443 p[i].x = Vx (x[i]);
3444 p[i].y = Vy (y[i]);
3446 #if 0
3447 printf ("fill_polygon %d pts\n", n_coords);
3448 #endif
3449 set_gc (gc);
3450 XFillPolygon (display, pixmap, my_gc, p, n_coords, Complex,
3451 CoordModeOrigin);
3452 if (use_mask)
3453 XFillPolygon (display, mask_bitmap, mask_gc, p, n_coords, Complex,
3454 CoordModeOrigin);
3457 static void
3458 lesstif_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
3460 int vw = Vz (gc->width);
3461 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase)
3462 return;
3463 x1 = Vx (x1);
3464 y1 = Vy (y1);
3465 x2 = Vx (x2);
3466 y2 = Vy (y2);
3467 if (x1 < -vw && x2 < -vw)
3468 return;
3469 if (y1 < -vw && y2 < -vw)
3470 return;
3471 if (x1 > view_width + vw && x2 > view_width + vw)
3472 return;
3473 if (y1 > view_height + vw && y2 > view_height + vw)
3474 return;
3475 if (x1 > x2) { int xt = x1; x1 = x2; x2 = xt; }
3476 if (y1 > y2) { int yt = y1; y1 = y2; y2 = yt; }
3477 set_gc (gc);
3478 XFillRectangle (display, pixmap, my_gc, x1, y1, x2 - x1 + 1,
3479 y2 - y1 + 1);
3480 if (use_mask)
3481 XFillRectangle (display, mask_bitmap, mask_gc, x1, y1, x2 - x1 + 1,
3482 y2 - y1 + 1);
3485 static void
3486 lesstif_calibrate (double xval, double yval)
3488 CRASH;
3491 static int
3492 lesstif_shift_is_pressed (void)
3494 return shift_pressed;
3497 static int
3498 lesstif_control_is_pressed (void)
3500 return ctrl_pressed;
3503 static int
3504 lesstif_mod1_is_pressed (void)
3506 return alt_pressed;
3509 extern void lesstif_get_coords (const char *msg, Coord *x, Coord *y);
3511 static void
3512 lesstif_set_crosshair (int x, int y, int action)
3514 if (crosshair_x != x || crosshair_y != y)
3516 lesstif_show_crosshair(0);
3517 crosshair_x = x;
3518 crosshair_y = y;
3519 need_idle_proc ();
3521 if (mainwind
3522 && !in_move_event
3523 && (x < view_left_x
3524 || x > view_left_x + view_width * view_zoom
3525 || y < view_top_y || y > view_top_y + view_height * view_zoom))
3527 view_left_x = x - (view_width * view_zoom) / 2;
3528 view_top_y = y - (view_height * view_zoom) / 2;
3529 lesstif_pan_fixup ();
3534 if (action == HID_SC_PAN_VIEWPORT)
3536 Window root, child;
3537 unsigned int keys_buttons;
3538 int pos_x, pos_y, root_x, root_y;
3539 XQueryPointer (display, window, &root, &child,
3540 &root_x, &root_y, &pos_x, &pos_y, &keys_buttons);
3541 if (flip_x)
3542 view_left_x = x - (view_width-pos_x) * view_zoom;
3543 else
3544 view_left_x = x - pos_x * view_zoom;
3545 if (flip_y)
3546 view_top_y = y - (view_height-pos_y) * view_zoom;
3547 else
3548 view_top_y = y - pos_y * view_zoom;
3549 lesstif_pan_fixup();
3550 action = HID_SC_WARP_POINTER;
3552 if (action == HID_SC_WARP_POINTER)
3554 in_move_event ++;
3555 XWarpPointer (display, None, window, 0, 0, 0, 0, Vx(x), Vy(y));
3556 in_move_event --;
3560 typedef struct
3562 void (*func) (hidval);
3563 hidval user_data;
3564 XtIntervalId id;
3565 } TimerStruct;
3567 static void
3568 lesstif_timer_cb (XtPointer * p, XtIntervalId * id)
3570 TimerStruct *ts = (TimerStruct *) p;
3571 ts->func (ts->user_data);
3572 free (ts);
3575 static hidval
3576 lesstif_add_timer (void (*func) (hidval user_data),
3577 unsigned long milliseconds, hidval user_data)
3579 TimerStruct *t;
3580 hidval rv;
3581 t = (TimerStruct *) malloc (sizeof (TimerStruct));
3582 rv.ptr = t;
3583 t->func = func;
3584 t->user_data = user_data;
3585 t->id = XtAppAddTimeOut (app_context, milliseconds, (XtTimerCallbackProc)lesstif_timer_cb, t);
3586 return rv;
3589 static void
3590 lesstif_stop_timer (hidval hv)
3592 TimerStruct *ts = (TimerStruct *) hv.ptr;
3593 XtRemoveTimeOut (ts->id);
3594 free (ts);
3598 typedef struct
3600 void (*func) ( hidval, int, unsigned int, hidval );
3601 hidval user_data;
3602 int fd;
3603 XtInputId id;
3605 WatchStruct;
3607 /* We need a wrapper around the hid file watch because to pass the correct flags
3609 static void
3610 lesstif_watch_cb (XtPointer client_data, int *fid, XtInputId * id)
3612 unsigned int pcb_condition = 0;
3613 struct pollfd fds;
3614 short condition;
3615 hidval x;
3616 WatchStruct *watch = (WatchStruct*)client_data;
3618 fds.fd = watch->fd;
3619 fds.events = POLLIN | POLLOUT;
3620 poll( &fds, 1, 0 );
3621 condition = fds.revents;
3623 // Should we only include those we were asked to watch?
3624 if (condition & POLLIN)
3625 pcb_condition |= PCB_WATCH_READABLE;
3626 if (condition & POLLOUT)
3627 pcb_condition |= PCB_WATCH_WRITABLE;
3628 if (condition & POLLERR)
3629 pcb_condition |= PCB_WATCH_ERROR;
3630 if (condition & POLLHUP)
3631 pcb_condition |= PCB_WATCH_HANGUP;
3633 x.ptr = (void *) watch;
3634 watch->func (x, watch->fd, pcb_condition, watch->user_data);
3636 return;
3639 hidval
3640 lesstif_watch_file (int fd, unsigned int condition, void (*func) (hidval watch, int fd, unsigned int condition, hidval user_data),
3641 hidval user_data)
3643 WatchStruct *watch = (WatchStruct *) malloc (sizeof(WatchStruct));
3644 hidval ret;
3645 unsigned int xt_condition = 0;
3647 if (condition & PCB_WATCH_READABLE)
3648 xt_condition |= XtInputReadMask;
3649 if (condition & PCB_WATCH_WRITABLE)
3650 xt_condition |= XtInputWriteMask;
3651 if (condition & PCB_WATCH_ERROR)
3652 xt_condition |= XtInputExceptMask;
3653 if (condition & PCB_WATCH_HANGUP)
3654 xt_condition |= XtInputExceptMask;
3656 watch->func = func;
3657 watch->user_data = user_data;
3658 watch->fd = fd;
3659 watch->id = XtAppAddInput( app_context, fd, (XtPointer) (size_t) xt_condition, lesstif_watch_cb, watch );
3661 ret.ptr = (void *) watch;
3662 return ret;
3665 void
3666 lesstif_unwatch_file (hidval data)
3668 WatchStruct *watch = (WatchStruct*)data.ptr;
3669 XtRemoveInput( watch->id );
3670 free( watch );
3673 typedef struct
3675 XtBlockHookId id;
3676 void (*func) (hidval user_data);
3677 hidval user_data;
3678 } BlockHookStruct;
3680 static void lesstif_block_hook_cb(XtPointer user_data);
3682 static void
3683 lesstif_block_hook_cb (XtPointer user_data)
3685 BlockHookStruct *block_hook = (BlockHookStruct *)user_data;
3686 block_hook->func( block_hook->user_data );
3689 static hidval
3690 lesstif_add_block_hook (void (*func) (hidval data), hidval user_data )
3692 hidval ret;
3693 BlockHookStruct *block_hook = (BlockHookStruct *) malloc( sizeof( BlockHookStruct ));
3695 block_hook->func = func;
3696 block_hook->user_data = user_data;
3698 block_hook->id = XtAppAddBlockHook( app_context, lesstif_block_hook_cb, (XtPointer)block_hook );
3700 ret.ptr = (void *) block_hook;
3701 return ret;
3704 static void
3705 lesstif_stop_block_hook (hidval mlpoll)
3707 BlockHookStruct *block_hook = (BlockHookStruct *)mlpoll.ptr;
3708 XtRemoveBlockHook( block_hook->id );
3709 free( block_hook );
3713 extern void lesstif_logv (const char *fmt, va_list ap);
3715 extern int lesstif_confirm_dialog (char *msg, ...);
3717 extern int lesstif_close_confirm_dialog ();
3719 extern void lesstif_report_dialog (char *title, char *msg);
3721 extern int
3722 lesstif_attribute_dialog (HID_Attribute * attrs,
3723 int n_attrs, HID_Attr_Val * results,
3724 const char * title, const char * descr);
3726 static void
3727 pinout_callback (Widget da, PinoutData * pd,
3728 XmDrawingAreaCallbackStruct * cbs)
3730 BoxType region;
3731 int save_vx, save_vy, save_vw, save_vh;
3732 int save_fx, save_fy;
3733 double save_vz;
3734 Pixmap save_px;
3735 int reason = cbs ? cbs->reason : 0;
3737 if (pd->window == 0 && reason == XmCR_RESIZE)
3738 return;
3739 if (pd->window == 0 || reason == XmCR_RESIZE)
3741 Dimension w, h;
3742 double z;
3744 n = 0;
3745 stdarg (XmNwidth, &w);
3746 stdarg (XmNheight, &h);
3747 XtGetValues (da, args, n);
3749 pd->window = XtWindow (da);
3750 pd->v_width = w;
3751 pd->v_height = h;
3752 pd->zoom = (pd->right - pd->left + 1) / (double) w;
3753 z = (pd->bottom - pd->top + 1) / (double) h;
3754 if (pd->zoom < z)
3755 pd->zoom = z;
3757 pd->x = (pd->left + pd->right) / 2 - pd->v_width * pd->zoom / 2;
3758 pd->y = (pd->top + pd->bottom) / 2 - pd->v_height * pd->zoom / 2;
3761 save_vx = view_left_x;
3762 save_vy = view_top_y;
3763 save_vz = view_zoom;
3764 save_vw = view_width;
3765 save_vh = view_height;
3766 save_fx = flip_x;
3767 save_fy = flip_y;
3768 save_px = pixmap;
3769 pinout = pd;
3770 pixmap = pd->window;
3771 view_left_x = pd->x;
3772 view_top_y = pd->y;
3773 view_zoom = pd->zoom;
3774 view_width = pd->v_width;
3775 view_height = pd->v_height;
3776 use_mask = 0;
3777 flip_x = flip_y = 0;
3779 region.X1 = 0;
3780 region.Y1 = 0;
3781 region.X2 = PCB->MaxWidth;
3782 region.Y2 = PCB->MaxHeight;
3784 XFillRectangle (display, pixmap, bg_gc, 0, 0, pd->v_width, pd->v_height);
3785 hid_expose_callback (&lesstif_hid, &region, pd->item);
3787 pinout = 0;
3788 view_left_x = save_vx;
3789 view_top_y = save_vy;
3790 view_zoom = save_vz;
3791 view_width = save_vw;
3792 view_height = save_vh;
3793 pixmap = save_px;
3794 flip_x = save_fx;
3795 flip_y = save_fy;
3798 static void
3799 pinout_unmap (Widget w, PinoutData * pd, void *v)
3801 if (pd->prev)
3802 pd->prev->next = pd->next;
3803 else
3804 pinouts = pd->next;
3805 if (pd->next)
3806 pd->next->prev = pd->prev;
3807 XtDestroyWidget (XtParent (pd->form));
3808 free (pd);
3811 static void
3812 lesstif_show_item (void *item)
3814 double scale;
3815 Widget da;
3816 BoxType *extents;
3817 PinoutData *pd;
3819 for (pd = pinouts; pd; pd = pd->next)
3820 if (pd->item == item)
3821 return;
3822 if (!mainwind)
3823 return;
3825 pd = (PinoutData *) calloc (1, sizeof (PinoutData));
3827 pd->item = item;
3829 extents = hid_get_extents (item);
3830 pd->left = extents->X1;
3831 pd->right = extents->X2;
3832 pd->top = extents->Y1;
3833 pd->bottom = extents->Y2;
3835 if (pd->left > pd->right)
3837 free (pd);
3838 return;
3840 pd->prev = 0;
3841 pd->next = pinouts;
3842 if (pd->next)
3843 pd->next->prev = pd;
3844 pinouts = pd;
3845 pd->zoom = 0;
3847 n = 0;
3848 pd->form = XmCreateFormDialog (mainwind, "pinout", args, n);
3849 pd->window = 0;
3850 XtAddCallback (pd->form, XmNunmapCallback, (XtCallbackProc) pinout_unmap,
3851 (XtPointer) pd);
3853 scale =
3854 sqrt (200.0 * 200.0 /
3855 ((pd->right - pd->left + 1.0) * (pd->bottom - pd->top + 1.0)));
3857 n = 0;
3858 stdarg (XmNwidth, (int) (scale * (pd->right - pd->left + 1)));
3859 stdarg (XmNheight, (int) (scale * (pd->bottom - pd->top + 1)));
3860 stdarg (XmNleftAttachment, XmATTACH_FORM);
3861 stdarg (XmNrightAttachment, XmATTACH_FORM);
3862 stdarg (XmNtopAttachment, XmATTACH_FORM);
3863 stdarg (XmNbottomAttachment, XmATTACH_FORM);
3864 da = XmCreateDrawingArea (pd->form, "pinout", args, n);
3865 XtManageChild (da);
3867 XtAddCallback (da, XmNexposeCallback, (XtCallbackProc) pinout_callback,
3868 (XtPointer) pd);
3869 XtAddCallback (da, XmNresizeCallback, (XtCallbackProc) pinout_callback,
3870 (XtPointer) pd);
3872 XtManageChild (pd->form);
3873 pinout = 0;
3876 static void
3877 lesstif_beep (void)
3879 putchar (7);
3880 fflush (stdout);
3884 static bool progress_cancelled = false;
3886 static void
3887 progress_cancel_callback (Widget w, void *v, void *cbs)
3889 progress_cancelled = true;
3892 static Widget progress_dialog = 0;
3893 static Widget progress_cancel, progress_label;
3894 static Widget progress_scale;
3896 static void
3897 lesstif_progress_dialog (int so_far, int total, const char *msg)
3899 XmString xs;
3901 if (mainwind == 0)
3902 return;
3904 if (progress_dialog == 0)
3906 Atom close_atom;
3908 n = 0;
3909 stdarg (XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON);
3910 stdarg (XmNtitle, "Progress");
3911 stdarg (XmNdialogStyle, XmDIALOG_APPLICATION_MODAL);
3912 stdarg (XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
3913 progress_dialog = XmCreateInformationDialog (mainwind, "progress", args, n);
3914 XtAddCallback (progress_dialog, XmNcancelCallback,
3915 (XtCallbackProc) progress_cancel_callback, NULL);
3917 progress_cancel = XmMessageBoxGetChild (progress_dialog, XmDIALOG_CANCEL_BUTTON);
3918 progress_label = XmMessageBoxGetChild (progress_dialog, XmDIALOG_MESSAGE_LABEL);
3920 XtUnmanageChild (XmMessageBoxGetChild (progress_dialog, XmDIALOG_OK_BUTTON));
3921 XtUnmanageChild (XmMessageBoxGetChild (progress_dialog, XmDIALOG_HELP_BUTTON));
3923 stdarg (XmNdefaultPosition, False);
3924 XtSetValues (progress_dialog, args, n);
3926 n = 0;
3927 stdarg(XmNminimum, 0);
3928 stdarg(XmNvalue, 0);
3929 stdarg(XmNmaximum, total > 0 ? total : 1);
3930 stdarg(XmNorientation, XmHORIZONTAL);
3931 stdarg(XmNshowArrows, false);
3932 progress_scale = XmCreateScrollBar (progress_dialog, "scale", args, n);
3933 XtManageChild (progress_scale);
3935 close_atom = XmInternAtom (display, "WM_DELETE_WINDOW", 0);
3936 XmAddWMProtocolCallback (XtParent (progress_dialog), close_atom,
3937 (XtCallbackProc) progress_cancel_callback, 0);
3940 n = 0;
3941 stdarg(XmNvalue, 0);
3942 stdarg(XmNsliderSize, (so_far <= total) ? (so_far < 0) ? 0 : so_far : total);
3943 stdarg(XmNmaximum, total > 0 ? total : 1);
3944 XtSetValues (progress_scale, args, n);
3946 n = 0;
3947 xs = XmStringCreatePCB ((char *)msg);
3948 stdarg (XmNmessageString, xs);
3949 XtSetValues (progress_dialog, args, n);
3951 return;
3954 #define MIN_TIME_SEPARATION 0.1 /* seconds */
3956 static int
3957 lesstif_progress (int so_far, int total, const char *message)
3959 static bool started = false;
3960 XEvent e;
3961 struct timeval time;
3962 double time_delta, time_now;
3963 static double time_then = 0.0;
3964 int retval = 0;
3966 if (so_far == 0 && total == 0 && message == NULL)
3968 XtUnmanageChild (progress_dialog);
3969 started = false;
3970 progress_cancelled = false;
3971 return retval;
3974 gettimeofday (&time, NULL);
3975 time_now = time.tv_sec + time.tv_usec / 1000000.0;
3977 time_delta = time_now - time_then;
3979 if (started && time_delta < MIN_TIME_SEPARATION)
3980 return retval;
3982 /* Create or update the progress dialog */
3983 lesstif_progress_dialog (so_far, total, message);
3985 if (!started)
3987 XtManageChild (progress_dialog);
3988 started = true;
3991 /* Dispatch pending events */
3992 while (XtAppPending (app_context))
3994 XtAppNextEvent (app_context, &e);
3995 XtDispatchEvent (&e);
3997 idle_proc (NULL);
3999 /* If rendering takes a while, make sure the core has enough time to
4000 do work. */
4001 gettimeofday (&time, NULL);
4002 time_then = time.tv_sec + time.tv_usec / 1000000.0;
4004 return progress_cancelled;
4007 static HID_DRAW *
4008 lesstif_request_debug_draw (void)
4010 /* Send drawing to the backing pixmap */
4011 pixmap = main_pixmap;
4012 return lesstif_hid.graphics;
4015 static void
4016 lesstif_flush_debug_draw (void)
4018 /* Copy the backing pixmap to the display and redraw any attached objects */
4019 XSetFunction (display, my_gc, GXcopy);
4020 XCopyArea (display, main_pixmap, window, my_gc, 0, 0, view_width,
4021 view_height, 0, 0);
4022 pixmap = window;
4023 if (crosshair_on)
4025 DrawAttached (crosshair_gc);
4026 DrawMark (crosshair_gc);
4028 pixmap = main_pixmap;
4031 static void
4032 lesstif_finish_debug_draw (void)
4034 lesstif_flush_debug_draw ();
4035 /* No special tear down requirements
4039 #include "dolists.h"
4041 void
4042 hid_lesstif_init ()
4044 memset (&lesstif_hid, 0, sizeof (HID));
4045 memset (&lesstif_graphics, 0, sizeof (HID_DRAW));
4047 common_nogui_init (&lesstif_hid);
4048 common_draw_helpers_init (&lesstif_graphics);
4050 lesstif_hid.struct_size = sizeof (HID);
4051 lesstif_hid.name = "lesstif";
4052 lesstif_hid.description = "LessTif - a Motif clone for X/Unix";
4053 lesstif_hid.gui = 1;
4054 lesstif_hid.poly_before = 1;
4056 lesstif_hid.get_export_options = lesstif_get_export_options;
4057 lesstif_hid.do_export = lesstif_do_export;
4058 lesstif_hid.parse_arguments = lesstif_parse_arguments;
4059 lesstif_hid.invalidate_lr = lesstif_invalidate_lr;
4060 lesstif_hid.invalidate_all = lesstif_invalidate_all;
4061 lesstif_hid.notify_crosshair_change = lesstif_notify_crosshair_change;
4062 lesstif_hid.notify_mark_change = lesstif_notify_mark_change;
4063 lesstif_hid.set_layer = lesstif_set_layer;
4065 lesstif_hid.calibrate = lesstif_calibrate;
4066 lesstif_hid.shift_is_pressed = lesstif_shift_is_pressed;
4067 lesstif_hid.control_is_pressed = lesstif_control_is_pressed;
4068 lesstif_hid.mod1_is_pressed = lesstif_mod1_is_pressed;
4069 lesstif_hid.get_coords = lesstif_get_coords;
4070 lesstif_hid.set_crosshair = lesstif_set_crosshair;
4071 lesstif_hid.add_timer = lesstif_add_timer;
4072 lesstif_hid.stop_timer = lesstif_stop_timer;
4073 lesstif_hid.watch_file = lesstif_watch_file;
4074 lesstif_hid.unwatch_file = lesstif_unwatch_file;
4075 lesstif_hid.add_block_hook = lesstif_add_block_hook;
4076 lesstif_hid.stop_block_hook = lesstif_stop_block_hook;
4078 lesstif_hid.log = lesstif_log;
4079 lesstif_hid.logv = lesstif_logv;
4080 lesstif_hid.confirm_dialog = lesstif_confirm_dialog;
4081 lesstif_hid.close_confirm_dialog = lesstif_close_confirm_dialog;
4082 lesstif_hid.report_dialog = lesstif_report_dialog;
4083 lesstif_hid.prompt_for = lesstif_prompt_for;
4084 lesstif_hid.fileselect = lesstif_fileselect;
4085 lesstif_hid.attribute_dialog = lesstif_attribute_dialog;
4086 lesstif_hid.show_item = lesstif_show_item;
4087 lesstif_hid.beep = lesstif_beep;
4088 lesstif_hid.progress = lesstif_progress;
4089 lesstif_hid.edit_attributes = lesstif_attributes_dialog;
4091 lesstif_hid.request_debug_draw = lesstif_request_debug_draw;
4092 lesstif_hid.flush_debug_draw = lesstif_flush_debug_draw;
4093 lesstif_hid.finish_debug_draw = lesstif_finish_debug_draw;
4095 lesstif_hid.graphics = &lesstif_graphics;
4097 lesstif_graphics.make_gc = lesstif_make_gc;
4098 lesstif_graphics.destroy_gc = lesstif_destroy_gc;
4099 lesstif_graphics.use_mask = lesstif_use_mask;
4100 lesstif_graphics.set_color = lesstif_set_color;
4101 lesstif_graphics.set_line_cap = lesstif_set_line_cap;
4102 lesstif_graphics.set_line_width = lesstif_set_line_width;
4103 lesstif_graphics.set_draw_xor = lesstif_set_draw_xor;
4104 lesstif_graphics.draw_line = lesstif_draw_line;
4105 lesstif_graphics.draw_arc = lesstif_draw_arc;
4106 lesstif_graphics.draw_rect = lesstif_draw_rect;
4107 lesstif_graphics.fill_circle = lesstif_fill_circle;
4108 lesstif_graphics.fill_polygon = lesstif_fill_polygon;
4109 lesstif_graphics.fill_rect = lesstif_fill_rect;
4111 lesstif_graphics.draw_pcb_polygon = common_gui_draw_pcb_polygon;
4113 hid_register_hid (&lesstif_hid);
4114 #include "lesstif_lists.h"