[was Re: gEDA: PCB fork to operate under the Tcl/Tk interpreter]

> I could try to lend you a hand since current gerber and ps/eps
> drivers do look not that difficult/complicated (with a superficial
> look, that is).

My source tree is still in the "intermediate mess" phase, but here's
the hid.h file at the moment.  When I've got it working enough that I
don't think the API will change much any more, I'll worry about
getting it "out there" for others to play with.

I think the "tool" concept is going away, and I'm moving some of the
crosshair support into the HID - grid computations are done in the
core, but *display* of the crosshair moves to the HID, taking all the
show/hide logic out of the core and allowing for different
gui-specific types of crosshairs (play with xfig, you'll see).

Don't code to this yet, but if you want to think about how your driver
would fit, feedback and discussion would be welcome.  I tried to
consider gerber and PS drivers when I wrote it, but I'd like to see a
PNG driver at least too.  Or a GIMP XCF driver :-)

#ifndef _HID_H_
#define _HID_H_

#include <stdarg.h>

/* Human Interface Device */

/*

The way the HID layer works is that you instantiate a HID device
structure, and invoke functions through its members.  Code in the
common part of PCB may *not* rely on *anything* other than what's
defined in this file.  Code in the HID layers *may* rely on data and
functions in the common code (like, board size and such) but it's
considered bad form to do so when not needed.

Coordinates are ALWAYS in pcb's default resolution (1/100 mil at the
moment).  Positive X is right, positive Y is down.  Angles are
degrees, with 0 being right (positive X) and 90 being up (negative Y).
All zoom, scaling, panning, and conversions are hidden inside the HID
layers.

The main structure is at the end of this file.

Data structures passed to the HIDs will be copied if the HID needs to
save them.  Data structures retured from the HIDs must not be freed,
and may be changed by the HID in response to new information.

FIXMEs:

  Callbacks probably aren't needed, as the HID can call those
  functions directly.

  Actions and tools can probably be handled in the common code.

*/

/* Like end cap styles.  The cap *always* extends beyond the
   coordinates given, by half the width of the line.  Beveled ends can
   used to make octagonal pads by giving the same x,y coordinate
   twice.  */
typedef enum {
  Square_Cap,
  Round_Cap,
  Beveled_Cap
} EndCapStyle;

typedef enum {
  BC_Click,     /* Click and release at the same point. */
  BC_Press,     /* Initial press of a drag-n-drop, or key press.  */
  BC_Drag,      /* Motion during drag-n-drop.  */
  BC_Drop,      /* Release of a drag-n-drop. */
  BC_Release    /* Key release.  */
} KeyButtonType;

/* The HID may need something more than an "int" for colors, timers,
   etc.  So it passes/returns one of these, which is castable to a
   variety of things.  */
typedef union {
  long lval;
  void *ptr;
} hidval;

/* This graphics context is an opaque pointer defined by the HID.  GCs
   are HID-specific; attempts to use one HID's GC for a different HID
   will result in a fatal error.  */
typedef struct hid_gc_struct *hidGC;

#define HIDCONCAT(a,b) a##b
#define HIDCTOR(l) static void __attribute__((constructor)) \
HIDCONCAT(this_file_register_ctor_,l) () 

/* This is how we define each of the editing tools.  */
typedef struct {
  /* used to match against GUI layouts.  */
  char *name;
  /* Called when the user switches to this tool.  */
  void (*select) (void);
  /* mouse button callbacks.  */
  void (*button_cb) (KeyButtonType type, int x, int y);
  /* keyboard key pressed.  "ch" is an ASCII character.  The "enter"
     key generates '\n', backspace is '\b'.  */
  void (*key) (KeyButtonType type, int x, int y, int ch);
} HID_Tools;

/* This is used to register the action callbacks (for menus and
   whatnot).  HID assumes the following actions are available for its
   use:
        SaveAs(filename);
        Quit();
*/
typedef struct {
  /* This is matched against action names in the GUI configuration */
  char *name;
  /* If true, the X and Y in the callback are relevent, else they may
     be just 0,0. */
  int needs_coords;
  /* if needs_coords is nonzero, this string may be used to prompt the
     user to select a coordinate.  */
  const char *need_coord_msg;
  /* Called when the action is triggered.  If this function returns
     non-zero, no further actions will be invoked for this key/mouse
     event.  */
  int (*trigger_cb) (int argc, char **argv, int x, int y);
} HID_Action;

extern void hid_register_actions(HID_Action *, int);
#define REGISTER_ACTIONS(a) HIDCTOR(__LINE__) \
{ hid_register_actions(a, sizeof(a)/sizeof(a[0])); }

  /* Note that PCB expects the gui to provide the following actions:

     PCBChanged();
     RouteStylesChanged()
     NetlistChanged()
     LayerGroupsChanged()
     LibraryChanged()
  */

void hid_action (const char *action);
void hid_actionl (const char *action, ...); /* NULL terminated */
void hid_actionv (const char *action, int argc, char **argv);

