/* unicodedialog.c - draw a unicode selector
   Copyright (C) 1996-2000 Paul Sheer

   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., 59 Temple Place, Suite 330, Boston, MA
   02111-1307, USA.
 */


#include <config.h>
#include <stdio.h>
#include <my_string.h>
#include <stdlib.h>
#include <stdarg.h>

#include <X11/Intrinsic.h>
#include <X11/Xatom.h>
#include "lkeysym.h"

#include "stringtools.h"
#include "app_glob.c"

#include "coolwidget.h"
#include "coollocal.h"

#include "edit.h"
#include "editcmddef.h"

#include "mad.h"

#define MID_X 20
#define MID_Y 20

extern struct look *look;

int last_unichar_left = 0;
int last_unichar_right = 0;
int last_unichar_focussed = 0;

static void render_unicode (CWidget * wdt)
{
    int w, h, isfocussed, i, j;
    Window win, temp_win;

    CPushFont ("editor", 0);
    win = wdt->pixmap;
    isfocussed = (wdt->winid == CGetFocus ());

    CSetColor (COLOR_WHITE);
    CRectangle (win, 2, 2, wdt->width - 4, wdt->height - 4);

    for (j = 0; j < 16; j++)
	for (i = 0; i < 17; i++) {
	    wchar_t wc;
	    int l;
	    XChar2b c;
	    c.byte1 = wdt->cursor >> 8;
	    c.byte2 = i + j * 16;
	    wc = i + j * 16 + (wdt->cursor & ~0xFF);
	    w = (FONT_MEAN_WIDTH * 2 + 5) * i + 5;
	    h = (FONT_PIX_PER_LINE + 5) * j + 5;
	    CSetBackgroundColor (COLOR_WHITE);
	    if (i == 16) {
		CSetColor (COLOR_FLAT);
		CImageText (win, w, h + FONT_BASE_LINE, "0123456789ABCDEF" + j, 1);
	    } else {
		l = FONT_PER_CHAR (wc);
		if (l) {
		    CSetColor (COLOR_BLACK);
		    CImageTextWC (win, w, h + FONT_BASE_LINE, &c, &wc, 1);
		} else {
		    CSetColor (COLOR_FLAT);
		    l = FONT_MEAN_WIDTH;
		    CRectangle (win, w, h, l, FONT_PIX_PER_LINE);
		}
		if (wc == wdt->cursor) {
		    CSetColor (color_palette (18));
		    CBox (win, w - 2, h - 2, l + 4, FONT_PIX_PER_LINE + 4);
		}
	    }
	}
    {
	char c[10];
	sprintf (c, "%04X", (unsigned int) wdt->cursor);
	w = (FONT_MEAN_WIDTH * 2 + 5) * 0 + 5;
	h = (FONT_PIX_PER_LINE + 5) * j + 5;
	CSetBackgroundColor (COLOR_WHITE);
	CSetColor (color_palette (1));
	CImageText (win, w, h + FONT_BASE_LINE, c, strlen (c));
    }
    for (i = 3; i < 16; i++) {
	w = (FONT_MEAN_WIDTH * 2 + 5) * i + 5;
	h = (FONT_PIX_PER_LINE + 5) * j + 5;
	CSetBackgroundColor (COLOR_WHITE);
	CSetColor (COLOR_FLAT);
	CImageText (win, w, h + FONT_BASE_LINE, "0123456789ABCDEF" + i, 1);
    }

    w = wdt->width;
    h = wdt->height;

    temp_win = wdt->winid;
    wdt->winid = win;
    (*look->render_textbox_tidbits) (wdt, isfocussed);
    wdt->winid = temp_win;
    XCopyArea(CDisplay, win, wdt->winid, CGC, 0, 0, w, h, 0, 0);
    CPopFont ();
    return;
}

/*
   This will reallocate a previous draw of the same identifier.
   so you can draw the same widget over and over without flicker
 */
CWidget *CDrawUnicodeInput (const char *identifier, Window parent, int x, int y, wchar_t start_char)
{
    CWidget *wdt;
    int w, h;

    CPushFont ("editor", 0);

    w = (FONT_MEAN_WIDTH * 2 + 5) * (16 + 1) - FONT_MEAN_WIDTH + 5;
    h = (FONT_PIX_PER_LINE + 5) * (16 + 1) + 5;

    set_hint_pos (x + w + WIDGET_SPACING, y + h + WIDGET_SPACING);

    wdt = CSetupWidget (identifier, parent, x, y, w, h, C_UNICODE_WIDGET, INPUT_KEY, COLOR_WHITE, 1);
    wdt->cursor = start_char;
    wdt->pixmap = XCreatePixmap (CDisplay, wdt->winid, w, h, CDepth);

    xdnd_set_type_list (CDndClass, wdt->winid, xdnd_typelist_send[DndText]);
    CPopFont ();
    return wdt;
}

