Redo Eval Graph with generic popup
authorH.G. Muller <h.g.muller@hccnet.nl>
Fri, 23 Mar 2012 19:06:15 +0000 (20:06 +0100)
committerH.G. Muller <h.g.muller@hccnet.nl>
Tue, 10 Apr 2012 09:39:39 +0000 (11:39 +0200)
The Graph option of the GenericPopUp is used to implement the Eval Graph.
Compared to the previous implementation, which was drawing directly in the
form widget, the new one has one extra widget layer, but that did not
affect the code anywhere. Adapt eval title to width of eval graph.

backend.h
dialogs.h
frontend.h
xboard.c
xevalgraph.c
xoptions.c

index a5b1056..e53bb45 100644 (file)
--- a/backend.h
+++ b/backend.h
@@ -113,6 +113,7 @@ extern Board boards[];
 extern char marker[BOARD_RANKS][BOARD_FILES];
 extern char lastMsg[MSG_SIZ];
 extern Boolean bookUp;
+extern int tinyLayout, smallLayout;
 
 char *CmailMsg P((void));
 /* Tord: Added the useFEN960 parameter in PositionToFEN() below */
index 835b369..d566b7d 100644 (file)
--- a/dialogs.h
+++ b/dialogs.h
@@ -84,6 +84,7 @@ TransientDlg=0, // transient: grabs mouse events and is destroyed at pop-down (s
 CommentDlg, TagsDlg, TextMenuDlg, InputBoxDlg, NoDlg, BrowserDlg, HistoryDlg, // persistent: no grab and reused
 GameListDlg,
 EngOutDlg,
+EvalGraphDlg,
 PromoDlg,       // this and beyond are destroyed at pop-down
 ErrorDlg,
 AskDlg,         // this and beyond do grab mouse events (and are destroyed)
index 358726a..4cad55a 100644 (file)
@@ -238,7 +238,6 @@ void EngineOutputPopDown P((void));
 int  EngineOutputIsUp P((void));
 int  EngineOutputDialogExists P((void));
 void EvalGraphPopUp P((void));
-void EvalGraphPopDown P((void));
 Boolean EvalGraphIsUp P((void));
 int  EvalGraphDialogExists P((void));
 
index ea765ad..9e89d57 100644 (file)
--- a/xboard.c
+++ b/xboard.c
@@ -309,7 +309,7 @@ Widget shellWidget, layoutWidget, formWidget, boardWidget, messageWidget,
   commentShell, whitePieceMenu, blackPieceMenu, dropMenu,
   menuBarWidget, buttonBarWidget, editShell, errorShell, analysisShell,
   ICSInputShell, fileNameShell;
-Widget historyShell, evalGraphShell;
+Widget historyShell;
 XSegment secondSegments[BOARD_RANKS + BOARD_FILES + 2];
 XSegment gridSegments[BOARD_RANKS + BOARD_FILES + 2];
 #if ENABLE_NLS
@@ -519,7 +519,6 @@ XtActionsRec boardActions[] = {
     { "TempBackwardProc", TempBackwardProc },
     { "TempForwardProc", TempForwardProc },
     { "CommentClick", (XtActionProc) CommentClick },
-    { "EvalGraphPopDown", (XtActionProc) EvalGraphPopDown },
     { "GenericPopDown", (XtActionProc) GenericPopDown },
     { "ErrorPopDown", (XtActionProc) ErrorPopDown },
     { "CopyMemoProc", (XtActionProc) CopyMemoProc },
@@ -993,8 +992,8 @@ GetWindowCoords ()
   // In XBoard this will have to wait until awareness of window parameters is implemented
   GetActualPlacement(shellWidget, &wpMain);
   if(shellUp[EngOutDlg]) GetActualPlacement(shells[EngOutDlg], &wpEngineOutput);
-  if(MoveHistoryIsUp()) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
-  if(EvalGraphIsUp()) GetActualPlacement(evalGraphShell, &wpEvalGraph);
+  if(shellUp[HistoryDlg]) GetActualPlacement(shells[HistoryDlg], &wpMoveHistory);
+  if(shellUp[EvalGraphDlg]) GetActualPlacement(shells[EvalGraphDlg], &wpEvalGraph);
   if(shellUp[GameListDlg]) GetActualPlacement(shells[GameListDlg], &wpGameList);
   if(shellUp[CommentDlg]) GetActualPlacement(shells[CommentDlg], &wpComment);
   if(shellUp[TagsDlg]) GetActualPlacement(shells[TagsDlg], &wpTags);
@@ -3382,8 +3381,8 @@ DragProc ()
           wpNew.width == wpMain.width && wpNew.height == wpMain.height) // not sized
            return; // false alarm
        if(shellUp[EngOutDlg]) CoDrag(shells[EngOutDlg], &wpEngineOutput);