/* Used for HID attributes (exporting and printing, mostly).
   HA_boolean uses int_value, HA_enum sets int_value to the index and
   str_value to the enumeration string.  HID_Label just shows the
   default str_value.  HID_Mixed is a real_value followed by an enum,
   like 0.5in or 100mm. */
typedef struct {
  int int_value;
  char *str_value;
  float real_value;
} HID_Attr_Val;

typedef struct {
  char *name;
  char *help_text;
  enum { HID_Label, HID_Integer, HID_Real, HID_String,
         HID_Boolean, HID_Enum, HID_Mixed, HID_Path } type;
  int min_val, max_val; /* for integer and real */
  HID_Attr_Val default_val; /* Also actual value for global attributes.  */
  const char **enumerations;
  /* If set, this is used for global attributes (i.e. those set
     statically with REGISTER_ATTRIBUTES below) instead of changing
     the default_val.  Note that a HID_Mixed attribute must specify a
     pointer to HID_Attr_Val here.  */
  void *value;
} HID_Attribute;

extern void hid_register_attributes(HID_Attribute *, int);
#define REGISTER_ATTRIBUTES(a) HIDCTOR(__LINE__) \
{ hid_register_attributes(a, sizeof(a)/sizeof(a[0])); }

/* These three are set by hid_parse_command_line().  */
extern char *program_name;
extern char *program_directory;
extern char *program_basename;
void hid_parse_command_line (int *argc, char ***argv);


/* This is the main HID structure.  */
typedef struct {
  /* The name of this HID.  This should be suitable for
     command line options, multi-selection menus, file names,
     etc. */
  const char *name;

  /* Likewise, but allowed to be longer and more descriptive.  */
  const char *description;

  /* If set, this is the printer-class HID.  The common part of PCB
     may use this to do command-line printing, without having
     instantiated any GUI HIDs.  Only one printer HID is normally
     defined at a time.  */
  char printer:1;

  /* If set, this HID provides an export option, and should be used as
     part of the File->Export menu option.  Examples are PNG, Gerber,
     and EPS exporters.  */
  char exporter:1;

  /* Returns a set of resources describing options the export or print
     HID supports.  In GUI mode, the print/export dialogs use this to
     set up the selectable options.  In command line mode, these are
     used to interpret command line options.  */
  HID_Attribute *(*get_export_options) (void);

  /* Export (or print) the current PCB.  The options given represent
     the choices made from the options returned from
     get_export_options.  Call with options == NULL to start the
     primary GUI (create a main window, print, export, etc)  */
  void (*do_export) (HID_Attr_Val *options);

  /* Parse the command line.  Call this early for whatever HID will be
     the primary HID, as it will set all the registered attributes.
     The HID should remove all arguments, leaving any possible file
     names behind.  */
  void (*parse_arguments) (int *argc, char ***argv);

  /* This may be called outside of redraw to force a redraw.  Pass
     zero for "last" for all but the last call before control returns
     to the user (pass nonzero the last time).  If determining the
     last call is difficult, call *_wh at the end with width and
     height zero.  */
  void (*invalidate_wh) (int x, int y, int width, int height, int last);
  void (*invalidate_lr) (int left, int right, int top, int bottom, int last);
  void (*invalidate_all) (void);

  /* During redraw or print/export cycles, this is called once per
     layer.  If it returns false (zero), the HID does not want that
     layer, and none of the drawing functions should be called.  If it
     returns true (nonzero), the items in that layer should be drawn
     using the various drawing functions.  You may select layers
     beyond the list given to set_layer_list; these will be used when
     exporting or printing by layers, and disabled for GUI or
     full-board prints.

     Special layer names "outline", "fab", and "drill" may be selected
     by name rather than idx, but it's assumed that the idx for a
     given special layer does not change between calls to
     set_layer_list() (below).  */
  int (*set_layer) (const char *name, int idx);

  /* Drawing Functions.  Coordinates and distances are ALWAYS in PCB's
     default coordinates (1/100 mil at the time this comment was
     written).  Angles are always in degrees, with 0 being "right"
     (positive X) and 90 being "up" (positive Y).  */

  /* Make an empty graphics context.  */
  hidGC (*make_gc) (void);
  void (*destroy_gc) (hidGC gc);

  /* Special note about the "erase" color: To use this color, you must
     use this function to tell the HID when you're using it.  At the
     beginning of a layer redraw cycle (i.e. after set_layer), call
     use_mask(1) to redirect output to a buffer.  Draw to the buffer
     (using regular HID calls) using regular and "erase" colors.  Then
     call use_mask(0) to flush the buffer to the HID.  If you use the
     "erase" color when use_mask is disabled, it simply draws in the
     background color.  */
  void (*use_mask) (int use_it);

  /* Set a color.  Names can be like "red" or "#rrggbb" or special
     names like "erase".  *Always* use the "erase" color for removing
     ink (like polygon reliefs or thermals), as you cannot rely on
     knowing the background color or special needs of the HID.  You
     may assume this is cheap enough to call inside the redraw
     callback, but not cheap enough to call for each item drawn.*/
  void (*set_color) (hidGC gc, const char *name);

  /* Set the line style.  While calling this is cheap, calling it with
     different values each time may be expensive, so grouping items by
     line style is helpful.  */
  void (*set_line_cap) (hidGC gc, EndCapStyle style);
  void (*set_line_width) (hidGC gc, int width);
  void (*set_draw_xor) (hidGC gc, int xor);

  /* When you pass the same x,y twice to draw_line, the end caps are
     drawn as if the "line" were parallel to the line defined by these
     coordinates.  Use this for rotating non-round pads.  */
  void (*set_line_cap_angle) (hidGC gc, int x1, int y1, int x2, int y2);

  /* The usual drawing functions.  "draw" means to use segments of the
     given width, whereas "fill" means to fill to a zero-width
     outline.  */
  void (*draw_line) (hidGC gc, int x1, int y1, int x2, int y2);
  void (*draw_arc) (hidGC gc, int cx, int cy, int width, int height,
                    int start_angle, int end_angle);
  void (*fill_circle) (hidGC gc, int cx, int cy, int radius);
  void (*fill_polygon) (hidGC gc, int n_coords, int *x, int *y);


  /* This is for the printer.  If you call this for the GUI, xval and
     yval are ignored, and a dialog pops up to lead you through the
     calibration procedure.  For the printer, if xval and yval are
     zero, a calibration page is printed with instructions for
     calibrating your printer.  After calibrating, nonzero xval and
     yval are passed according to the instructions.  Metric is nonzero
     if the user prefers metric units, else inches are used. */
  void (*calibrate) (double xval, double yval, int metric);


  /* GUI layout functions.  Not used or defined for print/export
     HIDs.  */

  /* Temporary */
  int (*shift_is_pressed)(void);
  int (*control_is_pressed)(void);
  void (*get_coords)(const char *msg, int *x, int *y);

  /* May be called multiple times. If n_tools is zero,
     tools must be a NULL-terminated list.  */
  void (*add_tools) (HID_Tools *tools, int n_tools);

  /* Causes func to be called at some point in the future.  Timers are
     only good for *one* call; if you want it to repeat, add another
     timer during the callback for the first.  user_data can be
     anything, it's just passed to func.  Times are not guaranteed to
     be accurate.  */
  hidval (*add_timer) (void (*func)(hidval user_data),
                       unsigned long milliseconds,
                       hidval user_data);
  /* Use this to stop a timer that hasn't triggered yet.  */
  void (*stop_timer) (hidval timer);

  /* Various dialogs */

  /* Log a message to the log window.  */
  void (*log) (char *fmt, ...);
  void (*logv) (char *fmt, va_list args);

  /* A generic yes/no dialog.  Returns zero if the cancel button is
     pressed, one for the ok button.  If you specify alternate labels
     for ..., they are used instead of the default OK/Cancel ones, and
     the return value is the index of the label chosen.  You MUST pass
     NULL as the last parameter to this.  */
  int (*confirm_dialog) (char *msg, ...);

  /* Just prints text.  */
  void (*report_dialog) (char *title, char *msg);

  /* Prompts the user to enter a string, returns the string.  If
     default_string isn't NULL, the form is pre-filled with this
     value.  */
  char *(*prompt_for)(char *msg, char *default_string);

  /* A generic dialog to ask for a set of attributes.  If n_attrs is
     zero, attrs(.name) must be NULL terminated.  */
  void (*attribute_dialog) (HID_Attribute *attrs,
                            int n_attrs,
                            HID_Attr_Val *results);

  /* This causes a second window to display, which only shows the
     selected item. The expose callback is called twice; once to size
     the extents of the item, and once to draw it.  To pass magic
     values, pass the address of a variable created for this
     purpose.  */
  void (*show_item) (void *item);

  /* Something to alert the user.  */
  void (*beep) (void);
} HID;

