/*
* widget.cc
* DIN Is Noise is copyright (c) 2006-2024 Jagannathan Sampath
* For more information, please visit https://dinisnoise.org/
*/

#include "widget.h"
#include "viewwin.h"
#include "tokenizer.h"
#include "input.h"
#include "basic_editor.h"
#include "container.h"
#include "file-utils.h"

#include <vector>
#include <fstream>
#include <string>
#include <sstream>

using namespace std;

extern int mousex, mouseyy;
extern int lmb, mmb, rmb;
extern viewport view;

widget::widget (int left, int bottom, int right, int top) : extents (left, bottom, right, top), clr (R, G, B), movr (this) {
	id = 0;
	size = -1;
  posx = posy = 0;
	hover = 0;
  enabled = 1;
  visible = 1;
	moveable = 0;
	movlis = 0;
  numchil = 0;
  nametothis ();
}

widget::~widget () {}

void widget::set_name (const std::string& _name) {
  stringstream ss (_name);
  string word;
  name = "";
  while (ss.eof () == 0) {
    ss >> word;
    name = name + '-' + word;
  }
}

void widget::nametothis () {
  stringstream ss; ss << this; ss >> name;
}

int widget::handle_input () {
  int movr_result = 0; if (moveable) movr_result = movr.handle_input ();
	if (inbox (extents, mousex, mouseyy)) hover = 1; else hover = 0;
  int widget_handled = hover | movr_result;
	basic_editor::hide_cursor += widget_handled;

#ifdef __WIDGET_MOVE__
  if (keypressed (SDLK_LALT)) {if (hover) dg = !dg;}
#endif
  return widget_handled;
}

#ifdef __WIDGET_MOVE__
void widget::draw_guides () {

	glColor3f (0.2, 0.2, 0.2);
  const box<int>& e = extents;
  bb[0]=e.left;bb[1]=view.ymax;
  bb[2]=e.left;bb[3]=0;
  bb[4]=e.right;bb[5]=view.ymax;
  bb[6]=e.right;bb[7]=0;
	bb[8]=0; bb[9]=e.bottom;
	bb[10]=view.xmax; bb[11]=e.bottom;
	bb[12]=0; bb[13]=e.top;
	bb[14]=view.xmax; bb[15]=e.top;
  glVertexPointer (2, GL_INT, 0, bb);
  glDrawArrays (GL_LINES, 0, 8);

}
#endif

void widget::draw_bbox () {
  const box<int>& e = extents;
  bb[0]=e.left;bb[1]=e.bottom;
  bb[2]=e.right;bb[3]=e.bottom;
  bb[4]=e.right;bb[5]=e.top;
  bb[6]=e.left;bb[7]=e.top;
	glColor3f (clr.r, clr.g, clr.b);
  glVertexPointer (2, GL_INT, 0, bb);
  glDrawArrays (GL_LINE_LOOP, 0, 4);
}

void widget::fill_bbox (float a, int g) {
	const box<int>& e = extents;
  glEnable (GL_BLEND);
  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glColor4f (clr.r, clr.g, clr.b, a);
    glRecti (e.left-g, e.bottom-g, e.right+g, e.top+g);
  glDisable (GL_BLEND);
}

void widget::draw_and_fill_bbox () {
  fill_bbox ();
  draw_bbox ();
}

void widget::set_pos (int x, int y) {
  posx = x;
  posy = y;
  set_extents (x, y, x + extents.width, y + extents.height);
}

void widget::set_extents (int l, int b, int r, int t) {
  extents (l, b, r, t);
}

void widget::set_moveable (int m, int mc, int* pmb) {
	moveable = m; 
	if (mc) {
		if (numchil) for (int i = 0; i < numchil; ++i) children[i]->set_moveable (m, mc, pmb);
	}
	movr.pmb = pmb;
}

void widget::move (int dx, int dy, int mc) {
	if (mc && numchil) 
    for (int i = 0; i < numchil; ++i) children[i]->move (dx, dy);
  set_pos (posx + dx, posy + dy);
}

void widget::show () {
  visible = 1;
  if (numchil) 
    for (int i = 0; i < numchil; ++i) children[i]->show ();
}

void widget::hide (int what) {
  if (what == all) visible = 0;
  if (numchil) 
    for (int i = 0; i < numchil; ++i) children[i]->hide ();
}

void widget::add_child (widget* w) {
  children.push_back (w);
  ++numchil;
}

void widget::remove_child (widget* w) {
	numchil -= erase (children, w);
}

void widget::swapchild (widget* w1, widget* w2) {
  remove_child (w1);
  add_child (w2);
}

void widget::load (ifstream& file) {
  file >> name >> posx >> posy;
  set_pos (posx, posy);
}

