/* dialog.c - dialog windows for internal use
 * 
 *  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 <X11/keysym.h>


#include <stdlib.h>
#include <stdio.h>

#include "generic/wwmlib.h"
#include "WindowMaker.h"
#include "GNUstep.h"
#include "wcore.h"
#include "button.h"
#include "text.h"
#include "wconfig.h"
#include "actions.h"
#include "window.h"
#include "texture.h"
#include "funcs.h"
#include "dialog.h"
#include "pixmap.h"
#include "dlg_pixmaps.h"
#include "properties.h"



extern XContext wWinContext;



static void button1Click(WObjDescriptor *obj, XEvent *event);
static void button2Click(WObjDescriptor *obj, XEvent *event);


static WMethodTable button1Methods;
static WMethodTable button2Methods;


void
wDialogInitialize()
{
    memcpy(&button1Methods, &wButtonMethods, sizeof(WMethodTable));
    memcpy(&button2Methods, &wButtonMethods, sizeof(WMethodTable));
    button1Methods.click = button1Click;
    button2Methods.click = button2Click;
}


void 
wDialogDestroy(WDialog *dlg)
{
    wButtonDestroy(dlg->but1);
    if (dlg->but2)
      wButtonDestroy(dlg->but2);
    wCoreDestroy(dlg->core);
    wUnmanageWindow(dlg->wwin, False);
    if (dlg->pixmap)
      wPixmapDestroy(dlg->pixmap);
    XFreeGC(dpy, dlg->gc);
    wfree(dlg);
}


void
wDialogPaint(WDialog *dlg)
{
    WScreen *scr = dlg->core->screen_ptr;
    Window win = dlg->core->window;
    char *msg;
    int i, y=0;
    
    XDrawLine(dpy, win, 
	      scr->normal_button_texture->solid.dim_gc, 0, 80, 400, 80);
    XDrawLine(dpy, win, 
	      scr->normal_button_texture->solid.light_gc, 0, 81, 400, 81);
#ifndef I18N_MB    
    XSetFont(dpy, dlg->gc, scr->panel_title_font.font->fid);
    XDrawString(dpy, win, dlg->gc, 80, 40, dlg->title, strlen(dlg->title));
    XSetFont(dpy, dlg->gc, scr->panel_text_font.font->fid);    
#else
    XmbDrawString(dpy, win, scr->panel_title_font.font, dlg->gc, 80, 40, 
		  dlg->title, strlen(dlg->title));
#endif

    /* paint multi-line message */
    msg = dlg->message;
    while (*msg!=0) {
	i=0;
	while (msg[i]!='\n' && msg[i]!=0) i++;
#ifndef I18N_MB
	XDrawString(dpy, win, dlg->gc, 20, 100+y, msg, i);
#else
	XmbDrawString(dpy, win, scr->panel_text_font.font, dlg->gc, 20, 100+y, 
		      msg, i);
#endif
	msg += i;
	y += dlg->text_h;
	if (*msg==0) break;
	msg++;
    }
    
#ifdef USE_TEXT_FIELD
    if( dlg->wText != NULL )
      wTextPaint(dlg->wText);
#endif
    
    wButtonPaint(dlg->but1, False);
    if (dlg->but2)
      wButtonPaint(dlg->but2, False);

    if (dlg->pixmap) {
	XSetClipMask(dpy, dlg->gc, dlg->pixmap->mask);
	if (dlg->pixmap->depth==1)
	  XCopyPlane(dpy, dlg->pixmap->image, dlg->core->window, 
		     dlg->gc, 0, 0, dlg->pixmap->width,
		     dlg->pixmap->height, 15, 15, 1);
	else
	  XCopyArea(dpy, dlg->pixmap->image, dlg->core->window, 
		    dlg->gc, 0, 0, dlg->pixmap->width,
		    dlg->pixmap->height, 15, 15);
	XSetClipMask(dpy, dlg->gc, None);
    }
}


