/* X11buttons - buttons for X11 dialogs and windows */
/* XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney */
/* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz */
/* You may give out copies of this software; for conditions see the */
/* file COPYING included with this distribution. */
/***********************************************************************/
/** **/
/** General Includes and Definitions **/
/** **/
/***********************************************************************/
#include "dialogs.h"
extern Display *StX11Display();
extern Point DialogStringSize();
extern LVAL StX11ItemObject();
extern char *checkstring();
extern LVAL s_window_id;
#define NullWindow ((Window) 0)
typedef struct {
unsigned long fore, back;
} ColorPair;
/* layout defines */
# define BUTTON_PAD 15
# define BUTTON_LEAD 5
# define CloseButton 1
# define MenuButton 2
# define CLOSE_TEXT "Close"
# define MENU_TEXT "Menu"
/* forward declarations */
LOCAL LVAL special_button_object _((Display *dpy, Window button));
LOCAL VOID draw_button _((Display *dpy, Window win, LVAL item, int reversed));
LOCAL VOID draw_special_button _((Display *dpy, Window win,
int type, int reversed));
LOCAL VOID delete_special_button _((Window win, int type));
/***********************************************************************/
/** **/
/** Global Variables **/
/** **/
/***********************************************************************/
/* configuration parameters - should be set using the defaults database */
extern XFontStruct *DialogFont;
extern unsigned long DialogBorderColor, ButtonBorderColor;
extern ColorPair DialogC, ButtonC;
extern unsigned int dialog_border_width, button_border_width;
extern int min_button_height, min_button_width, dialog_item_gap;
extern GC DialogGC, DialogRGC;
extern XContext EventContext, ObjectContext, CloseContext, MenuContext;
extern LVAL s_menu, sk_select;
/***********************************************************************/
/** **/
/** Button Items **/
/** **/
/***********************************************************************/
static LVAL track_button(dpy, win, item, modal)
Display *dpy;
Window win;
LVAL item;
int modal;
{
int done = FALSE;
LVAL result = NIL;
XEvent report;
draw_button(dpy, win, item, TRUE);
while (! done) {
XNextEvent(dpy, &report);
switch (report.type) {
case ButtonRelease:
done = TRUE;
result = item;
break;
case LeaveNotify:
done = TRUE;
if (report.xcrossing.window == win)
XSetWindowBorderWidth(dpy, win, button_border_width);
break;
default:
break;
}
}
draw_button(dpy, win, item, FALSE);
if (! modal && result != NIL) send_message(item, sk_do_action);
return(result);
}
LOCAL VOID draw_button(dpy, win, item, reversed)
Display *dpy;
Window win;
LVAL item;
int reversed;
{
Point ssz, bsz;
char *text;
int x, y, len;
GC gc;
unsigned long color;
gc = (reversed) ? DialogRGC : DialogGC;
color = (reversed) ? DialogC.fore : DialogC.back;
XSetWindowBackground(dpy, win, color);
XClearWindow(dpy, win);
text = checkstring(slot_value(item, s_text));
ssz = DialogStringSize(text);
bsz = ListToPoint(slot_value(item, s_size));
x = (bsz.h - ssz.h) / 2;
y = (bsz.v - ssz.v) / 2 + DialogFont->max_bounds.ascent;
len = strlen(text);
XDrawString(dpy, win, gc, x, y, text, len);
XSetWindowBackground(dpy, win, DialogC.back);
}
static LVAL button_handler(report, modal)
XEvent report;
int modal;
{
Display *dpy = StX11Display();
Window win;
LVAL item;
LVAL result = NIL;
win = report.xany.window;
item = StX11ItemObject(dpy, win);
if (item != NIL) {
switch (report.type) {
case Expose:
draw_button(dpy, win, item, FALSE);
break;
case ButtonPress:
result = track_button(dpy, win, item, modal);
break;
case ButtonRelease:
break;
case EnterNotify:
XSetWindowBorderWidth(dpy,report.xcrossing.window,
button_border_width + 1);
break;
case LeaveNotify:
XSetWindowBorderWidth(dpy, report.xcrossing.window, button_border_width);
break;
default:
break;
}
}
return(result);
}
VOID InstallButtonItem(win, item)
Window win;
LVAL item;
{
Display *dpy = StX11Display();
Point loc, size;
Window button;
loc = ListToPoint(slot_value(item, s_location));
size = ListToPoint(slot_value(item, s_size));
button = XCreateSimpleWindow(dpy, win, loc.h, loc.v, size.h, size.v,
button_border_width,
ButtonBorderColor, ButtonC.back);
XSelectInput(dpy, button,
StructureNotifyMask | ExposureMask | EnterWindowMask |
LeaveWindowMask | ButtonPressMask | ButtonReleaseMask);
set_slot_value(item, s_window_id, cvfixnum((FIXTYPE) button));
install_dialog_item_handler(dpy, button, button_handler, item);
if (XSaveContext(dpy, button, ObjectContext, (caddr_t) item) != 0)
xlfail("could not install object in window");
}
VOID DeleteButtonItem(win, item)
Window win;
LVAL item;
{
Display *dpy = StX11Display();
Window button;
button = (Window) getfixnum(slot_value(item, s_window_id));
delete_dialog_item_handler(dpy, button);
if (XDeleteContext(dpy, button, ObjectContext) != 0)
xlfail("could not delete object context");
set_slot_value(item, s_window_id, NIL);
}
VOID DialogButtonGetDefaultSize(item, width, height)
LVAL item;
int *width, *height;
{
Point sz;
sz = DialogStringSize(checkstring(slot_value(item, s_text)));
if (width != NULL) *width = max(sz.h + BUTTON_PAD, min_button_width);
if (height != NULL) *height = max(sz.v + BUTTON_LEAD, min_button_height);
}
/***********************************************************************/
/** **/
/** Close Buttons **/
/** **/
/***********************************************************************/
int ClosePanelHeight()
{
Point sz;
sz = DialogStringSize(CLOSE_TEXT);
return (sz.v + 4 * BUTTON_LEAD);
}
LOCAL LVAL special_button_object(dpy, button)
Display *dpy;
Window button;
{
LVAL object;
if (XFindContext(dpy, button, ObjectContext, (caddr_t *) &object) == 0
&& objectp(object))
return(object);
else return(NIL);
}
static Point special_button_size(type)
int type;
{
char *text = NULL;
Point bsz, ssz;
switch (type) {
case CloseButton: text = CLOSE_TEXT; break;
case MenuButton: text = MENU_TEXT; break;
default: break;
}
ssz = DialogStringSize(text);
bsz.h = max(ssz.h + BUTTON_PAD, min_button_width);
bsz.v = max(ssz.v + BUTTON_LEAD, min_button_height);
return(bsz);
}
static VOID track_special_button(dpy, win, type, modal)
Display *dpy;
Window win;
int type, modal;
{
int done = FALSE, result = FALSE;
XEvent report;
LVAL object;
draw_special_button(dpy, win, type, TRUE);
while (! done) {
XNextEvent(dpy, &report);
switch (report.type) {
case ButtonRelease:
done = TRUE;
result = TRUE;
break;
case LeaveNotify:
done = TRUE;
if (report.xcrossing.window == win)
XSetWindowBorderWidth(dpy, win, button_border_width);
break;
default:
break;
}
}
draw_special_button(dpy, win, type, FALSE);
if (! modal && result == TRUE) {
switch (type) {
case CloseButton:
object = special_button_object(dpy, win);
if (object != NIL) send_message(object, sk_close);
break;
default:
break;
}
}
}
LOCAL VOID draw_special_button(dpy, win, type, reversed)
Display *dpy;
Window win;
int type, reversed;
{
Point ssz, bsz;
char *text = NULL;
int x, y, len;
GC gc;
unsigned long color;
switch (type) {
case CloseButton: text = CLOSE_TEXT; break;
case MenuButton: text = MENU_TEXT; break;
default: break;
}
gc = (reversed) ? DialogRGC : DialogGC;
color = (reversed) ? DialogC.fore : DialogC.back;
XSetWindowBackground(dpy, win, color);
XClearWindow(dpy, win);
ssz = DialogStringSize(text);
bsz = special_button_size(type);
x = (bsz.h - ssz.h) / 2;
y = (bsz.v - ssz.v) / 2 + DialogFont->max_bounds.ascent;
len = strlen(text);
XDrawString(dpy, win, gc, x, y, text, len);
XSetWindowBackground(dpy, win, DialogC.back);
}
static LVAL basic_special_button_handler(report, modal, type)
XEvent report;
int modal, type;
{
Display *dpy = StX11Display();
int screen = StX11Screen();
Window win, child;
int x, y, item;
LVAL object, menu;
if (modal) return(NIL);
win = report.xany.window;
object = special_button_object(dpy, win);
if (objectp(object) && GETWINDOWADDRESS(object) != NullWindow) {
switch (report.type) {
case Expose:
draw_special_button(dpy, win, type, FALSE);
break;
case ButtonPress:
switch(type) {
case MenuButton:
XTranslateCoordinates(dpy, win, RootWindow(dpy, screen),
report.xbutton.x, report.xbutton.y, &x, &y,
&child);
menu = slot_value(object, s_menu);
if (menu_p(menu)) {
draw_special_button(dpy, win, type, TRUE);
XSetWindowBorderWidth(dpy, report.xcrossing.window,
button_border_width);
item = StMObPopup(menu, x, y, NIL);
draw_special_button(dpy, win, type, FALSE);
if (item > 0) send_message1(menu, sk_select, item);
}
else
XSetWindowBorderWidth(dpy, report.xcrossing.window,
button_border_width);
break;
default:
track_special_button(dpy, win, type, modal);
break;
}
break;
case ButtonRelease:
break;
case EnterNotify:
XSetWindowBorderWidth(dpy,report.xcrossing.window,
button_border_width + 1);
break;
case LeaveNotify:
XSetWindowBorderWidth(dpy, report.xcrossing.window, button_border_width);
break;
default:
break;
}
}
return(NIL);
}
static LVAL close_button_handler(report, modal)
XEvent report;
int modal;
{
return(basic_special_button_handler(report, modal, CloseButton));
}
static LVAL menu_button_handler(report, modal)
XEvent report;
int modal;
{
return(basic_special_button_handler(report, modal, MenuButton));
}
static VOID install_special_button(win, object, type)
Window win;
LVAL object;
int type;
{
Display *dpy = StX11Display();
Point loc, size;
Window button;
LVAL (*handler)() = NULL;
int width, height, gravity = 0;
XSetWindowAttributes winattr;
switch (type) {
case CloseButton:
loc.h = BUTTON_LEAD;
loc.v = BUTTON_LEAD;
size = special_button_size(type);
handler = close_button_handler;
gravity = NorthWestGravity;
break;
case MenuButton:
size = special_button_size(type);
loc.v = BUTTON_LEAD;
StWGetSize(win, &width, &height, TRUE);
loc.h = width - size.h - BUTTON_LEAD;
handler = menu_button_handler;
gravity = NorthEastGravity;
default:
break;
}
button = XCreateSimpleWindow(dpy, win, loc.h, loc.v, size.h, size.v,
button_border_width,
ButtonBorderColor, ButtonC.back);
XSelectInput(dpy, button,
StructureNotifyMask | ExposureMask | EnterWindowMask |
LeaveWindowMask | ButtonPressMask | ButtonReleaseMask);
winattr.win_gravity = gravity;
XChangeWindowAttributes(dpy, button, CWWinGravity, &winattr);
switch (type) {
case CloseButton:
if (XSaveContext(dpy, win, CloseContext, (caddr_t) button) != 0)
xlfail("could not install close button context");
break;
case MenuButton:
if (XSaveContext(dpy, win, MenuContext, (caddr_t) button) != 0)
xlfail("could not install menu button context");
break;
default:
break;
}
if (XSaveContext(dpy, button, EventContext, (caddr_t) handler) != 0)
xlfail("could not install event handler");
if (XSaveContext(dpy, button, ObjectContext, (caddr_t) object) != 0)
xlfail("could not install object in window");
}
LOCAL VOID delete_special_button(win, type)
Window win;
int type;
{
Display *dpy = StX11Display();
Window button;
XContext context = (XContext) 0;
switch (type) {
case CloseButton: context = CloseContext; break;
case MenuButton: context = MenuContext; break;
default: break;
}
if (XFindContext(dpy, win, context, (caddr_t *) &button) == 0) {
if (XDeleteContext(dpy, win, context) != 0)
xlfail("could not delete buttont context");
if (XDeleteContext(dpy, button, EventContext) != 0)
xlfail("could not delete event context");
if (XDeleteContext(dpy, button, ObjectContext) != 0)
xlfail("could not delete object context");
}
}
VOID InstallCloseButton(win, object)
Window win;
LVAL object;
{
install_special_button(win, object, CloseButton);
}
VOID DeleteCloseButton(win)
Window win;
{
delete_special_button(win, CloseButton);
}
VOID InstallMenuButton(win, object)
Window win;
LVAL object;
{
install_special_button(win, object, MenuButton);
}
VOID DeleteMenuButton(win)
Window win;
{
delete_special_button(win, MenuButton);
}
syntax highlighted by Code2HTML, v. 0.9.1