/* PIKA - Photo and Image Kooker Application * a rebranding of The GNU Image Manipulation Program (created with heckimp) * A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio * * Original copyright, applying to most contents (license remains unchanged): * Copyright (C) 1995 Spencer Kimball and Peter Mattis * * pikadockcolumns.c * Copyright (C) 2009 Martin Nordholts * * 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, see . */ #include "config.h" #include #include #include "libpikabase/pikabase.h" #include "widgets-types.h" #include "core/pika.h" #include "core/pikacontext.h" #include "menus/menus.h" #include "pikadialogfactory.h" #include "pikadock.h" #include "pikadockable.h" #include "pikadockbook.h" #include "pikadockcolumns.h" #include "pikamenudock.h" #include "pikapanedbox.h" #include "pikatoolbox.h" #include "pikauimanager.h" #include "pika-log.h" enum { PROP_0, PROP_CONTEXT, PROP_DIALOG_FACTORY, PROP_UI_MANAGER }; enum { DOCK_ADDED, DOCK_REMOVED, LAST_SIGNAL }; struct _PikaDockColumnsPrivate { PikaContext *context; PikaDialogFactory *dialog_factory; PikaUIManager *ui_manager; GList *docks; GtkWidget *paned_hbox; }; static void pika_dock_columns_dispose (GObject *object); static void pika_dock_columns_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); static void pika_dock_columns_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec); static gboolean pika_dock_columns_dropped_cb (GtkWidget *notebook, GtkWidget *child, gint insert_index, gpointer data); static void pika_dock_columns_real_dock_added (PikaDockColumns *dock_columns, PikaDock *dock); static void pika_dock_columns_real_dock_removed (PikaDockColumns *dock_columns, PikaDock *dock); static void pika_dock_columns_dock_book_removed (PikaDockColumns *dock_columns, PikaDockbook *dockbook, PikaDock *dock); G_DEFINE_TYPE_WITH_PRIVATE (PikaDockColumns, pika_dock_columns, GTK_TYPE_BOX) #define parent_class pika_dock_columns_parent_class static guint dock_columns_signals[LAST_SIGNAL] = { 0 }; static void pika_dock_columns_class_init (PikaDockColumnsClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = pika_dock_columns_dispose; object_class->set_property = pika_dock_columns_set_property; object_class->get_property = pika_dock_columns_get_property; klass->dock_added = pika_dock_columns_real_dock_added; klass->dock_removed = pika_dock_columns_real_dock_removed; g_object_class_install_property (object_class, PROP_CONTEXT, g_param_spec_object ("context", NULL, NULL, PIKA_TYPE_CONTEXT, PIKA_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_DIALOG_FACTORY, g_param_spec_object ("dialog-factory", NULL, NULL, PIKA_TYPE_DIALOG_FACTORY, PIKA_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); g_object_class_install_property (object_class, PROP_UI_MANAGER, g_param_spec_object ("ui-manager", NULL, NULL, PIKA_TYPE_UI_MANAGER, PIKA_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)); dock_columns_signals[DOCK_ADDED] = g_signal_new ("dock-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (PikaDockColumnsClass, dock_added), NULL, NULL, NULL, G_TYPE_NONE, 1, PIKA_TYPE_DOCK); dock_columns_signals[DOCK_REMOVED] = g_signal_new ("dock-removed", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_FIRST, G_STRUCT_OFFSET (PikaDockColumnsClass, dock_removed), NULL, NULL, NULL, G_TYPE_NONE, 1, PIKA_TYPE_DOCK); } static void pika_dock_columns_init (PikaDockColumns *dock_columns) { gtk_orientable_set_orientation (GTK_ORIENTABLE (dock_columns), GTK_ORIENTATION_HORIZONTAL); dock_columns->p = pika_dock_columns_get_instance_private (dock_columns); dock_columns->p->paned_hbox = pika_paned_box_new (FALSE, 0, GTK_ORIENTATION_HORIZONTAL); pika_paned_box_set_dropped_cb (PIKA_PANED_BOX (dock_columns->p->paned_hbox), pika_dock_columns_dropped_cb, dock_columns); gtk_box_pack_start (GTK_BOX (dock_columns), dock_columns->p->paned_hbox, TRUE, TRUE, 0); gtk_widget_show (dock_columns->p->paned_hbox); } static void pika_dock_columns_dispose (GObject *object) { PikaDockColumns *dock_columns = PIKA_DOCK_COLUMNS (object); while (dock_columns->p->docks) { PikaDock *dock = dock_columns->p->docks->data; g_object_ref (dock); pika_dock_columns_remove_dock (dock_columns, dock); gtk_widget_destroy (GTK_WIDGET (dock)); g_object_unref (dock); } g_clear_weak_pointer (&dock_columns->p->context); g_clear_weak_pointer (&dock_columns->p->dialog_factory); g_clear_weak_pointer (&dock_columns->p->ui_manager); G_OBJECT_CLASS (parent_class)->dispose (object); } static void pika_dock_columns_set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) { PikaDockColumns *dock_columns = PIKA_DOCK_COLUMNS (object); switch (property_id) { case PROP_CONTEXT: g_set_weak_pointer (&dock_columns->p->context, g_value_get_object (value)); break; case PROP_DIALOG_FACTORY: g_set_weak_pointer (&dock_columns->p->dialog_factory, g_value_get_object (value)); break; case PROP_UI_MANAGER: g_set_weak_pointer (&dock_columns->p->ui_manager, g_value_get_object (value)); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static void pika_dock_columns_get_property (GObject *object, guint property_id, GValue *value, GParamSpec *pspec) { PikaDockColumns *dock_columns = PIKA_DOCK_COLUMNS (object); switch (property_id) { case PROP_CONTEXT: g_value_set_object (value, dock_columns->p->context); break; case PROP_DIALOG_FACTORY: g_value_set_object (value, dock_columns->p->dialog_factory); break; case PROP_UI_MANAGER: g_value_set_object (value, dock_columns->p->ui_manager); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); break; } } static gboolean pika_dock_columns_dropped_cb (GtkWidget *notebook, GtkWidget *child, gint insert_index, gpointer data) { PikaDockColumns *dock_columns = PIKA_DOCK_COLUMNS (data); PikaDockable *dockable = PIKA_DOCKABLE (child); GtkWidget *new_dockbook = NULL; /* Create a new dock (including a new dockbook) */ pika_dock_columns_prepare_dockbook (dock_columns, insert_index, &new_dockbook); /* Move the dockable to the new dockbook */ g_object_ref (new_dockbook); g_object_ref (dockable); gtk_notebook_detach_tab (GTK_NOTEBOOK (notebook), child); gtk_notebook_append_page (GTK_NOTEBOOK (new_dockbook), child, NULL); g_object_unref (dockable); g_object_unref (new_dockbook); return TRUE; } static void pika_dock_columns_real_dock_added (PikaDockColumns *dock_columns, PikaDock *dock) { } static void pika_dock_columns_real_dock_removed (PikaDockColumns *dock_columns, PikaDock *dock) { } static void pika_dock_columns_dock_book_removed (PikaDockColumns *dock_columns, PikaDockbook *dockbook, PikaDock *dock) { g_return_if_fail (PIKA_IS_DOCK (dock)); if (pika_dock_get_dockbooks (dock) == NULL && ! PIKA_IS_TOOLBOX (dock) && gtk_widget_get_parent (GTK_WIDGET (dock)) != NULL) pika_dock_columns_remove_dock (dock_columns, dock); } /** * pika_dock_columns_new: * @context: * * Returns: A new #PikaDockColumns. **/ GtkWidget * pika_dock_columns_new (PikaContext *context, PikaDialogFactory *dialog_factory, PikaUIManager *ui_manager) { g_return_val_if_fail (PIKA_IS_CONTEXT (context), NULL); g_return_val_if_fail (PIKA_IS_DIALOG_FACTORY (dialog_factory), NULL); g_return_val_if_fail (PIKA_IS_UI_MANAGER (ui_manager), NULL); return g_object_new (PIKA_TYPE_DOCK_COLUMNS, "context", context, "dialog-factory", dialog_factory, "ui-manager", ui_manager, NULL); } /** * pika_dock_columns_add_dock: * @dock_columns: * @dock: * * Add a dock, added to a horizontal PikaPanedBox. **/ void pika_dock_columns_add_dock (PikaDockColumns *dock_columns, PikaDock *dock, gint index) { g_return_if_fail (PIKA_IS_DOCK_COLUMNS (dock_columns)); g_return_if_fail (PIKA_IS_DOCK (dock)); PIKA_LOG (DND, "Adding PikaDock %p to PikaDockColumns %p", dock, dock_columns); dock_columns->p->docks = g_list_insert (dock_columns->p->docks, dock, index); pika_dock_update_with_context (dock, dock_columns->p->context); pika_paned_box_add_widget (PIKA_PANED_BOX (dock_columns->p->paned_hbox), GTK_WIDGET (dock), index); g_signal_connect_object (dock, "book-removed", G_CALLBACK (pika_dock_columns_dock_book_removed), dock_columns, G_CONNECT_SWAPPED); g_signal_emit (dock_columns, dock_columns_signals[DOCK_ADDED], 0, dock); } /** * pika_dock_columns_prepare_dockbook: * @dock_columns: * @dock_index: * @dockbook_p: * * Create a new dock and add it to the dock columns with the given * dock_index insert index, then create and add a dockbook and put it * in the dock. **/ void pika_dock_columns_prepare_dockbook (PikaDockColumns *dock_columns, gint dock_index, GtkWidget **dockbook_p) { PikaDialogFactory *dialog_factory; PikaMenuFactory *menu_factory; GtkWidget *dock; GtkWidget *dockbook; dock = pika_menu_dock_new (); pika_dock_columns_add_dock (dock_columns, PIKA_DOCK (dock), dock_index); dialog_factory = dock_columns->p->dialog_factory; menu_factory = menus_get_global_menu_factory (pika_dialog_factory_get_context (dialog_factory)->pika); dockbook = pika_dockbook_new (menu_factory); pika_dock_add_book (PIKA_DOCK (dock), PIKA_DOCKBOOK (dockbook), -1); gtk_widget_show (GTK_WIDGET (dock)); if (dockbook_p) *dockbook_p = dockbook; } void pika_dock_columns_remove_dock (PikaDockColumns *dock_columns, PikaDock *dock) { g_return_if_fail (PIKA_IS_DOCK_COLUMNS (dock_columns)); g_return_if_fail (PIKA_IS_DOCK (dock)); PIKA_LOG (DND, "Removing PikaDock %p from PikaDockColumns %p", dock, dock_columns); dock_columns->p->docks = g_list_remove (dock_columns->p->docks, dock); pika_dock_update_with_context (dock, NULL); g_signal_handlers_disconnect_by_func (dock, pika_dock_columns_dock_book_removed, dock_columns); g_object_ref (dock); pika_paned_box_remove_widget (PIKA_PANED_BOX (dock_columns->p->paned_hbox), GTK_WIDGET (dock)); g_signal_emit (dock_columns, dock_columns_signals[DOCK_REMOVED], 0, dock); g_object_unref (dock); } GList * pika_dock_columns_get_docks (PikaDockColumns *dock_columns) { g_return_val_if_fail (PIKA_IS_DOCK_COLUMNS (dock_columns), NULL); return dock_columns->p->docks; } PikaContext * pika_dock_columns_get_context (PikaDockColumns *dock_columns) { g_return_val_if_fail (PIKA_IS_DOCK_COLUMNS (dock_columns), NULL); return dock_columns->p->context; } void pika_dock_columns_set_context (PikaDockColumns *dock_columns, PikaContext *context) { g_return_if_fail (PIKA_IS_DOCK_COLUMNS (dock_columns)); dock_columns->p->context = context; } PikaDialogFactory * pika_dock_columns_get_dialog_factory (PikaDockColumns *dock_columns) { g_return_val_if_fail (PIKA_IS_DOCK_COLUMNS (dock_columns), NULL); return dock_columns->p->dialog_factory; } PikaUIManager * pika_dock_columns_get_ui_manager (PikaDockColumns *dock_columns) { g_return_val_if_fail (PIKA_IS_DOCK_COLUMNS (dock_columns), NULL); return dock_columns->p->ui_manager; }