/* X11choice - choice items for X11 dialogs                            */
/* XLISP-STAT 2.1 Copyright (c) 1990, by Luke Tierney                  */
/* Additions to Xlisp 2.1, Copyright (c) 1989 by David Michael Betz    */
/* You may give out copies of this software; for conditions see the    */
/* file COPYING included with this distribution.                       */
 
/***********************************************************************/
/**                                                                   **/
/**                    General Includes and Definitions               **/
/**                                                                   **/
/***********************************************************************/

#include "dialogs.h"

extern Display *StX11Display();
extern Point DialogStringSize();
extern LVAL StX11ItemObject();
extern char *checkstring();
extern LVAL s_window_id;

typedef struct {
  unsigned long fore, back;
} ColorPair;

/* layout defines */
# define CHOICE_PAD 20
# define CHOICE_MARK_HEIGHT 16
# define CHOICE_LEAD 5

/***********************************************************************/
/**                                                                   **/
/**                        Global Variables                           **/
/**                                                                   **/
/***********************************************************************/

/* configuration parameters - should be set using the defaults database */
extern XFontStruct *DialogFont;
extern unsigned long DialogBorderColor;
extern ColorPair DialogC;
extern unsigned int dialog_border_width;
extern int min_choice_height;

extern GC DialogGC, DialogRGC;

extern XContext ObjectContext;

extern Pixmap ChoiceOffPM, ChoiceOnPM;

/***********************************************************************/
/**                                                                   **/
/**                         Choice Items                              **/
/**                                                                   **/
/***********************************************************************/

static VOID draw_choice(dpy, win, item)
     Display *dpy;
     Window win;
     LVAL item;
{
  LVAL text, val;
  char *text_item;
  int x, y, len, ascent, descent, value, i, step;
  Pixmap mark;

  ascent = DialogFont->max_bounds.ascent;
  descent = DialogFont->max_bounds.descent;

  text = slot_value(item, s_text);
  val = slot_value(item, s_value);
  value = (fixp(val)) ? getfixnum(val) : 0;
  x = CHOICE_PAD;
  step = descent + max(CHOICE_MARK_HEIGHT, ascent) + CHOICE_LEAD;

  for (i = 0, y = max(ascent, CHOICE_MARK_HEIGHT);
       consp(text);
       i++, y += step, text = cdr(text)) {
    mark = (value == i) ? ChoiceOnPM : ChoiceOffPM;
    text_item = checkstring(car(text));
    XCopyPlane(dpy, mark, win, DialogGC, 
	       0, 0, CHOICE_MARK_HEIGHT, CHOICE_MARK_HEIGHT,
	       0, y - CHOICE_MARK_HEIGHT, 1);
    len = strlen(text_item);
    XDrawString(dpy, win, DialogGC, x, y, text_item, len);
  }
}
  
static LVAL choice_handler(report, modal)
     XEvent report;
     int modal;
{
  Display *dpy = StX11Display();
  Window win;
  LVAL item, result = NIL;
  int i, item_height, ascent, descent;

  ascent = DialogFont->max_bounds.ascent;
  descent = DialogFont->max_bounds.descent;

  win = report.xany.window;
  item = StX11ItemObject(dpy, win);
  if (item != NIL) {
    switch (report.type) {
    case Expose:
      draw_choice(dpy, win, item);
      break;
    case ButtonPress:
      item_height = descent + max(CHOICE_MARK_HEIGHT, ascent) + CHOICE_LEAD;
      i = report.xbutton.y / item_height;
      DialogChoiceItemValue(item, TRUE, i);
      if (! modal) send_message(item, sk_do_action);
      break;
    case ButtonRelease:
      break;
    default: 
      break;
    }
  }
  return(result);
}

VOID InstallChoiceItem(win, item)
     Window win;
     LVAL item;
{
  Display *dpy = StX11Display();
  Point loc, size;
  Window choice;

  loc = ListToPoint(slot_value(item, s_location));
  size = ListToPoint(slot_value(item, s_size));
  choice = XCreateSimpleWindow(dpy, win, loc.h, loc.v, size.h, size.v,
			       0, DialogBorderColor, DialogC.back);
  XSelectInput(dpy, choice, 
	       ExposureMask | ButtonPressMask | ButtonReleaseMask);

  set_slot_value(item, s_window_id, cvfixnum((FIXTYPE) choice));
  if (! fixp(slot_value(item, s_value)))
    set_slot_value(item, s_value, cvfixnum((FIXTYPE) 0));

  install_dialog_item_handler(dpy, choice, choice_handler, item);
  if (XSaveContext(dpy, choice, ObjectContext, (caddr_t) item) != 0)
    xlfail("could not install object in window");
}

VOID DeleteChoiceItem(win, item)
     Window win;
     LVAL item;
{
  Display *dpy = StX11Display();
  Window choice;

  choice = (Window) getfixnum(slot_value(item, s_window_id));

  delete_dialog_item_handler(dpy, choice);
  if (XDeleteContext(dpy, choice, ObjectContext) != 0)
    xlfail("could not delete object context");
  set_slot_value(item, s_window_id, NIL);
}

VOID DialogChoiceGetDefaultSize(item, width, height)
     LVAL item;
     int *width, *height;
{
  Point i_sz, s_sz;
  LVAL text = slot_value(item, s_text);

  for (i_sz.h = 0, i_sz.v = 0; consp(text); text = cdr(text)) {
    s_sz = DialogStringSize(getstring(car(text)));
    if (i_sz.v != 0) i_sz.v += CHOICE_LEAD; /* only add lead between lines */
    i_sz.v += max(s_sz.v, min_choice_height);
    i_sz.h = max(i_sz.h, s_sz.h);
  }
  if (width != NULL) *width = i_sz.h + CHOICE_PAD;
  if (height != NULL) *height = i_sz.v;
}

LVAL DialogChoiceItemValue(item, set, value)
     LVAL item;
     int set, value;
{
  Display *dpy = StX11Display();
  LVAL win_id, text;
  int n;

  if (set) {
    text = slot_value(item, s_text);
    n = (consp(text)) ? llength(text) : 0;
    value = max(0, min(value, n - 1));
    set_slot_value(item, s_value, cvfixnum((FIXTYPE) value));
    win_id = slot_value(item, s_window_id);
    if (fixp(win_id)) draw_choice(dpy, (Window) getfixnum(win_id), item);
  }
  return(slot_value(item, s_value));
}


syntax highlighted by Code2HTML, v. 0.9.1