Move MarkMenuItem to xoptions.c
[xboard.git] / xoptions.c
index 55a3935..cd18a57 100644 (file)
@@ -68,6 +68,9 @@ extern char *getenv();
 #include <X11/Xaw/Toggle.h>
 #include <X11/Xaw/Scrollbar.h>
 
+#include <cairo/cairo.h>
+#include <cairo/cairo-xlib.h>
+
 #include "common.h"
 #include "backend.h"
 #include "xboard.h"
@@ -140,6 +143,18 @@ static Arg formArgs[] = {
 };
 
 void
+MarkMenuItem (char *menuRef, int state)
+{
+    MenuItem *item = MenuNameToItem(menuRef);
+
+    if(item) {
+       Arg args[2];
+       XtSetArg(args[0], XtNleftBitmap, state ? xMarkPixmap : None);
+       XtSetValues(item->handle, args, 1);
+    }
+}
+
+void
 GetWidgetText (Option *opt, char **buf)
 {
     Arg arg;
@@ -409,7 +424,7 @@ 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, &wpEvalGraph,
-    NULL, NULL, NULL, NULL, &wpMain
+    NULL, NULL, NULL, NULL, /*&wpMain*/ NULL
 };
 
 int
@@ -535,19 +550,44 @@ GraphEventProc(Widget widget, caddr_t client_data, XEvent *event)
 {   // handle expose and mouse events on Graph widget
     Dimension w, h;
     Arg args[16];
-    int j, button=10, f=1;
-    Option *opt;
+    int j, button=10, f=1, sizing=0;
+    Option *opt, *graph = (Option *) client_data;
+    PointerCallback *userHandler = graph->target;
+
     if (!XtIsRealized(widget)) return;
 
     switch(event->type) {
-       case Expose:
-           if (((XExposeEvent*)event)->count > 0) return;  // don't bother if further exposure is pending
-           /* Get client area */
+       case Expose: // make handling of expose events generic, just copying from memory buffer (->choice) to display (->textValue)
+           /* Get window size */
            j = 0;
            XtSetArg(args[j], XtNwidth, &w); j++;
            XtSetArg(args[j], XtNheight, &h); j++;
            XtGetValues(widget, args, j);
-           break;
+
+           if(w < graph->max || w > graph->max + 1 || h != graph->value) { // use width fudge of 1 pixel
+               if(((XExposeEvent*)event)->count >= 0) { // suppress sizing on expose for ordered redraw in response to sizing.
+                   sizing = 1;
+                   graph->max = w; graph->value = h; // note: old values are kept if we we don't exceed width fudge
+               }
+           } else w = graph->max;
+
+           if(sizing && ((XExposeEvent*)event)->count > 0) { graph->max = 0; return; } // don't bother if further exposure is pending during resize
+           if(!graph->textValue || sizing) { // create surfaces of new size for display widget
+               if(graph->textValue) cairo_surface_destroy((cairo_surface_t *)graph->textValue);
+               graph->textValue = (char*) cairo_xlib_surface_create(xDisplay, XtWindow(widget), DefaultVisual(xDisplay, 0), w, h);
+           }
+           if(sizing) { // the memory buffer was already created in GenericPopup(),
+                        // to give drawing routines opportunity to use it before first expose event
+                        // (which are only processed when main gets to the event loop, so after all init!)
+                        // so only change when size is no longer good
+               if(graph->choice) cairo_surface_destroy((cairo_surface_t *) graph->choice);
+               graph->choice = (char**) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, w, h);
+               break;
+           }
+           w = ((XExposeEvent*)event)->width;
+           if(((XExposeEvent*)event)->x + w > graph->max) w--; // cut off fudge pixel
+           if(w) ExposeRedraw(graph, ((XExposeEvent*)event)->x, ((XExposeEvent*)event)->y, w, ((XExposeEvent*)event)->height);
+           return;
        case MotionNotify:
            f = 0;
            w = ((XButtonEvent*)event)->x; h = ((XButtonEvent*)event)->y;
@@ -565,7 +605,7 @@ GraphEventProc(Widget widget, caddr_t client_data, XEvent *event)
            }
     }
     button *= f;
-    opt = ((PointerCallback*) client_data)(button, w, h);
+    opt = userHandler(button, w, h);
     if(opt) { // user callback specifies a context menu; pop it up
        XUngrabPointer(xDisplay, CurrentTime);
        XtCallActionProc(widget, "XawPositionSimpleMenu", event, &(opt->name), 1);
@@ -574,6 +614,15 @@ GraphEventProc(Widget widget, caddr_t client_data, XEvent *event)
     XSync(xDisplay, False);
 }
 
