/* Written by Dan Heller and Paula Ferguson.
* Copyright 1994, O'Reilly & Associates, Inc.
* Permission to use, copy, and modify this program without
* restriction is hereby granted, as long as this copyright
* notice appears in each copy of the program source code.
* This program is freely distributable without licensing fees and
* is provided without guarantee or warrantee expressed or implied.
* This program is -not- in the public domain.
*/
/* draw2.c -- extremely simple drawing program that demonstrates
* how to draw into an off screen pixmap in order to retain the
* contents of the DrawingArea widget. This allows us to redisplay
* the widget if it needs repainting (expose events).
*/
#include <Xm/DrawingA.h>
#include <Xm/PushBG.h>
#include <Xm/RowColumn.h>
#define WIDTH 400 /* arbitrary width and height values */
#define HEIGHT 300
Pixmap pixmap; /* used to redraw the DrawingArea */
main(argc, argv)
int argc;
char *argv[];
{
Widget toplevel, drawing_a, pb;
XtAppContext app;
GC gc;
void drawing_area_callback();
XtSetLanguageProc (NULL, NULL, NULL);
toplevel = XtVaAppInitialize (&app, "Demos", NULL, 0,
&argc, argv, NULL,
XmNwidth, WIDTH,
XmNheight, HEIGHT,
NULL);
/* Create a DrawingArea widget. */
drawing_a = XtVaCreateWidget ("drawing_a",
xmDrawingAreaWidgetClass, toplevel,
NULL);
/* add callback for all mouse and keyboard input events */
XtAddCallback (drawing_a, XmNinputCallback, drawing_area_callback, NULL);
XtAddCallback (drawing_a, XmNexposeCallback, drawing_area_callback, NULL);
gc = XCreateGC (XtDisplay (drawing_a),
RootWindowOfScreen (XtScreen (drawing_a)), 0, NULL);
XtVaSetValues (drawing_a, XmNuserData, gc, NULL);
XSetForeground (XtDisplay (drawing_a), gc,
WhitePixelOfScreen (XtScreen (drawing_a)));
/* create a pixmap the same size as the drawing area. */
pixmap = XCreatePixmap (XtDisplay (drawing_a),
RootWindowOfScreen (XtScreen (drawing_a)), WIDTH, HEIGHT,
DefaultDepthOfScreen (XtScreen (drawing_a)));
/* clear pixmap with white */
XFillRectangle (XtDisplay (drawing_a), pixmap, gc, 0, 0, WIDTH, HEIGHT);
/* drawing is now drawn into with "black"; change the gc for future */
XSetForeground (XtDisplay (drawing_a), gc,
BlackPixelOfScreen (XtScreen (drawing_a)));
/* add a pushbutton the user can use to clear the canvas */
pb = XtVaCreateManagedWidget ("Clear",
xmPushButtonGadgetClass, drawing_a,
NULL);
/* if activated, call same callback as XmNinputCallback. */
XtAddCallback (pb, XmNactivateCallback, drawing_area_callback, NULL);
XtManageChild (drawing_a);
XtRealizeWidget (toplevel);
XtAppMainLoop (app);
}
/* Callback routine for DrawingArea's input and expose callbacks
* as well as the PushButton's activate callback. Determine which
* it is by testing the cbs->reason field.
*/
void
drawing_area_callback(widget, client_data, call_data)
Widget widget;
XtPointer client_data;
XtPointer call_data;
{
static Position x, y;
XmDrawingAreaCallbackStruct *cbs =
(XmDrawingAreaCallbackStruct *) call_data;
XEvent *event = cbs->event;
Display *dpy = event->xany.display;
if (cbs->reason == XmCR_INPUT) {
/* activated by DrawingArea input event -- draw lines.
* Button Down events anchor the initial point and Button
* Up draws from the anchor point to the button-up point.
*/
if (event->xany.type == ButtonPress) {
/* anchor initial point (i.e., save its value) */
x = event->xbutton.x;
y = event->xbutton.y;
} else if (event->xany.type == ButtonRelease) {
/* draw full line; get GC and use in XDrawLine() */
GC gc;
XtVaGetValues (widget, XmNuserData, &gc, NULL);
XDrawLine (dpy, cbs->window, gc, x, y,
event->xbutton.x, event->xbutton.y);
/* draw into the pixmap as well for redrawing later */
XDrawLine (dpy, pixmap, gc, x, y,
event->xbutton.x, event->xbutton.y);
x = event->xbutton.x;
y = event->xbutton.y;
}
}
if (cbs->reason == XmCR_EXPOSE || cbs->reason == XmCR_ACTIVATE) {
GC gc;
if (cbs->reason == XmCR_ACTIVATE) /* Clear button pushed */
widget = XtParent (widget); /* get the DrawingArea widget */
XtVaGetValues (widget, XmNuserData, &gc, NULL);
if (cbs->reason == XmCR_ACTIVATE) { /* Clear button pushed */
/* to clear a pixmap, reverse foreground and background */
XSetForeground (dpy, gc, WhitePixelOfScreen (XtScreen (widget)));
/* ...and fill rectangle the size of the pixmap */
XFillRectangle (dpy, pixmap, gc, 0, 0, WIDTH, HEIGHT);
/* don't foreget to reset */
XSetForeground (dpy, gc, BlackPixelOfScreen (XtScreen (widget)));
}
/* Note: we don't have to use WIDTH and HEIGHT--we could pull the
* exposed area out of the event structure, but only if the reason
* was XmCR_EXPOSE... make it simple for the demo; optimize as needed.
*/
XCopyArea (dpy, pixmap, event->xany.window, gc,
0, 0, WIDTH, HEIGHT, 0, 0);
}
}