// IconListCellRenderer.cc --- Icon list cell renderer
//
// Copyright (C) 2001, 2002, 2003, 2007, 2011, 2013 Rob Caelers & Raymond Penners
// All rights reserved.
//
// This program 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 3 of the License, or
// (at your option) any later version.
//
// This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
//

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <gtk/gtk.h>
#include <gtkmm.h>

#include "debug.hh"

#include "IconListCellRenderer.hh"

#define PAD 3
#define SPACE 5

IconListCellRenderer::IconListCellRenderer()
  : Glib::ObjectBase (typeid(IconListCellRenderer)),
    Gtk::CellRenderer(),
    property_text_   (*this, "text"),
    property_pixbuf_ (*this, "pixbuf")
{
  update_properties();
}

IconListCellRenderer::~IconListCellRenderer()
{}

Glib::PropertyProxy<Glib::ustring> IconListCellRenderer::property_text()
{
  return property_text_.get_proxy();
}

Glib::PropertyProxy<Glib::RefPtr<Gdk::Pixbuf> > IconListCellRenderer::property_pixbuf()
{
  return property_pixbuf_.get_proxy();
}

void
IconListCellRenderer::update_properties()
{
  text_renderer.property_text() = property_text_;
  pixbuf_renderer.property_pixbuf() = property_pixbuf_;
}

#ifdef HAVE_GTK3

void
IconListCellRenderer::get_preferred_width_vfunc(Gtk::Widget &widget, int &minimum_width, int &natural_width) const
{
  TRACE_ENTER("IconListCellRenderer::get_preferred_width_vfunc");
  int text_minimum_width, text_natural_width;
  int pixbuf_minimum_width, pixbuf_natural_width;

  // FIXME:
  const_cast<IconListCellRenderer*>(this)->update_properties();

  text_renderer.get_preferred_width(widget, text_minimum_width, text_natural_width);
  pixbuf_renderer.get_preferred_width(widget, pixbuf_minimum_width, pixbuf_natural_width);

  minimum_width = MAX(text_minimum_width, pixbuf_minimum_width) + 2 * SPACE;
  natural_width = MAX(text_natural_width, pixbuf_natural_width) + 2 * SPACE;
  TRACE_MSG(minimum_width << " " << natural_width);
  TRACE_EXIT();
}

void IconListCellRenderer::get_preferred_height_for_width_vfunc(Gtk::Widget &widget, int width, int &minimum_height, int &natural_height) const
{
  (void) width;
  TRACE_ENTER("IconListCellRenderer::get_preferred_height_for_width_vfunc");
  get_preferred_height_vfunc(widget, minimum_height, natural_height);
  TRACE_MSG(minimum_height << " " << natural_height);
  TRACE_EXIT();

}

void IconListCellRenderer::get_preferred_height_vfunc(Gtk::Widget &widget, int &minimum_height, int &natural_height) const
{
  TRACE_ENTER("IconListCellRenderer::get_preferred_height_vfunc");
  int text_minimum_height, text_natural_height;
  int pixbuf_minimum_height, pixbuf_natural_height;

  // FIXME:
  const_cast<IconListCellRenderer*>(this)->update_properties();

  text_renderer.get_preferred_height(widget, text_minimum_height, text_natural_height);
  pixbuf_renderer.get_preferred_height(widget, pixbuf_minimum_height, pixbuf_natural_height);

  minimum_height = text_minimum_height + pixbuf_minimum_height + PAD;
  natural_height = text_natural_height + pixbuf_natural_height + PAD;

  TRACE_MSG(minimum_height << " " << natural_height);
  TRACE_EXIT();
}

void IconListCellRenderer::get_preferred_width_for_height_vfunc(Gtk::Widget &widget, int height, int &minimum_width, int &natural_width) const
{
  (void) height;
  TRACE_ENTER("IconListCellRenderer::get_preferred_width_for_height_vfunc");
  get_preferred_width_vfunc(widget, minimum_width, natural_width);
  TRACE_MSG(minimum_width << " " << natural_width);
  TRACE_EXIT();
}

