/* $Id: Label.c,v 1.2 1997/06/10 15:29:14 archer Exp $
 *	LABEL.C - Handle Label/Labelling objects
 *
 * Labels are inactive centered terminal objects.
 */
#include <Widget/LabelP.h>
#include <Widget/IconP.h>
#include <Widget/Shell.h>
#include <Widget/Manage.h>
#include <Widget/drawP.h>
#include <Widget/fontsP.h>


/**
 ** Private variable
 **/
static GC	label_gc;


/**
 ** X11_LABEL_SIZE
 **	Compute the size used by the label
 **/
void x11__label_size(x11__label *label)
{
XFontStruct	*info;
X11_icon	*icon;
char		*s, *t;
x11__size	w, h;
x11__size	v;
/*
 * Sizes
 */
	info = label->font;
	label->multi_line = False;
	w = 0;
/*
 * Label has a string. Which string?
 */
	if ((s = label->string) != 0 && *s) {
		h = info->ascent + info->descent;
		while ((t = strchr(s, '\n')) != 0) {
			label->multi_line = True;
			v = XTextWidth(info, s, (t-s));
			if (v > w)
				w = v;
			h += info->ascent + info->descent;
			s = t+1;
		}
		v = XTextWidth(info, s, strlen(s));
		if (v > w)
			w = v;
	} else
		h = 0;
/*
 * Final line
 */
	label->w_str = w;
	label->h_str = h;
/*
 * Icon present?
 */
	if ((icon = label->icon) != 0) {
		x11__icon_sized(icon);
		if (label->icon_above) {
			if (icon->w > w)
				w = icon->w;
			h += icon->h;
			if (s && *s)
				h += label->core.margin_inside;
		} else {
			w += icon->w;
			if (s && *s) {
				w += label->core.margin_inside;
				if (icon->h > h)
					h = icon->h;
			} else
				h = icon->h;
		}
	}
/*
 * Final size
 */
	label->w = w;
	label->h = h;
}


/**
 ** X11_LABEL_FIT
 **	Fits the current draw area to label
 **/
void x11__label_fit(x11__label *label)
{
	x11__draw_fit_v(label->w);
	x11__draw_fit_h(label->h);
}


/**
 ** X11_LABEL_DRAW
 **	Draw an object's label in the box
 **/
void x11__label_draw(x11__label *label, X11_color bk, X11_color fg)
{
XFontStruct	*info;
X11_icon	*icon;
char		*s, *t;
GC		gc;
x11__pos	x, y;
/*
 * Check needed
 */
	if (!label_gc)
		label_gc = x11__widget_gc(&label->core);
	info = label->font;
	x11__label_fit(label);
/*
 * Draw icon
 */
	x = x11__x_left;
	y = x11__y_top;
	if ((icon = label->icon) != 0) {
		if (label->icon_above)
			x += (label->w - icon->w) / 2;
		else
			y += (label->h - icon->h) / 2;
		x11__icon_draw(label->core.id, icon, bk, fg, x, y);
/*
 * Label is offset by?
 */
		if (label->icon_above) {
			x  = x11__x_left + (label->w - label->w_str) / 2;
			y += icon->h + label->core.margin_inside;
		} else {
			x += icon->w + label->core.margin_inside;
			y  = 1 + x11__y_bot - label->h_str;
		}
	}
/*
 * Draw string
 */
	if ((s = label->string) != 0) {
		if (label->core.is_disabled)
			gc = x11__stippled_gc;
		else
			gc = label_gc;
		XSetForeground(x11__screen, gc, fg);
		XSetBackground(x11__screen, gc, bk);
		XSetFont(x11__screen, gc, info->fid);
		y += info->ascent;
		if (label->multi_line)
			while ((t = strchr(s, '\n')) != 0) {
				XDrawString(x11__screen, label->core.id, gc,
							x, y, s, t-s);
				y += info->ascent + info->descent;
				s = t+1;
			}
		if (*s)
			XDrawString(x11__screen, label->core.id, gc,
							x, y, s, strlen(s));
	}
}


/**
 ** X11_LABEL_DRAW_ACTIVE
 **	Draw a label, using either active or unactivated colors
 **/
void x11__label_draw_active(x11__label *l)
{
	if (l->core.is_active)
		x11__label_draw(l, l->core.active_bk, l->core.active_fg);
	else
		x11__label_draw(l, l->core.background, l->core.foreground);
}


