#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"
float top, bottom, f, g;
HighlightListBoxItem(opt, sel);
if(!ReadScroll(opt, &top, &bottom)) return; // no scroll bar
- bottom = bottom*max - 1.;
+ bottom = bottom*max - 1.f;
f = g = top;
top *= max;
- if(sel > (top + 3*bottom)/4) f = (sel - 0.75*(bottom-top))/max; else
- if(sel < (3*top + bottom)/4) f = (sel - 0.25*(bottom-top))/max;
- if(f < 0.) f = 0.; if(f + 1./max > 1.) f = 1. - 1./max;
+ if(sel > (top + 3*bottom)/4) f = (sel - 0.75f*(bottom-top))/max; else
+ if(sel < (3*top + bottom)/4) f = (sel - 0.25f*(bottom-top))/max;
+ if(f < 0.f) f = 0.; if(f + 1.f/max > 1.f) f = 1. - 1./max;
if(f != g) SetScroll(opt, f);
}
static Widget
CreateComboPopup (Widget parent, Option *opt, int n, int fromList, int def)
{ // fromList determines if the item texts are taken from a list of strings, or from a menu table
- int i, j;
+ int i;
Widget menu, entry;
Arg arg;
MenuItem *mb = (MenuItem *) opt->choice;
for (i=0; 1; i++)
{
- char *msg = fromList ? list[i] : mb[i].string, *msg2;
+ char *msg = fromList ? list[i] : mb[i].string;
if(!msg) break;
entry = CreateMenuItem(menu, opt->min & NO_GETTEXT ? msg : _(msg), (XtCallbackProc) ComboSelect, (n<<16)+i);
if(!fromList) mb[i].handle = (void*) entry; // save item ID, for enabling / checkmarking
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
{ // 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;
}
}
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);
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
int j=0, n = atoi(prms[0]);
static char *params[3] = { "", "Continuous", "Proportional" };
Arg args[16];
- float f, h, top;
+ float h, top;
Widget v;
if(!n) { // transient dialogs also use this for list-selection callback
n = prms[1][0]-'0';
XtSetArg(args[j], XtNshown, &h); j++;
XtSetArg(args[j], XtNtopOfThumb, &top); j++;
XtGetValues(v, args, j);
- top += 0.1*h*n; if(top < 0.) top = 0.;
+ top += 0.1f*h*n; if(top < 0.f) top = 0.;
XtCallActionProc(v, "StartScroll", event, params+1, 1);
XawScrollbarSetThumb(v, top, -1.0);
XtCallActionProc(v, "NotifyThumb", event, params, 0);
static void
SqueezeIntoBox (Option *opt, int nr, int width)
{ // size buttons in bar to fit, clipping button names where necessary
- int i, j, wtot = 0;
+ int i, wtot = 0;
Dimension widths[20], oldWidths[20];
Arg arg;
for(i=1; i<nr; i++) {
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;
char def[MSG_SIZ], *msg, engineDlg = (currentCps != NULL && dlgNr != BrowserDlg);
static char pane[6] = "paneX";
Widget texts[100], forelast = NULL, anchor, widest, lastrow = NULL, browse = NULL;
- Dimension bWidth = 50, m;
+ Dimension bWidth = 50;
if(dlgNr < PromoDlg && shellUp[dlgNr]) return 0; // already up
if(dlgNr && dlgNr < PromoDlg && shells[dlgNr]) { // reusable, and used before (but popped down)
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++;
#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++;
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);
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