#ifndef lint
#ifdef sccs
static char     sccsid[] = "@(#)wizzy.c 1.1 91/02/28";
#endif
#endif

#include <xview/frame.h>
#include <xview/panel.h>
#include <xview/wizzy.h>

#define WIZZY_CAN_ACCEPT_KBD_FOCUS

#define WIZZY_PRIVATE(item) \
	XV_PRIVATE(Wizzy_info, Xv_panel_wizzy, item)

/* Item specific definitions */
#define INITIAL_OFFSET	10
#define BLOCK_WIDTH	16
#define BLOCK_HEIGHT	12

/* XView functions */
Pkg_private int wizzy_init();
Pkg_private Xv_opaque wizzy_set_avlist();
Pkg_private Xv_opaque wizzy_get_attr();
Pkg_private int wizzy_destroy();

/* Panel Item Operations
 *
 * Declare all wizzy item handler procedures used in the Ops Vector Table
 */
static void	wizzy_begin_preview();
static void	wizzy_update_preview();
static void	wizzy_cancel_preview();
static void	wizzy_accept_preview();
static void	wizzy_accept_menu();
static void	wizzy_accept_key();
static void	wizzy_paint();
static void	wizzy_remove();
static void	wizzy_restore();
static void	wizzy_layout();
#ifdef WIZZY_CAN_ACCEPT_KBD_FOCUS
static void	wizzy_accept_kbd_focus();
static void	wizzy_yield_kbd_focus();
#endif /* WIZZY_CAN_ACCEPT_KBD_FOCUS */

/*
 * Panel Operations Vector Table for this item.
 *
 * If any of the operations do not apply, then use NULL as the handler address.
 */
static Panel_ops ops = {
    panel_default_handle_event,		/* handle_event() */
    wizzy_begin_preview,		/* begin_preview() */
    wizzy_update_preview,		/* update_preview() */
    wizzy_cancel_preview,		/* cancel_preview() */
    wizzy_accept_preview,		/* accept_preview() */
    wizzy_accept_menu,			/* accept_menu() */
    wizzy_accept_key,			/* accept_key() */
    wizzy_clear,			/* clear() */
    wizzy_paint,			/* paint() */
    wizzy_resize,			/* resize() */
    wizzy_remove,			/* remove() */
    wizzy_restore,			/* restore() */
    wizzy_layout,			/* layout() */
#ifdef WIZZY_CAN_ACCEPT_KBD_FOCUS
    wizzy_accept_kbd_focus,		/* accept_kbd_focus() */
    wizzy_yield_kbd_focus,		/* yield_kbd_focus() */
#else
    NULL,				/* accept_kbd_focus() */
    NULL,				/* yield_kbd_focus() */
#endif /* WIZZY_CAN_ACCEPT_KBD_FOCUS */
    NULL				/* extension: reserved for future use */
};

typedef struct wizzy_info {
    Panel_item      public_self;/* back pointer to object */
    /*
     * Wizzy private data goes here.
     * *** All references to these entries is for illustration
     * *** purposes only.  They are to be replaced with your
     * *** item's private data requirements.
     */
    Rect	    block;	/* Some rectangle within the item */
    GC		    gc;		/* Graphics Context */
    int		    offset;	/* The block's offset */
    Panel	    panel;	/* Panel this item is owned by */
#ifdef WIZZY_CAN_ACCEPT_KBD_FOCUS
    int		    has_kbd_focus; /* TRUE or FALSE */
#endif /* WIZZY_CAN_ACCEPT_KBD_FOCUS */
} Wizzy_info;



/* ========================================================================= */

