X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=xevalgraph.c;h=f3cac1fd65adfa4c82380b64db0b47e7f3064e5e;hb=21a44c336aa8cd16a38f3c682386528c8f112650;hp=5c8f1f073cbfc8b9938b4f9f6296f549020e2c50;hpb=ed47244d151ccf276b9e233b4415e00aa5d3d29d;p=xboard.git diff --git a/xevalgraph.c b/xevalgraph.c index 5c8f1f0..f3cac1f 100644 --- a/xevalgraph.c +++ b/xevalgraph.c @@ -6,7 +6,7 @@ * * Copyright 2005 Alessandro Scotti * - * Enhancements Copyright 2009, 2010 Free Software Foundation, Inc. + * Enhancements Copyright 2009, 2010, 2011, 2012 Free Software Foundation, Inc. * * ------------------------------------------------------------------------ * @@ -67,11 +67,18 @@ extern char *getenv(); #include #include +#include +#include + #include "common.h" #include "frontend.h" #include "backend.h" +#include "dialogs.h" +#include "menus.h" #include "xboard.h" #include "evalgraph.h" +#include "xevalgraph.h" +#include "draw.h" #include "gettext.h" #ifdef ENABLE_NLS @@ -90,358 +97,233 @@ extern char *getenv(); #define _LL_ 100 -// imports from xboard.c -extern Widget formWidget, shellWidget, boardWidget, menuBarWidget; -extern Display *xDisplay; -extern Window xBoardWindow; -extern int squareSize; -extern Pixmap xMarkPixmap, wIconPixmap, bIconPixmap; -extern char *layoutName; - Pixmap icons[8]; // [HGM] this front-end array translates back-end icon indicator to handle Widget outputField[2][7]; // [HGM] front-end array to translate output field to window handle - -/* Imports from backend.c */ - -/* Imports from xboard.c */ -extern Arg layoutArgs[2], formArgs[2], messageArgs[4]; -extern GC coordGC; +static char *title = N_("Evaluation graph"); //extern WindowPlacement wpEvalGraph; Position evalGraphX = -1, evalGraphY = -1; Dimension evalGraphW, evalGraphH; -Widget evalGraphShell; -static int evalGraphDialogUp; /* Module variables */ char *crWhite = "#FFFFB0"; char *crBlack = "#AD5D3D"; -static Display *yDisplay; -static Window eGraphWindow; +Option *disp; -static GC pens[6]; // [HGM] put all pens in one array -static GC hbrHist[3]; +static Option *EvalCallback P((int button, int x, int y)); -#if 0 -static HDC hdcPB = NULL; -static HBITMAP hbmPB = NULL; -#endif +static void +ChoosePen(cairo_t *cr, int i) +{ + switch(i) { + case PEN_BLACK: + SetPen(cr, 1.0, "#000000", 0); + break; + case PEN_DOTTED: + SetPen(cr, 1.0, "#A0A0A0", 1); + break; + case PEN_BLUEDOTTED: + SetPen(cr, 1.0, "#0000FF", 1); + break; + case PEN_BOLDWHITE: + SetPen(cr, 3.0, crWhite, 0); + break; + case PEN_BOLDBLACK: + SetPen(cr, 3.0, crBlack, 0); + break; + case PEN_BACKGD: + SetPen(cr, 3.0, "#E0E0F0", 0); + break; + } +} // [HGM] front-end, added as wrapper to avoid use of LineTo and MoveToEx in other routines (so they can be back-end) -void DrawSegment( int x, int y, int *lastX, int *lastY, int penType ) +void +DrawSegment (int x, int y, int *lastX, int *lastY, enum PEN penType) { static int curX, curY; - if(penType != PEN_NONE) - XDrawLine(yDisplay, eGraphWindow, pens[penType], curX, curY, x, y); + if(penType != PEN_NONE) { + cairo_t *cr = cairo_create(DRAWABLE(disp)); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + cairo_move_to (cr, curX, curY); + cairo_line_to (cr, x,y); + ChoosePen(cr, penType); + cairo_stroke (cr); + cairo_destroy (cr); + } + if(lastX != NULL) { *lastX = curX; *lastY = curY; } curX = x; curY = y; } // front-end wrapper for drawing functions to do rectangles -void DrawRectangle( int left, int top, int right, int bottom, int side, int style ) -{ - XFillRectangle(yDisplay, eGraphWindow, hbrHist[side], left, top, right-left, bottom-top); - if(style != FILLED) - XDrawRectangle(yDisplay, eGraphWindow, pens[PEN_BLACK], left, top, right-left-1, bottom-top-1); -} - -// front-end wrapper for putting text in graph -void DrawEvalText(char *buf, int cbBuf, int y) -{ - // the magic constants 7 and 5 should really be derived from the font size somehow - XDrawString(yDisplay, eGraphWindow, coordGC, MarginX - 2 - 7*cbBuf, y+5, buf, cbBuf); -} - -// front-end -static Pixel MakeColor(char *color ) +void +DrawRectangle (int left, int top, int right, int bottom, int side, int style) { - XrmValue vFrom, vTo; + cairo_t *cr; + + cr = cairo_create (DRAWABLE(disp)); + cairo_set_antialias (cr, CAIRO_ANTIALIAS_NONE); + cairo_rectangle (cr, left, top, right-left, bottom-top); + switch(side) + { + case 0: ChoosePen(cr, PEN_BOLDWHITE); break; + case 1: ChoosePen(cr, PEN_BOLDBLACK); break; + case 2: ChoosePen(cr, PEN_BACKGD); break; + } + cairo_fill (cr); - vFrom.addr = (caddr_t) color; - vFrom.size = strlen(color); - XtConvert(evalGraphShell, XtRString, &vFrom, XtRPixel, &vTo); - // test for NULL? + if(style != FILLED) + { + cairo_rectangle (cr, left, top, right-left-1, bottom-top-1); + ChoosePen(cr, PEN_BLACK); + cairo_stroke (cr); + } - return *(Pixel *) vTo.addr; + cairo_destroy(cr); } -static GC CreateGC(int width, char *fg, char *bg, int style) +// front-end wrapper for putting text in graph +void +DrawEvalText (char *buf, int cbBuf, int y) { - XtGCMask value_mask = GCLineWidth | GCLineStyle | GCForeground - | GCBackground | GCFunction | GCPlaneMask; - XGCValues gc_values; + // the magic constants 8 and 5 should really be derived from the font size somehow + cairo_text_extents_t extents; + cairo_t *cr = cairo_create(DRAWABLE(disp)); - gc_values.plane_mask = AllPlanes; - gc_values.line_width = width; - gc_values.line_style = style; - gc_values.function = GXcopy; + /* GTK-TODO this has to go into the font-selection */ + cairo_select_font_face (cr, "Sans", + CAIRO_FONT_SLANT_NORMAL, + CAIRO_FONT_WEIGHT_NORMAL); + cairo_set_font_size (cr, 12.0); - gc_values.foreground = MakeColor(fg); - gc_values.background = MakeColor(bg); - return XtGetGC(evalGraphShell, value_mask, &gc_values); -} - -// front-end. Create pens, device context and buffer bitmap for global use, copy result to display -// The back-end part n the middle has been taken out and moed to PainEvalGraph() -static void DisplayEvalGraph() -{ - int j; - int width; - int height; - Dimension w, h; - Arg args[6]; - - /* Get client area */ - j = 0; - XtSetArg(args[j], XtNwidth, &w); j++; - XtSetArg(args[j], XtNheight, &h); j++; - XtGetValues(evalGraphShell, args, j); - width = w; - height = h; - - /* Create or recreate paint box if needed */ - if( width != nWidthPB || height != nHeightPB ) { - - nWidthPB = width; - nHeightPB = height; - } + cairo_text_extents (cr, buf, &extents); - // back-end painting; calls back front-end primitives for lines, rectangles and text - PaintEvalGraph(); + cairo_move_to (cr, MarginX - 2 - 8*cbBuf, y+5); + cairo_text_path (cr, buf); + cairo_set_source_rgb (cr, 0.0, 0.0, 0); + cairo_fill_preserve (cr); + cairo_set_source_rgb (cr, 0, 1.0, 0); + cairo_set_line_width (cr, 0.1); + cairo_stroke (cr); - XSync(yDisplay, False); + /* free memory */ + cairo_destroy (cr); } -static void InitializeEvalGraph() +static int initDone = FALSE; + +static void +InitializeEvalGraph (Option *opt, int w, int h) { - pens[PEN_BLACK] = CreateGC(1, "black", "black", LineSolid); - pens[PEN_DOTTED] = CreateGC(1, "#A0A0A0", "#A0A0A0", LineOnOffDash); - pens[PEN_BLUEDOTTED] = CreateGC(1, "#0000FF", "#0000FF", LineOnOffDash); - pens[PEN_BOLD] = CreateGC(3, crWhite, crWhite, LineSolid); - pens[PEN_BOLD+1] = CreateGC(3, crBlack, crBlack, LineSolid); - hbrHist[0] = CreateGC(3, crWhite, crWhite, LineSolid); - hbrHist[1] = CreateGC(3, crBlack, crBlack, LineSolid); - hbrHist[2] = CreateGC(3, "#E0E0F0", "#E0E0F0", LineSolid);; // background (a bit blueish, for contrst with yellow curve) + if(w == 0) { + Arg args[10]; + XtSetArg(args[0], XtNwidth, &evalGraphW); + XtSetArg(args[1], XtNheight, &evalGraphH); + XtGetValues(opt->handle, args, 2); + nWidthPB = evalGraphW; nHeightPB = evalGraphH; + } else nWidthPB = w, nHeightPB = h; + + initDone = TRUE; } -void EvalClick(widget, unused, event) - Widget widget; - caddr_t unused; - XEvent *event; +// The following stuff is really back-end (but too little to bother with a separate file) + +static void +EvalClick (int x, int y) { - if( widget && event->type == ButtonPress ) { - int index = GetMoveIndexFromPoint( event->xbutton.x, event->xbutton.y ); + int index = GetMoveIndexFromPoint( x, y ); - if( index >= 0 && index < currLast ) { - ToNrEvent( index + 1 ); - } - } + if( index >= 0 && index < currLast ) ToNrEvent( index + 1 ); } -// This (cloned from EventProc in xboard.c) is needed as event handler, to prevent -// the graph being wiped out after covering / uncovering by other windows. -void EvalEventProc(widget, unused, event) - Widget widget; - caddr_t unused; - XEvent *event; -{ - if (!XtIsRealized(widget)) - return; - - switch (event->type) { - case Expose: - if (event->xexpose.count > 0) return; /* no clipping is done */ - DisplayEvalGraph(); - break; - default: - return; - } +static Option graphOptions[] = { +{ 150, 0x9C, 300, NULL, (void*) &EvalCallback, NULL, NULL, Graph , "" }, +{ 0, 2, 0, NULL, NULL, "", NULL, EndMark , "" } +}; + +static void +DisplayEvalGraph () +{ // back-end painting; calls back front-end primitives for lines, rectangles and text + char *t = MakeEvalTitle(_(title)); + nWidthPB = disp->max; nHeightPB = disp->value; + if(t != title && nWidthPB < 340) t = MakeEvalTitle(nWidthPB < 240 ? "" : _("Eval")); + PaintEvalGraph(); + GraphExpose(graphOptions, 0, 0, nWidthPB, nHeightPB); + SetDialogTitle(EvalGraphDlg, t); } -// The following routines are mutated clones of the commentPopUp routines -Widget EvalGraphCreate(name) - char *name; +static Option * +EvalCallback (int button, int x, int y) { - Arg args[16]; - Widget shell, layout, form; - Dimension bw_width, bw_height; - int j; - - // get board width - j = 0; - XtSetArg(args[j], XtNwidth, &bw_width); j++; - XtSetArg(args[j], XtNheight, &bw_height); j++; - XtGetValues(boardWidget, args, j); - - // define form within layout within shell. - j = 0; - XtSetArg(args[j], XtNresizable, True); j++; - shell = -#if TOPLEVEL - XtCreatePopupShell(name, topLevelShellWidgetClass, -#else - XtCreatePopupShell(name, transientShellWidgetClass, -#endif - shellWidget, args, j); - layout = - XtCreateManagedWidget(layoutName, formWidgetClass, shell, - layoutArgs, XtNumber(layoutArgs)); - // divide window vertically into two equal parts, by creating two forms - form = - XtCreateManagedWidget("form", formWidgetClass, layout, - formArgs, XtNumber(formArgs)); - // make sure width is known in advance, for better placement of child widgets - j = 0; - XtSetArg(args[j], XtNwidth, (XtArgVal) bw_width-16); j++; - XtSetArg(args[j], XtNheight, (XtArgVal) bw_height/4); j++; - XtSetValues(shell, args, j); - - XtRealizeWidget(shell); - - if(wpEvalGraph.width > 0) { - evalGraphW = wpEvalGraph.width; - evalGraphH = wpEvalGraph.height; - evalGraphX = wpEvalGraph.x; - evalGraphY = wpEvalGraph.y; - } - - if (evalGraphX == -1) { - int xx, yy; - Window junk; - evalGraphH = bw_height/4; - evalGraphW = bw_width-16; - - XSync(xDisplay, False); -#ifdef NOTDEF - /* This code seems to tickle an X bug if it is executed too soon - after xboard starts up. The coordinates get transformed as if - the main window was positioned at (0, 0). - */ - XtTranslateCoords(shellWidget, - (bw_width - evalGraphW) / 2, 0 - evalGraphH / 2, - &evalGraphX, &evalGraphY); -#else /*!NOTDEF*/ - XTranslateCoordinates(xDisplay, XtWindow(shellWidget), - RootWindowOfScreen(XtScreen(shellWidget)), - (bw_width - evalGraphW) / 2, 0 - evalGraphH / 2, - &xx, &yy, &junk); - evalGraphX = xx; - evalGraphY = yy; -#endif /*!NOTDEF*/ - if (evalGraphY < 0) evalGraphY = 0; /*avoid positioning top offscreen*/ + if(!initDone) return NULL; + + switch(button) { + case 10: // expose event + /* Create or recreate paint box if needed */ + if(x != nWidthPB || y != nHeightPB) { + InitializeEvalGraph(&graphOptions[0], x, y); + } + nWidthPB = x; + nHeightPB = y; + DisplayEvalGraph(); + break; + case 1: EvalClick(x, y); // left button + default: break; // other buttons ignored } - j = 0; - XtSetArg(args[j], XtNheight, evalGraphH); j++; - XtSetArg(args[j], XtNwidth, evalGraphW); j++; - XtSetArg(args[j], XtNx, evalGraphX); j++; - XtSetArg(args[j], XtNy, evalGraphY); j++; - XtSetValues(shell, args, j); - - yDisplay = XtDisplay(shell); - eGraphWindow = XtWindow(form); - XtAddEventHandler(form, ExposureMask, False, - (XtEventHandler) EvalEventProc, NULL); - XtAddEventHandler(form, ButtonPressMask, False, - (XtEventHandler) EvalClick, NULL); - - return shell; + return NULL; // no context menu! } void -EvalGraphPopUp() +EvalGraphPopUp () { - Arg args[16]; - int j; - static int needInit = TRUE; - static char *title = _("Evaluation graph"); - - if (evalGraphShell == NULL) { - - evalGraphShell = - EvalGraphCreate(title); - XtRealizeWidget(evalGraphShell); - CatchDeleteWindow(evalGraphShell, "EvalGraphPopDown"); - if( needInit ) { - InitializeEvalGraph(); - needInit = FALSE; - } + if (GenericPopUp(graphOptions, _(title), EvalGraphDlg, BoardWindow, NONMODAL, 1)) { + InitializeEvalGraph(&graphOptions[0], 0, 0); // first time: add callbacks and initialize pens + disp = graphOptions; } else { - j = 0; - XtSetArg(args[j], XtNiconName, (XtArgVal) title); j++; - XtSetArg(args[j], XtNtitle, (XtArgVal) title); j++; - XtSetValues(evalGraphShell, args, j); + SetDialogTitle(EvalGraphDlg, _(title)); + SetIconName(EvalGraphDlg, _(title)); } - XtPopup(evalGraphShell, XtGrabNone); - XSync(yDisplay, False); + MarkMenu("View.EvaluationGraph", EvalGraphDlg); - j=0; - XtSetArg(args[j], XtNleftBitmap, xMarkPixmap); j++; - XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Evaluation Graph"), - args, j); - - evalGraphDialogUp = True; // ShowThinkingEvent(); // [HGM] thinking: might need to prompt engine for thinking output } -void EvalGraphPopDown() +void +EvalGraphPopDown () { - Arg args[16]; - int j; - - if (!evalGraphDialogUp) return; - j = 0; - XtSetArg(args[j], XtNx, &evalGraphX); j++; - XtSetArg(args[j], XtNy, &evalGraphY); j++; - XtSetArg(args[j], XtNwidth, &evalGraphW); j++; - XtSetArg(args[j], XtNheight, &evalGraphH); j++; - XtGetValues(evalGraphShell, args, j); - wpEvalGraph.x = evalGraphX - 4; - wpEvalGraph.y = evalGraphY - 23; - wpEvalGraph.width = evalGraphW; - wpEvalGraph.height = evalGraphH; - XtPopdown(evalGraphShell); - XSync(xDisplay, False); - j=0; - XtSetArg(args[j], XtNleftBitmap, None); j++; - XtSetValues(XtNameToWidget(menuBarWidget, "menuView.Show Evaluation Graph"), - args, j); - - evalGraphDialogUp = False; + PopDown(EvalGraphDlg); + // ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output } -Boolean EvalGraphIsUp() +Boolean +EvalGraphIsUp () { - return evalGraphDialogUp; + return shellUp[EvalGraphDlg]; } -int EvalGraphDialogExists() +int +EvalGraphDialogExists () { - return evalGraphShell != NULL; + return DialogExists(EvalGraphDlg); } void -EvalGraphProc(w, event, prms, nprms) - Widget w; - XEvent *event; - String *prms; - Cardinal *nprms; +EvalGraphProc () { - if (evalGraphDialogUp) { - EvalGraphPopDown(); - } else { - EvalGraphPopUp(); - } + if (!PopDown(EvalGraphDlg)) EvalGraphPopUp(); } -// This function is the interface to the back-end. It is currently called through the front-end, -// though, where it shares the HistorySet() wrapper with MoveHistorySet(). Once all front-ends -// support the eval graph, it would be more logical to call it directly from the back-end. -void EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pvInfo ) + +// This function is the interface to the back-end. + +void +EvalGraphSet (int first, int last, int current, ChessProgramStats_Move * pvInfo) { /* [AS] Danger! For now we rely on the pvInfo parameter being a static variable! */ @@ -450,7 +332,8 @@ void EvalGraphSet( int first, int last, int current, ChessProgramStats_Move * pv currCurrent = current; currPvInfo = pvInfo; - if( evalGraphShell ) { + if( DialogExists(EvalGraphDlg) ) { DisplayEvalGraph(); } } +