10.3 An Example
Let’s suppose that you want to display a list of icons that have dimensions of 64x64. You
wish to display the icons in rows and columns in a canvas. Because there may be more icons
than the canvas can display at once, you attach scrollbars to the canvas. When the user uses
the scrollbars to view the icons, each scrolling action should scroll an entire icon or set of
icons into view. Paging should scroll the next page of icons into view.
For demonstration purposes, rather than display actual icons, we present a grid where each
cell in the grid represents an icon (see Figure 10-5).
1.1
2.1
3.1
4.1
5.1
6.1
7.1
1.2
2.2
3.2
4.2
5.2
6.2
7.2
1.3
2.3
3.3
4.3
5.3
6.3
7.3
1.4
2.4
3.4
4.4
5.4
6.4
7.4
8.4
1.5
2.5
3.5
4.5
5.5
6.5
7.5
8.5
1.6
2.6
3.6
4.6
5.6
6.6
7.6
8.6
1.7
2.7
3.7
4.7
5.7
6.7
7.7
8.7
3.2
4.2
5.2
6.2
7.2
3.3
4.3
5.3
6.3
7.3
3.4
4.4
5.4
6.4
7.4
3.5
4.5
5.5
6.5
7.5
3.6
4.6
5.6
6.6
7.6
3.2
4.2
5.2
6.2
7.2
3.3
4.3
5.3
6.3
7.3
3.4
4.4
5.4
6.4
7.4
3.5
4.5
5.5
6.5
7.5
3.6
4.6
5.6
6.6
7.6
backing
bitmap
canvas
subwindow
base frame with
canvas subwindow
Figure 10-5. Model for scroll_cells.c
258 XView Programming Manual
Each cell is considered a unit to the scrollbars, so the number of pixels per scrollbar-unit
must be set to the size of the cell. Thus, the attribute SCROLLBAR_PIXELS_PER_UNIT is set
to 64 for each scrollbar (the width and height are the same). With this attribute set, when the
user selects an arrow on the scrollbar, an entire cell is scrolled into view (depending on which
arrow is selected).
We set SCROLLBAR_PAGE_LENGTH to be the same as SCROLLBAR_VIEW_LENGTH to specify
the paging size. When the user selects any part of the scrollbar cable, the view is paged and a
new set of icons is scrolled into view (depending on which side of the elevator is selected).
The page length could be set to one unit less than the view length, so that paging causes the
last cell in the old block to be the first cell in the new block. Remember, the “lengths” men-
tioned here are given in units.
The setting of the scrollbar unit size also assures that the upper-left corner of a cell maps to
the upper-left corner of the window so as not to display a portion of the cell. This guarantee
cannot be made for the lower and right-hand edges of the window because we cannot control
the resizing of the frame by the user.
In the program in Example 10-1, the variable cell_map is a Pixmap of depth 1. But, the
depth is arbitrary—we use 1 because we know that the icons we are displaying are of depth
1. The canvas, on the other hand, may be any depth at all; color canvases have a depth
greater than 1. Copying drawables of different depths onto one another is an X Protocol
error, so we use XCopyPlane() to guarantee that the pixmap is rendered into the canvas
correctly.
Example 10-1. The scroll_cells.c program
/*
* scroll_cells.c -- scroll a bitmap of cells around in a canvas.
* The cells are rectangular areas labeled with numbers which may
* represent arbitrary data such as icon images. The cell sizes are
* defined to be 64 by 64 aligned in rows and columns. This example
* is used to demonstrate how to configure scrollbars to accommodate
* arbitrary data within a window.
*/
#include <stdio.h>
#include <X11/X.h>
#include <X11/Xlib.h> /* Using Xlib graphics */
#include <xview/xview.h>
#include <xview/canvas.h>
#include <xview/scrollbar.h>
#include <xview/font.h>
#include <xview/xv_xrect.h>
#define CELL_WIDTH 64
#define CELL_HEIGHT 64
#define CELLS_PER_HOR_PAGE 5 /* when paging w/scrollbar */
#define CELLS_PER_VER_PAGE 5 /* when paging w/scrollbar */
#define CELLS_PER_ROW 8
#define CELLS_PER_COL 16
Pixmap cell_map; /* pixmap copied onto canvas window */
Scrollbar horiz_scrollbar;
Scrollbar vert_scrollbar;
Scrollbars
Scrollbars 259
Example 10-1. The scroll_cells.c program (continued)
GC gc; /* General usage GC */
main(argc, argv)
int argc;
char *argv[ ];
{
Frame frame;
Canvas canvas;
void repaint_proc();
/* Initialize, create frame and canvas... */
xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, NULL);
frame = (Frame)xv_create(XV_NULL, FRAME,
FRAME_LABEL, argv[0],
FRAME_SHOW_FOOTER, TRUE,
NULL);
canvas = (Canvas)xv_create(frame, CANVAS,
/* make subwindow the size of a "page" */
XV_WIDTH, CELL_WIDTH * CELLS_PER_HOR_PAGE,
XV_HEIGHT, CELL_HEIGHT * CELLS_PER_VER_PAGE,
/* canvas is much larger than the window */
CANVAS_WIDTH, CELL_WIDTH * CELLS_PER_ROW + 1,
CANVAS_HEIGHT, CELL_HEIGHT * CELLS_PER_COL + 1,
CANVAS_AUTO_EXPAND, FALSE,
CANVAS_AUTO_SHRINK, FALSE,
/* dont retain window -- well need
* to repaint it all the time */
CANVAS_RETAINED, FALSE,
/* were using Xlib graphics calls in repaint_proc() */
CANVAS_X_PAINT_WINDOW, TRUE,
CANVAS_REPAINT_PROC, repaint_proc,
/* well be repainting over exposed areas,
* so dont bother clearing */
OPENWIN_AUTO_CLEAR, FALSE,
NULL);
/*
* Create scrollbars attached to the canvas. When user clicks
* on cable, page by the page size (PAGE_LENGTH). Scrolling
* should move cell by cell, not by one pixel (PIXELS_PER_UNIT).
*/
vert_scrollbar = xv_create(canvas, SCROLLBAR,
SCROLLBAR_DIRECTION, SCROLLBAR_VERTICAL,
SCROLLBAR_PIXELS_PER_UNIT, CELL_HEIGHT,
SCROLLBAR_OBJECT_LENGTH, CELLS_PER_COL,
SCROLLBAR_PAGE_LENGTH, CELLS_PER_VER_PAGE,
SCROLLBAR_VIEW_LENGTH, CELLS_PER_VER_PAGE,
NULL);
horiz_scrollbar = xv_create(canvas, SCROLLBAR,
SCROLLBAR_DIRECTION, SCROLLBAR_HORIZONTAL,
SCROLLBAR_PIXELS_PER_UNIT, CELL_WIDTH,
SCROLLBAR_OBJECT_LENGTH, CELLS_PER_ROW,
SCROLLBAR_PAGE_LENGTH, CELLS_PER_HOR_PAGE,
SCROLLBAR_VIEW_LENGTH, CELLS_PER_HOR_PAGE,
260 XView Programming Manual
Example 10-1. The scroll_cells.c program (continued)
NULL);
/*
* create pixmap and draw cells into it ... this is the abstraction.
* The cell_map is copied into the window via XCopyPlane in the
* repaint procedure.
*/
{
short x, y, pt = 0;
Xv_Font font;
XPoint points[256]; /* keep Xlib calls to a minimum */
XGCValues gcvalues;
Display *dpy = (Display *)xv_get(canvas, XV_DISPLAY);
font = (Xv_Font)xv_find(frame, FONT,
FONT_NAME, "icon",
NULL);
cell_map = XCreatePixmap(dpy, DefaultRootWindow(dpy),
CELLS_PER_ROW * CELL_WIDTH + 1,
CELLS_PER_COL * CELL_HEIGHT + 1,
1); /* We only need a 1-bit deep pixmap */
/* Create the gc for the cell_map -- since it is 1-bit deep,
* use 0 and 1 for fg/bg values. Also, limit number of
* events generated by setting graphics exposures to False.
*/
gcvalues.graphics_exposures = False;
gcvalues.background = 0;
gcvalues.foreground = 1;
if (font)
gcvalues.font = (Font)xv_get(font, XV_XID);
gc = XCreateGC(dpy, cell_map,
GCFont|GCForeground|GCBackground|GCGraphicsExposures,
&gcvalues);
if (!font) {
/* dot every other pixel */
for (x = 0; x <= CELL_WIDTH * CELLS_PER_ROW; x += 2)
for (y = 0; y <= CELL_HEIGHT * CELLS_PER_COL; y += 2) {
if (x % CELL_WIDTH != 0 && y % CELL_HEIGHT != 0)
continue;
points[pt].x = x, points[pt].y = y;
if (++pt == sizeof points / sizeof points[0]) {
XDrawPoints(dpy, cell_map, gc, points, pt,
CoordModeOrigin);
pt = 0;
}
}
if (pt != sizeof points) /* flush remaining points */
XDrawPoints(dpy, cell_map, gc,
points, pt, CoordModeOrigin);
}
/* Icon font not available. Instead, label each cell
* with a string describing the cells coordinates.
*/
for (x = 0; x < CELLS_PER_ROW; x++)
Scrollbars
Scrollbars 261
Example 10-1. The scroll_cells.c program (continued)
for (y = 0; y < CELLS_PER_COL; y++) {
char buf[8 ];
if (!font) {
sprintf(buf, "%d,%d", x+1, y+1);
XDrawString(dpy, cell_map, gc,
x * CELL_WIDTH + 5, y * CELL_HEIGHT + 25,
buf, strlen(buf));
} else {
buf[0 ] = x + y * CELLS_PER_COL;
XDrawString(dpy, cell_map, gc,
x * CELL_WIDTH, y * CELL_HEIGHT, buf, 1);
}
}
/* were now done with the cell_map, so free gc and create
* a new one based on the window that will use it. Otherwise,
* the GC may not work because of different depths.
*/
if (font)
xv_destroy(gc);
XFreeGC(dpy, gc);
gcvalues.background = WhitePixel(dpy, DefaultScreen(dpy));
gcvalues.foreground = BlackPixel(dpy, DefaultScreen(dpy));
gcvalues.plane_mask = 1L;
gc = XCreateGC(dpy, DefaultRootWindow(dpy),
GCForeground|GCBackground|GCGraphicsExposures, &gcvalues);
}
/* shrink frame to minimal size and start notifier */
window_fit(frame);
xv_main_loop(frame);
}
/*
* The repaint procedure is called whenever repainting is needed in
* a paint window. Since the canvas is not retained, this routine
* is going to be called any time the user scrolls the canvas. The
* canvas will handle repainting the portion of the canvas that
* was in view and has scrolled onto another viewable portion of
* the window. The xrects parameter will cover the new areas that
* were not in view before and have just scrolled into view. If
* the window resizes or if the window is exposed by other windows
* disappearing or cycling through the window tree, then the number
* of xrects will be more than one and well have to copy the new
* areas one by one. Clipping isnt necessary since the areas to
* be rendered are set by the xrects value.
*/
void
repaint_proc(canvas, paint_window, dpy, win, xrects)
Canvas canvas;
Xv_Window paint_window;
Display *dpy;
Window win;
Xv_xrectlist *xrects;
{
int x, y;
262 XView Programming Manual

Get Volume 7A: XView Programming Manual now with O’Reilly online learning.

O’Reilly members experience live online training, plus books, videos, and digital content from 200+ publishers.