#ifndef CODE_GFXTEXT_CXX
#define CODE_GFXTEXT_CXX

/*-----------------------------------------------------------------------
 * Xclasses code file
 * ($Id: gfx_text.cxx,v 1.2 1998/08/13 21:21:04 schmitzj Exp $)
 * 
 * Copyright (C) 1998 Jürgen Schmitz
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA  02111-1307, USA.
 *-----------------------------------------------------------------------
 */

#include <string.h>
#include <ctype.h>
#include "types.h"
#include <Xclasses/Xcolors.h>
#include <Xclasses/gadget.h>
#include <Xclasses/gfx_object.h>
#include <Xclasses/gfx_text.h>
#include "include/gfx_text_p.h"

#define UNDERSCORE	'_'


gfx_text::gfx_text(void) : gfx_object()
{
	while (!(p=new pgfx_text))
	{
		outOfMemory("gfx_text");
	}
	p->o=this;
	Name("gfx_text");
	Text(NULL);
}
gfx_text::gfx_text(char *t) : gfx_object()
{
	while (!(p=new pgfx_text))
	{
		outOfMemory("gfx_text");
	}
	p->o=this;
	Name("gfx_text");
	Text(t);
}
pgfx_text::pgfx_text(void)
{
	teile=NULL;
	adjust=ADJUST_LEFT|ADJUST_TOP;
	width=0;
	height=0;
	allowunderline=0;
}
pgfx_text::~pgfx_text()
{
	freemem();
}
gfx_text::~gfx_text()
{
	if (p) delete p;
}

void gfx_text::Adjust(int a)
{
	p->adjust=a;
}
char gfx_text::ShortCut(char *txt)
{
	if (txt)
	{
		while (*txt)
		{
			if (*txt==UNDERSCORE) return tolower(*(txt+1));
			txt++;
		}
	}
	return 0;
}
char gfx_text::ShortCut(void)
{
	if (p->teile)
	{
		gtxt_line *c1;
		gtxt_part *d1;

		c1=p->teile;
		do
		{
			d1=c1->parts;
			do
			{
				if (d1->under) return tolower(d1->text[d1->under]);
				d1=d1->next;
			}
			while (d1);
			c1=c1->next;
		}
		while (c1);
	}
	return 0;
}

void pgfx_text::freemem(void)
{
	width=0;
	height=0;
	if (teile)
	{
		gtxt_line *c1,*c2;
		gtxt_part *d1,*d2;

		c1=teile;
		while (c1)
		{
			c2=c1->next;
			d1=c1->parts;
			while (d1)
			{
				d2=d1->next;
				::free(d1);
				d1=d2;
			}
			delete c1;
			c1=c2;
		}
		teile=NULL;
	}
}
gtxt_part *pgfx_text::addpart(gtxt_line *g,gtxt_part *p1,char *c1,char *c2,int f)
{
	gtxt_part *p2=(gtxt_part*)malloc(sizeof(gtxt_part)+(c1-c2));
	p2->next=NULL;
	p2->font=f;
	p2->under=0;

	int j=0;
	for(int i=0;i<c1-c2;i++)
	{
		p2->text[j]=c2[i];
		if (c2[i]==UNDERSCORE && !allowunderline)
		{
			p2->under=i+1;
		}
		else if (c2[i]=='\\')
		{
			p2->text[j++]=c2[++i];
		}
		else
			j++;
	}
	p2->length=j;
	p2->text[j]=0;
	if (p1)
		p1->next=p2;
	else
		g->parts=p2;
	return p2;
}
void gfx_text::NoUnderlineText(char *txt)
{
	p->allowunderline=1;
	Text(txt);
	p->allowunderline=1;
}
void gfx_text::Text(char *txt)
{
	p->freemem();
	p->width=0;
	p->height=0;

	if (!txt) txt="";

	char *c1,*c2;
	gtxt_line *g1=NULL,*g2=NULL;
	gtxt_part *p1=NULL;
	int fnt=0;

	c1=txt;
	c2=txt;
	g1=new gtxt_line;
	if (!g1) return;
	g1->next=NULL;
	g1->parts=NULL;
	g1->width=0;
	g1->height=0;

	p->teile=g1;
	while (*c1)
	{
		if (*c1=='\n')
		{
			p1=p->addpart(g1,p1,c1,c2,fnt);
			g2=new gtxt_line;
			if (!g2) return;
			g2->next=NULL;
			g2->parts=NULL;
			g2->width=0;
			g2->height=0;
			g1->next=g2;
			g1=g2;
			p1=NULL;
			c2=c1+1;
		}
		else if (*c1=='\\')
		{
			c1++;
			if (!*c1)
				c1--;
		}
		else if (*c1=='{')
		{
			p1=p->addpart(g1,p1,c1,c2,fnt);
			c2=c1+1;
			while (*c1 && *c1!='}') c1++;
			if (*c1=='}')
			{
				char buf[100];
				strncpy(buf,c2,c1-c2);
				buf[c1-c2]=0;

				if (buf[0]=='F' &&
					buf[1]=='O' &&
					buf[2]=='N' &&
					buf[3]=='T' &&
					buf[4]=='_')
				{
					if (!strcmp(&buf[5],"FIXED")) fnt=FONT_FIXED;
					if (!strcmp(&buf[5],"GADGET")) fnt=FONT_GADGET;
					if (!strcmp(&buf[5],"GROUP")) fnt=FONT_GROUP;
					if (!strcmp(&buf[5],"SMALL")) fnt=FONT_SMALL;
					if (!strcmp(&buf[5],"BIG")) fnt=FONT_BIG;
					if (!strcmp(&buf[5],"MENU")) fnt=FONT_MENU;
				}
				if (buf[0]=='/' &&
					buf[1]=='F' &&
					buf[2]=='O' &&
					buf[3]=='N' &&
					buf[4]=='T')
				{
					fnt=0;
				}
			}
			c2=c1;
			if (*c2) c2++;
		}
		else
		{
		}
		c1++;
	}
	p1=p->addpart(g1,p1,c1,c2,fnt);
	p->allowunderline=0;
}
void pgfx_text::calcSize(gadget *g)
{
	XCharStruct cs;
	int dhint,fasc,fdec;
	XFontStruct *ft,*oldft;

	ft=oldft=g->gg_font();

	width=1;
	height=0;

	if (teile)
	{
		gtxt_line *c1;
		gtxt_part *d1;

		c1=teile;
		do
		{
			c1->width=0;
			c1->height=0;
			c1->baseline=0;
			d1=c1->parts;
			do
			{
				switch (d1->font)
				{
					case FONT_FIXED:
					case FONT_GROUP:
					case FONT_GADGET:
					case FONT_SMALL:
					case FONT_BIG:
					case FONT_MENU:
						g->Font(d1->font);
						ft=g->gg_font();
						break;
					default:
						g->gg_font(oldft);
						ft=g->gg_font();
						break;
				}
				XTextExtents(ft,d1->text,d1->length,&dhint,&fasc,&fdec,&cs);
				d1->width=cs.width;
				c1->width+=cs.width;
				if (fasc+fdec>c1->height) c1->height=fasc+fdec;
				if (fasc>c1->baseline) c1->baseline=fasc;

				if (d1->under>0)
				{
					XTextExtents(ft,d1->text,d1->under-1,&dhint,&fasc,&fdec,&cs);
					d1->ux1=cs.width;
					XTextExtents(ft,d1->text,d1->under,&dhint,&fasc,&fdec,&cs);
					d1->ux2=cs.width-1;
				}
				d1=d1->next;
			}
			while (d1);

			if (c1->width>width) width=c1->width;
			height+=c1->height;
			c1=c1->next;
		}
		while (c1);
	}
	g->gg_font(oldft);
}


