/* ==================================================== ======== ======= *
 *
 *  dtext.cc  [demo]
 *  Ubit Project [Elc::99]
 *  Author: Eric Lecolinet
 *
 *  Part of the Ubit System: A Visual+Textual Environment for Building GUIs.
 *
 *  (C) 1999 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 WARANTY 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:99] ======= *
 * ==================================================== ======== ======= */

#include <ubit/ubit.hpp>
#include "dmisc.hh"
#include "dtext.hh"


TextDialog::TextDialog() : myfont(UFont::normal), mycolor(UColor::orange) { 

  // will be included inside 'body'
  UScrollpane &included_pane =	// vertical scrollbar only
    uscrollpane
    (
     true, false, 
     uheight(150) + uwidth(200)
     + uvbox(ubutton("four") 
	     + ubutton("five") 
	     + ubutton("six") 
	     + uhbox(ubutton(ubit_pix + "truc")
		     + ucheckbox(UPix::ray + "truc")
		     + ubutton(UPix::folder + "truc")
		     )
	     + utextbox(uedit() + UColor::blue+ "mytext")
	     + ubutton("height") 
	     + ubutton("nine") 
	     + ubutton("ten") 
	     + ubutton("eleven") 
	     + ubutton("twelve") 
	     )
     );

  UStr *svalue = &ustr(" 0");
  
  UVbox &bottomControls = uvbox
    ( 
     UBorder::etchedOut + uhflex() + UBgcolor::lightgrey
     + uhbox(" Selection: " + uhflex() + utextbox(mess))
      
     + uhbox
      (
       UColor::black + " Font:  "
       + ulinkbutton("Normal"
	       + ucall(this, &UFont::normal, &TextDialog::setFont))
       + ulinkbutton(UFont::bold + "Bold"
	       + ucall(this, &UFont::bold, &TextDialog::setFont))
       + ulinkbutton(UFont::italic + "Italic" 
	       + ucall(this, &UFont::italic, &TextDialog::setFont))
       + "  Custom: "
       + uhflex() // H justify the text field
       + utextbox(uedit() + fontname + ucall(this, (UFont*)0, &TextDialog::setFont))
       + uright()
       + ubutton("Set" + ucall(this, (UFont*)0, &TextDialog::setFont))
       )
       
     + uhbox
      (
       uvcenter() + " Color: " 
       + ulinkbutton(UColor::red + " Red "
		+ ucall(this, &UColor::red, &TextDialog::setColor))
       + ulinkbutton(UColor::blue + " Blue "
	       + ucall(this, &UColor::blue, &TextDialog::setColor))
       + ulinkbutton(UColor::orange + "Yellow"
	       + ucall(this, &UColor::yellow, &TextDialog::setColor))
       + ulinkbutton(UColor::green + "Green"
	       + ucall(this, &UColor::green, &TextDialog::setColor))
       + " Custom: "
       + uhflex()
       + utextbox(uedit() + colorname
		  + ucall(this, (UColor*)0, &TextDialog::setColor))
       + uright()
       + ubutton("Set" + ucall(this, (UColor*)0, &TextDialog::setColor))
       )

     + uhbox
     (
      uvcenter() + " Scale:  " + svalue
      // !att: ucall() peut etre appele avant ce qui precede => se mefier
      // car on lui passe une reference!
      + ubutton(UBgcolor::blue + UColor::white
		+ " - "
		+ ucall(this, -1, svalue, &TextDialog::setScale))
      + ubutton(UBgcolor::orange + UColor::white
		+ " + " 
		+ ucall(this, +1, svalue, &TextDialog::setScale))
      )
     );

  body.addlist
    ( 
     uedit()   // makes text editable
     + scale
     + UFlowView::style // flow layout
     + UOn::mpress   / ucall(this, &TextDialog::clickOnText)
     + UOn::mrelease / ucall(this, &TextDialog::clickOnText)
		     
     + UFont::bold
     + "A " + ulinkbutton(bricks_pix + "Brick"  )
     + "Construction Game Model"
     + UFont::_bold
     + " for creating" + UPix::cross
     + UFont::italic + UColor::red + "Graphical User Interfaces" + UFont::_italic
     + UPix::cross
     + ulabel(UBgcolor::yellow + UFont::bold + eyes_pix + "Search:") 
     
     + shared->shtext // shared textfield
     
     + UColor::navy
     + myfont
     + "\naaaaaa bbbbbbbbbbbb cccccccc ccccccccc ddddddd dddddd"
     + "aaaaaa bbbbbbbbbbbbbbbbb\ncccccccccccc ccccccccccccccc cccccccccccccccccccc\ndddddddddddddddd ddddddddddddddddd dddddddd eeeeeeeeeee eeeeeee eeeeeee eeeeeeee eeeeeeeee" + "xxxxx"
     + UColor::green + UFont::bold +
     + "eeeeeee FFFFF "
     +  UColor::black + UFont::italic 
     + ubutton("clic clic")
     + UFont::_bold
     + "OOOOOOO ooooooo ooooooo .......\nxxxxxxx" 
     + UFont::_italic
     + " " + UPix::diskette + "ggggg gggggg"
     
     + included_pane


     + "blah blah blablah blbblah blah lblah blah blah blah\n ah blah ah blah bblah blah lah h blblah blah " 
     + UFont::bold + UColor::orange + "BOLD ah bblah blah blah blah lablah blah h blah blah blah blah bblah blah l\nah blah blah blah blah blah blah \nblah blah blah blah" 
     + UFont::_bold + UColor::blue + "bblahblah blah  blah lah blah blah bblah blah lah "
     );

  // make initial value large enough (see UWidth::keepSize below)
  xpos.set("000");
  ypos.set("000");

  // add to the Dialog
  addlist
    (
     utitle("Text and misc. included objects")
     //+ scale
     + uhflex()
     + utop()
     + uhbox( UBorder::shadowOut
	      + uhflex()
	      + ulabel( UColor::red + UFont::bold + UFont::italic
			+ UPix::ray + UPix::ray + UPix::ray
			+ "Press, Drag then Release on text to create a Mark "
			)
	      + uright()
	      // UWidth::keepSize => will keep its initial size (ie. the size
	      // for containing "x:" and the initial value of xpos
	      //+ uhbox(UBorder::shadowIn + uwidth(UWidth::keepSize)+ "x:" + xpos)
	      //+ uhbox(UBorder::shadowIn + uwidth(UWidth::keepSize)+ "y:" + ypos)
	      + utextbox(uwidth(40) + "x:" + xpos)
	      + utextbox(uwidth(40) + "y:" + ypos)
	      )
     
       // the scrollpane will be justified
     + uvflex()
     + uscrollpane(true, false,
		   uheight(200)
		   + uhbox(uleft() + uvflex()
			   + UBgcolor::none
			   // adds the left margin
			   + marge.addlist
			   (
			    mycolor + uwidth(35)
			    //on ajoute selectedMark a la marge
			    // pour 2 raisons qui sont expliquee
			    // en debut de texte
			    + selectedMark
			    )
			   
			   + uhflex() // body is H justified
			   + body

			   // ajouter le transparent_postit a la page de texte
			   + shared->transparent_postit
			   )
		   )
     
     + utop()		// not V justified
     + bottomControls
     
     + uhbox(uhcenter()
	      // closes the dialog box when Close is clicked
	     + ubutton( UPix::cross + "Close" + ucloseWin())
	     + ubutton("List Marks" + ucall(this, &TextDialog::listMarks))
	     + ubutton("Del Mark" + ucall(this, &TextDialog::delMark))
	     )
     );
}

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

