Blob Blame History Raw
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8; coding: utf-8 -*-
 *
 * This file is part of GtkSourceView
 *
 * Copyright (C) 2014 - Christian Hergert
 * Copyright (C) 2014 - Ignacio Casal Quinteiro
 *
 * GtkSourceView 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.
 *
 * GtkSourceView 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 GtkSourceView. If not, see <http://www.gnu.org/licenses/>.
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "gtksourcestyleschemechooserbutton.h"
#include "gtksourcestyleschemechooser.h"
#include "gtksourcestyleschemechooserwidget.h"
#include "gtksourcestylescheme.h"
#include "gtksourceview-i18n.h"

/**
 * SECTION:styleschemechooserbutton
 * @Short_description: A button to launch a style scheme selection dialog
 * @Title: GtkSourceStyleSchemeChooserButton
 * @See_also: #GtkSourceStyleSchemeChooserWidget
 *
 * The #GtkSourceStyleSchemeChooserButton is a button which displays
 * the currently selected style scheme and allows to open a style scheme
 * selection dialog to change the style scheme.
 * It is suitable widget for selecting a style scheme in a preference dialog.
 *
 * In #GtkSourceStyleSchemeChooserButton, a #GtkSourceStyleSchemeChooserWidget
 * is used to provide a dialog for selecting style schemes.
 *
 * Since: 3.16
 */

typedef struct
{
	GtkSourceStyleScheme *scheme;

	GtkWidget *dialog;
	GtkSourceStyleSchemeChooserWidget *chooser;
} GtkSourceStyleSchemeChooserButtonPrivate;

static void gtk_source_style_scheme_chooser_button_style_scheme_chooser_interface_init (GtkSourceStyleSchemeChooserInterface *iface);

G_DEFINE_TYPE_WITH_CODE (GtkSourceStyleSchemeChooserButton,
                         gtk_source_style_scheme_chooser_button,
                         GTK_TYPE_BUTTON,
                         G_ADD_PRIVATE (GtkSourceStyleSchemeChooserButton)
                         G_IMPLEMENT_INTERFACE (GTK_SOURCE_TYPE_STYLE_SCHEME_CHOOSER,
                                                gtk_source_style_scheme_chooser_button_style_scheme_chooser_interface_init))

#define GET_PRIV(o) gtk_source_style_scheme_chooser_button_get_instance_private (o)

enum
{
	PROP_0,
	PROP_STYLE_SCHEME
};

static void
gtk_source_style_scheme_chooser_button_dispose (GObject *object)
{
	GtkSourceStyleSchemeChooserButton *button = GTK_SOURCE_STYLE_SCHEME_CHOOSER_BUTTON (object);
	GtkSourceStyleSchemeChooserButtonPrivate *priv = GET_PRIV (button);

	g_clear_object (&priv->scheme);

	G_OBJECT_CLASS (gtk_source_style_scheme_chooser_button_parent_class)->dispose (object);
}

static void
gtk_source_style_scheme_chooser_button_get_property (GObject    *object,
                                                     guint       prop_id,
                                                     GValue     *value,
                                                     GParamSpec *pspec)
{
	switch (prop_id)
	{
		case PROP_STYLE_SCHEME:
			g_value_set_object (value,
			                    gtk_source_style_scheme_chooser_get_style_scheme (GTK_SOURCE_STYLE_SCHEME_CHOOSER (object)));
			break;

		default:
			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
	}
}

static void
gtk_source_style_scheme_chooser_button_set_property (GObject      *object,
                                                     guint         prop_id,
                                                     const GValue *value,
                                                     GParamSpec   *pspec)
{
	switch (prop_id)
	{
		case PROP_STYLE_SCHEME:
			gtk_source_style_scheme_chooser_set_style_scheme (GTK_SOURCE_STYLE_SCHEME_CHOOSER (object),
			                                                  g_value_get_object (value));
			break;

		default:
			G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
	}
}

