/*********************************************************************
 *
 *         EZWGL, the EZ Widget and Graphics Library
 *
 *             Copyright (C) 1996, 1997  Maorong Zou
 *  
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 **********************************************************************/
/*
 *  June 1996.  Beta Release.
 *  Sept 1996.  Release Version 1.0
 *  Dec 1996.  Release Version 1.1 Beta
 *  April 1997.  Release Version 1.2
 *  November 1997.  Release Version 1.3
 */
/*****************************************************************
 ***                                                           ***
 ***       Pane Handle                                         ***
 ***                                                           ***
 *****************************************************************/
#define _EZ_WIDGET_PANE_HANDLE_C_

#include "EZ_Widget.h"

/*********************************************************************
 * 
 *  Functions implemented in this file:
 */
EZ_Widget       *EZ_CreatePaneHandle MY_ANSIARGS((EZ_Widget *parent));
void            EZ_DrawPaneHandle MY_ANSIARGS((EZ_Widget *widget));
void            EZ_PaneHEventHandle MY_ANSIARGS((EZ_Widget *widget,XEvent *event));
void            EZ_ComputePaneHandleSize MY_ANSIARGS((EZ_Widget *widget, int *w, int *h));

/*********************************************************************
 * 
 *  Local Variables.
 */
static void finish_paneHandle MY_ANSIARGS((EZ_Widget *widget, int x,int y));

static EZ_WidgetHandle EZ_PaneDividerHandle =
{ 
  EZ_ComputePaneHandleSize,
  EZ_DrawPaneHandle,
  EZ_FreeUnknownData,
  EZ_PaneHEventHandle,
};

