// This may look like C code, but it is really -*- C++ -*-

/***********************************************************
Copyright 1991 by the Massachusetts Institute of Technology

Permission to use, copy, modify, distribute, and sell this software and its
documentation for any purpose is hereby granted without fee, provided that
the above copyright notice appear in all copies and that both that
copyright notice and this permission notice appear in supporting
documentation, and that the name of M.I.T. not be used in advertising or
publicity pertaining to distribution of the software without specific,
written prior permission.  M.I.T. makes no representations about the
suitability of this software for any purpose.  It is provided "as is"
without express or implied warranty.


Author: Roman J. Budzianowski - Project Athena MIT

******************************************************************/

#include "Widgets.h"
#include "ObjectEditor.h"
#include <iostream.h>
#include "WindowStream.h"

#include "Application.h"
#include "LayoutSpace.h"
#include <xt++/Xaw/Scrollbar.h>

extern Application* appl;
extern wstream msg;

VisualObject::VisualObject(String class_name, String name, Cardinal input_count, Cardinal output_count)
: BaseObject(class_name, name), widget(0)
{
   workspace->AddObjectView(ClassName(),this,input_count+1,output_count);
}

void VisualObject::SetupIO(ObjectView* v)
{
   v->AddInput(map=new ObjectInput("map", this, Data::BooleanType));
}

Boolean VisualObject::AcceptInput(IO*,Data* data)
{
//   cerr << "VisualObject: got input: " << (int)*data << "\n";
   Boolean map = (Boolean)*data;
   if(map)
     widget->Map();
   else
     widget->Unmap();
   return True;
}

LayoutSpace* VisualObject::PromptForWidget()
{
   if(widget && !widget->IsRealized()){
      delete widget;
      widget = NULL;
   }

   if(!widget){
      if(appl){
	 msg.clear();
	 msg << "Creating widget for: " << Name() << "\n";
	 msg << "Place the widget in the Application window...\n" << flush;
	 return appl->GetLayout();
      }
      else
	msg << "Application window not created.\n" << flush;
   }
   else
     msg << "Widget already created.\n" << flush;

   return (LayoutSpace*)NULL;
}

static void TrueCB(Core*, XtPointer closure, XtPointer)
{
   TrueButton* obj = (TrueButton*)closure;
   obj->SendTrue();
}

BooleanData* TrueButton::true_value = (BooleanData*)NULL;
BooleanData* TrueButton::false_value = (BooleanData*)NULL;

TrueButton::TrueButton(String name) 
: VisualObject("true_button",name,0,1), callback(TrueCB)
{
   if(true_value==NULL) {
      true_value = new BooleanData(True); 
      false_value = new BooleanData(False); 
   }
}

TrueButton::TrueButton(String name, String class_name, XtCallbackProc callback=TrueCB) 
: VisualObject(class_name,name,0,1), callback(callback)
{
   if(true_value==NULL) {
      true_value = new BooleanData(True); 
      false_value = new BooleanData(False); 
   }
}

void TrueButton::SetupIO(ObjectView* v)
{
   VisualObject::SetupIO(v);
   v->AddOutput(output =new ObjectOutput("true", this, Data::BooleanType));
}

void TrueButton::CreateWidget()
{
   LayoutSpace* lay = PromptForWidget();
   if(lay){
      widget = new CommandWidget(Core::Unmanaged,Name(),lay);
      widget->AddCallback(XtNcallback,callback,(XtPointer)this);
	 
      lay->AddObject(new WidgetObject(widget, Name()));
   }
}


void BoolCB(Core*, XtPointer closure, XtPointer)
{
   BooleanButton* obj = (BooleanButton*)closure;
   obj->SendBool();
}

BooleanButton::BooleanButton(String name) 
: TrueButton(name,"bool_button", BoolCB), state(False) {}

void BooleanButton::SendBool()
{ 
   state = (state == true_value) ? false_value : true_value;
   output->Send(state);
}

NumberText::NumberText(String name)
: VisualObject("number_text",name,1,0) {}

void NumberText::SetupIO(ObjectView* v)
{
   VisualObject::SetupIO(v);
   v->AddInput(number =new ObjectInput("number", this, Data::IntegerType));
}

// it should use TextWidget and WindowStream
// and accept input
//
extern "C" {
char *sprintf(char *, const char * ...);
}

Boolean NumberText::AcceptInput(IO* io,Data* data)
{
   if(io == number){
      char buf[128];
      int val = (int)*data;
      sprintf(buf,"%d",val);
      widget->SetValues(XtNlabel,(XtArgVal)buf);
      return True;
   }
   else
     return VisualObject::AcceptInput(io,data);
}

void NumberText::CreateWidget()
{
   LayoutSpace* lay = PromptForWidget();
   if(lay){
      widget = new LabelWidget(Core::Unmanaged,Name(),lay);
      widget->SetValues(XtNlabel,(XtArgVal)"      0");
      lay->AddObject(new WidgetObject(widget, Name()));
   }
}

static void LeverCB(Core*, XtPointer closure, XtPointer val)
{
   NumberLever* obj = (NumberLever*)closure;
   float percent = *(float*)val;
   int intval = (int)(100*percent);
   obj->SendValue(intval);
}

NumberLever::NumberLever(String name)
: VisualObject("number_lever",name,1,1), callback(LeverCB) {}

void NumberLever::SetupIO(ObjectView* v)
{
   VisualObject::SetupIO(v);
   v->AddInput(input =new ObjectInput("input", this, Data::IntegerType));
   v->AddOutput(output =new ObjectOutput("output", this, Data::IntegerType));
}

void NumberLever::SendValue(int val)
{
   Integer data(val);
   output->Send(&data);		// XXX 
}

Boolean NumberLever::AcceptInput(IO* io,Data* data)
{
   if(io == input){

   }
   else
     return VisualObject::AcceptInput(io,data);
}

void NumberLever::CreateWidget()
{
   LayoutSpace* lay = PromptForWidget();
   if(lay){
      widget = new ScrollbarWidget(Core::Unmanaged,Name(),lay);
      // apparently you cannot set length
      widget->SetValues(XtNheight,(XtArgVal)100, // should check if it's already set
			XtNwidth,(XtArgVal)10,
			XtNshown,(XtArgVal)0.01,
			XtNtopOfThumb,(XtArgVal)0.01);
      widget->AddCallback(XtNjumpProc,callback,(XtPointer)this);
      
      lay->AddObject(new WidgetObject(widget, Name()));
   }
}