void TextDialog::setScale(int incr, UStr *s) {
  scale.incr(incr);
  s->setNum(scale.getValue());
}

void TextDialog::clickOnText(UEvent& e) {
  UGroup *grp = e.getSource();
  UStr *str = e.getStr();
  const char *evname;

  if (e.getID() == UEvent::mpress) evname = "Press";
  else if (e.getID() == UEvent::mrelease) evname = "Release";
  else if (e.getID() == UEvent::mmove) evname = "Move";
  else evname = "Unknown";

  if (!grp || !str) return;

  if (e.getID() == UEvent::mpress) {
    xpos.setNum(e.getX());	// conversion int -> str
    ypos.setNum(e.getY());
  }

  else if (e.getID() == UEvent::mrelease) {
    if (str) mess.set(*str);

#if KKKK
    if (itd.str && itd.str == lastStr && itd.strpos > lastPos
	&& itd.exactMatch	// !!!ATTENTION
	) {
      //printf("# Add mark (pos = (%d, %d)\n", itd.region.x, itd.region.y);

      // find position of itd.str in the container child list
      int pos = body.getChildPos(itd.str);
      if (pos < 0) return; ///not found

      // split itd.str into 2 parts
      UStr *s2 = itd.str->_split(lastPos);
      //printf("--s2: '%s'\n", s2 ? s2->chars() : "NULL");
      if (s2) {
	// split s2 into 2 parts
	UStr *s3 = s2->_split(itd.strpos);

	body.add(&UColor::red, pos+1);
	body.add(s2, pos+2);
	body.add(&UColor::black, pos+3);
	if (s3) body.add(s3, pos+4);

	body.update(); // essentiel!
      }
      
      addMark(e, &itd);
    }
#endif
  }
}

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