void pgfx_text::draw(class gadget *g,int x,int y,int w,int h,int col)
{
	int ht=0,xx=0;
	XFontStruct *ft,*oldft;

	o->width(g);
	oldft=g->gg_font();

	XSetForeground(o->display(),g->gg_gc(),col);
	if (teile)
	{
		gtxt_line *c1;
		gtxt_part *d1;

		switch (adjust & (4|8))
		{	
			case ADJUST_TOP:
				ht=y;
				break;
			case ADJUST_MIDDLE:
				ht=y+(h-height)/2;
				break;
			case ADJUST_BOTTOM:
				ht=y+(h-height);
				break;
		}
		c1=teile;
		do
		{
			if (w>=c1->width && (h-(ht-y))>=c1->height)
			{
				d1=c1->parts;
				switch (adjust & (1|2))
				{
					case ADJUST_LEFT:
						xx=x;
						break;
					case ADJUST_CENTER:
						xx=x+(w-c1->width)/2;
						break;
					case ADJUST_RIGHT:
						xx=x+(w-c1->width);
						break;
				}
				do
				{
					switch (d1->font)
					{
						case FONT_FIXED:
						case FONT_GROUP:
						case FONT_GADGET:
						case FONT_SMALL:
						case FONT_BIG:
						case FONT_MENU:
							g->Font(d1->font);
							ft=g->gg_font();
							break;
						default:
							g->gg_font(oldft);
							ft=g->gg_font();
							break;
					}

					XDrawString(o->display(),g->gg_win(),g->gg_gc(),
					 xx,ht+c1->baseline,d1->text,d1->length);
					if (d1->under>0)
						XDrawLine(o->display(),g->gg_win(),g->gg_gc(),
						 xx+d1->ux1,ht+c1->height-1,xx+d1->ux2,ht+c1->height-1);

					xx+=d1->width;
					d1=d1->next;
				}
				while (d1);
			}
			ht+=c1->height;
			c1=c1->next;
		}
		while (c1);
	}
	g->gg_font(oldft);
}
void gfx_text::draw_normal(class gadget *g,int x,int y,int w,int h)
{
	p->draw(g,x,y,w,h,col_text());
}
void gfx_text::draw_selected(class gadget *g,int x,int y,int w,int h)
{
	p->draw(g,x+1,y+1,w,h,col_selectedtext());
}
void gfx_text::draw_locked(class gadget *g,int x,int y,int w,int h)
{
	p->draw(g,x+1,y+1,w,h,col_shine2());
	p->draw(g,x,y,w,h,col_shadow2());
}
void gfx_text::draw_selectedlocked(class gadget *g,int x,int y,int w,int h)
{
	draw_locked(g,x,y,w,h);
}

int gfx_text::height(class gadget *g)
{
	if (p->height) return p->height;
	p->calcSize(g);
	return p->height;
}
int gfx_text::width(class gadget *g)
{
	if (p->width) return p->width;
	p->calcSize(g);
	return p->width;
}

#endif