/*********************************************************************/
EZ_Widget  *EZ_CreatePaneHandle(parent)
     EZ_Widget *parent;
{
  EZ_Widget  *tmp;

  if(parent == (EZ_Widget *)NULL)
    {
      (void)fprintf(stderr,
		    "Error in EZ_CreatePaneHandle, parent widget is NULL\n");
      return(NULL);
    }
  tmp = EZ_CreateNewWidget(parent);
  EZ_WidgetHandlingFunctions[EZ_WIDGET_PANE_HANDLE] = &EZ_PaneDividerHandle;

  EZ_SetWidgetTypeAndNames(tmp, EZ_WIDGET_PANE_HANDLE);
  EZ_SetWidgetExpandFlag(tmp);
  EZ_SetWidgetTransientFlag(tmp);
  EZ_WidgetPadX(tmp) = 0;
  EZ_WidgetPadY(tmp) = 0;
  EZ_WidgetPadB(tmp) = 1;
  EZ_WidgetBorderWidth(tmp)  = 0;

  EZ_WidgetCursor(tmp) = EZ_GetCursor(EZ_C_HAND2);

  EZ_PaneHandleOrientation(tmp) = EZ_HORIZONTAL;

  EZ_SetDoNotPropagateFlag(tmp);
  EZ_SetWidgetFocusableFlag(tmp);  

  return(tmp);
}
/****************************************************************************/
void  EZ_ComputePaneHandleSize(widget, w,h)
     EZ_Widget *widget;
     int             *w, *h;
{
  EZ_Widget *parent = EZ_WidgetParent(widget);
  EZ_GManager       *gmanager; 
  int orien = EZ_WidgetStacking(parent);
  int fill = EZ_WidgetFillMode(parent);
  /* if parent is a gridbag, paneHandle has nothing to do. */
  gmanager = EZ_WidgetGManager(parent);
  if(gmanager && EZ_GMType(gmanager) == EZ_GB_GEOM_MANAGER)
    {
      if(EZ_WidgetGBW(widget) > 1) orien = EZ_VERTICAL;
      else orien = EZ_HORIZONTAL;
      EZ_WidgetGBFill(widget) = EZ_FILL_NONE;
      EZ_WidgetGBAnchor(widget) = EZ_CENTER;
      EZ_ClearWidgetExpandFlag(widget);
    }
  
  if(!(EZ_GetWidgetSizeComputedFlag(widget)))
    {
      EZ_SetWidgetSizeComputedFlag(widget);
    }      
  if(orien >= EZ_HORIZONTAL && orien <= EZ_HORIZONTAL_CENTER)
    {
      int px = (EZ_WidgetPadB(widget) + EZ_WidgetPadX(widget)) << 1;
      *w = 6 + px;
      *h = 32;
      EZ_ClearWidgetHeightSetFlag(widget);
      EZ_SetWidgetWidthSetFlag(widget);
      EZ_PaneHandleOrientation(widget) = EZ_HORIZONTAL;
      switch(fill)
	{
	case EZ_FILL_NONE:
	  EZ_WidgetFillMode(parent) = EZ_FILL_HORIZONTALLY;
	  break;
	case EZ_FILL_VERTICALLY:
	  EZ_WidgetFillMode(parent) = EZ_FILL_BOTH;
	  break;
	default:
	  break;
	}
    }
  else
    {
      int py = (EZ_WidgetPadB(widget) + EZ_WidgetPadY(widget)) << 1;
      *w = 32;
      *h = 6 + py;
      EZ_ClearWidgetWidthSetFlag(widget);
      EZ_SetWidgetHeightSetFlag(widget);
      EZ_PaneHandleOrientation(widget) = EZ_VERTICAL;
      switch(fill)
	{
	case EZ_FILL_NONE:
	  EZ_WidgetFillMode(parent) = EZ_FILL_VERTICALLY;
	  break;
	case EZ_FILL_HORIZONTALLY:
	  EZ_WidgetFillMode(parent) = EZ_FILL_BOTH;
	  break;
	default:
	  break;
	}
    }
}
/****************************************************************************/
void EZ_DrawPaneHandle(wptr)
     EZ_Widget *wptr;
{
  int             w, h, x,y, padb, padb2, filled = 0;
  Pixmap          pixmap;
  Window          win;
  GC              gc, gc1, gc2, junkgc;
  unsigned long   bgpv, bgpva;
  int orien = EZ_PaneHandleOrientation(wptr);

  win = EZ_WidgetWindow(wptr);
  w   = EZ_WidgetWidth(wptr);
  h   = EZ_WidgetHeight(wptr);
  padb = EZ_WidgetPadB(wptr);
  padb2 = padb + padb;

  pixmap = XCreatePixmap(EZ_DisplayForWidgets, win, w, h, EZ_DepthForWidgets); 
  if(padb > 0)
    {
      EZ_GetParentBgGCN(wptr, &gc,&bgpva);
      XFillRectangle(EZ_DisplayForWidgets, pixmap, gc, 0,0, w, h); 
      filled = 1;
    }
  else bgpva = 0;  
  EZ_GetBackgroundGC(wptr, &gc,&bgpv, 1, 0);
  if(filled == 0 || bgpva != bgpv)
    XFillRectangle(EZ_Display, pixmap, gc, padb,padb, w-padb2, h-padb2); 
  
  EZ_GetDarkBrightNormalBDGC(wptr, &gc1, &gc2, &junkgc); /* dark, bright */
  if(orien == EZ_HORIZONTAL)
    {
      int px = EZ_WidgetPadX(wptr) + padb;
      int ll;
      /* x = (w>>1) - 1; */
      /* XDrawLine(EZ_DisplayForWidgets,pixmap, gc1,  x, 0,   x, h);*/
      x = (w>>1) + 1;
      /* XDrawLine(EZ_DisplayForWidgets,pixmap, gc2,  x, 0,   x, h);*/
      XDrawLine(EZ_Display,pixmap, EZ_DARKREDGC,  px, h-32, w-px, h-32);
      y = x--;
      ll = x - px;
      XDrawLine(EZ_Display,pixmap, EZ_DARKREDGC,  x, h-32-ll, x, h-32+ll);
    }
  else
    {
      int py = EZ_WidgetPadY(wptr) + padb;
      int ll;
      /* y = (h>>1) - 1; */
      /* XDrawLine(EZ_DisplayForWidgets,pixmap, gc1,  0, y,   w, y);*/
      y = (h>>1) + 1;
      /*XDrawLine(EZ_DisplayForWidgets,pixmap, gc2,  0, y,   w, y);*/
      x = y--;
      ll = y - py;
      XDrawLine(EZ_Display,pixmap, EZ_DARKREDGC,  w-32-x, y, w-32+x,y);
      XDrawLine(EZ_Display,pixmap, EZ_DARKREDGC,  w-32, py, w-32, h-py);
    }
  EZ_DrawRectBorder(wptr, pixmap);
  XCopyArea(EZ_Display,pixmap,win, EZ_WRITABLEGC,0,0,w,h,0,0); 
  XFreePixmap(EZ_Display, pixmap);                             
} 