int eh_unicode (CWidget * w, XEvent * xevent, CEvent * cwevent)
{
    int handled = 0;
    int i, j;
    long cursor;
    cursor = w->cursor;
    switch (xevent->type) {
    case ButtonPress:
	resolve_button (xevent, cwevent);
	CFocus (w);
	CPushFont ("editor", 0);
	i = (xevent->xbutton.x - 5) / (FONT_MEAN_WIDTH * 2 + 5);
	j = (xevent->xbutton.y - 5) / (FONT_PIX_PER_LINE + 5);
	if (i < 16 && j < 16 && i >= 0 && j >= 0)
	    w->cursor = i + j * 16 + (w->cursor & ~0xFF);
	CPopFont ();
	break;
    case FocusIn:
    case FocusOut:
	render_unicode (w);
	return 0;
    case Expose:
	if (!xevent->xexpose.count)
	    render_unicode (w);
	return 0;
    case ButtonRelease:
    case EnterNotify:
    case MotionNotify:
    case LeaveNotify:
	return 0;
	break;
    case KeyPress:
	cwevent->ident = w->ident;
	cwevent->state = xevent->xkey.state;
	switch (cwevent->command) {
	case CK_Down:
	    if (w->cursor <= 0xFFFF - 16)
		w->cursor += 16;
	    handled = 1;
	    break;
	case CK_Up:
	    if (w->cursor >= 16)
		w->cursor -= 16;
	    handled = 1;
	    break;
	case CK_Right:
	    if (w->cursor <= 0xFFFF - 1)
		w->cursor += 1;
	    handled = 1;
	    break;
	case CK_Left:
	    if (w->cursor >= 1)
		w->cursor -= 1;
	    handled = 1;
	    break;
	case CK_Home:
	    w->cursor = 0;
	    handled = 1;
	    break;
	case CK_End:
	    w->cursor = 0xFFFF;
	    handled = 1;
	    break;
	case CK_Page_Up:
	    if (w->cursor >= 256)
		w->cursor -= 256;
	    handled = 1;
	    break;
	case CK_Page_Down:
	    if (w->cursor <= 0xFFFF - 256)
		w->cursor += 256;
	    handled = 1;
	    break;
	}
	break;
    }
    if (w->cursor != cursor)
	render_unicode (w);
    w->keypressed |= handled;
    return handled;
}

long CUnicodeDialog (Window in, int x, int y, char *heading)
{
    Window win;
    CEvent cwevent;
    CState s;
    CWidget *w;
    long result = -1;
    if (!in) {
	x = MID_X;
	y = MID_Y;
    }
    in = find_mapped_window (in);
    CBackupState (&s);
    CDisable ("*");
    if (heading)
	win = CDrawHeadedDialog ("_unicode", in, x, y, heading);
    else
	win = CDrawDialog ("_unicode", in, x, y);
    CGetHintPos (&x, &y);
    CDrawUnicodeInput ("_unicode.box1", win, x, y, last_unichar_left);
    CGetHintPos (&x, 0);
    CDrawUnicodeInput ("_unicode.box2", win, x, y, last_unichar_right);
    CSetSizeHintPos ("_unicode");
    CMapDialog ("_unicode");
    if (last_unichar_focussed)
	CFocus (CIdent ("_unicode.box2"));
    else
	CFocus (CIdent ("_unicode.box1"));
    do {
	CNextEvent (NULL, &cwevent);
	if (!CIdent ("_unicode"))
	    break;
	if (cwevent.double_click)
	    cwevent.command = CK_Enter;
    } while (cwevent.command != CK_Cancel && cwevent.command != CK_Enter);
    if ((w = CIdent ("_unicode.box1"))) {
	if (CGetFocus () == w->winid) {
	    last_unichar_focussed = 0;
	    if (cwevent.command == CK_Enter)
		result = (wchar_t) w->cursor;
	}
	last_unichar_left = (int) w->cursor;
    }
    if ((w = CIdent ("_unicode.box2"))) {
	if (CGetFocus () == w->winid) {
	    last_unichar_focussed = 1;
	    if (cwevent.command == CK_Enter)
		result = (wchar_t) w->cursor;
	}
	last_unichar_right = (int) w->cursor;
    }
    CDestroyWidget ("_unicode");
    CRestoreState (&s);
    return result;
}

unsigned char *CGetUnichar (Window in, char *heading)
{
    long r;
    r = CUnicodeDialog (in, MID_X, MID_Y, heading);
    if (r == -1)
	return 0;
    return wcrtomb_ucs4_to_utf8 (r);
}