static void
gtk_source_style_scheme_chooser_button_constructed (GObject *object)
{
	GtkSourceStyleSchemeChooserButton *button = GTK_SOURCE_STYLE_SCHEME_CHOOSER_BUTTON (object);

	G_OBJECT_CLASS (gtk_source_style_scheme_chooser_button_parent_class)->constructed (object);

	gtk_source_style_scheme_chooser_set_style_scheme (GTK_SOURCE_STYLE_SCHEME_CHOOSER (button),
	                                                  _gtk_source_style_scheme_get_default ());
}

static gboolean
dialog_destroy (GtkWidget *widget,
                gpointer   data)
{
	GtkSourceStyleSchemeChooserButton *button = GTK_SOURCE_STYLE_SCHEME_CHOOSER_BUTTON (data);
	GtkSourceStyleSchemeChooserButtonPrivate *priv = GET_PRIV (button);

	priv->dialog = NULL;
	priv->chooser = NULL;

	return FALSE;
}

static void
dialog_response (GtkDialog *dialog,
                 gint       response,
                 gpointer   data)
{
	if (response == GTK_RESPONSE_CANCEL)
	{
		gtk_widget_hide (GTK_WIDGET (dialog));
	}
	else if (response == GTK_RESPONSE_OK)
	{
		GtkSourceStyleSchemeChooserButton *button = GTK_SOURCE_STYLE_SCHEME_CHOOSER_BUTTON (data);
		GtkSourceStyleSchemeChooserButtonPrivate *priv = GET_PRIV (button);
		GtkSourceStyleScheme *scheme;

		scheme = gtk_source_style_scheme_chooser_get_style_scheme (GTK_SOURCE_STYLE_SCHEME_CHOOSER (priv->chooser));

		gtk_widget_hide (GTK_WIDGET (dialog));

		gtk_source_style_scheme_chooser_set_style_scheme (GTK_SOURCE_STYLE_SCHEME_CHOOSER (button),
		                                                  scheme);
	}
}

/* Create the dialog and connects its buttons */
static void
ensure_dialog (GtkSourceStyleSchemeChooserButton *button)
{
	GtkSourceStyleSchemeChooserButtonPrivate *priv = GET_PRIV (button);
	GtkWidget *parent, *dialog, *scrolled_window;
	GtkWidget *content_area;

	if (priv->dialog != NULL)
	{
		return;
	}

	parent = gtk_widget_get_toplevel (GTK_WIDGET (button));

	/* TODO: have a ChooserDialog? */
	priv->dialog = dialog = gtk_dialog_new_with_buttons (_("Select a Style"),
	                                                     GTK_WINDOW (parent),
	                                                     GTK_DIALOG_DESTROY_WITH_PARENT |
	                                                     GTK_DIALOG_USE_HEADER_BAR,
	                                                     _("_Cancel"), GTK_RESPONSE_CANCEL,
	                                                     _("_Select"), GTK_RESPONSE_OK,
	                                                     NULL);
	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);

	scrolled_window = gtk_scrolled_window_new (NULL, NULL);
	gtk_widget_set_size_request (scrolled_window, 325, 350);
	gtk_widget_show (scrolled_window);
	gtk_widget_set_hexpand (scrolled_window, TRUE);
	gtk_widget_set_vexpand (scrolled_window, TRUE);
	content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
	gtk_container_add (GTK_CONTAINER (content_area), scrolled_window);

	priv->chooser = GTK_SOURCE_STYLE_SCHEME_CHOOSER_WIDGET (gtk_source_style_scheme_chooser_widget_new ());
	gtk_widget_show (GTK_WIDGET (priv->chooser));
	gtk_source_style_scheme_chooser_set_style_scheme (GTK_SOURCE_STYLE_SCHEME_CHOOSER (priv->chooser),
	                                                  priv->scheme);

	gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (priv->chooser));

	if (gtk_widget_is_toplevel (parent) && GTK_IS_WINDOW (parent))
	{
		if (GTK_WINDOW (parent) != gtk_window_get_transient_for (GTK_WINDOW (dialog)))
		{
			gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (parent));
		}

		gtk_window_set_modal (GTK_WINDOW (dialog),
		                      gtk_window_get_modal (GTK_WINDOW (parent)));
	}

	g_signal_connect (dialog, "response",
	                  G_CALLBACK (dialog_response), button);
	g_signal_connect (dialog, "destroy",
	                  G_CALLBACK (dialog_destroy), button);
}