/****************************************************************************/
void  EZ_PaneHEventHandle(widget, event)
     EZ_Widget *widget;
     XEvent    *event;
{
  int     Ox,Oy,x,y, dx,dy, rootx, rooty, oldx, oldy, buttonP, orien;
  XEvent  xevent;
  Window  root, child;
  unsigned int    mask;
  
  if(widget == (EZ_Widget *)NULL) return;
  switch(event->type)
    {
    case Expose:
      EZ_DrawWidget(widget);      
      break;

    case ButtonPress:
      XRaiseWindow(EZ_Display, EZ_WidgetWindow(widget));
      EZ_DrawWidget(widget);      
      buttonP = event->xbutton.button;
      XQueryPointer(EZ_Display, RootWindow(EZ_Display, EZ_ScreenNum),
		    &root,                                    /* root return win */
		    &child,                                   /* child ret win   */
		    &oldx, &oldy,                             /* x, y in root    */
		    &x,&y,                                    /* x, y in win     */
		    &mask);  
      /*
       * wait for a matching ButtonRelease. In the mean time, process
       * MotionNotify and SelectionRequest events.
       */
      Ox = EZ_WidgetOriginX(widget);
      Oy = EZ_WidgetOriginY(widget);
      orien = EZ_PaneHandleOrientation(widget);
      while(1)
	{
	  XNextEvent(EZ_Display, &xevent); 
	  EZ_FilterEvent(&xevent);
	  if(xevent.xany.window != EZ_WidgetWindow(widget))
	    EZ_WidgetDispatchEvent(&xevent);
	  else
	    {
	      switch(xevent.type)
		{
		case MotionNotify:
		  XQueryPointer(EZ_Display, RootWindow(EZ_Display, EZ_ScreenNum),
				&root,                                    /* root return win */
				&child,                                   /* child ret win   */
				&rootx, &rooty,                           /* x, y in root    */
				&x,&y,                                    /* x, y in win     */
				&mask);  
		  dx = rootx - oldx;  dy = rooty - oldy;
		  oldx = rootx;   oldy = rooty;
		  if(orien == EZ_HORIZONTAL)
		    EZ_WidgetOriginX(widget) += dx;
		  else
		    EZ_WidgetOriginY(widget) += dy;
		  EZ_ClearWidgetSizeComputedFlag(widget);
		  EZ_ReDisplayWidget(widget);
		  while(XCheckTypedEvent(EZ_Display, MotionNotify, &xevent))
		    EZ_FilterEvent(&xevent);
		  break;
		case ButtonRelease:
		  if(xevent.xbutton.button == buttonP)
		    {
		      finish_paneHandle(widget,Ox,Oy);
		      return;
		    }
		  break;
		default:
		  break;
		}
	    }
	}
      break;
    case KeyPress:
      {
	KeySym            keysym;
	XComposeStatus    compose; 
	char              tmpbuffer[8];
	int               count,move_unitX = 0, move_unitY = 0;
	count = XLookupString(&(event->xkey), tmpbuffer, 8, &keysym, &compose);
	tmpbuffer[count] = '\0';
	orien = EZ_PaneHandleOrientation(widget);
	Ox = EZ_WidgetOriginX(widget);
	Oy = EZ_WidgetOriginY(widget);
	if(orien == EZ_HORIZONTAL)
	  {
	    switch(keysym)
	      {
	      case XK_Left: case XK_b:  case XK_h: case XK_B:  case XK_H: 
#ifdef XK_KP_Left
	      case XK_KP_Left:
#endif
		if(event->xkey.state & ShiftMask) move_unitX = -20;
		else move_unitX = -10;
		
		break;
	      case XK_Right: case XK_f: case XK_l: case XK_F: case XK_L:  
#ifdef XK_KP_Right
	      case XK_KP_Right: 
#endif
		if(event->xkey.state & ShiftMask) move_unitX = 20;
		else move_unitX = 10;
		break;
	      default:
		break;
	      }
	  }
	else
	  {
	    switch(keysym)
	      {
	      case XK_Down: case XK_n: case XK_j: case XK_N: case XK_J:  
#ifdef XK_KP_Down
	      case XK_KP_Down:
#endif
		if(event->xkey.state & ShiftMask) move_unitY = 20;
		else move_unitY = 10;
		break;
	      case XK_Up:  case XK_k:  case XK_p: case XK_K:  case XK_P: 
#ifdef XK_KP_Up
	      case XK_KP_Up:
#endif
		if(event->xkey.state & ShiftMask) move_unitY = -20;
		else move_unitY = -10;
		break;
	      default:
		break;
	      }
	  }
	if(move_unitX || move_unitY)
	  {
	    EZ_WidgetOriginX(widget) += move_unitX;
	    EZ_WidgetOriginY(widget) += move_unitY;
	    EZ_ClearWidgetSizeComputedFlag(widget);
	    EZ_ReDisplayWidget(widget);
	    /* resize parent */
	    finish_paneHandle(widget, Ox, Oy);
	    /* take focus  again */
	    /* EZ_WarpPointerToWidgetWindow(widget, 1);*/
	  }
	{
	  XEvent xevent;
	  while(XCheckTypedEvent(EZ_Display, KeyPress, &xevent))
	    if(EZ_FilterEvent(&xevent))
	      EZ_InvokePrivateEventHandler(&xevent);	    
	}
      }
      break;
    case EnterNotify:
      EZ_SetWidgetHighlightFlag(widget);
      EZ_DrawWidget(widget);      
      break;
    case LeaveNotify:
      EZ_ClearWidgetHighlightFlag(widget);
      EZ_DrawWidget(widget);
    default:
      break;
    }
}
/******************************************************************/
static void finish_paneHandle(widget, Ox, Oy)
     EZ_Widget *widget;
     int Ox, Oy;
{
  int cx,cy, Bflag, Aflag, orien;
  EZ_Widget *parent, *tmp, *before, *after;
  EZ_GManager       *gmanager; 

  parent = EZ_WidgetParent(widget);
  gmanager = EZ_WidgetGManager(parent);
  if(gmanager && EZ_GMType(gmanager) != EZ_DEFAULT_GEOM_MANAGER) return;

  orien = EZ_PaneHandleOrientation(widget);
  /* if parent is a grid bag, better not interfere with it. */

  before = after = NULL;
  tmp = EZ_WidgetChildren(parent);
  while(tmp && tmp != widget)
    {
      before = tmp;
      tmp = EZ_WidgetSibling(tmp);
    }
  if(tmp) after = EZ_WidgetSibling(tmp);
  if(before && after)
    {
      Bflag = (before== NULL)? 0: EZ_WidgetFlags(before);
      Aflag = (after == NULL)? 0: EZ_WidgetFlags(after);
      if(orien == EZ_HORIZONTAL)
	{
	  cx = EZ_WidgetOriginX(widget) - Ox;
	  if(cx < 0)
	    {
	      int ww = EZ_WidgetWidth(before);
	      if(ww + cx < 16) cx = 16 - ww;
	      EZ_WidgetWidthHint(before) = ww + cx;
	      EZ_ClearWidgetSizeComputedFlag(before);
	      EZ_SetWidgetWidthSetFlag(before);
	      
	      ww = EZ_WidgetWidth(after);
	      EZ_WidgetWidthHint(after) = ww - cx;
	      EZ_ClearWidgetSizeComputedFlag(after);
	      EZ_SetWidgetWidthSetFlag(after);				  
	    }
	  else
	    {
	      int ww = EZ_WidgetWidth(after);
	      if(ww - cx < 16) cx = ww - 16;
	      EZ_WidgetWidthHint(after) = ww - cx;
	      EZ_ClearWidgetSizeComputedFlag(after);
	      EZ_SetWidgetWidthSetFlag(after);				  
	      
	      ww = EZ_WidgetWidth(before);
	      EZ_WidgetWidthHint(before) = ww + cx;
	      EZ_ClearWidgetSizeComputedFlag(before);
	      EZ_SetWidgetWidthSetFlag(before);
	    }
	}
      else
	{
	  cy = EZ_WidgetOriginY(widget) - Oy;
	  if(cy < 0)
	    {
	      int hh = EZ_WidgetHeight(before);
	      if(hh + cy < 16) cy = 16 - hh;
	      EZ_WidgetHeightHint(before) = hh + cy;
	      EZ_ClearWidgetSizeComputedFlag(before);
	      EZ_SetWidgetHeightSetFlag(before);
	      
	      hh = EZ_WidgetHeight(after);
	      EZ_WidgetHeightHint(after) = hh - cy;
	      EZ_ClearWidgetSizeComputedFlag(after);
	      EZ_SetWidgetHeightSetFlag(after);				  
	    }
	  else
	    {
	      int hh = EZ_WidgetHeight(after);
	      if(hh - cy < 16) cy = hh - 16;				  
	      EZ_WidgetHeightHint(after) = hh - cy;
	      EZ_ClearWidgetSizeComputedFlag(after);
	      EZ_SetWidgetHeightSetFlag(after);				  
	      hh = EZ_WidgetHeight(before);
	      EZ_WidgetHeightHint(before) = hh + cy;
	      EZ_ClearWidgetSizeComputedFlag(before);
	      EZ_SetWidgetHeightSetFlag(before);
	    }
	}
      EZ_ClearWidgetSizeComputedFlag(parent);
      EZ_ReDisplayWidget(parent);
      if(before) EZ_WidgetFlags(before) = Bflag;
      if(after) EZ_WidgetFlags(after) = Aflag;
    }
  else
    {
      EZ_WidgetOriginX(widget) = Ox;
      EZ_WidgetOriginY(widget) = Oy;
      EZ_ClearWidgetSizeComputedFlag(widget);
      EZ_ReDisplayWidget(widget);
    }
}
/******************************************************************/
#undef _EZ_WIDGET_PANE_HANDLE_C_