int
wMessageDialog(WScreen *scr, char *title, char *message, int type)
{
    XEvent event;
    WDialog *dlg;
    XGCValues gcv;
    int selected;
    GNUstepWMAttributes gattr;
    XClassHint *chint;
    KeyCode kcode;
    XWindowAttributes attr;

    dlg = wmalloc(sizeof(WDialog));
    dlg->message = message;
    dlg->title = title;
    dlg->selected = 0;
    dlg->type = type;
    dlg->core = wCoreCreateTopLevel(scr, (scr->scr_width-400)/2,
				    (scr->scr_height-180)/2, 400, 180, 0,
				    True);
    XSetWindowBackground(dpy, dlg->core->window,
			 scr->normal_button_texture->any.color.pixel);

    gattr.flags = (GSWindowStyleAttr|GSWindowLevelAttr);
    gattr.window_style = (NSTitledWindowMask);
    gattr.window_level = NSFloatingWindowLevel;
    PropWriteGNUstepWMAttr(dlg->core->window, &gattr);

    dlg->core->descriptor.self = dlg;
    dlg->core->descriptor.parent_type = WCLASS_DIALOG;
    dlg->core->descriptor.parent = dlg;

    chint = XAllocClassHint();
    chint->res_name = "";
    chint->res_class = "WindowMaker";
    XSetClassHint(dpy, dlg->core->window, chint);
    XFree(chint);

    gcv.foreground = scr->black_pixel;
    dlg->gc = XCreateGC(dpy, dlg->core->window, GCForeground, &gcv);
    XSetClipOrigin(dpy, dlg->gc, 15, 15);
    XStoreName(dpy, dlg->core->window, "");
#ifdef XPM
    dlg->pixmap = wPixmapCreateFromXPMData(scr, GNUSTEP_XPM);
#else
    dlg->pixmap =
      wPixmapCreateFromXBMData(scr, GNUSTEP_XBM_DATA,GNUSTEP_MASK_XBM_DATA,
			       GNUSTEP_XBM_WIDTH, GNUSTEP_XBM_HEIGHT,
			       scr->black_pixel, scr->white_pixel);
#endif /* XPM */
    switch (type) {
     case WD_ERROR:
     case WD_INFORMATION:
	dlg->but1 = wButtonCreate(dlg->core, 320, 145, 70, 24);
	dlg->but1->label = _("OK ");
	dlg->but1->label_gc = dlg->gc;
	dlg->but1->image = scr->button_arrow;
	dlg->but1->core->descriptor.methods = &button1Methods;
	dlg->but1->core->descriptor.parent_type = WCLASS_DIALOG;
	dlg->but1->core->descriptor.parent = dlg;
	dlg->but2=NULL;
	break;

     case WD_EXIT_CONFIRM:
	dlg->but1 = wButtonCreate(dlg->core, 220, 145, 70, 24);
	dlg->but2 = wButtonCreate(dlg->core, 300, 145, 80, 24);
	dlg->but1->label = _("Exit");
	dlg->but1->label_gc = dlg->gc;
	dlg->but2->label = _("Cancel");
	dlg->but2->label_gc = dlg->gc;
#ifdef NEWSTYLE
	dlg->but2->image = scr->button_arrow;
	dlg->but2->image1 = scr->button_arrow;
#else
	dlg->but2->image = scr->button_arrow;
#endif
	dlg->but1->core->descriptor.methods = &button1Methods;
	dlg->but1->core->descriptor.parent_type = WCLASS_DIALOG;
	dlg->but1->core->descriptor.parent = dlg;
	dlg->but2->core->descriptor.methods = &button2Methods;
	dlg->but2->core->descriptor.parent_type = WCLASS_DIALOG;
	dlg->but2->core->descriptor.parent = dlg;
	break;
    }
    dlg->wText = NULL;
    
    dlg->wwin = wManageWindow(scr, dlg->core->window);
    XMapSubwindows(dpy, dlg->core->window);
    XMapWindow(dpy, dlg->core->window);
    XFlush(dpy); 
    dlg->text_h = scr->panel_text_font.height;

    XGetWindowAttributes(dpy, dlg->core->window, &attr);    
    XSelectInput(dpy, dlg->core->window, attr.your_event_mask|KeyPressMask
		 |KeyReleaseMask);

    kcode = XKeysymToKeycode(dpy, XK_Return);
    dlg->selected = -1;
    while (dlg->selected < 0) {
/*
	WObjDescriptor *desc;
*/	
	wNextEvent(&event);
/*	
	if (event.type == KeyPress
	    && event.xkey.window == dlg->core->window) {
	    if (event.xkey.keycode == kcode) {
		puts("PUSH");
	    }
	}
*/	 
	DispatchEvent(&event);
    }
    selected = dlg->selected;
    wDialogDestroy(dlg);
    return selected;
}

