/*                               -*- Mode: C -*- 
 * button.c -- Create a button.
 * 
 * Author          : 
 * Created On      : Tue Apr 20 08:24:53 1999
 * Last Modified By: Peter Bosch
 * Last Modified On: Fri Oct  1 11:09:08 1999
 * Status          : Unknown, Use with caution!
 * 
 * Unless other notices are present in any part of this file
 * explicitly claiming copyrights for other people and/or 
 * organizations, the contents of this file is fully copyright 
 * (C) 1999 Peter Bosch, all rights reserved.
 */

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <errno.h>
#include <assert.h>

#include "button.h"

static button_t *blist;

static void b_redraw(button_t *b);
static button_t *b_match(int x, int y, int width, int height);

button_t *
b_new(Display *display, Window win, GC gc, XFontStruct *mf, Pixmap stipple,
      int x, int y, int width, int height, 
      unsigned long fg, unsigned long bg, unsigned long hi, unsigned long lo,
      int active, char *info, Pixmap bm, int bmw, int bmh, b_f pressf,
      void *data1, void *data2)
{
  button_t *b;

  b = (button_t *)malloc(sizeof(button_t));
  assert(b);

  b->b_display = display;
  b->b_win     = win;
  b->b_gc      = gc;
  b->b_mf      = mf;
  b->b_stipple = stipple;
  b->b_x       = x - 1;
  b->b_y       = y - 1;
  b->b_width   = width;
  b->b_height  = height;
  b->b_fg      = fg;
  b->b_bg      = bg;
  b->b_hi      = hi;
  b->b_lo      = lo;
  b->b_active  = active;
  b->b_info    = (info)? strdup(info): NULL;
  b->b_bm      = bm;
  b->b_bmw     = bmw;
  b->b_bmh     = bmh;
  b->b_pressf  = pressf;
  b->b_data1   = data1;
  b->b_data2   = data2;
  b->b_next    = blist;
  blist	       = b;
  return b;
}

static button_t *
b_match(int x, int y, int width, int height)
{
  button_t *b;

  b = blist;
  while (b) {
    if (x >= b->b_x && x < b->b_x + b->b_width &&
	y >= b->b_y && y < b->b_y + b->b_height)
      return b;
    b = b->b_next;
  }
  return NULL;
}

void
b_setactive(button_t *b, int active)
{
  if (b->b_active != active) {
    b->b_active = active;
    b_redraw(b);
  }
}

static void
b_redraw(button_t *b)
{
  int ix, iy, n;

  XSetForeground(b->b_display, b->b_gc, b->b_bg);
  XFillRectangle(b->b_display, b->b_win, b->b_gc, b->b_x + 1, b->b_y + 1,
		 b->b_width - 1, b->b_height - 1);
  
  XSetForeground(b->b_display, b->b_gc, b->b_hi);
  for (n = 0; n != 3; n++) {
    XDrawLine(b->b_display, b->b_win, b->b_gc, b->b_x + n, 
	      b->b_y + b->b_height - n, b->b_x + n,  b->b_y + n);
    XDrawLine(b->b_display, b->b_win, b->b_gc, b->b_x + n, b->b_y + n,  
	      b->b_x + b->b_width - n, b->b_y + n);
  }

  XSetForeground(b->b_display, b->b_gc, b->b_lo);

  for (n = 0;  n != 3; n++) {
    XDrawLine(b->b_display, b->b_win, b->b_gc, b->b_x + n + 1, 
	      b->b_y + b->b_height - n, b->b_x + b->b_width - n, 
	      b->b_y + b->b_height - n);
    XDrawLine(b->b_display, b->b_win, b->b_gc, b->b_x + b->b_width - n, 
	      b->b_y + b->b_height - n, b->b_x + b->b_width - n,
	      b->b_y + n + 1);
  }

  XSetForeground(b->b_display, b->b_gc, b->b_bg);
  for (n = 0; n != 3; n++) {
    XDrawPoint(b->b_display, b->b_win, b->b_gc, b->b_x + n, 
	       b->b_y + b->b_height - n);
    XDrawPoint(b->b_display, b->b_win, b->b_gc, b->b_x + b->b_width - n, 
	       b->b_y + n);
  }

  XSetForeground(b->b_display, b->b_gc, b->b_fg);
  XDrawRectangle(b->b_display, b->b_win, b->b_gc, b->b_x, b->b_y,
		 b->b_width, b->b_height);

  if (!b->b_active) {
    XSetFillStyle(b->b_display, b->b_gc, FillStippled);
    XSetStipple(b->b_display, b->b_gc, b->b_stipple);
  }

  if (b->b_info) {
    ix = b->b_x + b->b_width / 2 - 
      XTextWidth(b->b_mf, b->b_info, strlen(b->b_info)) / 2;
    iy = b->b_y + b->b_height / 2 - 
      (b->b_mf->ascent + b->b_mf->descent) / 2 + b->b_mf->ascent;

    XDrawString(b->b_display, b->b_win, b->b_gc, ix, iy, 
		b->b_info, strlen(b->b_info));
    if (!b->b_active)
      XSetFillStyle(b->b_display, b->b_gc, FillSolid);
  }
  else {
    ix = b->b_x + (1 + b->b_width - b->b_bmw) / 2;
    iy = b->b_y + (1 + b->b_height - b->b_bmh) / 2;

    XSetBackground(b->b_display, b->b_gc, b->b_bg);
    XCopyPlane(b->b_display, b->b_bm, b->b_win, b->b_gc, 
	       0, 0, b->b_bmw, b->b_bmh, ix, iy, 1);

    if (!b->b_active) {
      XSetFillStyle(b->b_display, b->b_gc, FillStippled);
      XSetStipple(b->b_display, b->b_gc, b->b_stipple);
      XSetForeground(b->b_display, b->b_gc, b->b_bg);
      XFillRectangle(b->b_display, b->b_win, b->b_gc, b->b_x, b->b_y, 
		     b->b_width, b->b_height);
      XSetFillStyle(b->b_display, b->b_gc, FillSolid);
    }
  }
}

void
b_redrawall()
{
  button_t *b;

  b = blist;
  while (b) {
    b_redraw(b);
    b = b->b_next;
  }
}

void
b_press(XButtonEvent *e)
{
  button_t *b;

  b = b_match(e->x, e->y, 1, 1);
  if (b == NULL) return;
  b->b_pressf(b);
}

  
