/* ==================================================== ======== ======= *
 *
 *  transptool.cc
 *  Ubit Project [Elc::2002]
 *  Author: Eric Lecolinet
 *
 *  Part of the Ubit Toolkit: A Brick Construction Game Model for Creating GUIs
 *
 *  (C) 2002 Eric Lecolinet @ ENST Paris
 *  WWW: http://www.enst.fr/~elc/ubit   Email: elc@enst.fr (subject: ubit)
 *
 * ***********************************************************************
 * COPYRIGHT NOTICE : 
 * THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY AND WITHOUT EVEN THE 
 * IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. 
 * YOU CAN REDISTRIBUTE IT AND/OR MODIFY IT UNDER THE TERMS OF THE GNU 
 * GENERAL PUBLIC LICENSE AS PUBLISHED BY THE FREE SOFTWARE FOUNDATION; 
 * EITHER VERSION 2 OF THE LICENSE, OR (AT YOUR OPTION) ANY LATER VERSION.
 * SEE FILES 'COPYRIGHT' AND 'COPYING' FOR MORE DETAILS.
 * ***********************************************************************
 *
 * ==================================================== [Elc:02] ======= *
 * ==================================================== ======== ======= */

#include <iostream>
#include <stdio.h>
#include <ubit/ubit.hpp>
#include <ubit/ugraph.hpp>
#include "transptool.hpp"
using namespace std;

const UFlag TTOOL_FLAG;

/* ==================================================== [Elc:02] ======= */
/* ==================================================== ======== ======= */

int main(int argc, char *argv[]) {
  UAppli appli(&argc, argv);   // creates the application context.

  // creates the Main Frame and adds it to the UAppli
  TTMain ttmain;
  appli.add(ttmain);

  // show the main frame and starts the event main loop
  ttmain.show();
  return appli.mainLoop();
}

/* ==================================================== [Elc:02] ======= */
/* ==================================================== ======== ======= */

