/*
 * button.cc
 *
 * Copyright (C) 1995-2000 Kenichi Kourai
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, or (at your option)
 * any later version.
 * 
 * This program 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 General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with qvwm; see the file COPYING.  If not, write to
 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include "main.h"
#include "misc.h"
#include "button.h"
#include "event.h"
#include "qvwmrc.h"
#include "image.h"
#include "tooltip.h"

XContext Button::context;

Button::Button(Window pWin, const Rect& rect)
: parent(pWin), rc(rect)
{
  XSetWindowAttributes attributes;
  unsigned long valueMask;

  // initialize state
  state = NORMAL;

  attributes.background_pixel = ButtonColor.pixel;
  attributes.event_mask = ExposureMask | ButtonPressMask | ButtonReleaseMask |
                          EnterWindowMask | LeaveWindowMask |
                          PointerMotionMask ;
  valueMask = CWBackPixel | CWEventMask;

  frame = XCreateWindow(display, parent,
			rc.x, rc.y, rc.width, rc.height, 0,
			CopyFromParent, InputOutput, CopyFromParent,
			valueMask, &attributes);

  // save frame window id to context
  XSaveContext(display, frame, Button::context, (caddr_t)this);

  toolTip = new Tooltip();

  imgBack = NULL;
  imgActiveBack = NULL;
}

Button::~Button()
{
  XDestroyWindow(display, frame);

  // delete frame window id to context
  XDeleteContext(display, frame, Button::context);

  QvImage::Destroy(imgBack);
  QvImage::Destroy(imgActiveBack);

  delete toolTip;
}  

/*
 * MapButton --
 *   Map button frame.
 */
void Button::MapButton()
{
  XMapWindow(display, frame);
}

/*
 * UnmapButton --
 *   Unmap button frame.
 */
void Button::UnmapButton()
{
  XUnmapWindow(display, frame);
}

/*
 * DrawButton --
 *   Draw button according to state.
 */
void Button::DrawButton()
{
  XPoint xp[3];

  xp[0].x = rc.width - 2;
  xp[0].y = 0;
  xp[1].x = 0;
  xp[1].y = 0;
  xp[2].x = 0;
  xp[2].y = rc.height - 2;

  if (state == PUSH)
    XSetForeground(display, gc, black.pixel);
  else
    XSetForeground(display, gc, white.pixel);
  XDrawLines(display, frame, gc, xp, 3, CoordModeOrigin);

  xp[0].x = rc.width - 1;
  xp[0].y = 0;
  xp[1].x = rc.width - 1;
  xp[1].y = rc.height - 1;
  xp[2].x = 0;
  xp[2].y = rc.height - 1;

  if (state == PUSH)
    XSetForeground(display, gc, white.pixel);
  else
    XSetForeground(display, gc, black.pixel);
  XDrawLines(display, frame, gc, xp, 3, CoordModeOrigin);

  xp[0].x = rc.width - 3;
  xp[0].y = 1;
  xp[1].x = 1;
  xp[1].y = 1;
  xp[2].x = 1;
  xp[2].y = rc.height - 3;

  if (state == PUSH)
    XSetForeground(display, gc, darkGray.pixel);
  else
    XSetForeground(display, gc, lightGray.pixel);
  XDrawLines(display, frame, gc, xp, 3, CoordModeOrigin);

  xp[0].x = rc.width - 2;
  xp[0].y = 1;
  xp[1].x = rc.width - 2;
  xp[1].y = rc.height - 2;
  xp[2].x = 1;
  xp[2].y = rc.height - 2;
  
  if (state == PUSH)
    XSetForeground(display, gc, lightGray.pixel);
  else
    XSetForeground(display, gc, darkGray.pixel);
  XDrawLines(display, frame, gc, xp, 3, CoordModeOrigin);
}

/*
 * MoveResizeButton --
 *   Move and resize button.
 */
void Button::MoveResizeButton(const Rect& rect)
{
  rc = rect;

  XMoveResizeWindow(display, frame, rc.x, rc.y, rc.width, rc.height);
}

// img must be passed as only a pointer
void Button::SetBgImage(QvImage* img, const Point& off)
{
  if (img) {
    QvImage::Destroy(imgBack);
    imgBack = img->GetOffsetImage(off);
  }
}  

// image must be passed as only a pointer
void Button::SetBgActiveImage(QvImage* img, const Point& off)
{
  if (img) {
    QvImage::Destroy(imgActiveBack);
    imgActiveBack = img->GetOffsetImage(off);
  }
}  

/*
 * Button1Press --
 *   Process press of button1 (mouse left button)
 */
void Button::Button1Press()
{
  XEvent ev;
  ButtonState bs;

  toolTip->Disable();

  state = PUSH;
  DrawButton();

  while (1) {
    XMaskEvent(display, EnterWindowMask | LeaveWindowMask | ButtonReleaseMask,
	       &ev);
    switch (ev.type) {
    case EnterNotify:
      if (ev.xcrossing.window == frame) {
	state = PUSH;
	DrawButton();
      }
      break;

    case LeaveNotify:
      if (ev.xcrossing.window == frame) {
	state = NORMAL;
	DrawButton();
      }
      break;

    case ButtonRelease:
      if (ev.xbutton.state & Button1Mask) {
	bs = state;
	state = NORMAL;

	ExecButtonFunc(bs);
	DrawButton();
	return;
      }
    }
  }
}

void Button::Enter()
{
  toolTip->SetTimer();
}

void Button::Leave()
{
  toolTip->Disable();
}

void Button::PointerMotion()
{
  if (!toolTip->IsMapped())
    toolTip->ResetTimer();
}

void Button::Initialize()
{
  Button::context = XUniqueContext();
}
