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

    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/menu.c

Description:	

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

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

#include "basic.h"
#include "alert.h"
#include "menu.h"

/******************************
 * Handle an event for a menu *
 ******************************/
int mx_menu_event(Display *display, int screen, XEvent *event,
		  mx_menu *menu, int *done, int *x, int *y)
{
  switch(event->type) {
  case Expose:
    if (event->xexpose.window == menu->window) {
      mx_items_draw(display, menu->window, menu->app,
		    menu->item, menu->start_item, menu->max_items,
		    menu->width, menu->height, 0, 0);
      return True;
    }
    break;
  case LeaveNotify:
    if (event->xcrossing.window == menu->window) {
      if (!(menu->item[menu->cur_y + menu->start_item].flag &
	    MXItemFlag_Disabled))
	XFillRectangle(display, menu->window, menu->app->gcf,
		       0, menu->cur_y * menu->height,
		       menu->width, menu->height);
      menu->inside = 0;
      menu->choice = -1;
      return True;
    }
    break;
  case EnterNotify:
    if (event->xcrossing.window == menu->window) {
      menu->cur_y = event->xcrossing.y / menu->height;
      if (!(menu->item[menu->cur_y + menu->start_item].flag &
	    MXItemFlag_Disabled)) {
	XFillRectangle(display, menu->window, menu->app->gcf,
		       0, menu->cur_y * menu->height,
		       menu->width, menu->height);
	menu->choice = menu->cur_y + menu->start_item;
      }
      else
	menu->choice = -1;
      menu->inside = 1;
      return True;
    }
    break;
  case MotionNotify:
    if (event->xmotion.window == menu->window && menu->inside) {
      if (event->xmotion.y / menu->height != menu->cur_y) {
	if (!(menu->item[menu->cur_y + menu->start_item].flag &
	      MXItemFlag_Disabled))
	  XFillRectangle(display, menu->window, menu->app->gcf,
			 0, menu->cur_y * menu->height,
			 menu->width, menu->height);
	menu->cur_y = event->xmotion.y / menu->height;
	if (!(menu->item[menu->cur_y + menu->start_item].flag &
	      MXItemFlag_Disabled)) {
	  XFillRectangle(display, menu->window, menu->app->gcf,
			 0, menu->cur_y * menu->height,
			 menu->width, menu->height);
	  menu->choice = menu->cur_y + menu->start_item;
	}
	else
	  menu->choice = -1;
      }
      return True;
    }
    break;
  case ButtonRelease:
    if (event->xbutton.window == menu->window) {
      menu->cur_y = event->xbutton.y / menu->height;
      if (!(menu->item[menu->cur_y + menu->start_item].flag &
	    MXItemFlag_Disabled))
	menu->choice = menu->cur_y + menu->start_item;
      else
	menu->choice = -1;
      if  (menu->momentary) {
	*x = event->xbutton.x_root;
	*y = event->xbutton.y_root;
	*done = 1;
      }
      return True;
    }
    break;
  case ButtonPress:
    if (event->xbutton.window == menu->window) {
      menu->cur_y = event->xbutton.y / menu->height;
      if (!(menu->item[menu->cur_y + menu->start_item].flag &
	    MXItemFlag_Disabled))
	menu->choice = menu->cur_y + menu->start_item;
      else
	menu->choice = -1;
      if (!menu->momentary) {
	*x = event->xbutton.x_root;
	*y = event->xbutton.y_root;
	*done = 1;
      }
      return True;
    }
    break;
  default:
    break;
  }
  return False;
}

/************************************
 * Pop up a menu on the root window *
 * at position x, y                 *
 ************************************/
int mx_popup_menu(Display *display, int screen, mx_panel *panel,
		  int *x, int *y, int momentary)
{
  XEvent event;
  mx_alert title;
  mx_menu menu;
  int done;

  if (!panel)
    return -1;

  menu.app = panel->app;
  menu.width = panel->width + 2 * menu.app->item_border;
  menu.height = menu.app->ascent + menu.app->descent +
    2 * menu.app->item_border;
  menu.start_item = 1;
  menu.max_items = panel->last_item - panel->first_item;
  menu.item = panel->item + panel->first_item;

  title.app = panel->app;
  title.width = menu.width;
  title.height = menu.height;
  title.start_item = 0;
  title.max_items = 1;
  title.item = panel->item + panel->first_item;
				/* make sure the wondows are on screen */
  mx_adjust_xy(display, title.width + 2 * menu.app->win_border,
	       (menu.height * (menu.max_items + 1) +
		3 * menu.app->win_border),
	       x, y);
				/* open the title window */
  title.window =
    mx_transient_window_open(display, screen, title.app->win_border, *x, *y,
			     title.width, title.height);
  XSelectInput(display, title.window, ExposureMask | OwnerGrabButtonMask |
	       ButtonPressMask | ButtonReleaseMask |
	       EnterWindowMask | LeaveWindowMask);
  title.inside = -1;
  title.momentary = momentary;

				/* open the menu window */
  menu.window
    = mx_transient_window_open(display, screen, menu.app->win_border,
			    *x, *y + menu.height + menu.app->win_border,
			    menu.width,
			    menu.height * menu.max_items);
  XSelectInput(display, menu.window, ExposureMask | OwnerGrabButtonMask |
	       ButtonPressMask | PointerMotionMask | ButtonReleaseMask |
	       EnterWindowMask | LeaveWindowMask);

  done = 0;
  menu.inside = 0;
  menu.momentary = momentary;
  menu.cur_y = 0;
  menu.choice = -1;

  while (!done) {
    XNextEvent(display, &event);
    if (mx_menu_event(display, screen, &event, &menu, &done, x, y))
      continue;
    if (mx_alert_event(display, screen, &event, &title, &done, x, y))
      continue;
    if (event.type == Expose && menu.app->expose_fun) {
      if ((*(menu.app->expose_fun))(&event))
	continue;
    }
    if (momentary && event.type == ButtonRelease) {
      *x = event.xbutton.x_root;
      *y = event.xbutton.y_root;
      done = 1;
    }
  }
  mx_window_close(display, title.window);
  mx_window_close(display, menu.window);
  return menu.choice;
}
