/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/***************************************************************************
 *            widget.cc
 *
 *  Sun Oct  9 13:01:44 CEST 2011
 *  Copyright 2011 Bent Bisballe Nyeng
 *  deva@aasimon.org
 ****************************************************************************/

/*
 *  This file is part of DrumGizmo.
 *
 *  DrumGizmo is free software; 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.
 *
 *  DrumGizmo is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with DrumGizmo; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
 */
#include "widget.h"

#include "painter.h"
#include "window.h"

#include <stdio.h>

GUI::Widget::Widget(Widget *parent)
  : pixbuf(1, 1)
{
  _width = _height = 10;

  this->parent = parent;
  if(parent) {
    parent->addChild(this);
    _window = parent->window();
  }
  _width = _height = 0;
  _visible = true;
}

GUI::Widget::~Widget()
{
  if(parent) parent->removeChild(this);
}

void GUI::Widget::show()
{
  setVisible(true);
}

void GUI::Widget::hide()
{
  setVisible(false);
}

void GUI::Widget::setVisible(bool v)
{
  _visible = v;
  repaintEvent(NULL);
}

bool GUI::Widget::visible()
{
  return _visible;
}

void GUI::Widget::addChild(GUI::Widget *widget)
{
  children.push_back(widget);
}

void GUI::Widget::removeChild(GUI::Widget *widget)
{
  std::vector<Widget *>::iterator i = children.begin();
  while(i != children.end()) {
    if(*i == widget) {
      children.erase(i);
      return;
    }
    i++;
  }
}

void GUI::Widget::resize(int width, int height)
{
  if(width < 1 || height < 1) return;
  _width = width;
  _height = height;
  pixbuf.realloc(width, height);
}

void GUI::Widget::move(size_t x, size_t y)
{
  _x = x;
  _y = y;
}

size_t GUI::Widget::x() { return _x; }
size_t GUI::Widget::y() { return _y; }
size_t GUI::Widget::width() { return _width; }
size_t GUI::Widget::height() { return _height; }

size_t GUI::Widget::windowX()
{
  size_t window_x = x();
  if(parent) window_x += parent->windowX();
  return window_x;
}

size_t GUI::Widget::windowY()
{
  size_t window_y = y();
  if(parent) window_y += parent->windowY();
  return window_y;
}

GUI::Widget *GUI::Widget::find(size_t x, size_t y)
{
  std::vector<Widget*>::reverse_iterator i = children.rbegin();
  while(i != children.rend()) {
    Widget *w = *i;
    if(w->visible()) {
      if(w->x() <= x && (w->x() + w->width()) >= x &&
         w->y() <= y && w->y() + w->height() >= y)
        return w->find(x - w->x(), y - w->y());
    }
    i++;
  }

  if(x > width() || x < 0 || y > height() || y < 0) return NULL;
  return this;
}

GUI::Window *GUI::Widget::window()
{
  return _window;
}

void GUI::Widget::repaint_r(GUI::RepaintEvent *e)
{
  Painter p(this); // make sure pixbuf refcount is incremented.

  repaintEvent(e);

  std::vector<Widget*>::iterator i = children.begin();
  while(i != children.end()) {
    Widget *w = *i;
    w->repaint_r(e);
    i++;
  }
}

std::vector<GUI::PixelBufferAlpha *> GUI::Widget::getPixelBuffers()
{
  std::vector<PixelBufferAlpha *> pbs;

  pixbuf.x = windowX();
  pixbuf.y = windowY();

  pbs.push_back(&pixbuf);

  std::vector<Widget*>::iterator i = children.begin();
  while(i != children.end()) {
    Widget *w = *i;
    if(w->visible()) {
      std::vector<PixelBufferAlpha *> pbs0 = w->getPixelBuffers();
      pbs.insert(pbs.end(), pbs0.begin(), pbs0.end());
    }
    i++;
  }

  return pbs;
}

bool GUI::Widget::hasKeyboardFocus()
{
  return window()->keyboardFocus() == this;
}

#ifdef TEST_WIDGET
//deps: window.cc globalcontext.cc
//cflags:
//libs:
#include "test.h"

#include "window.h"

TEST_BEGIN;

GUI::Window w1(NULL);
w1.move(0,0);
w1.resize(100, 100);

GUI::Widget w2(&w1);
w2.resize(40,40);
w2.move(10,10);

GUI::Widget w3(&w2);
w3.resize(20,20);
w3.move(10,10);

TEST_EQUAL_PTR(w1.find(101,0), NULL, "Miss?");
TEST_EQUAL_PTR(w1.find(0,0), &w1, "Hit w1?");
TEST_EQUAL_PTR(w1.find(100,100), &w1, "Hit w1?");
TEST_EQUAL_PTR(w1.find(0,0), &w1, "Hit w1?");
TEST_EQUAL_PTR(w1.find(11,11), &w2, "Hit w2?");
TEST_EQUAL_PTR(w1.find(22,22), &w3, "Hit w3?");

TEST_END;

#endif/*TEST_WIDGET*/