#ifndef CODE_VISIBLE_CXX
#define CODE_VISIBLE_CXX

/*-----------------------------------------------------------------------
 * Xclasses code file
 * ($Id: visible.cxx,v 1.3 1999/03/05 15:28:35 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 "types.h"
#include <Xclasses/gadget.h>
#include <Xclasses/Xcolors.h>
#include <Xclasses/Ddraw.h>
#include <Xclasses/visible.h>
#include "include/visible_p.h"

visible::visible(): gadget(), Ddraw(this)
{
	while (!(p=new pvisible))
	{
		outOfMemory("visible");
	}
	p->o=this;
	Name("visible");
	p->horiz.ParentClass(this);
	p->vert.ParentClass(this);
	p->scale.ParentClass(this);
	p->innen.ParentClass(this);
}
visible::~visible()
{
	if (win) Free();
	if (p) delete p;
}
pvisible::pvisible() : horiz(), vert(), scale(), innen()
{
	obj=NULL;
	px=0;
	sc=0;
	v_visible=1;
	h_visible=1;
	horiz.specialflags|=SPF_NOKEYBORDER;
	vert.specialflags|=SPF_NOKEYBORDER;
	scale.specialflags|=SPF_NOKEYBORDER;
}
pvisible::~pvisible()
{
}
void visible::Apply(class gadget &g)
{
	Apply(&g);
}
void visible::Apply(class gadget *g)
{
	if (p->obj && win)
	{
		XUnmapWindow(display(),p->obj->gg_win());
//		p->obj->ParentClass(NULL);
	}
	p->obj=g;
	if (p->obj)
	{
		g->ParentClass(this);

		if (win)
		{
			if (p->obj->gg_win())
			{
				p->obj->Move(0,0);
				p->obj->Resize(p->S_Width(width-SCROLLER_WIDTH-RAHMEN-RAHMEN+PRAHMEN1-p->px),p->S_Height(height-SCROLLER_HEIGHT-RAHMEN-RAHMEN+PRAHMEN1));
				XMapRaised(display(),p->obj->gg_win());
			}
			else
			{
				p->obj->GSetLimits();
				p->obj->Dimensions(p->innen.gg_win(),0,0,p->S_Width(width-SCROLLER_WIDTH-RAHMEN-RAHMEN+PRAHMEN1-p->px),p->S_Height(height-SCROLLER_HEIGHT-RAHMEN-RAHMEN+PRAHMEN1));
				if (!p->obj->Create())
				{
					error_printf("Can't create applyed object!\n",this);
				}
			}
		}
	}
	if (win)
	{
		p->Resize();
		p->SetProps();
	}
}
void visible::Zoom(int z)
{
	if (!win)
	{
		p->px=1;
		p->zoom=z;
	}
}
static void scale_txt(int val,char *txt,int s)
{
	sprintf(txt,"%1.2f",(((double)val)/25.0+1.0));
}
int visible::Create(void)
{ 
	Background(col_background());
	BorderSize(PRAHMENB);
	KeyBorder();
	
    if (gadget::Create())
    {
        Mode(GM_ONEEXPOSE|GM_KEY);

		if (p->px)
		{
			p->scale.Vert();
			if (!setlimit)
			{
				p->scale.CopyFont(this);
				p->scale.GSetLimits();
			}
    	    p->scale.Dimensions(win,RealSize()-PRAHMENB,RealSize()-PRAHMENB,p->px-PRAHMEN1-(RealSize()-PRAHMENB),height-(RealSize()-PRAHMENB)*2);
			p->scale.MaxValue(p->zoom*10);
			p->scale.MinValue(0);
			p->scale.Value(0);
			p->scale.TextCallback(scale_txt);
        	if (p->scale.Create())
	        {
    	    	p->scale.SendEventTo(this);
        	}
	        else
    	    {
        		eprintf("No scale slider!\n");
	        }
		}

		p->horiz.Horiz();
        p->horiz.Dimensions(win,p->px+RealSize()-PRAHMENB,height-SCROLLER_HEIGHT,width-SCROLLER_WIDTH-p->px-(RealSize()-PRAHMENB),SCROLLER_HEIGHT-(RealSize()-PRAHMENB));
        if (p->horiz.Create())
        {
        	p->horiz.SendEventTo(this);
        }
        else
        {
        	error_printf("No horiz scroller!\n",this);
        }

		p->vert.Vert();
        p->vert.Dimensions(win,width-SCROLLER_WIDTH,RealSize()-PRAHMENB,SCROLLER_WIDTH-(RealSize()-PRAHMENB),height-SCROLLER_HEIGHT-PRAHMEN1-(RealSize()-PRAHMENB));
        if (p->vert.Create())
        {
        	p->vert.SendEventTo(this);
        }
        else
        {
        	error_printf("No vert scroller!\n",this);
        }

		p->innen.Dimensions(win,p->px+RAHMEN-PRAHMEN1,RAHMEN-PRAHMEN1,width-SCROLLER_WIDTH-RAHMEN-RAHMEN+PRAHMEN1-p->px,height-SCROLLER_HEIGHT-RAHMEN-RAHMEN+PRAHMEN1);
		p->innen.Background(col_background());
        if (p->innen.Create())
        {
        	p->innen.Mode(0);
        	p->innen.SendEventTo(this);
        }
		if (p->obj)
		{
			if (!setlimit) p->obj->GSetLimits();
			p->obj->Dimensions(p->innen.gg_win(),0,0,p->S_Width(width-SCROLLER_WIDTH-RAHMEN-RAHMEN+PRAHMEN1-p->px),p->S_Height(height-SCROLLER_HEIGHT-RAHMEN-RAHMEN+PRAHMEN1));
	        if (!p->obj->Create())
    	    {
				error_printf("Can't create applyed object!\n",this);
        	}
        }
        p->Resize();
        p->SetProps();
        return 1;
    } 
    return 0;
}
void visible::Free(void)
{
	if (p->obj) p->obj->Free();
	p->innen.Free();
	p->horiz.Free();
	p->vert.Free();
	if (p->px)
	{
		p->scale.Free();
	}
	gadget::Free();
}
void pvisible::Move(void)
{
	if (obj) obj->Move(-horiz.Position(),-vert.Position());
}
void pvisible::SetProps(void)
{
	if (obj)
	{
		horiz.Items(obj->gg_width());
		horiz.Visible(innen.gg_width());
		vert.Items(obj->gg_height());
		vert.Visible(innen.gg_height());
	}
	else
	{
		horiz.Items(0);
		horiz.Visible(1);
		vert.Items(0);
		vert.Visible(1);
	}
	Move();
}
int pvisible::S_Width(int w)
{
	if (obj)
	{
		w=(int)(((double)w)*(((double)sc)/25.0+1.0));
//		if (w<innen.gg_width()) w=innen.gg_width();
		if (w<obj->gg_minwidth()) w=obj->gg_minwidth();
		if (w>obj->gg_maxwidth()) w=obj->gg_maxwidth();
	}
	return w;
}
int pvisible::S_Height(int h)
{
	if (obj)
	{
		h=(int)(((double)h)*(((double)sc)/25.0+1.0));
//		if (h<innen.gg_height()) h=innen.gg_height();
		if (h<obj->gg_minheight()) h=obj->gg_minheight();
		if (h>obj->gg_maxheight()) h=obj->gg_maxheight();
	}
	return h;
}
void pvisible::Resize(void)
{
	int w2=o->width-/*SCROLLER_WIDTH-*/PRAHMEN-PRAHMEN+PRAHMEN1-px;
	int h2=o->height-/*SCROLLER_HEIGHT-*/PRAHMEN-PRAHMEN+PRAHMEN1;
	int w1=S_Width(w2);
	int h1=S_Height(h2);

	if (h1>h2)
	{
		w1-=SCROLLER_WIDTH;
		w2-=SCROLLER_WIDTH;
		// vert Scroller sichtbar
		if (!v_visible)
		{
			XMapWindow(o->display(),vert.gg_win());
			horiz.Resize(o->width-SCROLLER_WIDTH-PRAHMEN1-px-(o->RealSize()-PRAHMENB),SCROLLER_HEIGHT-(o->RealSize()-PRAHMENB));
			v_visible=1;
			XClearWindow(o->display(),o->win);
		}
		w1=S_Width(w1);
	}
	else
	{
		// vert Scroller verstecken
		if (v_visible)
		{
			XUnmapWindow(o->display(),vert.gg_win());
			horiz.Resize(o->width-PRAHMEN1-px-(o->RealSize()-PRAHMENB),SCROLLER_HEIGHT-(o->RealSize()-PRAHMENB));
			v_visible=0;
			XClearWindow(o->display(),o->win);
		}
	}
	if (w1>w2)
	{
		h1-=SCROLLER_HEIGHT;
		h2-=SCROLLER_HEIGHT;
		// horiz Scroller sichtbar
		if (!h_visible)
		{
			XMapWindow(o->display(),horiz.gg_win());
			vert.Resize(SCROLLER_WIDTH-(o->RealSize()-PRAHMENB),o->height-SCROLLER_HEIGHT-PRAHMEN1-(o->RealSize()-PRAHMENB));
			h_visible=1;
			XClearWindow(o->display(),o->win);
		}
		h1=S_Height(h1);
	}
	else
	{
		// horiz Scroller verstecken
		if (h_visible)
		{
			XUnmapWindow(o->display(),horiz.gg_win());
			vert.Resize(SCROLLER_WIDTH-(o->RealSize()-PRAHMENB),o->height-PRAHMEN1-(o->RealSize()-PRAHMENB));
			h_visible=0;
			XClearWindow(o->display(),o->win);
		}
	}
	if (h1>h2 && !v_visible)
	{
		w1-=SCROLLER_WIDTH;
		w2-=SCROLLER_WIDTH;
		// vert Scroller sichtbar
		if (!v_visible)
		{
			XMapWindow(o->display(),vert.gg_win());
			horiz.Resize(o->width-SCROLLER_WIDTH-PRAHMEN1-px-(o->RealSize()-PRAHMENB),SCROLLER_HEIGHT-(o->RealSize()-PRAHMENB));
			v_visible=1;
			XClearWindow(o->display(),o->win);
		}
		w1=S_Width(w1);
	}

	if (obj) obj->Resize(w1,h1);
	innen.Resize(w2,h2);

	gadget *owasfor=o->wasfor; // schlecht, aber nicht anders möglich
	o->wasfor=NULL;
	o->GExpose(NULL);
	o->wasfor=owasfor;
	if (v_visible || h_visible || px)
		o->Mode(GM_ONEEXPOSE|GM_KEY);
	else
		o->Mode(GM_ONEEXPOSE);
}
void visible::Resize(int nw,int nh)
{
	gadget::Resize(nw,nh);
	p->horiz.Move(p->px+RealSize()-PRAHMENB,nh-SCROLLER_HEIGHT);
	p->vert.Move(nw-SCROLLER_WIDTH,RealSize()-PRAHMENB);
	p->horiz.Resize(nw-(p->v_visible?SCROLLER_WIDTH:0)-PRAHMEN1-p->px-(RealSize()-PRAHMENB),SCROLLER_HEIGHT-(RealSize()-PRAHMENB));
	p->vert.Resize(SCROLLER_WIDTH-(RealSize()-PRAHMENB),nh-(p->h_visible?SCROLLER_HEIGHT:0)-PRAHMEN1-(RealSize()-PRAHMENB));
	if (p->px) p->scale.Resize(p->px-PRAHMEN1-(RealSize()-PRAHMENB),nh-(RealSize()-PRAHMENB)*2);

	p->Resize();
	p->SetProps();
}
void visible::Lock(void)
{
	gadget::Lock();
	p->innen.Lock();
	p->horiz.Lock();
	p->vert.Lock();
	if (p->px) p->scale.Lock();
	if (p->obj) p->obj->Lock();
}
void visible::Unlock(void)
{
	gadget::Unlock();
	p->innen.Unlock();
	p->horiz.Unlock();
	p->vert.Unlock();
	if (p->px) p->scale.Unlock();
	if (p->obj) p->obj->Unlock();
}
void visible::Block(int b)
{
 	gadget::Block(b);
 	p->innen.Block(b);
 	p->horiz.Block(b);
 	p->vert.Block(b);
 	if (p->px) p->scale.Block(b);
 	if (p->obj) p->obj->Block(b);
}
void visible::Unblock(int b)
{
 	gadget::Unblock(b);
 	p->innen.Unblock(b);
 	p->horiz.Unblock(b);
 	p->vert.Unblock(b);
 	if (p->px) p->scale.Unblock(b);
 	if (p->obj) p->obj->Unblock(b);
}
void visible::GExpose(XEvent *event)
{
	if (wasfor)
	{
		if (wasfor!=&p->innen) wasfor->GExpose(event);
	}
	else
	{
		if (p->v_visible || p->h_visible)
			borderDown(this,p->px,0,width-(p->v_visible?SCROLLER_WIDTH:0)-p->px-PRAHMEN1,height-(p->h_visible?SCROLLER_HEIGHT:0)-PRAHMEN1);
		if (active & GA_KEY)
		{
			bordermark(this,0,0,width,height);
		}
	    else
    	{
			borderunmark(this,0,0,width,height);
	    }
	}
}
void visible::GActionPress(int mx,int my,int rx,int ry,unsigned int state,int button,int reason)
{
	if (reason==GB_KEY)
	{
		if (wasfor)
		{
			ActivateKey();
		}
		else
		{
			bordermark(this,0,0,width,height);
		}
		return;
	}
	if (wasfor)
	{
		if (wasfor!=&p->innen) wasfor->GActionPress(mx,my,rx,ry,state,button,reason);
	}
}
void visible::GActionRelease(int mx,int my,int rx,int ry,unsigned int state,int button,int reason)
{
	if (reason==GB_KEY)
	{
		if (!wasfor)
		{
			borderunmark(this,0,0,width,height);
		}
		return;
	}
	if (wasfor)
	{
		if (wasfor!=&p->innen) wasfor->GActionRelease(mx,my,rx,ry,state,button,reason);
	}
}
int visible::GActivate(XEvent *event,int why)
{
	if (why==GA_KEY)
	{
		int c;
		char taste[5];
		KeySym key;

		c=XLookupString((XKeyEvent*)event,taste,sizeof(taste),&key,0);
		switch (key)
		{
			case XK_Left:
				p->horiz.Position(p->horiz.Position()-1);
				p->Move();
				return GAR_ACTIVE;
				break;
			case XK_Up:
				p->vert.Position(p->vert.Position()-1);
				p->Move();
				return GAR_ACTIVE;
				break;
			case XK_Right:
				p->horiz.Position(p->horiz.Position()+1);
				p->Move();
				return GAR_ACTIVE;
				break;
			case XK_Down:
				p->vert.Position(p->vert.Position()+1);
				p->Move();
				return GAR_ACTIVE;
				break;
			case XK_Home:
				p->vert.Position(0);
				p->horiz.Position(0);
				p->Move();
				return GAR_ACTIVE;
				break;
			case XK_End:
				p->vert.Position(p->obj->gg_height());
				p->horiz.Position(p->obj->gg_width());
				p->Move();
				return GAR_ACTIVE;
				break;
			default:
				if (taste[0]=='+')
				{
					if (p->px)
					{
						p->scale.Value(p->scale.Value()+1);
						p->sc=p->scale.Value();
						p->Resize();
						p->SetProps();
					}
				}
				else if (taste[0]=='-')
				{
					if (p->px)
					{
						p->scale.Value(p->scale.Value()-1);
						p->sc=p->scale.Value();
						p->Resize();
						p->SetProps();
					}
				}
				else
				{
					c=DefaultKeyHandler(event);
				}
				break;
		}
		return 0;
	}
	if (wasfor && wasfor!=&p->innen)
	{
		return wasfor->GActivate(event,why) & GAR_ACTIVE;
	}
	ActivateKey();
	return 0;
}
int visible::GSelected(XEvent *event,int why,int wasabove)
{
	if (why==GA_KEY) return GSR_SELECTION;
	if (wasfor && wasfor!=&p->innen)
	{
		if (wasfor==&p->horiz)
		{
			if (wasfor->GSelected(event,why,wasabove) & GSR_SELECTION)
			{
				p->Move();
			}
			return 0;
		}
		if (wasfor==&p->vert)
		{
			if (wasfor->GSelected(event,why,wasabove) & GSR_SELECTION)
			{
				p->Move();
			}
			return 0;
		}
		if (wasfor==&p->scale)
		{
			if (wasfor->GSelected(event,why,wasabove) & GSR_SELECTION) // && why==GA_BUTTONPRESS)
			{
				if (p->scale.Value()!=p->sc)
				{
					p->sc=p->scale.Value();
					p->Resize();
					p->SetProps();
				}
			}
			return 0;
		} error_printf("How happed this call??\n",this);
		return wasfor->GSelected(event,why,wasabove) & GSR_SELECTION;
	}
	return 0;
}
int visible::GMouseMove(int mx,int my,int rx,int ry,unsigned int state,int button)
{
	if (wasfor)
	{
		if (wasfor==&p->horiz)
		{
			if (wasfor->GMouseMove(mx,my,rx,ry,state,button) & GSR_SELECTION)
			{
				p->Move();
			}
			return 0;
		}
		if (wasfor==&p->vert)
		{
			if (wasfor->GMouseMove(mx,my,rx,ry,state,button) & GSR_SELECTION)
			{
				p->Move();
			}
			return 0;
		}
		if (wasfor==&p->scale)
		{
			if (wasfor->GMouseMove(mx,my,rx,ry,state,button) & GSR_SELECTION)
			{
				if (p->scale.Value()!=p->sc)
				{
					p->sc=p->scale.Value();
					p->Resize();
					p->SetProps();
				}
			}
			return 0;
		} error_printf("How happed this call??\n",this);
		return wasfor->GMouseMove(mx,my,rx,ry,state,button) & GSR_SELECTION;
	}
	else
	{
		return 0;
	}
}
void visible::GSetLimits(void)
{
	setlimit=1;
	if (p->px)
	{
		p->scale.CopyFont(this);
		p->scale.GSetLimits();
		p->px=p->scale.gg_minwidth()+PRAHMEN1-(RealSize()-PRAHMENB);
	}
	if (p->obj) p->obj->GSetLimits();
//	before_x=p->obj->before_x;
	minwidth=SCROLLER_WIDTH+RAHMEN+RAHMEN+20+p->px;
	minheight=SCROLLER_HEIGHT+RAHMEN+RAHMEN+20;
//	maxwidth=p->obj->gg_maxwidth()+SCROLLER_WIDTH+RAHMEN+RAHMEN+p->px;
//	maxheight=p->obj->gg_maxheight()+SCROLLER_HEIGHT+RAHMEN+RAHMEN;
}

#endif
