From 72ba1bd6310dc6f6138d447c6548a83f539f3529 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Erick=20P=C3=A9rez=20Castellanos?= Date: Wed, 2 May 2012 22:29:22 -0400 Subject: [PATCH] Added GcalFloatingContainer --- src/gcal-floating-container.c | 379 ++++++++++++++++++++++++++++++++++ src/gcal-floating-container.h | 59 ++++++ 2 files changed, 438 insertions(+) create mode 100644 src/gcal-floating-container.c create mode 100644 src/gcal-floating-container.h diff --git a/src/gcal-floating-container.c b/src/gcal-floating-container.c new file mode 100644 index 00000000..f4ee4d08 --- /dev/null +++ b/src/gcal-floating-container.c @@ -0,0 +1,379 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 2 -*- */ +/* + * gcal-floating-container.c + * Copyright (C) 2012 Erick Pérez Castellanos + * + * gnome-calendar 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. + * + * gnome-calendar 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 . + */ + +#include "gcal-floating-container.h" + +struct _GcalFloatingContainerPrivate +{ + guint border; +}; + +static void gcal_floating_container_get_preferred_width (GtkWidget *widget, + gint *minimum_width, + gint *natural_width); + +static void gcal_floating_container_get_preferred_height_for_width (GtkWidget *widget, + gint width, + gint *minimum_height, + gint *natural_height); + +static void gcal_floating_container_get_preferred_height (GtkWidget *widget, + gint *minimum_height, + gint *natural_height); + +static void gcal_floating_container_get_preferred_width_for_height (GtkWidget *widget, + gint height, + gint *minimum_width, + gint *natural_width); + +static void gcal_floating_container_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); + +static gboolean gcal_floating_container_draw (GtkWidget *widget, + cairo_t *cr); + +static void gcal_floating_container_realize (GtkWidget *widget); + +static void gcal_floating_container_unrealize (GtkWidget *widget); + +static void gcal_floating_container_style_updated (GtkWidget *widget); + +static void gcal_floating_container_add (GtkContainer *container, + GtkWidget *child); + +static void _gcal_floating_container_get_padding_and_border (GtkWidget *widget, + GtkBorder *border); + +G_DEFINE_TYPE(GcalFloatingContainer, gcal_floating_container, GTK_TYPE_BIN) + +static void +gcal_floating_container_class_init (GcalFloatingContainerClass *klass) +{ + GtkWidgetClass* widget_class; + GtkContainerClass *container_class; + + widget_class = GTK_WIDGET_CLASS (klass); + container_class = GTK_CONTAINER_CLASS (klass); + + widget_class->get_preferred_width = + gcal_floating_container_get_preferred_width; + widget_class->get_preferred_height_for_width = + gcal_floating_container_get_preferred_height_for_width; + widget_class->get_preferred_height = + gcal_floating_container_get_preferred_height; + widget_class->get_preferred_width_for_height = + gcal_floating_container_get_preferred_width_for_height; + widget_class->size_allocate = gcal_floating_container_size_allocate; + widget_class->draw = gcal_floating_container_draw; + widget_class->realize = gcal_floating_container_realize; + widget_class->unrealize = gcal_floating_container_unrealize; + widget_class->style_updated = gcal_floating_container_style_updated; + + container_class->add = gcal_floating_container_add; + + g_type_class_add_private ((gpointer)klass, sizeof (GcalFloatingContainerPrivate)); +} + + + +static void +gcal_floating_container_init (GcalFloatingContainer *self) +{ + gtk_widget_set_has_window (GTK_WIDGET (self), FALSE); + + self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, + GCAL_TYPE_FLOATING_CONTAINER, + GcalFloatingContainerPrivate); + +} + +static void +gcal_floating_container_get_preferred_width (GtkWidget *widget, + gint *minimum_width, + gint *natural_width) +{ + gint child_min, child_nat; + GtkWidget *child; + GtkBorder padding; + gint minimum, natural; + + _gcal_floating_container_get_padding_and_border (widget, &padding); + + minimum = 0; + natural = 0; + + child = gtk_bin_get_child (GTK_BIN (widget)); + if (child && gtk_widget_get_visible (child)) + { + gtk_widget_get_preferred_width (child, + &child_min, &child_nat); + minimum += child_min; + natural += child_nat; + } + + minimum += padding.left + padding.right; + natural += padding.left + padding.right; + + if (minimum_width) + *minimum_width = minimum; + + if (natural_width) + *natural_width = natural; +} + +static void +gcal_floating_container_get_preferred_height_for_width (GtkWidget *widget, + gint width, + gint *minimum_height, + gint *natural_height) +{ + gint child_min, child_nat, child_width; + GtkWidget *child; + GtkBorder padding; + gint minimum; + gint natural; + + _gcal_floating_container_get_padding_and_border (widget, &padding); + + minimum = 0; + natural = 0; + + child = gtk_bin_get_child (GTK_BIN (widget)); + if (child && gtk_widget_get_visible (child)) + { + child_width = width - padding.left - padding.top; + + gtk_widget_get_preferred_height_for_width (child, child_width, + &child_min, &child_nat); + minimum = MAX (minimum, child_min); + natural = MAX (natural, child_nat); + } + + minimum += padding.top + padding.top; + natural += padding.top + padding.top; + + if (minimum_height) + *minimum_height = minimum; + + if (natural_height) + *natural_height = natural; +} + +static void +gcal_floating_container_get_preferred_height (GtkWidget *widget, + gint *minimum_height, + gint *natural_height) +{ + gint child_min, child_nat; + GtkWidget *child; + GtkBorder padding; + gint minimum; + gint natural; + + _gcal_floating_container_get_padding_and_border (widget, &padding); + + minimum = 0; + natural = 0; + + child = gtk_bin_get_child (GTK_BIN (widget)); + if (child && gtk_widget_get_visible (child)) + { + gtk_widget_get_preferred_height (child, + &child_min, &child_nat); + minimum = child_min; + natural = child_nat; + } + + minimum += padding.top + padding.top; + natural += padding.top + padding.top; + + if (minimum_height) + *minimum_height = minimum; + + if (natural_height) + *natural_height = natural; +} + +static void +gcal_floating_container_get_preferred_width_for_height (GtkWidget *widget, + gint height, + gint *minimum_width, + gint *natural_width) +{ + gint child_min, child_nat, child_height; + GtkWidget *child; + GtkBorder padding; + gint minimum; + gint natural; + + _gcal_floating_container_get_padding_and_border (widget, &padding); + + minimum = 0; + natural = 0; + + child_height = height - padding.top - padding.bottom; + + child = gtk_bin_get_child (GTK_BIN (widget)); + if (child && gtk_widget_get_visible (child)) + { + gtk_widget_get_preferred_width_for_height (child, child_height, + &child_min, &child_nat); + minimum += child_min; + natural += child_nat; + } + + minimum += padding.left + padding.right; + natural += padding.left + padding.right; + + if (minimum_width) + *minimum_width = minimum; + + if (natural_width) + *natural_width = natural; +} + +static void +gcal_floating_container_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + GtkAllocation child_allocation; + GtkBorder padding; + GtkWidget *child; + + gtk_widget_set_allocation (widget, allocation); + + _gcal_floating_container_get_padding_and_border (widget, &padding); + + if (gtk_widget_get_realized (widget)) + { + gdk_window_move_resize (gtk_widget_get_window (widget), + allocation->x, + allocation->y, + allocation->width, + allocation->height); + } + + child_allocation.x = padding.left; + child_allocation.y = padding.top; + child_allocation.height = + MAX (1, + allocation->height - padding.top - padding.bottom); + + child_allocation.width = + MAX (1, + allocation->width - padding.left - padding.right); + + child = gtk_bin_get_child (GTK_BIN (widget)); + if (child && gtk_widget_get_visible (child)) + gtk_widget_size_allocate (child, &child_allocation); +} + +static gboolean +gcal_floating_container_draw (GtkWidget *widget, + cairo_t *cr) +{ + GtkStyleContext *context; + GdkRectangle rect; + guint border_width; + + context = gtk_widget_get_style_context (widget); + gtk_widget_get_allocation (widget, &rect); + border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); + + gtk_render_background (context, cr, + border_width, border_width, + gtk_widget_get_allocated_width (widget) - 2 * border_width, + gtk_widget_get_allocated_height (widget) - 2 * border_width); + gtk_render_frame (context, cr, + border_width, border_width, + gtk_widget_get_allocated_width (widget) - 2 * border_width, + gtk_widget_get_allocated_height (widget) - 2 * border_width); + if (GTK_WIDGET_CLASS (gcal_floating_container_parent_class)->draw != NULL) + GTK_WIDGET_CLASS (gcal_floating_container_parent_class)->draw(widget, cr); + + return FALSE; +} + +static void +gcal_floating_container_realize (GtkWidget *widget) +{ + GdkWindow *window; + GtkWidget *child; + + gtk_widget_set_realized (widget, TRUE); + + window = gtk_widget_get_parent_window (widget); + gtk_widget_set_window (widget, window); + g_object_ref (window); + + child = gtk_bin_get_child (GTK_BIN (widget)); + if (child) + gtk_widget_set_parent_window (child, window); +} + +static void +gcal_floating_container_unrealize (GtkWidget *widget) +{ + GTK_WIDGET_CLASS (gcal_floating_container_parent_class)->unrealize (widget); +} + +static void +gcal_floating_container_style_updated (GtkWidget *widget) +{ + GTK_WIDGET_CLASS (gcal_floating_container_parent_class)->style_updated (widget); + + if (gtk_widget_get_realized (widget)) + gtk_style_context_set_background (gtk_widget_get_style_context (widget), + gtk_widget_get_window (widget)); +} + +static void +gcal_floating_container_add (GtkContainer *container, + GtkWidget *child) +{ + g_return_if_fail (gtk_bin_get_child (GTK_BIN (container)) == NULL); + + GTK_CONTAINER_CLASS (gcal_floating_container_parent_class)->add (container, child); +} + +static void +_gcal_floating_container_get_padding_and_border (GtkWidget *widget, + GtkBorder *border) +{ + GtkStyleContext *context; + GtkStateFlags state; + GtkBorder tmp; + + context = gtk_widget_get_style_context (widget); + state = gtk_widget_get_state_flags (widget); + + gtk_style_context_get_padding (context, state, border); + + gtk_style_context_get_border (context, state, &tmp); + border->top += tmp.top; + border->right += tmp.right; + border->bottom += tmp.bottom; + border->left += tmp.left; +} + +GtkWidget* +gcal_floating_container_new (void) +{ + return g_object_new (GCAL_TYPE_FLOATING_CONTAINER, NULL); +} diff --git a/src/gcal-floating-container.h b/src/gcal-floating-container.h new file mode 100644 index 00000000..bc0302ba --- /dev/null +++ b/src/gcal-floating-container.h @@ -0,0 +1,59 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 2 -*- */ +/* + * gcal-floating-container.h + * Copyright (C) 2012 Erick Pérez Castellanos + * + * gnome-calendar 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. + * + * gnome-calendar 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 . + */ + +#ifndef __GCAL_FLOATING_CONTAINER_H__ +#define __GCAL_FLOATING_CONTAINER_H__ + +#include + +G_BEGIN_DECLS + + +#define GCAL_TYPE_FLOATING_CONTAINER (gcal_floating_container_get_type ()) +#define GCAL_FLOATING_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), GCAL_TYPE_FLOATING_CONTAINER, GcalFloatingContainer)) +#define GCAL_FLOATING_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GCAL_TYPE_FLOATING_CONTAINER, GcalFloatingContainerClass)) +#define GCAL_IS_FLOATING_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), GCAL_TYPE_FLOATING_CONTAINER)) +#define GCAL_IS_FLOATING_CONTAINER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GCAL_TYPE_FLOATING_CONTAINER)) +#define GCAL_FLOATING_CONTAINER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), GCAL_TYPE_FLOATING_CONTAINER, GcalFloatingContainerClass)) + +typedef struct _GcalFloatingContainer GcalFloatingContainer; +typedef struct _GcalFloatingContainerClass GcalFloatingContainerClass; +typedef struct _GcalFloatingContainerPrivate GcalFloatingContainerPrivate; + +struct _GcalFloatingContainer +{ + GtkBin parent; + /* add your public declarations here */ + + GcalFloatingContainerPrivate *priv; +}; + +struct _GcalFloatingContainerClass +{ + GtkBinClass parent_class; +}; + + +GType gcal_floating_container_get_type (void); +GtkWidget* gcal_floating_container_new (void); + + +G_END_DECLS + +#endif /* __GCAL_FLOATING_CONTAINER_H__ */