/*
 * Mail Notification
 * Copyright (C) 2003-2008 Jean-Yves Lefort <jylefort@brutele.be>
 *
 * 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, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

%headertop{
#include "mn-widget.h"
%}

%{
#include <math.h>
#include "mn-util.h"

#define ICON_XALIGN		0.5
#define ICON_YALIGN		0.5

#define COUNT_BOX_XPAD		3
#define COUNT_BOX_YPAD		3

#define COUNT_BOX_XMARGIN	0
#define COUNT_BOX_YMARGIN	0
%}

class MN:Mail:Icon:Widget from Mn:Widget
{
  private gboolean blinking;
  property BOOLEAN blinking (export)
    set
    {
      gboolean blinking = g_value_get_boolean(VAL);
      if (blinking != selfp->blinking) {
        selfp->blinking = blinking;
        if (blinking) {
          g_assert(selfp->blink_timeout_id == 0);
          selfp->blink_timeout_id = gdk_threads_add_timeout(500, self_blink_timeout_cb, self);
        } else {
          g_assert(selfp->blink_timeout_id != 0);
          mn_source_clear(&selfp->blink_timeout_id);
          selfp->is_on = TRUE;
          gtk_widget_queue_draw(GTK_WIDGET(self));
        }
      }
    }
    get
    {
      g_value_set_boolean(VAL, selfp->blinking);
    };

  private PangoLayout *count_layout unrefwith g_object_unref;

  private int count;
  property INT count (export)
    set
    {
      int count = g_value_get_int(VAL);
      if (count != selfp->count) {
        selfp->count = count;
        self_invalidate_count_layout(self);
        gtk_widget_queue_draw(GTK_WIDGET(self));
      }
    }
    get
    {
      g_value_set_int(VAL, selfp->count);
    };

  private unsigned int blink_timeout_id;
  private gboolean is_on = TRUE; /* is currently displaying the image? */

  private char *stock_id destroywith g_free;
  private GtkIconSize icon_size;

  init (self)
  {
    gtk_widget_set_has_window(GTK_WIDGET(self), FALSE);

    gtk_widget_set_name(GTK_WIDGET(self), "mn-mail-icon");

    g_object_connect(self,
                     "swapped-signal::size-allocate", self_invalidate_count_layout, self,
                     "swapped-signal::style-set", self_context_changed, self,
                     "swapped-signal::direction-changed", self_context_changed, self,
                     NULL);
  }

  dispose (self)
  {
    mn_source_clear(&selfp->blink_timeout_id);
  }

  private void
    size_request_internal(GtkWidget *widget, GtkRequisition *requisition)
  {
    Self *self = SELF(widget);
    GdkPixbuf *pixbuf;
    static int prev_width = 0;
    static int prev_height = 0;

    pixbuf = self_render_icon(self);

    if (pixbuf) {
      requisition->width = gdk_pixbuf_get_width(pixbuf);
      requisition->height = gdk_pixbuf_get_height(pixbuf);

      g_object_unref(pixbuf);
    } else {
      requisition->width = 0;
      requisition->height = 0;
    }

    if (prev_width != requisition->width ||
        prev_height != requisition->height) {

        prev_width = requisition->width;
        prev_height = requisition->height;
        gtk_widget_queue_draw(GTK_WIDGET(self));
    }
  }

  override (Mn:Widget) void
    mn_size_request (GtkWidget *widget, GtkRequisition *requisition)
  {
    self_size_request_internal(widget, requisition);
  }

  override (Mn:Widget) void
    mn_get_preferred_width (GtkWidget *widget, gint *minimal_width, gint *natural_width)
  {
#if GTK_CHECK_VERSION(3,0,0)
    GtkRequisition requisition;

     self_size_request_internal (widget, &requisition);
     *minimal_width = *natural_width = requisition.width;
#endif
  }

  override (Mn:Widget) void
    mn_get_preferred_height(GtkWidget *widget, gint *minimal_height, gint *natural_height)
  {
#if GTK_CHECK_VERSION(3,0,0)
    GtkRequisition requisition;

    self_size_request_internal (widget, &requisition);
    *minimal_height = *natural_height = requisition.height;
#endif
  }

  /* GTK2 only */
  override (Mn:Widget) gboolean
    mn_expose_event (GtkWidget *widget, GdkEventExpose *event)
  {
#if !GTK_CHECK_VERSION(3,0,0)
    Self *self = SELF(widget);

    if (! GTK_WIDGET_DRAWABLE(widget) || ! selfp->stock_id)
      return FALSE;

    if (selfp->is_on) {
      int x;
      int y;
      GdkRectangle image_area;

      /* note: widget->requisition is the pixbuf size, see size_request() */

      x = floor(widget->allocation.x + ((widget->allocation.width - widget->requisition.width) * ICON_XALIGN));
      y = floor(widget->allocation.y + ((widget->allocation.height - widget->requisition.height) * ICON_YALIGN));

      image_area.x = x;
      image_area.y = y;
      image_area.width = widget->requisition.width;
      image_area.height = widget->requisition.height;

      if (gdk_rectangle_intersect(&event->area, &image_area, &image_area)) {
        GdkPixbuf *pixbuf;

        pixbuf = self_render_icon(self);

        gdk_draw_pixbuf(widget->window,
                        NULL,
                        pixbuf,
                        image_area.x - x,
                        image_area.y - y,
                        image_area.x,
                        image_area.y,
                        image_area.width,
                        image_area.height,
                        GDK_RGB_DITHER_NORMAL,
                        0,
                        0);

        g_object_unref(pixbuf);
      }
    }

    if (selfp->count) {
      PangoRectangle count_rect;
      int count_x;
      int count_y;
      int box_x;
      int box_y;
      int box_width;
      int box_height;

      if (! selfp->count_layout) {
        const char *size;
        char *markup;

        if (widget->allocation.height < 32)
          size = "small";
        else
          size = "medium";

        selfp->count_layout = gtk_widget_create_pango_layout(widget, NULL);

        markup = g_strdup_printf("<span size=\"%s\">%i</span>", size, selfp->count);
        pango_layout_set_markup(selfp->count_layout, markup, -1);
        g_free(markup);
      }

      pango_layout_get_pixel_extents(selfp->count_layout, &count_rect, NULL);

      box_width = count_rect.width + COUNT_BOX_XPAD * 2;
      box_height = count_rect.height + COUNT_BOX_YPAD * 2;

      box_x = widget->allocation.x + widget->allocation.width - box_width - COUNT_BOX_XMARGIN;
      box_y = widget->allocation.y + widget->allocation.height - box_height - COUNT_BOX_YMARGIN;

      count_x = box_x - count_rect.x + COUNT_BOX_XPAD;
      count_y = box_y - count_rect.y + COUNT_BOX_YPAD;

#if !GTK_CHECK_VERSION(2,8,0)
      gtk_paint_box(widget->style,
                    widget->window,
                    GTK_WIDGET_STATE(widget),
                    GTK_SHADOW_OUT,
                    &event->area,
                    widget,
                    NULL,
                    box_x,
                    box_y,
                    box_width,
                    box_height);
#else
      cairo_t *cr;
      cr = gdk_cairo_create(GDK_DRAWABLE(widget->window));
      cairo_save(cr);
      cairo_set_line_width(cr, 2.0);
      cairo_set_source_rgba (cr, 0.66, 0.62, 0.55, 1.0);
      cairo_rectangle (cr, box_x, box_y, box_width, box_height);
      cairo_stroke_preserve (cr);

      cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
      cairo_set_source_rgba (cr, 0.93, 0.91, 0.89, 0.8);
      cairo_fill(cr);

      cairo_restore(cr);
      cairo_destroy(cr);
#endif

      gtk_paint_layout(widget->style,
                       widget->window,
                       GTK_WIDGET_STATE(widget),
                       FALSE,
                       &event->area,
                       widget,
                       NULL,
                       count_x,
                       count_y,
                       selfp->count_layout);
    }
#endif

    return FALSE;
  }

  /* GTK3 only */
  override (Mn:Widget) gboolean
    mn_draw (GtkWidget *widget, cairo_t *cr)
  {
#if GTK_CHECK_VERSION(3,0,0)
    Self *self = SELF(widget);

    if (! gtk_widget_is_drawable(widget) || ! selfp->stock_id)
      return FALSE;

    if (selfp->is_on) {
      int x;
      int y;
      GdkRectangle image_area;
      GtkAllocation allocation;
      GtkRequisition requisition;
      GdkPixbuf *pixbuf;

      /* note: widget->requisition is the pixbuf size, see size_request() */

      gtk_widget_get_allocation(widget, &allocation);
      gtk_widget_get_requisition(widget, &requisition);

      x = floor(allocation.x + ((allocation.width - requisition.width) * ICON_XALIGN));
      y = floor(allocation.y + ((allocation.height - requisition.height) * ICON_YALIGN));

      image_area.x = x;
      image_area.y = y;
      image_area.width = requisition.width;
      image_area.height = requisition.height;

      cairo_save(cr);
      pixbuf = self_render_icon(self);
      gdk_cairo_set_source_pixbuf(cr, pixbuf, image_area.x, image_area.y);
      cairo_move_to(cr, image_area.x - x, image_area.y - y);
      cairo_paint(cr);
      cairo_restore(cr);

      g_object_unref(pixbuf);
    }

    if (selfp->count) {
      PangoRectangle count_rect;
      int count_x;
      int count_y;
      int box_x;
      int box_y;
      int box_width;
      int box_height;
      GtkAllocation allocation;

      gtk_widget_get_allocation(widget, &allocation);

      if (! selfp->count_layout) {
        const char *size;
        char *markup;

        if (allocation.height < 32)
          size = "small";
        else
          size = "medium";

        selfp->count_layout = gtk_widget_create_pango_layout(widget, NULL);

        markup = g_strdup_printf("<span size=\"%s\">%i</span>", size, selfp->count);
        pango_layout_set_markup(selfp->count_layout, markup, -1);
        g_free(markup);
      }

      pango_layout_get_pixel_extents(selfp->count_layout, &count_rect, NULL);

      box_width = count_rect.width + COUNT_BOX_XPAD * 2;
      box_height = count_rect.height + COUNT_BOX_YPAD * 2;

      box_x = allocation.x + allocation.width - box_width - COUNT_BOX_XMARGIN;
      box_y = allocation.y + allocation.height - box_height - COUNT_BOX_YMARGIN;

      count_x = box_x - count_rect.x + COUNT_BOX_XPAD;
      count_y = box_y - count_rect.y + COUNT_BOX_YPAD;

      cairo_save(cr);
      cairo_set_line_width(cr, 2.0);
      cairo_set_source_rgba (cr, 0.66, 0.62, 0.55, 1.0);
      cairo_rectangle (cr, box_x, box_y, box_width, box_height);
      cairo_stroke_preserve (cr);

      cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
      cairo_set_source_rgba (cr, 0.93, 0.91, 0.89, 0.8);
      cairo_fill(cr);

      cairo_restore(cr);

      gtk_paint_layout(gtk_widget_get_style(widget),
                       cr,
                       gtk_widget_get_state_flags(widget),
                       FALSE,
                       widget,
                       NULL,
                       count_x,
                       count_y,
                       selfp->count_layout);
    }
#endif

    return FALSE;
  }

  private GdkPixbuf *
    render_icon (self)
  {
    if (selfp->stock_id)
      return gtk_widget_render_icon(GTK_WIDGET(self),
                                    selfp->stock_id,
                                    selfp->icon_size,
                                    NULL);
    else
      return NULL;
  }

  private void
    context_changed (self)
  {
    if (selfp->count_layout) {
      pango_layout_context_changed(selfp->count_layout);
      gtk_widget_queue_draw(GTK_WIDGET(self));
    }
  }

  private void
    invalidate_count_layout (self)
  {
    if (selfp->count_layout) {
      g_object_unref(selfp->count_layout);
      selfp->count_layout = NULL;
    }
  }

  private gboolean
    blink_timeout_cb (gpointer data)
  {
    Self *self = data;

    selfp->is_on = ! selfp->is_on;

    gtk_widget_queue_draw(GTK_WIDGET(self));

    return TRUE;
  }

  public MnWidget *
    new (void)
  {
    return MN_WIDGET(GET_NEW);
  }

  public void
    set_from_stock (self,
		    const char *stock_id (check null),
		    GtkIconSize icon_size)
  {
    g_free(selfp->stock_id);
    selfp->stock_id = g_strdup(stock_id);
    selfp->icon_size = icon_size;

    /* affects the size request: call queue_resize(), not queue_draw() */
    gtk_widget_queue_resize(GTK_WIDGET(self));
  }
}
