/*
 *  $Id: data-view-layer.c 29656 2026-03-26 10:21:10Z yeti-dn $
 *  Copyright (C) 2003-2024 David Necas (Yeti), Petr Klapetek.
 *  E-mail: yeti@gwyddion.net, klapetek@gwyddion.net.
 *
 *  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 2 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.
 */

#include "config.h"
#include <gtk/gtk.h>
#include <glib-object.h>

#include "libgwyddion/macros.h"

#include "libgwyui/data-view-layer.h"
#include "libgwyui/data-view.h"

enum {
    SGNL_PLUGGED,
    SGNL_UNPLUGGED,
    SGNL_UPDATED,
    NUM_SIGNALS
};

struct _GwyDataViewLayerPrivate {
    GtkWidget *parent;
};

struct _GwyDataViewLayerClassPrivate {
    gint dummy;
};

static void dispose          (GObject *object);

static guint signals[NUM_SIGNALS];
static GObjectClass *parent_class = NULL;

G_DEFINE_ABSTRACT_TYPE_WITH_CODE(GwyDataViewLayer, gwy_data_view_layer, G_TYPE_INITIALLY_UNOWNED,
                                 G_ADD_PRIVATE(GwyDataViewLayer))

static void
gwy_data_view_layer_class_init(GwyDataViewLayerClass *klass)
{
    GObjectClass *gobject_class = G_OBJECT_CLASS(klass);
    GType type = G_TYPE_FROM_CLASS(klass);

    parent_class = gwy_data_view_layer_parent_class;

    gobject_class->dispose = dispose;

   /**
    * GwyDataViewLayer::plugged:
    * @gwydataviewlayer: The #GwyDataViewLayer which received the signal.
    *
    * The ::plugged signal is emitted when a #GwyDataViewLayer is plugged into a #GwyDataView.
    **/
    signals[SGNL_PLUGGED] = g_signal_new("plugged", type,
                                         G_SIGNAL_RUN_FIRST,
                                         G_STRUCT_OFFSET(GwyDataViewLayerClass, plugged),
                                         NULL, NULL,
                                         g_cclosure_marshal_VOID__VOID,
                                         G_TYPE_NONE, 0);
    g_signal_set_va_marshaller(signals[SGNL_PLUGGED], type, g_cclosure_marshal_VOID__VOIDv);

    /**
     * GwyDataViewLayer::unplugged:
     * @gwydataviewlayer: The #GwyDataViewLayer which received the signal.
     *
     * The ::unplugged signal is emitted when a #GwyDataViewLayer is removed from its #GwyDataView.
     **/
    signals[SGNL_UNPLUGGED] = g_signal_new("unplugged", type,
                                           G_SIGNAL_RUN_FIRST,
                                           G_STRUCT_OFFSET(GwyDataViewLayerClass, unplugged),
                                           NULL, NULL,
                                           g_cclosure_marshal_VOID__VOID,
                                           G_TYPE_NONE, 0);
    g_signal_set_va_marshaller(signals[SGNL_UNPLUGGED], type, g_cclosure_marshal_VOID__VOIDv);

    /**
     * GwyDataViewLayer::updated:
     * @gwydataviewlayer: The #GwyDataViewLayer which received the signal.
     *
     * The ::updated signal is emitted when a #GwyDataViewLayer is updated; the exact means how a layer can be updated
     * depends its type.
     **/
    signals[SGNL_UPDATED] = g_signal_new("updated", type,
                                         G_SIGNAL_RUN_FIRST,
                                         G_STRUCT_OFFSET(GwyDataViewLayerClass, updated),
                                         NULL, NULL,
                                         g_cclosure_marshal_VOID__VOID,
                                         G_TYPE_NONE, 0);
    g_signal_set_va_marshaller(signals[SGNL_UPDATED], type, g_cclosure_marshal_VOID__VOIDv);
}

static void
gwy_data_view_layer_init(GwyDataViewLayer *layer)
{
    layer->priv = gwy_data_view_layer_get_instance_private(layer);
}

static void
dispose(GObject *object)
{
    GwyDataViewLayer *layer = GWY_DATA_VIEW_LAYER(object);

    g_clear_object(&layer->data);
    G_OBJECT_CLASS(parent_class)->dispose(object);
}

/**
 * gwy_data_view_layer_set_parent:
 * @layer: A data view layer.
 * @parent: Parent widget, currently restricted to #GwyDataView, or %NULL.
 *
 * Sets or unsets the parent widget of a data view layer.
 **/
void
gwy_data_view_layer_set_parent(GwyDataViewLayer *layer,
                               GtkWidget *parent)
{
    g_return_if_fail(GWY_IS_DATA_VIEW_LAYER(layer));
    GwyDataViewLayerPrivate *priv = layer->priv;
    gwy_debug("layer %p, parent %p (current %p)", layer, parent, priv->parent);
    if (parent == priv->parent)
        return;

    g_return_if_fail(!parent || GWY_IS_DATA_VIEW(parent));
    /* The order must be send signal first, really unplug later. Layers still want to see the parent while unplugging
     * to disconnect signals, etc. They could be keeping their own parent pointers just for that but they should not
     * have to. */
    if (priv->parent) {
        gwy_debug("unplugging from %p", priv->parent);
        g_signal_emit(layer, signals[SGNL_UNPLUGGED], 0);
        priv->parent = NULL;
    }
    if (parent) {
        priv->parent = parent;
        gwy_debug("plugging to %p", priv->parent);
        g_signal_emit(layer, signals[SGNL_PLUGGED], 0);
    }
}

/**
 * gwy_data_view_layer_get_parent:
 * @layer: A data view layer.
 *
 * Gets the parent widget of a data view layer.
 *
 * Returns: The parent widget, of %NULL if there is none.
 **/
GtkWidget*
gwy_data_view_layer_get_parent(GwyDataViewLayer *layer)
{
    g_return_val_if_fail(GWY_IS_DATA_VIEW_LAYER(layer), NULL);
    return layer->priv->parent;
}

/**
 * gwy_data_view_layer_updated:
 * @layer: A data view layer.
 *
 * Emits a "updated" singal on a layer.
 **/
void
gwy_data_view_layer_updated(GwyDataViewLayer *layer)
{
    g_return_if_fail(GWY_IS_DATA_VIEW_LAYER(layer));
    gwy_debug("%p: emitting \"updated\"", layer);
    g_signal_emit(layer, signals[SGNL_UPDATED], 0);
}

/**
 * SECTION: data-view-layer
 * @title: GwyDataViewLayer
 * @short_description: Layer GwyDataView is composed of
 * @see_also: #GwyDataView -- data display widget,
 *            <link linkend="libgwyui-pixbuf-render">pixbuf-render</link> --
 *            low level functions for painting data fields,
 *
 * #GwyDataViewLayer's are parts of #GwyDataView.  They are not widgets and they are not normally usable outside of
 * a data view.
 **/

/* vim: set cin columns=120 tw=118 et ts=4 sw=4 cino=>1s,e0,n0,f0,{0,}0,^0,\:1s,=0,g1s,h0,t0,+1s,c3,(0,u0 : */
