/* ev-loading-window.c
 *  this file is part of atril, a mate document viewer
 *
 * Copyright (C) 2010 Carlos Garcia Campos <carlosgc@gnome.org>
 *
 * Atril 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.
 *
 * Atril 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.
 */

#include "config.h"

#include <string.h>
#include <glib/gi18n.h>
#include "ev-loading-window.h"

enum {
	PROP_0,
	PROP_PARENT
};

struct _EvLoadingWindow {
	GtkWindow  base_instance;

	GtkWindow *parent;
	GtkWidget *spinner;

	gint       x;
	gint       y;
	gint       width;
	gint       height;
};

struct _EvLoadingWindowClass {
	GtkWindowClass base_class;
};

G_DEFINE_TYPE (EvLoadingWindow, ev_loading_window, GTK_TYPE_WINDOW)

static void
ev_loading_window_set_property (GObject      *object,
				guint         prop_id,
				const GValue *value,
				GParamSpec   *pspec)
{
	EvLoadingWindow *window = EV_LOADING_WINDOW (object);

	switch (prop_id) {
	case PROP_PARENT:
		window->parent = g_value_get_object (value);
		break;
	default:
		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
	}
}

static void
ev_loading_window_init (EvLoadingWindow *window)
{
	GtkWindow   *gtk_window = GTK_WINDOW (window);
	GtkWidget   *widget = GTK_WIDGET (window);
	GtkWidget   *hbox;
	GtkWidget   *label;
#if GTK_CHECK_VERSION (3, 0, 0)
	GtkStyleContext *context;
	GdkRGBA    fg, bg;
#else
	GtkStyle    *style;
	GdkColor    fg, bg;
#endif
	const gchar *loading_text = _("Loading…");
	const gchar *fg_color_name = "info_fg_color";
	const gchar *bg_color_name = "info_bg_color";

	hbox = gtk_hbox_new (FALSE, 12);

	window->spinner = gtk_spinner_new ();
	gtk_box_pack_start (GTK_BOX (hbox), window->spinner, FALSE, FALSE, 0);
	gtk_widget_show (window->spinner);

	label = gtk_label_new (loading_text);
	gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
	gtk_widget_show (label);

	gtk_container_add (GTK_CONTAINER (window), hbox);
	gtk_widget_show (hbox);

	gtk_widget_set_app_paintable (widget, TRUE);

	gtk_container_set_border_width (GTK_CONTAINER (window), 10);

	gtk_window_set_type_hint (gtk_window, GDK_WINDOW_TYPE_HINT_NOTIFICATION);
	gtk_window_set_accept_focus (gtk_window, FALSE);
	gtk_window_set_decorated (gtk_window, FALSE);
	gtk_window_set_resizable (gtk_window, FALSE);

#if GTK_CHECK_VERSION (3, 0, 0)
	context = gtk_widget_get_style_context (widget);
	if (!gtk_style_context_lookup_color (context, fg_color_name, &fg) ||
	    !gtk_style_context_lookup_color (context, bg_color_name, &bg)) {
		fg.red = 0.7;
		fg.green = 0.67;
		fg.blue = 0.63;
		fg.alpha = 1.0;

		bg.red = 0.99;
		bg.green = 0.99;
		bg.blue = 0.71;
		bg.alpha = 1.0;
	}

        gtk_widget_override_background_color (widget, GTK_STATE_NORMAL, &bg);
        gtk_widget_override_color (widget, GTK_STATE_NORMAL, &fg);
}
#else
	style = gtk_widget_get_style (widget);
	if (!gtk_style_lookup_color (style, fg_color_name, &fg) ||
	    !gtk_style_lookup_color (style, bg_color_name, &bg)) {
		fg.pixel = 0;
		fg.red = 0xb800;
		fg.green = 0xad00;
		fg.blue = 0x9d00;

		bg.pixel = 0;
		bg.red = 0xff00;
		bg.green = 0xff00;
		bg.blue = 0xbf00;
	}

	if (!gdk_color_equal (&bg, &style->bg[GTK_STATE_NORMAL]))
		gtk_widget_modify_bg (widget, GTK_STATE_NORMAL, &bg);
	if (!gdk_color_equal (&fg, &style->fg[GTK_STATE_NORMAL]))
		gtk_widget_modify_fg (widget, GTK_STATE_NORMAL, &fg);
}
#endif

static GObject *
ev_loading_window_constructor (GType                  type,
			       guint                  n_construct_properties,
			       GObjectConstructParam *construct_params)
{
	GObject         *object;
	EvLoadingWindow *window;
	GtkWindow       *gtk_window;

	object = G_OBJECT_CLASS (ev_loading_window_parent_class)->constructor (type,
									       n_construct_properties,
									       construct_params);
	window = EV_LOADING_WINDOW (object);
	gtk_window = GTK_WINDOW (window);

	gtk_window_set_transient_for (gtk_window, window->parent);
	gtk_window_set_destroy_with_parent (gtk_window, TRUE);

	return object;
}