TTMain::TTMain() {
  scene = null;
  scene_scale = &uscale();
  rowCount = 20;
  colCount = 10;

  UArgs bprops = UBgcolor::none + UOn::enter / UColor::yellow;

  UMenu& file_menu = umenu
    (
     UBgcolor::navy + ualpha(0.3) + UColor::white
     + ubutton(bprops + UPix::edit + "Open")
     + ubutton(bprops + UPix::ray + "Save")
     + ubutton(bprops + UPix::ray + "Save As")
     + ubutton(UBgcolor::none + UOn::enter / UColor::red
	       + UPix::ray + "Exit" + ucall(0, UAppli::quit))
     );

  UMenu& tool_menu = umenu
    (
     UBgcolor::teal + ualpha(0.6) + UColor::white
     + ubutton(bprops + UPix::edit + "Note" 
	       + ucall(this, 0, &TTMain::addTool))
     + ubutton(bprops + UPix::colors + "TranspTool" 
		+ ucall(this, 1, &TTMain::addTool))
     + ubutton(bprops + UPix::cross + "CrossTool" 
		+ ucall(this, 2, &TTMain::addTool))
     + ubutton(bprops +  UPix::windows + "Small Views" 
		+ ucall(this, &TTMain::makeSmallView))
     );


  UMenu& help_menu = umenu
    (
     UBgcolor::orange + ualpha(0.55)
     + UColor::white
     + ubutton( UBgcolor::none + UOn::enter / UColor::black + "A question?")
     + ubutton( UBgcolor::none + UOn::enter / UColor::black + "What question!")
     );

  UMenubar& mbar = umenubar
    (
     ubutton("File" + file_menu)
     + ubutton("Tools" + tool_menu)
     + ubutton(UPix::question + help_menu)
     );

  /* ==================================================== ======== ======= */
  // Toolbar, MenuBar and FileMenu

  UBox &toolbar = ubar
    (
     uvbox(uvflex()
	   + uhbox(uitem(USymbol::down + ucall(scene_scale, -1, &UScale::incr))
		   + uitem(USymbol::up + ucall(scene_scale, +1, &UScale::incr)))
	   + " Scale "
           )
     + ubutton(UPix::edit + "Notes" 
	       + ucall(this, 0, &TTMain::addTool))
     + ubutton(UPix::colors + "TranspTool" 
	       + ucall(this, 1, &TTMain::addTool))
     + ubutton(UPix::cross + "CrossTool" 
	       + ucall(this, 2, &TTMain::addTool))
     + ubutton(UPix::windows + "Small Views" 
	       + ucall(this, &TTMain::makeSmallView))

     + uhflex() + ulabel("")
     + uright()
     + ubutton(UPix::stop + "Exit" + ucall(0, UAppli::quit))
     );

 /* ==================================================== ======== ======= */
  // Make the StatusBar

  xpos = &ustr("000"); // will set enough space for three digits
  ypos = &ustr("000");
  message = &ustr("Ready");

  statusbar = &uhbox
    (
     uleft()
     + ubox( UMode::canSelect + USymbol::square )
     + uhbox(UBorder::shadowIn + uright() + xpos)
     + uhbox(UBorder::shadowIn + uright() + ypos)
     + uhflex()
     + uhbox(UBorder::shadowIn + " " + "Ready")
     + uleft()
     + ubar(uvcenter() + ubutton(UPix::ray) + ubutton(UPix::edit))
     );

   /* ==================================================== ======== ======= */

  scene = &uvbox(scene_scale);
  char s[100];

  UTable& tab = utable();
  
  for (int r = 0; r < rowCount; r++) {
    UTrow* row = &utrow();
    for (int c = 0; c < colCount; c++) {
      sprintf(s, "row%d, col%d", r, c);
      Cell* cell = new Cell(s);
      cell->add( UOn::mpress / ucall(cell, &Cell::applyTool) );
      row->add(cell);
    }
    tab.add(row);
  }

  scene->add(tab);

  scene->add(new Note("Note", 300, 150));  // Transparent Note
  scene->add(new TTool("", 150, 70));      // Transparent Tool
  scene->add(new CTool("", 20, 20));       // Cross Tool

  // add to the MainWin
  addlist
    (
     uhflex() + utop()
     + mbar 
     + toolbar

     // this block will be justified vertically
     + uvflex()
     + uhbox( uvflex()
	      // 'mainArea' will be adjusted horizontally
	      + uhflex() 
	      + (main_pane
		 = &uscrollpane(uwidth(500) + uheight(350) + scene)
		 )
	      // 'details' width will remain constant
	      + uright()
	      )
     
     + ubottom()
     + statusbar
    );
}

/* ==================================================== [Elc:00] ======= */
/* ==================================================== ======== ======= */

Cell::Cell(const char *s) : UTextbox() {
  addlist(UBgcolor::white + fg + font + uedit() + s);
}

void Cell::applyTool(UEvent& e) {
  const UPropdef* pd = e.getPropdef(TTOOL_FLAG);
  if (pd) {
    UProp*p = pd->getProp();
    if (!p) return;
    UColor* c = null;
    UFont* f = null;
    if ((c = dynamic_cast<UColor*>(p))) fg = *c;
    else if ((f = dynamic_cast<UFont*>(p))) font = *f;
    update();
  }
}

/* ==================================================== [Elc:00] ======= */
/* ==================================================== ======== ======= */

void TTMain::closeSmallView(UEvent&e) {
  UGroup* d = e.getSource();
  d->show(false);
  delete d;
}

void TTMain::makeSmallView() {
  static int no = 0;
  no++;
  char s_title[100];
  sprintf(s_title, "Small View #%d", no);

  UScale *dial_scale = &uscale(-2);
  UDialog &d = udialog
    (
     utitle(s_title)
     + UOn::close / ucall(this, &TTMain::closeSmallView)
     + uhflex() 
     + utop()
     + ubar("Scale:"
	    + ubutton(USymbol::down + ucall(dial_scale, -1, &UScale::incr))
	    + ubutton(USymbol::up + ucall(dial_scale, +1, &UScale::incr))
	    )
     + uvflex()
     + uscrollpane(uwidth(200) + uheight(200) + ubox(*dial_scale + scene))
     );
  add(d);
  d.show(true);
}

