diff options
Diffstat (limited to 'src/iwindow.cpp')
-rw-r--r-- | src/iwindow.cpp | 674 |
1 files changed, 674 insertions, 0 deletions
diff --git a/src/iwindow.cpp b/src/iwindow.cpp new file mode 100644 index 0000000..848204d --- /dev/null +++ b/src/iwindow.cpp @@ -0,0 +1,674 @@ +/**************************************************************************\ + ibtk (Insomnia's Basic ToolKit) + + By Insomnia (Steaphan Greene) + (insomnia@core.binghamton.edu) + + Copyright (C) 1999 Steaphan Greene + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. + +\**************************************************************************/ + +#include "iwindow.h" + +#define DEFAULT_NAME "IBTK v0.0" + +#include <X11/X.h> +#include <X11/Xutil.h> +#include <sys/types.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static int Blue, Red, Green; + +#define W 255<<8 +#define B 0<<8 +#define Gr 192<<8 +#define GrL 228<<8 +#define GrD 93<<8 + +#define EVENT_MASK (PointerMotionMask|ButtonPressMask|ButtonReleaseMask \ + |ExposureMask|KeyPressMask|KeyReleaseMask|StructureNotifyMask \ + |VisibilityChangeMask) + +IWindow::~IWindow() { + XDestroyWindow(Disp, Win); + XFreeGC(Disp, gc); + XFreeGC(Disp, cgc); + XCloseDisplay(Disp); + } + +IWindow::IWindow(char *name, int xs, int ys, int xpos, int ypos, char *bg) { + Init(name, xs, ys, xpos, ypos, bg, NULL, 0, 0); + } + +IWindow::IWindow(char *bg) { + Init(DEFAULT_NAME, 0, 0, -1, -1, bg, NULL, 0, 0); + } + +IWindow::IWindow(int xs, int ys, char *bg) { + Init(DEFAULT_NAME, xs, ys, -1, -1, bg, NULL, 0, 0); + } + +IWindow::IWindow(int xs, int ys, int xpos, int ypos, char *bg) { + Init(DEFAULT_NAME, xs, ys, xpos, ypos, bg, NULL, 0, 0); + } + +IWindow::IWindow(char *name, char *bg, Window* iwin, int xsi, int ysi) { + Init(name, 0, 0, -1, -1, bg, iwin, xsi, ysi); + } + +IWindow::IWindow(char *name, int xs, int ys, char *bg) { + Init(name, xs, ys, -1, -1, bg, NULL, 0, 0); + } + +void IWindow::Init(char *name, int xs, int ys, int xp, int yp, char *bg, + Window* iwin, int xsi, int ysi) { + LoadConfig(); + XWMHints wmhints; + useicon=0; + WinBuf=0; bufxs=0; bufys=0; + xsize = xs; ysize = ys; xpos = xp; ypos = yp; mapped = 0; + xsizei = xsi; ysizei = ysi; xposi = 0; yposi = 0; + Disp = XOpenDisplay(NULL); + if(Disp==NULL) { + fprintf(stderr, "IBTK: Unable to open DISPLAY!\n"); + exit(1); + } + + DispFD = ConnectionNumber(Disp); + depth = DefaultDepth(Disp, 0); + XColor g, t; + + if(bg != NULL) { + XAllocNamedColor(Disp, DefaultColormap(Disp, 0), bg, &g, &t); + wbgcol = g.pixel; + } + + g.flags = DoRed|DoBlue|DoGreen; + + g.red = 0; g.green = 0; g.blue = Blue; + XAllocColor(Disp, DefaultColormap(Disp, 0), &g); + scol = g.pixel; + + g.red = W; g.green = W; g.blue = W; + XAllocColor(Disp, DefaultColormap(Disp, 0), &g); + pcol = g.pixel; + + g.red = B; g.green = B; g.blue = B; + XAllocColor(Disp, DefaultColormap(Disp, 0), &g); + fgcol = g.pixel; + + g.red = Gr; g.green = Gr; g.blue = Gr; + XAllocColor(Disp, DefaultColormap(Disp, 0), &g); + bgcol = g.pixel; + + g.red = GrL; g.green = GrL; g.blue = GrL; + XAllocColor(Disp, DefaultColormap(Disp, 0), &g); + lbgcol = g.pixel; + + g.red = GrD; g.green = GrD; g.blue = GrD; + XAllocColor(Disp, DefaultColormap(Disp, 0), &g); + dbgcol = g.pixel; + + g.red = 0; g.green = W; g.blue = 0; + XAllocColor(Disp, DefaultColormap(Disp, 0), &g); + greencol = g.pixel; + + g.red = W; g.green = 0; g.blue = 0; + XAllocColor(Disp, DefaultColormap(Disp, 0), &g); + redcol = g.pixel; + + g.red = W; g.green = W; g.blue = 0; + XAllocColor(Disp, DefaultColormap(Disp, 0), &g); + yellowcol = g.pixel; + + if(bg == NULL) { + wbgcol = bgcol; + } + + Root = DefaultRootWindow(Disp); + if(xsize) { + bufxs=xsize; bufys=ysize; + Win = XCreateSimpleWindow(Disp, Root, xpos, ypos, xsize, ysize, + 0, bgcol, wbgcol); + gc = XCreateGC(Disp, Win, None, None); + XSetForeground(Disp, gc, wbgcol); + WinBuf = XCreatePixmap(Disp, Win, bufxs, bufys, DefaultDepth(Disp, 0)); + XFillRectangle(Disp, WinBuf, gc, 0, 0, bufxs, bufys); + } + else { + Win = XCreateSimpleWindow(Disp, Root, xpos, ypos, 320, 240, + 0, bgcol, wbgcol); + gc = XCreateGC(Disp, Win, None, None); + } + + if (iwin) { + Icon = XCreateSimpleWindow(Disp, Root, 0, 0, xsizei, ysizei, + 0, bgcol, wbgcol); + *iwin = Icon; + XSelectInput(Disp, Icon, StructureNotifyMask|VisibilityChangeMask); + wmhints.flags = IconWindowHint; + wmhints.icon_window = Icon; + XSetWMHints(Disp,Win,&wmhints); + useicon=1; + } + else Icon = 0; + + cgc = XCreateGC(Disp, Win, None, None); + XSelectInput(Disp, Win, EVENT_MASK); + if(xsize) XMapRaised(Disp, Win); + closeatom = XInternAtom(Disp, "WM_DELETE_WINDOW", 1); + if(closeatom) XSetWMProtocols(Disp, Win, (Atom *)&closeatom, 1); + DispatchHook = NULL; + DispatchTime = NULL; + unhandledcallback = NULL; + clickcallback = NULL; + dblclickcallback = NULL; + dragcallback = NULL; + activitycallback = NULL; + exposecallback = NULL; + resizecallback = NULL; + repositioncallback = NULL; + keymappingcallback = NULL; + parent = NULL; + claim = NULL; + pdd = NULL; + fdd = NULL; + + clicktime = 0; + +// int t; +// char **fns = XListFonts(Disp, "*", -1, &t); +// int ctr; +// for(ctr=0; ctr<t; ctr++) printf("Font(%d): %s\n", ctr+1, fns[ctr]); + fs = XLoadQueryFont(Disp, "fixed"); + if(fs == NULL) fs = XLoadQueryFont(Disp, "times-roman"); + if(fs == NULL) fs = XLoadQueryFont(Disp, "*times-medium-r*"); + XSetFont(Disp, gc, fs->fid); +// XGCValues gv; +// printf("Step 1\n"); +// XGetGCValues(Disp, gc, GCFont, &gv); +// printf("Step 2, gv.font=%d \n", gv.font); +// fs = XQueryFont(Disp, gv.font); +// printf("Step 3, fs=%p\n", fs); + SetTitle(name); + quit=0; + } + +void IWindow::AddClaim(IDoDad *it, int xp, int yp, int xs, int ys) { + PositionClaim *cl = claim; + for(;cl != NULL && cl->dodad != it; cl = cl->next); + if(cl == NULL) { +// printf("Adding new claim, Type %d\n", it->Type()); + PositionClaim *tmpd = claim; + claim = new PositionClaim; + claim->next = tmpd; + claim->dodad = it; + cl = claim; + } +// else printf("Changing Old claim, Type %d\n", it->Type()); + cl->xp = xp; + cl->yp = yp; + cl->xs = xs; + cl->ys = ys; +// printf("Added Type %d at (%d,%d), %dx%d.\n", cl->dodad->Type(), xp, yp, xs, ys); + } + +void IWindow::RemoveClaim(IDoDad *it) { + if(claim == NULL) return; +// printf("Removing %d.\n", it->Type()); + if(claim->dodad == it) { + PositionClaim *tmpd = claim; + claim = claim->next; + delete tmpd; + return; + } + if(pdd == it) pdd = NULL; + if(fdd == it) fdd = NULL; + PositionClaim *tmpd = claim; + while(tmpd->next != NULL && tmpd->next->dodad != it) tmpd = tmpd->next; + if(tmpd->next == NULL) return; + PositionClaim *tmprem = tmpd->next; + tmpd->next = tmpd->next->next; + delete tmprem; + } + +void IWindow::DispatchCurrentEvents() { + XEvent ev; + quit=0; + XFlush(Disp); + while((!quit)&&(XCheckMaskEvent(Disp, EVENT_MASK|StructureNotifyMask, &ev))) { +// printf("Got Type = %d\n", ev.type); + Dispatch(ev); + if(parent != NULL) parent->DispatchAutomaticEvents(); + } + } + +void IWindow::DispatchAutomaticEvents() { + XEvent ev; + quit=0; + XFlush(Disp); + while((!quit)&&(XCheckMaskEvent(Disp, EVENT_MASK|StructureNotifyMask, &ev))) { +// printf("Got Type = %d\n", ev.type); + if(ev.type == Expose) Dispatch(ev); + if(parent != NULL) parent->DispatchAutomaticEvents(); + } + } + +void IWindow::RegisterHook(void (*hookfn)(), struct timeval *waittime) { + DispatchHook=hookfn; + DispatchTime=waittime; + } + +void IWindow::DispatchEvents() { + XEvent ev; + struct timeval timeout,*timeptr; + fd_set readfds; + quit=0; + XFlush(Disp); + while(!quit) { + if (DispatchTime==NULL) timeptr=NULL; + else { + timeout=*DispatchTime; + timeptr=&timeout; + } + FD_ZERO(&readfds); + FD_SET(DispFD, &readfds); + if((select(DispFD+1,&readfds,NULL,NULL,timeptr)>0)||(XQLength(Disp)>0)) { + do { + XNextEvent(Disp, &ev); +// if(Win != ev.xany.window) printf("Got Win = %d/%d\n", ev.xany.window, Win); + Dispatch(ev); + if(parent != NULL) parent->DispatchAutomaticEvents(); + } while(XQLength(Disp)>0); + XFlush(Disp); + } + if(DispatchHook!=NULL) DispatchHook(); + } + } + +void IWindow::Close() { + XEvent ev; + ev.type = ClientMessage; + ev.xclient.format = 32; + ev.xclient.data.l[0] = closeatom; + ev.xany.display = Disp; + ev.xany.window = Win; + XSendEvent(Disp, Win, False, NoEventMask, &ev); + } + +void IWindow::Dispatch(XEvent ev) { + Time oclicktime = clicktime; + + if((!useicon) && (ev.xany.window==Icon)) return; + int sendevent = (mapped) ? (ev.xany.window!=Icon) : (ev.xany.window==Icon); + if(ev.type == ClientMessage && (Atom)(ev.xclient.data.l[0]) == closeatom) + quit = 1; + else if(ev.type == ButtonPress) { + clicktime = ev.xbutton.time; + if(pdd != NULL) pdd->Release(0, -1, -1); + pdd = GetClaim(ev.xbutton.x, ev.xbutton.y); + if(pdd != NULL) pdd->Press(ev.xbutton.button, + ev.xbutton.x-lclaim->xp, ev.xbutton.y-lclaim->yp); + else { + TakeFocus(NULL); + if((clicktime - oclicktime) <= doubleclicktime) { + if(dblclickcallback != NULL) + (*dblclickcallback)(this, ev.xbutton.button, + ev.xbutton.x, ev.xbutton.y); + } + else { + if(clickcallback != NULL) + (*clickcallback)(this, ev.xbutton.button, + ev.xbutton.x, ev.xbutton.y); + } + } + } + else if(ev.type == ButtonRelease) { + IDoDad *tmpd = GetClaim(ev.xbutton.x, ev.xbutton.y); + if(tmpd != NULL && tmpd == pdd) pdd->Release(ev.xbutton.button, + ev.xbutton.x-lclaim->xp, ev.xbutton.y-lclaim->yp); + else if(pdd != NULL) pdd->Release(0, -1, -1); + else if(releasecallback != NULL) + (*releasecallback)(this, ev.xbutton.button, + ev.xbutton.x, ev.xbutton.y); + pdd = NULL; + if(activitycallback != NULL) { + (*activitycallback)(this); + } + } + else if(ev.type == MotionNotify) { + while(XCheckMaskEvent(Disp, PointerMotionMask, &ev)); + if(pdd != NULL) pdd->Drag( + ev.xmotion.x-lclaim->xp, ev.xmotion.y-lclaim->yp); + if(ev.xmotion.state != 0 && dragcallback != NULL) { + (*dragcallback)(this, ev.xbutton.state, ev.xbutton.x, ev.xbutton.y); + } + if(activitycallback != NULL) { + (*activitycallback)(this); + } + } + else if(ev.type == Expose) { + if(claim != NULL) RevRedraw(claim); + if(exposecallback != NULL) + (*exposecallback)(this); + } + else if(ev.type == ConfigureNotify) { + int xp, yp; Window child; int *xptr, *yptr; + XTranslateCoordinates(Disp,ev.xany.window,Root,0,0,&xp,&yp,&child); + int x = ev.xconfigure.width, y = ev.xconfigure.height; + xptr = (ev.xany.window==Icon) ? &xsizei : &xsize; + yptr = (ev.xany.window==Icon) ? &ysizei : &ysize; + if(x != *yptr || y != *yptr) { + *xptr = x; *yptr = y; + if(sendevent && resizecallback != NULL) + (*resizecallback)(this, x, y); + if(ev.xany.window!=Icon && claim != NULL) RevRedraw(claim); + } + xptr = (ev.xany.window==Icon) ? &xposi : &xpos; + yptr = (ev.xany.window==Icon) ? &yposi : &ypos; + if(xp != *yptr || yp != *yptr) { + *xptr = xp; *yptr = yp; + if(sendevent && repositioncallback != NULL) + (*repositioncallback)(this, xp, yp); + if(ev.xany.window!=Icon && claim != NULL) RevRedraw(claim); + } + } + else if(ev.type == KeyPress) { + if(fdd == NULL || !fdd->KeyDown(ev.xkey)) { + if(unhandledcallback != NULL) { + (*unhandledcallback)(this, &ev); + } + } + if(activitycallback != NULL) { + (*activitycallback)(this); + } + } + else if(ev.type == MapNotify || ev.type == UnmapNotify) { + if(ev.xany.window!=Icon) { + mapped = (ev.type==MapNotify); + } + sendevent = (mapped) ? (ev.xany.window!=Icon) : (ev.xany.window==Icon) ; + if(!useicon) sendevent=1; + if(sendevent && unhandledcallback != NULL) { + (*unhandledcallback)(this, &ev); + } + if(activitycallback != NULL) { + (*activitycallback)(this); + } + } + else if(ev.type == MappingNotify) { + if(keymappingcallback != NULL) + (*keymappingcallback)(this, &ev); + } + else if(sendevent && unhandledcallback != NULL) { + (*unhandledcallback)(this, &ev); + } + } + +IDoDad *IWindow::GetClaim(int x, int y) { + if(claim == NULL) return NULL; + if(claim->xp <= x && claim->yp <= y + && (claim->xp+claim->xs) > x + && (claim->yp+claim->ys) > y + && (!claim->dodad->Hidden())) { + lclaim = claim; + return claim->dodad; + } + PositionClaim *tmpd = claim; + while(tmpd->next != NULL && !(tmpd->next->xp <= x && tmpd->next->yp <= y + && (tmpd->next->xp+tmpd->next->xs) > x + && (tmpd->next->yp+tmpd->next->ys) > y + && (!tmpd->next->dodad->Hidden()))) tmpd = tmpd->next; + if(tmpd->next == NULL) return NULL; + lclaim = tmpd->next; + return tmpd->next->dodad; + } + +void IWindow::RevRedraw(PositionClaim *it) { + RevRedraw(it, -1, -1, -1, -1); + } + +void IWindow::RevRedraw(PositionClaim *it, int x, int y, int xs, int ys) { + if(it==NULL) return; + if(it->next != NULL) RevRedraw(it->next, x, y, xs, ys); + if(!it->dodad->Hidden()) { + if(xs<0) it->dodad->Redraw(); + else if(it->xp < (x+xs) && it->yp < (y+ys) + && x < (it->xp+it->xs) && y < (it->yp+it->ys)) { + it->dodad->Redraw(); + } + } + } + +void IWindow::TakeFocus(IDoDad *it) { + IDoDad *ofdd = fdd; + fdd = it; + if(ofdd != NULL) ofdd->LostFocus(); + if(fdd != NULL) fdd->GotFocus(); + } + +void IWindow::SetTitle(char *tit) { + XTextProperty tp; + tp.value = (unsigned char *)tit; + tp.encoding = XA_WM_NAME; + tp.format = 8; + tp.nitems = strlen(tit); + XSetWMName(Disp, Win, &tp); + XStoreName(Disp, Win, tit); + XSetIconName(Disp, Win, tit); + XSetWMIconName(Disp, Win, &tp); + } + +unsigned int IWindow::GetRGBColor(int r, int g, int b) { + r<<=8; g<<=8; b<<=8; + XColor C; + C.flags = DoRed|DoBlue|DoGreen; + + C.red = r; C.green = g; C.blue = b; + XAllocColor(Disp, DefaultColormap(Disp, 0), &C); + return(C.pixel); + } + +void IWindow::SetActivityCallback(void (*cb)(IWindow *)) { + activitycallback = cb; + if(activitycallback != NULL) + (*activitycallback)(this); + } + +void IWindow::SetExposeCallback(void (*cb)(IWindow *)) { + exposecallback = cb; + if(exposecallback != NULL) + (*exposecallback)(this); + } + +void IWindow::SetResizeCallback(void (*cb)(IWindow *, int, int)) { + resizecallback = cb; + if(resizecallback != NULL) + (*resizecallback)(this, xsize, ysize); + } + +void IWindow::SetRepositionCallback(void (*cb)(IWindow *, int, int)) { + repositioncallback = cb; + if(repositioncallback != NULL) + (*repositioncallback)(this, xsize, ysize); + } + +void IWindow::SetUnhandledCallback(void (*cb)(IWindow *, XEvent *)) { + unhandledcallback = cb; + } + +void IWindow::SetClickCallback(void (*cb)(IWindow *, int, int, int)) { + clickcallback = cb; + } + +void IWindow::SetDblClickCallback(void (*cb)(IWindow *, int, int, int)) { + dblclickcallback = cb; + } + +void IWindow::SetReleaseCallback(void (*cb)(IWindow *, int, int, int)) { + releasecallback = cb; + } + +void IWindow::SetDragCallback(void (*cb)(IWindow *, int, int, int)) { + dragcallback = cb; + } + +void IWindow::SetKeyMappingCallback(void (*cb)(IWindow *, XEvent *)) { + keymappingcallback = cb; + } + +void IWindow::Resize(int x, int y) { + XResizeWindow(Disp, Win, x, y); + } + +void IWindow::Map(int x, int y) { + Resize(x, y); + if(bufxs<=0) bufxs=x; + if(bufys<=0) bufys=y; + if(WinBuf==0) { + XSetForeground(Disp, gc, wbgcol); + WinBuf = XCreatePixmap(Disp, Win, bufxs, bufys, DefaultDepth(Disp, 0)); + XFillRectangle(Disp, WinBuf, gc, 0, 0, bufxs, bufys); + } + Map(); + } + +void IWindow::SetBufSize(int x, int y) { + bufxs=x; bufys=y; + } + +void IWindow::Map() { + XMapRaised(Disp, Win); + } + +void IWindow::Redraw(int x, int y, int xs, int ys) { +// XClearArea(Disp, Win, x, y, xs<?(bufxs-x), ys<?(bufys-y), False); + XCopyArea(Disp, WinBuf, Win, gc, x, y, xs<?(bufxs-x), ys<?(bufys-y), x, y); + } + +void IWindow::Redraw() { + XClearWindow(Disp, Win); + XCopyArea(Disp, WinBuf, Win, gc, 0, 0, xsize<?bufxs, ysize<?bufys, 0, 0); + } + +void IWindow::Rebuild(int x, int y, int xs, int ys) { +// XClearWindow(Disp, Win); + XSetForeground(Disp, gc, wbgcol); + XFillRectangle(Disp, WinBuf, gc, x, y, xs, ys); + RevRedraw(claim, x, y, xs, ys); + XCopyArea(Disp, WinBuf, Win, gc, x, y, xs, ys, x, y); + } + +void IWindow::Rebuild() { +// XClearWindow(Disp, Win); + XSetForeground(Disp, gc, wbgcol); + XFillRectangle(Disp, WinBuf, gc, 0, 0, xsize, ysize); + RevRedraw(claim); + XCopyArea(Disp, WinBuf, Win, gc, 0, 0, xsize, ysize, 0, 0); + } + +int IWindow::XDeskSize() { + XWindowAttributes wa; + XGetWindowAttributes(Disp, Root, &wa); + return wa.width; + } + +int IWindow::YDeskSize() { + XWindowAttributes wa; + XGetWindowAttributes(Disp, Root, &wa); + return wa.height; + } + +void IWindow::LoadConfig() { + appearance = IBTK_DEFAULT; + doubleclicktime = 200; + FILE *cfg = fopen(CONFIGFILE, "r"); + if(cfg!=NULL) { + char buf[256], *ln; + ln = fgets(buf, 256, cfg); + while(ln != NULL) { + if(!strncasecmp(ln, "appearance", 10)) { + while(*ln != '=' && *ln != '\n' && *ln != 0) ++ln; + if(*ln != '\n' && *ln != 0) ++ln; + while(*ln == ' ' || *ln == '\t') ++ln; + if(*ln != '\n' && *ln != 0) { + if(!strncasecmp(ln, "default", 7)) + appearance=IBTK_DEFAULT; + else if(!strncasecmp(ln, "step", 4)) + appearance=IBTK_STEP; + } + } + else if(!strncasecmp(ln, "doubleclicktime", 10)) { + while(*ln != '=' && *ln != '\n' && *ln != 0) ++ln; + if(*ln != '\n' && *ln != 0) ++ln; + while(*ln == ' ' || *ln == '\t') ++ln; + if(*ln != '\n' && *ln != 0) { + doubleclicktime = strtol(ln, NULL, 10); + } + } + ln = fgets(buf, 256, cfg); + } + fclose(cfg); + } + switch(appearance) { + case(IBTK_DEFAULT): { + Blue = 255<<8; + Red = 255<<8; + Green = 255<<8; + }break; + case(IBTK_STEP): { + Blue = 128<<8; + Red = 128<<8; + Green = 128<<8; + }break; + } + } + +void IWindow::RebuildClip() { + int ctrx, ctry, n=0, ctr=0, m=0; + XRectangle *rec; + for(ctry=5; ctry<ysize; ctry+=10) { + for(ctrx=5; ctrx<xsize; ctrx+=10) { + if(GetClaim(ctrx, ctry)==NULL) { + ++m; + } + else if(m>0) { ++n; m=0; } + } + if(m>0) { ++n; m=0; } + } + rec = new XRectangle[n]; m=0; + for(ctry=5; ctry<ysize; ctry+=10) { + for(ctrx=5; ctrx<xsize; ctrx+=10) { + if(GetClaim(ctrx, ctry)==NULL) { + ++m; + } + else if(m>0) { + rec[ctr].x = ctrx-(5+(10*m)); + rec[ctr].y = ctry-5; + rec[ctr].width = 10*m; + rec[ctr].height = 10; + ++ctr; m=0; + } + } + if(m>0) { + rec[ctr].x = ctrx-(5+(10*m)); + rec[ctr].y = ctry-5; + rec[ctr].width = 10*m; + rec[ctr].height = 10; + ++ctr; m=0; + } + } + XSetClipRectangles(Disp, cgc, 0, 0, rec, n, YXBanded); + } |