void widget::save (ofstream& file) {
  file << name << ' ' << posx << ' ' << posy << endl;
}

mover::mover (widget* _w, int* _pmb) : w (_w){
  pmb = _pmb;
}

int mover::handle_input () {
  int ret = 0;
  int mb = *pmb;
  if (mb) {
    if (mb_clicked == 0) {
      if (move) {
        move = 0;
        widget::focus = 0;
        ret = 1;
        move_listener* wm = w->movlis;
        if (wm) wm->endmove ();
      } else if (w->hover) {
        move = 1;
        widget::focus = w;
        prevx = mousex;
        prevy = mouseyy;
        move_listener* wm = w->movlis;
        if (wm) wm->movestart ();
        ret = 1;
      }
      mb_clicked = 1;
    }
  } else {
    if (move) {
      int dx = mousex - prevx, dy = mouseyy - prevy;
			if (SHIFT) 
				w->move (0, dy); 
			else if (CTRL) 
				w->move (dx, 0);
			else 
      	w->move (dx, dy);
      prevx = mousex; prevy = mouseyy;
      move_listener* wm = w->movlis;
      if (wm) wm->moved ();
      ret = 1;
    }
    mb_clicked = 0;
  }
  return ret;
}

void widget::set_color (float r, float g, float b) {
  clr.r = r;
  clr.g = g;
  clr.b = b;
}

void widget::set_color (unsigned char ur, unsigned char ug, unsigned char ub) {
  float r, g, b; hex2rgb (ur, ug, ub, r, g, b); set_color (r, g, b);
}

void widget::enable () {
	enabled = 1;
	set_color (R, G, B);
}

void widget::disable () {
	enabled = 0;
	set_color (0.5f, 0.5f, 0.5f);
}


void widget_load (const std::string& fname, std::vector<widget*>& vec) {
	file_in fi (fname);
	ifstream& f = fi();
  for (int i = 0, j = vec.size (); i < j; ++i) vec[i]->load (f);
}

void widget_load (const string& fname, widget** pw, int n) {
	file_in fi (fname);
	ifstream& f = fi ();
	for (int i = 0; i < n; ++i) pw[i]->load (f);
}

void widget_save (const std::string& fname, std::vector<widget*>& vec) {
	file_out fo (fname);
	ofstream& f = fo ();
  for (int i = 0, j = vec.size (); i < j; ++i) vec[i]->save (f);
}

void widget_save (const string& fname, widget** pw, int n) {
	file_out fo (fname);
	ofstream& f = fo ();
	for (int i = 0; i < n; ++i) pw[i]->save (f);
}

is_lmb_t::is_lmb_t () { tie = 0; }

int is_lmb_t::operator() (widget* w) {
	if (tie == 0) return lmb;
	else {
		if (tie == w) 
			return lmb; 
		else 
			return 0;
	}
}

void is_lmb_t::clear (widget* _tie) {
	if (tie) {
		if (_tie == 0 || tie == _tie)
			tie = 0;
	}
}

void set_focus (widget* w) {
	if (widget::focus == 0) 
		widget::focus = w;
	else if (widget::focus != w) 
		widget::next_focus = w;
}

void defocus () {
	widget::focus = widget::next_focus;
	widget::next_focus = 0;
}

void defocus (widget* w) {
	if (widget::focus == w) {
		widget::focus = widget::next_focus;
		widget::next_focus = 0;
	}
}

void makehier (widget** wa) {
  for (widget** p = wa;;) {
    widget* wi = *p++;
    if (*p != 0) {
      widget* wj = *p;
      wi->add_child (wj);
    } else break;
  }
}

void makefam (widget** wa) {
  widget* p = wa[0];
  for (widget** q = ++wa;;) {
    widget* c = *q++;
    if (c) p->add_child (c); else break;
  }
}

void makehier (widget** wa, int n) {
	for (int i = 0, j = n - 1; i < j; ++i) {
		widget* wi = wa[i], *wj = wa[i+1];
		wi->add_child (wj);
	}
}

void makefam (widget* parent, widget** children, int n) {
	for (int i = 0; i < n; ++i) parent->add_child (children[i]);
}

void makefam (widget** mem, int n) {
  widget* p = mem[0];
	for (int i = 1; i < n; ++i) p->add_child (mem[i]); 
}

void widget::setpos2 (widget& w) {
  if (w.posx != posx || w.posy != posy) set_pos (w.posx, w.posy);
}

/*void autoincdec::eval () {
  if ( operator()(ui_clk()) ) {
    if (what == INC) {
      pid->increase ();
    } else if (what== DEC) {
      pid->decrease ();
    } else {
      rnd<float> rd (0.0f, 1.0f);
      if (rd() < 0.5f) pid->decrease (); else pid->increase ();
    }
  }
}*/