+void
+GraphExpose (Option *opt, int x, int y, int w, int h)
+{
+  XExposeEvent e;
+  if(!opt->handle) return;
+  e.x = x; e.y = y; e.width = w; e.height = h; e.count = -1; e.type = Expose; // count = -1: kludge to suppress sizing
+  GraphEventProc(opt->handle, (caddr_t) opt, (XEvent *) &e); // fake expose event
+}
+
 static void
 GenericCallback (Widget w, XtPointer client_data, XtPointer call_data)
 {   // all Buttons in a dialog (including OK, cancel) invoke this
@@ -709,8 +758,8 @@ SetPositionAndSize (Arg *args, Widget leftNeigbor, Widget topNeigbor, int b, int
     if(!appData.monoMode) {
        if(!b && appData.dialogColor[0]) XtSetArg(args[j], XtNbackground, dialogColor),  j++;
        if(b == 3 && appData.buttonColor[0]) XtSetArg(args[j], XtNbackground, buttonColor),  j++;
-       if(b == 3) b = 1;
     }
+    if(b == 3) b = 1;
     // border
     XtSetArg(args[j], XtNborderWidth, b);  j++;
     return j;
@@ -744,7 +793,6 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent
 
     if(engineDlg) { // Settings popup for engine: format through heuristic
        int n = currentCps->nrOptions;
-       if(!n) { DisplayNote(_("Engine has no options")); currentCps = NULL; return 0; }
        if(n > 50) width = 4; else if(n>24) width = 2; else width = 1;
        height = n / width + 1;
        if(n && (currentOption[n-1].type == Button || currentOption[n-1].type == SaveButton)) currentOption[n].min = SAME_ROW; // OK on same line
@@ -807,12 +855,16 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent
            if(option[i].type == FileName || option[i].type == PathName) w -= 55;
            j = SetPositionAndSize(args, dialog, last, 1 /* border */,
                                   w /* w */, option[i].type == TextBox ? option[i].value : 0 /* h */, 0x91 /* chain full width */);
-           if(option[i].type == TextBox && option[i].value) { // decorations for multi-line text-edits
+           if(option[i].type == TextBox) { // decorations for multi-line text-edits
                if(option[i].min & T_VSCRL) { XtSetArg(args[j], XtNscrollVertical, XawtextScrollAlways);  j++; }
                if(option[i].min & T_HSCRL) { XtSetArg(args[j], XtNscrollHorizontal, XawtextScrollAlways);  j++; }
                if(option[i].min & T_FILL)  { XtSetArg(args[j], XtNautoFill, True);  j++; }
                if(option[i].min & T_WRAP)  { XtSetArg(args[j], XtNwrap, XawtextWrapWord); j++; }
-               if(option[i].min & T_TOP)   { XtSetArg(args[j], XtNtop, XtChainTop); j++; }
+               if(option[i].min & T_TOP)   { XtSetArg(args[j], XtNtop, XtChainTop); j++;
+                   if(!option[i].value) {    XtSetArg(args[j], XtNbottom, XtChainTop); j++;
+                                             XtSetValues(dialog, args+j-2, 2);
+                   }
+               }
            } else shrink = TRUE;
            XtSetArg(args[j], XtNeditType, XawtextEdit);  j++;
            XtSetArg(args[j], XtNuseStringInPlace, False);  j++;
@@ -879,7 +931,7 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent
 #if ENABLE_NLS
            if(option[i].choice) XtSetArg(args[j], XtNfontSet, *(XFontSet*)option[i].choice), j++;
 #else
-           if(option[i].choice) XtSetArg(args[j], XtNfont, *(XFontStruct*)option[i].choice), j++;
+           if(option[i].choice) XtSetArg(args[j], XtNfont, (XFontStruct*)option[i].choice), j++;
 #endif
            XtSetArg(args[j], XtNresizable, False);  j++;
            XtSetArg(args[j], XtNjustify, XtJustifyLeft);  j++;
@@ -961,8 +1013,9 @@ GenericPopUp (Option *option, char *title, DialogClass dlgNr, DialogClass parent
            option[i].handle = (void*)
                (last = XtCreateManagedWidget("graph", widgetClass, form, args, j));
            XtAddEventHandler(last, ExposureMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask, False,
-                     (XtEventHandler) GraphEventProc, option[i].target); // mandatory user-supplied expose handler
+                     (XtEventHandler) GraphEventProc, &option[i]); // mandatory user-supplied expose handler
            if(option[i].min & SAME_ROW) last = forelast, forelast = lastrow;
+           option[i].choice = (char**) cairo_image_surface_create (CAIRO_FORMAT_ARGB32, option[i].max, option[i].value); // image buffer
            break;
          case PopUp: // note: used only after Graph, so 'last' refers to the Graph widget
            option[i].handle = (void*) CreateComboPopup(last, option + i, i + 256*dlgNr, TRUE, option[i].value);
@@ -1149,7 +1202,7 @@ SetInsertPos (Option *opt, int pos)
     XtSetArg(args[0], XtNinsertPosition, pos);
     XtSetValues(opt->handle, args, 1);
 //    SetFocus(opt->handle, shells[InputBoxDlg], NULL, False); // No idea why this does not work, and the following is needed:
-    XSetInputFocus(xDisplay, XtWindow(opt->handle), RevertToPointerRoot, CurrentTime);
+//    XSetInputFocus(xDisplay, XtWindow(opt->handle), RevertToPointerRoot, CurrentTime);
 }
 
 void