static void
_cairo_rounded_rectangle (cairo_t *cr,
			  gint     width,
			  gint     height,
			  gdouble  radius)
{
	cairo_move_to (cr, radius, 0);
	cairo_line_to (cr, width - radius, 0);
	cairo_curve_to (cr,
			width, 0,
			width, 0,
			width,
			radius);
	cairo_line_to (cr, width, height - radius);
	cairo_curve_to (cr,
			width,height,
			width, height,
			width - radius,
			height);
	cairo_line_to (cr, radius, height);
	cairo_curve_to (cr,
			0, height,
			0, height,
			0, height - radius);
	cairo_line_to (cr, 0, radius);
	cairo_curve_to (cr,
			0, 0,
			0, 0,
			radius, 0);
}

static void
ev_loading_window_size_allocate (GtkWidget      *widget,
				 GtkAllocation  *allocation)
{
	EvLoadingWindow *window = EV_LOADING_WINDOW (widget);
#if GTK_CHECK_VERSION (3, 0, 0)
	cairo_surface_t *surface;
	cairo_region_t *shape;
#else
	GdkPixmap       *mask;
#endif
	cairo_t         *cr;
	double           r;

	GTK_WIDGET_CLASS (ev_loading_window_parent_class)->size_allocate (widget, allocation);

	if (allocation->width == window->width && allocation->height == window->height)
		return;

	window->width = allocation->width;
	window->height = allocation->height;

#if GTK_CHECK_VERSION (3, 0, 0)
	surface = cairo_image_surface_create (CAIRO_FORMAT_A8, window->width, window->height);
	cr = cairo_create (surface);
#else
	mask = gdk_pixmap_new (NULL, window->width, window->height, 1);
	cr = gdk_cairo_create (GDK_DRAWABLE (mask));
#endif

	cairo_save (cr);
	cairo_rectangle (cr, 0, 0, window->width, window->height);
	cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
	cairo_fill (cr);
	cairo_restore (cr);

	cairo_set_source_rgb (cr, 1., 1., 1.);
	r = MIN (window->width, window->height) / 2.;
	_cairo_rounded_rectangle (cr, window->width, window->height, r);
	cairo_fill (cr);

	cairo_destroy (cr);

#if GTK_CHECK_VERSION (3, 0, 0)
	shape = gdk_cairo_region_create_from_surface (surface);
	cairo_surface_destroy (surface);

	gtk_widget_shape_combine_region (widget, shape);
	cairo_region_destroy (shape);
#else
	gtk_widget_shape_combine_mask (widget, mask, 0, 0);
	g_object_unref (mask);
#endif
}

static void
ev_loading_window_hide (GtkWidget *widget)
{
	EvLoadingWindow *window = EV_LOADING_WINDOW (widget);

	window->x = window->y = 0;

	gtk_spinner_stop (GTK_SPINNER (window->spinner));

	GTK_WIDGET_CLASS (ev_loading_window_parent_class)->hide (widget);
}

static void
ev_loading_window_show (GtkWidget *widget)
{
	EvLoadingWindow *window = EV_LOADING_WINDOW (widget);

	gtk_spinner_start (GTK_SPINNER (window->spinner));

	GTK_WIDGET_CLASS (ev_loading_window_parent_class)->show (widget);
}

static void
ev_loading_window_class_init (EvLoadingWindowClass *klass)
{
	GObjectClass   *g_object_class = G_OBJECT_CLASS (klass);
	GtkWidgetClass *gtk_widget_class = GTK_WIDGET_CLASS (klass);

	g_object_class->constructor = ev_loading_window_constructor;
	g_object_class->set_property = ev_loading_window_set_property;

	gtk_widget_class->size_allocate = ev_loading_window_size_allocate;
	gtk_widget_class->show = ev_loading_window_show;
	gtk_widget_class->hide = ev_loading_window_hide;

	g_object_class_install_property (g_object_class,
					 PROP_PARENT,
					 g_param_spec_object ("parent",
							      "Parent",
							      "The parent window",
							      GTK_TYPE_WINDOW,
							      G_PARAM_WRITABLE |
							      G_PARAM_CONSTRUCT_ONLY));
}

/* Public methods */
GtkWidget *
ev_loading_window_new (GtkWindow *parent)
{
	GtkWidget *window;

	g_return_val_if_fail (GTK_IS_WINDOW (parent), NULL);

	window = g_object_new (EV_TYPE_LOADING_WINDOW,
                               "type", GTK_WINDOW_POPUP,
			       "parent", parent,
			       NULL);
	return window;
}

void
ev_loading_window_get_size (EvLoadingWindow *window,
			    gint            *width,
			    gint            *height)
{
	if (width) *width = window->width;
	if (height) *height = window->height;
}

void
ev_loading_window_move (EvLoadingWindow *window,
			gint             x,
			gint             y)
{
	if (x == window->x && y == window->y)
		return;

	window->x = x;
	window->y = y;
	gtk_window_move (GTK_WINDOW (window), x, y);
}
