/* button.c- generic button class
 * 
 *  WindowMaker window manager
 * 
 *  Copyright (c) 1997 Alfredo K. Kojima
 * 
 *  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 of the License, 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 this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include "wconfig.h"

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <stdlib.h>
#include <stdio.h>

#include "generic/wwmlib.h"
#include "WindowMaker.h"
#include "wcore.h"
#include "button.h"
#include "funcs.h"

static void buttonMouseDown(WObjDescriptor *desc, XButtonEvent *bev);

WMethodTable wButtonMethods = {
    (WEventHandler)buttonMouseDown,
      (WEventHandler)NULL,
      (WEventHandler)NULL,
      (WEventHandler)NULL
};

/*
 *---------------------------------------------------------------------- 
 * wButtonCreate--
 * 	Creates a button inside the window in the specified position.
 * 
 * Returns:
 * 	A new initialized (zeroed) button.
 *----------------------------------------------------------------------
 */
WButton *
wButtonCreate(WCoreWindow *core, int x, int y, int width, int height)
{
    WButton *wbut;
    
    wbut = wmalloc(sizeof(WButton));
    wbut->core = wCoreCreate(core, x, y, width, height);
    wbut->texture = core->screen_ptr->normal_button_texture;
    wbut->texture_data = 0;
    wbut->alt_texture = core->screen_ptr->pushed_button_texture;
    wbut->alt_texture_data = 0;
    wbut->image = NULL;
#ifdef NEWSTYLE
    wbut->image1 = NULL;
    wbut->image2 = NULL;
#endif
    wbut->label = NULL;
    wbut->label_gc = core->screen_ptr->menu_entry_gc;
    wbut->core->descriptor.self = wbut;
    wbut->core->descriptor.methods = &wButtonMethods;
    wbut->pushed = 0; 
    return wbut;
}


void
wButtonDestroy(WButton *wbut)
{
#ifdef NEWSTYLE
    if (wbut->image1 && !wbut->image1->shared)
      wPixmapDestroy(wbut->image1);

    if (wbut->image2 && !wbut->image2->shared)
      wPixmapDestroy(wbut->image2);
    
    if (wbut->image && wbut->image!=wbut->image1 && wbut->image!=wbut->image2)
      wPixmapDestroy(wbut->image);
#else
    if (wbut->image && !wbut->image->shared)
      wPixmapDestroy(wbut->image);
#endif
    wTextureFreeData(wbut->core->screen_ptr->normal_button_texture,
		     &wbut->texture_data);
    wTextureFreeData(wbut->core->screen_ptr->pushed_button_texture,
		     &wbut->alt_texture_data);

    wCoreDestroy(wbut->core);
    wfree(wbut);
}


void
wButtonPaint(WButton *wbut, int repaint)
{
    WCoreWindow *core = wbut->core;
    GC copy_gc = core->screen_ptr->copy_gc;
    WTexture *texture;
    WTexData *texdata;
    WPixmap *image;
    WFont *font = &core->screen_ptr->panel_text_font;
    int x=0, y=0, w=0, d=0;
    int left=0, width=0;

    image = wbut->image;    
    /* setup stuff according to the state */
    if (wbut->pushed) {
	texture = wbut->alt_texture;
	texdata = &wbut->alt_texture_data;
	if (image) {
	    if (image->width>=image->height*2) {
		/* the image contains 2 pictures: the second is for the 
		 * pushed state */
		width = image->width/2;
		left = image->width/2;
	    } else {
		left = 0;
		width = image->width;
	    }
	}
	d=1;
    } else {
	texture = wbut->texture;
	texdata = &wbut->texture_data;
	if (image) {
	    left = 0;
	    if (image->width>=image->height*2)
	      width = image->width/2;
	    else
	      width = image->width;
	}
	d=0;
    }
    wTexturePaint(texture, texdata, wbut->core, repaint);
    /* calculate offsets for the text/image labels */
    if (wbut->label) {
	w = MyTextWidth(font->font, wbut->label, strlen(wbut->label));
	if (image) {
	    w += width + 4;
	}
    } else {
	if (image) {
	    w = width;
	}
    }
#ifdef I18N_MB
    /* display text */
    if (wbut->label) {
	y = font->y + d + (core->height - font->height)/2;
	XmbDrawString(dpy, core->window, font->font, wbut->label_gc,
		    (core->width-w)/2+d, y, wbut->label, strlen(wbut->label));
    }
#else
    /* display text */
    if (wbut->label) {
	y = font->font->ascent + d
          + (core->height - (font->font->ascent + font->font->descent))/2;
	XDrawString(dpy, core->window, wbut->label_gc,
		    (core->width-w)/2+d, y, wbut->label, strlen(wbut->label));
    }
#endif
    /* display image */
    if (image) {
	XSetClipMask(dpy, copy_gc, image->mask);
	if (wbut->label)
	  x = core->width - (core->width-w)/2 - width + d;
	else
	  x = (core->width - w)/2 + d;
	y = (core->height - image->height)/2 + d;
	XSetClipOrigin(dpy, copy_gc, x-left, y);
	if (image->depth==1)
	  XCopyPlane(dpy, image->image, core->window, copy_gc,
		     left, 0, width, image->height, x, y, 1);
	else
	  XCopyArea(dpy, image->image, core->window, copy_gc,
		    left, 0, width, image->height, x, y);
    }
}


static void
buttonMouseDown(WObjDescriptor *desc, XButtonEvent *bev)
{
    XEvent event;
    WButton *wbut = desc->self;
    int done=0, execute=1;
    
    if (XGrabPointer(dpy, wbut->core->window, False, 
		     ButtonReleaseMask|EnterWindowMask|LeaveWindowMask,
		     GrabModeAsync, GrabModeAsync, None, 
		     None, CurrentTime)!=GrabSuccess) {
#ifdef DEBUG0
	wWarning("pointer grab failed for button press");
#endif
	return;
    }
    
    wbut->pushed = True;
    wButtonPaint(wbut, False);
    while (!done) {
	XMaskEvent(dpy, LeaveWindowMask|EnterWindowMask|ButtonReleaseMask
		   |ExposureMask, &event);
	switch (event.type) {
	 case LeaveNotify:
	    wbut->pushed = False;
	    execute = 0;
	    wButtonPaint(wbut, False);
	    break;
	    
	 case EnterNotify:
	    wbut->pushed = True;
	    execute = 1;
	    wButtonPaint(wbut, False);    
	    break;

	 case ButtonRelease:
	    done = 1;
	    break;
	    
	 default:
	    DispatchEvent(&event);
	}
    }
    if (wbut->pushed) {
	wbut->pushed = False;	
	wButtonPaint(wbut, False);
    }
    XUngrabPointer(dpy, CurrentTime);
    if (execute && desc->methods->click!=NULL) {
	(*desc->methods->click)(desc, &event);
    }
}

#if 0
static void
buttonKeyPress(WObjDescriptor *desc, XKeyEvent *kev)
{
    XEvent event;
    WButton *wbut = desc->self;
    int done=0, execute=1;
    KeyCode kcode = kev->keycode;

    wbut->pushed = True;
    wButtonPaint(wbut, False);
    while (!done) {
	XMaskEvent(dpy, KeyReleaseMask, &event);
	switch (event.type) {
	 case KeyRelease:
	    if (event.xkey.keycode==kcode)
	      done = 1;
	    break;
	}
    }
    if (wbut->pushed) {
	wbut->pushed = False;	
	wButtonPaint(wbut, False);
    }
    if (execute && desc->methods->click!=NULL) {
	(*desc->methods->click)(desc, &event);
    }
}
#endif
