/* $Id: LorMap.c,v 1.4 1997/07/01 14:44:39 archer Exp $
 *	LORMAP.C - Lorenai Map view at various scaling factors
 */
#include "LorMapP.h"
#include <Widget/Manage.h>
#include <Widget/panP.h>
#include "lorenai.h"


/**
 ** Local variables
 **/
static GC		map_gc, draw_gc;
static X11_color	red, yellow;


/**
 ** Internal: DRAW_WORLD
 **	Draw all squares?
 **/
static void draw_world(x11__lor_map *map, int r, int c,
					int lo_x, int hi_x, int lo_y, int hi_y)
{
area_s		*a;
X11_color	p;
int		x, y,
		x_b, y_b;
int		s;
/*
 * Compute the position
 */
	s = map->scale;
	x = c * s;
	x_b = x + s;
	y = r * s;
	if ((c & 1) == 0)
		y += s / 2;
	y_b = y + s;
/*
 * Falls within the area?
 */
	if (x > hi_x || y > hi_y)
		return;
	if (x_b <= lo_x || y_b <= lo_y)
		return;
/*
 * Refresh!
 */
	x -= map->delta_x;
	y -= map->delta_y;
	a = &lorenai_map[r][c];
	if (a->type) {
		p = a->type->worldview;
		XSetForeground(x11__screen, map_gc, p);
		XFillRectangle(x11__screen, map->core.id, map_gc, x, y, s, s);
	} else
		XClearArea(x11__screen, map->core.id, x, y, s, s, False);
/*
 * Special highlighting
 */
	if (a->highlighted == 1) {
		XSetForeground(x11__screen, draw_gc, red);
		XDrawLine(x11__screen, map->core.id, draw_gc, x, y+s-2, x+s-1, y+1);
	} else
		if (a->highlighted) {
			XSetForeground(x11__screen, draw_gc, yellow);
			XDrawLine(x11__screen, map->core.id, draw_gc, x, y+1,
								x+s-1, y+s-2);
		}
}


/**
 ** Internal: WORLD_VIEW
 **	Draw the map at large scale
 **/
static void world_view(X11_widget wdg, XEvent *e)
{
int	lo_x, hi_x,
	lo_y, hi_y;
int	r, c;
/*
 * Figure out which side we are
 */
	lo_x = e->xexpose.x + W_LORMAP->delta_x;
	hi_x = lo_x + e->xexpose.width - 1;
	lo_y = e->xexpose.y + W_LORMAP->delta_y;
	hi_y = lo_y + e->xexpose.height - 1;
/*
 * Draw now?
 */
	for (r = 1; r <= MAX_MAP; r++)
		for (c = 1; c <= MAX_MAP; c++)
			draw_world(W_LORMAP, r, c, lo_x, hi_x, lo_y, hi_y);
}


/**
 ** LOR_MAP_REFRESH
 **	Refresh the Map (supposedly, we did check which kind of area)
 **/
void Lor_Map_Refresh(X11_widget wdg)
{
int	lo_x, hi_x,
	lo_y, hi_y;
int	r, c;
/*
 * Expose all around
 */
	lo_x = W_LORMAP->delta_x;
	lo_y = W_LORMAP->delta_y;
	hi_x = lo_x + wdg->w - 1;
	hi_y = lo_y + wdg->h - 1;
/*
 * Draw now?
 */
	for (r = 1; r <= MAX_MAP; r++)
		for (c = 1; c <= MAX_MAP; c++)
			if (lorenai_map[r][c].update_needed) {
				lorenai_map[r][c].update_needed = 0;
				draw_world(W_LORMAP, r, c, lo_x, hi_x, lo_y, hi_y);
			}
}


/**
 ** Internal: MAP_RESIZE
 **	Impacts the scrollbars
 **/