void TTMain::moveMouseCB(UEvent& e) {
  xpos->setNum(e.getX());	// conversion int -> str
  ypos->setNum(e.getY());
}

void TTMain::pressMouseCB(UEvent& e) {
  printf("%d, %d\n", e.getX(), e.getY());
}

void TTMain::addTool(int tooltype) {
  static int x = 10, y = 10;
  x += 25;
  y += 25;
  Lens *lens = null;

  switch (tooltype) {
  case 0:
    lens = new Note("Note", x, y);
    break;
  case 1:
    lens = new TTool("", x, y);
    break;
  case 2:
    lens = new CTool("", x, y);
    break;
  default:
    return;
  }

  scene->add(lens);
}

/* ==================================================== ======== ======= */

Lens::Lens(const char* title, u_pos x, u_pos y) {
  pos.set(x,y);

  lens_handle.addlist
    (
     ualpha(0.40) + UBgcolor::navy + UColor::white//+ UOn::arm/UColor::orange
     + UFont::bold + " " + title
     + uhflex()
     + ubox(UMode::ignoreEvents + UBgcolor::none + " ") // padding
     + uright() 
     + ubox(UBgcolor::none + UOn::arm/UColor::orange
	    + " ? "
	    + umenu(ualpha(0.40) 
		    //+ UBgcolor::white + UColor::navy + UFont::bold
		    + UBgcolor::navy + UColor::white + UFont::bold
		    + help_message)
	    )
     + ubox(UBgcolor::none + UOn::arm/UColor::red
	    + "X" + ucall(this, &Lens::deleteLens))
     );

  addlist
    (
     pos
     + UBgcolor::none
     //+ UBorder::etchedIn
     + uhflex()
     + utop()
     + uhbox(UFont::small + " ")
     + lens_handle
     + uvflex()
     );
  
  lens_handle.add(UOn::mpress / ucall(this, &Lens::pressLens));
  lens_handle.add(UOn::mdrag  / ucall(this, &Lens::dragLens));
}

/* ==================================================== ======== ======= */

Note::Note(const char* _title, u_pos x, u_pos y)
: Lens(_title, x, y)
{
  text_color.set(UColor::red);

  help_message.addlist
    (
     UBgcolor::none
     + "You can type, edit, cut, paste"
     + "your notes in this area"
     );

  UBox& inbox = uflowbox
    (
     uheight(100) + uwidth(125)
     + ualpha(0.50) + UBgcolor::wheat
     + uedit()
     + text_color + UFont::bold
     + "you can write your\nnotes here"
     );

  UBox& controls = uhbox
    (
     UFont::x_small
     + ubutton(UBgcolor::black + "  "  + usetref(&text_color, UColor::black))
     + ubutton(UBgcolor::red + "  "    + usetref(&text_color, UColor::red))
     + ubutton(UBgcolor::green + "  "  + usetref(&text_color, UColor::green))
     + ubutton(UBgcolor::navy + "  "   + usetref(&text_color, UColor::navy))
     );

  addlist(inbox + controls);
}

/* ==================================================== [Elc:02] ======= */
/* ==================================================== ======== ======= */