void IconListCellRenderer::render_vfunc(const Cairo::RefPtr<Cairo::Context> &cr, Gtk::Widget &widget, const Gdk::Rectangle &background_area, const Gdk::Rectangle &cell_area, Gtk::CellRendererState flags)
{
  update_properties();

  Gdk::Rectangle text_area;
  Gdk::Rectangle pixbuf_area;

  Gtk::Requisition minimum_size, natural_size;

  pixbuf_renderer.get_preferred_size(widget, minimum_size, natural_size);

  pixbuf_area.set_x(cell_area.get_x());
  pixbuf_area.set_y(cell_area.get_y());
  pixbuf_area.set_width(cell_area.get_width());
  pixbuf_area.set_height(natural_size.height);

  text_renderer.get_preferred_size(widget, minimum_size, natural_size);

  text_area.set_x(cell_area.get_x() + (cell_area.get_width() - natural_size.width) / 2);
  text_area.set_y(cell_area.get_y() + (pixbuf_area.get_height() + PAD));
  text_area.set_height(natural_size.height);
  text_area.set_width(natural_size.width);

  pixbuf_renderer.render(cr, widget, background_area, pixbuf_area, flags);
  text_renderer.render(cr, widget, background_area, text_area, flags);
}

#else

void
IconListCellRenderer::get_size_vfunc(Gtk::Widget& widget,
                                     const Gdk::Rectangle* cell_area,
                                     int* x_offset, int* y_offset,
                                     int* width,    int* height) const
{
  // FIXME: gtkmm 2.4 changed their API. this method now needs to be const.
  //        This is a (temporary) hack to get thing working again.
  IconListCellRenderer *r = const_cast<IconListCellRenderer *>(this);
  r->get_size_vfunc(widget, cell_area, x_offset, y_offset, width, height);
}

void
IconListCellRenderer::get_size_vfunc(Gtk::Widget& widget,
                                     const Gdk::Rectangle* cell_area,
                                     int* x_offset, int* y_offset,
                                     int* width,    int* height)
{
  (void) x_offset;
  (void) y_offset;

  int text_x_offset;
  int text_y_offset;
  int text_width;
  int text_height;

  update_properties();
  GdkRectangle *rect = NULL;
  if (cell_area)
    {
      rect = (GdkRectangle *) cell_area->gobj();
    }

  GtkCellRenderer *rend = GTK_CELL_RENDERER(text_renderer.gobj());
  gtk_cell_renderer_get_size (rend, widget.gobj(), rect,
                              NULL, NULL, width, height);

  rend = GTK_CELL_RENDERER(pixbuf_renderer.gobj());
  gtk_cell_renderer_get_size (rend, widget.gobj(),
                              rect,
                              &text_x_offset, &text_y_offset,
                              &text_width, &text_height);
  if (height) {
    *height = *height + text_height + PAD;
  }

  if (width) {
    *width = MAX (*width, text_width);
    *width += SPACE * 2;
  }
}


void
IconListCellRenderer::render_vfunc(
                                   const Glib::RefPtr<Gdk::Drawable>& window,
                                   Gtk::Widget& widget,
                                   const Gdk::Rectangle& bg_area,
                                   const Gdk::Rectangle& cell_area,
                                   const Gdk::Rectangle& expose_area,
                                   Gtk::CellRendererState flags)
{
  update_properties();

  GdkRectangle text_area;
  GdkRectangle pixbuf_area;
  int width, height;

  GdkRectangle *ca = (GdkRectangle *) cell_area.gobj();
  GtkWidget *widg = widget.gobj();
  GdkWindow *wind = window->gobj();
  GtkCellRenderer *prend = GTK_CELL_RENDERER(pixbuf_renderer.gobj());
  gtk_cell_renderer_get_size (prend, widg, ca,
                              NULL, NULL, &width, &height);

  pixbuf_area.y = ca->y;
  pixbuf_area.x = ca->x;
  pixbuf_area.height = height;
  pixbuf_area.width = ca->width;

  GtkCellRenderer *trend = GTK_CELL_RENDERER(text_renderer.gobj());
  gtk_cell_renderer_get_size (trend, widg, ca,
                              NULL, NULL, &width, &height);

  text_area.x = ca->x + (ca->width - width) / 2;
  text_area.y = ca->y + (pixbuf_area.height + PAD);
  text_area.height = height;
  text_area.width = width;

  gtk_cell_renderer_render (prend, wind, widg,
                            (GdkRectangle*)bg_area.gobj(), &pixbuf_area,
                            (GdkRectangle*)expose_area.gobj(),
                            (GtkCellRendererState) flags);

  gtk_cell_renderer_render (trend, wind, widg,
                            (GdkRectangle*)bg_area.gobj(),
                            &text_area,
                            (GdkRectangle*)expose_area.gobj(),
                            (GtkCellRendererState)  flags);
}

#endif