static void
gtk_source_style_scheme_chooser_button_clicked (GtkButton *button)
{
	GtkSourceStyleSchemeChooserButton *cbutton = GTK_SOURCE_STYLE_SCHEME_CHOOSER_BUTTON (button);
	GtkSourceStyleSchemeChooserButtonPrivate *priv = GET_PRIV (cbutton);

	ensure_dialog (cbutton);

	gtk_source_style_scheme_chooser_set_style_scheme (GTK_SOURCE_STYLE_SCHEME_CHOOSER (priv->chooser),
	                                                  priv->scheme);

	gtk_window_present (GTK_WINDOW (priv->dialog));
}

static void
gtk_source_style_scheme_chooser_button_class_init (GtkSourceStyleSchemeChooserButtonClass *klass)
{
	GObjectClass *object_class = G_OBJECT_CLASS (klass);
	GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass);

	object_class->dispose = gtk_source_style_scheme_chooser_button_dispose;
	object_class->get_property = gtk_source_style_scheme_chooser_button_get_property;
	object_class->set_property = gtk_source_style_scheme_chooser_button_set_property;
	object_class->constructed = gtk_source_style_scheme_chooser_button_constructed;

	button_class->clicked = gtk_source_style_scheme_chooser_button_clicked;

	g_object_class_override_property (object_class, PROP_STYLE_SCHEME, "style-scheme");
}

static void
gtk_source_style_scheme_chooser_button_init (GtkSourceStyleSchemeChooserButton *button)
{
}

static GtkSourceStyleScheme *
gtk_source_style_scheme_chooser_button_get_style_scheme (GtkSourceStyleSchemeChooser *chooser)
{
	GtkSourceStyleSchemeChooserButton *button = GTK_SOURCE_STYLE_SCHEME_CHOOSER_BUTTON (chooser);
	GtkSourceStyleSchemeChooserButtonPrivate *priv = GET_PRIV (button);

	return priv->scheme;
}

static void
gtk_source_style_scheme_chooser_button_update_label (GtkSourceStyleSchemeChooserButton *button)
{
	GtkSourceStyleSchemeChooserButtonPrivate *priv = GET_PRIV (button);
	const gchar *label;

	label = priv->scheme != NULL ? gtk_source_style_scheme_get_name (priv->scheme) : NULL;
	gtk_button_set_label (GTK_BUTTON (button), label);
}

static void
gtk_source_style_scheme_chooser_button_set_style_scheme (GtkSourceStyleSchemeChooser *chooser,
                                                         GtkSourceStyleScheme        *scheme)
{
	GtkSourceStyleSchemeChooserButton *button = GTK_SOURCE_STYLE_SCHEME_CHOOSER_BUTTON (chooser);
	GtkSourceStyleSchemeChooserButtonPrivate *priv = GET_PRIV (button);

	if (g_set_object (&priv->scheme, scheme))
	{
		gtk_source_style_scheme_chooser_button_update_label (button);

		g_object_notify (G_OBJECT (button), "style-scheme");
	}
}

static void
gtk_source_style_scheme_chooser_button_style_scheme_chooser_interface_init (GtkSourceStyleSchemeChooserInterface *iface)
{
	iface->get_style_scheme = gtk_source_style_scheme_chooser_button_get_style_scheme;
	iface->set_style_scheme = gtk_source_style_scheme_chooser_button_set_style_scheme;
}

/**
 * gtk_source_style_scheme_chooser_button_new:
 *
 * Creates a new #GtkSourceStyleSchemeChooserButton.
 *
 * Returns: a new #GtkSourceStyleSchemeChooserButton.
 *
 * Since: 3.16
 */
GtkWidget *
gtk_source_style_scheme_chooser_button_new (void)
{
	return g_object_new (GTK_SOURCE_TYPE_STYLE_SCHEME_CHOOSER_BUTTON, NULL);
}