/* -------------------- XView Functions  -------------------- */
Pkg_private int
wizzy_init(panel, item, avlist)
    Panel           panel;
    Panel_item      item;
    Attr_avlist     avlist;
{
    Xv_panel_wizzy *item_object = (Xv_panel_wizzy *) item;
    Display	   *display;
    Wizzy_info     *dp;
    XGCValues	    values;
    XID		    xid;

    dp = xv_alloc(Wizzy_info);

    item_object->private_data = (Xv_opaque) dp;
    dp->public_self = item;

    /*
     * Initialize non-zero private data
     */
    display = (Display *) XV_DISPLAY_FROM_WINDOW(panel);
    xid = (XID) xv_get(panel, XV_XID);
    values.foreground = BlackPixel(display, 0);
    dp->gc = XCreateGC(display, xid, GCForeground, &values);
    dp->offset = INITIAL_OFFSET;
    dp->panel = panel;

    /*
     * Process avlist for create-only attributes.
     */
    for ( ; *avlist; avlist = attr_next(avlist)) {
        switch ((int) avlist[0]) {
	  /* case <create_only_attr>: */
	  default:
	    break;
	}
    }

    xv_set(item,
	   PANEL_OPS_VECTOR, &ops,
#ifdef WIZZY_CAN_ACCEPT_KBD_FOCUS
	   PANEL_ACCEPT_KEYSTROKE, TRUE,
#endif /* WIZZY_CAN_ACCEPT_KBD_FOCUS */
	   0);

    return XV_OK;
}


Pkg_private Xv_opaque
wizzy_set_avlist(item, avlist)
    Panel_item	    item;
    Attr_avlist	    avlist;
{
    Wizzy_info	   *dp = WIZZY_PRIVATE(item);
    Xv_opaque       result;
    Rect	    value_rect;

    if (*avlist != XV_END_CREATE) {
	/* Call generic item set code to handle layout attributes.
	 * Prevent panel_redisplay_item from being called in item_set_avlist.
	 */
	xv_set(dp->panel, PANEL_NO_REDISPLAY_ITEM, TRUE, 0);
        result = xv_super_set_avlist(item, &xv_panel_wizzy_pkg, avlist);
	xv_set(dp->panel, PANEL_NO_REDISPLAY_ITEM, FALSE, 0);
        if (result != XV_OK)
            return result;
    }
 
    /* Parse Attribute-Value List.  Complete initialization upon
     * receipt of XV_END_CREATE.
     */
    for ( ; *avlist; avlist = attr_next(avlist)) {
        switch ((int) avlist[0]) {
	  case WIZZY_OFFSET:
	    dp->offset = (int) avlist[1];
	    break;
	  case XV_END_CREATE:
	    value_rect = *(Rect *) xv_get(item, PANEL_ITEM_VALUE_RECT);
	    rect_construct(&dp->block,
			   value_rect.r_left + dp->offset,
			   value_rect.r_top,
			   BLOCK_HEIGHT, BLOCK_WIDTH);
	    value_rect = rect_bounding(&value_rect, &dp->block);
	    /* Note: Setting the value rect will cause the item rect to be
	     * recalculated as the enclosing rect containing both the label
	     * and value rects.
	     */
	    xv_set(item,
	    	   PANEL_ITEM_VALUE_RECT, &value_rect,
		   0);
	    break;
	  default:
	    break;
	}
    }
    return XV_OK;	/* return XV_ERROR if something went wrong... */
}


/*ARGSUSED*/
Pkg_private Xv_opaque
wizzy_get_attr(item, status, which_attr, avlist)
    Panel_item      item;
    int            *status;	/* set to XV_ERROR if something goes wrong */
    register Attr_attribute which_attr;
    va_list         avlist;
{
    Wizzy_info	   *dp = WIZZY_PRIVATE(item);

    switch (which_attr) {
      case WIZZY_OFFSET:
	return (Xv_opaque) dp->offset;
      default:
	*status = XV_ERROR;
	return (Xv_opaque) 0;
    }
}
      

