/*****************************************************************************

    Copyright (C) 1994,1997 Ivan A. Curtis.  All rights reserved.

This code must not be re-distributed without these copyright notices intact.

*******************************************************************************
*******************************************************************************

Filename:	~icurtis/src/mx/alert.c

Description:	

Update History:   (most recent first)
   I. Curtis   9-Apr-97 12:02 -- Updated
   I. Curtis  22-Mar-94 23:11 -- Created.

******************************************************************************/
#include <stdlib.h>
#include "basic.h"
#include "alert.h"

/********************************************
 * Handle an event for an alert             *
 * Exposure events always cause a re-draw.  *
 * Enter/Leave events are only processed if *
 *            alert->inside is non-negative *
 * Button Press/Release events are only     *
 *         processed if alert->momentary is *
 *         TRUE                             *
 ********************************************/
int mx_alert_event(Display *display, int screen, XEvent *event,
		   mx_alert *alert, int *done, int *x, int *y)
{
  switch(event->type) {
  case Expose:
    if (event->xexpose.window == alert->window) {
      mx_items_draw(display, alert->window, alert->app,
		    alert->item, alert->start_item, alert->max_items,
		    alert->width, alert->height, 0, 0);
      return True;
    }
    break;
  case ButtonRelease:
    if (event->xbutton.window == alert->window) {
      if  (alert->momentary == 1) {
	*x = event->xbutton.x_root;
	*y = event->xbutton.y_root;
	*done = 1;
      }
      return True;
    }
    break;
  case ButtonPress:
    if (event->xbutton.window == alert->window) {
      if (alert->momentary == 0) {
	*x = event->xbutton.x_root;
	*y = event->xbutton.y_root;
	*done = 1;
      }
      return True;
    }
    break;
  case LeaveNotify:
    if (event->xcrossing.window == alert->window) {
      if (alert->inside == 1) {
	XFillRectangle(display, alert->window, alert->app->gcf,
		       0, 0,
		       alert->width, alert->height);
	alert->inside = 0;
      }
      return True;
    }
    break;
  case EnterNotify:
    if (event->xcrossing.window == alert->window) {
      if (alert->inside == 0) {
	XFillRectangle(display, alert->window, alert->app->gcf,
		       0, 0,
		       alert->width, alert->height);
	alert->inside = 1;
      }
      return True;
    }
    break;
  default:
    break;
  }
  return False;
}

/*****************************************************************************
 * Pop up an alert on the root window                                        *
 * at position x, y                                                          *
 *****************************************************************************/
int mx_popup_alert(Display *display, int screen, mx_panel *main_panel,
		   mx_panel *resp_panel,
		   int *x, int *y)
{
  XEvent event;
  mx_alert title, body, *button;
  int bod_height, n_buttons, b, b_xofs, b_yofs, b_dx;
  int choice, done;

  button = NULL;
  b_xofs = b_yofs = b_dx = 0;
  if (!main_panel)
    return -1;

  title.app = main_panel->app;
  title.width = main_panel->width + 2 * main_panel->app->item_border;
  title.height = main_panel->app->ascent + main_panel->app->descent +
    2 * main_panel->app->item_border;
  title.start_item = 0;
  title.max_items = 1;
  title.item = main_panel->item + main_panel->first_item;

  body.app = main_panel->app;
  body.width = main_panel->width + 2 * main_panel->app->item_border;
  body.height = main_panel->app->ascent + main_panel->app->descent +
    2 * main_panel->app->item_border;
  body.start_item = 0;
  body.max_items = main_panel->last_item - main_panel->first_item;
  body.item = main_panel->item + main_panel->first_item + 1;
  bod_height = body.max_items * body.height;

  if (resp_panel) {
    bod_height = (body.max_items + 2) * body.height;
    n_buttons = resp_panel->last_item - resp_panel->first_item + 1;
    b_yofs = title.height + title.app->win_border + 
      body.max_items * body.height + body.height / 2;
    b_xofs = body.height / 2;
    b_dx = body.width - body.height -
      (resp_panel->width + resp_panel->app->item_border * 2 + 
       resp_panel->app->win_border * 2);
    if (n_buttons > 2)
      b_dx = b_dx / (n_buttons - 1);

    button = (mx_alert *)malloc(sizeof(mx_alert) * n_buttons);
    for (b = 0; b < n_buttons; b++) {
      button[b].app = resp_panel->app;
      button[b].width = resp_panel->width + 2 * resp_panel->app->item_border;
      button[b].height = resp_panel->app->ascent + resp_panel->app->descent +
	2 * resp_panel->app->item_border;
      button[b].start_item = 0;
      button[b].max_items = 1;
      button[b].item = resp_panel->item + resp_panel->first_item + b;
    }
  }
  else {
    bod_height = body.max_items * body.height;
    n_buttons = 0;
  }

  mx_adjust_xy(display, title.width + 2 * title.app->win_border,
	       (title.height * (body.max_items + 1) +
		3 * title.app->win_border),
	       x, y);
				/* open the alert window */
  title.window =
    mx_transient_window_open(display, screen, title.app->win_border, *x, *y,
			     title.width, title.height * title.max_items);
  XSelectInput(display, title.window,
	       ExposureMask | OwnerGrabButtonMask |
	       ButtonPressMask | ButtonReleaseMask |
	       EnterWindowMask | LeaveWindowMask);
  title.inside = -1;
  if (resp_panel)
    title.momentary = -1;
  else
    title.momentary = 0;

  body.window =
    mx_transient_window_open(display, screen, body.app->win_border,
			     *x, *y + title.height + title.app->win_border,
			     body.width, bod_height);
  XSelectInput(display, body.window,
	       ExposureMask | OwnerGrabButtonMask |
	       ButtonPressMask | ButtonReleaseMask |
	       EnterWindowMask | LeaveWindowMask);
  body.inside = -1;
  if (resp_panel)
    body.momentary = -1;
  else
    body.momentary = 0;

  for (b = 0; b < n_buttons; b++) {
    button[b].window = 
      mx_transient_window_open(display, screen, button[b].app->win_border,
			       *x + b_xofs + b_dx * b,
			       *y + b_yofs,
			       button[b].width, button[b].height);
    XSelectInput(display, button[b].window,
		 ExposureMask | OwnerGrabButtonMask |
		 ButtonPressMask | ButtonReleaseMask |
		 EnterWindowMask | LeaveWindowMask);
    button[b].inside = 0;
    button[b].momentary = 0;
  }

  done = 0;
  choice = -1;

  while (!done) {
    XNextEvent(display, &event);
    if (mx_alert_event(display, screen, &event, &title, &done, x, y))
      continue;
    if (mx_alert_event(display, screen, &event, &body, &done, x, y))
      continue;
    for (b = 0; b < n_buttons; b++) {
      if (mx_alert_event(display, screen, &event, button + b, &done, x, y)) {
	if (done)
	  choice = b;
	break;
      }
    }
    if (event.type == Expose && title.app->expose_fun) {
      if ((*(title.app->expose_fun))(&event))
	continue;
    }
    /*
     *     if (event.type == ButtonRelease){
     *       *x = event.xbutton.x_root;
     *       *y = event.xbutton.y_root;
     *       done = 1;
     *       choice = -1;
     *     }
     */
  }
  mx_window_close(display, title.window);
  mx_window_close(display, body.window);
  for (b = 0; b < n_buttons; b++) {
    mx_window_close(display, button[b].window);
  }
  free(button);
  return choice;
}
