/*
 * Do not edit this file.
 * It has been generated by TwiXt
 * from widget description Joystick.xt.
 */

#include <stddef.h>
#include <JoystickP.h>

#include <stdio.h>
#include <X11/Xlib.h>

#define MARGIN          2
#define OFF_IS_HOLLOW   0

static void draw_square(JoystickWidget joy, int filled, Pixel color,
                        int x, int y, int w, int h);

/******************************************************************
 *
 * Joystick Resources
 *
 ******************************************************************/

static XtResource resources[] = {
    {
        .resource_name   = XtNfireColor,
        .resource_class  = XtCForeground,
        .resource_type   = XtRPixel,
        .resource_size   = sizeof(Pixel),
        .resource_offset = XtOffsetOf(JoystickRec, joystick.fire_color),
        .default_type    = XtRString,
        .default_addr    = (XtPointer)("red"),
    },
    {
        .resource_name   = XtNdirectionColor,
        .resource_class  = XtCForeground,
        .resource_type   = XtRPixel,
        .resource_size   = sizeof(Pixel),
        .resource_offset = XtOffsetOf(JoystickRec, joystick.direction_color),
        .default_type    = XtRString,
        .default_addr    = (XtPointer)("green"),
    },
    {
        .resource_name   = XtNoffColor,
        .resource_class  = XtCForeground,
        .resource_type   = XtRPixel,
        .resource_size   = sizeof(Pixel),
        .resource_offset = XtOffsetOf(JoystickRec, joystick.off_color),
        .default_type    = XtRString,
        .default_addr    = (XtPointer)("XtDefaultForeground"),
    },
    { /* From lsb to msb: up down left right fire */
        .resource_name   = XtNenableBits,
        .resource_class  = XtCCardinal,
        .resource_type   = XtRCardinal,
        .resource_size   = sizeof(Cardinal),
        .resource_offset = XtOffsetOf(JoystickRec, joystick.enable_bits),
        .default_type    = XtRImmediate,
        .default_addr    = (XtPointer)(0),
    },

};

struct JoystickClassRec joystickClassRec = {
    { /* Core for Joystick */
        .superclass = (WidgetClass)&simpleClassRec, /* pointer to superclass ClassRec  */
        .class_name = "Joystick", /* widget resource class name       */
        .widget_size = sizeof(JoystickRec), /* size in bytes of widget record   */
        .class_initialize = JoystickClassInitialize, /* class initialization proc        */
        .class_part_initialize = JoystickClassPartInitialize, /* dynamic initialization      */
        .class_inited = FALSE, /* has class been initialized?      */
        .initialize = JoystickInitialize, /* initialize subclass fields       */
        .initialize_hook = 0, /* notify that initialize called    */
        .realize = XtInheritRealize, /* XCreateWindow for widget         */
        .actions = 0, /* widget semantics name to proc map */
        .num_actions = 0, /* number of entries in actions     */
        .resources = resources, /* resources for subclass fields    */
        .num_resources = XtNumber(resources), /* number of entries in resources   */
        .xrm_class = NULLQUARK, /* resource class quarkified        */
        .compress_motion = FALSE, /* compress MotionNotify for widget */
        .compress_exposure = TRUE, /* compress Expose events for widget*/
        .compress_enterleave = FALSE, /* compress enter and leave events  */
        .visible_interest = FALSE, /* select for VisibilityNotify      */
        .destroy = JoystickDestroy, /* free data for subclass pointers  */
        .resize = JoystickResize, /* geom manager changed widget size */
        .expose = JoystickExpose, /* rediplay window                  */
        .set_values = JoystickSetValues, /* set subclass resource values     */
        .set_values_hook = 0, /* notify that set_values called    */
        .set_values_almost = XtInheritSetValuesAlmost, /* set_values got "Almost" geo reply */
        .get_values_hook = 0, /* notify that get_values called    */
        .accept_focus = 0, /* assign input focus to widget     */
        .version = XtVersion, /* version of intrinsics used       */
        .callback_private = 0, /* list of callback offsets         */
        .tm_table = 0, /* state machine                    */
        .query_geometry = XtInheritQueryGeometry, /* return preferred geometry        */
        .display_accelerator = XtInheritDisplayAccelerator, /* display your accelerator         */
        .extension = 0, /* pointer to extension record      */
    }, /* Core */
    { /* Simple for Joystick */
        .change_sensitive = XtInheritChangeSensitive, 
        .extension = 0, 
    }, /* Simple */
    { /* Joystick for Joystick */
    }, /* Joystick */

};

/*
 * Declare this as WidgetClass instead of the "more real" types
 *
 *     JoystickClassRec * or CoreClassRec *,
 *
 * because Xt functions such as XtCreateWidget() take an argument of that type.
 *
 * The definition of WidgetClass in <X11/Core.h> is
 *
 *     typedef struct _WidgetClassRec *CoreWidgetClass;
 *
 * where Widget is a strange alias of Core.
 */
WidgetClass joystickWidgetClass = (WidgetClass)&joystickClassRec.core_class;

/* Definitions for class functions */
void JoystickClassInitialize(void)
{

}

void JoystickClassPartInitialize(WidgetClass class)
{

}

