#include <ubit/ubit.hpp>
#include <ubit/ugraph.hpp>    // needed for graphics
#include <vector>
using namespace std;

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

class Drawing : public UAppli {
  struct Point {
    int x, y;
  };

  vector<Point> points;
  Point last_point;

  UColor brush_color;
  UBgcolor canvas_color;

  void mousePressed(UEvent&);
  void mouseDragged(UEvent&);
  // sert a reafficher le dessin qunad on passe une fenetre par dessus
  void repaintGraphics(UEvent&);

public:
  Drawing(int* argc, char* argv[]);
};

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

int main(int argc, char* argv[]) {
  Drawing appli(&argc, argv);
  return appli.mainLoop();
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// classe de boutons qui changent la valeur de 'color_ref':

class MyButton : public UCheckbox {
public:
  MyButton(const char* name,
	   URadioSelect& bgroup, // passage par reference: ne pas oublier les &
	   UColor& color_ref, 
	   UColor& color_val) {

    addlist(name 
	    // ajouter chaque bouton au RadioGroup pour le rendre exclusif
	    + bgroup 
	    // fonction de callback simplifiee
	    // !!ATTENTION: le 1er arg de 'uset()' doit etre un pointeur
	    + uset(&color_ref, color_val)
	    );
  }
};

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
// classe principale:
// NOTE: on va maintenant rendre le graphique persistant

Drawing::Drawing(int* argc, char* argv[]) : UAppli(argc, argv) 
{
  canvas_color.set(UColor::white);
  brush_color.set(UColor::black);

  // Zone de dessin :
  UBox& canvas = ubox
    (
     canvas_color		    // fond blanc puis variable
     + uwidth(400) + uheight(400)   // affecter une taille
     // ajout des fonctions de callback
     + UOn::mpress / ucall(this, &Drawing::mousePressed)
     + UOn::mdrag  / ucall(this, &Drawing::mouseDragged)
     // rafraichissement
     + UOn::viewPaint / ucall(this, &Drawing::repaintGraphics)
     );

  // cet objet rendra les RadioButtons exclusifs
  URadioSelect& bgroup1 = uradioSelect();

  // Panel contenant les RadioButtons qui changent la couleur
  // du background
  UBox& panel1 = ubar
    (
     uhcenter() + uvmargin(5)
     + ulabel(UFont::bold + "Background Color: ")
     + new MyButton("Noir",  bgroup1, canvas_color, UColor::black)
     + new MyButton("White", bgroup1, canvas_color, UColor::white)
     + new MyButton("Jaune", bgroup1, canvas_color, UColor::yellow)
     + new MyButton("Rouge", bgroup1, canvas_color, UColor::red)
     + new MyButton("Vert",  bgroup1, canvas_color, UColor::green)
     );

  // cet objet rendra les RadioButtons exclusifs
  URadioSelect& bgroup2 = uradioSelect();

  // Panel contenant les RadioButtons qui changent la couleur
  // du foreground
  UBox& panel2 = ubar
    (
     uhcenter() + uvmargin(5)
     + ulabel("Foreround Color: ")
     + new MyButton("Noir",  bgroup2, brush_color, UColor::black)
     + new MyButton("White", bgroup2, brush_color, UColor::white)
     + new MyButton("Jaune", bgroup2, brush_color, UColor::yellow)
     + new MyButton("Rouge", bgroup2, brush_color, UColor::red)
     + new MyButton("Vert",  bgroup2, brush_color, UColor::green)
     );

  UFrame& frame = uframe
  (
   utop()
   + panel1 
   + uvflex()
   + uscrollpane(canvas)
   + ubottom()
   + panel2
   );

  add(frame);
  frame.show(true);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

void Drawing::mousePressed(UEvent& e) {
  UGraph g(e);

  // remet le vecteur a 0 (NB: faire AVANT le clearView car ce dernier
  // provoque un appel de repaintGraphics)
  points.clear();

  // efface tout (puis reaffiche le fond si l'argument est true)
  // NOTE: ca va provoquer un "flicker". pour eviter cet effet il faudrait
  // reafficher en XOR pour effacer ou bien afficher en double buffering
  g.clearView(true);

  last_point.x = e.getX();
  last_point.y = e.getY();
  points.push_back(last_point);
}

// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 

void Drawing::mouseDragged(UEvent& e) {
  UGraph g(e);

  // g prendra la couleur de brush_color
  g.setColor(brush_color);
  int x = e.getX();
  int y = e.getY();

  g.drawLine(last_point.x, last_point.y, x, y);
  last_point.x = x;
  last_point.y = y;
  points.push_back(last_point);
}

void Drawing::repaintGraphics(UEvent& e) {
  UGraph g(e);

  for (unsigned int i=1; i < points.size(); i++)
    g.drawLine(points[i-1].x, points[i-1].y, points[i].x, points[i].y);
}