void TextDialog::addMark(UStr *str, int y) {
  marge.add(new TextMark(this, 2, y, str, null, null));
  // update() must be explicitely called after add()
  marge.update();
}

void TextDialog::listMarks(UEvent&e) {
  UBrick **children = marge.getChildren(); // null terminated list
  
  // scans the children of the box
  for (int k = 0; children[k] != null; k++)
    if (children[k]->boxCast()) {
      TextMark *tm = (TextMark*)children[k];
      printf("==TextMark #%d - tmark=%s\n\n",
	     tm->no, (tm->markstr ? tm->markstr->chars() : "Null"));
    }

  delete [] children;
}


void TextDialog::setFont(UEvent&e, UFont*f) {
  // change la fonte courante de myfont
  myfont.set(*f);
}


void TextDialog::setColor(UEvent&e, UColor *c) {

  if (!c) { // recuperer le nom

    const char* cname = colorname.chars();
    if (!cname || !*cname) return;

    printf(">colname = '%s'\n", cname);

    // il faudrait verifier qu'on n'alloue pas plusieurs fois la meme color
    // (pour des raisons de performance)

    c = new UColor(cname); 
    if (!c) {
      printf("! colname = '%s' not found\n", cname);
      return;
    }

    // realize prend en arg le dispc (display context)
    // ou appc (appli context)
    c->realize(e.getView()->getDisp());  //!OBSOLETE: to be changed!
  }
  
  mycolor.set(*c);
}

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

TextMark::TextMark(TextDialog *td, u_pos x, u_pos y,
		   UStr *initial_s, UStr* marked_s, UStr *remaining_s)
  : UHbox() {
  static int numero = 0;
  no = numero++;
  tdial = td;
  markstr = initial_s;
  UStr& str = ustr(); str.setNum(no);

  // add children to Texmark
  addlist
    (
     UMode::canSelect    // will have a state like a Checkbox
     + upos(x, y)
     + td->selectedMark  // marks will be exclusive
     + USymbol::square
     + UFont::small + str
     + USymbol::right + ucall(this, &TextMark::clickOnMark)
     );
}


TextMark::~TextMark(){
  tdial->marge.remove(this, false);
  /*
  if (colstart) {
    tdial->body.remove(colstart);
    delete colstart;
  }

  if (colend) {
    tdial->body.remove(colend);
    delete colend;
  }
  */
}


void TextMark::clickOnMark(UEvent&) {
  const char *s = (markstr ? markstr->chars() : "Null");
  // s not copied! (internal representation)
  printf("==TextMark #%d - tmark=%s\n\n", no, s);
  tdial->mess.set(s);
}


void TextDialog::delMark(UEvent&) {
  if (selectedMark.getItem()) {
    delete selectedMark.getItem();
    update();
  }
}


/* ==================================================== [TheEnd] ======= */
/* ==================================================== [Elc:99] ======= */