-       if(MoveHistoryIsUp()) CoDrag(shells[HistoryDlg], &wpMoveHistory);
-       if(EvalGraphIsUp()) CoDrag(evalGraphShell, &wpEvalGraph);
+       if(shellUp[HistoryDlg]) CoDrag(shells[HistoryDlg], &wpMoveHistory);
+       if(shellUp[EvalGraphDlg]) CoDrag(shells[EvalGraphDlg], &wpEvalGraph);
        if(shellUp[GameListDlg]) CoDrag(shells[GameListDlg], &wpGameList);
        wpMain = wpNew;
        DrawPosition(True, NULL);
index ad0e962..2d87f12 100644 (file)
@@ -70,6 +70,8 @@ extern char *getenv();
 #include "common.h"
 #include "frontend.h"
 #include "backend.h"
+#include "dialogs.h"
+#include "menus.h"
 #include "xboard.h"
 #include "evalgraph.h"
 #include "gettext.h"
@@ -98,24 +100,16 @@ static char *title = N_("Evaluation graph");
 
 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;
 
 static GC pens[6]; // [HGM] put all pens in one array
 static GC hbrHist[3];
 
-#if 0
-static HDC hdcPB = NULL;
-static HBITMAP hbmPB = NULL;
-#endif
-
 // [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)
@@ -123,7 +117,7 @@ DrawSegment (int x, int y, int *lastX, int *lastY, int penType)
   static int curX, curY;
 
   if(penType != PEN_NONE)
-    XDrawLine(yDisplay, eGraphWindow, pens[penType], curX, curY, x, y);
+    XDrawLine(xDisplay, eGraphWindow, pens[penType], curX, curY, x, y);
   if(lastX != NULL) { *lastX = curX; *lastY = curY; }
   curX = x; curY = y;
 }
@@ -132,9 +126,9 @@ DrawSegment (int x, int y, int *lastX, int *lastY, int penType)
 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);
+    XFillRectangle(xDisplay, 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);
+      XDrawRectangle(xDisplay, eGraphWindow, pens[PEN_BLACK], left, top, right-left-1, bottom-top-1);
 }
 
 // front-end wrapper for putting text in graph
@@ -142,7 +136,7 @@ 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);
+    XDrawString(xDisplay, eGraphWindow, coordGC, MarginX - 2 - 7*cbBuf, y+5, buf, cbBuf);
 }
 
 // front-end
@@ -153,7 +147,7 @@ MakeColor (char *color)
 
     vFrom.addr = (caddr_t) color;
     vFrom.size = strlen(color);
-    XtConvert(evalGraphShell, XtRString, &vFrom, XtRPixel, &vTo);
+    XtConvert(shells[EvalGraphDlg], XtRString, &vFrom, XtRPixel, &vTo);
     // test for NULL?
 
     return *(Pixel *) vTo.addr;
@@ -174,46 +168,16 @@ CreateGC (int width, char *fg, char *bg, int style)
     gc_values.foreground = MakeColor(fg);
     gc_values.background = MakeColor(bg);
 
-    return XtGetGC(evalGraphShell, value_mask, &gc_values);
+    return XtGetGC(shells[EvalGraphDlg], 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;
-    }
-
-    // back-end painting; calls back front-end primitives for lines, rectangles and text
-    PaintEvalGraph();
-    XtSetArg(args[0], XtNtitle, MakeEvalTitle(_(title))); j++;
-    XtSetValues(evalGraphShell, args, 1);
-
-    XSync(yDisplay, False);
-}
+static int initDone = FALSE;
 
 static void
