eterm/src/scrollbar.c

540 lines
15 KiB
C
Raw Normal View History

/*--------------------------------*-C-*---------------------------------*
* File: scrollbar.c
*
* scrollbar routines
*
* Copyright 1996,97
* mj olesen <olesen@me.QueensU.CA> Queen's Univ at Kingston
*
* You can do what you like with this source code provided you don't make
* money from it and you include an unaltered copy of this message
* (including the copyright). As usual, the author accepts no
* responsibility for anything, nor does he guarantee anything whatsoever.
*----------------------------------------------------------------------*/
static const char cvs_ident[] = "$Id$";
#include "feature.h"
#include "main.h"
#include "scrollbar.h"
#include "screen.h"
#include "debug.h"
#include "options.h"
#ifdef PIXMAP_SCROLLBAR
# include "pixmap.h"
#endif
/* extern functions referenced */
/* extern variables referenced */
/* extern variables declared here */
#ifdef PIXMAP_SCROLLBAR
scrollBar_t scrollBar =
{0, 0, 0, 0, 0, SCROLLBAR_DEFAULT_TYPE, SB_WIDTH, None, None, None, None};
#else
scrollBar_t scrollBar =
{0, 0, 0, 0, 0, SCROLLBAR_DEFAULT_TYPE, SB_WIDTH, None};
#endif
int sb_shadow;
/*----------------------------------------------------------------------*
*/
static GC scrollbarGC;
static short last_top = 0, last_bot = 0; /* old (drawn) values */
#ifdef XTERM_SCROLLBAR /* bitmap scrollbar */
static GC shadowGC;
static char xterm_sb_bits[] =
{0xaa, 0x0a, 0x55, 0x05}; /* 12x2 bitmap */
#endif
#if defined(MOTIF_SCROLLBAR) || defined(NEXT_SCROLLBAR)
static GC topShadowGC, botShadowGC;
/* draw triangular up button with a shadow of SHADOW (1 or 2) pixels */
/* PROTO */
void
Draw_up_button(int x, int y, int state)
{
const unsigned int sz = (scrollBar.width), sz2 = (scrollBar.width / 2);
XPoint pt[3];
GC top = None, bot = None;
# ifdef PIXMAP_SCROLLBAR
Pixmap pixmap = upPixmap.pixmap;
# endif
D_SCROLLBAR(("Draw_up_button(%d, %d, %d)\n", x, y, state));
switch (state) {
case +1:
top = topShadowGC;
bot = botShadowGC;
break;
case -1:
top = botShadowGC;
bot = topShadowGC;
break;
case 0:
default:
top = bot = scrollbarGC;
break;
}
# ifdef PIXMAP_SCROLLBAR
if ((scrollbar_is_pixmapped()) && (pixmap != None)) {
XSetWindowBackgroundPixmap(Xdisplay, scrollBar.up_win, pixmap);
XClearWindow(Xdisplay, scrollBar.up_win);
} else
# endif
{
/* fill triangle */
pt[0].x = x;
pt[0].y = y + sz - 1;
pt[1].x = x + sz - 1;
pt[1].y = y + sz - 1;
pt[2].x = x + sz2;
pt[2].y = y;
XFillPolygon(Xdisplay, scrollBar.win, scrollbarGC,
pt, 3, Convex, CoordModeOrigin);
/* draw base */
XDrawLine(Xdisplay, scrollBar.win, bot,
pt[0].x, pt[0].y, pt[1].x, pt[1].y);
/* draw shadow */
pt[1].x = x + sz2 - 1;
pt[1].y = y;
XDrawLine(Xdisplay, scrollBar.win, top,
pt[0].x, pt[0].y, pt[1].x, pt[1].y);
# if (SHADOW > 1)
/* doubled */
pt[0].x++;
pt[0].y--;
pt[1].y++;
XDrawLine(Xdisplay, scrollBar.win, top,
pt[0].x, pt[0].y, pt[1].x, pt[1].y);
# endif
/* draw shadow */
pt[0].x = x + sz2;
pt[0].y = y;
pt[1].x = x + sz - 1;
pt[1].y = y + sz - 1;
XDrawLine(Xdisplay, scrollBar.win, bot,
pt[0].x, pt[0].y, pt[1].x, pt[1].y);
# if (SHADOW > 1)
/* doubled */
pt[0].y++;
pt[1].x--;
pt[1].y--;
XDrawLine(Xdisplay, scrollBar.win, bot,
pt[0].x, pt[0].y, pt[1].x, pt[1].y);
# endif
}
}
/* draw triangular down button with a shadow of SHADOW (1 or 2) pixels */
/* PROTO */
void
Draw_dn_button(int x, int y, int state)
{
const unsigned int sz = (scrollBar.width), sz2 = (scrollBar.width / 2);
XPoint pt[3];
GC top = None, bot = None;
# ifdef PIXMAP_SCROLLBAR
Pixmap pixmap = dnPixmap.pixmap;
# endif
D_SCROLLBAR(("Draw_dn_button(%d, %d, %d)\n", x, y, state));
switch (state) {
case +1:
top = topShadowGC;
bot = botShadowGC;
break;
case -1:
top = botShadowGC;
bot = topShadowGC;
break;
case 0:
default:
top = bot = scrollbarGC;
break;
}
# ifdef PIXMAP_SCROLLBAR
if ((scrollbar_is_pixmapped()) && (pixmap != None)) {
XSetWindowBackgroundPixmap(Xdisplay, scrollBar.up_win, pixmap);
XClearWindow(Xdisplay, scrollBar.dn_win);
} else
# endif
{
/* fill triangle */
pt[0].x = x;
pt[0].y = y;
pt[1].x = x + sz - 1;
pt[1].y = y;
pt[2].x = x + sz2;
pt[2].y = y + sz;
XFillPolygon(Xdisplay, scrollBar.win, scrollbarGC,
pt, 3, Convex, CoordModeOrigin);
/* draw base */
XDrawLine(Xdisplay, scrollBar.win, top,
pt[0].x, pt[0].y, pt[1].x, pt[1].y);
/* draw shadow */
pt[1].x = x + sz2 - 1;
pt[1].y = y + sz - 1;
XDrawLine(Xdisplay, scrollBar.win, top,
pt[0].x, pt[0].y, pt[1].x, pt[1].y);
# if (SHADOW > 1)
/* doubled */
pt[0].x++;
pt[0].y++;
pt[1].y--;
XDrawLine(Xdisplay, scrollBar.win, top,
pt[0].x, pt[0].y, pt[1].x, pt[1].y);
# endif
/* draw shadow */
pt[0].x = x + sz2;
pt[0].y = y + sz - 1;
pt[1].x = x + sz - 1;
pt[1].y = y;
XDrawLine(Xdisplay, scrollBar.win, bot,
pt[0].x, pt[0].y, pt[1].x, pt[1].y);
# if (SHADOW > 1)
/* doubled */
pt[0].y--;
pt[1].x--;
pt[1].y++;
XDrawLine(Xdisplay, scrollBar.win, bot,
pt[0].x, pt[0].y, pt[1].x, pt[1].y);
# endif
}
}
#endif /* MOTIF_SCROLLBAR || NEXT_SCROLLBAR */
/* PROTO */
int
scrollbar_mapping(int map)
{
int change = 0;
D_SCROLLBAR(("scrollbar_mapping(%d)\n", map));
if (map && !scrollbar_visible()) {
scrollBar.state = 1;
XMapWindow(Xdisplay, scrollBar.win);
#ifdef PIXMAP_SCROLLBAR
if (scrollbar_is_pixmapped()) {
XMapWindow(Xdisplay, scrollBar.up_win);
XMapWindow(Xdisplay, scrollBar.dn_win);
XMapWindow(Xdisplay, scrollBar.sa_win);
}
#endif
change = 1;
} else if (!map && scrollbar_visible()) {
scrollBar.state = 0;
#ifdef PIXMAP_SCROLLBAR
if (scrollbar_is_pixmapped()) {
XUnmapWindow(Xdisplay, scrollBar.up_win);
XUnmapWindow(Xdisplay, scrollBar.dn_win);
XUnmapWindow(Xdisplay, scrollBar.sa_win);
}
#endif
XUnmapWindow(Xdisplay, scrollBar.win);
change = 1;
}
return change;
}
void
scrollbar_reset(void)
{
if (scrollbarGC != None) {
XFreeGC(Xdisplay, scrollbarGC);
scrollbarGC = None;
}
if (topShadowGC != None) {
XFreeGC(Xdisplay, topShadowGC);
topShadowGC = None;
}
if (botShadowGC != None) {
XFreeGC(Xdisplay, botShadowGC);
botShadowGC = None;
}
if (shadowGC != None) {
XFreeGC(Xdisplay, shadowGC);
shadowGC = None;
}
last_top = last_bot = 0;
if (scrollBar.type == SCROLLBAR_XTERM) {
sb_shadow = 0;
} else {
sb_shadow = (Options & Opt_scrollBar_floating) ? 0 : SHADOW;
}
}
int
scrollbar_show(int mouseoffset)
{
static short sb_width; /* old (drawn) values */
unsigned char xsb = 0, force_update = 0;
#ifdef CHANGE_SCROLLCOLOR_ON_FOCUS
static int focus = -1;
#endif
if (!scrollbar_visible())
return 0;
D_SCROLLBAR(("scrollbar_show(%d)\n", mouseoffset));
if (scrollbarGC == None) {
XGCValues gcvalue;
#ifdef XTERM_SCROLLBAR
if (scrollBar.type == SCROLLBAR_XTERM) {
sb_width = scrollBar.width - 1;
gcvalue.stipple = XCreateBitmapFromData(Xdisplay, scrollBar.win,
xterm_sb_bits, 12, 2);
if (!gcvalue.stipple) {
print_error("can't create bitmap");
exit(EXIT_FAILURE);
}
gcvalue.fill_style = FillOpaqueStippled;
gcvalue.foreground = PixColors[fgColor];
gcvalue.background = PixColors[bgColor];
scrollbarGC = XCreateGC(Xdisplay, scrollBar.win,
GCForeground | GCBackground |
GCFillStyle | GCStipple,
&gcvalue);
gcvalue.foreground = PixColors[borderColor];
shadowGC = XCreateGC(Xdisplay, scrollBar.win, GCForeground, &gcvalue);
}
#endif /* XTERM_SCROLLBAR */
#if defined(MOTIF_SCROLLBAR) || defined(NEXT_SCROLLBAR)
if (scrollBar.type == SCROLLBAR_MOTIF || scrollBar.type == SCROLLBAR_NEXT) {
sb_width = scrollBar.width;
# ifdef KEEP_SCROLLCOLOR
gcvalue.foreground = (Xdepth <= 2 ? PixColors[fgColor]
: PixColors[scrollColor]);
# else
gcvalue.foreground = PixColors[fgColor];
# endif
scrollbarGC = XCreateGC(Xdisplay, scrollBar.win, GCForeground,
&gcvalue);
if ((sb_shadow) && (!(scrollbar_is_pixmapped()))) {
XSetWindowBackground(Xdisplay, scrollBar.win, gcvalue.foreground);
XClearWindow(Xdisplay, scrollBar.win);
} else if (Options & Opt_scrollBar_floating) {
if (!(Options & Opt_pixmapTrans)) {
if (background_is_pixmap()) {
XSetWindowBackground(Xdisplay, scrollBar.win, PixColors[scrollColor]);
} else {
XSetWindowBackground(Xdisplay, scrollBar.win, PixColors[bgColor]);
}
}
XClearWindow(Xdisplay, scrollBar.win);
}
# ifdef KEEP_SCROLLCOLOR
gcvalue.foreground = PixColors[topShadowColor];
# else /* KEEP_SCROLLCOLOR */
gcvalue.foreground = PixColors[bgColor];
# endif /* KEEP_SCROLLCOLOR */
topShadowGC = XCreateGC(Xdisplay, scrollBar.win,
GCForeground,
&gcvalue);
# ifdef KEEP_SCROLLCOLOR
gcvalue.foreground = PixColors[bottomShadowColor];
# else /* KEEP_SCROLLCOLOR */
gcvalue.foreground = PixColors[bgColor];
# endif /* KEEP_SCROLLCOLOR */
botShadowGC = XCreateGC(Xdisplay, scrollBar.win,
GCForeground,
&gcvalue);
}
#endif /* MOTIF_SCROLLBAR || NEXT_SCROLLBAR */
}
#if defined(CHANGE_SCROLLCOLOR_ON_FOCUS) && (defined(MOTIF_SCROLLBAR) || defined(NEXT_SCROLLBAR))
if (scrollBar.type == SCROLLBAR_MOTIF || scrollBar.type == SCROLLBAR_NEXT) {
if (focus != TermWin.focus) {
XGCValues gcvalue;
focus = TermWin.focus;
gcvalue.foreground = PixColors[focus ? scrollColor : unfocusedScrollColor];
# ifdef PIXMAP_OFFSET
if (!((Options & Opt_pixmapTrans) && (Options & Opt_scrollBar_floating))) {
# endif
XSetWindowBackground(Xdisplay, scrollBar.win, gcvalue.foreground);
XClearWindow(Xdisplay, scrollBar.win);
# ifdef PIXMAP_OFFSET
}
# endif /* PIXMAP_OFFSET */
XChangeGC(Xdisplay, scrollbarGC, GCForeground,
&gcvalue);
gcvalue.foreground = PixColors[focus ? topShadowColor : unfocusedTopShadowColor];
XChangeGC(Xdisplay, topShadowGC,
GCForeground,
&gcvalue);
gcvalue.foreground = PixColors[focus ? bottomShadowColor : unfocusedBottomShadowColor];
XChangeGC(Xdisplay, botShadowGC,
GCForeground,
&gcvalue);
force_update = 1;
}
}
#endif /* CHANGE_SCROLLCOLOR_ON_FOCUS && (MOTIF_SCROLLBAR || NEXT_SCROLLBAR) */
if (mouseoffset) {
int top = (TermWin.nscrolled - TermWin.view_start);
int bot = top + (TermWin.nrow - 1);
int len = max((TermWin.nscrolled + (TermWin.nrow - 1)), 1);
scrollBar.top = (scrollBar.beg + (top * scrollbar_size()) / len);
scrollBar.bot = (scrollBar.beg + (bot * scrollbar_size()) / len);
if (rs_min_anchor_size && scrollBar.type != SCROLLBAR_XTERM) {
if ((scrollbar_size() > rs_min_anchor_size) && (scrollBar.bot - scrollBar.top < rs_min_anchor_size)) {
int grab_point = scrollBar.top + mouseoffset;
if (grab_point - mouseoffset < scrollBar.beg) {
scrollBar.top = scrollBar.beg;
scrollBar.bot = rs_min_anchor_size + scrollBar.beg;
} else if (scrollBar.top + rs_min_anchor_size > scrollBar.end) {
scrollBar.top = scrollBar.end - rs_min_anchor_size;
scrollBar.bot = scrollBar.end;
} else {
scrollBar.top = grab_point - mouseoffset;
scrollBar.bot = scrollBar.top + rs_min_anchor_size;
}
if (scrollBar.bot == scrollBar.end) {
scr_move_to(scrollBar.end, scrollbar_size());
scr_refresh(SMOOTH_REFRESH);
}
}
}
/* no change */
if (!force_update && (scrollBar.top == last_top) && (scrollBar.bot == last_bot))
return 0;
}
#ifdef XTERM_SCROLLBAR
xsb = ((scrollBar.type == SCROLLBAR_XTERM) && (Options & Opt_scrollBar_right)) ? 1 : 0;
#endif
if (last_top < scrollBar.top) {
#ifdef PIXMAP_SCROLLBAR
if (scrollbar_is_pixmapped()) {
D_SCROLLBAR(("ATTN: XClearArea() #1, going down\n"));
XClearArea(Xdisplay, scrollBar.win,
sb_shadow + xsb, last_top,
sb_width, (scrollBar.top - last_top),
False);
XMoveResizeWindow(Xdisplay, scrollBar.sa_win,
0, scrollBar.top,
scrollbar_total_width(),
(scrollBar.bot - scrollBar.top));
} else
#endif
{
D_SCROLLBAR(("ATTN: XClearArea() #2\n"));
XClearArea(Xdisplay, scrollBar.win,
sb_shadow + xsb, last_top,
sb_width, (scrollBar.top - last_top),
False);
}
}
if (scrollBar.bot < last_bot) {
#ifdef PIXMAP_SCROLLBAR
if (scrollbar_is_pixmapped()) {
D_SCROLLBAR(("ATTN: XClearArea() #3, going up\n"));
XClearArea(Xdisplay, scrollBar.win,
sb_shadow + xsb, scrollBar.bot,
sb_width, (last_bot - scrollBar.bot),
False);
XMoveResizeWindow(Xdisplay, scrollBar.sa_win,
0, scrollBar.top,
scrollbar_total_width(),
(scrollBar.bot - scrollBar.top));
} else
#endif
{
D_SCROLLBAR(("ATTN: XClearArea() #4\n"));
XClearArea(Xdisplay, scrollBar.win,
sb_shadow + xsb, scrollBar.bot,
sb_width, (last_bot - scrollBar.bot),
False);
}
}
last_top = scrollBar.top;
last_bot = scrollBar.bot;
/* scrollbar slider */
#ifdef XTERM_SCROLLBAR
if (scrollBar.type == SCROLLBAR_XTERM) {
XFillRectangle(Xdisplay, scrollBar.win, scrollbarGC,
xsb + 1, scrollBar.top,
sb_width - 2, (scrollBar.bot - scrollBar.top));
XDrawLine(Xdisplay, scrollBar.win, shadowGC,
xsb ? 0 : sb_width, scrollBar.beg, xsb ? 0 : sb_width, scrollBar.end);
}
#endif /* XTERM_SCROLLBAR */
#if defined(MOTIF_SCROLLBAR) || defined(NEXT_SCROLLBAR)
if (scrollBar.type == SCROLLBAR_MOTIF || scrollBar.type == SCROLLBAR_NEXT) {
# ifdef PIXMAP_SCROLLBAR
if ((scrollbar_is_pixmapped()) && (saPixmap.pixmap != None)) {
D_SCROLLBAR(("ATTN: XCopyArea(%dx%d)", sb_width, (scrollBar.bot - scrollBar.top)));
XCopyArea(Xdisplay, saPixmap.pixmap, scrollBar.sa_win, scrollbarGC,
0, 0, sb_width, (scrollBar.bot - scrollBar.top),
0, scrollBar.top);
XClearArea(Xdisplay, scrollBar.sa_win, 0, scrollBar.top,
sb_width, (scrollBar.bot - scrollBar.top), False);
} else
# endif
{
XFillRectangle(Xdisplay, scrollBar.win, scrollbarGC,
sb_shadow, scrollBar.top,
sb_width, (scrollBar.bot - scrollBar.top));
}
if ((sb_shadow) && (!(scrollbar_is_pixmapped()))) {
/* trough shadow */
Draw_Shadow(scrollBar.win, botShadowGC, topShadowGC, 0, 0,
(sb_width + 2 * sb_shadow),
scrollBar.end + ((scrollBar.type == SCROLLBAR_NEXT) ? (2 * (sb_width + 1) + sb_shadow) : ((sb_width + 1) + sb_shadow)));
}
/* shadow for scrollbar slider */
if (!(scrollbar_is_pixmapped())) {
Draw_Shadow(scrollBar.win, topShadowGC, botShadowGC, sb_shadow, scrollBar.top, sb_width,
(scrollBar.bot - scrollBar.top));
}
/*
* Redraw scrollbar arrows
*/
Draw_up_button(sb_shadow, scrollbar_up_loc(), (scrollbar_isUp()? -1 : +1));
Draw_dn_button(sb_shadow, scrollbar_dn_loc(), (scrollbar_isDn()? -1 : +1));
}
#endif /* MOTIF_SCROLLBAR || NEXT_SCROLLBAR */
return 1;
}