#include <Xm/DrawingA.h>
#include <Xm/PushB.h>
#include <Xm/MessageB.h>
#include <Xm/ScrolledW.h>

#undef SHELL

XtAppContext app;

Widget top;

Widget CreateColorPanel(Widget parent, String name);
void QuitCB(Widget w, XtPointer c, XtPointer p);

int
main(int ac, char *av[])
{
    Widget pb, panel, box, label;
    Widget wlist[2];
    Colormap cmap;
    Arg mbox_args[] = {
	{ XmNdialogType, XmDIALOG_TEMPLATE },
	{ XmNokLabelString, (XtArgVal)XmStringCreateLocalized("Quit") },
    };

    top = XtAppInitialize(&app, "Sample", NULL, 0, &ac, av, NULL, NULL, 0);

#ifdef SHELL
    cmap = XCreateColormap(XtDisplay(top), RootWindowOfScreen(XtScreen(top)),
			   DefaultVisualOfScreen(XtScreen(top)), AllocNone);
    XtVaSetValues(top, XmNcolormap, cmap, NULL);
#endif

    box = XmCreateMessageBox(top, "message_box",
			     mbox_args, XtNumber(mbox_args));
    XtManageChild(box);
    XtAddCallback(box, XmNokCallback,
		  (XtCallbackProc)QuitCB, NULL);

    panel = CreateColorPanel(box, "panel");
    XtManageChild(panel);

    XtRealizeWidget(top);
    XtAppMainLoop(app);
}

void
QuitCB(Widget w, XtPointer c, XtPointer p)
{
    exit(0);
}

/* ポインタ入出自の動作を記述 */
char *action_table = "<Enter>: SetCm(0)\n <Leave>: SetCm(1)\n";
/* アクションと関数を結び付ける */
void SetCM(Widget w, XEvent *ev, String *args, Cardinal *num);
static XtActionsRec actions[] =
{
{ "SetCm", SetCM },
};

void ExposeCB(Widget w, Pixmap px, XmDrawingAreaCallbackStruct *s);

#define CELL_SIZE 32
Pixmap CreatePanelPixmap(Widget w);

Widget
CreateColorPanel(Widget parent, String name)
{
    Widget sw, da;
    Arg sw_args[] = {
	{ XmNwidth, 8 * CELL_SIZE },
	{ XmNheight, 8 * CELL_SIZE },
	{ XmNscrollingPolicy, XmAUTOMATIC },
    };
    Arg da_args[] = {
	{ XmNwidth, 16 * CELL_SIZE },
	{ XmNheight, 16 * CELL_SIZE },
    };
    Colormap cmap;
    Pixmap panel;

    sw = XmCreateScrolledWindow(parent, name, sw_args, XtNumber(sw_args));
    da = XmCreateDrawingArea(sw, "draw_area", da_args, XtNumber(da_args));
    XtManageChild(da);
#ifndef SHELL
    cmap = XCreateColormap(XtDisplay(da), RootWindowOfScreen(XtScreen(da)),
			   DefaultVisualOfScreen(XtScreen(da)), AllocNone);
    XtVaSetValues(da, XmNcolormap, cmap, NULL);

    /* アクションの登録 */
    XtAppAddActions(app, actions, XtNumber(actions));
    /* 動作をDrawingAreaに仕込む */
    XtOverrideTranslations(da, XtParseTranslationTable(action_table));
#endif
    panel = CreatePanelPixmap(da);
    XtAddCallback(da, XmNexposeCallback,
		  (XtCallbackProc)ExposeCB, (XtPointer)panel);

    return sw;
}

void
SetCM(Widget w, XEvent *ev, String *args, Cardinal *num)
{
    Widget wlist[2];

    if (args[0][0] == '0') {
	/* DrawingAreaのカラーマップを優先 */
	wlist[0] = w;
	wlist[1] = top;
    } else {
	/* デフォルトのカラーマップを優先 */
	wlist[0] = top;
	wlist[1] = w;
    }
    XtSetWMColormapWindows(top, wlist, 2);
}

void
ExposeCB(Widget w, Pixmap pixmap, XmDrawingAreaCallbackStruct *s)
{
    XExposeEvent *ev = &s->event->xexpose;
    static GC gc = NULL;

    if (!gc) gc = XtGetGC(w, 0, NULL);
    XCopyArea(ev->display, pixmap, s->window, gc,
	      ev->x, ev->y,
	      ev->width, ev->height,
	      ev->x, ev->y);
}

Pixmap
CreatePanelPixmap(Widget w)
{
    Display *dpy = XtDisplay(w);
    Window root = RootWindowOfScreen(XtScreen(w));
    Colormap cmap;
    XColor color;
    int i, j, maxcols, depth;
    Pixmap pixmap;
    Pixel pixels[256];
    GC gc;

    XtVaGetValues(w,
		  XmNcolormap, &cmap,
		  XmNdepth, &depth,
		  NULL);

    for (i = 0; i < 256; i++) {
	color.red = (i & 0x07) << 13;
	color.green = (i >> 3 & 0x07) << 13;
	color.blue = (i >> 6 & 0x07) << 14;
	if (!XAllocColor(dpy, cmap, &color))
	    break;
	pixels[i] = color.pixel;
    }
    maxcols = i;
    pixmap = XCreatePixmap(dpy, root, CELL_SIZE * 16, CELL_SIZE * 16, depth);
    gc = XCreateGC(dpy, pixmap, 0, NULL);
    for (j = 0; j < 16; j++) {
	for (i = 0; i < 16; i++) {
	    XSetForeground(dpy, gc, pixels[(j * 16 + i) % maxcols]);
	    XFillRectangle(dpy, pixmap, gc,
			   i * CELL_SIZE, j * CELL_SIZE,
			   CELL_SIZE, CELL_SIZE);
	}
    }
    return pixmap;
}