void JoystickInitialize(Widget request, Widget new, ArgList args,
        Cardinal *num_args )
{
    JoystickWidget joy = (JoystickWidget)new;
    XGCValues values;

    joy->joystick.led_xsize = 4;    /* arbitrary value */
    joy->joystick.led_ysize = 4;    /* arbitrary value */

    values.foreground = joy->joystick.direction_color;
    values.background = joy->core.background_pixel;
    values.line_width = 0;

    /* Below are defaults but specify them anyway */
    values.line_style = LineSolid;
    values.join_style = JoinMiter;
    values.fill_style = FillSolid;
    values.fill_rule  = EvenOddRule;
    values.clip_mask  = None;
    values.plane_mask  = ~0;
    values.function = GXcopy;

    /*
     * Create a Graphics Context with the above attributes.
     * We're going to change the foreground colour.
     * Pretty much all the other attributes, we don't use, so
     * we don't care about them if they change behind our back.
     */
    joy->joystick.gc = XtAllocateGC(new, 0,
            GCForeground | GCBackground | GCLineWidth |
            GCLineStyle | GCJoinStyle | GCFillStyle |
            GCFillRule | GCClipMask | GCPlaneMask | GCFunction,
            &values,
            GCForeground,
            GCFont | GCSubwindowMode | GCGraphicsExposures |
            GCTile | GCStipple | GCTileStipXOrigin |
            GCTileStipYOrigin | GCClipXOrigin |
            GCClipYOrigin | GCDashOffset | GCDashList |
            GCArcMode);

    JoystickResize(new);
}

void JoystickDestroy(Widget widget)
{
    JoystickWidget joy = (JoystickWidget)widget;
    XtReleaseGC(widget, joy->joystick.gc);
}

void JoystickResize(Widget widget)
{
    /* Code for JoystickResize: always comply. */
    JoystickWidget joy = (JoystickWidget)widget;

    joy->joystick.led_xsize = (joy->core.width - 2 * MARGIN) / 3;
    joy->joystick.led_ysize = (joy->core.height - 2 * MARGIN) / 3;
}

void JoystickExpose(Widget widget, XEvent* event, Region region)
{
    /* Code for JoystickExpose */
    JoystickWidget joy = (JoystickWidget)widget;

    /*
     * Call superclass Expose function;
     * not needed but shown as an example how to inherit.
     *
    joystickClassRec.core_class.superclass->core_class.expose(widget, event, region);
     */

    int bits = joy->joystick.enable_bits;
    int xsize = joy->joystick.led_xsize;
    int ysize = joy->joystick.led_ysize;

    /*
     * If this is not the last expose event in a sequence,
     * simply ignore it. We can do this because we repaint
     * everything every time.
     */
    if (event->type == Expose) {
        XExposeEvent *ee = (XExposeEvent *)event;

        if (ee->count != 0) {
            return;
        }
    }

    /* up */
    draw_square(joy, bits & 1, joy->joystick.direction_color,
            MARGIN + xsize, 0, xsize, ysize);

    /* down */
    draw_square(joy, bits & 2, joy->joystick.direction_color,
            MARGIN + xsize, 2*MARGIN + 2*ysize, xsize, ysize);

    /* left */
    draw_square(joy, bits & 4, joy->joystick.direction_color,
            0, MARGIN + ysize, xsize, ysize);

    /* right */
    draw_square(joy, bits & 8, joy->joystick.direction_color,
            2*MARGIN + 2*xsize, MARGIN + ysize, xsize, ysize);

    /* fire, middle */
    draw_square(joy, bits & 16, joy->joystick.fire_color,
            MARGIN + xsize, MARGIN + ysize, xsize, ysize);
}

Boolean JoystickSetValues(Widget old, Widget request, Widget new, ArgList args,
        Cardinal *num_args )
{
    JoystickWidget curjoy = (JoystickWidget)old;
    JoystickWidget newjoy = (JoystickWidget)new;
    Boolean redisplay = False;

    if (curjoy->joystick.fire_color != newjoy->joystick.fire_color ||
        curjoy->joystick.direction_color != newjoy->joystick.direction_color ||
        curjoy->joystick.off_color != newjoy->joystick.off_color) {
        /*fprintf(stderr, "JoystickWidget: colour changed\n");*/
        redisplay = True;
    }

    if (!redisplay &&
        curjoy->joystick.enable_bits != newjoy->joystick.enable_bits) {
        /*fprintf(stderr, "JoystickWidget: bits changed\n");*/
#if OFF_IS_HOLLOW
        /*
         * We could be clever here, and apply XClearArea(..., True)
         * to only the modified area, in which case we don't need to set
         * redisplay to True, which will repaint everything.
         */
        redisplay = True;
#else
        /*
         * Just force an Expose event without actually clearing
         * the background (just 1 pixel that is not painted anyway).
         * This helps to reduce flicker.
         */
        XClearArea(XtDisplay(new), XtWindow(new), 0, 0, 1, 1, True);
#endif

    }

    return redisplay;
}



static void draw_square(JoystickWidget joy, int on, Pixel color,
                        int x, int y, int w, int h)
{
    GC gc = joy->joystick.gc;

    /*fprintf(stderr, "draw_square: on=%d, x=%d, y=%d, w=%d, h=%d\n",
     * on, x, y, w, h);*/

#if OFF_IS_HOLLOW
    /*
     * Draw "off" indicators as hollow, coloured boxes.
     * Draw "on"  indicators as filled, coloured boxes.
     */
    XSetForeground(XtDisplay(joy), gc, color);

    if (on) {
        XFillRectangle(XtDisplay(joy), XtWindow(joy),
                       gc, x, y, w, h);
    } else {
        XDrawRectangle(XtDisplay(joy), XtWindow(joy),
                       gc, x, y, w - 1, h - 1);
    }
#else
    /*
     * Draw "off" indicators as filled, black boxes.
     * Draw "on"  indicators as filled, coloured boxes.
     */
    if (on) {
        XSetForeground(XtDisplay(joy), gc, color);
    } else {
        XSetForeground(XtDisplay(joy), gc, joy->joystick.off_color);
    }
    XFillRectangle(XtDisplay(joy), XtWindow(joy),
                   gc, x, y, w, h);
#endif
}
