#include "puLocal.h"

#define PUMENU_BUTTON_HEIGHT       25
#define PUMENU_BUTTON_EXTRA_WIDTH  25

puObject *puPopupMenu::add_item ( char *str, puCallback cb )
{
  int w, h ;
  getSize ( &w, &h ) ;
  puOneShot *b = new puOneShot ( 0, h, str ) ;
  b->setStyle        ( PUSTYLE_PLAIN ) ;
  b->setColourScheme ( colour[PUCOL_FOREGROUND][0],
		       colour[PUCOL_FOREGROUND][1],
		       colour[PUCOL_FOREGROUND][2],
		       colour[PUCOL_FOREGROUND][3] ) ;
  b->setCallback     ( cb ) ;
  recalc_bbox () ;
  return b ;
}

void puPopupMenu::close ( void )
{
  puPopup::close () ;

  int widest = 0 ;
  puObject *ob = dlist ;

  /*
   * June 17th, 1998, Shammi
   * There seems to be some mismatch with the
   * #define pumenusize and the actual size
   * There seems to be some overlap resulting
   * in more than one option being highlighted.
   * By setting the size to the actual values,
   * the overlap area seems to be less now.
   */

  int w, h ;

  for ( ob = dlist ; ob != NULL ; ob = ob -> next )
  {
    ob -> getSize ( &w, &h ) ;

    if ( w > widest ) widest = w ;
  }

  for ( ob = dlist ; ob != NULL ; ob = ob -> next )
  {
    ob -> getSize ( &w, &h ) ;
    ob -> setSize ( widest, h ) ;
  }

  recalc_bbox () ;
}


int puPopupMenu::checkKey ( int key, int updown )
{
  if ( dlist == NULL || ! isVisible () || ! isActive () )
    return FALSE ;

  if ( updown == PU_DOWN )
  {
    hide () ;

    /* Turn everything off ready for next time. */

    for ( puObject *bo = dlist ; bo != NULL ; bo = bo->next )
      bo -> clrValue () ;
  }

  puObject *bo ;

  /*
    We have to walk the list backwards to ensure that
    the click order is the same as the DRAW order.
  */

  for ( bo = dlist ; bo->next != NULL ; bo = bo->next )
    /* Find the last object in our list. */ ;

  for ( ; bo != NULL ; bo = bo->prev )
    if ( bo -> checkKey ( key, updown ) )
      return TRUE ;

  return FALSE ;
}


int puPopupMenu::checkHit ( int button, int updown, int x, int y )
{
  if ( dlist == NULL || ! isVisible () || ! isActive () )
    return FALSE ;

  /* Must test 'isHit' before making the menu invisible! */

  int hit = isHit ( x, y ) ;

  /*
   * June 17th, 1998, Shammi :
   * There seemed to be a miscalculation with the menus initially
   * Therefore I moved the recalculation stuff before the clearing.
   */

  /*
    This might be a bit redundant - but it's too hard to keep
    track of changing abox sizes when daughter objects are
    changing sizes.
  */

  recalc_bbox();
  x -= abox.min[0] ;
  y -= abox.min[1] ;

  /*
   * June 17th, 1998, Shammi :
   * Also clear the menu when the dragging the mouse and not hit.
   */

  if (   updown == active_mouse_edge || active_mouse_edge == PU_UP_AND_DOWN ||
       ( updown == PU_DRAG && !hit ) )
  {

    /* June 17th, 1998, Shammi :
     * Do not hide the menu if mouse is dragged out
     */

    if ( updown != PU_DRAG )
      hide () ;

    /* Turn everything off ready for next time. */

    /* June 17th, 1998, Shammi:
     * Make sure we check for a hit, if the mouse is moved
     * out of the menu.
     */

    for ( puObject *bo = dlist ; bo != NULL ; bo = bo->next )
    {
      if ( ! hit )
	bo -> checkHit ( button, updown, x , y ) ;

      bo -> clrValue () ;
    }
  }

  if ( ! hit )
    return FALSE ;

  puObject *bo ;
  
  /*
    We have to walk the list backwards to ensure that
    the click order is the same as the DRAW order.
  */

  /* June 17th, 1998, Shammi :
   * If the mouse is dragged and the menuItem is not hit, 
   * clear it
   */

  for ( bo = dlist ; bo->next != NULL ; bo = bo->next )
    if ( updown == PU_DRAG && ! bo -> checkHit ( button, updown, x, y ) )
      bo -> clrValue () ;

    /* Find the last object in our list. */ ;

  for ( ; bo != NULL ; bo = bo->prev )
    if ( bo -> checkHit ( button, updown, x, y ) )
      return TRUE ;

  return FALSE ;
}