/*ARGSUSED*/
Pkg_private int
wizzy_destroy(item, status)
    Panel_item      item;
    Destroy_status  status;
{
    Wizzy_info	   *dp = WIZZY_PRIVATE(item);

    if ((status == DESTROY_CHECKING) || (status == DESTROY_SAVE_YOURSELF))
	return XV_OK;
#ifdef WIZZY_CAN_ACCEPT_KBD_FOCUS
    wizzy_remove(item);
#endif /* WIZZY_CAN_ACCEPT_KBD_FOCUS */
    free(dp);
    return XV_OK;
}



/* --------------------  Panel Item Operations  -------------------- */
/*ARGSUSED*/
static void
wizzy_begin_preview(item, event)
    Panel_item	    item;
    Event          *event;
{
    /*
     * SELECT-down has occurred over the item.
     * Highlight the item to show the active feedback,
     * but do not take any action yet.
     */
}


/*ARGSUSED*/
static void
wizzy_update_preview(item, event)
    Panel_item      item;
    Event          *event;
{
    /*
     * The pointer as been dragged within the item after
     * beginning a preview.  Adjust the highlighting to
     * reflect the new position of the pointer, and update
     * appropriate private data.
     */
}


/*ARGSUSED*/
static void
wizzy_cancel_preview(item, event)
    Panel_item      item;
    Event          *event;
{
    /*
     * The pointer as been dragged out of the item after
     * beginning a preview.  Remove the active feedback
     * (i.e., unhighlight) and clean up any private data.
     */
}


/*ARGSUSED*/
static void
wizzy_accept_preview(item, event)
    Panel_item      item;
    Event          *event;
{
    /*
     * The SELECT button has been released over the item.
     * Remove the active feedback (i.e., unhighlight),
     * paint the busy feedback,
     * perform the action associated with the item,
     * and then remove the busy feedback.
     */
}


/*ARGSUSED*/
static void
wizzy_accept_menu(item, event)
    Panel_item      item;
    Event          *event;
{
    /*
     * The MENU button has been depressed over the item.
     * Show the menu attached to the item, if any.
     */
}


/*ARGSUSED*/
static void
wizzy_accept_key(item, event)
    Panel_item      item;
    Event          *event;
{
    /*
     * A keyboard event has occurred.  Process the key,
     * and update the display.
     */
}


static void
wizzy_clear(item_public)
    Panel_item	    item_public;
{
    /*
     * Clear the item rectangle.  Update any private data as needed.
     */
    panel_default_clear_item(item_public);
}


/*ARGSUSED*/
static void
wizzy_paint(item)
    Panel_item      item;
{
    Display	   *display;
    Wizzy_info	   *dp = WIZZY_PRIVATE(item);
    Panel_paint_window *ppw;	/* ptr to Panel_paint_window structure */
    Xv_Window	    pw;		/* paint window */
    XID		    xid;

    /*
     * Do everything necessary to paint the entire item.
     * Don't go outside of the PANEL_ITEM_RECT, the rectangle describing the
     * boundaries of the item.
     */

    /* Paint the label */
    panel_paint_label(item);

    /* Paint the value.
     * In this wizzy example, we paint something into dp->block.
     */
    display = (Display *) XV_DISPLAY_FROM_WINDOW(dp->panel);
    for (ppw = (Panel_paint_window *)
	     xv_get(dp->panel, PANEL_FIRST_PAINT_WINDOW);
	 ppw;
	 ppw = ppw->next) {
	pw = ppw->pw;	/* pw = the actual window to paint in */
	xid = (XID) xv_get(pw, XV_XID);
	XFillRectangle(display, xid, dp->gc, dp->block.r_left, dp->block.r_top,
		       dp->block.r_width, dp->block.r_height);
    }
}


/*ARGSUSED*/
static void
wizzy_resize(item)
    Panel_item	    item;
{
    /*
     * The panel has been resized.  Recalculate any extend-to-edge dimensions.
     */
}


