Blob Blame History Raw
/*
 * glade-gtk-overlay.c - GladeWidgetAdaptor for GtkOverlay widget
 *
 * Copyright (C) 2013 Juan Pablo Ugarte
 *
 * Authors:
 *      Juan Pablo Ugarte <juanpablougarte@gmail.com>
 *
 * This library is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser 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 "glade-gtk.h"
#include <gladeui/glade.h>
#include <glib/gi18n-lib.h>
#include <string.h>

typedef struct
{
  GtkWidget *bin_child;
  GtkWidget *overlay_child;
} VisibilityData;

static void 
set_children_visibility (GtkWidget *widget, gpointer user_data)
{
  VisibilityData *data = user_data;

  /* We never hide the main child */
  if (widget == data->bin_child)
    return;

  /* We only hide overlay children when one of them is selected */
  if (data->overlay_child)
    gtk_widget_set_visible (widget, widget == data->overlay_child);
  else
    /* otherwhise we show them so we can interact with the container */
    gtk_widget_set_visible (widget, TRUE);
}

static inline GtkWidget *
get_overlay_children (GtkWidget *deep_child, GtkWidget *overlay)
{
  GtkWidget *parent = deep_child;
  
  while (parent)
    {
      if (parent == overlay)
        return deep_child;

      deep_child = parent;
      parent = gtk_widget_get_parent (parent);
    }

  return NULL;
}

static void
on_project_selection_changed (GladeProject *project, GtkWidget *overlay)
{
  VisibilityData data = { gtk_bin_get_child (GTK_BIN (overlay)), NULL };
  GList *l;
  
  for (l = glade_project_selection_get (project); l; l = g_list_next (l))
    {
      GtkWidget *selection;
      
      if (GTK_IS_WIDGET (l->data) && (selection = GTK_WIDGET (l->data)) &&
          overlay != selection)
        data.overlay_child = get_overlay_children (selection, overlay);

      if (data.overlay_child)
        break;
    }

  gtk_container_foreach (GTK_CONTAINER (overlay), set_children_visibility, &data);
}

static void 
on_widget_project_notify (GObject *gobject,
                          GParamSpec *pspec,
                          GladeProject *old_project)
{
  GladeWidget *gwidget = GLADE_WIDGET (gobject);
  GladeProject *project = glade_widget_get_project (gwidget);
  GObject *object = glade_widget_get_object (gwidget);

  if (old_project)
    g_signal_handlers_disconnect_by_func (old_project, on_project_selection_changed, object);

  g_signal_handlers_disconnect_by_func (gwidget, on_widget_project_notify, old_project);
  
  g_signal_connect_object (gwidget, "notify::project",
                           G_CALLBACK (on_widget_project_notify),
                           project, 0);

  if (project)
    g_signal_connect_object (project, "selection-changed",
                             G_CALLBACK (on_project_selection_changed),
                             object, 0);
}

void
glade_gtk_overlay_post_create (GladeWidgetAdaptor *adaptor,
                               GObject            *object,
                               GladeCreateReason   reason)
{
  GladeWidget *widget = glade_widget_get_from_gobject (object);

  if (reason == GLADE_CREATE_USER)
    gtk_container_add (GTK_CONTAINER (object), glade_placeholder_new ());

  on_widget_project_notify (G_OBJECT (widget), NULL, NULL);
}

gboolean
glade_gtk_overlay_add_verify (GladeWidgetAdaptor *adaptor,
                              GtkWidget          *container,
                              GtkWidget          *child,
                              gboolean            user_feedback)
{
  if (!GTK_IS_WIDGET (child))
    {
      if (user_feedback)
	{
	  GladeWidgetAdaptor *widget_adaptor = 
	    glade_widget_adaptor_get_by_type (GTK_TYPE_WIDGET);

	  glade_util_ui_message (glade_app_get_window (),
				 GLADE_UI_INFO, NULL,
				 ONLY_THIS_GOES_IN_THAT_MSG,
				 glade_widget_adaptor_get_title (widget_adaptor),
				 glade_widget_adaptor_get_title (adaptor));
	}

      return FALSE;
    }

  return TRUE;
}

void
glade_gtk_overlay_add_child (GladeWidgetAdaptor *adaptor,
                             GObject            *object,
                             GObject            *child)
{
  gchar *special_type = g_object_get_data (child, "special-child-type");
  GtkWidget *bin_child;

  if ((special_type && !strcmp (special_type, "overlay")) ||
      ((bin_child = gtk_bin_get_child (GTK_BIN (object))) &&
       !GLADE_IS_PLACEHOLDER (bin_child)))
    {
      g_object_set_data (child, "special-child-type", "overlay");
      gtk_overlay_add_overlay (GTK_OVERLAY (object), GTK_WIDGET (child));
    }
  else
    /* Chain Up */
    GWA_GET_CLASS (GTK_TYPE_CONTAINER)->add (adaptor, object, child);
}

void
glade_gtk_overlay_remove_child (GladeWidgetAdaptor *adaptor,
                                GObject            *object,
                                GObject            *child)
{
  gchar *special_type = g_object_get_data (child, "special-child-type");

  if (special_type && !strcmp (special_type, "overlay"))
    {
      g_object_set_data (child, "special-child-type", NULL);
      gtk_widget_show (GTK_WIDGET (child));
    }

  gtk_container_remove (GTK_CONTAINER (object), GTK_WIDGET (child));
  
  if (gtk_bin_get_child (GTK_BIN (object)) == NULL)
    gtk_container_add (GTK_CONTAINER (object), glade_placeholder_new ());
}