[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
gEDA: [pcb] multi-gui support
I had a couple of hours of travel time to play with the laptop, and
decided to work on a gui segregation API for PCB, letting us (at build
time) choose between GTK and Lesstif (for starters, Win32 later I
suppose). I *only* wrote the .h file(s) (hid.h attached, the private
hidint.h is tiny and boring). The theory is that the common side of
the API (pcb itself) always deals with PCB units (1/100 thou), and
only cares about changing the board. The device side (gui, printers,
exporters) do all the units conversions and map everything into "draw
the board...HERE". The device side also does all the dialogs (the
common side doesn't even *know* about printing), main window layout,
menus, etc, and can access all the global data structures in the
common part if needed.
This should be good enough to do the old Xaw layout, the current GTK
layout, a Motif compliant lesstif layout (different menu layout and
shortcuts, for example), and Win32 MDI. Also, this hooks in print
(postscript or Win32) and export (gerber, png, eps, pdf, postscript,
whatever) without the common parts even knowing it. The isolation
also means the scripting mode is simpler, and perhaps even a DOS, Mac,
or Java gui could be made!
Comments?
/* 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 unless 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.
*/
/* 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
} EndCapStyles;
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;
} opaque;
/* 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. */
void (*trigger_cb) (int argc, char **argv, int x, int y);
} HID_Actions;
/* 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. */
typedef struct {
int int_value;
char *str_value;
double real_value;
} HID_Attr_Val;
typedef struct {
char *name;
enum { HID_Label, HID_Integer, HID_Real, HID_String,
HID_Boolean, HID_Enum } type;
int min_val, max_val; /* for integer and real */
HID_Attr_Val default_val;
const char **enumerations;
} HID_Attribute;
/* 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;
/* The HID itself sets and uses this as needed. */
void *private;
/* 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) ();
/* Export (or print) the current PCB. The options given represent
the choices made from the options returned from
export_options. */
void (*do_export) (HID_Attr_Val *options);
/* 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" and
90 being "up". */
/* Get 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.*/
opaque (*get_color) (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_style) (opaque color, int rounded_ends, int width);
/* 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) (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) (int x1, int y1, int x2, int y2);
void (*draw_arc) (int cx, int cy, int radius,
int start_angle, int end_angle);
void (*fill_circle) (int cx, int cy, int radius);
void (*fill_polygon) (int n_coords, int *x, int *y);
/* GUI layout functions. Not used or defined for print/export
HIDs. */
/* A generic dialog to ask for a set of attributes. If n_attrs is
zero, attrs must be NULL terminated. */
void (*attribute_dialog) (HID_Attribute *attrs,
int n_attrs,
HID_Attr_Val *results);
/* 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);
/* May be called multiple times. If n_actions is zero, actions must
be a NULL-terminated list. */
void (*add_actions) (HID_Actions *actions, int n_actions);
/* Pass an action name and a NULL terminated list of arguments (all
char *) */
void (*call_action) (const char *action, ...);
/* The index into this array is the layer's "idx". If n_layers is
zero, layer_names must be NULL-terminated. This function may be
called multiple times to replace the layer list. There may be
more layers than the ones specified here; extra layers will not
be selectable or editable but may be printed or exported. */
void (*set_layer_list) (char **layer_names, int n_layers);
/* Returns an array of flags, zero for hidden layers and nonzero for
non-hidden layers. If n_layers is not NULL, the number of layers
is stored in it (it's just a copy of n_layers from set_layer_list
so you might not need it). */
char *(*get_layer_masks) (int *n_layers);
/* When the user selects a layer to draw on, func is called. You
may also call get_active_layer to retrieve the same number. */
void (*set_layer_select_callback) (void (*func)(int idx));
int (*get_active_layer) ();
/* groups has n_layers elements, each has a value between 0 and
max_group (inclusive). Layers with the same group value are in
the same group. */
void (*set_layer_group_callback) (void (*func)(int *groups, int n_layers,
int max_group));
/* If n_layers or max_group are not NULL, they're filled in with the
current values. */
int *(*get_layer_groups) (int *n_layers, int *max_group);
/* Call whenever the netlist changes. This is used mostly for
the netlist window. */
void (*set_netlist) (const char **nets, const char ***nodes);
/* The following actions are assumed to exist:
select_netlist(netlist_name)
unselect_netlist(netlist_name)
select_netlist_node(netlist_name, node_name)
unselect_netlist_node(netlist_name, node_name)
*/
/* Returns the set of marked nets in the netlist dialog. If nets is
nonzero, a list of net names is stored there. Otherwise, the
array returned has one char per net in the list passed to
set_netlist, which is either zero or nonzero. */
char *(*get_active_netlists)(const char ***nets);
/* Called to set up the library dialog. When both parameters are
NULL, returns a list of libraries. When library is set but
element is NULL, return a list of elements in that library. When
both are set, the user has selected that element. */
char *(*set_library_callback)(char **(*func)(char *library, char *element));
/* 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. */
opaque (*add_timer) (void (*func)(opaque user_data),
unsigned long milliseconds,
opaque user_data);
/* Use this to stop a timer that hasn't triggered yet. */
void (*stop_timer) (opaque timer);
/* Various dialogs */
/* Log a message to the log window. */
void (*log) (char *fmt, ...);
/* 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);
/* This is for the printer. If you call this from 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);
} HID;
/* Call this as soon as possible from main(). No other HID calls are
valid until this is called. */
void hid_init ();
/* When PCB runs in interactive mode, this is called to instantiate
one GUI HID which happens to be the default GUI. This HID is the
one that interacts with the mouse and keyboard. */
HID *hid_find_default_gui (int *argc, char ***argv);
/* Finds the one printer HID and instantiates it. */
HID *hid_find_printer ();
/* 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();
/* func will be called whenever the GUI needs to redraw the screen,
print the board, or export a layer. If the function will limit
itself to the region specified, pass a non-zero value for smart,
and func may be called multiple times per redraw cycle. If you
pass zero for smart, func may be called only once, specifying the
whole board. 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 set_expose_callback(void (*func)(HID *hid, void *item,
int minx, int miny,
int maxx, int maxy),
int smart);