TTool::TTool(const char* _title, u_pos x, u_pos y)
: Lens(_title, x, y)
{
  help_message.addlist
    (
     UBgcolor::none
     + "The CELL under the TRANSPARENT BUTTON"
     + "is changed when clicking on it."
     + "EDITING is possible through the tool"
     );

  UBox& inbox = ubox
    (
     uvspacing(0)

     + uhbox(uhspacing(0)
             + ubutton(ualpha(0.50) +UBgcolor::orange
                       + "   "
                       //+ UOn::preChildEvent / ucallref(this, fgToOrange, &TTool::flag))
                       + UOn::preChildEvent / ucall(this, &UColor::orange, &TTool::flag))
             
             + ubutton(ualpha(0.50) +UBgcolor::red
                       + "   "
                       //+ UOn::preChildEvent / ucallref(this, fgToRed, &TTool::flag))
                       + UOn::preChildEvent / ucall(this, &UColor::red, &TTool::flag))

             + ubutton(ualpha(0.40) + UBgcolor::grey
                       + UColor::navy
                       + UFont::x_large + UFont::normal + "A"
                       //+ UOn::preChildEvent / ucallref(this, fontToNormal, &TTool::flag))
                       + UOn::preChildEvent / ucall(this, &UFont::normal, &TTool::flag))

             + ubutton(ualpha(0.40) + UBgcolor::grey
                       + UColor::navy
                       + UFont::x_large + UFont::bold + "A"
                       //+ UOn::preChildEvent / ucallref(this, fontToBold, &TTool::flag))
                       + UOn::preChildEvent / ucall(this, &UFont::bold, &TTool::flag))
	     )

     + uhbox(uhspacing(0)
	     + ubutton(ualpha(0.50) + UBgcolor::green
		       + "   "
                //+ UOn::preChildEvent / ucallref(this, fgToGreen, &TTool::flag))
                + UOn::preChildEvent / ucall(this, &UColor::green, &TTool::flag))
     
	     + ubutton(ualpha(0.50) +UBgcolor::navy
                + "   "
                //+ UOn::preChildEvent / ucallref(this, fgToBlue, &TTool::flag))
                + UOn::preChildEvent / ucall(this, &UColor::blue, &TTool::flag))
	       
	     + ubutton(ualpha(0.40) + UBgcolor::grey // +UColor::white 
		       + UColor::navy
		       + UFont::x_large + UFont::italic + "A"
                //+ UOn::preChildEvent / ucallref(this, fontToItalic, &TTool::flag))
                + UOn::preChildEvent / ucall(this, &UFont::italic, &TTool::flag))
             )
     );
  
  add(inbox);
}

// ==========================================================================

CTool::CTool(const char* _title, u_pos x, u_pos y)
: Lens(_title, x, y)
{
  help_message.addlist
    (
     UBgcolor::none
     + "The CELL under the CROSS is changed"
     + "when clicking on TRANSPARENT BUTTON."
     + "EDITING is possible through the tool"
     );

  UBox& inbox = ubox
    (
     uvspacing(0)
     + UFont::large 
     + UColor::navy

     + uhbox(uhspacing(0)
             + ubutton(ualpha(0.50) + UBgcolor::orange
                       + "   "
                       //+ UOn::preChildEvent / ucallref(this, fgToOrange, &CTool::flag))
                       + UOn::preChildEvent / ucall(this, &UColor::orange, &CTool::flag))

             + ubutton(ualpha(0.50) + UBgcolor::red
                       + "   "
                       //+ UOn::preChildEvent / ucallref(this, fgToRed, &CTool::flag))
                       + UOn::preChildEvent / ucall(this, &UColor::red, &CTool::flag))

             + ubutton(ualpha(0.50) + UBgcolor::white //black + UColor::white
                       + UFont::bold + "A"
                       //+ UOn::preChildEvent / ucallref(this, fontToBold, &CTool::flag))
                       + UOn::preChildEvent / ucall(this, &UFont::bold, &CTool::flag))

             + ubutton(ualpha(0.50) + UBgcolor::white //black + UColor::white
                       + UFont::italic + "A"
                       //+ UOn::preChildEvent / ucallref(this, fontToItalic, &CTool::flag))
                       + UOn::preChildEvent / ucall(this, &UFont::italic, &CTool::flag))
	     )

     + uhbox(uhspacing(0)
	     + ubutton(ualpha(0.50) + UBgcolor::green
		       + "   "
                //+ UOn::preChildEvent / ucallref(this, fgToGreen,&CTool::flag))
                + UOn::preChildEvent / ucall(this, &UColor::green, &CTool::flag))
	    
	     + ubutton(ualpha(0.50) + UBgcolor::navy
                + "   "
                // + UOn::preChildEvent / ucallref(this, fgToBlue, &CTool::flag))
                + UOn::preChildEvent / ucall(this, &UColor::blue, &CTool::flag))
	    
	     + ubutton(ualpha(0.50) + UBgcolor::white
		       + UFont::normal + "A"
                //+ UOn::preChildEvent / ucallref(this, fontToNormal, &CTool::flag))
                + UOn::preChildEvent / ucall(this, &UFont::normal, &CTool::flag))
	    )
     );

  // cette boite sert de calque pour pouyvoir reafficher automatiquement la croix
  // cette boite est transparente visuellement et transparente aux events
  crossbox.addlist(uheight(50)
		   // transparence visuelle 
		   + UBgcolor::none
		   // transparence aux events
                   //+ UOn::preChildEvent / ucallref(this, UFlag::none, &CTool::flag)
                   + UOn::preChildEvent / ucall(this, (UProp*)0, &CTool::flag)
		   + UOn::viewPaint / ucall(this, &CTool::paintCross)
		   );

  addlist(inbox + crossbox);
}