-InitializeEvalGraph ()
+InitializeEvalGraph (Option *opt)
 {
+  eGraphWindow = XtWindow(opt->handle);
+
   pens[PEN_BLACK]      = CreateGC(1, "black", "black", LineSolid);
   pens[PEN_DOTTED]     = CreateGC(1, "#A0A0A0", "#A0A0A0", LineOnOffDash);
   pens[PEN_BLUEDOTTED] = CreateGC(1, "#0000FF", "#0000FF", LineOnOffDash);
@@ -222,215 +186,98 @@ InitializeEvalGraph ()
   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)
+
+  initDone = TRUE;
 }
 
-void
-EvalClick (Widget widget, caddr_t unused, XEvent *event)
-{
-        if( widget && event->type == ButtonPress ) {
-            int index = GetMoveIndexFromPoint( event->xbutton.x, event->xbutton.y );
+// The following stuff is really back-end (but too little to bother with a separate file)
 
-            if( index >= 0 && index < currLast ) {
-                ToNrEvent( index + 1 );
-            }
-        }
+static void
+DisplayEvalGraph ()
+{   // back-end painting; calls back front-end primitives for lines, rectangles and text
+    char *t = MakeEvalTitle(_(title));
+    if(t != title && nWidthPB < 340) t = MakeEvalTitle(nWidthPB < 240 ? "" : _("Eval"));
+    PaintEvalGraph();
+    SetDialogTitle(EvalGraphDlg, t);
 }
 
-// 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 widget, caddr_t unused, XEvent *event)
+static void
+EvalClick (int x, int y)
 {
-    if (!XtIsRealized(widget))
-      return;
-
-    switch (event->type) {
-      case Expose:
-       if (event->xexpose.count > 0) return;  /* no clipping is done */
-       DisplayEvalGraph();
-       break;
-      default:
-       return;
-    }
+    int index = GetMoveIndexFromPoint( x, y );
+
+    if( index >= 0 && index < currLast ) ToNrEvent( index + 1 );
 }
-// The following routines are mutated clones of the commentPopUp routines
 
-Widget
-EvalGraphCreate (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 */
+           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!
 }
 
+static Option graphOptions[] = {
+{ 150, 0x9C, 300, NULL, (void*) &EvalCallback, NULL, NULL, Graph , "" },
+{ 0, 2, 0, NULL, NULL, "", NULL, EndMark , "" }
+};
+
 void
 EvalGraphPopUp ()
 {
     Arg args[16];
     int j;
-    static int  needInit = TRUE;
-
-    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]); // first time: add callbacks and initialize pens
     } 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("Show Evaluation Graph", 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 ()
 {
-    Arg args[16];
-    int j;
+    PopDown(EvalGraphDlg);
 
-    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;
 //    ShowThinkingEvent(); // [HGM] thinking: might need to shut off thinking output
 }
 
 Boolean
 EvalGraphIsUp ()
 {
-    return evalGraphDialogUp;
+    return shellUp[EvalGraphDlg];
 }
 
 int
 EvalGraphDialogExists ()
 {
-    return evalGraphShell != NULL;
+    return DialogExists(EvalGraphDlg);
 }
 
 void
-EvalGraphProc (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.
+
+// This function is the interface to the back-end.
+
 void
 EvalGraphSet (int first, int last, int current, ChessProgramStats_Move * pvInfo)
 {
@@ -441,7 +288,8 @@ EvalGraphSet (int first, int last, int current, ChessProgramStats_Move * pvInfo)
     currCurrent = current;
     currPvInfo = pvInfo;
 
-    if( evalGraphShell ) {
+    if( DialogExists(EvalGraphDlg) ) {
         DisplayEvalGraph();
     }
 }
+
index f87176e..88a9ff3 100644 (file)
@@ -408,7 +408,7 @@ AddHandler (Option *opt, int nr)
 Widget shells[NrOfDialogs];
 DialogClass parents[NrOfDialogs];
 WindowPlacement *wp[NrOfDialogs] = { // Beware! Order must correspond to DialogClass enum
-    NULL, &wpComment, &wpTags, NULL, NULL, NULL, NULL, &wpMoveHistory, &wpGameList, &wpEngineOutput
+    NULL, &wpComment, &wpTags, NULL, NULL, NULL, NULL, &wpMoveHistory, &wpGameList, &wpEngineOutput, &wpEvalGraph
 };
 
 int