|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: B T
Length: 27226 (0x6a5a)
Types: TextFile
Names: »BitmapEdit.c«
└─⟦8648bda34⟧ Bits:30007244 EUUGD5_II: X11R5
└─⟦2ca9b63e1⟧ »./contrib-1/contrib-1.00«
└─⟦a8392fb20⟧
└─⟦this⟧ »contrib/examples/OReilly/Vol4/ch10/BitmapEdit.c«
/*
* Copyright 1989 O'Reilly and Associates, Inc.
* See ../Copyright for complete rights and liability information.
*/
/*
* BitmapEdit.c - bitmap editor widget.
*/
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include <stdio.h>
#include <X11/Xatom.h>
#include <X11/Xmu/Atoms.h>
#include "BitmapEdiP.h"
#define INTERNAL_WIDTH 2
#define INTERNAL_HEIGHT 4
#define DEFAULT_PIXMAP_WIDTH 32 /* in cells */
#define DEFAULT_PIXMAP_HEIGHT 32 /* in cells */
#define DEFAULT_CELL_SIZE 30 /* in pixels */
/* values for instance variable is_drawn, and for char elements
* in cell state array. */
#define DRAWN 'y'
#define UNDRAWN 'n'
/* modes for drawing */
#define DRAW 'y'
#define UNDRAW 'n'
#define MAXLINES 1000 /* max of horiz or vertical cells */
#define SCROLLBARWIDTH 15
#define offset(field) XtOffset(BitmapEditWidget, field)
static XtResource resources[] = {
{XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
offset(bitmapEdit.foreground), XtRString, XtDefaultForeground },
{XtNselectionForeground, XtCSelectionForeground, XtRPixel,
sizeof(Pixel), offset(bitmapEdit.selectionForeground),
XtRString, "red" },
{XtNcallback, XtCCallback, XtRCallback, sizeof(XtPointer),
offset(bitmapEdit.callback), XtRCallback, NULL},
{XtNcellSizeInPixels, XtCCellSizeInPixels, XtRInt, sizeof(int),
offset(bitmapEdit.cell_size_in_pixels), XtRImmediate,
(XtPointer)DEFAULT_CELL_SIZE },
{XtNpixmapWidthInCells, XtCPixmapWidthInCells, XtRDimension,
sizeof(Dimension), offset(bitmapEdit.pixmap_width_in_cells),
XtRImmediate, (XtPointer)DEFAULT_PIXMAP_WIDTH },
{XtNpixmapHeightInCells, XtCPixmapHeightInCells, XtRDimension,
sizeof(Dimension), offset(bitmapEdit.pixmap_height_in_cells),
XtRImmediate, (XtPointer)DEFAULT_PIXMAP_HEIGHT },
{XtNcurX, XtCCurX, XtRInt, sizeof(int),
offset(bitmapEdit.cur_x), XtRImmediate, (XtPointer) 0},
{XtNcurY, XtCCurY, XtRInt, sizeof(int),
offset(bitmapEdit.cur_y), XtRImmediate, (XtPointer) 0},
};
/* Declaration of methods */
static void Initialize();
static void Redisplay();
static void Destroy();
static void Resize();
static Boolean SetValues();
/* these Core methods not needed by BitmapEdit:
*
* static void ClassInitialize();
* static void Realize();
* static void ClassInitialize();
* static void Realize();
*/
/* the following are private functions unique to BitmapEdit */
static void DrawPixmaps(), HighlightCell(), draw_box(), DrawCell();
/* private functions for selections */
static void lose_ownership_proc(), transfer_done_proc(),
requestor_callback();
static Boolean convert_proc();
/* the following are actions of BitmapEdit */
static void DoCell(), UndoCell(), ToggleCell();
static void TopLeft(), BottomRight(), DragHighlight();
static void PasteSelection();
/* The following are public functions of BitmapEdit, declared extern
* in the public include file: */
char *BitmapEditGetArrayString();
static char defaultTranslations[] =
"Shift<Btn1Down>: TopLeft() \n\
Shift<Btn1Motion>: DragHighlight() \n\
Shift<Btn1Up>: BottomRight() \n\
Shift<Btn2Down>: PasteSelection() \n\
~Shift<Btn1Down>: DoCell() \n\
~Shift<Btn2Down>: UndoCell() \n\
~Shift<Btn3Down>: ToggleCell() \n\
~Shift<Btn1Motion>: DoCell() \n\
~Shift<Btn2Motion>: UndoCell() \n\
~Shift<Btn3Motion>: ToggleCell()";
static XtActionsRec actions[] = {
{"DoCell", DoCell},
{"UndoCell", UndoCell},
{"ToggleCell", ToggleCell},
{"TopLeft", TopLeft},
{"DragHighlight", DragHighlight},
{"BottomRight", BottomRight},
{"PasteSelection", PasteSelection},
};
/* definition in BitmapEdit.h */
static BitmapEditPointInfo info;
BitmapEditClassRec bitmapEditClassRec = {
{
/* core_class fields */
/* superclass */ (WidgetClass) &widgetClassRec,
/* class_name */ "BitmapEdit",
/* widget_size */ sizeof(BitmapEditRec),
/* class_initialize */ NULL,
/* class_part_initialize */ NULL,
/* class_inited */ FALSE,
/* initialize */ Initialize,
/* initialize_hook */ NULL,
/* realize */ XtInheritRealize,
/* actions */ actions,
/* num_actions */ XtNumber(actions),
/* resources */ resources,
/* num_resources */ XtNumber(resources),
/* xrm_class */ NULLQUARK,
/* compress_motion */ TRUE,
/* compress_exposure */ TRUE,
/* compress_enterleave */ TRUE,
/* visible_interest */ FALSE,
/* destroy */ Destroy,
/* resize */ Resize,
/* expose */ Redisplay,
/* set_values */ SetValues,
/* set_values_hook */ NULL,
/* set_values_almost */ XtInheritSetValuesAlmost,
/* get_values_hook */ NULL,
/* accept_focus */ NULL,
/* version */ XtVersion,
/* callback_private */ NULL,
/* tm_table */ defaultTranslations,
/* query_geometry */ NULL,
},
{
/* dummy_field */ 0,
},
};
WidgetClass bitmapEditWidgetClass = (WidgetClass) & bitmapEditClassRec;
static void
GetDrawGC(w)
Widget w;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
XGCValues values;
XtGCMask mask = GCForeground | GCBackground | GCDashOffset
| GCDashList | GCLineStyle;
/*
* Setting foreground and background to 1 and 0 looks like a
* kludge but isn't. This GC is used for drawing
* into a pixmap of depth one. Real colors are applied with a
* separate GC when the pixmap is copied into the window.
*/
values.foreground = 1;
values.background = 0;
values.dashes = 1;
values.dash_offset = 0;
values.line_style = LineOnOffDash;
cw->bitmapEdit.draw_gc = XCreateGC(XtDisplay(cw),
cw->bitmapEdit.big_picture, mask, &values);
}
static void
GetUndrawGC(w)
Widget w;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
XGCValues values;
XtGCMask mask = GCForeground | GCBackground;
/* this looks like a kludge but isn't. This GC is used for drawing
* into a pixmap of depth one. Real colors are applied as the
* pixmap is copied into the window.
*/
values.foreground = 0;
values.background = 1;
cw->bitmapEdit.undraw_gc = XCreateGC(XtDisplay(cw),
cw->bitmapEdit.big_picture, mask, &values);
}
static void
GetDeepUndrawGC(w)
Widget w;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
XGCValues values;
XtGCMask mask = GCForeground | GCBackground;
values.foreground = cw->core.background_pixel;
values.background = cw->bitmapEdit.foreground;
cw->bitmapEdit.deep_undraw_gc = XtGetGC(cw, mask, &values);
}
static void
GetDeepDrawGC(w)
Widget w;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
XGCValues values;
XtGCMask mask = GCForeground | GCBackground;
values.foreground = cw->bitmapEdit.foreground;
values.background = cw->core.background_pixel;
cw->bitmapEdit.deep_draw_gc = XtGetGC(cw, mask, &values);
}
/* ARGSUSED */
static void
Initialize(treq, tnew, args, num_args)
Widget treq, tnew;
ArgList args;
Cardinal *num_args;
{
BitmapEditWidget new = (BitmapEditWidget) tnew;
new->bitmapEdit.cur_x = 0;
new->bitmapEdit.cur_y = 0;
/*
* Check instance values set by resources that may be invalid.
*/
if ((new->bitmapEdit.pixmap_width_in_cells < 1) ||
(new->bitmapEdit.pixmap_height_in_cells < 1)) {
XtWarning("BitmapEdit: pixmapWidth and/or pixmapHeight is too small\
(using 10 x 10).");
new->bitmapEdit.pixmap_width_in_cells = 10;
new->bitmapEdit.pixmap_height_in_cells = 10;
}
if (new->bitmapEdit.cell_size_in_pixels < 5) {
XtWarning("BitmapEdit: cellSize is too small (using 5).");
new->bitmapEdit.cell_size_in_pixels = 5;
}
if ((new->bitmapEdit.cur_x < 0) || (new->bitmapEdit.cur_y < 0)) {
XtWarning("BitmapEdit: cur_x and cur_y must be non-negative\
(using 0, 0).");
new->bitmapEdit.cur_x = 0;
new->bitmapEdit.cur_y = 0;
}
new->bitmapEdit.cell = XtCalloc(new->bitmapEdit.pixmap_width_in_cells
* new->bitmapEdit.pixmap_height_in_cells, sizeof(char));
new->bitmapEdit.pixmap_width_in_pixels = new->bitmapEdit.pixmap_width_in_cells
* new->bitmapEdit.cell_size_in_pixels;
new->bitmapEdit.pixmap_height_in_pixels = new->bitmapEdit.pixmap_height_in_cells
* new->bitmapEdit.cell_size_in_pixels;
if (new->core.width == 0)
new->core.width = (new->bitmapEdit.pixmap_width_in_pixels > 300)
? 300 : (new->bitmapEdit.pixmap_width_in_pixels);
if (new->core.height == 0)
new->core.height = (new->bitmapEdit.pixmap_height_in_pixels > 300)
? 300 : (new->bitmapEdit.pixmap_height_in_pixels);
CreateBigPixmap(new);
GetDrawGC(new);
GetUndrawGC(new);
GetDeepDrawGC(new);
GetDeepUndrawGC(new);
DrawIntoBigPixmap(new);
new->bitmapEdit.target_atom = XInternAtom(XtDisplay(new),
"CELL_ARRAY", False);
/* This makes Xmu initialize the necessary atoms.
* Wierd, but true. */
(void) XmuInternAtom( XtDisplay(new), XmuMakeAtom("NULL") );
new->bitmapEdit.data = XtCalloc(
new->bitmapEdit.pixmap_width_in_cells *
new->bitmapEdit.pixmap_height_in_cells, sizeof(char));
}
/* ARGSUSED */
static void
Redisplay(w, event)
Widget w;
XExposeEvent *event;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
register int x, y;
unsigned int width, height;
if (!XtIsRealized(cw))
return;
if (event) { /* called from btn-event */
x = event->x;
y = event->y;
width = event->width;
height = event->height;
}
else { /* called because of expose */
x = 0;
y = 0;
width = cw->bitmapEdit.pixmap_width_in_pixels;
height = cw->bitmapEdit.pixmap_height_in_pixels;
}
if (DefaultDepthOfScreen(XtScreen(cw)) == 1)
XCopyArea(XtDisplay(cw), cw->bitmapEdit.big_picture, XtWindow(cw),
cw->bitmapEdit.deep_draw_gc, x + cw->bitmapEdit.cur_x, y +
cw->bitmapEdit.cur_y, width, height, x, y);
else
XCopyPlane(XtDisplay(cw), cw->bitmapEdit.big_picture, XtWindow(cw),
cw->bitmapEdit.deep_draw_gc, x + cw->bitmapEdit.cur_x, y +
cw->bitmapEdit.cur_y, width, height, x, y, 1);
if (cw->bitmapEdit.first_box)
draw_box(cw, cw->bitmapEdit.select_end_x, cw->bitmapEdit.select_end_y, True);
}
/* ARGSUSED */
static Boolean
SetValues(current, request, new, args, num_args)
Widget current, request, new;
ArgList args;
Cardinal *num_args;
{
BitmapEditWidget curcw = (BitmapEditWidget) current;
BitmapEditWidget newcw = (BitmapEditWidget) new;
Boolean do_redisplay = False;
if (curcw->bitmapEdit.foreground != newcw->bitmapEdit.foreground) {
XtReleaseGC(curcw, curcw->bitmapEdit.deep_draw_gc);
XtReleaseGC(curcw, curcw->bitmapEdit.deep_undraw_gc);
GetDeepDrawGC(newcw);
GetDeepUndrawGC(newcw);
do_redisplay = True;
}
if ((curcw->bitmapEdit.cur_x != newcw->bitmapEdit.cur_x) ||
(curcw->bitmapEdit.cur_y != newcw->bitmapEdit.cur_y)) {
do_redisplay = True;
}
if ((curcw->bitmapEdit.pixmap_width_in_cells !=
newcw->bitmapEdit.pixmap_width_in_cells) ||
(curcw->bitmapEdit.pixmap_height_in_cells !=
newcw->bitmapEdit.pixmap_height_in_cells) ||
(curcw->bitmapEdit.cell_size_in_pixels !=
newcw->bitmapEdit.cell_size_in_pixels))
XtWarning("BitmapEdit widget: pixmap_width_in_cells,\
pixmap_heigt, and cell_size_in_pixels resources\
can only be set before widget is created\n");
return do_redisplay;
}
static void
Destroy(w)
Widget w;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
if (cw->bitmapEdit.big_picture)
XFreePixmap(XtDisplay(cw), cw->bitmapEdit.big_picture);
if (cw->bitmapEdit.draw_gc)
XFreeGC(XtDisplay(cw), cw->bitmapEdit.draw_gc);
if (cw->bitmapEdit.undraw_gc)
XFreeGC(XtDisplay(cw), cw->bitmapEdit.undraw_gc);
XtFree(cw->bitmapEdit.cell);
}
static void
DoCell(w, event)
Widget w;
XEvent *event;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
DrawPixmaps(cw->bitmapEdit.draw_gc, DRAW, cw, event);
}
static void
UndoCell(w, event)
Widget w;
XEvent *event;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
DrawPixmaps(cw->bitmapEdit.undraw_gc, UNDRAW, cw, event);
}
static void
ToggleCell(w, event)
Widget w;
XEvent *event;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
static int oldx = -1, oldy = -1;
int newx, newy;
/* This is strictly correct, but doesn't
* seem to be necessary */
if (event->type == ButtonPress) {
newx = (cw->bitmapEdit.cur_x + ((XButtonEvent *)event)->x)
/ cw->bitmapEdit.cell_size_in_pixels;
newy = (cw->bitmapEdit.cur_y + ((XButtonEvent *)event)->y)
/ cw->bitmapEdit.cell_size_in_pixels;
}
else {
newx = (cw->bitmapEdit.cur_x + ((XMotionEvent *)event)->x)
/ cw->bitmapEdit.cell_size_in_pixels;
newy = (cw->bitmapEdit.cur_y + ((XMotionEvent *)event)->y)
/ cw->bitmapEdit.cell_size_in_pixels;
if (oldx == newx && oldy == newy)
return;
}
if (cw->bitmapEdit.cell[newx + newy * cw->bitmapEdit.pixmap_width_in_cells] == DRAWN)
DrawPixmaps(cw->bitmapEdit.undraw_gc, UNDRAW, cw, event);
else
DrawPixmaps(cw->bitmapEdit.draw_gc, DRAW, cw, event);
if (event->type == MotionNotify) {
oldx = newx;
oldy = newy;
}
}
static void
DrawPixmaps(gc, mode, w, event)
GC gc;
char mode;
Widget w;
XButtonEvent *event;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
int newx = (cw->bitmapEdit.cur_x + event->x)
/ cw->bitmapEdit.cell_size_in_pixels;
int newy = (cw->bitmapEdit.cur_y + event->y)
/ cw->bitmapEdit.cell_size_in_pixels;
XExposeEvent fake_event;
/* if already done, return */
if (cw->bitmapEdit.cell[newx + newy *
cw->bitmapEdit.pixmap_width_in_cells] == mode)
return;
DrawCell(cw, newx, newy, gc);
cw->bitmapEdit.cell[newx + newy * cw->bitmapEdit.pixmap_width_in_cells] = mode;
info.mode = mode;
info.newx = newx;
info.newy = newy;
fake_event.x = cw->bitmapEdit.cell_size_in_pixels * newx - cw->bitmapEdit.cur_x;
fake_event.y = cw->bitmapEdit.cell_size_in_pixels * newy - cw->bitmapEdit.cur_y;
fake_event.width = cw->bitmapEdit.cell_size_in_pixels;
fake_event.height = cw->bitmapEdit.cell_size_in_pixels;
Redisplay(cw, &fake_event);
XtCallCallbacks(cw, XtNcallback, &info);
}
static void
DrawCell(w, x, y, gc)
Widget w;
int x, y;
GC gc;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
/* draw or undraw */
XFillRectangle(XtDisplay(cw), cw->bitmapEdit.big_picture, gc,
cw->bitmapEdit.cell_size_in_pixels * x + 2,
cw->bitmapEdit.cell_size_in_pixels * y + 2,
(unsigned int)cw->bitmapEdit.cell_size_in_pixels - 3,
(unsigned int)cw->bitmapEdit.cell_size_in_pixels - 3);
}
CreateBigPixmap(w)
Widget w;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
/* always a 1 bit deep pixmap, regardless of screen depth */
cw->bitmapEdit.big_picture = XCreatePixmap(XtDisplay(cw),
RootWindow(XtDisplay(cw), DefaultScreen(XtDisplay(cw))),
cw->bitmapEdit.pixmap_width_in_pixels, cw->bitmapEdit.pixmap_height_in_pixels, 1);
}
DrawIntoBigPixmap(w)
Widget w;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
int n_horiz_segments, n_vert_segments;
XSegment segment[MAXLINES];
register int x, y;
XFillRectangle(XtDisplay(cw), cw->bitmapEdit.big_picture,
cw->bitmapEdit.undraw_gc, 0, 0,
cw->bitmapEdit.pixmap_width_in_pixels
+ 2, cw->bitmapEdit.pixmap_height_in_pixels + 2);
n_horiz_segments = cw->bitmapEdit.pixmap_height_in_cells + 1;
n_vert_segments = cw->bitmapEdit.pixmap_width_in_cells + 1;
for (x = 0; x < n_horiz_segments; x += 1) {
segment[x].x1 = 0;
segment[x].x2 = cw->bitmapEdit.pixmap_width_in_pixels;
segment[x].y1 = cw->bitmapEdit.cell_size_in_pixels * x;
segment[x].y2 = cw->bitmapEdit.cell_size_in_pixels * x;
}
XDrawSegments(XtDisplay(cw), cw->bitmapEdit.big_picture,
cw->bitmapEdit.draw_gc, segment, n_horiz_segments);
for (y = 0; y < n_vert_segments; y += 1) {
segment[y].x1 = y * cw->bitmapEdit.cell_size_in_pixels;
segment[y].x2 = y * cw->bitmapEdit.cell_size_in_pixels;
segment[y].y1 = 0;
segment[y].y2 = cw->bitmapEdit.pixmap_height_in_pixels;
}
XDrawSegments(XtDisplay(cw), cw->bitmapEdit.big_picture,
cw->bitmapEdit.draw_gc, segment, n_vert_segments);
}
/* A Public function, not static */
char *
BitmapEditGetArrayString(w)
Widget w;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
return (cw->bitmapEdit.cell);
}
/* ARGSUSED */
static void
Resize(w)
Widget w;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
/*
* This takes care of the case where the widget is resized larger
* but there is no more pixmap to display in the bottom right corner.
* in that case, we need to move cur_x and cur_y to make sure that
* the pixmap fills as much of the window as possible, and fill
* the remainder of the window with gray, or draw a line around it.
*/
if (cw->bitmapEdit.cur_x + cw->core.width >
cw->bitmapEdit.pixmap_width_in_pixels)
cw->bitmapEdit.cur_x = cw->bitmapEdit.pixmap_width_in_pixels
- cw->core.width;
if (cw->bitmapEdit.cur_y + cw->core.height >
cw->bitmapEdit.pixmap_height_in_pixels)
cw->bitmapEdit.cur_y = cw->bitmapEdit.pixmap_height_in_pixels
- cw->core.height;
/* Can't clear window is it hasn't been realized yet,
* as would happen if -geometry option is specified. */
if (XtIsRealized(cw))
/* now force redraw by clearing window */
XClearArea(XtDisplay(cw), XtWindow(cw), 0, 0,
cw->bitmapEdit.pixmap_width_in_pixels,
cw->bitmapEdit.pixmap_height_in_pixels, True);
}
static void
TopLeft(w, event)
Widget w;
XButtonEvent *event;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
cw->bitmapEdit.first_box = False;
cw->bitmapEdit.select_start_x = (cw->bitmapEdit.cur_x + event->x)
/ cw->bitmapEdit.cell_size_in_pixels;
cw->bitmapEdit.select_start_y = (cw->bitmapEdit.cur_y + event->y)
/ cw->bitmapEdit.cell_size_in_pixels;
/* clear old selection */
Redisplay(cw, NULL);
}
/* ARGSUSED */
static void
transfer_done_proc(w, selection, target)
Widget w;
Atom *selection;
Atom *target;
{
/*
* This widget keeps the selection ready for pasting additional
* times. Having a transfer_done_proc indicates that the
* selection owner owns the storage allocated for
* converting the selection. However, this widget allocates
* this storage only once in initialize, and keeps it until
* quitting. Therefore, no \f(CWXtFree\fP call necessary here.
*/
}
static void
BottomRight(w, event)
Widget w;
XButtonEvent *event;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
int temp;
cw->bitmapEdit.select_end_x = (cw->bitmapEdit.cur_x + event->x)
/ cw->bitmapEdit.cell_size_in_pixels;
cw->bitmapEdit.select_end_y = (cw->bitmapEdit.cur_y + event->y)
/ cw->bitmapEdit.cell_size_in_pixels;
if ((cw->bitmapEdit.select_end_x == cw->bitmapEdit.select_start_x) &&
(cw->bitmapEdit.select_end_y == cw->bitmapEdit.select_start_y)) {
Redisplay(cw, NULL);
return; /* no selection */
}
/* swap start and end if end is greater than start */
if (cw->bitmapEdit.select_end_x < cw->bitmapEdit.select_start_x) {
temp = cw->bitmapEdit.select_end_x;
cw->bitmapEdit.select_end_x = cw->bitmapEdit.select_start_x;
cw->bitmapEdit.select_start_x = temp;
}
if (cw->bitmapEdit.select_end_y < cw->bitmapEdit.select_start_y) {
temp = cw->bitmapEdit.select_end_y;
cw->bitmapEdit.select_end_y = cw->bitmapEdit.select_start_y;
cw->bitmapEdit.select_start_y = temp;
}
if (XtOwnSelection(cw, XA_PRIMARY, event->time, convert_proc,
lose_ownership_proc, transfer_done_proc) == False) {
XtWarning("bitmapEdit: failed attempting to become selection owner; make a new selection.\n");
/* Clear old selection, because lose_ownership_proc
* isn't registered. */
Redisplay(cw, NULL);
}
}
static Boolean
convert_proc(w, selection, target, type_return, value_return, length_return, format_return)
Widget w;
Atom *selection;
Atom *target;
Atom *type_return;
XtPointer *value_return;
unsigned long *length_return;
int *format_return;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
int x, y;
int width, height;
XSelectionRequestEvent* req = XtGetSelectionRequest(w,
*selection, (XtRequestId) NULL);
/* handle all required atoms, and the one that we use */
if (*target == XA_TARGETS(XtDisplay(cw))) {
/* TARGETS handling copied from xclipboard.c */
Atom* targetP;
Atom* std_targets;
unsigned long std_length;
XmuConvertStandardSelection(cw, req->time, selection,
target, type_return,
(XtPointer*)&std_targets,
&std_length, format_return);
*value_return = XtMalloc(sizeof(Atom)*(std_length + 1));
targetP = *(Atom**)value_return;
*length_return = std_length + 1;
*targetP++ = cw->bitmapEdit.target_atom;
bcopy((char*)std_targets, (char*)targetP, sizeof(Atom)*std_length);
XtFree((char*)std_targets);
*type_return = XA_ATOM;
*format_return = sizeof(Atom) * 8;
return(True);
}
/* Xt already handles MULTIPLE, no branch necessary */
else if (*target == cw->bitmapEdit.target_atom) {
char *data;
width = cw->bitmapEdit.select_end_x - cw->bitmapEdit.select_start_x;
height = cw->bitmapEdit.select_end_y - cw->bitmapEdit.select_start_y;
/* 8 chars is enough for two 3-digit numbers and two delimiters */
*length_return = ((width * height) + 8) * sizeof(char);
data = XtMalloc(*length_return);
sprintf(data, "%d@%d~", width, height);
for (x = 0; x < width; x++) {
for (y = 0; y < height; y++) {
data[8 + x + (y * width)] = cw->bitmapEdit.cell[(x + cw->bitmapEdit.select_start_x) + ((y + cw->bitmapEdit.select_start_y) * cw->bitmapEdit.pixmap_width_in_cells)];
}
}
*value_return = data;
*type_return = cw->bitmapEdit.target_atom;
*format_return = 8; /* number of bits in char */
return(True);
}
else {
if (XmuConvertStandardSelection(cw, CurrentTime, selection,
target, type_return, value_return,
length_return, format_return))
return True;
else {
XtWarning("bitmapEdit: requestor is requesting\
unsupported selection target type.\n");
return(False);
}
}
}
/* ARGSUSED */
static void
lose_ownership_proc(w, selection)
Widget w;
Atom *selection;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
/* clear old selection */
cw->bitmapEdit.first_box = False;
cw->bitmapEdit.select_start_x = 0;
cw->bitmapEdit.select_start_y = 0;
cw->bitmapEdit.select_end_x = 0;
cw->bitmapEdit.select_end_y = 0;
Redisplay(cw, NULL);
}
/* Note: these global variables are necessary
* because the x and y position in the buttonpress event
* last only as long as the PasteSelection Action, yet
* these values are needed when interpreting the selection
* in requestor_callback. */
static int xPos, yPos;
static void
PasteSelection(w, event)
Widget w;
XButtonEvent *event;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
xPos = event->x;
yPos = event->y;
/*
* Note: the actual pasting takes place in requestor_callback.
* This is a callback because the owner and requestor roles
* may not be in the same widget.
*/
XtGetSelectionValue(cw, XA_PRIMARY, cw->bitmapEdit.target_atom,
requestor_callback, (XtPointer) event /* client_data */,
XtLastTimestampProcessed(XtDisplay(w)));
}
/* ARGSUSED */
static void
requestor_callback(w, client_data, selection, type, value, length, format)
Widget w;
XtPointer client_data;
Atom *selection;
Atom *type;
XtPointer value;
unsigned long *length;
int *format;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
char *data = (char *)value;
if (*type == 0 /*XT_CONVERT_FAIL*/ || *length == 0 || value == NULL) {
XBell(XtDisplay(cw), 100);
XtWarning("bitmapEdit: no selection or selection timed out; try again\n");
}
else {
XButtonEvent *event = (XButtonEvent *) client_data;
int width, height;
int x, y;
int dst_offset_x, dst_offset_y;
char *ptr;
dst_offset_x = (cw->bitmapEdit.cur_x + xPos) / cw->bitmapEdit.cell_size_in_pixels;
dst_offset_y = (cw->bitmapEdit.cur_y + yPos) / cw->bitmapEdit.cell_size_in_pixels;
ptr = (char *) value;
width = atoi(ptr);
ptr = index(ptr, '@');
ptr++;
height = atoi(ptr);
ptr = &data[8];
for (x = 0; x < width; x++) {
for (y = 0; y < height; y++) {
/* range checking */
if (((dst_offset_x + x) >
cw->bitmapEdit.pixmap_width_in_cells)
|| ((dst_offset_x + x) < 0))
break;
if (((dst_offset_y + y) >
cw->bitmapEdit.pixmap_height_in_cells)
|| ((dst_offset_y + y) < 0))
break;
cw->bitmapEdit.cell[(dst_offset_x + x)
+ ((dst_offset_y + y) *
cw->bitmapEdit.pixmap_width_in_cells)]
= ptr[x + (y * width)];
if (cw->bitmapEdit.cell[(dst_offset_x + x)
+ ((dst_offset_y + y) *
cw->bitmapEdit.pixmap_width_in_cells)]
== DRAWN)
DrawCell(cw, dst_offset_x + x,
dst_offset_y + y,
cw->bitmapEdit.draw_gc);
else
DrawCell(cw, dst_offset_x + x,
dst_offset_y + y,
cw->bitmapEdit.undraw_gc);
}
}
/* Regardless of the presence of a
* \f(CWtransfer_done_proc\fP in the owner,
* the requestor must free the data passed by
* Xt after using it. */
XtFree(value);
Redisplay(cw, NULL);
}
}
static void
DragHighlight(w, event)
Widget w;
XMotionEvent *event;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
static int last_drawn_x, last_drawn_y;
int event_cell_x, event_cell_y;
event_cell_x = cw->bitmapEdit.cur_x + (event->x / cw->bitmapEdit.cell_size_in_pixels);
event_cell_y = cw->bitmapEdit.cur_y + (event->y / cw->bitmapEdit.cell_size_in_pixels);
if ((event_cell_x == last_drawn_x) && (event_cell_y == last_drawn_y))
return;
if (cw->bitmapEdit.first_box) {
draw_box(cw, last_drawn_x, last_drawn_y, False);
draw_box(cw, event_cell_x, event_cell_y, True);
}
else {
draw_box(cw, event_cell_x, event_cell_y, True);
cw->bitmapEdit.first_box = True;
}
last_drawn_x = event_cell_x;
last_drawn_y = event_cell_y;
}
static void
draw_box(w, x, y, draw)
Widget w;
Position x, y;
Bool draw;
{
BitmapEditWidget cw = (BitmapEditWidget) w;
Position start_pos_x, start_pos_y;
Dimension width, height;
int i, j;
start_pos_x = cw->bitmapEdit.cur_x + cw->bitmapEdit.select_start_x;
start_pos_y = cw->bitmapEdit.cur_x + cw->bitmapEdit.select_start_y;
/* swap start and end if end is greater than start */
if (x < start_pos_x) {
width = start_pos_x - x;
start_pos_x = x;
}
else {
width = x - start_pos_x;
}
if (y < start_pos_y) {
height = start_pos_y - y;
start_pos_y = y;
}
else {
height = y - start_pos_y;
}
/* XDrawRectangle(XtDisplay(cw), XtWindow(cw), gc,
(start_pos_x * cw->bitmapEdit.cell_size_in_pixels) - 1,
(start_pos_y * cw->bitmapEdit.cell_size_in_pixels) - 1,
(unsigned int) width * cw->bitmapEdit.cell_size_in_pixels + 2,
(unsigned int) height * cw->bitmapEdit.cell_size_in_pixels + 2);
*/
for (i=start_pos_x;i < start_pos_x + width;i++)
for (j=start_pos_y;j < start_pos_y + height;j++)
DrawX(cw, i, j, draw);
}
DrawX(cw, x, y, draw)
BitmapEditWidget cw;
Position x, y;
Bool draw;
{
GC gc;
if (cw->bitmapEdit.cell[x + y * cw->bitmapEdit.pixmap_width_in_cells] == DRAWN)
if (draw)
gc = cw->bitmapEdit.deep_undraw_gc;
else
gc = cw->bitmapEdit.deep_draw_gc;
else
if (draw)
gc = cw->bitmapEdit.deep_draw_gc;
else
gc = cw->bitmapEdit.deep_undraw_gc;
XDrawLine(XtDisplay(cw), XtWindow(cw), gc,
x * cw->bitmapEdit.cell_size_in_pixels,
y * cw->bitmapEdit.cell_size_in_pixels,
(x + 1) * cw->bitmapEdit.cell_size_in_pixels,
(y + 1) * cw->bitmapEdit.cell_size_in_pixels);
XDrawLine(XtDisplay(cw), XtWindow(cw), gc,
x * cw->bitmapEdit.cell_size_in_pixels,
(y + 1) * cw->bitmapEdit.cell_size_in_pixels,
(x + 1) * cw->bitmapEdit.cell_size_in_pixels,
y * cw->bitmapEdit.cell_size_in_pixels);
}