/* ==================================================== [Elc:03] ======= */
/* ==================================================== ======== ======= */

void Lens::deleteLens(UEvent&) {
  show(false);
  delete(this);
}

void Lens::pressLens(UEvent& e) {
  last_x = e.getXwin();
  last_y = e.getYwin();
}

void Lens::dragLens(UEvent& e) {
  u_pos delta_x = e.getXwin() - last_x;
  u_pos delta_y = e.getYwin() - last_y;

  // position precedente + ajouter le deplacement
  pos.set(pos.getX() + delta_x, pos.getY() + delta_y);
  last_x = e.getXwin();
  last_y = e.getYwin();
}

/* ==================================================== ======== ======= */

void TTool::flag(UEvent& e, UColor* prop) {flag(e, (UProp*)prop);}

void TTool::flag(UEvent& e, UFont* prop) {flag(e, (UProp*)prop);}

void TTool::flag(UEvent& e, UProp* prop) {
  static UPropdef pdef(TTOOL_FLAG);

  // Events will go through the TTool
  e.goThrough(this);
  
  // mpress events are flagged
  //if (&f != &UFlag::none && e.getID() == UEvent::mpress)  {
  if (prop != null && e.getID() == UEvent::mpress)  {
    pdef.set(prop);
    e.addFlagdef(&pdef);
  }
}

/* ==================================================== ======== ======= */

void CTool::flag(UEvent& e, UColor* prop) {flag(e, (UProp*)prop);}

void CTool::flag(UEvent& e, UFont* prop) {flag(e, (UProp*)prop);}

void CTool::flag(UEvent& e, UProp* prop) {
  static UPropdef pdef(TTOOL_FLAG);

  // Events will go through the TTool
  e.goThrough(this);

  // Press mouse events are flagged
  // and the mouse position is modified so that the object
  // that receive the event will "believe" that this event
  // was generated under the tool Cross
 
  // mpress events are flagged
 // if (&f != &UFlag::none && e.getID() == UEvent::mpress) {
  if (prop != null && e.getID() == UEvent::mpress)  {

    pdef.set(prop);
    e.addFlagdef(&pdef);
    
    // returns the Tool's View that contains the Event location
    UView *tool_v = this->getViewContaining(e);

    // returns the Cross' View that is inside the Tool's View
    UView* cross_v = crossbox.getFirstViewInside(tool_v);

    // change mouse coordinates so that unlerlying objects
    // will think this event was produced in the middle 
    // of the cross (which is in the middle of crossbox)

    if (cross_v) e.setMouse(cross_v->getXwin() + cross_v->getWidth()/2,
		       cross_v->getYwin() + cross_v->getHeight()/2);
  }
}

void CTool::paintCross(UEvent& e) {
  UView *v = e.getView();
  UGraph g(v);
  g.setColor(&UColor::red);
  g.setThickness(2);

  // the cross is in the middle of the crossbox
  u_pos xcenter = v->getWidth() / 2;
  u_pos ycenter = v->getHeight() / 2;
  u_dim len = v->getHeight() / 4;
  g.drawLine(xcenter-len, ycenter, xcenter+len, ycenter);
  g.drawLine(xcenter, ycenter-len, xcenter, ycenter+len);
}

/* ==================================================== [Elc:02] ======= */
/* ==================================================== ======== ======= */
