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

    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/select.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"
#include "select.h"

/**********************************
 * Handle an event for a scroller *
 **********************************/
int mx_scroll_event(Display *display, int screen, XEvent *event,
		    mx_scroll *scroll, int *done)
{
  static x, y, pick_x, pick_y;
  static int pick_item, item;
  int cursor_range, item_range;
  switch(event->type) {
  case Expose:
    if (event->xexpose.window == scroll->window) {
      XFillRectangle(display, scroll->window, scroll->app->gcd,
		     scroll->cur_x, scroll->cur_y,
		     scroll->cur_w, scroll->cur_h);
      return True;
    }
    break;
  case ButtonPress:
    if (event->xbutton.window == scroll->window) {
      pick_x = event->xbutton.x;
      pick_y = event->xbutton.y;
      pick_item = scroll->menu->start_item;
      if (pick_x >= scroll->cur_x && pick_x <= scroll->cur_x + scroll->cur_w &&
	  pick_y >= scroll->cur_y && pick_y <= scroll->cur_y + scroll->cur_h)
	scroll->inside = 1;
      return True;
    }
    break;
  case ButtonRelease:
    if (event->xbutton.window == scroll->window) {
      scroll->inside = 0;
    }
    break;
  case MotionNotify:
    if (event->xmotion.window == scroll->window) {
      if (!scroll->inside)
	return True;
      x = event->xbutton.x;
      y = event->xbutton.y;
      if (scroll->cur_y + y - pick_y < scroll->app->item_border)
	y = scroll->app->item_border + pick_y - scroll->cur_y;
      else if (scroll->cur_y + y - pick_y > scroll->height -
	       scroll->app->item_border - scroll->cur_h)
	y = scroll->height - scroll->app->item_border - scroll->cur_h +
	  pick_y - scroll->cur_y;
      if (y != pick_y) {
	XFillRectangle(display, scroll->window, scroll->app->gcf,
		       scroll->cur_x, scroll->cur_y,
		       scroll->cur_w, scroll->cur_h);
	scroll->cur_y += y - pick_y;

	cursor_range = scroll->height - 2 * scroll->app->item_border -
	  scroll->cur_h;
	item_range = scroll->max_item - scroll->min_item -
	  scroll->menu->max_items + 1;
	item = scroll->min_item +
	  (item_range * (scroll->cur_y - scroll->app->item_border) +
	   cursor_range / 2) / cursor_range;
	if (item != pick_item) {
	  scroll->menu->start_item = pick_item = item;
	  XClearArea(display, scroll->menu->window, 0, 0, 0, 0, True);
	}

	XFillRectangle(display, scroll->window, scroll->app->gcf,
		       scroll->cur_x, scroll->cur_y,
		       scroll->cur_w, scroll->cur_h);
	pick_y = y;
      }
      return True;
    }
    break;
  default:
    break;
  }
  return False;
}

/****************************************
 * Pop up a selector on the root window *
 * at position x, y                     *
 ****************************************/
int mx_popup_select(Display *display, int screen, mx_panel *panel,
		    int *x, int *y, int max_items)
{
  XEvent event;
  mx_menu menu;
  mx_scroll scroll;
  mx_alert title;
  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 = max_items;
  menu.n_items = panel->last_item - panel->first_item + 1;
  menu.item = panel->item + panel->first_item;

  scroll.app = panel->app;
  scroll.cur_w = 7;
  scroll.cur_h = 10;
  scroll.width = scroll.cur_w + 2 * scroll.app->item_border;
  scroll.height = menu.height * menu.max_items;
  scroll.menu = &menu;
  scroll.min_item = 1;
  scroll.max_item = menu.n_items - 1;

  title.app = panel->app;
  title.width = menu.width + scroll.width + menu.app->win_border;
  title.height = menu.height;
  title.start_item = 0;
  title.max_items = 1;
  title.item = menu.item;
  
  mx_adjust_xy(display, title.width + 2 * menu.app->win_border,
	       (menu.height * (menu.max_items + 1) +
		3 * menu.app->win_border),
	       x, y);

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

  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);

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

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

  scroll.inside = 0;
  scroll.cur_x = scroll.app->item_border;
  scroll.cur_y = scroll.app->item_border;

  while (!done) {
    XNextEvent(display, &event);
    if (mx_menu_event(display, screen, &event, &menu, &done, x, y))
      continue;
    if (mx_scroll_event(display, screen, &event, &scroll, &done))
      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;
    }
  }
  mx_window_close(display, title.window);
  mx_window_close(display, menu.window);
  mx_window_close(display, scroll.window);
  return menu.choice;
}