/*ARGSUSED*/
static void
wizzy_remove(item)
    Panel_item	    item;
{
    /*
     * The item has been made hidden via xv_set(item, XV_SHOW, FALSE, avlist).
     */
#ifdef WIZZY_CAN_ACCEPT_KBD_FOCUS
    Wizzy_info	   *dp = WIZZY_PRIVATE(item);
    Panel_status   *panel_status;

    /*
     * Only reassign the keyboard focus to another item if the panel isn't
     * being destroyed.
     */
    panel_status = (Panel_status *) xv_get(dp->panel, PANEL_STATUS);
    if (!panel_status->destroying &&
	xv_get(dp->panel, PANEL_CARET_ITEM) == item)
	(void) panel_advance_caret(dp->panel);
#endif /* WIZZY_CAN_ACCEPT_KBD_FOCUS */
}


/*ARGSUSED*/
static void
wizzy_restore(item)
    Panel_item	    item;
{
    /*
     * The item has been made visible via xv_set(item, XV_SHOW, TRUE, avlist).
     */
#ifdef WIZZY_CAN_ACCEPT_KBD_FOCUS
    Wizzy_info	   *dp = WIZZY_PRIVATE(item);

    /* If no item has the keyboard focus, then give this item the focus */
    if (!xv_get(dp->panel, PANEL_CARET_ITEM))
        xv_set(dp->panel, PANEL_CARET_ITEM, item, 0);
#endif /* WIZZY_CAN_ACCEPT_KBD_FOCUS */
}


/*ARGSUSED*/
static void
wizzy_layout(item, deltas)
    Panel_item	    item;
    Rect	   *deltas;
{
    /*
     * The item has been moved.  Adjust the item coordinates.
     */
    Wizzy_info	   *dp = WIZZY_PRIVATE(item);

    dp->block.r_left += deltas->r_left;
    dp->block.r_top += deltas->r_top;
}


#ifdef WIZZY_CAN_ACCEPT_KBD_FOCUS
/*ARGSUSED*/
static void
wizzy_accept_kbd_focus(item)
    Panel_item	    item;
{
    /*
     * The keyboard focus has been set to this item.
     * Change the keyboard focus feedback to active, and
     * update private data as necessary.
     */
    Wizzy_info	   *dp = WIZZY_PRIVATE(item);
    Frame	    frame;
    int		    x;
    int		    y;

    dp->has_kbd_focus = TRUE;
    frame = xv_get(dp->panel, WIN_FRAME);
    if (xv_get(dp->panel, PANEL_LAYOUT) == PANEL_HORIZONTAL) {
	xv_set(frame, FRAME_FOCUS_DIRECTION, FRAME_FOCUS_UP, 0);
	x = dp->block.r_left +
	    (dp->block.r_width - FRAME_FOCUS_UP_WIDTH)/2;
	y = dp->block.r_top + dp->block.r_height - FRAME_FOCUS_UP_HEIGHT/2;
    } else {
	xv_set(frame, FRAME_FOCUS_DIRECTION, FRAME_FOCUS_RIGHT, 0);
	x = dp->block.r_left - FRAME_FOCUS_RIGHT_WIDTH/2;
	y = dp->block.r_top +
	    (dp->block.r_height - FRAME_FOCUS_RIGHT_HEIGHT)/2;
    }
    if (x < 0)
	x = 0;
    if (y < 0)
	y = 0;
    panel_show_focus_win(item, frame, x, y);
}


/*ARGSUSED*/
static void
wizzy_yield_kbd_focus(item)
    Panel_item	    item;
{
    /*
     * The keyboard focus has been removed from this item.
     * Change the keyboard focus feedback to inactive, and
     * update private data as necessary.
     */
    Wizzy_info	   *dp = WIZZY_PRIVATE(item);
    Xv_Window	    focus_win;
    Frame	    frame;

    dp->has_kbd_focus = FALSE;
    frame = xv_get(dp->panel, WIN_FRAME);
    focus_win = xv_get(frame, FRAME_FOCUS_WIN);
    xv_set(focus_win, XV_SHOW, FALSE, 0);
}
#endif /* WIZZY_CAN_ACCEPT_KBD_FOCUS */