/**
 ** Internal: LABEL_EXPOSE
 **	Redraw the label. If called here, it is a terminal label, and always
 **	inactive
 **/
static void label_expose(X11_widget wdg, XEvent *dummy)
{
/*
 * Initialize drawing
 */
	x11__draw_start(wdg);
	x11__label_draw(W_LABEL, wdg->background, wdg->foreground);
}


/**
 ** Internal: LABEL_GEOMETRY
 **	Apply geometry from a label
 **/
static void label_geometry(X11_widget wdg, XEvent *dummy)
{
x11__size	w, h;
x11__size	b;
/*
 * Basic size
 */
	b = wdg->border2;
	w = b + W_LABEL->w;
	h = b + W_LABEL->h;
	wdg->fixed_w = True;
	wdg->fixed_h = True;
	wdg->w_min   = w;
	wdg->h_min   = h;
/*
 * Do the resize?
 */
	if (w != wdg->w || h != wdg->h) {
		wdg->w = w;
		wdg->h = h;
		(*wdg->on_resize_window)(wdg, dummy);
	}
}


/**
 ** X11_LABEL_CLEANUP
 **	Free the label
 **/
void x11__label_cleanup(X11_widget wdg, XEvent *dummy)
{
/*
 * Free storage
 */
	if (W_LABEL->string) {
		free(W_LABEL->string);
		W_LABEL->string = 0;
	}
}


/**
 ** X11_LABEL_GET_STRING
 **	Figure out the label associated with a widget
 **/
char *X11_LabelGetString(X11_widget wdg)
{
	return W_LABEL->string;
}


/**
 ** X11_LABEL_SET_STRING
 **	Set a new string to the label
 **/
void X11_LabelSetString(X11_widget wdg, char *text)
{
/*
 * Free old storage
 */
	if (W_LABEL->string) {
		free(W_LABEL->string);
		W_LABEL->string = 0;
	}
/*
 * new string
 */
	if (text)
		W_LABEL->string = strdup(text);
	x11__label_size(W_LABEL);
	(*wdg->on_geometry_check)(wdg, (XEvent *)0);
/*
 * Need some visual impact?
 */
	if (X11_IsManaged(wdg) && wdg->id) {
		XClearArea(x11__screen, wdg->id, 0, 0, 0, 0, False);
		(*wdg->on_expose)(wdg, (XEvent *)0);
	}
}


/**
 ** X11_LABEL_SET_ICON
 **	Set an icon to be associated with a label
 ** (it is assumed that: either we're not yet fully managed, or we're adding
 **  a new icon of the same size: No geometry change/resize)
 **/
void X11_LabelSetIcon(X11_widget wdg, X11_icon *icon)
{
	W_LABEL->icon = icon;
	if (!W_LABEL->icon_above && !wdg->margin_inside)
		wdg->margin_inside = 5;
	x11__label_size(W_LABEL);
}


/**
 ** X11_LABEL_RESOURCES
 **	Initialize the properties of a Label, or subclass of label
 **/
void x11__label_resources(x11__label *l, char *font, char *text)
{
char	*s;
/*
 * Generic resources
 */
	x11__resource_basic(&l->core);
/*
 * Label specific resources
 */
	l->font = x11__font_resource(font);
	if ((s = x11__resource_value("Text")) != 0)
		text = s;
	if (text)
		l->string = strdup(text);
	x11__label_size(l);
}


/**
 ** X11_LABEL
 **	Create a Label window
 **/
X11_widget X11_Label(X11_widget parent, char *name, char *text)
{
x11__label	*object;
/*
 * Get resource
 */
	object = allocator(x11__label);
	x11__core_setup(&object->core, parent, "Label", name);
/*
 * Initialize fields
 */
	object->core.event_mask        = ExposureMask;
	object->core.on_destruction    = x11__label_cleanup;
	object->core.on_expose         = label_expose;
	object->core.on_geometry_check = label_geometry;
/*
 * Basic style
 */
	x11__label_resources(object, x11__font_helvetica12, text);
/*
 * Specific fields
 */
	object->core.w     =
	object->core.w_min = object->w + object->core.border2;
	object->core.h     =
	object->core.h_min = object->h + object->core.border2;
/*
 * Ok
 */
	return OBJECT_P;
}