/* Call this as soon as possible from main().  No other HID calls are
   valid until this is called.  */
void hid_init (void);

/* When PCB runs in interactive mode, this is called to instantiate
   one GUI HID which happens to be the GUI.  This HID is the one that
   interacts with the mouse and keyboard.  */
HID *hid_find_gui ();

/* Finds the one printer HID and instantiates it.  */
HID *hid_find_printer (void);

/* Finds the indicated exporter HID and instantiates it.  */
HID *hid_find_exporter (const char *);

/* This returns a NULL-terminated array of available HIDs.  The only
   real reason to use this is to locate all the export-style HIDs. */
HID **hid_enumerate(void);

/* This function (in the common code) will be called whenever the GUI
   needs to redraw the screen, print the board, or export a layer.If
   item is not NULL, only draw the given item.  Item is only non-NULL
   if the HID was created via show_item.

   Each time func is called, it should do the following:

   * allocate any colors needed, via get_color.

   * cycle through the layers, calling set_layer for each layer to be
     drawn, and only drawing elements (all or specified) of desired
     layers.

   Do *not* assume that the hid that is passed is the GUI hid.  This
   callback is also used for printing and exporting. */
void hid_expose_callback(HID *hid, void *item);

/* This is initially set to a "no-gui" gui, and later reset by
   hid_start_gui.  */
extern HID *gui;

#endif

Reply via email to