static void map_resize(X11_widget wdg, XEvent *dummy)
{
X11_widget	scrollbar;
x11__scroller	*scroller;
int		s;
boolean		shuffle = False;
/*
 * Core resize
 */
	x11__core_resize(wdg, dummy);
/*
 * Modify the scrollbars size
 */
	scroller = W_LORMAP->scroller;
/*
 * Vertical scrollbar size
 */
	s = wdg->h - wdg->border2;
	scrollbar = scroller->vertical_bar;
	if (s >= W_LORMAP->h) {
		if (!scrollbar->unmanaged) {
			X11_UnManage(scrollbar);
			shuffle = True;
		}
	} else {
		x11__scrollbar_set_bounds(scrollbar, W_LORMAP->h, s);
		if (scrollbar->unmanaged) {
			X11_Manage(scrollbar);
			shuffle = True;
		}
	}
/*
 * Horizontal scrollbar size
 */
	s = wdg->w - wdg->border2;
	scrollbar = scroller->horizontal_bar;
	if (s >= W_LORMAP->w) {
		if (!scrollbar->unmanaged) {
			X11_UnManage(scrollbar);
			shuffle = True;
		}
	} else {
		x11__scrollbar_set_bounds(scrollbar, W_LORMAP->w, s);
		if (scrollbar->unmanaged) {
			X11_Manage(scrollbar);
			shuffle = True;
		}
	}
/*
 * Scrollbars appear?
 *	(this will recursively end up calling this resize function!)
 */
	if (shuffle && scroller->core.w)
		(*scroller->core.on_resize_window)(&scroller->core, (XEvent *)0);
}


/**
 ** Internal: MAP_GEOMETRY
 **	Quick and simple
 **/
static void map_geometry(X11_widget wdg, XEvent *dummy)
{
/*
 * Simple and easy
 */
	wdg->h_min =
	wdg->w_min = wdg->border2 + W_LORMAP->scale * 3;
/*
 * Size suggestion
 */
	if (!wdg->w) {
		wdg->w = 500 + wdg->border2;
		wdg->h = 350 + wdg->border2;
		map_resize(wdg, dummy);
	} else
		x11__widget_grow(wdg);
}


/**
 ** Internal: MAP_PAN_X
 **	User pans on the list
 **/
static long map_pan_x(X11_widget wdg, long value)
{
	if (value != W_LORMAP->delta_x) {
		x11__pan_window(wdg, W_LORMAP->delta_x - value, 0);
		W_LORMAP->delta_x = value;
	}
	return value;
}


/**
 ** Internal: MAP_PAN_Y
 **	User pans on the list
 **/
static long map_pan_y(X11_widget wdg, long value)
{
	if (value != W_LORMAP->delta_y) {
		x11__pan_window(wdg, 0, W_LORMAP->delta_y - value);
		W_LORMAP->delta_y = value;
	}
	return value;
}


/**
 ** LOR_MAP
 **	Create the Map widget. There's only one of its kind in the app
 **/
X11_widget Lor_map(X11_widget parent)
{
x11__lor_map	*object;
X11_widget	scroller;
/*
 * Allocate scroller window
 */
	scroller = X11_Scroller(parent, True, True);
/*
 * Create actual object
 */
	object = allocator(x11__lor_map);
	x11__core_setup(&object->core, scroller, "Map", "map");
/*
 * Initialize fields
 */
	object->core.event_mask        = ExposureMask;
	object->core.on_expose         = world_view;
	object->core.on_geometry_check = map_geometry;
	object->core.on_resize_window  = map_resize;
/*
 * Look and feel depends on the style. The scroller too!
 */
	object->core.border2 = 2;
	x11__resource_basic(&object->core);
/*
 * Scrolling
 */
	object->scroller = (x11__scroller *)scroller;
	x11__scrollbar_call(object->scroller->horizontal_bar, &object->core,
						map_pan_x);
	x11__scrollbar_set_arrow(object->scroller->horizontal_bar, 6, 0);
	x11__scrollbar_call(object->scroller->vertical_bar, &object->core,
						map_pan_y);
	x11__scrollbar_set_arrow(object->scroller->vertical_bar, 6, 0);
	object->scale = 6;
	object->w = 600;
	object->h = 603;
/*
 * GC needed
 */
	if (!map_gc)
		map_gc = x11__widget_gc(&object->core);
	if (!draw_gc)
		draw_gc = x11__widget_gc(&object->core);
	if (!red)
		red = X11_ColorByName("red", x11__white_pixel);
	if (!yellow)
		yellow = X11_ColorByName("yellow", x11__black_pixel);
/*
 * Ok
 */
	return OBJECT_P;
}
