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

    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/request.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 "X11/keysym.h"
#include "alert.h"
#include "request.h"

/******************************************
 * Handle an event for a requester window *
 ******************************************/
int mx_request_event(Display *display, int screen, XEvent *event,
		     mx_request *req, int *done)
{
  XCharStruct xcs;
  KeySym key;
  int i, j, dir, asc, desc;
  char keys[10];

  switch(event->type) {
  case Expose:
    if (event->xexpose.window != req->window)
      return False;
				/* draw the text string */
    XDrawString(display, req->window, req->app->gcd,
		req->app->item_border, req->app->item_border + req->app->ascent,
		req->text, req->length);
				/* determine cursor y posn and height */
    req->cur_y = req->app->item_border;
    req->cur_h = req->app->ascent + req->app->descent;
				/* cursor x position */
    if (req->cp == 0)
      req->cur_x = req->app->item_border;
    else {
      XTextExtents(req->app->font, req->text, req->cp,
		   &dir, &asc, &desc, &xcs);
      req->cur_x = req->app->item_border + xcs.width;
    }
				/* cursor width */
    if (req->cp == req->length)
      XTextExtents(req->app->font, " ", 1, &dir, &asc, &desc, &xcs);
    else
      XTextExtents(req->app->font, req->text + req->cp, 1,
		   &dir, &asc, &desc, &xcs);
    req->cur_w = xcs.width;
    if (req->inside)		/* display cursor */
      XFillRectangle(display, req->window, req->app->gcf,
		     req->cur_x, req->cur_y,
		     req->cur_w, req->cur_h);
    return True;
    break;
  case KeyPress:
    if (event->xkey.window != req->window)
      return False;
    j = XLookupString((XKeyPressedEvent*)event, keys, 10, &key, 0);
    if (j == 1 && keys[0] >= ' ' && keys[0] <= '~') {
      if (req->length < req->max_len - 1) { /* insert character */
	for (i = req->length + 1; i > req->cp; i--)
	  req->text[i] = req->text[i - 1];
	req->length ++;
	req->text[req->cp] = keys[0];
	req->cp ++;
	XClearArea(display, req->window, 0, 0, 0, 0, True);
      }
      return True;
    }
    if (key == XK_End || (j == 1 && keys[0] == 5)) { /* Ctrl-E */
      req->cp = req->length;
      XClearArea(display, req->window, 0, 0, 0, 0, True);
    }
    else if (key == XK_Begin || key == XK_Home ||
	     (j == 1 && keys[0] == 1)) { /* Ctrl-A */
      req->cp = 0;
      XClearArea(display, req->window, 0, 0, 0, 0, 1);
    }
    else if (key == XK_Right && req->cp < req->length)  {
      req->cp ++;
      XClearArea(display, req->window, 0, 0, 0, 0, 1);
    }
    else if (key == XK_Left && req->cp > 0)  {
      req->cp --;
      XClearArea(display, req->window, 0, 0, 0, 0, 1);
    }
    else if ((key == XK_BackSpace || (j == 1 && keys[0] == 4))
	     && req->cp < req->length) { /* Ctrl-D */
      for (i = req->cp; i < req->length - 1; i++)
	req->text[i] = req->text[i + 1];
      req->length --;
      XClearArea(display, req->window, 0, 0, 0, 0, 1);
    }
    else if (key == XK_Delete && req->cp > 0) {
      for (i = req->cp - 1; i < req->length - 1; i++)
	req->text[i] = req->text[i + 1];
      req->length --;
      req->cp --;
      XClearArea(display, req->window, 0, 0, 0, 0, 1);
    }
    else if (j == 1 && keys[0] == 11 && req->cp < req->length) { /* Ctrl-K */
      req->length = req->cp;
      XClearArea(display, req->window, 0, 0, 0, 0, 1);
    }
    else if (key == XK_Return || key == 1) {
      req->text[req->length] = '\0';
      *done = 1;
    }
    return True;
    break;
  case LeaveNotify:
    if (event->xcrossing.window != req->window)
      return False;
    XFillRectangle(display, req->window, req->app->gcf, req->cur_x, req->cur_y,
		   req->cur_w, req->cur_h);
    req->inside = 0;
    return True;
    break;
  case EnterNotify:
    if (event->xcrossing.window != req->window)
      return False;
    if (!req->inside)
      XFillRectangle(display, req->window, req->app->gcf,
		     req->cur_x, req->cur_y,
		     req->cur_w, req->cur_h);
    req->inside = 1;
    return True;
    break;
  }
  return False;
}

/*****************************************
 * Pop up a requester on the root window *
 * at position x y                       *
 *****************************************/
int mx_popup_request(Display *display, int screen, mx_panel *panel,
		     int *x, int *y, char *text, int max_len)
{
  mx_alert title;
  mx_request req;
  XEvent event;
  int done;

  if (!panel)
    return -1;
				/* determine dimensions of requester window */
  req.app = panel->app;
  req.text = text;
  req.length = strlen(req.text);
  req.max_len = max_len;
  if (req.app->em * max_len > panel->width)
    req.width = req.app->em * max_len +
      2 * req.app->item_border;
  else
    req.width = panel->width + 2 * req.app->item_border;

  req.height = req.app->ascent + req.app->descent + 2 * req.app->item_border;

				/* determine dimensions of title window */
  title.app = req.app;
  title.width = req.width;
  title.height = req.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 * panel->app->win_border,
	       req.height * 2 + 3 * panel->app->win_border,
	       x, y);
				/* open title window and set event masks */
  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 = 0;

				/* open requester window and set event masks */
  req.window =
    mx_transient_window_open(display, screen, req.app->win_border,
			     *x, *y + title.height + req.app->win_border,
			     req.width, req.height);
  XSelectInput(display, req.window, ExposureMask | OwnerGrabButtonMask |
	       ButtonPressMask | ButtonReleaseMask |
	       EnterWindowMask | LeaveWindowMask |
	       KeyPressMask);

  done = 0;
  req.inside = 0;
  req.cp = 0;

  while (!done) {
    XNextEvent(display, &event);
    if (mx_request_event(display, screen, &event, &req, &done))
      continue;
    if (mx_alert_event(display, screen, &event, &title, &done, x, y))
      continue;
    if (event.type == Expose && req.app->expose_fun) {
      if ((*(req.app->expose_fun))(&event))
	continue;
    }
  }
  mx_window_close(display, title.window);
  mx_window_close(display, req.window);
  return 0;
}