#ifdef USE_ARG_DIALOG
#  define WD_ARG_WIDTH  400
#  define WD_ARG_HEIGHT 180

/********************************************************************\
 * wInputDialog                                                     *
 *   Pops up a dialog that prompts the user to enter a string (or   *
 *   maybe in the future, select a file) and then returns the       *
 *   string (or filename with path).                                *
 *                                                                  *
 * ARGS:   src     -                                                *
 *         message - The usage message (ex: "Enter filename:")      *
 * 	   value   - default value				    *
 * RETURN: string  - the users input, if the user presses the "Ok"  *
 *                   button, otherwise NULL                         *
 * GLOBAL: dpy     - the display                                    *
 *         ????                                                     *
\********************************************************************/
char *
wInputDialog( WScreen *scr, char *title, char *message, char *value )
{
    XEvent     event;
    WDialog    *dlg;
    XGCValues  gcv;
    int        selected;
    XClassHint *chint;
    KeyCode    kcode;
    GNUstepWMAttributes gattr;
    XWindowAttributes   attr;
    
    dlg = wmalloc(sizeof(WDialog));
    dlg->message  = message;
    dlg->title    = title;
    dlg->selected = 0;
    dlg->type     = WD_INPUT;
    
    /* Create the toplevel window */
    dlg->core = wCoreCreateTopLevel(scr, 
				    (scr->scr_width-WD_ARG_WIDTH)/2,
				    (scr->scr_height-WD_ARG_HEIGHT)/2, 
				    WD_ARG_WIDTH, 
				    WD_ARG_HEIGHT, 0,
				    True);
    
    XSetWindowBackground(dpy, dlg->core->window,
			 scr->normal_button_texture->any.color.pixel);
    
    dlg->core->descriptor.self = dlg;
    dlg->core->descriptor.parent_type = WCLASS_DIALOG;
    dlg->core->descriptor.parent = dlg;
    
    /* Setup the GNUStep window attributes */
    gattr.flags = (GSWindowStyleAttr|GSWindowLevelAttr);
    gattr.window_style = (NSTitledWindowMask);
    gattr.window_level = NSFloatingWindowLevel;
    PropWriteGNUstepWMAttr(dlg->core->window, &gattr);
    
#  if 0    /* For some reason, this is messing up the XKeyEvents! */
    /* Setup the "hint" */
    chint = XAllocClassHint();
    chint->res_name = "";
    chint->res_class = "WindowMaker";
    XSetClassHint(dpy, dlg->core->window, chint);
    XFree(chint);
#  endif  
    
    /* Draw the GNUStep icon at (15,15) in the window */
    gcv.foreground = scr->black_pixel;
    dlg->gc = XCreateGC(dpy, dlg->core->window, GCForeground, &gcv);
    XSetClipOrigin(dpy, dlg->gc, 15, 15);
    XStoreName(dpy, dlg->core->window, "");
#  ifdef XPM
    dlg->pixmap = wPixmapCreateFromXPMData(scr, GNUSTEP_XPM);
#  else
    dlg->pixmap =
      wPixmapCreateFromXBMData(scr, GNUSTEP_XBM_DATA,GNUSTEP_MASK_XBM_DATA,
			       GNUSTEP_XBM_WIDTH, GNUSTEP_XBM_HEIGHT,
			       scr->black_pixel, scr->white_pixel);
#  endif /* XPM */
    /* Setup a text field */
    dlg->wText = wTextCreate(dlg->core, 60, 110, 280, 20);
    dlg->wText->core->descriptor.parent_type = WCLASS_DIALOG;
    dlg->wText->core->descriptor.parent      = dlg;
    if (value) {
	wTextPutText(dlg->wText, value);
    }
    
    /* Setup the buttons... the button methods call button1Click()
     * or button2Click() (depending on which of the two buttons gets
     * pressed.  These callback functions set the value of 
     * dlg->selected, which tells us that we can return now */
    dlg->but1 = wButtonCreate(dlg->core, 220, 145, 70, 24);
    dlg->but2 = wButtonCreate(dlg->core, 300, 145, 80, 24);
    dlg->but1->label    = _("Ok");
    dlg->but1->label_gc = dlg->gc;
    dlg->but2->label    = _("Cancel");
    dlg->but2->label_gc = dlg->gc;
    dlg->but2->image    = scr->button_arrow;
    dlg->but1->core->descriptor.methods     = &button1Methods;
    dlg->but1->core->descriptor.parent_type = WCLASS_DIALOG;
    dlg->but1->core->descriptor.parent      = dlg;
    dlg->but2->core->descriptor.methods     = &button2Methods;
    dlg->but2->core->descriptor.parent_type = WCLASS_DIALOG;
    dlg->but2->core->descriptor.parent      = dlg;
    
    dlg->wwin = wManageWindow(scr, dlg->core->window);
    XMapSubwindows(dpy, dlg->core->window);
    XMapWindow(dpy, dlg->core->window);
    XFlush(dpy); 
    
    dlg->text_h = scr->panel_text_font.height;
    
#  if 1
    XGetWindowAttributes(dpy, dlg->core->window, &attr);    
    XSelectInput(dpy, dlg->core->window, attr.your_event_mask|KeyPressMask
		 |KeyReleaseMask);
    kcode = XKeysymToKeycode(dpy, XK_Return);
#  endif  
    dlg->selected = -1;
    
    while ((dlg->selected < 0) && (!dlg->wText->done)) {
	WObjDescriptor *desc=NULL;
	int handled = FALSE;
	
	wNextEvent(&event);
	
	XFindContext( dpy, event.xany.window, wWinContext, (XPointer *)&desc );
	
	if ((desc != NULL) &&
	   (desc->methods != NULL) &&
	   (desc->methods->any_event != NULL))
	  (*desc->methods->any_event)(desc, &event);
	else
	  DispatchEvent(&event);
    }
    
    selected = dlg->selected;
    wDialogDestroy(dlg);
    
    if ((selected == WDB_OK) || (dlg->wText->done)) {
	/* Get the contents of the text field, and return it */
	return wTextGetText(dlg->wText);
    } else
      return NULL;
}
# endif /* USE_ARG_DIALOG */




static void 
button1Click(WObjDescriptor *obj, XEvent *event)
{
    WDialog *dlg = obj->parent;
    
    switch (dlg->type) {
     case WD_INPUT:
     case WD_ERROR:
     case WD_INFORMATION:
	dlg->selected=WDB_OK;
	break;
     case WD_EXIT_CONFIRM:
	dlg->selected=WDB_EXIT;
	break;
     default:
	dlg->selected=-1;
    }
    
}


static void 
button2Click(WObjDescriptor *obj, XEvent *event)
{
    WDialog *dlg = obj->parent;
    
    switch (dlg->type) {
     case WD_INPUT:
     case WD_EXIT_CONFIRM:
	dlg->selected=WDB_CANCEL;
	break;
     default:
	dlg->selected=-1;
    }
}

