/* A compact, interactive gallery of Motif controls. */
#include <stdio.h>
#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/Label.h>
#include <Xm/PushB.h>
#include <Xm/ToggleB.h>
#include <Xm/RowColumn.h>
#include <Xm/TextF.h>
#include <Xm/List.h>
#include <Xm/Scale.h>
#include <Xm/Separator.h>
#include <Xm/CascadeB.h>
#include <Xm/MessageB.h>
#include <Xm/Protocols.h>

static Widget status, entry, dialog;

static void set_label(Widget w, const char *text)
{
    XmString s = XmStringCreateLocalized((char *)text);
    XtVaSetValues(w, XmNlabelString, s, NULL);
    XmStringFree(s);
}

static Widget labelled(Widget parent, const char *name, WidgetClass class,
                       const char *text)
{
    Widget w = XtVaCreateManagedWidget(name, class, parent, NULL);
    set_label(w, text);
    return w;
}

static void quit(Widget w, XtPointer client, XtPointer call)
{
    (void)client; (void)call;
    XtAppSetExitFlag(XtWidgetToApplicationContext(w));
}

static void apply(Widget w, XtPointer client, XtPointer call)
{
    char message[256];
    char *text = XmTextFieldGetString(entry);
    (void)w; (void)client; (void)call;
    snprintf(message, sizeof message, "Applied: %s", text);
    set_label(status, message);
    XtFree(text);
}

static void toggle(Widget w, XtPointer client, XtPointer call)
{
    XmToggleButtonCallbackStruct *state = call;
    (void)w; (void)client;
    set_label(status, state->set ? "Preview enabled" : "Preview disabled");
}

static void selected(Widget w, XtPointer client, XtPointer call)
{
    XmListCallbackStruct *selection = call;
    char *text = NULL;
    (void)w; (void)client;
    if (XmStringGetLtoR(selection->item, XmFONTLIST_DEFAULT_TAG, &text)) {
        XmTextFieldSetString(entry, text);
        set_label(status, "Selection copied to the text field");
        XtFree(text);
    }
}

static void scaled(Widget w, XtPointer client, XtPointer call)
{
    XmScaleCallbackStruct *value = call;
    char text[64];
    (void)w; (void)client;
    snprintf(text, sizeof text, "Scale value: %d", value->value);
    set_label(status, text);
}

static void show_dialog(Widget w, XtPointer client, XtPointer call)
{
    (void)w; (void)client; (void)call;
    XtManageChild(dialog);
}

int main(int argc, char **argv)
{
    XtAppContext app;
    String fallback[] = {
        "*title: Motif widget gallery",
        "*XmLabel.fontList: fixed", "*XmTextField.fontList: fixed",
        "*XmList.fontList: fixed", "*XmPushButton.fontList: fixed",
        "*XmToggleButton.fontList: fixed", "*XmCascadeButton.fontList: fixed",
        "*background: #d4d0c8", "*foreground: #202020",
        "*panel.marginWidth: 16", "*panel.marginHeight: 16",
        "*panel.spacing: 12", "*panel.width: 440",
        "*actions.orientation: horizontal", "*actions.spacing: 10",
        "*status.alignment: ALIGNMENT_BEGINNING", NULL
    };
    XtSetLanguageProc(NULL, NULL, NULL);
    Widget shell = XtVaAppInitialize(&app, "WidgetGallery", NULL, 0,
                                    &argc, argv, fallback, NULL);
    Widget panel = XtVaCreateManagedWidget("panel", xmRowColumnWidgetClass,
                                          shell, NULL);
    Widget menu = XmCreateMenuBar(panel, "menubar", NULL, 0);
    Widget file = XmCreatePulldownMenu(menu, "fileMenu", NULL, 0);
    Widget cascade = labelled(menu, "file", xmCascadeButtonWidgetClass, "File");
    XtVaSetValues(cascade, XmNsubMenuId, file, NULL);
    Widget exit = labelled(file, "quit", xmPushButtonWidgetClass, "Quit");
    XtAddCallback(exit, XmNactivateCallback, quit, NULL);
    XtManageChild(menu);
    labelled(panel, "heading", xmLabelWidgetClass, "Text, choices and actions");
    entry = XtVaCreateManagedWidget("entry", xmTextFieldWidgetClass, panel,
                                    XmNvalue, "Hello, Motif", XmNcolumns, 32, NULL);
    Widget actions = XtVaCreateManagedWidget("actions", xmRowColumnWidgetClass,
                                            panel, NULL);
    Widget button = labelled(actions, "apply", xmPushButtonWidgetClass, "Apply");
    XtAddCallback(button, XmNactivateCallback, apply, NULL);
    button = labelled(actions, "details", xmPushButtonWidgetClass, "Details...");
    XtAddCallback(button, XmNactivateCallback, show_dialog, NULL);
    Widget check = labelled(actions, "preview", xmToggleButtonWidgetClass,
                             "Preview");
    XtAddCallback(check, XmNvalueChangedCallback, toggle, NULL);
    XtVaCreateManagedWidget("separator", xmSeparatorWidgetClass, panel, NULL);
    labelled(panel, "listLabel", xmLabelWidgetClass, "Choose a toolkit:");
    Widget list = XmCreateScrolledList(panel, "toolkits", NULL, 0);
    XtVaSetValues(list, XmNvisibleItemCount, 3,
                  XmNselectionPolicy, XmBROWSE_SELECT, NULL);
    const char *items[] = {"Motif", "Athena", "Xmt"};
    for (unsigned i = 0; i < sizeof items / sizeof items[0]; ++i) {
        XmString s = XmStringCreateLocalized((char *)items[i]);
        XmListAddItem(list, s, 0);
        XmStringFree(s);
    }
    XtAddCallback(list, XmNbrowseSelectionCallback, selected, NULL);
    XtManageChild(list);
    XmListSelectPos(list, 1, False);
    Widget scale = XtVaCreateManagedWidget("scale", xmScaleWidgetClass, panel,
        XmNorientation, XmHORIZONTAL, XmNminimum, 0, XmNmaximum, 100,
        XmNvalue, 40, XmNshowValue, True, NULL);
    XtAddCallback(scale, XmNvalueChangedCallback, scaled, NULL);
    status = labelled(panel, "status", xmLabelWidgetClass, "Ready");
    dialog = XmCreateInformationDialog(shell, "details", NULL, 0);
    XmString message = XmStringCreateLocalized("A standard Motif information dialog.\nOK closes this window.");
    XtVaSetValues(dialog, XmNmessageString, message, NULL);
    XmStringFree(message);
    XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_CANCEL_BUTTON));
    XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
    Display *display = XtDisplay(shell);
    XtVaSetValues(shell, XmNdeleteResponse, XmDO_NOTHING, NULL);
    XmAddWMProtocolCallback(shell, XInternAtom(display, "WM_DELETE_WINDOW", False),
                            quit, NULL);
    XtRealizeWidget(shell);
    XtVaSetValues(shell, XmNtitle, "Motif widget gallery", NULL);
    XtAppMainLoop(app);
    XtDestroyWidget(shell);
    XtCloseDisplay(display);
    XtDestroyApplicationContext(app);
    return 0;
}
