|
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: 20284 (0x4f3c) Types: TextFile Names: »BitmapEdit.c«
└─⟦8648bda34⟧ Bits:30007244 EUUGD5_II: X11R5 └─⟦2ca9b63e1⟧ »./contrib-1/contrib-1.00« └─⟦a8392fb20⟧ └─⟦this⟧ »contrib/examples/OReilly/Vol4/ch04/BitmapEdit.c« └─⟦this⟧ »contrib/examples/OReilly/Vol4/ch11/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 "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 */ #define DRAWN 1 #define UNDRAWN 0 /* modes for drawing */ #define DRAW 1 #define UNDRAW 0 #define MAXLINES 1000 /* max of horiz or vertical cells */ #define SCROLLBARWIDTH 15 #define DEFAULTWIDTH 300 /* widget size when showAll is False */ #define offset(field) XtOffsetOf(BitmapEditRec, field) static XtResource resources[] = { { XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel), offset(bitmapEdit.foreground), XtRString, XtDefaultForeground }, { 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 }, { XtNcellArray, XtCCellArray, XtRString, sizeof(String), offset(bitmapEdit.cell), XtRImmediate, (XtPointer) 0 }, { XtNshowEntireBitmap, XtCShowEntireBitmap, XtRBoolean, sizeof(Boolean), offset(bitmapEdit.showAll), XtRImmediate, (XtPointer) TRUE }, }; /* Declaration of methods */ static void Initialize(); static void Redisplay(); static void Destroy(); static void Resize(); static Boolean SetValues(); static XtGeometryResult QueryGeometry(); /* these Core methods not needed by BitmapEdit: * * static void ClassInitialize(); * static void Realize(); */ /* the following are private functions unique to BitmapEdit */ static void DrawPixmaps(), DoCell(), ChangeCellSize(); /* the following are actions of BitmapEdit */ static void DrawCell(), UndrawCell(), ToggleCell(); /* The following are public functions of BitmapEdit, declared extern * in the public include file: */ char *BitmapEditGetArrayString(); static char defaultTranslations[] = "<Btn1Down>: DrawCell() \n\ <Btn2Down>: UndrawCell() \n\ <Btn3Down>: ToggleCell() \n\ <Btn1Motion>: DrawCell() \n\ <Btn2Motion>: UndrawCell() \n\ <Btn3Motion>: ToggleCell()"; static XtActionsRec actions[] = { {"DrawCell", DrawCell}, {"UndrawCell", UndrawCell}, {"ToggleCell", ToggleCell}, }; /* definition in BitmapEdit.h */ static BitmapEditPointInfo info; BitmapEditClassRec bitmapEditClassRec = { { /* core_class fields */ /* superclass */ (WidgetClass) &coreClassRec, /* 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 */ XtExposeCompressMultiple, /* 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 */ QueryGeometry, /* display_accelerator */ XtInheritDisplayAccelerator, /* extension */ 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 GetCopyGC(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.copy_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; } if (new->bitmapEdit.cell == NULL) 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) { if (new->bitmapEdit.showAll == False) new->core.width = (new->bitmapEdit.pixmap_width_in_pixels > DEFAULTWIDTH) ? DEFAULTWIDTH : (new->bitmapEdit.pixmap_width_in_pixels); else new->core.width = new->bitmapEdit.pixmap_width_in_pixels; } if (new->core.height == 0) { if (new->bitmapEdit.showAll == False) new->core.height = (new->bitmapEdit.pixmap_height_in_pixels > DEFAULTWIDTH) ? DEFAULTWIDTH : (new->bitmapEdit.pixmap_height_in_pixels); else new->core.height = new->bitmapEdit.pixmap_height_in_pixels; } CreateBigPixmap(new); GetDrawGC(new); GetUndrawGC(new); GetCopyGC(new); DrawIntoBigPixmap(new); } /* 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 or expose */ x = event->x; y = event->y; width = event->width; height = event->height; } else { /* called because complete redraw */ 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.copy_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.copy_gc, x + cw->bitmapEdit.cur_x, y + cw->bitmapEdit.cur_y, width, height, x, y, 1); } /* 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.copy_gc); GetCopyGC(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.cell_size_in_pixels != newcw->bitmapEdit.cell_size_in_pixels) { ChangeCellSize(curcw, newcw->bitmapEdit.cell_size_in_pixels); do_redisplay = True; } if (curcw->bitmapEdit.pixmap_width_in_cells != newcw->bitmapEdit.pixmap_width_in_cells) { newcw->bitmapEdit.pixmap_width_in_cells = curcw->bitmapEdit.pixmap_width_in_cells; XtWarning("BitmapEdit: pixmap_width_in_cells cannot be set by XtSetValues.\n"); } if (curcw->bitmapEdit.pixmap_height_in_cells != newcw->bitmapEdit.pixmap_height_in_cells) { newcw->bitmapEdit.pixmap_height_in_cells = curcw->bitmapEdit.pixmap_height_in_cells; XtWarning("BitmapEdit: pixmap_height_in_cells cannot be set by XtSetValues.\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); if (cw->bitmapEdit.copy_gc) XFreeGC(XtDisplay(cw), cw->bitmapEdit.copy_gc); /* NOTE! This should only free when the application didn't * allocate it. Need to add another. */ XtFree(cw->bitmapEdit.cell); } static void DrawCell(w, event) Widget w; XEvent *event; { BitmapEditWidget cw = (BitmapEditWidget) w; DrawPixmaps(cw->bitmapEdit.draw_gc, DRAW, cw, event); } static void UndrawCell(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; GC gc; int mode; 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 ((mode = cw->bitmapEdit.cell[newx + newy * cw->bitmapEdit.pixmap_width_in_cells]) == DRAWN) { gc = cw->bitmapEdit.undraw_gc; mode = UNDRAW; } else { gc = cw->bitmapEdit.draw_gc; mode = DRAW; } if (oldx != newx || oldy != newy) { oldx = newx; oldy = newy; DrawPixmaps(gc, mode, cw, event); } } static void DrawPixmaps(gc, mode, w, event) GC gc; int 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; /* otherwise, draw or undraw */ XFillRectangle(XtDisplay(cw), cw->bitmapEdit.big_picture, gc, cw->bitmapEdit.cell_size_in_pixels*newx + 2, cw->bitmapEdit.cell_size_in_pixels*newy + 2, (unsigned int)cw->bitmapEdit.cell_size_in_pixels - 3, (unsigned int)cw->bitmapEdit.cell_size_in_pixels - 3); 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); } 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 + 2, cw->bitmapEdit.pixmap_height_in_pixels + 2, 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++) { 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++) { 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); /* draw current cell array into pixmap */ for (x = 0; x < cw->bitmapEdit.pixmap_width_in_cells; x++) { for (y = 0; y < cw->bitmapEdit.pixmap_height_in_cells; y++) { if (cw->bitmapEdit.cell[x + (y * cw->bitmapEdit.pixmap_width_in_cells)] == DRAWN) DoCell(cw, x, y, cw->bitmapEdit.draw_gc); else DoCell(cw, x, y, cw->bitmapEdit.undraw_gc); } } } /* 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; /* resize does nothing unless new size is bigger than entire pixmap */ if ((cw->core.width > cw->bitmapEdit.pixmap_width_in_pixels) && (cw->core.height > cw->bitmapEdit.pixmap_height_in_pixels)) { /* * Calculate the maximum cell size that will allow the * entire bitmap to be displayed. */ Dimension w_temp_cell_size_in_pixels, h_temp_cell_size_in_pixels; Dimension new_cell_size_in_pixels; w_temp_cell_size_in_pixels = cw->core.width / cw->bitmapEdit.pixmap_width_in_cells; h_temp_cell_size_in_pixels = cw->core.height / cw->bitmapEdit.pixmap_height_in_cells; if (w_temp_cell_size_in_pixels < h_temp_cell_size_in_pixels) new_cell_size_in_pixels = w_temp_cell_size_in_pixels; else new_cell_size_in_pixels = h_temp_cell_size_in_pixels; /* if size change mandates a new pixmap, make one */ if (new_cell_size_in_pixels != cw->bitmapEdit.cell_size_in_pixels) ChangeCellSize(cw, new_cell_size_in_pixels); } } static void ChangeCellSize(w, new_cell_size) Widget w; int new_cell_size; { BitmapEditWidget cw = (BitmapEditWidget) w; int x, y; cw->bitmapEdit.cell_size_in_pixels = new_cell_size; /* recalculate variables based on cell size */ cw->bitmapEdit.pixmap_width_in_pixels = cw->bitmapEdit.pixmap_width_in_cells * cw->bitmapEdit.cell_size_in_pixels; cw->bitmapEdit.pixmap_height_in_pixels = cw->bitmapEdit.pixmap_height_in_cells * cw->bitmapEdit.cell_size_in_pixels; /* destroy old and create new pixmap of correct size */ XFreePixmap(XtDisplay(cw), cw->bitmapEdit.big_picture); CreateBigPixmap(cw); /* draw lines into new pixmap */ DrawIntoBigPixmap(cw); /* draw current cell array into pixmap */ for (x = 0; x < cw->bitmapEdit.pixmap_width_in_cells; x++) { for (y = 0; y < cw->bitmapEdit.pixmap_height_in_cells; y++) { if (cw->bitmapEdit.cell[x + (y * cw->bitmapEdit.pixmap_width_in_cells)] == DRAWN) DoCell(cw, x, y, cw->bitmapEdit.draw_gc); else DoCell(cw, x, y, cw->bitmapEdit.undraw_gc); } } } static void DoCell(w, x, y, gc) Widget w; int x, y; GC gc; { BitmapEditWidget cw = (BitmapEditWidget) w; /* otherwise, 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); } static XtGeometryResult QueryGeometry(w, proposed, answer) Widget w; XtWidgetGeometry *proposed, *answer; { BitmapEditWidget cw = (BitmapEditWidget) w; answer->request_mode = CWWidth | CWHeight; /* initial width and height */ if (cw->bitmapEdit.showAll == True) answer->width = cw->bitmapEdit.pixmap_width_in_pixels; else answer->width = (cw->bitmapEdit.pixmap_width_in_pixels > DEFAULTWIDTH) ? DEFAULTWIDTH : cw->bitmapEdit.pixmap_width_in_pixels; if (cw->bitmapEdit.showAll == True) answer->height = cw->bitmapEdit.pixmap_height_in_pixels; else answer->height = (cw->bitmapEdit.pixmap_height_in_pixels > DEFAULTWIDTH) ? DEFAULTWIDTH : cw->bitmapEdit.pixmap_height_in_pixels; if ( ((proposed->request_mode & (CWWidth | CWHeight)) == (CWWidth | CWHeight)) && proposed->width == answer->width && proposed->height == answer->height) return XtGeometryYes; else if (answer->width == cw->core.width && answer->height == cw->core.height) return XtGeometryNo; else return XtGeometryAlmost; }