lesstif: Silence set but unused variable warning
[geda-pcb/pcjc2.git] / src / hid / lesstif / main.c
blob4bd53917ddae8eb1a5fe56805143b0a8572e726e
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 int use_mask = 0;
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 /* These are for the pinout windows. */
103 typedef struct PinoutData
105 struct PinoutData *prev, *next;
106 Widget form;
107 Window window;
108 Coord left, right, top, bottom; /* PCB extents of item */
109 Coord x, y; /* PCB coordinates of upper right corner of window */
110 double zoom; /* PCB units per screen pixel */
111 int v_width, v_height; /* pixels */
112 void *item;
113 } PinoutData;
115 /* Linked list of all pinout windows. */
116 static PinoutData *pinouts = 0;
117 /* If set, we are currently updating this pinout window. */
118 static PinoutData *pinout = 0;
120 static int crosshair_x = 0, crosshair_y = 0;
121 static int in_move_event = 0, crosshair_in_window = 1;
123 Widget mainwind;
124 Widget work_area, messages, command, hscroll, vscroll;
125 static Widget m_mark, m_crosshair, m_grid, m_zoom, m_mode, m_status;
126 static Widget m_rats;
127 Widget lesstif_m_layer;
128 Widget m_click;
130 /* This is the size, in pixels, of the viewport. */
131 static int view_width, view_height;
132 /* This is the PCB location represented by the upper left corner of
133 the viewport. Note that PCB coordinates put 0,0 in the upper left,
134 much like X does. */
135 static int view_left_x = 0, view_top_y = 0;
136 /* Denotes PCB units per screen pixel. Larger numbers mean zooming
137 out - the largest value means you are looking at the whole
138 board. */
139 static double view_zoom = MIL_TO_COORD (10), prev_view_zoom = MIL_TO_COORD (10);
140 static bool flip_x = 0, flip_y = 0;
141 static bool autofade = 0;
142 static bool crosshair_on = true;
144 static void
145 ShowCrosshair (bool show)
147 if (crosshair_on == show)
148 return;
150 notify_crosshair_change (false);
151 if (Marked.status)
152 notify_mark_change (false);
154 crosshair_on = show;
156 notify_crosshair_change (true);
157 if (Marked.status)
158 notify_mark_change (true);
161 static int
162 flag_flipx (void *data)
164 return flip_x;
166 static int
167 flag_flipy (void *data)
169 return flip_y;
172 HID_Flag lesstif_main_flag_list[] = {
173 {"flip_x", flag_flipx, NULL},
174 {"flip_y", flag_flipy, NULL}
177 REGISTER_FLAGS (lesstif_main_flag_list)
179 /* This is the size of the current PCB work area. */
180 /* Use PCB->MaxWidth, PCB->MaxHeight. */
181 /* static int pcb_width, pcb_height; */
183 static Arg args[30];
184 static int n;
185 #define stdarg(t,v) XtSetArg(args[n], t, v), n++
188 static int use_private_colormap = 0;
189 static int stdin_listen = 0;
190 static char *background_image_file = 0;
191 char *lesstif_pcbmenu_path = "pcb-menu.res";
193 HID_Attribute lesstif_attribute_list[] = {
194 {"install", "Install private colormap",
195 HID_Boolean, 0, 0, {0, 0, 0}, 0, &use_private_colormap},
196 #define HA_colormap 0
198 /* %start-doc options "22 lesstif GUI Options"
199 @ftable @code
200 @item --listen
201 Listen for actions on stdin.
202 @end ftable
203 %end-doc
205 {"listen", "Listen on standard input for actions",
206 HID_Boolean, 0, 0, {0, 0, 0}, 0, &stdin_listen},
207 #define HA_listen 1
209 /* %start-doc options "22 lesstif GUI Options"
210 @ftable @code
211 @item --bg-image <string>
212 File name of an image to put into the background of the GUI canvas. The image must
213 be a color PPM image, in binary (not ASCII) format. It can be any size, and will be
214 automatically scaled to fit the canvas.
215 @end ftable
216 %end-doc
218 {"bg-image", "Background Image",
219 HID_String, 0, 0, {0, 0, 0}, 0, &background_image_file},
220 #define HA_bg_image 2
222 /* %start-doc options "22 lesstif GUI Options"
223 @ftable @code
224 @item --pcb-menu <string>
225 Location of the @file{pcb-menu.res} file which defines the menu for the lesstif GUI.
226 @end ftable
227 %end-doc
229 {"pcb-menu", "Location of pcb-menu.res file",
230 HID_String, 0, 0, {0, PCBLIBDIR "/pcb-menu.res", 0}, 0, &lesstif_pcbmenu_path}
231 #define HA_pcbmenu 3
234 REGISTER_ATTRIBUTES (lesstif_attribute_list)
236 static void lesstif_use_mask (int use_it);
237 static void zoom_max ();
238 static void zoom_to (double factor, int x, int y);
239 static void zoom_by (double factor, int x, int y);
240 static void zoom_toggle (int x, int y);
241 static void pinout_callback (Widget, PinoutData *,
242 XmDrawingAreaCallbackStruct *);
243 static void pinout_unmap (Widget, PinoutData *, void *);
244 static void Pan (int mode, int x, int y);
246 /* Px converts view->pcb, Vx converts pcb->view */
248 static inline int
249 Vx (Coord x)
251 int rv = (x - view_left_x) / view_zoom + 0.5;
252 if (flip_x)
253 rv = view_width - rv;
254 return rv;
257 static inline int
258 Vy (Coord y)
260 int rv = (y - view_top_y) / view_zoom + 0.5;
261 if (flip_y)
262 rv = view_height - rv;
263 return rv;
266 static inline int
267 Vz (Coord z)
269 return z / view_zoom + 0.5;
272 static inline Coord
273 Px (int x)
275 if (flip_x)
276 x = view_width - x;
277 return x * view_zoom + view_left_x;
280 static inline Coord
281 Py (int y)
283 if (flip_y)
284 y = view_height - y;
285 return y * view_zoom + view_top_y;
288 static inline Coord
289 Pz (int z)
291 return z * view_zoom;
294 void
295 lesstif_coords_to_pcb (int vx, int vy, Coord *px, Coord *py)
297 *px = Px (vx);
298 *py = Py (vy);
301 Pixel
302 lesstif_parse_color (char *value)
304 XColor color;
305 if (XParseColor (display, colormap, value, &color))
306 if (XAllocColor (display, colormap, &color))
307 return color.pixel;
308 return 0;
311 static void
312 do_color (char *value, char *which)
314 XColor color;
315 if (XParseColor (display, colormap, value, &color))
316 if (XAllocColor (display, colormap, &color))
318 stdarg (which, color.pixel);
322 /* ------------------------------------------------------------ */
324 static char *
325 cur_clip ()
327 if (TEST_FLAG (ORTHOMOVEFLAG, PCB))
328 return "+";
329 if (TEST_FLAG (ALLDIRECTIONFLAG, PCB))
330 return "*";
331 if (PCB->Clipping == 0)
332 return "X";
333 if (PCB->Clipping == 1)
334 return "_/";
335 return "\\_";
338 /* Called from the core when it's busy doing something and we need to
339 indicate that to the user. */
340 static int
341 Busy(int argc, char **argv, Coord x, Coord y)
343 static Cursor busy_cursor = 0;
344 if (busy_cursor == 0)
345 busy_cursor = XCreateFontCursor (display, XC_watch);
346 XDefineCursor (display, window, busy_cursor);
347 XFlush(display);
348 old_cursor_mode = -1;
349 return 0;
352 /* ---------------------------------------------------------------------- */
354 /* Local actions. */
356 static int
357 PointCursor (int argc, char **argv, Coord x, Coord y)
359 if (argc > 0)
360 over_point = 1;
361 else
362 over_point = 0;
363 old_cursor_mode = -1;
364 return 0;
367 static int
368 PCBChanged (int argc, char **argv, Coord x, Coord y)
370 if (work_area == 0)
371 return 0;
372 /*pcb_printf("PCB Changed! %$mD\n", PCB->MaxWidth, PCB->MaxHeight); */
373 n = 0;
374 stdarg (XmNminimum, 0);
375 stdarg (XmNvalue, 0);
376 stdarg (XmNsliderSize, PCB->MaxWidth ? PCB->MaxWidth : 1);
377 stdarg (XmNmaximum, PCB->MaxWidth ? PCB->MaxWidth : 1);
378 XtSetValues (hscroll, args, n);
379 n = 0;
380 stdarg (XmNminimum, 0);
381 stdarg (XmNvalue, 0);
382 stdarg (XmNsliderSize, PCB->MaxHeight ? PCB->MaxHeight : 1);
383 stdarg (XmNmaximum, PCB->MaxHeight ? PCB->MaxHeight : 1);
384 XtSetValues (vscroll, args, n);
385 zoom_max ();
387 hid_action ("NetlistChanged");
388 hid_action ("LayersChanged");
389 hid_action ("RouteStylesChanged");
390 lesstif_sizes_reset ();
391 lesstif_update_layer_groups ();
392 while (pinouts)
393 pinout_unmap (0, pinouts, 0);
394 if (PCB->Filename)
396 char *cp = strrchr (PCB->Filename, '/');
397 n = 0;
398 stdarg (XmNtitle, cp ? cp + 1 : PCB->Filename);
399 XtSetValues (appwidget, args, n);
401 return 0;
405 static const char setunits_syntax[] =
406 "SetUnits(mm|mil)";
408 static const char setunits_help[] =
409 "Set the default measurement units.";
411 /* %start-doc actions SetUnits
413 @table @code
415 @item mil
416 Sets the display units to mils (1/1000 inch).
418 @item mm
419 Sets the display units to millimeters.
421 @end table
423 %end-doc */
425 static int
426 SetUnits (int argc, char **argv, Coord x, Coord y)
428 const Unit *new_unit;
429 if (argc == 0)
430 return 0;
431 new_unit = get_unit_struct (argv[0]);
432 if (new_unit != NULL && new_unit->allow != NO_PRINT)
434 Settings.grid_unit = new_unit;
435 Settings.increments = get_increments_struct (Settings.grid_unit->family);
436 AttributePut (PCB, "PCB::grid::unit", argv[0]);
438 lesstif_sizes_reset ();
439 lesstif_styles_update_values ();
440 return 0;
443 static const char zoom_syntax[] =
444 "Zoom()\n"
445 "Zoom(factor)";
447 static const char zoom_help[] =
448 "Various zoom factor changes.";
450 /* %start-doc actions Zoom
452 Changes the zoom (magnification) of the view of the board. If no
453 arguments are passed, the view is scaled such that the board just fits
454 inside the visible window (i.e. ``view all''). Otherwise,
455 @var{factor} specifies a change in zoom factor. It may be prefixed by
456 @code{+}, @code{-}, or @code{=} to change how the zoom factor is
457 modified. The @var{factor} is a floating point number, such as
458 @code{1.5} or @code{0.75}.
460 @table @code
462 @item +@var{factor}
463 Values greater than 1.0 cause the board to be drawn smaller; more of
464 the board will be visible. Values between 0.0 and 1.0 cause the board
465 to be drawn bigger; less of the board will be visible.
467 @item -@var{factor}
468 Values greater than 1.0 cause the board to be drawn bigger; less of
469 the board will be visible. Values between 0.0 and 1.0 cause the board
470 to be drawn smaller; more of the board will be visible.
472 @item =@var{factor}
474 The @var{factor} is an absolute zoom factor; the unit for this value
475 is "PCB units per screen pixel". Since PCB units are 0.01 mil, a
476 @var{factor} of 1000 means 10 mils (0.01 in) per pixel, or 100 DPI,
477 about the actual resolution of most screens - resulting in an "actual
478 size" board. Similarly, a @var{factor} of 100 gives you a 10x actual
479 size.
481 @end table
483 Note that zoom factors of zero are silently ignored.
485 %end-doc */
487 static int
488 ZoomAction (int argc, char **argv, Coord x, Coord y)
490 const char *vp;
491 double v;
492 if (x == 0 && y == 0)
494 x = view_width / 2;
495 y = view_height / 2;
497 else
499 x = Vx (x);
500 y = Vy (y);
502 if (argc < 1)
504 zoom_max ();
505 return 0;
507 vp = argv[0];
508 if (strcasecmp (vp, "toggle") == 0)
510 zoom_toggle (x, y);
511 return 0;
513 if (*vp == '+' || *vp == '-' || *vp == '=')
514 vp++;
515 v = g_ascii_strtod (vp, 0);
516 if (v <= 0)
517 return 1;
518 switch (argv[0][0])
520 case '-':
521 zoom_by (1 / v, x, y);
522 break;
523 default:
524 case '+':
525 zoom_by (v, x, y);
526 break;
527 case '=':
528 zoom_to (v, x, y);
529 break;
531 return 0;
534 static int pan_thumb_mode;
536 static int
537 PanAction (int argc, char **argv, Coord x, Coord y)
539 int mode;
541 if (argc == 2)
543 pan_thumb_mode = (strcasecmp (argv[0], "thumb") == 0) ? 1 : 0;
544 mode = atoi (argv[1]);
546 else
548 pan_thumb_mode = 0;
549 mode = atoi (argv[0]);
551 Pan (mode, Vx(x), Vy(y));
553 return 0;
556 static const char swapsides_syntax[] =
557 "SwapSides(|v|h|r)";
559 static const char swapsides_help[] =
560 "Swaps the side of the board you're looking at.";
562 /* %start-doc actions SwapSides
564 This action changes the way you view the board.
566 @table @code
568 @item v
569 Flips the board over vertically (up/down).
571 @item h
572 Flips the board over horizontally (left/right), like flipping pages in
573 a book.
575 @item r
576 Rotates the board 180 degrees without changing sides.
578 @end table
580 If no argument is given, the board isn't moved but the opposite side
581 is shown.
583 Normally, this action changes which pads and silk layer are drawn as
584 true silk, and which are drawn as the "invisible" layer. It also
585 determines which solder mask you see.
587 As a special case, if the layer group for the side you're looking at
588 is visible and currently active, and the layer group for the opposite
589 is not visible (i.e. disabled), then this action will also swap which
590 layer group is visible and active, effectively swapping the ``working
591 side'' of the board.
593 %end-doc */
595 static int
596 group_showing (int g, int *c)
598 int i, l;
599 *c = PCB->LayerGroups.Entries[g][0];
600 for (i=0; i<PCB->LayerGroups.Number[g]; i++)
602 l = PCB->LayerGroups.Entries[g][i];
603 if (l >= 0 && l < max_copper_layer)
605 *c = l;
606 if (PCB->Data->Layer[l].On)
607 return 1;
610 return 0;
613 static int
614 SwapSides (int argc, char **argv, Coord x, Coord y)
616 int old_shown_side = Settings.ShowBottomSide;
617 int top_group = GetLayerGroupNumberBySide (TOP_SIDE);
618 int bottom_group = GetLayerGroupNumberBySide (BOTTOM_SIDE);
619 int active_group = GetLayerGroupNumberByNumber (LayerStack[0]);
620 int top_layer;
621 int bottom_layer;
622 int top_showing = group_showing (top_group, &top_layer);
623 int bottom_showing = group_showing (bottom_group, &bottom_layer);
625 if (argc > 0)
627 switch (argv[0][0]) {
628 case 'h':
629 case 'H':
630 flip_x = ! flip_x;
631 break;
632 case 'v':
633 case 'V':
634 flip_y = ! flip_y;
635 break;
636 case 'r':
637 case 'R':
638 flip_x = ! flip_x;
639 flip_y = ! flip_y;
640 break;
641 default:
642 return 1;
644 /* SwapSides will swap this */
645 Settings.ShowBottomSide = (flip_x == flip_y);
648 n = 0;
649 if (flip_x)
650 stdarg (XmNprocessingDirection, XmMAX_ON_LEFT);
651 else
652 stdarg (XmNprocessingDirection, XmMAX_ON_RIGHT);
653 XtSetValues (hscroll, args, n);
655 n = 0;
656 if (flip_y)
657 stdarg (XmNprocessingDirection, XmMAX_ON_TOP);
658 else
659 stdarg (XmNprocessingDirection, XmMAX_ON_BOTTOM);
660 XtSetValues (vscroll, args, n);
662 Settings.ShowBottomSide = !Settings.ShowBottomSide;
664 /* The idea is that if we're looking at the front side and the front
665 layer is active (or visa versa), switching sides should switch
666 layers too. We used to only do this if the other layer wasn't
667 shown, but we now do it always. Change it back if users get
668 confused. */
669 if (Settings.ShowBottomSide != old_shown_side)
671 if (Settings.ShowBottomSide)
673 if (active_group == top_group)
675 if (top_showing && !bottom_showing)
676 ChangeGroupVisibility (top_layer, 0, 0);
677 ChangeGroupVisibility (bottom_layer, 1, 1);
680 else
682 if (active_group == bottom_group)
684 if (bottom_showing && !top_showing)
685 ChangeGroupVisibility (bottom_layer, 0, 0);
686 ChangeGroupVisibility (top_layer, 1, 1);
690 lesstif_invalidate_all ();
691 return 0;
694 static Widget m_cmd = 0, m_cmd_label;
696 static void
697 command_callback (Widget w, XtPointer uptr, XmTextVerifyCallbackStruct * cbs)
699 char *s;
700 switch (cbs->reason)
702 case XmCR_ACTIVATE:
703 s = XmTextGetString (w);
704 lesstif_show_crosshair (0);
705 hid_parse_command (s);
706 XtFree (s);
707 XmTextSetString (w, "");
708 case XmCR_LOSING_FOCUS:
709 XtUnmanageChild (m_cmd);
710 XtUnmanageChild (m_cmd_label);
711 break;
715 static void
716 command_event_handler (Widget w, XtPointer p, XEvent * e, Boolean * cont)
718 char buf[10];
719 KeySym sym;
721 switch (e->type)
723 case KeyPress:
724 XLookupString ((XKeyEvent *)e, buf, sizeof (buf), &sym, NULL);
725 switch (sym)
727 case XK_Escape:
728 XtUnmanageChild (m_cmd);
729 XtUnmanageChild (m_cmd_label);
730 XmTextSetString (w, "");
731 *cont = False;
732 break;
734 break;
738 static const char command_syntax[] =
739 "Command()";
741 static const char command_help[] =
742 "Displays the command line input window.";
744 /* %start-doc actions Command
746 The command window allows the user to manually enter actions to be
747 executed. Action syntax can be done one of two ways:
749 @itemize @bullet
751 @item
752 Follow the action name by an open parenthesis, arguments separated by
753 commas, end with a close parenthesis. Example: @code{Abc(1,2,3)}
755 @item
756 Separate the action name and arguments by spaces. Example: @code{Abc
757 1 2 3}.
759 @end itemize
761 The first option allows you to have arguments with spaces in them,
762 but the second is more ``natural'' to type for most people.
764 Note that action names are not case sensitive, but arguments normally
765 are. However, most actions will check for ``keywords'' in a case
766 insensitive way.
768 There are three ways to finish with the command window. If you press
769 the @code{Enter} key, the command is invoked, the window goes away,
770 and the next time you bring up the command window it's empty. If you
771 press the @code{Esc} key, the window goes away without invoking
772 anything, and the next time you bring up the command window it's
773 empty. If you change focus away from the command window (i.e. click
774 on some other window), the command window goes away but the next time
775 you bring it up it resumes entering the command you were entering
776 before.
778 %end-doc */
780 static int
781 Command (int argc, char **argv, Coord x, Coord y)
783 XtManageChild (m_cmd_label);
784 XtManageChild (m_cmd);
785 XmProcessTraversal (m_cmd, XmTRAVERSE_CURRENT);
786 return 0;
789 static const char benchmark_syntax[] =
790 "Benchmark()";
792 static const char benchmark_help[] =
793 "Benchmark the GUI speed.";
795 /* %start-doc actions Benchmark
797 This action is used to speed-test the Lesstif graphics subsystem. It
798 redraws the current screen as many times as possible in ten seconds.
799 It reports the amount of time needed to draw the screen once.
801 %end-doc */
803 static int
804 Benchmark (int argc, char **argv, Coord x, Coord y)
806 int i = 0;
807 time_t start, end;
808 BoxType region;
809 Drawable save_main;
811 save_main = main_pixmap;
812 main_pixmap = window;
814 region.X1 = 0;
815 region.Y1 = 0;
816 region.X2 = PCB->MaxWidth;
817 region.Y2 = PCB->MaxHeight;
819 pixmap = window;
820 XSync (display, 0);
821 time (&start);
824 XFillRectangle (display, pixmap, bg_gc, 0, 0, view_width, view_height);
825 hid_expose_callback (&lesstif_hid, &region, 0);
826 XSync (display, 0);
827 time (&end);
828 i++;
830 while (end - start < 10);
832 printf ("%g redraws per second\n", i / 10.0);
834 main_pixmap = save_main;
835 return 0;
838 static int
839 Center(int argc, char **argv, Coord x, Coord y)
841 x = GridFit (x, PCB->Grid, PCB->GridOffsetX);
842 y = GridFit (y, PCB->Grid, PCB->GridOffsetY);
843 view_left_x = x - (view_width * view_zoom) / 2;
844 view_top_y = y - (view_height * view_zoom) / 2;
845 lesstif_pan_fixup ();
846 /* Move the pointer to the center of the window, but only if it's
847 currently within the window already. Watch out for edges,
848 though. */
849 XWarpPointer (display, window, window, 0, 0, view_width, view_height,
850 Vx(x), Vy(y));
851 return 0;
854 static const char cursor_syntax[] =
855 "Cursor(Type,DeltaUp,DeltaRight,Units)";
857 static const char cursor_help[] =
858 "Move the cursor.";
860 /* %start-doc actions Cursor
862 This action moves the mouse cursor. Unlike other actions which take
863 coordinates, this action's coordinates are always relative to the
864 user's view of the board. Thus, a positive @var{DeltaUp} may move the
865 cursor towards the board origin if the board is inverted.
867 Type is one of @samp{Pan} or @samp{Warp}. @samp{Pan} causes the
868 viewport to move such that the crosshair is under the mouse cursor.
869 @samp{Warp} causes the mouse cursor to move to be above the crosshair.
871 @var{Units} can be one of the following:
873 @table @samp
875 @item mil
876 @itemx mm
877 The cursor is moved by that amount, in board units.
879 @item grid
880 The cursor is moved by that many grid points.
882 @item view
883 The values are percentages of the viewport's view. Thus, a pan of
884 @samp{100} would scroll the viewport by exactly the width of the
885 current view.
887 @item board
888 The values are percentages of the board size. Thus, a move of
889 @samp{50,50} moves you halfway across the board.
891 @end table
893 %end-doc */
895 static int
896 CursorAction(int argc, char **argv, Coord x, Coord y)
898 UnitList extra_units_x = {
899 { "grid", PCB->Grid, 0 },
900 { "view", Pz(view_width), UNIT_PERCENT },
901 { "board", PCB->MaxWidth, UNIT_PERCENT },
902 { "", 0, 0 }
904 UnitList extra_units_y = {
905 { "grid", PCB->Grid, 0 },
906 { "view", Pz(view_height), UNIT_PERCENT },
907 { "board", PCB->MaxHeight, UNIT_PERCENT },
908 { "", 0, 0 }
910 int pan_warp = HID_SC_DO_NOTHING;
911 double dx, dy;
913 if (argc != 4)
914 AFAIL(cursor);
916 if (strcasecmp (argv[0], "pan") == 0)
917 pan_warp = HID_SC_PAN_VIEWPORT;
918 else if (strcasecmp (argv[0], "warp") == 0)
919 pan_warp = HID_SC_WARP_POINTER;
920 else
921 AFAIL(cursor);
923 dx = GetValueEx (argv[1], argv[3], NULL, extra_units_x, "mil");
924 if (flip_x)
925 dx = -dx;
926 dy = GetValueEx (argv[2], argv[3], NULL, extra_units_y, "mil");
927 if (!flip_y)
928 dy = -dy;
930 EventMoveCrosshair (Crosshair.X + dx, Crosshair.Y + dy);
931 gui->set_crosshair (Crosshair.X, Crosshair.Y, pan_warp);
933 return 0;
936 HID_Action lesstif_main_action_list[] = {
937 {"PCBChanged", 0, PCBChanged,
938 pcbchanged_help, pcbchanged_syntax},
939 {"SetUnits", 0, SetUnits,
940 setunits_help, setunits_syntax},
941 {"Zoom", "Click on a place to zoom in", ZoomAction,
942 zoom_help, zoom_syntax},
943 {"Pan", "Click on a place to pan", PanAction,
944 zoom_help, zoom_syntax},
945 {"SwapSides", 0, SwapSides,
946 swapsides_help, swapsides_syntax},
947 {"Command", 0, Command,
948 command_help, command_syntax},
949 {"Benchmark", 0, Benchmark,
950 benchmark_help, benchmark_syntax},
951 {"PointCursor", 0, PointCursor},
952 {"Center", "Click on a location to center", Center},
953 {"Busy", 0, Busy},
954 {"Cursor", 0, CursorAction,
955 cursor_help, cursor_syntax},
958 REGISTER_ACTIONS (lesstif_main_action_list)
961 /* ----------------------------------------------------------------------
962 * redraws the background image
965 static int bg_w, bg_h, bgi_w, bgi_h;
966 static Pixel **bg = 0;
967 static XImage *bgi = 0;
968 static enum {
969 PT_unknown,
970 PT_RGB565,
971 PT_RGB888
972 } pixel_type = PT_unknown;
974 static void
975 LoadBackgroundFile (FILE *f, char *filename)
977 XVisualInfo vinfot, *vinfo;
978 Visual *vis;
979 int c, r, b;
980 int i, nret;
981 int p[3], rows, cols, maxval;
983 if (fgetc(f) != 'P')
985 printf("bgimage: %s signature not P6\n", filename);
986 return;
988 if (fgetc(f) != '6')
990 printf("bgimage: %s signature not P6\n", filename);
991 return;
993 for (i=0; i<3; i++)
995 do {
996 b = fgetc(f);
997 if (feof(f))
998 return;
999 if (b == '#')
1000 while (!feof(f) && b != '\n')
1001 b = fgetc(f);
1002 } while (!isdigit(b));
1003 p[i] = b - '0';
1004 while (isdigit(b = fgetc(f)))
1005 p[i] = p[i]*10 + b - '0';
1007 bg_w = cols = p[0];
1008 bg_h = rows = p[1];
1009 maxval = p[2];
1011 setbuf(stdout, 0);
1012 bg = (Pixel **) malloc (rows * sizeof (Pixel *));
1013 if (!bg)
1015 printf("Out of memory loading %s\n", filename);
1016 return;
1018 for (i=0; i<rows; i++)
1020 bg[i] = (Pixel *) malloc (cols * sizeof (Pixel));
1021 if (!bg[i])
1023 printf("Out of memory loading %s\n", filename);
1024 while (--i >= 0)
1025 free (bg[i]);
1026 free (bg);
1027 bg = 0;
1028 return;
1032 vis = DefaultVisual (display, DefaultScreen(display));
1034 vinfot.visualid = XVisualIDFromVisual(vis);
1035 vinfo = XGetVisualInfo (display, VisualIDMask, &vinfot, &nret);
1037 #if 0
1038 /* If you want to support more visuals below, you'll probably need
1039 this. */
1040 printf("vinfo: rm %04x gm %04x bm %04x depth %d class %d\n",
1041 vinfo->red_mask, vinfo->green_mask, vinfo->blue_mask,
1042 vinfo->depth, vinfo->class);
1043 #endif
1045 #if !defined(__cplusplus)
1046 #define c_class class
1047 #endif
1049 if (vinfo->c_class == TrueColor
1050 && vinfo->depth == 16
1051 && vinfo->red_mask == 0xf800
1052 && vinfo->green_mask == 0x07e0
1053 && vinfo->blue_mask == 0x001f)
1054 pixel_type = PT_RGB565;
1056 if (vinfo->c_class == TrueColor
1057 && vinfo->depth == 24
1058 && vinfo->red_mask == 0xff0000
1059 && vinfo->green_mask == 0x00ff00
1060 && vinfo->blue_mask == 0x0000ff)
1061 pixel_type = PT_RGB888;
1063 for (r=0; r<rows; r++)
1065 for (c=0; c<cols; c++)
1067 XColor pix;
1068 unsigned int pr = (unsigned)fgetc(f);
1069 unsigned int pg = (unsigned)fgetc(f);
1070 unsigned int pb = (unsigned)fgetc(f);
1072 switch (pixel_type)
1074 case PT_unknown:
1075 pix.red = pr * 65535 / maxval;
1076 pix.green = pg * 65535 / maxval;
1077 pix.blue = pb * 65535 / maxval;
1078 pix.flags = DoRed | DoGreen | DoBlue;
1079 XAllocColor (display, colormap, &pix);
1080 bg[r][c] = pix.pixel;
1081 break;
1082 case PT_RGB565:
1083 bg[r][c] = (pr>>3)<<11 | (pg>>2)<<5 | (pb>>3);
1084 break;
1085 case PT_RGB888:
1086 bg[r][c] = (pr << 16) | (pg << 8) | (pb);
1087 break;
1093 void
1094 LoadBackgroundImage (char *filename)
1096 FILE *f = fopen(filename, "rb");
1097 if (!f)
1099 if (NSTRCMP (filename, "pcb-background.ppm"))
1100 perror(filename);
1101 return;
1103 LoadBackgroundFile (f, filename);
1104 fclose(f);
1107 static void
1108 DrawBackgroundImage ()
1110 int x, y, w, h;
1111 double xscale, yscale;
1112 int pcbwidth = PCB->MaxWidth / view_zoom;
1113 int pcbheight = PCB->MaxHeight / view_zoom;
1115 if (!window || !bg)
1116 return;
1118 if (!bgi || view_width != bgi_w || view_height != bgi_h)
1120 if (bgi)
1121 XDestroyImage (bgi);
1122 /* Cheat - get the image, which sets up the format too. */
1123 bgi = XGetImage (XtDisplay(work_area),
1124 window,
1125 0, 0, view_width, view_height,
1126 -1, ZPixmap);
1127 bgi_w = view_width;
1128 bgi_h = view_height;
1131 w = MIN (view_width, pcbwidth);
1132 h = MIN (view_height, pcbheight);
1134 xscale = (double)bg_w / PCB->MaxWidth;
1135 yscale = (double)bg_h / PCB->MaxHeight;
1137 for (y=0; y<h; y++)
1139 int pr = Py(y);
1140 int ir = pr * yscale;
1141 for (x=0; x<w; x++)
1143 int pc = Px(x);
1144 int ic = pc * xscale;
1145 XPutPixel (bgi, x, y, bg[ir][ic]);
1148 XPutImage(display, main_pixmap, bg_gc,
1149 bgi,
1150 0, 0, 0, 0, w, h);
1152 /* ---------------------------------------------------------------------- */
1154 static HID_Attribute *
1155 lesstif_get_export_options (int *n)
1157 *n = sizeof (lesstif_attribute_list) / sizeof (HID_Attribute);
1158 return lesstif_attribute_list;
1161 static void
1162 set_scroll (Widget s, int pos, int view, int pcb)
1164 int sz = view * view_zoom;
1165 if (sz > pcb)
1166 sz = pcb;
1167 n = 0;
1168 stdarg (XmNvalue, pos);
1169 stdarg (XmNsliderSize, sz);
1170 stdarg (XmNincrement, view_zoom);
1171 stdarg (XmNpageIncrement, sz);
1172 stdarg (XmNmaximum, pcb);
1173 XtSetValues (s, args, n);
1176 void
1177 lesstif_pan_fixup ()
1179 #if 0
1180 if (view_left_x > PCB->MaxWidth - (view_width * view_zoom))
1181 view_left_x = PCB->MaxWidth - (view_width * view_zoom);
1182 if (view_top_y > PCB->MaxHeight - (view_height * view_zoom))
1183 view_top_y = PCB->MaxHeight - (view_height * view_zoom);
1184 if (view_left_x < 0)
1185 view_left_x = 0;
1186 if (view_top_y < 0)
1187 view_top_y = 0;
1188 if (view_width * view_zoom > PCB->MaxWidth
1189 && view_height * view_zoom > PCB->MaxHeight)
1191 zoom_by (1, 0, 0);
1192 return;
1194 #endif
1196 set_scroll (hscroll, view_left_x, view_width, PCB->MaxWidth);
1197 set_scroll (vscroll, view_top_y, view_height, PCB->MaxHeight);
1199 lesstif_invalidate_all ();
1202 static void
1203 zoom_max ()
1205 double new_zoom = PCB->MaxWidth / view_width;
1206 if (new_zoom < PCB->MaxHeight / view_height)
1207 new_zoom = PCB->MaxHeight / view_height;
1209 view_left_x = -(view_width * new_zoom - PCB->MaxWidth) / 2;
1210 view_top_y = -(view_height * new_zoom - PCB->MaxHeight) / 2;
1211 view_zoom = new_zoom;
1212 pixel_slop = view_zoom;
1213 lesstif_pan_fixup ();
1216 static void
1217 zoom_to (double new_zoom, int x, int y)
1219 double max_zoom, xfrac, yfrac;
1220 int cx, cy;
1222 xfrac = (double) x / (double) view_width;
1223 yfrac = (double) y / (double) view_height;
1225 if (flip_x)
1226 xfrac = 1-xfrac;
1227 if (flip_y)
1228 yfrac = 1-yfrac;
1230 max_zoom = PCB->MaxWidth / view_width;
1231 if (max_zoom < PCB->MaxHeight / view_height)
1232 max_zoom = PCB->MaxHeight / view_height;
1234 max_zoom *= MAX_ZOOM_SCALE;
1236 if (new_zoom < 1)
1237 new_zoom = 1;
1238 if (new_zoom > max_zoom)
1239 new_zoom = max_zoom;
1241 cx = view_left_x + view_width * xfrac * view_zoom;
1242 cy = view_top_y + view_height * yfrac * view_zoom;
1244 if (view_zoom != new_zoom)
1246 view_zoom = new_zoom;
1247 pixel_slop = view_zoom;
1249 view_left_x = cx - view_width * xfrac * view_zoom;
1250 view_top_y = cy - view_height * yfrac * view_zoom;
1252 lesstif_pan_fixup ();
1255 static void
1256 zoom_toggle(int x, int y)
1258 double tmp;
1260 tmp = prev_view_zoom;
1261 prev_view_zoom = view_zoom;
1262 zoom_to(tmp, x, y);
1265 void
1266 zoom_by (double factor, int x, int y)
1268 zoom_to (view_zoom * factor, x, y);
1271 static int panning = 0;
1272 static int shift_pressed;
1273 static int ctrl_pressed;
1274 static int alt_pressed;
1276 /* X and Y are in screen coordinates. */
1277 static void
1278 Pan (int mode, int x, int y)
1280 static int ox, oy;
1281 static int opx, opy;
1283 panning = mode;
1284 /* This is for ctrl-pan, where the viewport's position is directly
1285 proportional to the cursor position in the window (like the Xaw
1286 thumb panner) */
1287 if (pan_thumb_mode)
1289 opx = x * PCB->MaxWidth / view_width;
1290 opy = y * PCB->MaxHeight / view_height;
1291 if (flip_x)
1292 opx = PCB->MaxWidth - opx;
1293 if (flip_y)
1294 opy = PCB->MaxHeight - opy;
1295 view_left_x = opx - view_width / 2 * view_zoom;
1296 view_top_y = opy - view_height / 2 * view_zoom;
1297 lesstif_pan_fixup ();
1299 /* This is the start of a regular pan. On the first click, we
1300 remember the coordinates where we "grabbed" the screen. */
1301 else if (mode == 1)
1303 ox = x;
1304 oy = y;
1305 opx = view_left_x;
1306 opy = view_top_y;
1308 /* continued drag, we calculate how far we've moved the cursor and
1309 set the position accordingly. */
1310 else
1312 if (flip_x)
1313 view_left_x = opx + (x - ox) * view_zoom;
1314 else
1315 view_left_x = opx - (x - ox) * view_zoom;
1316 if (flip_y)
1317 view_top_y = opy + (y - oy) * view_zoom;
1318 else
1319 view_top_y = opy - (y - oy) * view_zoom;
1320 lesstif_pan_fixup ();
1324 static void
1325 mod_changed (XKeyEvent * e, int set)
1327 switch (XKeycodeToKeysym (display, e->keycode, 0))
1329 case XK_Shift_L:
1330 case XK_Shift_R:
1331 shift_pressed = set;
1332 break;
1333 case XK_Control_L:
1334 case XK_Control_R:
1335 ctrl_pressed = set;
1336 break;
1337 #ifdef __APPLE__
1338 case XK_Mode_switch:
1339 #else
1340 case XK_Alt_L:
1341 case XK_Alt_R:
1342 #endif
1343 alt_pressed = set;
1344 break;
1345 default:
1346 // to include the Apple keyboard left and right command keys use XK_Meta_L and XK_Meta_R respectivly.
1347 return;
1349 in_move_event = 1;
1350 notify_crosshair_change (false);
1351 if (panning)
1352 Pan (2, e->x, e->y);
1353 EventMoveCrosshair (Px (e->x), Py (e->y));
1354 AdjustAttachedObjects ();
1355 notify_crosshair_change (true);
1356 in_move_event = 0;
1359 static void
1360 work_area_input (Widget w, XtPointer v, XEvent * e, Boolean * ctd)
1362 static int pressed_button = 0;
1363 static int ignore_release = 0;
1365 show_crosshair (0);
1366 switch (e->type)
1368 case KeyPress:
1369 mod_changed (&(e->xkey), 1);
1370 if (lesstif_key_event (&(e->xkey)))
1371 return;
1372 break;
1374 case KeyRelease:
1375 mod_changed (&(e->xkey), 0);
1376 break;
1378 case ButtonPress:
1380 int mods;
1381 if (pressed_button)
1382 return;
1383 /*printf("click %d\n", e->xbutton.button); */
1384 if (lesstif_button_event (w, e))
1386 ignore_release = 1;
1387 return;
1389 ignore_release = 0;
1391 notify_crosshair_change (false);
1392 pressed_button = e->xbutton.button;
1393 mods = ((e->xbutton.state & ShiftMask) ? M_Shift : 0)
1394 + ((e->xbutton.state & ControlMask) ? M_Ctrl : 0)
1395 #ifdef __APPLE__
1396 + ((e->xbutton.state & (1<<13)) ? M_Alt : 0);
1397 #else
1398 + ((e->xbutton.state & Mod1Mask) ? M_Alt : 0);
1399 #endif
1400 do_mouse_action(e->xbutton.button, mods);
1401 notify_crosshair_change (true);
1402 break;
1405 case ButtonRelease:
1407 int mods;
1408 if (e->xbutton.button != pressed_button)
1409 return;
1410 lesstif_button_event (w, e);
1411 notify_crosshair_change (false);
1412 pressed_button = 0;
1413 mods = ((e->xbutton.state & ShiftMask) ? M_Shift : 0)
1414 + ((e->xbutton.state & ControlMask) ? M_Ctrl : 0)
1415 #ifdef __APPLE__
1416 + ((e->xbutton.state & (1<<13)) ? M_Alt : 0)
1417 #else
1418 + ((e->xbutton.state & Mod1Mask) ? M_Alt : 0)
1419 #endif
1420 + M_Release;
1421 do_mouse_action (e->xbutton.button, mods);
1422 notify_crosshair_change (true);
1423 break;
1426 case MotionNotify:
1428 Window root, child;
1429 unsigned int keys_buttons;
1430 int root_x, root_y, pos_x, pos_y;
1431 while (XCheckMaskEvent (display, PointerMotionMask, e));
1432 XQueryPointer (display, e->xmotion.window, &root, &child,
1433 &root_x, &root_y, &pos_x, &pos_y, &keys_buttons);
1434 shift_pressed = (keys_buttons & ShiftMask);
1435 ctrl_pressed = (keys_buttons & ControlMask);
1436 #ifdef __APPLE__
1437 alt_pressed = (keys_buttons & (1<<13));
1438 #else
1439 alt_pressed = (keys_buttons & Mod1Mask);
1440 #endif
1441 /*pcb_printf("m %#mS %#mS\n", Px(e->xmotion.x), Py(e->xmotion.y)); */
1442 crosshair_in_window = 1;
1443 in_move_event = 1;
1444 if (panning)
1445 Pan (2, pos_x, pos_y);
1446 EventMoveCrosshair (Px (pos_x), Py (pos_y));
1447 in_move_event = 0;
1449 break;
1451 case LeaveNotify:
1452 crosshair_in_window = 0;
1453 ShowCrosshair (false);
1454 need_idle_proc ();
1455 break;
1457 case EnterNotify:
1458 crosshair_in_window = 1;
1459 in_move_event = 1;
1460 EventMoveCrosshair (Px (e->xcrossing.x), Py (e->xcrossing.y));
1461 ShowCrosshair (true);
1462 in_move_event = 0;
1463 need_idle_proc ();
1464 break;
1466 default:
1467 printf ("work_area: unknown event %d\n", e->type);
1468 break;
1472 static void
1473 draw_right_cross (GC xor_gc, int x, int y,
1474 int view_width, int view_height)
1476 XDrawLine (display, window, xor_gc, 0, y, view_width, y);
1477 XDrawLine (display, window, xor_gc, x, 0, x, view_height);
1480 static void
1481 draw_slanted_cross (GC xor_gc, int x, int y,
1482 int view_width, int view_height)
1484 int x0, y0, x1, y1;
1486 x0 = x + (view_height - y);
1487 x0 = MAX(0, MIN (x0, view_width));
1488 x1 = x - y;
1489 x1 = MAX(0, MIN (x1, view_width));
1490 y0 = y + (view_width - x);
1491 y0 = MAX(0, MIN (y0, view_height));
1492 y1 = y - x;
1493 y1 = MAX(0, MIN (y1, view_height));
1494 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1495 x0 = x - (view_height - y);
1496 x0 = MAX(0, MIN (x0, view_width));
1497 x1 = x + y;
1498 x1 = MAX(0, MIN (x1, view_width));
1499 y0 = y + x;
1500 y0 = MAX(0, MIN (y0, view_height));
1501 y1 = y - (view_width - x);
1502 y1 = MAX(0, MIN (y1, view_height));
1503 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1506 static void
1507 draw_dozen_cross (GC xor_gc, int x, int y,
1508 int view_width, int view_height)
1510 int x0, y0, x1, y1;
1511 double tan60 = sqrt (3);
1513 x0 = x + (view_height - y) / tan60;
1514 x0 = MAX(0, MIN (x0, view_width));
1515 x1 = x - y / tan60;
1516 x1 = MAX(0, MIN (x1, view_width));
1517 y0 = y + (view_width - x) * tan60;
1518 y0 = MAX(0, MIN (y0, view_height));
1519 y1 = y - x * tan60;
1520 y1 = MAX(0, MIN (y1, view_height));
1521 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1523 x0 = x + (view_height - y) * tan60;
1524 x0 = MAX(0, MIN (x0, view_width));
1525 x1 = x - y * tan60;
1526 x1 = MAX(0, MIN (x1, view_width));
1527 y0 = y + (view_width - x) / tan60;
1528 y0 = MAX(0, MIN (y0, view_height));
1529 y1 = y - x / tan60;
1530 y1 = MAX(0, MIN (y1, view_height));
1531 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1533 x0 = x - (view_height - y) / tan60;
1534 x0 = MAX(0, MIN (x0, view_width));
1535 x1 = x + y / tan60;
1536 x1 = MAX(0, MIN (x1, view_width));
1537 y0 = y + x * tan60;
1538 y0 = MAX(0, MIN (y0, view_height));
1539 y1 = y - (view_width - x) * tan60;
1540 y1 = MAX(0, MIN (y1, view_height));
1541 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1543 x0 = x - (view_height - y) * tan60;
1544 x0 = MAX(0, MIN (x0, view_width));
1545 x1 = x + y * tan60;
1546 x1 = MAX(0, MIN (x1, view_width));
1547 y0 = y + x / tan60;
1548 y0 = MAX(0, MIN (y0, view_height));
1549 y1 = y - (view_width - x) / tan60;
1550 y1 = MAX(0, MIN (y1, view_height));
1551 XDrawLine (display, window, xor_gc, x0, y0, x1, y1);
1554 static void
1555 draw_crosshair (GC xor_gc, int x, int y,
1556 int view_width, int view_height)
1558 draw_right_cross (xor_gc, x, y, view_width, view_height);
1559 if (Crosshair.shape == Union_Jack_Crosshair_Shape)
1560 draw_slanted_cross (xor_gc, x, y, view_width, view_height);
1561 if (Crosshair.shape == Dozen_Crosshair_Shape)
1562 draw_dozen_cross (xor_gc, x, y, view_width, view_height);
1564 void
1565 lesstif_show_crosshair (int show)
1567 static int showing = 0;
1568 static int sx, sy;
1569 static GC xor_gc = 0;
1570 Pixel crosshair_color;
1572 if (!crosshair_in_window || !window)
1573 return;
1574 if (xor_gc == 0)
1576 crosshair_color = lesstif_parse_color (Settings.CrosshairColor) ^ bgcolor;
1577 xor_gc = XCreateGC (display, window, 0, 0);
1578 XSetFunction (display, xor_gc, GXxor);
1579 XSetForeground (display, xor_gc, crosshair_color);
1581 if (show == showing)
1582 return;
1583 if (show)
1585 sx = Vx (crosshair_x);
1586 sy = Vy (crosshair_y);
1588 else
1589 need_idle_proc ();
1590 draw_crosshair (xor_gc, sx, sy, view_width, view_height);
1591 showing = show;
1594 static void
1595 work_area_expose (Widget work_area, void *me,
1596 XmDrawingAreaCallbackStruct * cbs)
1598 XExposeEvent *e;
1600 show_crosshair (0);
1601 e = &(cbs->event->xexpose);
1602 XSetFunction (display, my_gc, GXcopy);
1603 XCopyArea (display, main_pixmap, window, my_gc,
1604 e->x, e->y, e->width, e->height, e->x, e->y);
1605 show_crosshair (1);
1608 static void
1609 scroll_callback (Widget scroll, int *view_dim,
1610 XmScrollBarCallbackStruct * cbs)
1612 *view_dim = cbs->value;
1613 lesstif_invalidate_all ();
1616 static void
1617 work_area_make_pixmaps (Dimension width, Dimension height)
1619 if (main_pixmap)
1620 XFreePixmap (display, main_pixmap);
1621 main_pixmap =
1622 XCreatePixmap (display, window, width, height,
1623 XDefaultDepth (display, screen));
1625 if (mask_pixmap)
1626 XFreePixmap (display, mask_pixmap);
1627 mask_pixmap =
1628 XCreatePixmap (display, window, width, height,
1629 XDefaultDepth (display, screen));
1630 #ifdef HAVE_XRENDER
1631 if (main_picture)
1633 XRenderFreePicture (display, main_picture);
1634 main_picture = 0;
1636 if (mask_picture)
1638 XRenderFreePicture (display, mask_picture);
1639 mask_picture = 0;
1641 if (use_xrender)
1643 main_picture = XRenderCreatePicture (display, main_pixmap,
1644 XRenderFindVisualFormat(display,
1645 DefaultVisual(display, screen)), 0, 0);
1646 mask_picture = XRenderCreatePicture (display, mask_pixmap,
1647 XRenderFindVisualFormat(display,
1648 DefaultVisual(display, screen)), 0, 0);
1649 if (!main_picture || !mask_picture)
1650 use_xrender = 0;
1652 #endif /* HAVE_XRENDER */
1654 if (mask_bitmap)
1655 XFreePixmap (display, mask_bitmap);
1656 mask_bitmap = XCreatePixmap (display, window, width, height, 1);
1658 pixmap = use_mask ? main_pixmap : mask_pixmap;
1659 pixmap_w = width;
1660 pixmap_h = height;
1663 static void
1664 work_area_resize (Widget work_area, void *me,
1665 XmDrawingAreaCallbackStruct * cbs)
1667 XColor color;
1668 Dimension width, height;
1670 show_crosshair (0);
1672 n = 0;
1673 stdarg (XtNwidth, &width);
1674 stdarg (XtNheight, &height);
1675 stdarg (XmNbackground, &bgcolor);
1676 XtGetValues (work_area, args, n);
1677 view_width = width;
1678 view_height = height;
1680 color.pixel = bgcolor;
1681 XQueryColor (display, colormap, &color);
1682 bgred = color.red;
1683 bggreen = color.green;
1684 bgblue = color.blue;
1686 if (!window)
1687 return;
1689 work_area_make_pixmaps (view_width, view_height);
1691 zoom_by (1, 0, 0);
1694 static void
1695 work_area_first_expose (Widget work_area, void *me,
1696 XmDrawingAreaCallbackStruct * cbs)
1698 int c;
1699 Dimension width, height;
1700 static char dashes[] = { 4, 4 };
1702 window = XtWindow (work_area);
1703 my_gc = XCreateGC (display, window, 0, 0);
1705 arc1_gc = XCreateGC (display, window, 0, 0);
1706 c = lesstif_parse_color ("#804000");
1707 XSetForeground (display, arc1_gc, c);
1708 arc2_gc = XCreateGC (display, window, 0, 0);
1709 c = lesstif_parse_color ("#004080");
1710 XSetForeground (display, arc2_gc, c);
1711 XSetLineAttributes (display, arc1_gc, 1, LineOnOffDash, 0, 0);
1712 XSetLineAttributes (display, arc2_gc, 1, LineOnOffDash, 0, 0);
1713 XSetDashes (display, arc1_gc, 0, dashes, 2);
1714 XSetDashes (display, arc2_gc, 0, dashes, 2);
1716 n = 0;
1717 stdarg (XtNwidth, &width);
1718 stdarg (XtNheight, &height);
1719 stdarg (XmNbackground, &bgcolor);
1720 XtGetValues (work_area, args, n);
1721 view_width = width;
1722 view_height = height;
1724 offlimit_color = lesstif_parse_color (Settings.OffLimitColor);
1725 grid_color = lesstif_parse_color (Settings.GridColor);
1727 bg_gc = XCreateGC (display, window, 0, 0);
1728 XSetForeground (display, bg_gc, bgcolor);
1730 work_area_make_pixmaps (width, height);
1732 #ifdef HAVE_XRENDER
1733 if (use_xrender)
1735 XRenderPictureAttributes pa;
1736 XRenderColor a = {0, 0, 0, 0x8000};
1738 pale_pixmap = XCreatePixmap (display, window, 1, 1, 8);
1739 pa.repeat = True;
1740 pale_picture = XRenderCreatePicture (display, pale_pixmap,
1741 XRenderFindStandardFormat(display, PictStandardA8),
1742 CPRepeat, &pa);
1743 if (pale_picture)
1744 XRenderFillRectangle(display, PictOpSrc, pale_picture, &a, 0, 0, 1, 1);
1745 else
1746 use_xrender = 0;
1748 #endif /* HAVE_XRENDER */
1750 clip_gc = XCreateGC (display, window, 0, 0);
1751 bset_gc = XCreateGC (display, mask_bitmap, 0, 0);
1752 XSetForeground (display, bset_gc, 1);
1753 bclear_gc = XCreateGC (display, mask_bitmap, 0, 0);
1754 XSetForeground (display, bclear_gc, 0);
1756 XtRemoveCallback (work_area, XmNexposeCallback,
1757 (XtCallbackProc) work_area_first_expose, 0);
1758 XtAddCallback (work_area, XmNexposeCallback,
1759 (XtCallbackProc) work_area_expose, 0);
1760 lesstif_invalidate_all ();
1763 static Widget
1764 make_message (char *name, Widget left, int resizeable)
1766 Widget w, f;
1767 n = 0;
1768 if (left)
1770 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
1771 stdarg (XmNleftWidget, XtParent(left));
1773 else
1775 stdarg (XmNleftAttachment, XmATTACH_FORM);
1777 stdarg (XmNtopAttachment, XmATTACH_FORM);
1778 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1779 stdarg (XmNshadowType, XmSHADOW_IN);
1780 stdarg (XmNshadowThickness, 1);
1781 stdarg (XmNalignment, XmALIGNMENT_CENTER);
1782 stdarg (XmNmarginWidth, 4);
1783 stdarg (XmNmarginHeight, 1);
1784 if (!resizeable)
1785 stdarg (XmNresizePolicy, XmRESIZE_GROW);
1786 f = XmCreateForm (messages, name, args, n);
1787 XtManageChild (f);
1788 n = 0;
1789 stdarg (XmNtopAttachment, XmATTACH_FORM);
1790 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1791 stdarg (XmNleftAttachment, XmATTACH_FORM);
1792 stdarg (XmNrightAttachment, XmATTACH_FORM);
1793 w = XmCreateLabel (f, name, args, n);
1794 XtManageChild (w);
1795 return w;
1798 static void
1799 lesstif_do_export (HID_Attr_Val * options)
1801 Dimension width, height;
1802 Widget menu;
1803 Widget work_area_frame;
1805 n = 0;
1806 stdarg (XtNwidth, &width);
1807 stdarg (XtNheight, &height);
1808 XtGetValues (appwidget, args, n);
1810 if (width < 1)
1811 width = 640;
1812 if (width > XDisplayWidth (display, screen))
1813 width = XDisplayWidth (display, screen);
1814 if (height < 1)
1815 height = 480;
1816 if (height > XDisplayHeight (display, screen))
1817 height = XDisplayHeight (display, screen);
1819 n = 0;
1820 stdarg (XmNwidth, width);
1821 stdarg (XmNheight, height);
1822 XtSetValues (appwidget, args, n);
1824 stdarg (XmNspacing, 0);
1825 mainwind = XmCreateMainWindow (appwidget, "mainWind", args, n);
1826 XtManageChild (mainwind);
1828 n = 0;
1829 stdarg (XmNmarginWidth, 0);
1830 stdarg (XmNmarginHeight, 0);
1831 menu = lesstif_menu (mainwind, "menubar", args, n);
1832 XtManageChild (menu);
1834 n = 0;
1835 stdarg (XmNshadowType, XmSHADOW_IN);
1836 work_area_frame =
1837 XmCreateFrame (mainwind, "work_area_frame", args, n);
1838 XtManageChild (work_area_frame);
1840 n = 0;
1841 do_color (Settings.BackgroundColor, XmNbackground);
1842 work_area = XmCreateDrawingArea (work_area_frame, "work_area", args, n);
1843 XtManageChild (work_area);
1844 XtAddCallback (work_area, XmNexposeCallback,
1845 (XtCallbackProc) work_area_first_expose, 0);
1846 XtAddCallback (work_area, XmNresizeCallback,
1847 (XtCallbackProc) work_area_resize, 0);
1848 /* A regular callback won't work here, because lesstif swallows any
1849 Ctrl<Button>1 event. */
1850 XtAddEventHandler (work_area,
1851 ButtonPressMask | ButtonReleaseMask
1852 | PointerMotionMask | PointerMotionHintMask
1853 | KeyPressMask | KeyReleaseMask
1854 | EnterWindowMask | LeaveWindowMask,
1855 0, work_area_input, 0);
1857 n = 0;
1858 stdarg (XmNorientation, XmVERTICAL);
1859 stdarg (XmNprocessingDirection, XmMAX_ON_BOTTOM);
1860 stdarg (XmNmaximum, PCB->MaxHeight ? PCB->MaxHeight : 1);
1861 vscroll = XmCreateScrollBar (mainwind, "vscroll", args, n);
1862 XtAddCallback (vscroll, XmNvalueChangedCallback,
1863 (XtCallbackProc) scroll_callback, (XtPointer) & view_top_y);
1864 XtAddCallback (vscroll, XmNdragCallback, (XtCallbackProc) scroll_callback,
1865 (XtPointer) & view_top_y);
1866 XtManageChild (vscroll);
1868 n = 0;
1869 stdarg (XmNorientation, XmHORIZONTAL);
1870 stdarg (XmNmaximum, PCB->MaxWidth ? PCB->MaxWidth : 1);
1871 hscroll = XmCreateScrollBar (mainwind, "hscroll", args, n);
1872 XtAddCallback (hscroll, XmNvalueChangedCallback,
1873 (XtCallbackProc) scroll_callback, (XtPointer) & view_left_x);
1874 XtAddCallback (hscroll, XmNdragCallback, (XtCallbackProc) scroll_callback,
1875 (XtPointer) & view_left_x);
1876 XtManageChild (hscroll);
1878 n = 0;
1879 stdarg (XmNresize, True);
1880 stdarg (XmNresizePolicy, XmRESIZE_ANY);
1881 messages = XmCreateForm (mainwind, "messages", args, n);
1882 XtManageChild (messages);
1884 n = 0;
1885 stdarg (XmNtopAttachment, XmATTACH_FORM);
1886 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1887 stdarg (XmNleftAttachment, XmATTACH_FORM);
1888 stdarg (XmNrightAttachment, XmATTACH_FORM);
1889 stdarg (XmNalignment, XmALIGNMENT_CENTER);
1890 stdarg (XmNshadowThickness, 2);
1891 m_click = XmCreateLabel (messages, "click", args, n);
1893 n = 0;
1894 stdarg (XmNtopAttachment, XmATTACH_FORM);
1895 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1896 stdarg (XmNleftAttachment, XmATTACH_FORM);
1897 stdarg (XmNlabelString, XmStringCreatePCB ("Command: "));
1898 m_cmd_label = XmCreateLabel (messages, "command", args, n);
1900 n = 0;
1901 stdarg (XmNtopAttachment, XmATTACH_FORM);
1902 stdarg (XmNbottomAttachment, XmATTACH_FORM);
1903 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
1904 stdarg (XmNleftWidget, m_cmd_label);
1905 stdarg (XmNrightAttachment, XmATTACH_FORM);
1906 stdarg (XmNshadowThickness, 1);
1907 stdarg (XmNhighlightThickness, 0);
1908 stdarg (XmNmarginWidth, 2);
1909 stdarg (XmNmarginHeight, 2);
1910 m_cmd = XmCreateTextField (messages, "command", args, n);
1911 XtAddCallback (m_cmd, XmNactivateCallback,
1912 (XtCallbackProc) command_callback, 0);
1913 XtAddCallback (m_cmd, XmNlosingFocusCallback,
1914 (XtCallbackProc) command_callback, 0);
1915 XtAddEventHandler (m_cmd, KeyPressMask, 0, command_event_handler, 0);
1917 m_mark = make_message ("m_mark", 0, 0);
1918 m_crosshair = make_message ("m_crosshair", m_mark, 0);
1919 m_grid = make_message ("m_grid", m_crosshair, 1);
1920 m_zoom = make_message ("m_zoom", m_grid, 1);
1921 lesstif_m_layer = make_message ("m_layer", m_zoom, 0);
1922 m_mode = make_message ("m_mode", lesstif_m_layer, 1);
1923 m_rats = make_message ("m_rats", m_mode, 1);
1924 m_status = make_message ("m_status", m_mode, 1);
1926 XtUnmanageChild (XtParent (m_mark));
1927 XtUnmanageChild (XtParent (m_rats));
1929 n = 0;
1930 stdarg (XmNrightAttachment, XmATTACH_FORM);
1931 XtSetValues (XtParent (m_status), args, n);
1933 /* We'll use this later. */
1934 n = 0;
1935 stdarg (XmNleftWidget, XtParent (m_mark));
1936 XtSetValues (XtParent (m_crosshair), args, n);
1938 n = 0;
1939 stdarg (XmNmessageWindow, messages);
1940 XtSetValues (mainwind, args, n);
1942 if (background_image_file)
1943 LoadBackgroundImage (background_image_file);
1945 XtRealizeWidget (appwidget);
1947 while (!window)
1949 XEvent e;
1950 XtAppNextEvent (app_context, &e);
1951 XtDispatchEvent (&e);
1954 PCBChanged (0, 0, 0, 0);
1956 XtAppMainLoop (app_context);
1959 #if 0
1960 XrmOptionDescRec lesstif_options[] = {
1963 XtResource lesstif_resources[] = {
1965 #endif
1967 typedef union
1969 int i;
1970 double f;
1971 char *s;
1972 Coord c;
1973 } val_union;
1975 static Boolean
1976 pcb_cvt_string_to_double (Display * d, XrmValue * args, Cardinal * num_args,
1977 XrmValue * from, XrmValue * to, XtPointer * data)
1979 static double rv;
1980 rv = strtod ((char *) from->addr, 0);
1981 if (to->addr)
1982 *(double *) to->addr = rv;
1983 else
1984 to->addr = (XPointer) & rv;
1985 to->size = sizeof (rv);
1986 return True;
1989 static Boolean
1990 pcb_cvt_string_to_coord (Display * d, XrmValue * args, Cardinal * num_args,
1991 XrmValue * from, XrmValue * to, XtPointer *data)
1993 static Coord rv;
1994 rv = GetValue ((char *) from->addr, NULL, NULL);
1995 if (to->addr)
1996 *(Coord *) to->addr = rv;
1997 else
1998 to->addr = (XPointer) &rv;
1999 to->size = sizeof (rv);
2000 return TRUE;
2003 static void
2004 mainwind_delete_cb ()
2006 hid_action ("Quit");
2009 static void
2010 lesstif_listener_cb (XtPointer client_data, int *fid, XtInputId *id)
2012 char buf[BUFSIZ];
2013 int nbytes;
2015 if ((nbytes = read (*fid, buf, BUFSIZ)) == -1)
2016 perror ("lesstif_listener_cb");
2018 if (nbytes)
2020 buf[nbytes] = '\0';
2021 hid_parse_actions (buf);
2025 static void
2026 lesstif_parse_arguments (int *argc, char ***argv)
2028 Atom close_atom;
2029 HID_AttrNode *ha;
2030 int acount = 0, amax;
2031 int rcount = 0, rmax;
2032 int i;
2033 XrmOptionDescRec *new_options;
2034 XtResource *new_resources;
2035 val_union *new_values;
2036 int render_event, render_error;
2038 XtSetTypeConverter (XtRString,
2039 XtRDouble,
2040 pcb_cvt_string_to_double, NULL, 0, XtCacheAll, NULL);
2041 XtSetTypeConverter (XtRString,
2042 XtRPCBCoord,
2043 pcb_cvt_string_to_coord, NULL, 0, XtCacheAll, NULL);
2046 for (ha = hid_attr_nodes; ha; ha = ha->next)
2047 for (i = 0; i < ha->n; i++)
2049 HID_Attribute *a = ha->attributes + i;
2050 switch (a->type)
2052 case HID_Integer:
2053 case HID_Coord:
2054 case HID_Real:
2055 case HID_String:
2056 case HID_Path:
2057 case HID_Boolean:
2058 acount++;
2059 rcount++;
2060 break;
2061 default:
2062 break;
2066 #if 0
2067 amax = acount + XtNumber (lesstif_options);
2068 #else
2069 amax = acount;
2070 #endif
2072 new_options = (XrmOptionDescRec *) malloc ((amax + 1) * sizeof (XrmOptionDescRec));
2074 #if 0
2075 memcpy (new_options + acount, lesstif_options, sizeof (lesstif_options));
2076 #endif
2077 acount = 0;
2079 #if 0
2080 rmax = rcount + XtNumber (lesstif_resources);
2081 #else
2082 rmax = rcount;
2083 #endif
2085 new_resources = (XtResource *) malloc ((rmax + 1) * sizeof (XtResource));
2086 new_values = (val_union *) malloc ((rmax + 1) * sizeof (val_union));
2087 #if 0
2088 memcpy (new_resources + acount, lesstif_resources,
2089 sizeof (lesstif_resources));
2090 #endif
2091 rcount = 0;
2093 for (ha = hid_attr_nodes; ha; ha = ha->next)
2094 for (i = 0; i < ha->n; i++)
2096 HID_Attribute *a = ha->attributes + i;
2097 XrmOptionDescRec *o = new_options + acount;
2098 char *tmpopt, *tmpres;
2099 XtResource *r = new_resources + rcount;
2101 tmpopt = (char *) malloc (strlen (a->name) + 3);
2102 tmpopt[0] = tmpopt[1] = '-';
2103 strcpy (tmpopt + 2, a->name);
2104 o->option = tmpopt;
2106 tmpres = (char *) malloc (strlen (a->name) + 2);
2107 tmpres[0] = '*';
2108 strcpy (tmpres + 1, a->name);
2109 o->specifier = tmpres;
2111 switch (a->type)
2113 case HID_Integer:
2114 case HID_Coord:
2115 case HID_Real:
2116 case HID_String:
2117 case HID_Path:
2118 o->argKind = XrmoptionSepArg;
2119 o->value = 0;
2120 acount++;
2121 break;
2122 case HID_Boolean:
2123 o->argKind = XrmoptionNoArg;
2124 o->value = "True";
2125 acount++;
2126 break;
2127 default:
2128 break;
2131 r->resource_name = a->name;
2132 r->resource_class = a->name;
2133 r->resource_offset = sizeof (val_union) * rcount;
2135 switch (a->type)
2137 case HID_Integer:
2138 r->resource_type = XtRInt;
2139 r->default_type = XtRInt;
2140 r->resource_size = sizeof (int);
2141 r->default_addr = &(a->default_val.int_value);
2142 rcount++;
2143 break;
2144 case HID_Coord:
2145 r->resource_type = XtRPCBCoord;
2146 r->default_type = XtRPCBCoord;
2147 r->resource_size = sizeof (Coord);
2148 r->default_addr = &(a->default_val.coord_value);
2149 rcount++;
2150 break;
2151 case HID_Real:
2152 r->resource_type = XtRDouble;
2153 r->default_type = XtRDouble;
2154 r->resource_size = sizeof (double);
2155 r->default_addr = &(a->default_val.real_value);
2156 rcount++;
2157 break;
2158 case HID_String:
2159 case HID_Path:
2160 r->resource_type = XtRString;
2161 r->default_type = XtRString;
2162 r->resource_size = sizeof (char *);
2163 r->default_addr = (char *) a->default_val.str_value;
2164 rcount++;
2165 break;
2166 case HID_Boolean:
2167 r->resource_type = XtRBoolean;
2168 r->default_type = XtRInt;
2169 r->resource_size = sizeof (int);
2170 r->default_addr = &(a->default_val.int_value);
2171 rcount++;
2172 break;
2173 default:
2174 break;
2177 #if 0
2178 for (i = 0; i < XtNumber (lesstif_resources); i++)
2180 XtResource *r = new_resources + rcount;
2181 r->resource_offset = sizeof (val_union) * rcount;
2182 rcount++;
2184 #endif
2186 n = 0;
2187 stdarg (XmNdeleteResponse, XmDO_NOTHING);
2189 appwidget = XtAppInitialize (&app_context,
2190 "Pcb",
2191 new_options, amax, argc, *argv, 0, args, n);
2193 display = XtDisplay (appwidget);
2194 screen_s = XtScreen (appwidget);
2195 screen = XScreenNumberOfScreen (screen_s);
2196 colormap = XDefaultColormap (display, screen);
2198 close_atom = XmInternAtom (display, "WM_DELETE_WINDOW", 0);
2199 XmAddWMProtocolCallback (appwidget, close_atom,
2200 (XtCallbackProc) mainwind_delete_cb, 0);
2202 /* XSynchronize(display, True); */
2204 XtGetApplicationResources (appwidget, new_values, new_resources,
2205 rmax, 0, 0);
2207 #ifdef HAVE_XRENDER
2208 use_xrender = XRenderQueryExtension (display, &render_event, &render_error) &&
2209 XRenderFindVisualFormat (display, DefaultVisual(display, screen));
2210 #ifdef HAVE_XINERAMA
2211 /* Xinerama and XRender don't get along well */
2212 if (XineramaQueryExtension (display, &render_event, &render_error)
2213 && XineramaIsActive (display))
2214 use_xrender = 0;
2215 #endif /* HAVE_XINERAMA */
2216 #endif /* HAVE_XRENDER */
2218 rcount = 0;
2219 for (ha = hid_attr_nodes; ha; ha = ha->next)
2220 for (i = 0; i < ha->n; i++)
2222 HID_Attribute *a = ha->attributes + i;
2223 val_union *v = new_values + rcount;
2224 switch (a->type)
2226 case HID_Integer:
2227 if (a->value)
2228 *(int *) a->value = v->i;
2229 else
2230 a->default_val.int_value = v->i;
2231 rcount++;
2232 break;
2233 case HID_Coord:
2234 if (a->value)
2235 *(Coord *) a->value = v->c;
2236 else
2237 a->default_val.coord_value = v->c;
2238 rcount++;
2239 break;
2240 case HID_Boolean:
2241 if (a->value)
2242 *(char *) a->value = v->i;
2243 else
2244 a->default_val.int_value = v->i;
2245 rcount++;
2246 break;
2247 case HID_Real:
2248 if (a->value)
2249 *(double *) a->value = v->f;
2250 else
2251 a->default_val.real_value = v->f;
2252 rcount++;
2253 break;
2254 case HID_String:
2255 case HID_Path:
2256 if (a->value)
2257 *(char **) a->value = v->s;
2258 else
2259 a->default_val.str_value = v->s;
2260 rcount++;
2261 break;
2262 default:
2263 break;
2267 /* redefine colormap, if requested via "-install" */
2268 if (use_private_colormap)
2270 colormap = XCopyColormapAndFree (display, colormap);
2271 XtVaSetValues (appwidget, XtNcolormap, colormap, NULL);
2274 /* listen on standard input for actions */
2275 if (stdin_listen)
2277 XtAppAddInput (app_context, fileno (stdin), (XtPointer) XtInputReadMask,
2278 lesstif_listener_cb, NULL);
2282 static void
2283 draw_grid ()
2285 static XPoint *points = 0;
2286 static int npoints = 0;
2287 Coord x1, y1, x2, y2, prevx;
2288 Coord x, y;
2289 int n;
2290 static GC grid_gc = 0;
2292 if (!Settings.DrawGrid)
2293 return;
2294 if (Vz (PCB->Grid) < MIN_GRID_DISTANCE)
2295 return;
2296 if (!grid_gc)
2298 grid_gc = XCreateGC (display, window, 0, 0);
2299 XSetFunction (display, grid_gc, GXxor);
2300 XSetForeground (display, grid_gc, grid_color);
2302 if (flip_x)
2304 x2 = GridFit (Px (0), PCB->Grid, PCB->GridOffsetX);
2305 x1 = GridFit (Px (view_width), PCB->Grid, PCB->GridOffsetX);
2306 if (Vx (x2) < 0)
2307 x2 -= PCB->Grid;
2308 if (Vx (x1) >= view_width)
2309 x1 += PCB->Grid;
2311 else
2313 x1 = GridFit (Px (0), PCB->Grid, PCB->GridOffsetX);
2314 x2 = GridFit (Px (view_width), PCB->Grid, PCB->GridOffsetX);
2315 if (Vx (x1) < 0)
2316 x1 += PCB->Grid;
2317 if (Vx (x2) >= view_width)
2318 x2 -= PCB->Grid;
2320 if (flip_y)
2322 y2 = GridFit (Py (0), PCB->Grid, PCB->GridOffsetY);
2323 y1 = GridFit (Py (view_height), PCB->Grid, PCB->GridOffsetY);
2324 if (Vy (y2) < 0)
2325 y2 -= PCB->Grid;
2326 if (Vy (y1) >= view_height)
2327 y1 += PCB->Grid;
2329 else
2331 y1 = GridFit (Py (0), PCB->Grid, PCB->GridOffsetY);
2332 y2 = GridFit (Py (view_height), PCB->Grid, PCB->GridOffsetY);
2333 if (Vy (y1) < 0)
2334 y1 += PCB->Grid;
2335 if (Vy (y2) >= view_height)
2336 y2 -= PCB->Grid;
2338 n = (x2 - x1) / PCB->Grid + 1;
2339 if (n > npoints)
2341 npoints = n + 10;
2342 points = (XPoint *) realloc (points, npoints * sizeof (XPoint));
2344 n = 0;
2345 prevx = 0;
2346 for (x = x1; x <= x2; x += PCB->Grid)
2348 int temp = Vx (x);
2349 points[n].x = temp;
2350 if (n)
2352 points[n].x -= prevx;
2353 points[n].y = 0;
2355 prevx = temp;
2356 n++;
2358 for (y = y1; y <= y2; y += PCB->Grid)
2360 int vy = Vy (y);
2361 points[0].y = vy;
2362 XDrawPoints (display, pixmap, grid_gc, points, n, CoordModePrevious);
2366 static void
2367 mark_delta_to_widget (Coord dx, Coord dy, Widget w)
2369 char *buf;
2370 double g = coord_to_unit (Settings.grid_unit, PCB->Grid);
2371 int prec;
2372 XmString ms;
2374 /* Integer-sized grid? */
2375 if (((int) (g * 10000 + 0.5) % 10000) == 0)
2376 prec = 0;
2377 else
2378 prec = Settings.grid_unit->default_prec;
2380 if (dx == 0 && dy == 0)
2381 buf = pcb_g_strdup_printf ("%m+%+.*mS, %+.*mS", UUNIT, prec, dx, prec, dy);
2382 else
2384 Angle angle = atan2 (dy, -dx) * 180 / M_PI;
2385 Coord dist = Distance (0, 0, dx, dy);
2387 buf = pcb_g_strdup_printf ("%m+%+.*mS, %+.*mS (%.*mS, %d\260)", UUNIT,
2388 prec, dx, prec, dy, prec, dist, angle);
2391 ms = XmStringCreatePCB (buf);
2392 n = 0;
2393 stdarg (XmNlabelString, ms);
2394 XtSetValues (w, args, n);
2395 g_free (buf);
2398 static int
2399 cursor_pos_to_widget (Coord x, Coord y, Widget w, int prev_state)
2401 int this_state = prev_state;
2402 static char *buf;
2403 double g = coord_to_unit (Settings.grid_unit, PCB->Grid);
2404 XmString ms;
2405 int prec;
2407 /* Determine necessary precision (and state) based
2408 * on the user's grid setting */
2409 if (((int) (g * 10000 + 0.5) % 10000) == 0)
2411 prec = 0;
2412 this_state = Settings.grid_unit->allow;
2414 else
2416 prec = Settings.grid_unit->default_prec;
2417 this_state = -Settings.grid_unit->allow;
2420 if (x < 0)
2421 buf = g_strdup ("");
2422 else
2423 buf = pcb_g_strdup_printf ("%m+%.*mS, %.*mS", UUNIT, prec, x, prec, y);
2425 ms = XmStringCreatePCB (buf);
2426 n = 0;
2427 stdarg (XmNlabelString, ms);
2428 XtSetValues (w, args, n);
2429 g_free (buf);
2430 return this_state;
2433 #define S Settings
2435 void
2436 lesstif_update_status_line ()
2438 char *buf = NULL;
2439 char *s45 = cur_clip ();
2440 XmString xs;
2442 switch (Settings.Mode)
2444 case VIA_MODE:
2445 buf = pcb_g_strdup_printf ("%m+%.2mS/%.2mS \370=%.2mS", UUNIT,
2446 S.ViaThickness, S.Keepaway, S.ViaDrillingHole);
2447 break;
2448 case LINE_MODE:
2449 case ARC_MODE:
2450 buf = pcb_g_strdup_printf ("%m+%.2mS/%.2mS %s", UUNIT,
2451 S.LineThickness, S.Keepaway, s45);
2452 break;
2453 case RECTANGLE_MODE:
2454 case POLYGON_MODE:
2455 buf = pcb_g_strdup_printf ("%m+%.2mS %s", UUNIT, S.Keepaway, s45);
2456 break;
2457 case TEXT_MODE:
2458 buf = g_strdup_printf ("%d %%", S.TextScale);
2459 break;
2460 case MOVE_MODE:
2461 case COPY_MODE:
2462 case INSERTPOINT_MODE:
2463 case RUBBERBANDMOVE_MODE:
2464 buf = g_strdup_printf ("%s", s45);
2465 break;
2466 case NO_MODE:
2467 case PASTEBUFFER_MODE:
2468 case ROTATE_MODE:
2469 case REMOVE_MODE:
2470 case THERMAL_MODE:
2471 case ARROW_MODE:
2472 case LOCK_MODE:
2473 default:
2474 buf = g_strdup("");
2475 break;
2478 xs = XmStringCreatePCB (buf);
2479 n = 0;
2480 stdarg (XmNlabelString, xs);
2481 XtSetValues (m_status, args, n);
2482 g_free (buf);
2485 #undef S
2487 static int idle_proc_set = 0;
2488 static int need_redraw = 0;
2490 static Boolean
2491 idle_proc (XtPointer dummy)
2493 if (need_redraw)
2495 int mx, my;
2496 BoxType region;
2497 lesstif_use_mask (0);
2498 pixmap = main_pixmap;
2499 mx = view_width;
2500 my = view_height;
2501 region.X1 = Px (0);
2502 region.Y1 = Py (0);
2503 region.X2 = Px (view_width);
2504 region.Y2 = Py (view_height);
2505 if (flip_x)
2507 Coord tmp = region.X1;
2508 region.X1 = region.X2;
2509 region.X2 = tmp;
2511 if (flip_y)
2513 Coord tmp = region.Y1;
2514 region.Y1 = region.Y2;
2515 region.Y2 = tmp;
2517 XSetForeground (display, bg_gc, bgcolor);
2518 XFillRectangle (display, main_pixmap, bg_gc, 0, 0, mx, my);
2520 if (region.X1 < 0 || region.Y1 < 0
2521 || region.X2 > PCB->MaxWidth || region.Y2 > PCB->MaxHeight)
2523 int leftmost, rightmost, topmost, bottommost;
2525 leftmost = Vx (0);
2526 rightmost = Vx (PCB->MaxWidth);
2527 topmost = Vy (0);
2528 bottommost = Vy (PCB->MaxHeight);
2529 if (leftmost > rightmost) {
2530 int t = leftmost;
2531 leftmost = rightmost;
2532 rightmost = t;
2534 if (topmost > bottommost) {
2535 int t = topmost;
2536 topmost = bottommost;
2537 bottommost = t;
2539 if (leftmost < 0)
2540 leftmost = 0;
2541 if (topmost < 0)
2542 topmost = 0;
2543 if (rightmost > view_width)
2544 rightmost = view_width;
2545 if (bottommost > view_height)
2546 bottommost = view_height;
2548 XSetForeground (display, bg_gc, offlimit_color);
2550 /* L T R
2551 L x R
2552 L B R */
2554 if (leftmost > 0)
2556 XFillRectangle (display, main_pixmap, bg_gc, 0, 0,
2557 leftmost, view_height);
2559 if (rightmost < view_width)
2561 XFillRectangle (display, main_pixmap, bg_gc, rightmost+1, 0,
2562 view_width-rightmost+1, view_height);
2564 if (topmost > 0)
2566 XFillRectangle (display, main_pixmap, bg_gc, leftmost, 0,
2567 rightmost-leftmost+1, topmost);
2569 if (bottommost < view_height)
2571 XFillRectangle (display, main_pixmap, bg_gc, leftmost, bottommost+1,
2572 rightmost-leftmost+1, view_height-bottommost+1);
2575 DrawBackgroundImage();
2576 hid_expose_callback (&lesstif_hid, &region, 0);
2577 draw_grid ();
2578 lesstif_use_mask (0);
2579 show_crosshair (0); /* To keep the drawn / not drawn info correct */
2580 XSetFunction (display, my_gc, GXcopy);
2581 XCopyArea (display, main_pixmap, window, my_gc, 0, 0, view_width,
2582 view_height, 0, 0);
2583 pixmap = window;
2584 if (crosshair_on)
2586 DrawAttached ();
2587 DrawMark ();
2589 need_redraw = 0;
2593 static int c_x = -2, c_y = -2;
2594 static MarkType saved_mark;
2595 static const Unit *old_grid_unit = NULL;
2596 if (crosshair_x != c_x || crosshair_y != c_y
2597 || Settings.grid_unit != old_grid_unit
2598 || memcmp (&saved_mark, &Marked, sizeof (MarkType)))
2600 static int last_state = 0;
2601 static int this_state = 0;
2603 c_x = crosshair_x;
2604 c_y = crosshair_y;
2606 this_state =
2607 cursor_pos_to_widget (crosshair_x, crosshair_y, m_crosshair,
2608 this_state);
2609 if (Marked.status)
2610 mark_delta_to_widget (crosshair_x - Marked.X, crosshair_y - Marked.Y,
2611 m_mark);
2613 if (Marked.status != saved_mark.status)
2615 if (Marked.status)
2617 XtManageChild (XtParent (m_mark));
2618 XtManageChild (m_mark);
2619 n = 0;
2620 stdarg (XmNleftAttachment, XmATTACH_WIDGET);
2621 stdarg (XmNleftWidget, XtParent (m_mark));
2622 XtSetValues (XtParent (m_crosshair), args, n);
2624 else
2626 n = 0;
2627 stdarg (XmNleftAttachment, XmATTACH_FORM);
2628 XtSetValues (XtParent (m_crosshair), args, n);
2629 XtUnmanageChild (XtParent (m_mark));
2631 last_state = this_state + 100;
2633 memcpy (&saved_mark, &Marked, sizeof (MarkType));
2635 if (old_grid_unit != Settings.grid_unit)
2637 old_grid_unit = Settings.grid_unit;
2638 /* Force a resize on units change. */
2639 last_state ++;
2642 /* This is obtuse. We want to enable XmRESIZE_ANY long enough
2643 to shrink to fit the new format (if any), then switch it
2644 back to XmRESIZE_GROW to prevent it from shrinking due to
2645 changes in the number of actual digits printed. Thus, when
2646 you switch from a small grid and %.2f formats to a large
2647 grid and %d formats, you aren't punished with a wide and
2648 mostly white-space label widget. "this_state" indicates
2649 which of the above formats we're using. "last_state" is
2650 either zero (when resizing) or the same as "this_state"
2651 (when grow-only), or a non-zero but not "this_state" which
2652 means we need to start a resize cycle. */
2653 if (this_state != last_state && last_state)
2655 n = 0;
2656 stdarg (XmNresizePolicy, XmRESIZE_ANY);
2657 XtSetValues (XtParent (m_mark), args, n);
2658 XtSetValues (XtParent (m_crosshair), args, n);
2659 last_state = 0;
2661 else if (this_state != last_state)
2663 n = 0;
2664 stdarg (XmNresizePolicy, XmRESIZE_GROW);
2665 XtSetValues (XtParent (m_mark), args, n);
2666 XtSetValues (XtParent (m_crosshair), args, n);
2667 last_state = this_state;
2673 static Coord old_grid = -1;
2674 static Coord old_gx, old_gy;
2675 static const Unit *old_unit;
2676 XmString ms;
2677 if (PCB->Grid != old_grid
2678 || PCB->GridOffsetX != old_gx
2679 || PCB->GridOffsetY != old_gy || Settings.grid_unit != old_unit)
2681 static char buf[100];
2682 old_grid = PCB->Grid;
2683 old_unit = Settings.grid_unit;
2684 old_gx = PCB->GridOffsetX;
2685 old_gy = PCB->GridOffsetY;
2686 if (old_grid == 1)
2688 strcpy (buf, "No Grid");
2690 else
2692 if (old_gx || old_gy)
2693 pcb_sprintf (buf, "%m+%$mS @%mS,%mS", UUNIT, old_grid, old_gx, old_gy);
2694 else
2695 pcb_sprintf (buf, "%m+%$mS", UUNIT, old_grid);
2697 ms = XmStringCreatePCB (buf);
2698 n = 0;
2699 stdarg (XmNlabelString, ms);
2700 XtSetValues (m_grid, args, n);
2705 static double old_zoom = -1;
2706 static const Unit *old_grid_unit = NULL;
2707 if (view_zoom != old_zoom || Settings.grid_unit != old_grid_unit)
2709 gchar *buf = pcb_g_strdup_printf ("%m+%$mS/pix",
2710 Settings.grid_unit->allow, (Coord) view_zoom);
2711 XmString ms;
2713 old_zoom = view_zoom;
2714 old_grid_unit = Settings.grid_unit;
2716 ms = XmStringCreatePCB (buf);
2717 n = 0;
2718 stdarg (XmNlabelString, ms);
2719 XtSetValues (m_zoom, args, n);
2720 g_free (buf);
2725 if (old_cursor_mode != Settings.Mode)
2727 char *s = "None";
2728 XmString ms;
2729 int cursor = -1;
2730 static int free_cursor = 0;
2732 old_cursor_mode = Settings.Mode;
2733 switch (Settings.Mode)
2735 case NO_MODE:
2736 s = "None";
2737 cursor = XC_X_cursor;
2738 break;
2739 case VIA_MODE:
2740 s = "Via";
2741 cursor = -1;
2742 break;
2743 case LINE_MODE:
2744 s = "Line";
2745 cursor = XC_pencil;
2746 break;
2747 case RECTANGLE_MODE:
2748 s = "Rectangle";
2749 cursor = XC_ul_angle;
2750 break;
2751 case POLYGON_MODE:
2752 s = "Polygon";
2753 cursor = XC_sb_up_arrow;
2754 break;
2755 case POLYGONHOLE_MODE:
2756 s = "Polygon Hole";
2757 cursor = XC_sb_up_arrow;
2758 break;
2759 case PASTEBUFFER_MODE:
2760 s = "Paste";
2761 cursor = XC_hand1;
2762 break;
2763 case TEXT_MODE:
2764 s = "Text";
2765 cursor = XC_xterm;
2766 break;
2767 case ROTATE_MODE:
2768 s = "Rotate";
2769 cursor = XC_exchange;
2770 break;
2771 case REMOVE_MODE:
2772 s = "Remove";
2773 cursor = XC_pirate;
2774 break;
2775 case MOVE_MODE:
2776 s = "Move";
2777 cursor = XC_crosshair;
2778 break;
2779 case COPY_MODE:
2780 s = "Copy";
2781 cursor = XC_crosshair;
2782 break;
2783 case INSERTPOINT_MODE:
2784 s = "Insert";
2785 cursor = XC_dotbox;
2786 break;
2787 case RUBBERBANDMOVE_MODE:
2788 s = "RBMove";
2789 cursor = XC_top_left_corner;
2790 break;
2791 case THERMAL_MODE:
2792 s = "Thermal";
2793 cursor = XC_iron_cross;
2794 break;
2795 case ARC_MODE:
2796 s = "Arc";
2797 cursor = XC_question_arrow;
2798 break;
2799 case ARROW_MODE:
2800 s = "Arrow";
2801 if (over_point)
2802 cursor = XC_draped_box;
2803 else
2804 cursor = XC_left_ptr;
2805 break;
2806 case LOCK_MODE:
2807 s = "Lock";
2808 cursor = XC_hand2;
2809 break;
2811 ms = XmStringCreatePCB (s);
2812 n = 0;
2813 stdarg (XmNlabelString, ms);
2814 XtSetValues (m_mode, args, n);
2816 if (free_cursor)
2818 XFreeCursor (display, my_cursor);
2819 free_cursor = 0;
2821 if (cursor == -1)
2823 static Pixmap nocur_source = 0;
2824 static Pixmap nocur_mask = 0;
2825 static Cursor nocursor = 0;
2826 if (nocur_source == 0)
2828 XColor fg, bg;
2829 nocur_source =
2830 XCreateBitmapFromData (display, window, "\0", 1, 1);
2831 nocur_mask =
2832 XCreateBitmapFromData (display, window, "\0", 1, 1);
2834 fg.red = fg.green = fg.blue = 65535;
2835 bg.red = bg.green = bg.blue = 0;
2836 fg.flags = bg.flags = DoRed | DoGreen | DoBlue;
2837 nocursor = XCreatePixmapCursor (display, nocur_source,
2838 nocur_mask, &fg, &bg, 0, 0);
2840 my_cursor = nocursor;
2842 else
2844 my_cursor = XCreateFontCursor (display, cursor);
2845 free_cursor = 1;
2847 XDefineCursor (display, window, my_cursor);
2848 lesstif_update_status_line ();
2852 static char *old_clip = 0;
2853 static int old_tscale = -1;
2854 char *new_clip = cur_clip ();
2856 if (new_clip != old_clip || Settings.TextScale != old_tscale)
2858 lesstif_update_status_line ();
2859 old_clip = new_clip;
2860 old_tscale = Settings.TextScale;
2865 static int old_nrats = -1;
2866 static char buf[20];
2868 if (old_nrats != PCB->Data->RatN)
2870 old_nrats = PCB->Data->RatN;
2871 sprintf(buf, "%d rat%s", PCB->Data->RatN, PCB->Data->RatN == 1 ? "" : "s");
2872 if (PCB->Data->RatN)
2874 XtManageChild(XtParent(m_rats));
2875 XtManageChild(m_rats);
2876 n = 0;
2877 stdarg (XmNleftWidget, m_rats);
2878 XtSetValues (XtParent (m_status), args, n);
2881 n = 0;
2882 stdarg (XmNlabelString, XmStringCreatePCB (buf));
2883 XtSetValues (m_rats, args, n);
2885 if (!PCB->Data->RatN)
2887 n = 0;
2888 stdarg (XmNleftWidget, m_mode);
2889 XtSetValues (XtParent (m_status), args, n);
2890 XtUnmanageChild(XtParent(m_rats));
2895 lesstif_update_widget_flags ();
2897 show_crosshair (1);
2898 idle_proc_set = 0;
2899 return True;
2902 void
2903 lesstif_need_idle_proc ()
2905 if (idle_proc_set || window == 0)
2906 return;
2907 XtAppAddWorkProc (app_context, idle_proc, 0);
2908 idle_proc_set = 1;
2911 static void
2912 lesstif_invalidate_lr (int l, int r, int t, int b)
2914 if (!window)
2915 return;
2917 need_redraw = 1;
2918 need_idle_proc ();
2921 void
2922 lesstif_invalidate_all (void)
2924 lesstif_invalidate_lr (0, PCB->MaxWidth, 0, PCB->MaxHeight);
2927 static void
2928 lesstif_notify_crosshair_change (bool changes_complete)
2930 static int invalidate_depth = 0;
2931 Pixmap save_pixmap;
2933 if (! my_gc)
2934 return;
2936 if (changes_complete)
2937 invalidate_depth --;
2939 if (invalidate_depth < 0)
2941 invalidate_depth = 0;
2942 /* A mismatch of changes_complete == false and == true notifications
2943 * is not expected to occur, but we will try to handle it gracefully.
2944 * As we know the crosshair will have been shown already, we must
2945 * repaint the entire view to be sure not to leave an artaefact.
2947 need_idle_proc ();
2948 return;
2951 if (invalidate_depth == 0 && crosshair_on)
2953 save_pixmap = pixmap;
2954 pixmap = window;
2955 DrawAttached ();
2956 pixmap = save_pixmap;
2959 if (!changes_complete)
2960 invalidate_depth ++;
2963 static void
2964 lesstif_notify_mark_change (bool changes_complete)
2966 static int invalidate_depth = 0;
2967 Pixmap save_pixmap;
2969 if (changes_complete)
2970 invalidate_depth --;
2972 if (invalidate_depth < 0)
2974 invalidate_depth = 0;
2975 /* A mismatch of changes_complete == false and == true notifications
2976 * is not expected to occur, but we will try to handle it gracefully.
2977 * As we know the mark will have been shown already, we must
2978 * repaint the entire view to be sure not to leave an artaefact.
2980 need_idle_proc ();
2981 return;
2984 if (invalidate_depth == 0 && crosshair_on)
2986 save_pixmap = pixmap;
2987 pixmap = window;
2988 DrawMark ();
2989 pixmap = save_pixmap;
2992 if (!changes_complete)
2993 invalidate_depth ++;
2996 static int
2997 lesstif_set_layer (const char *name, int group, int empty)
2999 int idx = group;
3000 if (idx >= 0 && idx < max_group)
3002 int n = PCB->LayerGroups.Number[group];
3003 for (idx = 0; idx < n-1; idx ++)
3005 int ni = PCB->LayerGroups.Entries[group][idx];
3006 if (ni >= 0 && ni < max_copper_layer + 2
3007 && PCB->Data->Layer[ni].On)
3008 break;
3010 idx = PCB->LayerGroups.Entries[group][idx];
3011 #if 0
3012 if (idx == LayerStack[0]
3013 || GetLayerGroupNumberByNumber (idx) ==
3014 GetLayerGroupNumberByNumber (LayerStack[0]))
3015 autofade = 0;
3016 else
3017 autofade = 1;
3018 #endif
3020 #if 0
3021 else
3022 autofade = 0;
3023 #endif
3024 if (idx >= 0 && idx < max_copper_layer + 2)
3025 return pinout ? 1 : PCB->Data->Layer[idx].On;
3026 if (idx < 0)
3028 switch (SL_TYPE (idx))
3030 case SL_INVISIBLE:
3031 return pinout ? 0 : PCB->InvisibleObjectsOn;
3032 case SL_MASK:
3033 if (SL_MYSIDE (idx) && !pinout)
3034 return TEST_FLAG (SHOWMASKFLAG, PCB);
3035 return 0;
3036 case SL_SILK:
3037 if (SL_MYSIDE (idx) || pinout)
3038 return PCB->ElementOn;
3039 return 0;
3040 case SL_ASSY:
3041 return 0;
3042 case SL_UDRILL:
3043 case SL_PDRILL:
3044 return 1;
3045 case SL_RATS:
3046 return PCB->RatOn;
3049 return 0;
3052 static hidGC
3053 lesstif_make_gc (void)
3055 hidGC rv = (hid_gc_struct *) malloc (sizeof (hid_gc_struct));
3056 memset (rv, 0, sizeof (hid_gc_struct));
3057 rv->me_pointer = &lesstif_hid;
3058 return rv;
3061 static void
3062 lesstif_destroy_gc (hidGC gc)
3064 free (gc);
3067 static void
3068 lesstif_use_mask (int use_it)
3070 if ((TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) &&
3071 !use_xrender)
3072 use_it = 0;
3073 if ((use_it == 0) == (use_mask == 0))
3074 return;
3075 use_mask = use_it;
3076 if (pinout)
3077 return;
3078 if (!window)
3079 return;
3080 /* printf("use_mask(%d)\n", use_it); */
3081 if (!mask_pixmap)
3083 mask_pixmap =
3084 XCreatePixmap (display, window, pixmap_w, pixmap_h,
3085 XDefaultDepth (display, screen));
3086 mask_bitmap = XCreatePixmap (display, window, pixmap_w, pixmap_h, 1);
3088 if (use_it)
3090 pixmap = mask_pixmap;
3091 XSetForeground (display, my_gc, 0);
3092 XSetFunction (display, my_gc, GXcopy);
3093 XFillRectangle (display, mask_pixmap, my_gc,
3094 0, 0, view_width, view_height);
3095 XFillRectangle (display, mask_bitmap, bclear_gc,
3096 0, 0, view_width, view_height);
3098 else
3100 pixmap = main_pixmap;
3101 #ifdef HAVE_XRENDER
3102 if (use_xrender)
3104 XRenderPictureAttributes pa;
3106 pa.clip_mask = mask_bitmap;
3107 XRenderChangePicture(display, main_picture, CPClipMask, &pa);
3108 XRenderComposite(display, PictOpOver, mask_picture, pale_picture,
3109 main_picture, 0, 0, 0, 0, 0, 0, view_width, view_height);
3111 else
3112 #endif /* HAVE_XRENDER */
3114 XSetClipMask (display, clip_gc, mask_bitmap);
3115 XCopyArea (display, mask_pixmap, main_pixmap, clip_gc,
3116 0, 0, view_width, view_height, 0, 0);
3121 static void
3122 lesstif_set_color (hidGC gc, const char *name)
3124 static void *cache = 0;
3125 hidval cval;
3126 static XColor color, exact_color;
3128 if (!display)
3129 return;
3130 if (!name)
3131 name = "red";
3132 gc->colorname = name;
3133 if (strcmp (name, "erase") == 0)
3135 gc->color = bgcolor;
3136 gc->erase = 1;
3138 else if (strcmp (name, "drill") == 0)
3140 gc->color = offlimit_color;
3141 gc->erase = 0;
3143 else if (hid_cache_color (0, name, &cval, &cache))
3145 gc->color = cval.lval;
3146 gc->erase = 0;
3148 else
3150 if (!XAllocNamedColor (display, colormap, name, &color, &exact_color))
3151 color.pixel = WhitePixel (display, screen);
3152 #if 0
3153 printf ("lesstif_set_color `%s' %08x rgb/%d/%d/%d\n",
3154 name, color.pixel, color.red, color.green, color.blue);
3155 #endif
3156 cval.lval = gc->color = color.pixel;
3157 hid_cache_color (1, name, &cval, &cache);
3158 gc->erase = 0;
3160 if (autofade)
3162 static int lastcolor = -1, lastfade = -1;
3163 if (gc->color == lastcolor)
3164 gc->color = lastfade;
3165 else
3167 lastcolor = gc->color;
3168 color.pixel = gc->color;
3170 XQueryColor (display, colormap, &color);
3171 color.red = (bgred + color.red) / 2;
3172 color.green = (bggreen + color.green) / 2;
3173 color.blue = (bgblue + color.blue) / 2;
3174 XAllocColor (display, colormap, &color);
3175 lastfade = gc->color = color.pixel;
3180 static void
3181 set_gc (hidGC gc)
3183 int cap, join, width;
3184 if (gc->me_pointer != &lesstif_hid)
3186 fprintf (stderr, "Fatal: GC from another HID passed to lesstif HID\n");
3187 abort ();
3189 #if 0
3190 pcb_printf ("set_gc c%s %08lx w%#mS c%d x%d e%d\n",
3191 gc->colorname, gc->color, gc->width, gc->cap, gc->xor_set, gc->erase);
3192 #endif
3193 switch (gc->cap)
3195 case Square_Cap:
3196 cap = CapProjecting;
3197 join = JoinMiter;
3198 break;
3199 case Trace_Cap:
3200 case Round_Cap:
3201 cap = CapRound;
3202 join = JoinRound;
3203 break;
3204 case Beveled_Cap:
3205 cap = CapProjecting;
3206 join = JoinBevel;
3207 break;
3208 default:
3209 cap = CapProjecting;
3210 join = JoinBevel;
3211 break;
3213 if (gc->xor_set)
3215 XSetFunction (display, my_gc, GXxor);
3216 XSetForeground (display, my_gc, gc->color ^ bgcolor);
3218 else if (gc->erase)
3220 XSetFunction (display, my_gc, GXcopy);
3221 XSetForeground (display, my_gc, offlimit_color);
3223 else
3225 XSetFunction (display, my_gc, GXcopy);
3226 XSetForeground (display, my_gc, gc->color);
3228 width = Vz (gc->width);
3229 if (width < 0)
3230 width = 0;
3231 XSetLineAttributes (display, my_gc, width, LineSolid, cap,
3232 join);
3233 if (use_mask)
3235 if (gc->erase)
3236 mask_gc = bclear_gc;
3237 else
3238 mask_gc = bset_gc;
3239 XSetLineAttributes (display, mask_gc, Vz (gc->width), LineSolid, cap,
3240 join);
3244 static void
3245 lesstif_set_line_cap (hidGC gc, EndCapStyle style)
3247 gc->cap = style;
3250 static void
3251 lesstif_set_line_width (hidGC gc, Coord width)
3253 gc->width = width;
3256 static void
3257 lesstif_set_draw_xor (hidGC gc, int xor_set)
3259 gc->xor_set = xor_set;
3262 #define ISORT(a,b) if (a>b) { a^=b; b^=a; a^=b; }
3264 static void
3265 lesstif_draw_line (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
3267 double dx1, dy1, dx2, dy2;
3268 int vw = Vz (gc->width);
3269 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) && gc->erase)
3270 return;
3271 #if 0
3272 pcb_printf ("draw_line %#mD-%#mD @%#mS", x1, y1, x2, y2, gc->width);
3273 #endif
3274 dx1 = Vx (x1);
3275 dy1 = Vy (y1);
3276 dx2 = Vx (x2);
3277 dy2 = Vy (y2);
3278 #if 0
3279 pcb_printf (" = %#mD-%#mD %s\n", x1, y1, x2, y2, gc->colorname);
3280 #endif
3282 #if 1
3283 if (! ClipLine (0, 0, view_width, view_height,
3284 &dx1, &dy1, &dx2, &dy2, vw))
3285 return;
3286 #endif
3288 x1 = dx1;
3289 y1 = dy1;
3290 x2 = dx2;
3291 y2 = dy2;
3293 set_gc (gc);
3294 if (gc->cap == Square_Cap && x1 == x2 && y1 == y2)
3296 XFillRectangle (display, pixmap, my_gc, x1 - vw / 2, y1 - vw / 2, vw,
3297 vw);
3298 if (use_mask)
3299 XFillRectangle (display, mask_bitmap, mask_gc, x1 - vw / 2,
3300 y1 - vw / 2, vw, vw);
3302 else
3304 XDrawLine (display, pixmap, my_gc, x1, y1, x2, y2);
3305 if (use_mask)
3306 XDrawLine (display, mask_bitmap, mask_gc, x1, y1, x2, y2);
3310 static void
3311 lesstif_draw_arc (hidGC gc, Coord cx, Coord cy, Coord width, Coord height,
3312 Angle start_angle, Angle delta_angle)
3314 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase)
3315 return;
3316 #if 0
3317 pcb_printf ("draw_arc %#mD %#mSx%#mS s %d d %d", cx, cy, width, height, start_angle, delta_angle);
3318 #endif
3319 width = Vz (width);
3320 height = Vz (height);
3321 cx = Vx (cx) - width;
3322 cy = Vy (cy) - height;
3323 if (flip_x)
3325 start_angle = 180 - start_angle;
3326 delta_angle = - delta_angle;
3328 if (flip_y)
3330 start_angle = - start_angle;
3331 delta_angle = - delta_angle;
3333 start_angle = NormalizeAngle (start_angle);
3334 if (start_angle >= 180)
3335 start_angle -= 360;
3336 #if 0
3337 pcb_printf (" = %#mD %#mSx%#mS %d %s\n", cx, cy, width, height, gc->width,
3338 gc->colorname);
3339 #endif
3340 set_gc (gc);
3341 XDrawArc (display, pixmap, my_gc, cx, cy,
3342 width * 2, height * 2, (start_angle + 180) * 64,
3343 delta_angle * 64);
3344 if (use_mask && !TEST_FLAG (THINDRAWFLAG, PCB))
3345 XDrawArc (display, mask_bitmap, mask_gc, cx, cy,
3346 width * 2, height * 2, (start_angle + 180) * 64,
3347 delta_angle * 64);
3348 #if 0
3349 /* Enable this if you want to see the center and radii of drawn
3350 arcs, for debugging. */
3351 if (TEST_FLAG (THINDRAWFLAG, PCB)
3352 && delta_angle != 360)
3354 cx += width;
3355 cy += height;
3356 XDrawLine (display, pixmap, arc1_gc, cx, cy,
3357 cx - width*cos(start_angle*M_PI/180),
3358 cy + width*sin(start_angle*M_PI/180));
3359 XDrawLine (display, pixmap, arc2_gc, cx, cy,
3360 cx - width*cos((start_angle+delta_angle)*M_PI/180),
3361 cy + width*sin((start_angle+delta_angle)*M_PI/180));
3363 #endif
3366 static void
3367 lesstif_draw_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
3369 int vw = Vz (gc->width);
3370 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase)
3371 return;
3372 x1 = Vx (x1);
3373 y1 = Vy (y1);
3374 x2 = Vx (x2);
3375 y2 = Vy (y2);
3376 if (x1 < -vw && x2 < -vw)
3377 return;
3378 if (y1 < -vw && y2 < -vw)
3379 return;
3380 if (x1 > view_width + vw && x2 > view_width + vw)
3381 return;
3382 if (y1 > view_height + vw && y2 > view_height + vw)
3383 return;
3384 if (x1 > x2) { int xt = x1; x1 = x2; x2 = xt; }
3385 if (y1 > y2) { int yt = y1; y1 = y2; y2 = yt; }
3386 set_gc (gc);
3387 XDrawRectangle (display, pixmap, my_gc, x1, y1, x2 - x1 + 1, y2 - y1 + 1);
3388 if (use_mask)
3389 XDrawRectangle (display, mask_bitmap, mask_gc, x1, y1, x2 - x1 + 1,
3390 y2 - y1 + 1);
3393 static void
3394 lesstif_fill_circle (hidGC gc, Coord cx, Coord cy, Coord radius)
3396 if (pinout && use_mask && gc->erase)
3397 return;
3398 if ((TEST_FLAG (THINDRAWFLAG, PCB) || TEST_FLAG(THINDRAWPOLYFLAG, PCB)) && gc->erase)
3399 return;
3400 #if 0
3401 pcb_printf ("fill_circle %#mD %#mS", cx, cy, radius);
3402 #endif
3403 radius = Vz (radius);
3404 cx = Vx (cx) - radius;
3405 cy = Vy (cy) - radius;
3406 if (cx < -2 * radius || cx > view_width)
3407 return;
3408 if (cy < -2 * radius || cy > view_height)
3409 return;
3410 #if 0
3411 pcb_printf (" = %#mD %#mS %lx %s\n", cx, cy, radius, gc->color, gc->colorname);
3412 #endif
3413 set_gc (gc);
3414 XFillArc (display, pixmap, my_gc, cx, cy,
3415 radius * 2, radius * 2, 0, 360 * 64);
3416 if (use_mask)
3417 XFillArc (display, mask_bitmap, mask_gc, cx, cy,
3418 radius * 2, radius * 2, 0, 360 * 64);
3421 static void
3422 lesstif_fill_polygon (hidGC gc, int n_coords, Coord *x, Coord *y)
3424 static XPoint *p = 0;
3425 static int maxp = 0;
3426 int i;
3428 if (maxp < n_coords)
3430 maxp = n_coords + 10;
3431 if (p)
3432 p = (XPoint *) realloc (p, maxp * sizeof (XPoint));
3433 else
3434 p = (XPoint *) malloc (maxp * sizeof (XPoint));
3437 for (i = 0; i < n_coords; i++)
3439 p[i].x = Vx (x[i]);
3440 p[i].y = Vy (y[i]);
3442 #if 0
3443 printf ("fill_polygon %d pts\n", n_coords);
3444 #endif
3445 set_gc (gc);
3446 XFillPolygon (display, pixmap, my_gc, p, n_coords, Complex,
3447 CoordModeOrigin);
3448 if (use_mask)
3449 XFillPolygon (display, mask_bitmap, mask_gc, p, n_coords, Complex,
3450 CoordModeOrigin);
3453 static void
3454 lesstif_fill_rect (hidGC gc, Coord x1, Coord y1, Coord x2, Coord y2)
3456 int vw = Vz (gc->width);
3457 if ((pinout || TEST_FLAG (THINDRAWFLAG, PCB)) && gc->erase)
3458 return;
3459 x1 = Vx (x1);
3460 y1 = Vy (y1);
3461 x2 = Vx (x2);
3462 y2 = Vy (y2);
3463 if (x1 < -vw && x2 < -vw)
3464 return;
3465 if (y1 < -vw && y2 < -vw)
3466 return;
3467 if (x1 > view_width + vw && x2 > view_width + vw)
3468 return;
3469 if (y1 > view_height + vw && y2 > view_height + vw)
3470 return;
3471 if (x1 > x2) { int xt = x1; x1 = x2; x2 = xt; }
3472 if (y1 > y2) { int yt = y1; y1 = y2; y2 = yt; }
3473 set_gc (gc);
3474 XFillRectangle (display, pixmap, my_gc, x1, y1, x2 - x1 + 1,
3475 y2 - y1 + 1);
3476 if (use_mask)
3477 XFillRectangle (display, mask_bitmap, mask_gc, x1, y1, x2 - x1 + 1,
3478 y2 - y1 + 1);
3481 static void
3482 lesstif_calibrate (double xval, double yval)
3484 CRASH;
3487 static int
3488 lesstif_shift_is_pressed (void)
3490 return shift_pressed;
3493 static int
3494 lesstif_control_is_pressed (void)
3496 return ctrl_pressed;
3499 static int
3500 lesstif_mod1_is_pressed (void)
3502 return alt_pressed;
3505 extern void lesstif_get_coords (const char *msg, Coord *x, Coord *y);
3507 static void
3508 lesstif_set_crosshair (int x, int y, int action)
3510 if (crosshair_x != x || crosshair_y != y)
3512 lesstif_show_crosshair(0);
3513 crosshair_x = x;
3514 crosshair_y = y;
3515 need_idle_proc ();
3517 if (mainwind
3518 && !in_move_event
3519 && (x < view_left_x
3520 || x > view_left_x + view_width * view_zoom
3521 || y < view_top_y || y > view_top_y + view_height * view_zoom))
3523 view_left_x = x - (view_width * view_zoom) / 2;
3524 view_top_y = y - (view_height * view_zoom) / 2;
3525 lesstif_pan_fixup ();
3530 if (action == HID_SC_PAN_VIEWPORT)
3532 Window root, child;
3533 unsigned int keys_buttons;
3534 int pos_x, pos_y, root_x, root_y;
3535 XQueryPointer (display, window, &root, &child,
3536 &root_x, &root_y, &pos_x, &pos_y, &keys_buttons);
3537 if (flip_x)
3538 view_left_x = x - (view_width-pos_x) * view_zoom;
3539 else
3540 view_left_x = x - pos_x * view_zoom;
3541 if (flip_y)
3542 view_top_y = y - (view_height-pos_y) * view_zoom;
3543 else
3544 view_top_y = y - pos_y * view_zoom;
3545 lesstif_pan_fixup();
3546 action = HID_SC_WARP_POINTER;
3548 if (action == HID_SC_WARP_POINTER)
3550 in_move_event ++;
3551 XWarpPointer (display, None, window, 0, 0, 0, 0, Vx(x), Vy(y));
3552 in_move_event --;
3556 typedef struct
3558 void (*func) (hidval);
3559 hidval user_data;
3560 XtIntervalId id;
3561 } TimerStruct;
3563 static void
3564 lesstif_timer_cb (XtPointer * p, XtIntervalId * id)
3566 TimerStruct *ts = (TimerStruct *) p;
3567 ts->func (ts->user_data);
3568 free (ts);
3571 static hidval
3572 lesstif_add_timer (void (*func) (hidval user_data),
3573 unsigned long milliseconds, hidval user_data)
3575 TimerStruct *t;
3576 hidval rv;
3577 t = (TimerStruct *) malloc (sizeof (TimerStruct));
3578 rv.ptr = t;
3579 t->func = func;
3580 t->user_data = user_data;
3581 t->id = XtAppAddTimeOut (app_context, milliseconds, (XtTimerCallbackProc)lesstif_timer_cb, t);
3582 return rv;
3585 static void
3586 lesstif_stop_timer (hidval hv)
3588 TimerStruct *ts = (TimerStruct *) hv.ptr;
3589 XtRemoveTimeOut (ts->id);
3590 free (ts);
3594 typedef struct
3596 void (*func) ( hidval, int, unsigned int, hidval );
3597 hidval user_data;
3598 int fd;
3599 XtInputId id;
3601 WatchStruct;
3603 /* We need a wrapper around the hid file watch because to pass the correct flags
3605 static void
3606 lesstif_watch_cb (XtPointer client_data, int *fid, XtInputId * id)
3608 unsigned int pcb_condition = 0;
3609 struct pollfd fds;
3610 short condition;
3611 hidval x;
3612 WatchStruct *watch = (WatchStruct*)client_data;
3614 fds.fd = watch->fd;
3615 fds.events = POLLIN | POLLOUT;
3616 poll( &fds, 1, 0 );
3617 condition = fds.revents;
3619 // Should we only include those we were asked to watch?
3620 if (condition & POLLIN)
3621 pcb_condition |= PCB_WATCH_READABLE;
3622 if (condition & POLLOUT)
3623 pcb_condition |= PCB_WATCH_WRITABLE;
3624 if (condition & POLLERR)
3625 pcb_condition |= PCB_WATCH_ERROR;
3626 if (condition & POLLHUP)
3627 pcb_condition |= PCB_WATCH_HANGUP;
3629 x.ptr = (void *) watch;
3630 watch->func (x, watch->fd, pcb_condition, watch->user_data);
3632 return;
3635 hidval
3636 lesstif_watch_file (int fd, unsigned int condition, void (*func) (hidval watch, int fd, unsigned int condition, hidval user_data),
3637 hidval user_data)
3639 WatchStruct *watch = (WatchStruct *) malloc (sizeof(WatchStruct));
3640 hidval ret;
3641 unsigned int xt_condition = 0;
3643 if (condition & PCB_WATCH_READABLE)
3644 xt_condition |= XtInputReadMask;
3645 if (condition & PCB_WATCH_WRITABLE)
3646 xt_condition |= XtInputWriteMask;
3647 if (condition & PCB_WATCH_ERROR)
3648 xt_condition |= XtInputExceptMask;
3649 if (condition & PCB_WATCH_HANGUP)
3650 xt_condition |= XtInputExceptMask;
3652 watch->func = func;
3653 watch->user_data = user_data;
3654 watch->fd = fd;
3655 watch->id = XtAppAddInput( app_context, fd, (XtPointer) (size_t) xt_condition, lesstif_watch_cb, watch );
3657 ret.ptr = (void *) watch;
3658 return ret;
3661 void
3662 lesstif_unwatch_file (hidval data)
3664 WatchStruct *watch = (WatchStruct*)data.ptr;
3665 XtRemoveInput( watch->id );
3666 free( watch );
3669 typedef struct
3671 XtBlockHookId id;
3672 void (*func) (hidval user_data);
3673 hidval user_data;
3674 } BlockHookStruct;
3676 static void lesstif_block_hook_cb(XtPointer user_data);
3678 static void
3679 lesstif_block_hook_cb (XtPointer user_data)
3681 BlockHookStruct *block_hook = (BlockHookStruct *)user_data;
3682 block_hook->func( block_hook->user_data );
3685 static hidval
3686 lesstif_add_block_hook (void (*func) (hidval data), hidval user_data )
3688 hidval ret;
3689 BlockHookStruct *block_hook = (BlockHookStruct *) malloc( sizeof( BlockHookStruct ));
3691 block_hook->func = func;
3692 block_hook->user_data = user_data;
3694 block_hook->id = XtAppAddBlockHook( app_context, lesstif_block_hook_cb, (XtPointer)block_hook );
3696 ret.ptr = (void *) block_hook;
3697 return ret;
3700 static void
3701 lesstif_stop_block_hook (hidval mlpoll)
3703 BlockHookStruct *block_hook = (BlockHookStruct *)mlpoll.ptr;
3704 XtRemoveBlockHook( block_hook->id );
3705 free( block_hook );
3709 extern void lesstif_logv (const char *fmt, va_list ap);
3711 extern int lesstif_confirm_dialog (char *msg, ...);
3713 extern int lesstif_close_confirm_dialog ();
3715 extern void lesstif_report_dialog (char *title, char *msg);
3717 extern int
3718 lesstif_attribute_dialog (HID_Attribute * attrs,
3719 int n_attrs, HID_Attr_Val * results,
3720 const char * title, const char * descr);
3722 static void
3723 pinout_callback (Widget da, PinoutData * pd,
3724 XmDrawingAreaCallbackStruct * cbs)
3726 BoxType region;
3727 int save_vx, save_vy, save_vw, save_vh;
3728 int save_fx, save_fy;
3729 double save_vz;
3730 Pixmap save_px;
3731 int reason = cbs ? cbs->reason : 0;
3733 if (pd->window == 0 && reason == XmCR_RESIZE)
3734 return;
3735 if (pd->window == 0 || reason == XmCR_RESIZE)
3737 Dimension w, h;
3738 double z;
3740 n = 0;
3741 stdarg (XmNwidth, &w);
3742 stdarg (XmNheight, &h);
3743 XtGetValues (da, args, n);
3745 pd->window = XtWindow (da);
3746 pd->v_width = w;
3747 pd->v_height = h;
3748 pd->zoom = (pd->right - pd->left + 1) / (double) w;
3749 z = (pd->bottom - pd->top + 1) / (double) h;
3750 if (pd->zoom < z)
3751 pd->zoom = z;
3753 pd->x = (pd->left + pd->right) / 2 - pd->v_width * pd->zoom / 2;
3754 pd->y = (pd->top + pd->bottom) / 2 - pd->v_height * pd->zoom / 2;
3757 save_vx = view_left_x;
3758 save_vy = view_top_y;
3759 save_vz = view_zoom;
3760 save_vw = view_width;
3761 save_vh = view_height;
3762 save_fx = flip_x;
3763 save_fy = flip_y;
3764 save_px = pixmap;
3765 pinout = pd;
3766 pixmap = pd->window;
3767 view_left_x = pd->x;
3768 view_top_y = pd->y;
3769 view_zoom = pd->zoom;
3770 view_width = pd->v_width;
3771 view_height = pd->v_height;
3772 use_mask = 0;
3773 flip_x = flip_y = 0;
3775 region.X1 = 0;
3776 region.Y1 = 0;
3777 region.X2 = PCB->MaxWidth;
3778 region.Y2 = PCB->MaxHeight;
3780 XFillRectangle (display, pixmap, bg_gc, 0, 0, pd->v_width, pd->v_height);
3781 hid_expose_callback (&lesstif_hid, &region, pd->item);
3783 pinout = 0;
3784 view_left_x = save_vx;
3785 view_top_y = save_vy;
3786 view_zoom = save_vz;
3787 view_width = save_vw;
3788 view_height = save_vh;
3789 pixmap = save_px;
3790 flip_x = save_fx;
3791 flip_y = save_fy;
3794 static void
3795 pinout_unmap (Widget w, PinoutData * pd, void *v)
3797 if (pd->prev)
3798 pd->prev->next = pd->next;
3799 else
3800 pinouts = pd->next;
3801 if (pd->next)
3802 pd->next->prev = pd->prev;
3803 XtDestroyWidget (XtParent (pd->form));
3804 free (pd);
3807 static void
3808 lesstif_show_item (void *item)
3810 double scale;
3811 Widget da;
3812 BoxType *extents;
3813 PinoutData *pd;
3815 for (pd = pinouts; pd; pd = pd->next)
3816 if (pd->item == item)
3817 return;
3818 if (!mainwind)
3819 return;
3821 pd = (PinoutData *) calloc (1, sizeof (PinoutData));
3823 pd->item = item;
3825 extents = hid_get_extents (item);
3826 pd->left = extents->X1;
3827 pd->right = extents->X2;
3828 pd->top = extents->Y1;
3829 pd->bottom = extents->Y2;
3831 if (pd->left > pd->right)
3833 free (pd);
3834 return;
3836 pd->prev = 0;
3837 pd->next = pinouts;
3838 if (pd->next)
3839 pd->next->prev = pd;
3840 pinouts = pd;
3841 pd->zoom = 0;
3843 n = 0;
3844 pd->form = XmCreateFormDialog (mainwind, "pinout", args, n);
3845 pd->window = 0;
3846 XtAddCallback (pd->form, XmNunmapCallback, (XtCallbackProc) pinout_unmap,
3847 (XtPointer) pd);
3849 scale =
3850 sqrt (200.0 * 200.0 /
3851 ((pd->right - pd->left + 1.0) * (pd->bottom - pd->top + 1.0)));
3853 n = 0;
3854 stdarg (XmNwidth, (int) (scale * (pd->right - pd->left + 1)));
3855 stdarg (XmNheight, (int) (scale * (pd->bottom - pd->top + 1)));
3856 stdarg (XmNleftAttachment, XmATTACH_FORM);
3857 stdarg (XmNrightAttachment, XmATTACH_FORM);
3858 stdarg (XmNtopAttachment, XmATTACH_FORM);
3859 stdarg (XmNbottomAttachment, XmATTACH_FORM);
3860 da = XmCreateDrawingArea (pd->form, "pinout", args, n);
3861 XtManageChild (da);
3863 XtAddCallback (da, XmNexposeCallback, (XtCallbackProc) pinout_callback,
3864 (XtPointer) pd);
3865 XtAddCallback (da, XmNresizeCallback, (XtCallbackProc) pinout_callback,
3866 (XtPointer) pd);
3868 XtManageChild (pd->form);
3869 pinout = 0;
3872 static void
3873 lesstif_beep (void)
3875 putchar (7);
3876 fflush (stdout);
3880 static bool progress_cancelled = false;
3882 static void
3883 progress_cancel_callback (Widget w, void *v, void *cbs)
3885 progress_cancelled = true;
3888 static Widget progress_dialog = 0;
3889 static Widget progress_cancel, progress_label;
3890 static Widget progress_scale;
3892 static void
3893 lesstif_progress_dialog (int so_far, int total, const char *msg)
3895 XmString xs;
3897 if (mainwind == 0)
3898 return;
3900 if (progress_dialog == 0)
3902 Atom close_atom;
3904 n = 0;
3905 stdarg (XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON);
3906 stdarg (XmNtitle, "Progress");
3907 stdarg (XmNdialogStyle, XmDIALOG_APPLICATION_MODAL);
3908 stdarg (XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL);
3909 progress_dialog = XmCreateInformationDialog (mainwind, "progress", args, n);
3910 XtAddCallback (progress_dialog, XmNcancelCallback,
3911 (XtCallbackProc) progress_cancel_callback, NULL);
3913 progress_cancel = XmMessageBoxGetChild (progress_dialog, XmDIALOG_CANCEL_BUTTON);
3914 progress_label = XmMessageBoxGetChild (progress_dialog, XmDIALOG_MESSAGE_LABEL);
3916 XtUnmanageChild (XmMessageBoxGetChild (progress_dialog, XmDIALOG_OK_BUTTON));
3917 XtUnmanageChild (XmMessageBoxGetChild (progress_dialog, XmDIALOG_HELP_BUTTON));
3919 stdarg (XmNdefaultPosition, False);
3920 XtSetValues (progress_dialog, args, n);
3922 n = 0;
3923 stdarg(XmNminimum, 0);
3924 stdarg(XmNvalue, 0);
3925 stdarg(XmNmaximum, total > 0 ? total : 1);
3926 stdarg(XmNorientation, XmHORIZONTAL);
3927 stdarg(XmNshowArrows, false);
3928 progress_scale = XmCreateScrollBar (progress_dialog, "scale", args, n);
3929 XtManageChild (progress_scale);
3931 close_atom = XmInternAtom (display, "WM_DELETE_WINDOW", 0);
3932 XmAddWMProtocolCallback (XtParent (progress_dialog), close_atom,
3933 (XtCallbackProc) progress_cancel_callback, 0);
3936 n = 0;
3937 stdarg(XmNvalue, 0);
3938 stdarg(XmNsliderSize, (so_far <= total) ? (so_far < 0) ? 0 : so_far : total);
3939 stdarg(XmNmaximum, total > 0 ? total : 1);
3940 XtSetValues (progress_scale, args, n);
3942 n = 0;
3943 xs = XmStringCreatePCB ((char *)msg);
3944 stdarg (XmNmessageString, xs);
3945 XtSetValues (progress_dialog, args, n);
3947 return;
3950 #define MIN_TIME_SEPARATION 0.1 /* seconds */
3952 static int
3953 lesstif_progress (int so_far, int total, const char *message)
3955 static bool visible = false;
3956 static bool started = false;
3957 XEvent e;
3958 struct timeval time;
3959 double time_delta, time_now;
3960 static double time_then = 0.0;
3961 int retval = 0;
3963 if (so_far == 0 && total == 0 && message == NULL)
3965 XtUnmanageChild (progress_dialog);
3966 visible = false;
3967 started = false;
3968 progress_cancelled = false;
3969 return retval;
3972 gettimeofday (&time, NULL);
3973 time_now = time.tv_sec + time.tv_usec / 1000000.0;
3975 time_delta = time_now - time_then;
3977 if (started && time_delta < MIN_TIME_SEPARATION)
3978 return retval;
3980 /* Create or update the progress dialog */
3981 lesstif_progress_dialog (so_far, total, message);
3983 if (!started)
3985 XtManageChild (progress_dialog);
3986 started = true;
3989 /* Dispatch pending events */
3990 while (XtAppPending (app_context))
3992 XtAppNextEvent (app_context, &e);
3993 XtDispatchEvent (&e);
3995 idle_proc (NULL);
3997 /* If rendering takes a while, make sure the core has enough time to
3998 do work. */
3999 gettimeofday (&time, NULL);
4000 time_then = time.tv_sec + time.tv_usec / 1000000.0;
4002 return progress_cancelled;
4005 static HID_DRAW *
4006 lesstif_request_debug_draw (void)
4008 /* Send drawing to the backing pixmap */
4009 pixmap = main_pixmap;
4010 return lesstif_hid.graphics;
4013 static void
4014 lesstif_flush_debug_draw (void)
4016 /* Copy the backing pixmap to the display and redraw any attached objects */
4017 XSetFunction (display, my_gc, GXcopy);
4018 XCopyArea (display, main_pixmap, window, my_gc, 0, 0, view_width,
4019 view_height, 0, 0);
4020 pixmap = window;
4021 if (crosshair_on)
4023 DrawAttached ();
4024 DrawMark ();
4026 pixmap = main_pixmap;
4029 static void
4030 lesstif_finish_debug_draw (void)
4032 lesstif_flush_debug_draw ();
4033 /* No special tear down requirements
4037 #include "dolists.h"
4039 void
4040 hid_lesstif_init ()
4042 memset (&lesstif_hid, 0, sizeof (HID));
4043 memset (&lesstif_graphics, 0, sizeof (HID_DRAW));
4045 common_nogui_init (&lesstif_hid);
4046 common_draw_helpers_init (&lesstif_graphics);
4048 lesstif_hid.struct_size = sizeof (HID);
4049 lesstif_hid.name = "lesstif";
4050 lesstif_hid.description = "LessTif - a Motif clone for X/Unix";
4051 lesstif_hid.gui = 1;
4052 lesstif_hid.poly_before = 1;
4054 lesstif_hid.get_export_options = lesstif_get_export_options;
4055 lesstif_hid.do_export = lesstif_do_export;
4056 lesstif_hid.parse_arguments = lesstif_parse_arguments;
4057 lesstif_hid.invalidate_lr = lesstif_invalidate_lr;
4058 lesstif_hid.invalidate_all = lesstif_invalidate_all;
4059 lesstif_hid.notify_crosshair_change = lesstif_notify_crosshair_change;
4060 lesstif_hid.notify_mark_change = lesstif_notify_mark_change;
4061 lesstif_hid.set_layer = lesstif_set_layer;
4063 lesstif_hid.calibrate = lesstif_calibrate;
4064 lesstif_hid.shift_is_pressed = lesstif_shift_is_pressed;
4065 lesstif_hid.control_is_pressed = lesstif_control_is_pressed;
4066 lesstif_hid.mod1_is_pressed = lesstif_mod1_is_pressed;
4067 lesstif_hid.get_coords = lesstif_get_coords;
4068 lesstif_hid.set_crosshair = lesstif_set_crosshair;
4069 lesstif_hid.add_timer = lesstif_add_timer;
4070 lesstif_hid.stop_timer = lesstif_stop_timer;
4071 lesstif_hid.watch_file = lesstif_watch_file;
4072 lesstif_hid.unwatch_file = lesstif_unwatch_file;
4073 lesstif_hid.add_block_hook = lesstif_add_block_hook;
4074 lesstif_hid.stop_block_hook = lesstif_stop_block_hook;
4076 lesstif_hid.log = lesstif_log;
4077 lesstif_hid.logv = lesstif_logv;
4078 lesstif_hid.confirm_dialog = lesstif_confirm_dialog;
4079 lesstif_hid.close_confirm_dialog = lesstif_close_confirm_dialog;
4080 lesstif_hid.report_dialog = lesstif_report_dialog;
4081 lesstif_hid.prompt_for = lesstif_prompt_for;
4082 lesstif_hid.fileselect = lesstif_fileselect;
4083 lesstif_hid.attribute_dialog = lesstif_attribute_dialog;
4084 lesstif_hid.show_item = lesstif_show_item;
4085 lesstif_hid.beep = lesstif_beep;
4086 lesstif_hid.progress = lesstif_progress;
4087 lesstif_hid.edit_attributes = lesstif_attributes_dialog;
4089 lesstif_hid.request_debug_draw = lesstif_request_debug_draw;
4090 lesstif_hid.flush_debug_draw = lesstif_flush_debug_draw;
4091 lesstif_hid.finish_debug_draw = lesstif_finish_debug_draw;
4093 lesstif_hid.graphics = &lesstif_graphics;
4095 lesstif_graphics.make_gc = lesstif_make_gc;
4096 lesstif_graphics.destroy_gc = lesstif_destroy_gc;
4097 lesstif_graphics.use_mask = lesstif_use_mask;
4098 lesstif_graphics.set_color = lesstif_set_color;
4099 lesstif_graphics.set_line_cap = lesstif_set_line_cap;
4100 lesstif_graphics.set_line_width = lesstif_set_line_width;
4101 lesstif_graphics.set_draw_xor = lesstif_set_draw_xor;
4102 lesstif_graphics.draw_line = lesstif_draw_line;
4103 lesstif_graphics.draw_arc = lesstif_draw_arc;
4104 lesstif_graphics.draw_rect = lesstif_draw_rect;
4105 lesstif_graphics.fill_circle = lesstif_fill_circle;
4106 lesstif_graphics.fill_polygon = lesstif_fill_polygon;
4107 lesstif_graphics.fill_rect = lesstif_fill_rect;
4109 lesstif_graphics.draw_pcb_polygon = common_gui_draw_pcb_polygon;
4111 hid_register_hid (&lesstif_hid);
4112 #include "lesstif_lists.h"