|
|
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: T s
Length: 21520 (0x5410)
Types: TextFile
Names: »sxScrollbar.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki
└─⟦526ad3590⟧ »EUUGD11/gnu-31mar87/X.V10.R4.tar.Z«
└─⟦2109abc41⟧
└─⟦this⟧ »./X.V10R4/Toolkit/Sx/code/sxScrollbar.c«
/*
* $Source: /u1/Sx.new/code/RCS/sxScrollbar.c,v $
* $Header: sxScrollbar.c,v 1.1 86/12/03 16:10:45 swick Exp $
*/
#ifndef lint
static char *rcsid_sxScrollbar_c = "$Header: sxScrollbar.c,v 1.1 86/12/03 16:10:45 swick Exp $";
#endif lint
/*
* sxScrollbar.c --
*
* This module implements scrollbars on top of the X window
* package.
*
* Copyright (C) 1986 Regents of the University of California.
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
#ifndef lint
static char rcsid[] = "$Header: sxScrollbar.c,v 1.1 86/12/03 16:10:45 swick Exp $ SPRITE (Berkeley)";
#endif not lint
#include <sys/types.h>
#include <X/Xlib.h>
#include "sprite.h"
#include "mem.h"
#include "sx.h"
/*
* The structure type below is used to hold information about a scrollbar:
*/
typedef struct Scrollbar {
Window window; /* Window corresponding to scrollbar. */
int foreground, background, elevatorColor;
/* Colors to use when displaying scrollbar. */
int width, height; /* Dimensions of scrollbar window. */
float top, bottom; /* Range of view. Each number is a fraction
* between 0 and 1. Top gives the position
* of the top (or left) edge of the view,
* as a fraction of the height (or width)
* of the object being displayed. Bottom
* gives the same information for the bottom
* (or right) edge of the view. */
int flags; /* Miscellaneous flag values: see below. */
void (*proc)(); /* Procedure to call when scrollbar is
* buttoned.
*/
ClientData clientData; /* Info to pass to proc. */
} Scrollbar;
/*
* Scrollbar flags:
*
* VERTICAL: 1 means scrollbar has vertical orientation, 0
* means it has horizontal orientation.
*/
#define VERTICAL 1
/*
* Widths of various parts of scrollbars, in pixels:
*/
#define WIDTH 13
#define ELEVATOR_MARGIN 3
/*
* Other information used to display scrollbars:
*/
#define BGSIZE 16
static short bgBits[] = { /* Bit pattern for background. */
0x0, 0x2222, 0x0, 0x8888,
0x0, 0x2222, 0x0, 0x8888,
0x0, 0x2222, 0x0, 0x8888,
0x0, 0x2222, 0x0, 0x8888
};
static int bgWidth, bgHeight; /* Dimensions to use for tile. Either dimension
* may be up to BGSIZE. */
/*
* The cursors used by the scrollbar package are defined in separate files
* so they can be edited with the "bitmap" program. See the procedure
* ScrollButtonProc for usage.
*/
#include "cursors/left"
#include "cursors/leftMask"
#include "cursors/right"
#include "cursors/rightMask"
#include "cursors/up"
#include "cursors/upMask"
#include "cursors/down"
#include "cursors/downMask"
#include "cursors/vert"
#include "cursors/vertMask"
#include "cursors/horiz"
#include "cursors/horizMask"
#include "cursors/thumbH"
#include "cursors/thumbHMask"
#include "cursors/thumbV"
#include "cursors/thumbVMask"
static Cursor cursorUp, cursorDown, cursorLeft, cursorRight;
static Cursor cursorHoriz, cursorVert, cursorThumbV, cursorThumbH;
static Boolean init = FALSE;
/*
* The association table below is used to map from X window ids
* to our internal Scrollbar structures.
*/
static XAssocTable *scrollbarTable = NULL;
extern XAssocTable *XCreateAssocTable();
/*
* Forward references:
*/
extern void ScrollbarInit();
extern void ScrollButtonProc();
extern void ScrollComputeLoc();
extern void ScrollDestroyProc();
extern void ScrollExposeProc();
extern void ScrollRedisplay();
\f
/*
*----------------------------------------------------------------------
*
* Sx_ScrollbarMake --
*
* Given an existing window, this procedure sets things up so that
* it will behave like a scrollbar.
*
* Results:
* None.
*
* Side effects:
* Data structures are set up so that window will behave like a
* scrollbar: whenever a user clicks a button in the scrollbar,
* proc will be invoked in the following way:
*
* void
* proc(clientData, distance, units, window)
* ClientData clientData;
* float distance;
* int units;
* Window window;
* {
* }
*
* The clientData parameter is the same as the parameter by the
* same name passed to this routine. It has no meaning to the
* scrollbar code, but is typically used to point to information
* relevant to the client. Distance and units indicate the scroll
* action requested by the user, and window of the window parameter
* passed to this procedure. If units is SX_SCROLL_ABSOLUTE,
* then distance gives a value between 0 and 1 indicating the
* desired positioning of the window's view: 0 means at the very
* top or right or beginning and 1 means at the very bottom or
* left or end. Otherwise, units is SX_SCROLL_PAGES, and distance
* gives a value between -1 and 1 indicating how much the window
* should be scrolled up or down: 1 means the window should be
* scrolled up (left) by its size and -1 means the window should
* be scrolled down (right) by its size.
*
* The scrollbar module does not actually adjust the position of
* the scrollbar elevator: proc must do that (if it wishes) by
* calling Sx_ScrollbarSetRange. If proc doesn't call
* Sx_ScrollbarSetRange, it means that it wishes to override the
* user's request for a change in position and not change anything.
*
*----------------------------------------------------------------------
*/
void
Sx_ScrollbarMake(window, vertical, foreground, background,
elevatorColor, proc, clientData)
Window window; /* Window to make into scrollbar. If this
* window is already a scrollbar, then the
* call just changes the scrollbar's
* parameters (and redisplays it). If the
* window isn't already a scrollbar, then
* it should not be mapped (this proc won't
* redisplay it). */
Boolean vertical; /* TRUE means use vertical scrollbar
* orientation, FALSE means horizontal. */
int foreground; /* Pixel value to use for the dark part of
* the scrollbar background. BlackPixel
* is typical. */
int background; /* Pixel value to use for the light part of
* the scrollbar background. WhitePixel
* is typical. */
int elevatorColor; /* Pixel value to use for the elevator that
* shows current scroll position. WhitePixel
* is typical. */
void (*proc)(); /* Procedure to call when scrollbar is buttoned
* by user. */
ClientData clientData; /* Arbitrary data to pass to proc. */
{
register Scrollbar *sbPtr;
Bitmap tmp;
Pixmap tile;
if (!init) {
ScrollbarInit();
}
/*
* If the display can accomodate tiles that fit in our background
* bitmap, then make a background pixmap from it. Otherwise, use a
* solid background bitmap in the light color.
*/
if ((bgWidth <= BGSIZE) && (bgHeight <= BGSIZE)) {
tmp = XStoreBitmap(bgWidth, bgHeight, bgBits);
if (tmp == 0) {
error:
Sx_Panic("Sx_ScrollbarMake: couldn't create background tile");
}
tile = XMakePixmap(tmp, foreground, background);
XFreeBitmap(tmp);
} else {
tile = XMakeTile(background);
}
if (tile == NULL) {
goto error;
}
XChangeBackground(window, tile);
XFreePixmap(tile);
/*
* See if this window is already a scrollbar. If not, create a new
* one.
*/
sbPtr = (Scrollbar *) XLookUpAssoc(scrollbarTable, window);
if (sbPtr == NULL) {
sbPtr = (Scrollbar *) Mem_Alloc(sizeof(Scrollbar));
sbPtr->window = window;
sbPtr->height = sbPtr->width = 0;
sbPtr->top = 0.0;
sbPtr->bottom = 1.0;
(void) Sx_HandlerCreate(window, ExposeWindow, ScrollExposeProc,
(ClientData) sbPtr);
(void) Sx_HandlerCreate(window, ButtonPressed|ButtonReleased,
ScrollButtonProc, (ClientData) sbPtr);
(void) Sx_HandlerCreate(window, KeyPressed|KeyReleased
|EnterWindow|LeaveWindow, Sx_NullProc, (ClientData) NULL);
(void) Sx_HandlerCreate(window, SX_DESTROYED, ScrollDestroyProc,
(ClientData) sbPtr);
XMakeAssoc(scrollbarTable, window, (caddr_t) sbPtr);
}
/*
* Complete the initialization.
*/
sbPtr->foreground = foreground;
sbPtr->background = background;
sbPtr->elevatorColor = elevatorColor;
if (vertical) {
sbPtr->flags = VERTICAL;
XDefineCursor(window, cursorVert);
} else {
sbPtr->flags = 0;
XDefineCursor(window, cursorHoriz);
}
sbPtr->proc = proc;
sbPtr->clientData = clientData;
if ((sbPtr->width > 0) && (sbPtr->height > 0)) {
ScrollRedisplay(sbPtr);
}
}
\f
/*
*----------------------------------------------------------------------
*
* Sx_ScrollbarCreate --
*
* Create a new scrollbar window. Similar to Sx_ScrollbarMake
* except that it creates the window and arranges for the packer
* to manage its geometry.
*
* Results:
* The return value is an X window id for a new scrollbar, which
* will always appear on the side'th side of parent.
*
* Side effects:
* Data structures are set up so that window will behave like a
* scrollbar: whenever a user clicks a button in the scrollbar,
* proc will be invoked in the same way as for Sx_MakeScrollbar.
*
*----------------------------------------------------------------------
*/
Window
Sx_ScrollbarCreate(parent, side, foreground, background, elevatorColor,
proc, clientData)
Window parent; /* Parent window in which to create new
* scrollbar. */
Sx_Side side; /* Which side of parent scrollbar should
* be displayed on. */
int foreground; /* Pixel value to use for the dark part of
* the scrollbar background. BlackPixel
* is typical. */
int background; /* Pixel value to use for the light part of
* the scrollbar background. WhitePixel
* is typical. */
int elevatorColor; /* Pixel value to use for the elevator that
* shows current scroll position. WhitePixel
* is typical. */
void (*proc)(); /* Procedure to call when scrollbar is buttoned
* by user. */
ClientData clientData; /* Arbitrary data to pass to proc. */
{
Window w;
Boolean vertical;
Pixmap borderPixmap;
if (foreground == BlackPixel) {
borderPixmap = BlackPixmap;
} else if (foreground == WhitePixel) {
borderPixmap = WhitePixmap;
} else {
borderPixmap = XMakeTile(foreground);
if (borderPixmap == NULL) {
Sx_Panic("Sx_ScrollbarCreate: couldn't create border pixmap.");
}
}
w = Sx_CreatePacked(parent, side, WIDTH, 1, (Window) 0, (Window) 0,
borderPixmap, WhitePixmap);
if ((borderPixmap != BlackPixmap) && (borderPixmap != WhitePixmap)) {
XFreePixmap(borderPixmap);
}
vertical = ((side == SX_LEFT) || (side == SX_RIGHT));
Sx_ScrollbarMake(w, vertical, foreground, background, elevatorColor,
proc, clientData);
return w;
}
\f
/*
*----------------------------------------------------------------------
*
* Sx_ScrollbarSetRange --
*
* This procedure is used to indicate the position of the elevator
* in a scrollbar.
*
* Results:
* None.
*
* Side effects:
* The elevator will be redisplayed to indicate the fraction
* of the object or file that is currently visible in the window.
* Top and bottom indicate this fraction.
*
*----------------------------------------------------------------------
*/
void
Sx_ScrollbarSetRange(window, top, bottom)
Window window; /* X id for window containing scrollbar. */
float top; /* The position of the top (or left) of the
* window's view, relative to the overall
* size of the file or object being
* displayed. Must be between 0 and 1.
* 0 means the top or left of the window is
* at the beginning or top or left of the
* file or object, and 1 means it's at the
* bottom or right of the object. */
float bottom; /* Similar to top, but indicates where the
* bottom or right side of the view is
* located. */
{
register Scrollbar *sbPtr;
/*
* Locate our data structures for the scrollbar.
*/
sbPtr = (Scrollbar *) XLookUpAssoc(scrollbarTable, window);
if (sbPtr == NULL) {
Sx_Panic("Sx_ScrollbarSetRange: not a scrollbar window.");
}
if (top > 1.0) {
top = 1.0;
} else if (top < 0.0) {
top = 0.0;
}
if (bottom > 1.0) {
bottom = 1.0;
} else if (bottom < top) {
bottom = top;
}
if ((sbPtr->top == top) && (sbPtr->bottom == bottom)) {
return;
}
sbPtr->top = top;
sbPtr->bottom = bottom;
ScrollRedisplay(sbPtr);
}
\f
/*
*----------------------------------------------------------------------
*
* Sx_ScrollbarGetRange --
*
* Returns the current range displayed in the scrollbar.
*
* Results:
* The values pointed to by topPtr and bottomPtr are filled
* in with the last values of top and bottom passed to
* Sx_ScrollbarSetRange for this scrollbar.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
Sx_ScrollbarGetRange(window, topPtr, bottomPtr)
Window window; /* X id for window containing scrollbar. */
float *topPtr; /* Put top value (between 0 and 1) here. */
float *bottomPtr; /* Put bottom value (between 0 and 1) here. */
{
register Scrollbar *sbPtr;
/*
* Locate our data structure for the scrollbar.
*/
sbPtr = (Scrollbar *) XLookUpAssoc(scrollbarTable, window);
if (sbPtr == NULL) {
Sx_Panic("Sx_ScrollbarGetRange: not a scrollbar window.");
}
*topPtr = sbPtr->top;
*bottomPtr = sbPtr->bottom;
}
\f
/*
*----------------------------------------------------------------------
*
* Sx_ScrollbarWidth --
*
* Returns a suggested width for scrollbars, in pixels.
*
* Results:
* The return value is the suggested width of scrollbars, in pixels
* not including the border. This may be of use to clients in
* laying out windows.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
int
Sx_ScrollbarWidth()
{
return WIDTH;
}
\f
/*
*----------------------------------------------------------------------
*
* ScrollDestroyProc --
*
* Called by the Sx dispatcher whenever a scrollbar window is deleted.
*
* Results:
* None.
*
* Side effects:
* Resources associated with the scrollbar will be freed up.
*
*----------------------------------------------------------------------
*/
static void
ScrollDestroyProc(sbPtr)
register Scrollbar *sbPtr; /* Internal structure for scrollbar. */
{
XDeleteAssoc(scrollbarTable, sbPtr->window);
Mem_Free((char *) sbPtr);
}
\f
/*
*----------------------------------------------------------------------
*
* ScrollbarInit --
*
* Performs once-only initialization for the scrollbar module.
*
* Results:
* None.
*
* Side effects:
* Generally-useful stuff, like the cursors, gets created and set up.
*
*----------------------------------------------------------------------
*/
static void
ScrollbarInit()
{
cursorUp = XCreateCursor(up_width, up_height, up_bits, upMask_bits,
up_x_hot, up_y_hot, BlackPixel, WhitePixel, GXcopy);
cursorDown = XCreateCursor(down_width, down_height, down_bits,
downMask_bits, down_x_hot, down_y_hot,
BlackPixel, WhitePixel, GXcopy);
cursorLeft = XCreateCursor(left_width, left_height, left_bits,
leftMask_bits, left_x_hot, left_y_hot,
BlackPixel, WhitePixel, GXcopy);
cursorRight = XCreateCursor(right_width, right_height, right_bits,
rightMask_bits, right_x_hot, right_y_hot,
BlackPixel, WhitePixel, GXcopy);
cursorVert = XCreateCursor(vert_width, vert_height, vert_bits,
vertMask_bits, vert_x_hot, vert_y_hot,
BlackPixel, WhitePixel, GXcopy);
cursorHoriz = XCreateCursor(horiz_width, horiz_height, horiz_bits,
horizMask_bits, horiz_x_hot, horiz_y_hot,
BlackPixel, WhitePixel, GXcopy);
cursorThumbV = XCreateCursor(thumbV_width, thumbV_height, thumbV_bits,
thumbVMask_bits, thumbV_x_hot, thumbV_y_hot,
BlackPixel, WhitePixel, GXcopy);
cursorThumbH = XCreateCursor(thumbH_width, thumbH_height, thumbH_bits,
thumbHMask_bits, thumbH_x_hot, thumbH_y_hot,
BlackPixel, WhitePixel, GXcopy);
scrollbarTable = XCreateAssocTable(4);
/*
* Find out about how big background tiles have to be, and see if
* our background pattern will work.
*/
XQueryTileShape(BGSIZE, BGSIZE, &bgWidth, &bgHeight);
if ((cursorUp == 0) || (cursorDown == 0) || (cursorLeft == 0)
|| (cursorRight == 0) || (cursorVert == 0) || (cursorHoriz == 0)
|| (cursorThumbV == 0) || (cursorThumbH == 0)
|| (scrollbarTable == NULL)) {
Sx_Panic("Sx_ScrollbarMake: couldn't initialize cursors and/or hash table.");
}
init = TRUE;
}
\f
/*
*----------------------------------------------------------------------
*
* ScrollRedisplay --
*
* This procedure is invoked to redisplay scrollbars.
*
* Results:
* None.
*
* Side effects:
* The scrollbar gets redisplayed.
*
*----------------------------------------------------------------------
*/
static void
ScrollRedisplay(sbPtr)
register Scrollbar *sbPtr; /* Scrollbar to be redisplayed. */
{
int x, y, width, height;
/*
* Compute location of elevator bar, then display it.
*/
XClear(sbPtr->window);
if (sbPtr->flags & VERTICAL) {
x = ELEVATOR_MARGIN;
y = sbPtr->height*sbPtr->top;
width = sbPtr->width - 2*ELEVATOR_MARGIN;
height = sbPtr->height*sbPtr->bottom;
height -= y;
} else {
x = sbPtr->width*sbPtr->top;
y = ELEVATOR_MARGIN;
width = sbPtr->width*sbPtr->bottom;
width -= x;
height = sbPtr->height - 2*ELEVATOR_MARGIN;
}
if ((width <= 0) || (height <= 0)) {
return;
}
XPixSet(sbPtr->window, x, y, width, height, sbPtr->elevatorColor);
width -= 1;
height -= 1;
XLine(sbPtr->window, x, y, x+width, y, 1, 1, sbPtr->foreground,
GXcopy, AllPlanes);
XLine(sbPtr->window, x, y, x, y+height, 1, 1, sbPtr->foreground,
GXcopy, AllPlanes);
XLine(sbPtr->window, x+width, y, x+width, y+height, 1, 1,
sbPtr->foreground, GXcopy, AllPlanes);
XLine(sbPtr->window, x, y+height, x+width, y+height, 1, 1,
sbPtr->foreground, GXcopy, AllPlanes);
}
\f
/*
*----------------------------------------------------------------------
*
* ScrollExposeProc --
*
* Invoked by the Sx_ dispatcher for each ExposeWindow event on
* a scrollbar.
*
* Results:
* None.
*
* Side effects:
* The window is redisplayed.
*
*----------------------------------------------------------------------
*/
void
ScrollExposeProc(sbPtr, eventPtr)
Scrollbar *sbPtr; /* Scrollbar that was exposed. */
XExposeEvent *eventPtr; /* Gives new dimensions of window. */
{
if (eventPtr->subwindow != 0) {
return;
}
sbPtr->width = eventPtr->width;
sbPtr->height = eventPtr->height;
ScrollRedisplay(sbPtr);
}
\f
/*
*----------------------------------------------------------------------
*
* ScrollButtonProc --
*
* This procedure is invoked by the Sx_ dispatcher whenever
* a button is pressed or released inside a scrollbar window.
*
* Results:
* None.
*
* Side effects:
* Calls client-supplied procedure if scrolling has been
* requested.
*
*----------------------------------------------------------------------
*/
static void
ScrollButtonProc(sbPtr, eventPtr)
register Scrollbar *sbPtr; /* Scrollbar being buttoned. */
register XKeyOrButtonEvent *eventPtr; /* Describes what happened. */
{
float distance;
int units, button;
if (eventPtr->subwindow != NULL) {
return;
}
/*
* When a button goes down, just change the cursor to reflect the
* operation that's in progress.
*/
button = eventPtr->detail & 0377;
if (eventPtr->type == ButtonPressed) {
if (sbPtr->flags & VERTICAL) {
if (button == LeftButton) {
Sx_GrabMouse(sbPtr->window, cursorUp,
ButtonPressed|ButtonReleased);
} else if (button == RightButton) {
Sx_GrabMouse(sbPtr->window, cursorDown,
ButtonPressed|ButtonReleased);
} else {
Sx_GrabMouse(sbPtr->window, cursorThumbV,
ButtonPressed|ButtonReleased);
}
} else {
if (button == LeftButton) {
Sx_GrabMouse(sbPtr->window, cursorLeft,
ButtonPressed|ButtonReleased);
} else if (button == RightButton) {
Sx_GrabMouse(sbPtr->window, cursorRight,
ButtonPressed|ButtonReleased);
} else {
Sx_GrabMouse(sbPtr->window, cursorThumbH,
ButtonPressed|ButtonReleased);
}
}
return;
}
/*
* Button release. Restore the cursor, and process the command.
*/
Sx_UngrabMouse();
if (sbPtr->flags & VERTICAL) {
distance = eventPtr->y;
distance /= sbPtr->height;
} else {
distance = eventPtr->x;
distance /= sbPtr->width;
}
if (distance < 0.0) {
distance = 0.0;
} else if (distance > 1.0) {
distance = 1.0;
}
if (button == LeftButton) {
units = SX_SCROLL_PAGES;
} else if (button == RightButton) {
units = SX_SCROLL_PAGES;
distance = -distance;
} else {
units = SX_SCROLL_ABSOLUTE;
}
(*sbPtr->proc)(sbPtr->clientData, distance, units, sbPtr->window);
/*
* It's important that we do NOTHING to the scrollbar after calling
* the client, since the client could conceivable have deleted the
* scrollbar, leaving us with a dangling pointer.
*/
}