Initial checkin of Pika from heckimp

This commit is contained in:
2023-09-25 15:35:21 -07:00
commit 891e999216
6761 changed files with 5240685 additions and 0 deletions

134
libpikawidgets/Makefile.gi Normal file
View File

@ -0,0 +1,134 @@
libpikawidgets_introspectable_headers = \
../libpikawidgets/pikabrowser.h \
../libpikawidgets/pikabusybox.h \
../libpikawidgets/pikabutton.h \
../libpikawidgets/pikacairo-utils.h \
../libpikawidgets/pikacellrenderercolor.h \
../libpikawidgets/pikacellrenderertoggle.h \
../libpikawidgets/pikachainbutton.h \
../libpikawidgets/pikacolorarea.h \
../libpikawidgets/pikacolorbutton.h \
../libpikawidgets/pikacolordisplay.h \
../libpikawidgets/pikacolordisplaystack.h \
../libpikawidgets/pikacolorhexentry.h \
../libpikawidgets/pikacolornotebook.h \
../libpikawidgets/pikacolorprofilechooserdialog.h \
../libpikawidgets/pikacolorprofilecombobox.h \
../libpikawidgets/pikacolorprofilestore.h \
../libpikawidgets/pikacolorprofileview.h \
## ../libpikawidgets/pikacolorscale.h
../libpikawidgets/pikacolorscaleentry.h \
## ../libpikawidgets/pikacolorscales.h
## ../libpikawidgets/pikacolorselect.h
../libpikawidgets/pikacolorselection.h \
../libpikawidgets/pikacolorselector.h \
../libpikawidgets/pikadialog.h \
../libpikawidgets/pikaenumcombobox.h \
../libpikawidgets/pikaenumlabel.h \
../libpikawidgets/pikaenumstore.h \
../libpikawidgets/pikaenumwidgets.h \
../libpikawidgets/pikafileentry.h \
../libpikawidgets/pikaframe.h \
../libpikawidgets/pikahelpui.h \
../libpikawidgets/pikahintbox.h \
../libpikawidgets/pikaicons.h \
../libpikawidgets/pikaintcombobox.h \
../libpikawidgets/pikaintradioframe.h \
../libpikawidgets/pikaintstore.h \
../libpikawidgets/pikalabelcolor.h \
../libpikawidgets/pikalabeled.h \
../libpikawidgets/pikalabelentry.h \
../libpikawidgets/pikalabelintwidget.h \
../libpikawidgets/pikalabelspin.h \
../libpikawidgets/pikamemsizeentry.h \
../libpikawidgets/pikanumberpairentry.h \
../libpikawidgets/pikaoffsetarea.h \
../libpikawidgets/pikapageselector.h \
../libpikawidgets/pikapatheditor.h \
../libpikawidgets/pikapickbutton.h \
../libpikawidgets/pikapreview.h \
../libpikawidgets/pikapreviewarea.h \
../libpikawidgets/pikapropwidgets.h \
../libpikawidgets/pikaquerybox.h \
../libpikawidgets/pikaruler.h \
../libpikawidgets/pikascaleentry.h \
../libpikawidgets/pikascrolledpreview.h \
../libpikawidgets/pikasizeentry.h \
../libpikawidgets/pikaspinbutton.h \
../libpikawidgets/pikaspinscale.h \
../libpikawidgets/pikastringcombobox.h \
../libpikawidgets/pikaunitcombobox.h \
../libpikawidgets/pikaunitstore.h \
../libpikawidgets/pikawidgets-error.h \
../libpikawidgets/pikawidgets.h \
../libpikawidgets/pikawidgetsenums.h \
../libpikawidgets/pikawidgetstypes.h \
../libpikawidgets/pikawidgetsutils.h \
../libpikawidgets/pikazoommodel.h
libpikawidgets_introspectable = \
../libpikawidgets/pikabrowser.c \
../libpikawidgets/pikabusybox.c \
../libpikawidgets/pikabutton.c \
../libpikawidgets/pikacairo-utils.c \
../libpikawidgets/pikacellrenderercolor.c \
../libpikawidgets/pikacellrenderertoggle.c \
../libpikawidgets/pikachainbutton.c \
../libpikawidgets/pikacolorarea.c \
../libpikawidgets/pikacolorbutton.c \
../libpikawidgets/pikacolordisplay.c \
../libpikawidgets/pikacolordisplaystack.c \
../libpikawidgets/pikacolorhexentry.c \
../libpikawidgets/pikacolornotebook.c \
../libpikawidgets/pikacolorprofilechooserdialog.c \
../libpikawidgets/pikacolorprofilecombobox.c \
../libpikawidgets/pikacolorprofilestore.c \
../libpikawidgets/pikacolorprofileview.c \
## ../libpikawidgets/pikacolorscale.c
../libpikawidgets/pikacolorscaleentry.c \
## ../libpikawidgets/pikacolorscales.c
## ../libpikawidgets/pikacolorselect.c
../libpikawidgets/pikacolorselection.c \
../libpikawidgets/pikacolorselector.c \
../libpikawidgets/pikadialog.c \
../libpikawidgets/pikaenumcombobox.c \
../libpikawidgets/pikaenumlabel.c \
../libpikawidgets/pikaenumstore.c \
../libpikawidgets/pikaenumwidgets.c \
../libpikawidgets/pikafileentry.c \
../libpikawidgets/pikaframe.c \
../libpikawidgets/pikahelpui.c \
../libpikawidgets/pikahintbox.c \
../libpikawidgets/pikaicons.c \
../libpikawidgets/pikaintcombobox.c \
../libpikawidgets/pikaintradioframe.c \
../libpikawidgets/pikaintstore.c \
../libpikawidgets/pikalabelcolor.c \
../libpikawidgets/pikalabeled.c \
../libpikawidgets/pikalabelentry.c \
../libpikawidgets/pikalabelintwidget.c \
../libpikawidgets/pikalabelspin.c \
../libpikawidgets/pikamemsizeentry.c \
../libpikawidgets/pikanumberpairentry.c \
../libpikawidgets/pikaoffsetarea.c \
../libpikawidgets/pikapageselector.c \
../libpikawidgets/pikapatheditor.c \
../libpikawidgets/pikapickbutton.c \
../libpikawidgets/pikapreview.c \
../libpikawidgets/pikapreviewarea.c \
../libpikawidgets/pikapropwidgets.c \
../libpikawidgets/pikaquerybox.c \
../libpikawidgets/pikaruler.c \
../libpikawidgets/pikascaleentry.c \
../libpikawidgets/pikascrolledpreview.c \
../libpikawidgets/pikasizeentry.c \
../libpikawidgets/pikaspinbutton.c \
../libpikawidgets/pikaspinscale.c \
../libpikawidgets/pikastringcombobox.c \
../libpikawidgets/pikaunitcombobox.c \
../libpikawidgets/pikaunitstore.c \
../libpikawidgets/pikawidgets-error.c \
../libpikawidgets/pikawidgets.c \
../libpikawidgets/pikawidgetsutils.c \
../libpikawidgets/pikazoommodel.c \
$(libpikawidgets_introspectable_headers)

250
libpikawidgets/meson.build Normal file
View File

@ -0,0 +1,250 @@
stamp_widgets_enums = custom_target('stamp-pikawidgetsenums.h',
input : [
files(
'pikawidgetsenums.h'
),
],
output: [ 'stamp-pikawidgetsenums.h', ],
command: [
mkenums_wrap, perl,
meson.project_source_root(), meson.current_source_dir(),
meson.current_build_dir(),
'pikawidgets',
'#include <gio/gio.h>\n' +
'#include "libpikabase/pikabase.h"\n',
'#include "libpika/libpika-intl.h"',
libpika_mkenums_dtails
],
build_by_default: true
)
pikawidgetsmarshal = gnome.genmarshal('pikawidgetsmarshal',
prefix: '_pika_widgets_marshal',
sources: 'pikawidgetsmarshal.list',
install_header: false,
)
libpikawidgets_sources_introspectable = files(
'pikabrowser.c',
'pikabusybox.c',
'pikabutton.c',
'pikacairo-utils.c',
'pikacellrenderercolor.c',
'pikacellrenderertoggle.c',
'pikachainbutton.c',
'pikacolorarea.c',
'pikacolorbutton.c',
'pikacolordisplay.c',
'pikacolordisplaystack.c',
'pikacolorhexentry.c',
'pikacolornotebook.c',
'pikacolorprofilechooserdialog.c',
'pikacolorprofilecombobox.c',
'pikacolorprofilestore.c',
'pikacolorprofileview.c',
'pikacolorscaleentry.c',
'pikacolorselection.c',
'pikacolorselector.c',
'pikadialog.c',
'pikaenumcombobox.c',
'pikaenumlabel.c',
'pikaenumstore.c',
'pikaenumwidgets.c',
'pikafileentry.c',
'pikaframe.c',
'pikahelpui.c',
'pikahintbox.c',
'pikaicons.c',
'pikaintcombobox.c',
'pikaintradioframe.c',
'pikaintstore.c',
'pikalabelcolor.c',
'pikalabeled.c',
'pikalabelintwidget.c',
'pikalabelspin.c',
'pikalabelentry.c',
'pikamemsizeentry.c',
'pikanumberpairentry.c',
'pikaoffsetarea.c',
'pikapageselector.c',
'pikapatheditor.c',
'pikapickbutton.c',
'pikapreview.c',
'pikapreviewarea.c',
'pikapropwidgets.c',
'pikaquerybox.c',
'pikaruler.c',
'pikascaleentry.c',
'pikascrolledpreview.c',
'pikasizeentry.c',
'pikaspinbutton.c',
'pikaspinscale.c',
'pikastringcombobox.c',
'pikaunitcombobox.c',
'pikaunitstore.c',
'pikawidgets-error.c',
'pikawidgets.c',
'pikawidgetsutils.c',
'pikazoommodel.c',
)
libpikawidgets_sources = [
libpikawidgets_sources_introspectable,
'pikacolorscale.c',
'pikacolorscales.c',
'pikacolorselect.c',
'pikacontroller.c',
'pikaeevl.c',
'pikawidgets-private.c',
'pikawidgetsenums.c',
stamp_widgets_enums,
pikawidgetsmarshal,
icons_imgs_sources,
cursors_sources,
pickers_sources,
]
libpikawidgets_headers_introspectable = files(
'pikabrowser.h',
'pikabusybox.h',
'pikabutton.h',
'pikacairo-utils.h',
'pikacellrenderercolor.h',
'pikacellrenderertoggle.h',
'pikachainbutton.h',
'pikacolorarea.h',
'pikacolorbutton.h',
'pikacolordisplay.h',
'pikacolordisplaystack.h',
'pikacolorhexentry.h',
'pikacolornotebook.h',
'pikacolorprofilechooserdialog.h',
'pikacolorprofilecombobox.h',
'pikacolorprofilestore.h',
'pikacolorprofileview.h',
'pikacolorscaleentry.h',
'pikacolorselection.h',
'pikacolorselector.h',
'pikadialog.h',
'pikaenumcombobox.h',
'pikaenumlabel.h',
'pikaenumstore.h',
'pikaenumwidgets.h',
'pikafileentry.h',
'pikaframe.h',
'pikahelpui.h',
'pikahintbox.h',
'pikaicons.h',
'pikaintcombobox.h',
'pikaintradioframe.h',
'pikalabelcolor.h',
'pikalabeled.h',
'pikalabelintwidget.h',
'pikalabelspin.h',
'pikalabelentry.h',
'pikaintstore.h',
'pikamemsizeentry.h',
'pikanumberpairentry.h',
'pikaoffsetarea.h',
'pikapageselector.h',
'pikapatheditor.h',
'pikapickbutton.h',
'pikapreview.h',
'pikapreviewarea.h',
'pikapropwidgets.h',
'pikaquerybox.h',
'pikaruler.h',
'pikascaleentry.h',
'pikascrolledpreview.h',
'pikasizeentry.h',
'pikaspinbutton.h',
'pikaspinscale.h',
'pikastringcombobox.h',
'pikaunitcombobox.h',
'pikaunitstore.h',
'pikawidgets-error.h',
'pikawidgets.h',
'pikawidgetsenums.h',
'pikawidgetstypes.h',
'pikawidgetsutils.h',
'pikazoommodel.h',
)
libpikawidgets_headers = [
libpikawidgets_headers_introspectable,
'pikacolorscale.h',
'pikacolorscales.h',
'pikacolorselect.h',
'pikacontroller.h',
]
libpikawidgets_introspectable = [
libpikawidgets_sources_introspectable,
libpikawidgets_headers_introspectable,
]
if platform_osx
libpikawidgets_sources += [
'pikapickbutton-quartz.c',
]
elif platform_windows
libpikawidgets_sources += [
'pikapickbutton-win32.c',
]
else
libpikawidgets_sources += [
'pikapickbutton-default.c',
'pikapickbutton-kwin.c',
'pikapickbutton-xdg.c',
]
endif
libpikawidgets = library('pikawidgets-'+ pika_api_version,
libpikawidgets_sources,
include_directories: rootInclude,
dependencies: [
gegl, gtk3, lcms, math, mscms
],
c_args: [ '-DG_LOG_DOMAIN="LibPikaWidgets"', '-DPIKA_WIDGETS_COMPILATION', ],
link_with: [
libpikabase,
libpikacolor,
libpikaconfig,
],
vs_module_defs: 'pikawidgets.def',
install: true,
version: so_version,
)
install_headers(
libpikawidgets_headers,
subdir: pika_api_name / 'libpikawidgets',
)
# Test programs, not installed
test_preview_area = executable('test-preview-area',
'test-preview-area.c',
include_directories: rootInclude,
dependencies: [
gtk3,
],
c_args: '-DG_LOG_DOMAIN="LibPikaWidgets"',
link_with: [ libpikawidgets, ],
install: false,
build_by_default: false,
)
test_eevl = executable('test-eevl',
'test-eevl.c',
include_directories: rootInclude,
dependencies: [
glib, gtk3, math,
],
c_args: '-DG_LOG_DOMAIN="LibPikaWidgets"',
link_with: [ libpikawidgets, ],
install: false,
)

View File

@ -0,0 +1,496 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikabrowser.c
* Copyright (C) 2005 Michael Natterer <mitch@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "pikawidgetstypes.h"
#include "pikawidgets.h"
#include "pikawidgetsmarshal.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikabrowser
* @title: PikaBrowser
* @short_description: A base class for a documentation browser.
*
* A base class for a documentation browser.
**/
enum
{
SEARCH,
LAST_SIGNAL
};
struct _PikaBrowserPrivate
{
GtkWidget *left_vbox;
GtkWidget *search_entry;
guint search_timeout_id;
GtkWidget *search_type_combo;
gint search_type;
GtkWidget *count_label;
GtkWidget *right_vbox;
GtkWidget *right_widget;
};
#define GET_PRIVATE(obj) (((PikaBrowser *) (obj))->priv)
static void pika_browser_dispose (GObject *object);
static void pika_browser_combo_changed (GtkComboBox *combo,
PikaBrowser *browser);
static void pika_browser_entry_changed (GtkEntry *entry,
PikaBrowser *browser);
static void pika_browser_entry_icon_press (GtkEntry *entry,
GtkEntryIconPosition icon_pos,
GdkEvent *event,
PikaBrowser *browser);
static gboolean pika_browser_search_timeout (gpointer data);
G_DEFINE_TYPE_WITH_PRIVATE (PikaBrowser, pika_browser, GTK_TYPE_PANED)
#define parent_class pika_browser_parent_class
static guint browser_signals[LAST_SIGNAL] = { 0 };
static void
pika_browser_class_init (PikaBrowserClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
browser_signals[SEARCH] =
g_signal_new ("search",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (PikaBrowserClass, search),
NULL, NULL,
_pika_widgets_marshal_VOID__STRING_INT,
G_TYPE_NONE, 2,
G_TYPE_STRING,
G_TYPE_INT);
object_class->dispose = pika_browser_dispose;
klass->search = NULL;
}
static void
pika_browser_init (PikaBrowser *browser)
{
PikaBrowserPrivate *priv;
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *scrolled_window;
GtkWidget *viewport;
browser->priv = pika_browser_get_instance_private (browser);
priv = GET_PRIVATE (browser);
gtk_orientable_set_orientation (GTK_ORIENTABLE (browser),
GTK_ORIENTATION_HORIZONTAL);
priv->search_type = -1;
priv->left_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_paned_pack1 (GTK_PANED (browser), priv->left_vbox, FALSE, TRUE);
gtk_widget_show (priv->left_vbox);
/* search entry */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (priv->left_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
label = gtk_label_new_with_mnemonic (_("_Search:"));
gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
priv->search_entry = gtk_entry_new ();
gtk_box_pack_start (GTK_BOX (hbox), priv->search_entry, TRUE, TRUE, 0);
gtk_widget_show (priv->search_entry);
gtk_label_set_mnemonic_widget (GTK_LABEL (label), priv->search_entry);
g_signal_connect (priv->search_entry, "changed",
G_CALLBACK (pika_browser_entry_changed),
browser);
gtk_entry_set_icon_from_icon_name (GTK_ENTRY (priv->search_entry),
GTK_ENTRY_ICON_SECONDARY, "edit-clear");
gtk_entry_set_icon_activatable (GTK_ENTRY (priv->search_entry),
GTK_ENTRY_ICON_SECONDARY, TRUE);
gtk_entry_set_icon_sensitive (GTK_ENTRY (priv->search_entry),
GTK_ENTRY_ICON_SECONDARY, FALSE);
g_signal_connect (priv->search_entry, "icon-press",
G_CALLBACK (pika_browser_entry_icon_press),
browser);
/* count label */
priv->count_label = gtk_label_new (_("No matches"));
gtk_label_set_xalign (GTK_LABEL (priv->count_label), 0.0);
pika_label_set_attributes (GTK_LABEL (priv->count_label),
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
-1);
gtk_box_pack_end (GTK_BOX (priv->left_vbox), priv->count_label,
FALSE, FALSE, 0);
gtk_widget_show (priv->count_label);
/* scrolled window */
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_ALWAYS);
gtk_paned_pack2 (GTK_PANED (browser), scrolled_window, TRUE, TRUE);
gtk_widget_show (scrolled_window);
viewport = gtk_viewport_new (NULL, NULL);
gtk_container_add (GTK_CONTAINER (scrolled_window), viewport);
gtk_widget_show (viewport);
priv->right_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_set_border_width (GTK_CONTAINER (priv->right_vbox), 12);
gtk_container_add (GTK_CONTAINER (viewport), priv->right_vbox);
gtk_widget_show (priv->right_vbox);
gtk_widget_grab_focus (priv->search_entry);
}
static void
pika_browser_dispose (GObject *object)
{
PikaBrowserPrivate *priv = GET_PRIVATE (object);
if (priv->search_timeout_id)
{
g_source_remove (priv->search_timeout_id);
priv->search_timeout_id = 0;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
/* public functions */
/**
* pika_browser_new:
*
* Create a new #PikaBrowser widget.
*
* Returns: a newly created #PikaBrowser.
*
* Since: 2.4
**/
GtkWidget *
pika_browser_new (void)
{
return g_object_new (PIKA_TYPE_BROWSER, NULL);
}
/**
* pika_browser_add_search_types: (skip)
* @browser: a #PikaBrowser widget
* @first_type_label: the label of the first search type
* @first_type_id: an integer that identifies the first search type
* @...: a %NULL-terminated list of more labels and ids.
*
* Populates the #GtkComboBox with search types.
*
* Since: 2.4
**/
void
pika_browser_add_search_types (PikaBrowser *browser,
const gchar *first_type_label,
gint first_type_id,
...)
{
PikaBrowserPrivate *priv;
g_return_if_fail (PIKA_IS_BROWSER (browser));
g_return_if_fail (first_type_label != NULL);
priv = GET_PRIVATE (browser);
if (! priv->search_type_combo)
{
GtkWidget *combo;
va_list args;
va_start (args, first_type_id);
combo = pika_int_combo_box_new_valist (first_type_label,
first_type_id,
args);
va_end (args);
gtk_widget_set_focus_on_click (combo, FALSE);
priv->search_type_combo = combo;
priv->search_type = first_type_id;
gtk_box_pack_end (GTK_BOX (gtk_widget_get_parent (priv->search_entry)),
combo, FALSE, FALSE, 0);
gtk_widget_show (combo);
pika_int_combo_box_connect (PIKA_INT_COMBO_BOX (combo),
priv->search_type,
G_CALLBACK (pika_int_combo_box_get_active),
&priv->search_type, NULL);
g_signal_connect (combo, "changed",
G_CALLBACK (pika_browser_combo_changed),
browser);
}
else
{
pika_int_combo_box_append (PIKA_INT_COMBO_BOX (priv->search_type_combo),
first_type_label, first_type_id,
NULL);
}
}
/**
* pika_browser_get_left_vbox:
* @browser: a #PikaBrowser widget
*
* Returns: (transfer none) (type GtkBox): The left vbox.
*
* Since: 3.0
**/
GtkWidget *
pika_browser_get_left_vbox (PikaBrowser *browser)
{
PikaBrowserPrivate *priv;
g_return_val_if_fail (PIKA_IS_BROWSER (browser), NULL);
priv = GET_PRIVATE (browser);
return priv->left_vbox;
}
/**
* pika_browser_get_right_vbox:
* @browser: a #PikaBrowser widget
*
* Returns: (transfer none) (type GtkBox): The right vbox.
*
* Since: 3.0
**/
GtkWidget *
pika_browser_get_right_vbox (PikaBrowser *browser)
{
PikaBrowserPrivate *priv;
g_return_val_if_fail (PIKA_IS_BROWSER (browser), NULL);
priv = GET_PRIVATE (browser);
return priv->right_vbox;
}
/**
* pika_browser_set_search_summary:
* @browser: a #PikaBrowser widget
* @summary: a string describing the search result
*
* Sets the search summary text.
*
* Since: 3.0
**/
void
pika_browser_set_search_summary (PikaBrowser *browser,
const gchar *summary)
{
PikaBrowserPrivate *priv;
g_return_if_fail (PIKA_IS_BROWSER (browser));
g_return_if_fail (summary != NULL);
priv = GET_PRIVATE (browser);
gtk_label_set_text (GTK_LABEL (priv->count_label), summary);
}
/**
* pika_browser_set_widget:
* @browser: a #PikaBrowser widget
* @widget: a #GtkWidget
*
* Sets the widget to appear on the right side of the @browser.
*
* Since: 2.4
**/
void
pika_browser_set_widget (PikaBrowser *browser,
GtkWidget *widget)
{
PikaBrowserPrivate *priv;
g_return_if_fail (PIKA_IS_BROWSER (browser));
g_return_if_fail (widget == NULL || GTK_IS_WIDGET (widget));
priv = GET_PRIVATE (browser);
if (widget == priv->right_widget)
return;
if (priv->right_widget)
gtk_container_remove (GTK_CONTAINER (priv->right_vbox),
priv->right_widget);
priv->right_widget = widget;
if (widget)
{
gtk_box_pack_start (GTK_BOX (priv->right_vbox), widget,
FALSE, FALSE, 0);
gtk_widget_show (widget);
}
}
/**
* pika_browser_show_message:
* @browser: a #PikaBrowser widget
* @message: text message
*
* Displays @message in the right side of the @browser. Unless the right
* side already contains a #GtkLabel, the widget previously added with
* pika_browser_set_widget() is removed and replaced by a #GtkLabel.
*
* Since: 2.4
**/
void
pika_browser_show_message (PikaBrowser *browser,
const gchar *message)
{
PikaBrowserPrivate *priv;
g_return_if_fail (PIKA_IS_BROWSER (browser));
g_return_if_fail (message != NULL);
priv = GET_PRIVATE (browser);
if (GTK_IS_LABEL (priv->right_widget))
{
gtk_label_set_text (GTK_LABEL (priv->right_widget), message);
}
else
{
GtkWidget *label = gtk_label_new (message);
pika_label_set_attributes (GTK_LABEL (label),
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
-1);
pika_browser_set_widget (browser, label);
}
while (gtk_events_pending ())
gtk_main_iteration ();
}
/* private functions */
static void
pika_browser_queue_search (PikaBrowser *browser)
{
PikaBrowserPrivate *priv = GET_PRIVATE (browser);
if (priv->search_timeout_id)
g_source_remove (priv->search_timeout_id);
priv->search_timeout_id =
g_timeout_add (100, pika_browser_search_timeout, browser);
}
static void
pika_browser_combo_changed (GtkComboBox *combo,
PikaBrowser *browser)
{
pika_browser_queue_search (browser);
}
static void
pika_browser_entry_changed (GtkEntry *entry,
PikaBrowser *browser)
{
pika_browser_queue_search (browser);
gtk_entry_set_icon_sensitive (entry,
GTK_ENTRY_ICON_SECONDARY,
gtk_entry_get_text_length (entry) > 0);
}
static void
pika_browser_entry_icon_press (GtkEntry *entry,
GtkEntryIconPosition icon_pos,
GdkEvent *event,
PikaBrowser *browser)
{
GdkEventButton *bevent = (GdkEventButton *) event;
if (icon_pos == GTK_ENTRY_ICON_SECONDARY && bevent->button == 1)
{
gtk_entry_set_text (entry, "");
}
}
static gboolean
pika_browser_search_timeout (gpointer data)
{
PikaBrowserPrivate *priv = GET_PRIVATE (data);
const gchar *search_string;
search_string = gtk_entry_get_text (GTK_ENTRY (priv->search_entry));
if (! search_string)
search_string = "";
g_signal_emit (data, browser_signals[SEARCH], 0,
search_string, priv->search_type);
priv->search_timeout_id = 0;
return FALSE;
}

View File

@ -0,0 +1,94 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikabrowser.h
* Copyright (C) 2005 Michael Natterer <mitch@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_BROWSER_H__
#define __PIKA_BROWSER_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
#define PIKA_TYPE_BROWSER (pika_browser_get_type ())
#define PIKA_BROWSER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_BROWSER, PikaBrowser))
#define PIKA_BROWSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_BROWSER, PikaBrowserClass))
#define PIKA_IS_BROWSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_BROWSER))
#define PIKA_IS_BROWSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_BROWSER))
#define PIKA_BROWSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_BROWSER, PikaBrowserClass))
typedef struct _PikaBrowserPrivate PikaBrowserPrivate;
typedef struct _PikaBrowserClass PikaBrowserClass;
struct _PikaBrowser
{
GtkPaned parent_instance;
PikaBrowserPrivate *priv;
};
struct _PikaBrowserClass
{
GtkPanedClass parent_class;
void (* search) (PikaBrowser *browser,
const gchar *search_string,
gint search_type);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_browser_get_type (void) G_GNUC_CONST;
GtkWidget * pika_browser_new (void);
void pika_browser_add_search_types (PikaBrowser *browser,
const gchar *first_type_label,
gint first_type_id,
...) G_GNUC_NULL_TERMINATED;
GtkWidget * pika_browser_get_left_vbox (PikaBrowser *browser);
GtkWidget * pika_browser_get_right_vbox (PikaBrowser *browser);
void pika_browser_set_search_summary (PikaBrowser *browser,
const gchar *summary);
void pika_browser_set_widget (PikaBrowser *browser,
GtkWidget *widget);
void pika_browser_show_message (PikaBrowser *browser,
const gchar *message);
G_END_DECLS
#endif /* __PIKA_BROWSER_H__ */

View File

@ -0,0 +1,232 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikabusybox.c
* Copyright (C) 2018 Ell
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "pikawidgetstypes.h"
#include "pikabusybox.h"
#include "pikawidgetsutils.h"
/**
* SECTION: pikabusybox
* @title: PikaBusyBox
* @short_description: A widget indicating an ongoing operation
*
* #PikaBusyBox displays a styled message, providing indication of
* an ongoing operation.
**/
enum
{
PROP_0,
PROP_MESSAGE
};
struct _PikaBusyBoxPrivate
{
GtkLabel *label;
};
/* local function prototypes */
static void pika_busy_box_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_busy_box_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE_WITH_PRIVATE (PikaBusyBox, pika_busy_box, GTK_TYPE_BOX)
#define parent_class pika_busy_box_parent_class
/* private functions */
static void
pika_busy_box_class_init (PikaBusyBoxClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = pika_busy_box_set_property;
object_class->get_property = pika_busy_box_get_property;
/**
* PikaBusyBox:message:
*
* Specifies the displayed message.
*
* Since: 2.10.4
**/
g_object_class_install_property (object_class, PROP_MESSAGE,
g_param_spec_string ("message",
"Message",
"The message to display",
NULL,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
}
static void
pika_busy_box_init (PikaBusyBox *box)
{
GtkWidget *spinner;
GtkWidget *label;
box->priv = pika_busy_box_get_instance_private (box);
gtk_widget_set_halign (GTK_WIDGET (box), GTK_ALIGN_CENTER);
gtk_widget_set_valign (GTK_WIDGET (box), GTK_ALIGN_CENTER);
gtk_box_set_spacing (GTK_BOX (box), 8);
/* the spinner */
spinner = gtk_spinner_new ();
gtk_spinner_start (GTK_SPINNER (spinner));
gtk_box_pack_start (GTK_BOX (box), spinner, FALSE, FALSE, 0);
gtk_widget_show (spinner);
/* the label */
label = gtk_label_new (NULL);
box->priv->label = GTK_LABEL (label);
pika_label_set_attributes (GTK_LABEL (label),
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
-1);
gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
gtk_widget_show (label);
}
static void
pika_busy_box_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaBusyBox *box = PIKA_BUSY_BOX (object);
switch (property_id)
{
case PROP_MESSAGE:
gtk_label_set_text (box->priv->label, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_busy_box_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaBusyBox *box = PIKA_BUSY_BOX (object);
switch (property_id)
{
case PROP_MESSAGE:
g_value_set_string (value, gtk_label_get_text (box->priv->label));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/* public functions */
/**
* pika_busy_box_new:
* @message: (allow-none): the displayed message, or %NULL
*
* Creates a new #PikaBusyBox widget.
*
* Returns: A pointer to the new #PikaBusyBox widget.
*
* Since: 2.10.4
**/
GtkWidget *
pika_busy_box_new (const gchar *message)
{
if (message == NULL)
message = "";
return g_object_new (PIKA_TYPE_BUSY_BOX,
"message", message,
NULL);
}
/**
* pika_busy_box_set_message:
* @box: a #PikaBusyBox
* @message: the displayed message
*
* Sets the displayed message og @box to @message.
*
* Since: 2.10.4
**/
void
pika_busy_box_set_message (PikaBusyBox *box,
const gchar *message)
{
g_return_if_fail (PIKA_IS_BUSY_BOX (box));
g_return_if_fail (message != NULL);
g_object_set (box,
"message", message,
NULL);
}
/**
* pika_busy_box_get_message:
* @box: a #PikaBusyBox
*
* Returns the displayed message of @box.
*
* Returns: The displayed message.
*
* Since: 2.10.4
**/
const gchar *
pika_busy_box_get_message (PikaBusyBox *box)
{
g_return_val_if_fail (PIKA_IS_BUSY_BOX (box), NULL);
return gtk_label_get_text (box->priv->label);
}

View File

@ -0,0 +1,76 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikabusybox.h
* Copyright (C) 2018 Ell
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_BUSY_BOX_H__
#define __PIKA_BUSY_BOX_H__
G_BEGIN_DECLS
#define PIKA_TYPE_BUSY_BOX (pika_busy_box_get_type ())
#define PIKA_BUSY_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_BUSY_BOX, PikaBusyBox))
#define PIKA_BUSY_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_BUSY_BOX, PikaBusyBoxClass))
#define PIKA_IS_BUSY_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_BUSY_BOX))
#define PIKA_IS_BUSY_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_BUSY_BOX))
#define PIKA_BUSY_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_BUSY_BOX, PikaBusyBoxClass))
typedef struct _PikaBusyBoxPrivate PikaBusyBoxPrivate;
typedef struct _PikaBusyBoxClass PikaBusyBoxClass;
struct _PikaBusyBox
{
GtkBox parent_instance;
PikaBusyBoxPrivate *priv;
};
struct _PikaBusyBoxClass
{
GtkBoxClass parent_class;
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_busy_box_get_type (void) G_GNUC_CONST;
GtkWidget * pika_busy_box_new (const gchar *message);
void pika_busy_box_set_message (PikaBusyBox *box,
const gchar *message);
const gchar * pika_busy_box_get_message (PikaBusyBox *box);
G_END_DECLS
#endif /* __PIKA_BUSY_BOX_H__ */

173
libpikawidgets/pikabutton.c Normal file
View File

@ -0,0 +1,173 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikabutton.c
* Copyright (C) 2000-2008 Michael Natterer <mitch@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gtk/gtk.h>
#include "pikawidgetstypes.h"
#include "pikabutton.h"
/**
* SECTION: pikabutton
* @title: PikaButton
* @short_description: A #GtkButton with a little extra functionality.
*
* #PikaButton adds an extra signal to the #GtkButton widget that
* allows the callback to distinguish a normal click from a click that
* was performed with modifier keys pressed.
**/
enum
{
EXTENDED_CLICKED,
LAST_SIGNAL
};
struct _PikaButtonPrivate
{
GdkModifierType press_state;
};
#define GET_PRIVATE(obj) (((PikaButton *) (obj))->priv)
static gboolean pika_button_button_press (GtkWidget *widget,
GdkEventButton *event);
static void pika_button_clicked (GtkButton *button);
G_DEFINE_TYPE_WITH_PRIVATE (PikaButton, pika_button, GTK_TYPE_BUTTON)
#define parent_class pika_button_parent_class
static guint button_signals[LAST_SIGNAL] = { 0 };
static void
pika_button_class_init (PikaButtonClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GtkButtonClass *button_class = GTK_BUTTON_CLASS (klass);
/**
* PikaButton::extended-clicked:
* @pikabutton: the object that received the signal.
* @arg1: the state of modifier keys when the button was clicked
*
* This signal is emitted when the button is clicked with a modifier
* key pressed.
**/
button_signals[EXTENDED_CLICKED] =
g_signal_new ("extended-clicked",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaButtonClass, extended_clicked),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
GDK_TYPE_MODIFIER_TYPE);
widget_class->button_press_event = pika_button_button_press;
button_class->clicked = pika_button_clicked;
}
static void
pika_button_init (PikaButton *button)
{
button->priv = pika_button_get_instance_private (button);
}
/**
* pika_button_new:
*
* Creates a new #PikaButton widget.
*
* Returns: A pointer to the new #PikaButton widget.
**/
GtkWidget *
pika_button_new (void)
{
return g_object_new (PIKA_TYPE_BUTTON, NULL);
}
/**
* pika_button_extended_clicked:
* @button: a #PikaButton.
* @modifier_state: a state as found in #GdkEventButton->state,
* e.g. #GDK_SHIFT_MASK.
*
* Emits the button's "extended_clicked" signal.
**/
void
pika_button_extended_clicked (PikaButton *button,
GdkModifierType modifier_state)
{
g_return_if_fail (PIKA_IS_BUTTON (button));
g_signal_emit (button, button_signals[EXTENDED_CLICKED], 0, modifier_state);
}
static gboolean
pika_button_button_press (GtkWidget *widget,
GdkEventButton *bevent)
{
PikaButtonPrivate *private = GET_PRIVATE (widget);
if (bevent->button == 1)
{
private->press_state = bevent->state;
}
else
{
private->press_state = 0;
}
return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, bevent);
}
static void
pika_button_clicked (GtkButton *button)
{
PikaButtonPrivate *private = GET_PRIVATE (button);
if (private->press_state &
(GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK |
gtk_widget_get_modifier_mask (GTK_WIDGET (button),
GDK_MODIFIER_INTENT_PRIMARY_ACCELERATOR) |
gtk_widget_get_modifier_mask (GTK_WIDGET (button),
GDK_MODIFIER_INTENT_EXTEND_SELECTION) |
gtk_widget_get_modifier_mask (GTK_WIDGET (button),
GDK_MODIFIER_INTENT_MODIFY_SELECTION)))
{
g_signal_stop_emission_by_name (button, "clicked");
pika_button_extended_clicked (PIKA_BUTTON (button), private->press_state);
}
else if (GTK_BUTTON_CLASS (parent_class)->clicked)
{
GTK_BUTTON_CLASS (parent_class)->clicked (button);
}
}

View File

@ -0,0 +1,81 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikabutton.h
* Copyright (C) 2001 Michael Natterer <mitch@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_BUTTON_H__
#define __PIKA_BUTTON_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
#define PIKA_TYPE_BUTTON (pika_button_get_type ())
#define PIKA_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_BUTTON, PikaButton))
#define PIKA_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_BUTTON, PikaButtonClass))
#define PIKA_IS_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_BUTTON))
#define PIKA_IS_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_BUTTON))
#define PIKA_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_BUTTON, PikaButtonClass))
typedef struct _PikaButtonPrivate PikaButtonPrivate;
typedef struct _PikaButtonClass PikaButtonClass;
struct _PikaButton
{
GtkButton parent_instance;
PikaButtonPrivate *priv;
};
struct _PikaButtonClass
{
GtkButtonClass parent_class;
void (* extended_clicked) (PikaButton *button,
GdkModifierType modifier_state);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_button_get_type (void) G_GNUC_CONST;
GtkWidget * pika_button_new (void);
void pika_button_extended_clicked (PikaButton *button,
GdkModifierType modifier_state);
G_END_DECLS
#endif /* __PIKA_BUTTON_H__ */

View File

@ -0,0 +1,202 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacairo-utils.c
* Copyright (C) 2007 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h"
#include "pikacairo-utils.h"
/**
* SECTION: pikacairo-utils
* @title: PikaCairo-utils
* @short_description: Utility functions for cairo
*
* Utility functions that make cairo easier to use with common
* PIKA data types.
**/
/**
* pika_cairo_set_focus_line_pattern:
* @cr: Cairo context
* @widget: widget to draw the focus indicator on
*
* Sets color and dash pattern for stroking a focus line on the given
* @cr. The line pattern is taken from @widget.
*
* Returns: %TRUE if the widget style has a focus line pattern,
* %FALSE otherwise
*
* Since: 2.6
**/
gboolean
pika_cairo_set_focus_line_pattern (cairo_t *cr,
GtkWidget *widget)
{
gint8 *dash_list;
gboolean retval = FALSE;
g_return_val_if_fail (cr != NULL, FALSE);
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
gtk_widget_style_get (widget,
"focus-line-pattern", (gchar *) &dash_list,
NULL);
if (dash_list[0])
{
/* Taken straight from gtk_default_draw_focus()
*/
gint n_dashes = strlen ((const gchar *) dash_list);
gdouble *dashes = g_new (gdouble, n_dashes);
gdouble total_length = 0;
gint i;
for (i = 0; i < n_dashes; i++)
{
dashes[i] = dash_list[i];
total_length += dash_list[i];
}
cairo_set_dash (cr, dashes, n_dashes, 0.5);
g_free (dashes);
retval = TRUE;
}
g_free (dash_list);
return retval;
}
/**
* pika_cairo_surface_create_from_pixbuf:
* @pixbuf: a #GdkPixbuf
*
* Create a Cairo image surface from a GdkPixbuf.
*
* You should avoid calling this function as there are probably more
* efficient ways of achieving the result you are looking for.
*
* Returns: a #cairo_surface_t.
*
* Since: 2.6
**/
cairo_surface_t *
pika_cairo_surface_create_from_pixbuf (GdkPixbuf *pixbuf)
{
cairo_surface_t *surface;
cairo_format_t format;
guchar *dest;
const guchar *src;
gint width;
gint height;
gint src_stride;
gint dest_stride;
gint y;
g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
width = gdk_pixbuf_get_width (pixbuf);
height = gdk_pixbuf_get_height (pixbuf);
switch (gdk_pixbuf_get_n_channels (pixbuf))
{
case 3:
format = CAIRO_FORMAT_RGB24;
break;
case 4:
format = CAIRO_FORMAT_ARGB32;
break;
default:
g_assert_not_reached ();
break;
}
surface = cairo_image_surface_create (format, width, height);
cairo_surface_flush (surface);
src = gdk_pixbuf_get_pixels (pixbuf);
src_stride = gdk_pixbuf_get_rowstride (pixbuf);
dest = cairo_image_surface_get_data (surface);
dest_stride = cairo_image_surface_get_stride (surface);
switch (format)
{
case CAIRO_FORMAT_RGB24:
for (y = 0; y < height; y++)
{
const guchar *s = src;
guchar *d = dest;
gint w = width;
while (w--)
{
PIKA_CAIRO_RGB24_SET_PIXEL (d, s[0], s[1], s[2]);
s += 3;
d += 4;
}
src += src_stride;
dest += dest_stride;
}
break;
case CAIRO_FORMAT_ARGB32:
for (y = 0; y < height; y++)
{
const guchar *s = src;
guchar *d = dest;
gint w = width;
while (w--)
{
PIKA_CAIRO_ARGB32_SET_PIXEL (d, s[0], s[1], s[2], s[3]);
s += 4;
d += 4;
}
src += src_stride;
dest += dest_stride;
}
break;
default:
break;
}
cairo_surface_mark_dirty (surface);
return surface;
}

View File

@ -0,0 +1,36 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacairo-utils.h
* Copyright (C) 2007 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_CAIRO_UTILS_H__
#define __PIKA_CAIRO_UTILS_H__
gboolean pika_cairo_set_focus_line_pattern (cairo_t *cr,
GtkWidget *widget);
cairo_surface_t * pika_cairo_surface_create_from_pixbuf (GdkPixbuf *pixbuf);
#endif /* __PIKA_CAIRO_UTILS_H__ */

View File

@ -0,0 +1,332 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacellrenderercolor.c
* Copyright (C) 2004,2007 Sven Neuman <sven1@gimp.org>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h"
#include "pikawidgetstypes.h"
#include "pikacairo-utils.h"
#include "pikacellrenderercolor.h"
/**
* SECTION: pikacellrenderercolor
* @title: PikaCellRendererColor
* @short_description: A #GtkCellRenderer to display a #PikaRGB color.
*
* A #GtkCellRenderer to display a #PikaRGB color.
**/
#define DEFAULT_ICON_SIZE GTK_ICON_SIZE_MENU
enum
{
PROP_0,
PROP_COLOR,
PROP_OPAQUE,
PROP_SIZE
};
struct _PikaCellRendererColorPrivate
{
PikaRGB color;
gboolean opaque;
GtkIconSize size;
gint border;
};
#define GET_PRIVATE(obj) (((PikaCellRendererColor *) (obj))->priv)
static void pika_cell_renderer_color_get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec);
static void pika_cell_renderer_color_set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec);
static void pika_cell_renderer_color_get_size (GtkCellRenderer *cell,
GtkWidget *widget,
const GdkRectangle *rectangle,
gint *x_offset,
gint *y_offset,
gint *width,
gint *height);
static void pika_cell_renderer_color_render (GtkCellRenderer *cell,
cairo_t *cr,
GtkWidget *widget,
const GdkRectangle *background_area,
const GdkRectangle *cell_area,
GtkCellRendererState flags);
G_DEFINE_TYPE_WITH_PRIVATE (PikaCellRendererColor, pika_cell_renderer_color,
GTK_TYPE_CELL_RENDERER)
#define parent_class pika_cell_renderer_color_parent_class
static void
pika_cell_renderer_color_class_init (PikaCellRendererColorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
object_class->get_property = pika_cell_renderer_color_get_property;
object_class->set_property = pika_cell_renderer_color_set_property;
cell_class->get_size = pika_cell_renderer_color_get_size;
cell_class->render = pika_cell_renderer_color_render;
g_object_class_install_property (object_class, PROP_COLOR,
g_param_spec_boxed ("color",
"Color",
"The displayed color",
PIKA_TYPE_RGB,
PIKA_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_OPAQUE,
g_param_spec_boolean ("opaque",
"Opaque",
"Whether to show transparency",
TRUE,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_SIZE,
g_param_spec_int ("icon-size",
"Icon Size",
"The cell's size",
0, G_MAXINT,
DEFAULT_ICON_SIZE,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
}
static void
pika_cell_renderer_color_init (PikaCellRendererColor *cell)
{
cell->priv = pika_cell_renderer_color_get_instance_private (cell);
pika_rgba_set (&cell->priv->color, 0.0, 0.0, 0.0, 1.0);
}
static void
pika_cell_renderer_color_get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec)
{
PikaCellRendererColorPrivate *private = GET_PRIVATE (object);
switch (param_id)
{
case PROP_COLOR:
g_value_set_boxed (value, &private->color);
break;
case PROP_OPAQUE:
g_value_set_boolean (value, private->opaque);
break;
case PROP_SIZE:
g_value_set_int (value, private->size);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
pika_cell_renderer_color_set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec)
{
PikaCellRendererColorPrivate *private = GET_PRIVATE (object);
PikaRGB *color;
switch (param_id)
{
case PROP_COLOR:
color = g_value_get_boxed (value);
private->color = *color;
break;
case PROP_OPAQUE:
private->opaque = g_value_get_boolean (value);
break;
case PROP_SIZE:
private->size = g_value_get_int (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
pika_cell_renderer_color_get_size (GtkCellRenderer *cell,
GtkWidget *widget,
const GdkRectangle *cell_area,
gint *x_offset,
gint *y_offset,
gint *width,
gint *height)
{
PikaCellRendererColorPrivate *private = GET_PRIVATE (cell);
gint calc_width;
gint calc_height;
gfloat xalign;
gfloat yalign;
gint xpad;
gint ypad;
gtk_icon_size_lookup (private->size, &calc_width, &calc_height);
gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
if (cell_area && calc_width > 0 && calc_height > 0)
{
if (x_offset)
{
*x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
1.0 - xalign : xalign) *
(cell_area->width - calc_width));
*x_offset = MAX (*x_offset, 0) + xpad;
}
if (y_offset)
{
*y_offset = (yalign * (cell_area->height - calc_height));
*y_offset = MAX (*y_offset, 0) + ypad;
}
}
else
{
if (x_offset)
*x_offset = 0;
if (y_offset)
*y_offset = 0;
}
if (width)
*width = calc_width + 2 * xpad;
if (height)
*height = calc_height + 2 * ypad;
}
static void
pika_cell_renderer_color_render (GtkCellRenderer *cell,
cairo_t *cr,
GtkWidget *widget,
const GdkRectangle *background_area,
const GdkRectangle *cell_area,
GtkCellRendererState flags)
{
PikaCellRendererColorPrivate *private = GET_PRIVATE (cell);
GdkRectangle rect;
gint xpad;
gint ypad;
pika_cell_renderer_color_get_size (cell, widget, cell_area,
&rect.x,
&rect.y,
&rect.width,
&rect.height);
gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
rect.x += cell_area->x + xpad;
rect.y += cell_area->y + ypad;
rect.width -= 2 * xpad;
rect.height -= 2 * ypad;
if (rect.width > 2 && rect.height > 2)
{
GtkStyleContext *context = gtk_widget_get_style_context (widget);
GtkStateFlags state;
GdkRGBA color;
cairo_rectangle (cr,
rect.x + 1, rect.y + 1,
rect.width - 2, rect.height - 2);
pika_cairo_set_source_rgb (cr, &private->color);
cairo_fill (cr);
if (! private->opaque && private->color.a < 1.0)
{
cairo_pattern_t *pattern;
cairo_move_to (cr, rect.x + 1, rect.y + rect.height - 1);
cairo_line_to (cr, rect.x + rect.width - 1, rect.y + rect.height - 1);
cairo_line_to (cr, rect.x + rect.width - 1, rect.y + 1);
cairo_close_path (cr);
pattern = pika_cairo_checkerboard_create (cr,
PIKA_CHECK_SIZE_SM,
NULL, NULL);
cairo_set_source (cr, pattern);
cairo_pattern_destroy (pattern);
cairo_fill_preserve (cr);
pika_cairo_set_source_rgba (cr, &private->color);
cairo_fill (cr);
}
/* draw border */
cairo_rectangle (cr,
rect.x + 0.5, rect.y + 0.5,
rect.width - 1, rect.height - 1);
state = gtk_cell_renderer_get_state (cell, widget, flags);
cairo_set_line_width (cr, 1);
gtk_style_context_get_color (context, state, &color);
gdk_cairo_set_source_rgba (cr, &color);
cairo_stroke (cr);
}
}
/**
* pika_cell_renderer_color_new:
*
* Creates a #GtkCellRenderer that displays a color.
*
* Returns: a new #PikaCellRendererColor
*
* Since: 2.2
**/
GtkCellRenderer *
pika_cell_renderer_color_new (void)
{
return g_object_new (PIKA_TYPE_CELL_RENDERER_COLOR, NULL);
}

View File

@ -0,0 +1,73 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacellrenderercolor.h
* Copyright (C) 2004 Sven Neuman <sven1@gimp.org>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_CELL_RENDERER_COLOR_H__
#define __PIKA_CELL_RENDERER_COLOR_H__
G_BEGIN_DECLS
#define PIKA_TYPE_CELL_RENDERER_COLOR (pika_cell_renderer_color_get_type ())
#define PIKA_CELL_RENDERER_COLOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CELL_RENDERER_COLOR, PikaCellRendererColor))
#define PIKA_CELL_RENDERER_COLOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CELL_RENDERER_COLOR, PikaCellRendererColorClass))
#define PIKA_IS_CELL_RENDERER_COLOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CELL_RENDERER_COLOR))
#define PIKA_IS_CELL_RENDERER_COLOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CELL_RENDERER_COLOR))
#define PIKA_CELL_RENDERER_COLOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CELL_RENDERER_COLOR, PikaCellRendererColorClass))
typedef struct _PikaCellRendererColorPrivate PikaCellRendererColorPrivate;
typedef struct _PikaCellRendererColorClass PikaCellRendererColorClass;
struct _PikaCellRendererColor
{
GtkCellRenderer parent_instance;
PikaCellRendererColorPrivate *priv;
};
struct _PikaCellRendererColorClass
{
GtkCellRendererClass parent_class;
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_cell_renderer_color_get_type (void) G_GNUC_CONST;
GtkCellRenderer * pika_cell_renderer_color_new (void);
G_END_DECLS
#endif /* __PIKA_CELL_RENDERER_COLOR_H__ */

View File

@ -0,0 +1,577 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacellrenderertoggle.c
* Copyright (C) 2003-2004 Sven Neumann <sven@gimp.org>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "pikawidgetstypes.h"
#include "pikawidgetsmarshal.h"
#include "pikacellrenderertoggle.h"
/**
* SECTION: pikacellrenderertoggle
* @title: PikaCellRendererToggle
* @short_description: A #GtkCellRendererToggle that displays icons instead
* of a checkbox.
*
* A #GtkCellRendererToggle that displays icons instead of a checkbox.
**/
#define DEFAULT_ICON_SIZE 16
enum
{
CLICKED,
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_ICON_NAME,
PROP_ICON_SIZE,
PROP_OVERRIDE_BACKGROUND
};
struct _PikaCellRendererTogglePrivate
{
gchar *icon_name;
gint icon_size;
gboolean override_background;
GdkPixbuf *pixbuf;
};
#define GET_PRIVATE(obj) (((PikaCellRendererToggle *) (obj))->priv)
static void pika_cell_renderer_toggle_finalize (GObject *object);
static void pika_cell_renderer_toggle_get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec);
static void pika_cell_renderer_toggle_set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec);
static void pika_cell_renderer_toggle_get_size (GtkCellRenderer *cell,
GtkWidget *widget,
const GdkRectangle *rectangle,
gint *x_offset,
gint *y_offset,
gint *width,
gint *height);
static void pika_cell_renderer_toggle_render (GtkCellRenderer *cell,
cairo_t *cr,
GtkWidget *widget,
const GdkRectangle *background_area,
const GdkRectangle *cell_area,
GtkCellRendererState flags);
static gboolean pika_cell_renderer_toggle_activate (GtkCellRenderer *cell,
GdkEvent *event,
GtkWidget *widget,
const gchar *path,
const GdkRectangle *background_area,
const GdkRectangle *cell_area,
GtkCellRendererState flags);
static void pika_cell_renderer_toggle_create_pixbuf (PikaCellRendererToggle *toggle,
GtkWidget *widget);
G_DEFINE_TYPE_WITH_PRIVATE (PikaCellRendererToggle, pika_cell_renderer_toggle,
GTK_TYPE_CELL_RENDERER_TOGGLE)
#define parent_class pika_cell_renderer_toggle_parent_class
static guint toggle_cell_signals[LAST_SIGNAL] = { 0 };
static void
pika_cell_renderer_toggle_class_init (PikaCellRendererToggleClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
toggle_cell_signals[CLICKED] =
g_signal_new ("clicked",
G_OBJECT_CLASS_TYPE (object_class),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (PikaCellRendererToggleClass, clicked),
NULL, NULL,
_pika_widgets_marshal_VOID__STRING_FLAGS,
G_TYPE_NONE, 2,
G_TYPE_STRING,
GDK_TYPE_MODIFIER_TYPE);
object_class->finalize = pika_cell_renderer_toggle_finalize;
object_class->get_property = pika_cell_renderer_toggle_get_property;
object_class->set_property = pika_cell_renderer_toggle_set_property;
cell_class->get_size = pika_cell_renderer_toggle_get_size;
cell_class->render = pika_cell_renderer_toggle_render;
cell_class->activate = pika_cell_renderer_toggle_activate;
g_object_class_install_property (object_class, PROP_ICON_NAME,
g_param_spec_string ("icon-name",
"Icon Name",
"The icon to display",
NULL,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_ICON_SIZE,
g_param_spec_int ("icon-size",
"Icon Size",
"The desired icon size to use in pixel (before applying scaling factor)",
0, G_MAXINT,
DEFAULT_ICON_SIZE,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_OVERRIDE_BACKGROUND,
g_param_spec_boolean ("override-background",
"Override Background",
"Draw the background if the row is selected",
FALSE,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
}
static void
pika_cell_renderer_toggle_init (PikaCellRendererToggle *toggle)
{
toggle->priv = pika_cell_renderer_toggle_get_instance_private (toggle);
}
static void
pika_cell_renderer_toggle_finalize (GObject *object)
{
PikaCellRendererTogglePrivate *priv = GET_PRIVATE (object);
g_clear_pointer (&priv->icon_name, g_free);
g_clear_object (&priv->pixbuf);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_cell_renderer_toggle_get_property (GObject *object,
guint param_id,
GValue *value,
GParamSpec *pspec)
{
PikaCellRendererTogglePrivate *priv = GET_PRIVATE (object);
switch (param_id)
{
case PROP_ICON_NAME:
g_value_set_string (value, priv->icon_name);
break;
case PROP_ICON_SIZE:
g_value_set_int (value, priv->icon_size);
break;
case PROP_OVERRIDE_BACKGROUND:
g_value_set_boolean (value, priv->override_background);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
}
static void
pika_cell_renderer_toggle_set_property (GObject *object,
guint param_id,
const GValue *value,
GParamSpec *pspec)
{
PikaCellRendererTogglePrivate *priv = GET_PRIVATE (object);
switch (param_id)
{
case PROP_ICON_NAME:
if (priv->icon_name)
g_free (priv->icon_name);
priv->icon_name = g_value_dup_string (value);
break;
case PROP_ICON_SIZE:
priv->icon_size = g_value_get_int (value);
break;
case PROP_OVERRIDE_BACKGROUND:
priv->override_background = g_value_get_boolean (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
break;
}
g_clear_object (&priv->pixbuf);
}
static void
pika_cell_renderer_toggle_get_size (GtkCellRenderer *cell,
GtkWidget *widget,
const GdkRectangle *cell_area,
gint *x_offset,
gint *y_offset,
gint *width,
gint *height)
{
PikaCellRendererToggle *toggle = PIKA_CELL_RENDERER_TOGGLE (cell);
PikaCellRendererTogglePrivate *priv = GET_PRIVATE (cell);
GtkStyleContext *context = gtk_widget_get_style_context (widget);
GtkBorder border;
gint scale_factor;
gint calc_width;
gint calc_height;
gint pixbuf_width;
gint pixbuf_height;
gfloat xalign;
gfloat yalign;
gint xpad;
gint ypad;
scale_factor = gtk_widget_get_scale_factor (widget);
if (! priv->icon_name)
{
GTK_CELL_RENDERER_CLASS (parent_class)->get_size (cell,
widget,
cell_area,
x_offset, y_offset,
width, height);
return;
}
gtk_style_context_save (context);
gtk_cell_renderer_get_alignment (cell, &xalign, &yalign);
gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
if (! priv->pixbuf)
pika_cell_renderer_toggle_create_pixbuf (toggle, widget);
pixbuf_width = gdk_pixbuf_get_width (priv->pixbuf);
pixbuf_height = gdk_pixbuf_get_height (priv->pixbuf);
/* The pixbuf size may be bigger than the logical size. */
calc_width = pixbuf_width / scale_factor + (gint) xpad * 2;
calc_height = pixbuf_height / scale_factor + (gint) ypad * 2;
gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
gtk_style_context_get_border (context, 0, &border);
calc_width += border.left + border.right;
calc_height += border.top + border.bottom;
if (width)
*width = calc_width;
if (height)
*height = calc_height;
if (cell_area)
{
if (x_offset)
{
*x_offset = (((gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) ?
(1.0 - xalign) : xalign) *
(cell_area->width - calc_width));
*x_offset = MAX (*x_offset, 0);
}
if (y_offset)
{
*y_offset = yalign * (cell_area->height - calc_height);
*y_offset = MAX (*y_offset, 0);
}
}
gtk_style_context_restore (context);
}
static void
pika_cell_renderer_toggle_render (GtkCellRenderer *cell,
cairo_t *cr,
GtkWidget *widget,
const GdkRectangle *background_area,
const GdkRectangle *cell_area,
GtkCellRendererState flags)
{
PikaCellRendererTogglePrivate *priv = GET_PRIVATE (cell);
GtkStyleContext *context = gtk_widget_get_style_context (widget);
GdkRectangle toggle_rect;
GtkStateFlags state;
gboolean active;
gint scale_factor;
gint xpad;
gint ypad;
scale_factor = gtk_widget_get_scale_factor (widget);
if (! priv->icon_name)
{
GTK_CELL_RENDERER_CLASS (parent_class)->render (cell, cr, widget,
background_area,
cell_area,
flags);
return;
}
if ((flags & GTK_CELL_RENDERER_SELECTED) &&
priv->override_background)
{
gboolean background_set;
g_object_get (cell,
"cell-background-set", &background_set,
NULL);
if (background_set)
{
GdkRGBA *color;
g_object_get (cell,
"cell-background-rgba", &color,
NULL);
gdk_cairo_rectangle (cr, background_area);
gdk_cairo_set_source_rgba (cr, color);
cairo_fill (cr);
gdk_rgba_free (color);
}
}
pika_cell_renderer_toggle_get_size (cell, widget, cell_area,
&toggle_rect.x,
&toggle_rect.y,
&toggle_rect.width,
&toggle_rect.height);
gtk_style_context_save (context);
gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
gtk_style_context_add_class (context, "toggle-icon");
gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
toggle_rect.x += cell_area->x + xpad;
toggle_rect.y += cell_area->y + ypad;
toggle_rect.width -= xpad * 2;
toggle_rect.height -= ypad * 2;
if (toggle_rect.width <= 0 || toggle_rect.height <= 0)
return;
state = gtk_cell_renderer_get_state (cell, widget, flags);
active =
gtk_cell_renderer_toggle_get_active (GTK_CELL_RENDERER_TOGGLE (cell));
if (active)
{
gtk_style_context_add_class (context, "visible");
state |= GTK_STATE_FLAG_ACTIVE;
}
if (! gtk_cell_renderer_toggle_get_activatable (GTK_CELL_RENDERER_TOGGLE (cell)))
state |= GTK_STATE_FLAG_INSENSITIVE;
gtk_style_context_set_state (context, state);
if (state & GTK_STATE_FLAG_PRELIGHT)
gtk_render_frame (context, cr,
toggle_rect.x, toggle_rect.y,
toggle_rect.width, toggle_rect.height);
if (active)
{
GtkBorder border;
gboolean inconsistent;
gtk_style_context_get_border (context, 0, &border);
toggle_rect.x += border.left;
toggle_rect.x *= scale_factor;
toggle_rect.y += border.top;
toggle_rect.y *= scale_factor;
toggle_rect.width -= border.left + border.right;
toggle_rect.height -= border.top + border.bottom;
/* For high DPI displays, pixbuf size is bigger than logical size. */
cairo_scale (cr, (gdouble) 1.0 / scale_factor, (gdouble) 1.0 / scale_factor);
gdk_cairo_set_source_pixbuf (cr, priv->pixbuf,
toggle_rect.x, toggle_rect.y);
cairo_paint (cr);
g_object_get (cell,
"inconsistent", &inconsistent,
NULL);
if (inconsistent)
{
GdkRGBA color;
gtk_style_context_get_color (context, state, &color);
gdk_cairo_set_source_rgba (cr, &color);
cairo_set_line_width (cr, scale_factor * 1.5);
cairo_move_to (cr,
toggle_rect.x + scale_factor * (toggle_rect.width - 1),
toggle_rect.y + scale_factor);
cairo_line_to (cr,
toggle_rect.x + scale_factor,
toggle_rect.y + scale_factor * (toggle_rect.height - 1));
cairo_stroke (cr);
}
}
gtk_style_context_restore (context);
}
static gboolean
pika_cell_renderer_toggle_activate (GtkCellRenderer *cell,
GdkEvent *event,
GtkWidget *widget,
const gchar *path,
const GdkRectangle *background_area,
const GdkRectangle *cell_area,
GtkCellRendererState flags)
{
GtkCellRendererToggle *toggle = GTK_CELL_RENDERER_TOGGLE (cell);
if (gtk_cell_renderer_toggle_get_activatable (toggle))
{
GdkModifierType state = 0;
if (event && ((GdkEventAny *) event)->type == GDK_BUTTON_PRESS)
state = ((GdkEventButton *) event)->state;
pika_cell_renderer_toggle_clicked (PIKA_CELL_RENDERER_TOGGLE (cell),
path, state);
return TRUE;
}
return FALSE;
}
static void
pika_cell_renderer_toggle_create_pixbuf (PikaCellRendererToggle *toggle,
GtkWidget *widget)
{
PikaCellRendererTogglePrivate *priv = GET_PRIVATE (toggle);
g_clear_object (&priv->pixbuf);
if (priv->icon_name)
{
GdkPixbuf *pixbuf;
GdkScreen *screen;
GtkIconTheme *icon_theme;
GtkIconInfo *icon_info;
gchar *icon_name;
gint scale_factor;
scale_factor = gtk_widget_get_scale_factor (widget);
screen = gtk_widget_get_screen (widget);
icon_theme = gtk_icon_theme_get_for_screen (screen);
/* Look for symbolic and fallback to color icon. */
icon_name = g_strdup_printf ("%s-symbolic", priv->icon_name);
icon_info = gtk_icon_theme_lookup_icon_for_scale (icon_theme, icon_name,
priv->icon_size, scale_factor,
GTK_ICON_LOOKUP_GENERIC_FALLBACK);
g_free (icon_name);
if (! icon_info)
{
icon_info = gtk_icon_theme_lookup_icon_for_scale (icon_theme, "image-missing",
priv->icon_size, scale_factor,
GTK_ICON_LOOKUP_GENERIC_FALLBACK |
GTK_ICON_LOOKUP_USE_BUILTIN);
}
g_return_if_fail (icon_info != NULL);
pixbuf = gtk_icon_info_load_symbolic_for_context (icon_info,
gtk_widget_get_style_context (widget),
NULL, NULL);
priv->pixbuf = pixbuf;
g_object_unref (icon_info);
}
}
/**
* pika_cell_renderer_toggle_new:
* @icon_name: the icon name of the icon to use for the active state
*
* Creates a custom version of the #GtkCellRendererToggle. Instead of
* showing the standard toggle button, it shows a named icon if the
* cell is active and no icon otherwise. This cell renderer is for
* example used in the Layers treeview to indicate and control the
* layer's visibility by showing %PIKA_STOCK_VISIBLE.
*
* Returns: a new #PikaCellRendererToggle
*
* Since: 2.2
**/
GtkCellRenderer *
pika_cell_renderer_toggle_new (const gchar *icon_name)
{
return g_object_new (PIKA_TYPE_CELL_RENDERER_TOGGLE,
"icon-name", icon_name,
NULL);
}
/**
* pika_cell_renderer_toggle_clicked:
* @cell: a #PikaCellRendererToggle
* @path: the path to the clicked row
* @state: the modifier state
*
* Emits the "clicked" signal from a #PikaCellRendererToggle.
*
* Since: 2.2
**/
void
pika_cell_renderer_toggle_clicked (PikaCellRendererToggle *cell,
const gchar *path,
GdkModifierType state)
{
g_return_if_fail (PIKA_IS_CELL_RENDERER_TOGGLE (cell));
g_return_if_fail (path != NULL);
g_signal_emit (cell, toggle_cell_signals[CLICKED], 0, path, state);
}

View File

@ -0,0 +1,81 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacellrenderertoggle.h
* Copyright (C) 2003-2004 Sven Neumann <sven@gimp.org>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_CELL_RENDERER_TOGGLE_H__
#define __PIKA_CELL_RENDERER_TOGGLE_H__
G_BEGIN_DECLS
#define PIKA_TYPE_CELL_RENDERER_TOGGLE (pika_cell_renderer_toggle_get_type ())
#define PIKA_CELL_RENDERER_TOGGLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CELL_RENDERER_TOGGLE, PikaCellRendererToggle))
#define PIKA_CELL_RENDERER_TOGGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CELL_RENDERER_TOGGLE, PikaCellRendererToggleClass))
#define PIKA_IS_CELL_RENDERER_TOGGLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CELL_RENDERER_TOGGLE))
#define PIKA_IS_CELL_RENDERER_TOGGLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CELL_RENDERER_TOGGLE))
#define PIKA_CELL_RENDERER_TOGGLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CELL_RENDERER_TOGGLE, PikaCellRendererToggleClass))
typedef struct _PikaCellRendererTogglePrivate PikaCellRendererTogglePrivate;
typedef struct _PikaCellRendererToggleClass PikaCellRendererToggleClass;
struct _PikaCellRendererToggle
{
GtkCellRendererToggle parent_instance;
PikaCellRendererTogglePrivate *priv;
};
struct _PikaCellRendererToggleClass
{
GtkCellRendererToggleClass parent_class;
void (* clicked) (PikaCellRendererToggle *cell,
const gchar *path,
GdkModifierType state);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_cell_renderer_toggle_get_type (void) G_GNUC_CONST;
GtkCellRenderer * pika_cell_renderer_toggle_new (const gchar *icon_name);
void pika_cell_renderer_toggle_clicked (PikaCellRendererToggle *cell,
const gchar *path,
GdkModifierType state);
G_END_DECLS
#endif /* __PIKA_CELL_RENDERER_TOGGLE_H__ */

View File

@ -0,0 +1,621 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikachainbutton.c
* Copyright (C) 1999-2000 Sven Neumann <sven@gimp.org>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "pikawidgetstypes.h"
#include "pikachainbutton.h"
#include "pikaicons.h"
/**
* SECTION: pikachainbutton
* @title: PikaChainButton
* @short_description: Widget to visually connect two entry widgets.
* @see_also: You may want to use the convenience function
* pika_coordinates_new() to set up two PikaSizeEntries
* (see #PikaSizeEntry) linked with a #PikaChainButton.
*
* This widget provides a button showing either a linked or a broken
* chain that can be used to link two entries, spinbuttons, colors or
* other GUI elements and show that they may be locked. Use it for
* example to connect X and Y ratios to provide the possibility of a
* constrained aspect ratio.
*
* The #PikaChainButton only gives visual feedback, it does not really
* connect widgets. You have to take care of locking the values
* yourself by checking the state of the #PikaChainButton whenever a
* value changes in one of the connected widgets and adjusting the
* other value if necessary.
**/
enum
{
PROP_0,
PROP_POSITION,
PROP_ICON_SIZE,
PROP_ACTIVE
};
enum
{
TOGGLED,
LAST_SIGNAL
};
struct _PikaChainButtonPrivate
{
PikaChainPosition position;
gboolean active;
GtkWidget *button;
GtkWidget *line1;
GtkWidget *line2;
GtkWidget *image;
};
#define GET_PRIVATE(obj) (((PikaChainButton *) (obj))->priv)
static void pika_chain_button_constructed (GObject *object);
static void pika_chain_button_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_chain_button_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_chain_button_compute_expand (GtkWidget *widget,
gboolean *hexpand_p,
gboolean *vexpand_p);
static void pika_chain_button_clicked_callback (GtkWidget *widget,
PikaChainButton *button);
static void pika_chain_button_update_image (PikaChainButton *button);
static GtkWidget * pika_chain_line_new (PikaChainPosition position,
gint which);
G_DEFINE_TYPE_WITH_PRIVATE (PikaChainButton, pika_chain_button, GTK_TYPE_GRID)
#define parent_class pika_chain_button_parent_class
static guint pika_chain_button_signals[LAST_SIGNAL] = { 0 };
static const gchar * const pika_chain_icon_names[] =
{
PIKA_ICON_CHAIN_HORIZONTAL,
PIKA_ICON_CHAIN_HORIZONTAL_BROKEN,
PIKA_ICON_CHAIN_VERTICAL,
PIKA_ICON_CHAIN_VERTICAL_BROKEN
};
static void
pika_chain_button_class_init (PikaChainButtonClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->constructed = pika_chain_button_constructed;
object_class->set_property = pika_chain_button_set_property;
object_class->get_property = pika_chain_button_get_property;
widget_class->compute_expand = pika_chain_button_compute_expand;
pika_chain_button_signals[TOGGLED] =
g_signal_new ("toggled",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaChainButtonClass, toggled),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
klass->toggled = NULL;
/**
* PikaChainButton:position:
*
* The position in which the chain button will be used.
*
* Since: 2.4
*/
g_object_class_install_property (object_class, PROP_POSITION,
g_param_spec_enum ("position",
"Position",
"The chain's position",
PIKA_TYPE_CHAIN_POSITION,
PIKA_CHAIN_TOP,
G_PARAM_CONSTRUCT_ONLY |
PIKA_PARAM_READWRITE));
/**
* PikaChainButton:icon-size:
*
* The chain button icon size.
*
* Since: 2.10.10
*/
g_object_class_install_property (object_class, PROP_ICON_SIZE,
g_param_spec_enum ("icon-size",
"Icon Size",
"The chain's icon size",
GTK_TYPE_ICON_SIZE,
GTK_ICON_SIZE_BUTTON,
G_PARAM_CONSTRUCT |
PIKA_PARAM_READWRITE));
/**
* PikaChainButton:active:
*
* The toggled state of the chain button.
*
* Since: 2.10.10
*/
g_object_class_install_property (object_class, PROP_ACTIVE,
g_param_spec_boolean ("active",
"Active",
"The chain's toggled state",
FALSE,
G_PARAM_CONSTRUCT |
PIKA_PARAM_READWRITE));
}
static void
pika_chain_button_init (PikaChainButton *button)
{
PikaChainButtonPrivate *private;
button->priv = pika_chain_button_get_instance_private (button);
private = GET_PRIVATE (button);
private->position = PIKA_CHAIN_TOP;
private->active = FALSE;
private->image = gtk_image_new ();
private->button = gtk_button_new ();
gtk_button_set_relief (GTK_BUTTON (private->button), GTK_RELIEF_NONE);
gtk_container_add (GTK_CONTAINER (private->button), private->image);
gtk_widget_show (private->image);
g_signal_connect (private->button, "clicked",
G_CALLBACK (pika_chain_button_clicked_callback),
button);
}
static void
pika_chain_button_constructed (GObject *object)
{
PikaChainButton *button = PIKA_CHAIN_BUTTON (object);
PikaChainButtonPrivate *private = GET_PRIVATE (button);
G_OBJECT_CLASS (parent_class)->constructed (object);
private->line1 = pika_chain_line_new (private->position, 1);
private->line2 = pika_chain_line_new (private->position, -1);
pika_chain_button_update_image (button);
if (private->position & PIKA_CHAIN_LEFT) /* are we a vertical chainbutton? */
{
gtk_widget_set_vexpand (private->line1, TRUE);
gtk_widget_set_vexpand (private->line2, TRUE);
gtk_grid_attach (GTK_GRID (button), private->line1, 0, 0, 1, 1);
gtk_grid_attach (GTK_GRID (button), private->button, 0, 1, 1, 1);
gtk_grid_attach (GTK_GRID (button), private->line2, 0, 2, 1, 1);
}
else
{
gtk_widget_set_hexpand (private->line1, TRUE);
gtk_widget_set_hexpand (private->line2, TRUE);
gtk_grid_attach (GTK_GRID (button), private->line1, 0, 0, 1, 1);
gtk_grid_attach (GTK_GRID (button), private->button, 1, 0, 1, 1);
gtk_grid_attach (GTK_GRID (button), private->line2, 2, 0, 1, 1);
}
gtk_widget_show (private->button);
gtk_widget_show (private->line1);
gtk_widget_show (private->line2);
}
static void
pika_chain_button_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaChainButton *button = PIKA_CHAIN_BUTTON (object);
PikaChainButtonPrivate *private = GET_PRIVATE (button);
switch (property_id)
{
case PROP_POSITION:
private->position = g_value_get_enum (value);
break;
case PROP_ICON_SIZE:
g_object_set_property (G_OBJECT (private->image), "icon-size", value);
break;
case PROP_ACTIVE:
pika_chain_button_set_active (button, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_chain_button_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaChainButton *button = PIKA_CHAIN_BUTTON (object);
PikaChainButtonPrivate *private = GET_PRIVATE (button);
switch (property_id)
{
case PROP_POSITION:
g_value_set_enum (value, private->position);
break;
case PROP_ICON_SIZE:
g_object_get_property (G_OBJECT (private->image), "icon-size", value);
break;
case PROP_ACTIVE:
g_value_set_boolean (value, pika_chain_button_get_active (button));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_chain_button_compute_expand (GtkWidget *widget,
gboolean *hexpand_p,
gboolean *vexpand_p)
{
/* don't inherit [hv]expand from the chain lines. see issue #3876. */
*hexpand_p = FALSE;
*vexpand_p = FALSE;
}
/**
* pika_chain_button_new:
* @position: The position you are going to use for the button
* with respect to the widgets you want to chain.
*
* Creates a new #PikaChainButton widget.
*
* This returns a button showing either a broken or a linked chain and
* small clamps attached to both sides that visually group the two
* widgets you want to connect. This widget looks best when attached
* to a grid taking up two columns (or rows respectively) next to the
* widgets that it is supposed to connect. It may work for more than
* two widgets, but the look is optimized for two.
*
* Returns: Pointer to the new #PikaChainButton, which is inactive
* by default. Use pika_chain_button_set_active() to
* change its state.
*/
GtkWidget *
pika_chain_button_new (PikaChainPosition position)
{
return g_object_new (PIKA_TYPE_CHAIN_BUTTON,
"position", position,
NULL);
}
/**
* pika_chain_button_set_icon_size:
* @button: Pointer to a #PikaChainButton.
* @size: The new icon size.
*
* Sets the icon size of the #PikaChainButton.
*
* Since: 2.10.10
*/
void
pika_chain_button_set_icon_size (PikaChainButton *button,
GtkIconSize size)
{
g_return_if_fail (PIKA_IS_CHAIN_BUTTON (button));
g_object_set (button,
"icon-size", size,
NULL);
}
/**
* pika_chain_button_get_icon_size:
* @button: Pointer to a #PikaChainButton.
*
* Gets the icon size of the #PikaChainButton.
*
* Returns: The icon size.
*
* Since: 2.10.10
*/
GtkIconSize
pika_chain_button_get_icon_size (PikaChainButton *button)
{
GtkIconSize size;
g_return_val_if_fail (PIKA_IS_CHAIN_BUTTON (button), GTK_ICON_SIZE_BUTTON);
g_object_get (button,
"icon-size", &size,
NULL);
return size;
}
/**
* pika_chain_button_set_active:
* @button: Pointer to a #PikaChainButton.
* @active: The new state.
*
* Sets the state of the #PikaChainButton to be either locked (%TRUE) or
* unlocked (%FALSE) and changes the showed pixmap to reflect the new state.
*/
void
pika_chain_button_set_active (PikaChainButton *button,
gboolean active)
{
PikaChainButtonPrivate *private;
g_return_if_fail (PIKA_IS_CHAIN_BUTTON (button));
private = GET_PRIVATE (button);
if (private->active != active)
{
private->active = active ? TRUE : FALSE;
pika_chain_button_update_image (button);
g_signal_emit (button, pika_chain_button_signals[TOGGLED], 0);
g_object_notify (G_OBJECT (button), "active");
}
}
/**
* pika_chain_button_get_active
* @button: Pointer to a #PikaChainButton.
*
* Checks the state of the #PikaChainButton.
*
* Returns: %TRUE if the #PikaChainButton is active (locked).
*/
gboolean
pika_chain_button_get_active (PikaChainButton *button)
{
PikaChainButtonPrivate *private;
g_return_val_if_fail (PIKA_IS_CHAIN_BUTTON (button), FALSE);
private = GET_PRIVATE (button);
return private->active;
}
/**
* pika_chain_button_get_button
* @button: A #PikaChainButton.
*
* Returns: (transfer none) (type GtkButton): The #PikaChainButton's button.
*
* Since: 3.0
*/
GtkWidget *
pika_chain_button_get_button (PikaChainButton *button)
{
PikaChainButtonPrivate *private;
g_return_val_if_fail (PIKA_IS_CHAIN_BUTTON (button), FALSE);
private = GET_PRIVATE (button);
return private->button;
}
/* private functions */
static void
pika_chain_button_clicked_callback (GtkWidget *widget,
PikaChainButton *button)
{
PikaChainButtonPrivate *private = GET_PRIVATE (button);
pika_chain_button_set_active (button, ! private->active);
}
static void
pika_chain_button_update_image (PikaChainButton *button)
{
PikaChainButtonPrivate *private = GET_PRIVATE (button);
guint i;
i = ((private->position & PIKA_CHAIN_LEFT) << 1) + (private->active ? 0 : 1);
gtk_image_set_from_icon_name (GTK_IMAGE (private->image),
pika_chain_icon_names[i],
pika_chain_button_get_icon_size (button));
}
/* PikaChainLine is a simple no-window widget for drawing the lines.
*
* Originally this used to be a GtkDrawingArea but this turned out to
* be a bad idea. We don't need an extra window to draw on and we also
* don't need any input events.
*/
static GType pika_chain_line_get_type (void) G_GNUC_CONST;
static gboolean pika_chain_line_draw (GtkWidget *widget,
cairo_t *cr);
struct _PikaChainLine
{
GtkWidget parent_instance;
PikaChainPosition position;
gint which;
};
typedef struct _PikaChainLine PikaChainLine;
typedef GtkWidgetClass PikaChainLineClass;
G_DEFINE_TYPE (PikaChainLine, pika_chain_line, GTK_TYPE_WIDGET)
static void
pika_chain_line_class_init (PikaChainLineClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
widget_class->draw = pika_chain_line_draw;
}
static void
pika_chain_line_init (PikaChainLine *line)
{
gtk_widget_set_has_window (GTK_WIDGET (line), FALSE);
}
static GtkWidget *
pika_chain_line_new (PikaChainPosition position,
gint which)
{
PikaChainLine *line = g_object_new (pika_chain_line_get_type (), NULL);
line->position = position;
line->which = which;
return GTK_WIDGET (line);
}
static gboolean
pika_chain_line_draw (GtkWidget *widget,
cairo_t *cr)
{
GtkStyleContext *context = gtk_widget_get_style_context (widget);
PikaChainLine *line = ((PikaChainLine *) widget);
GtkAllocation allocation;
GdkPoint points[3];
PikaChainPosition position;
GdkRGBA color;
gtk_widget_get_allocation (widget, &allocation);
#define SHORT_LINE 4
points[0].x = allocation.width / 2;
points[0].y = allocation.height / 2;
position = line->position;
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
{
switch (position)
{
case PIKA_CHAIN_TOP:
case PIKA_CHAIN_BOTTOM:
break;
case PIKA_CHAIN_LEFT:
position = PIKA_CHAIN_RIGHT;
break;
case PIKA_CHAIN_RIGHT:
position = PIKA_CHAIN_LEFT;
break;
}
}
switch (position)
{
case PIKA_CHAIN_LEFT:
points[0].x += SHORT_LINE;
points[1].x = points[0].x - SHORT_LINE;
points[1].y = points[0].y;
points[2].x = points[1].x;
points[2].y = (line->which == 1 ? allocation.height - 1 : 0);
break;
case PIKA_CHAIN_RIGHT:
points[0].x -= SHORT_LINE;
points[1].x = points[0].x + SHORT_LINE;
points[1].y = points[0].y;
points[2].x = points[1].x;
points[2].y = (line->which == 1 ? allocation.height - 1 : 0);
break;
case PIKA_CHAIN_TOP:
points[0].y += SHORT_LINE;
points[1].x = points[0].x;
points[1].y = points[0].y - SHORT_LINE;
points[2].x = (line->which == 1 ? allocation.width - 1 : 0);
points[2].y = points[1].y;
break;
case PIKA_CHAIN_BOTTOM:
points[0].y -= SHORT_LINE;
points[1].x = points[0].x;
points[1].y = points[0].y + SHORT_LINE;
points[2].x = (line->which == 1 ? allocation.width - 1 : 0);
points[2].y = points[1].y;
break;
default:
return FALSE;
}
cairo_move_to (cr, points[0].x, points[0].y);
cairo_line_to (cr, points[1].x, points[1].y);
cairo_line_to (cr, points[2].x, points[2].y);
cairo_set_line_width (cr, 2.0);
cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
gtk_style_context_get_color (context, gtk_widget_get_state_flags (widget), &color);
gdk_cairo_set_source_rgba (cr, &color);
cairo_stroke (cr);
return TRUE;
}

View File

@ -0,0 +1,93 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikachainbutton.h
* Copyright (C) 1999-2000 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
/*
* This implements a widget derived from GtkGrid that visualizes
* it's state with two different pixmaps showing a closed and a
* broken chain. It's intended to be used with the PikaSizeEntry
* widget. The usage is quite similar to the one the GtkToggleButton
* provides.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_CHAIN_BUTTON_H__
#define __PIKA_CHAIN_BUTTON_H__
G_BEGIN_DECLS
#define PIKA_TYPE_CHAIN_BUTTON (pika_chain_button_get_type ())
#define PIKA_CHAIN_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CHAIN_BUTTON, PikaChainButton))
#define PIKA_CHAIN_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CHAIN_BUTTON, PikaChainButtonClass))
#define PIKA_IS_CHAIN_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CHAIN_BUTTON))
#define PIKA_IS_CHAIN_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CHAIN_BUTTON))
#define PIKA_CHAIN_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CHAIN_BUTTON, PikaChainButtonClass))
typedef struct _PikaChainButtonPrivate PikaChainButtonPrivate;
typedef struct _PikaChainButtonClass PikaChainButtonClass;
struct _PikaChainButton
{
GtkGrid parent_instance;
PikaChainButtonPrivate *priv;
};
struct _PikaChainButtonClass
{
GtkGridClass parent_class;
void (* toggled) (PikaChainButton *button);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_chain_button_get_type (void) G_GNUC_CONST;
GtkWidget * pika_chain_button_new (PikaChainPosition position);
void pika_chain_button_set_icon_size (PikaChainButton *button,
GtkIconSize size);
GtkIconSize pika_chain_button_get_icon_size (PikaChainButton *button);
void pika_chain_button_set_active (PikaChainButton *button,
gboolean active);
gboolean pika_chain_button_get_active (PikaChainButton *button);
GtkWidget * pika_chain_button_get_button (PikaChainButton *button);
G_END_DECLS
#endif /* __PIKA_CHAIN_BUTTON_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,100 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorarea.h
* Copyright (C) 2001-2002 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
/* This provides a color preview area. The preview
* can handle transparency by showing the checkerboard and
* handles drag'n'drop.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_AREA_H__
#define __PIKA_COLOR_AREA_H__
G_BEGIN_DECLS
#define PIKA_TYPE_COLOR_AREA (pika_color_area_get_type ())
#define PIKA_COLOR_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_AREA, PikaColorArea))
#define PIKA_COLOR_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_AREA, PikaColorAreaClass))
#define PIKA_IS_COLOR_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_AREA))
#define PIKA_IS_COLOR_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_AREA))
#define PIKA_COLOR_AREA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_AREA, PikaColorAreaClass))
typedef struct _PikaColorAreaPrivate PikaColorAreaPrivate;
typedef struct _PikaColorAreaClass PikaColorAreaClass;
struct _PikaColorArea
{
GtkDrawingArea parent_instance;
PikaColorAreaPrivate *priv;
};
struct _PikaColorAreaClass
{
GtkDrawingAreaClass parent_class;
void (* color_changed) (PikaColorArea *area);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_color_area_get_type (void) G_GNUC_CONST;
GtkWidget * pika_color_area_new (const PikaRGB *color,
PikaColorAreaType type,
GdkModifierType drag_mask);
void pika_color_area_set_color (PikaColorArea *area,
const PikaRGB *color);
void pika_color_area_get_color (PikaColorArea *area,
PikaRGB *color);
gboolean pika_color_area_has_alpha (PikaColorArea *area);
void pika_color_area_set_type (PikaColorArea *area,
PikaColorAreaType type);
void pika_color_area_enable_drag (PikaColorArea *area,
GdkModifierType drag_mask);
void pika_color_area_set_draw_border (PikaColorArea *area,
gboolean draw_border);
void pika_color_area_set_out_of_gamut (PikaColorArea *area,
gboolean out_of_gamut);
void pika_color_area_set_color_config (PikaColorArea *area,
PikaColorConfig *config);
G_END_DECLS
#endif /* __PIKA_COLOR_AREA_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,113 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorbutton.h
* Copyright (C) 1999-2001 Sven Neumann
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
/* This provides a button with a color preview. The preview
* can handle transparency by showing the checkerboard.
* On click, a color selector is opened, which is already
* fully functional wired to the preview button.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_BUTTON_H__
#define __PIKA_COLOR_BUTTON_H__
#include <libpikawidgets/pikabutton.h>
G_BEGIN_DECLS
#define PIKA_TYPE_COLOR_BUTTON (pika_color_button_get_type ())
#define PIKA_COLOR_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_BUTTON, PikaColorButton))
#define PIKA_COLOR_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_BUTTON, PikaColorButtonClass))
#define PIKA_IS_COLOR_BUTTON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_BUTTON))
#define PIKA_IS_COLOR_BUTTON_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_BUTTON))
#define PIKA_COLOR_BUTTON_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_BUTTON, PikaColorButtonClass))
typedef struct _PikaColorButtonPrivate PikaColorButtonPrivate;
typedef struct _PikaColorButtonClass PikaColorButtonClass;
struct _PikaColorButton
{
PikaButton parent_instance;
PikaColorButtonPrivate *priv;
};
struct _PikaColorButtonClass
{
PikaButtonClass parent_class;
/* signals */
void (* color_changed) (PikaColorButton *button);
/* virtual functions */
GType (* get_action_type) (PikaColorButton *button);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_color_button_get_type (void) G_GNUC_CONST;
GtkWidget * pika_color_button_new (const gchar *title,
gint width,
gint height,
const PikaRGB *color,
PikaColorAreaType type);
void pika_color_button_set_title (PikaColorButton *button,
const gchar *title);
const gchar * pika_color_button_get_title (PikaColorButton *button);
void pika_color_button_set_color (PikaColorButton *button,
const PikaRGB *color);
void pika_color_button_get_color (PikaColorButton *button,
PikaRGB *color);
gboolean pika_color_button_has_alpha (PikaColorButton *button);
void pika_color_button_set_type (PikaColorButton *button,
PikaColorAreaType type);
gboolean pika_color_button_get_update (PikaColorButton *button);
void pika_color_button_set_update (PikaColorButton *button,
gboolean continuous);
void pika_color_button_set_color_config (PikaColorButton *button,
PikaColorConfig *config);
GSimpleActionGroup * pika_color_button_get_action_group (PikaColorButton *button);
G_END_DECLS
#endif /* __PIKA_COLOR_BUTTON_H__ */

View File

@ -0,0 +1,479 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolordisplay.c
* Copyright (C) 2002 Michael Natterer <mitch@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h"
#include "libpikaconfig/pikaconfig.h"
#include "pikawidgetstypes.h"
#include "pikacolordisplay.h"
#include "pikaicons.h"
/**
* SECTION: pikacolordisplay
* @title: PikaColorDisplay
* @short_description: Pluggable PIKA display color correction modules.
* @see_also: #GModule, #GTypeModule, #PikaModule
*
* Functions and definitions for creating pluggable PIKA
* display color correction modules.
**/
enum
{
PROP_0,
PROP_ENABLED,
PROP_COLOR_CONFIG,
PROP_COLOR_MANAGED
};
enum
{
CHANGED,
LAST_SIGNAL
};
struct _PikaColorDisplayPrivate
{
gboolean enabled;
PikaColorConfig *config;
PikaColorManaged *managed;
};
#define GET_PRIVATE(obj) (((PikaColorDisplay *) (obj))->priv)
static void pika_color_display_constructed (GObject *object);
static void pika_color_display_dispose (GObject *object);
static void pika_color_display_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_color_display_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_color_display_set_color_config (PikaColorDisplay *display,
PikaColorConfig *config);
static void pika_color_display_set_color_managed (PikaColorDisplay *display,
PikaColorManaged *managed);
G_DEFINE_TYPE_WITH_CODE (PikaColorDisplay, pika_color_display, G_TYPE_OBJECT,
G_ADD_PRIVATE (PikaColorDisplay)
G_IMPLEMENT_INTERFACE (PIKA_TYPE_CONFIG, NULL))
#define parent_class pika_color_display_parent_class
static guint display_signals[LAST_SIGNAL] = { 0 };
static void
pika_color_display_class_init (PikaColorDisplayClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = pika_color_display_constructed;
object_class->dispose = pika_color_display_dispose;
object_class->set_property = pika_color_display_set_property;
object_class->get_property = pika_color_display_get_property;
g_object_class_install_property (object_class, PROP_ENABLED,
g_param_spec_boolean ("enabled",
"Enabled",
"Whether this display filter is enabled",
TRUE,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_COLOR_CONFIG,
g_param_spec_object ("color-config",
"Color Config",
"The color config used for this filter",
PIKA_TYPE_COLOR_CONFIG,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_COLOR_MANAGED,
g_param_spec_object ("color-managed",
"Color Managed",
"The color managed pixel source that is filtered",
PIKA_TYPE_COLOR_MANAGED,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
display_signals[CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaColorDisplayClass, changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
klass->name = "Unnamed";
klass->help_id = NULL;
klass->icon_name = PIKA_ICON_DISPLAY_FILTER;
klass->convert_buffer = NULL;
klass->configure = NULL;
klass->changed = NULL;
}
static void
pika_color_display_init (PikaColorDisplay *display)
{
display->priv = pika_color_display_get_instance_private (display);
}
static void
pika_color_display_constructed (GObject *object)
{
G_OBJECT_CLASS (parent_class)->constructed (object);
/* emit an initial "changed" signal after all construct properties are set */
pika_color_display_changed (PIKA_COLOR_DISPLAY (object));
}
static void
pika_color_display_dispose (GObject *object)
{
PikaColorDisplayPrivate *private = GET_PRIVATE (object);
if (private->config)
{
g_signal_handlers_disconnect_by_func (private->config,
pika_color_display_changed,
object);
g_object_unref (private->config);
private->config = NULL;
}
if (private->managed)
{
g_signal_handlers_disconnect_by_func (private->managed,
pika_color_display_changed,
object);
g_object_unref (private->managed);
private->managed = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
pika_color_display_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaColorDisplay *display = PIKA_COLOR_DISPLAY (object);
PikaColorDisplayPrivate *private = GET_PRIVATE (object);
switch (property_id)
{
case PROP_ENABLED:
private->enabled = g_value_get_boolean (value);
break;
case PROP_COLOR_CONFIG:
pika_color_display_set_color_config (display,
g_value_get_object (value));
break;
case PROP_COLOR_MANAGED:
pika_color_display_set_color_managed (display,
g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_color_display_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaColorDisplayPrivate *private = GET_PRIVATE (object);
switch (property_id)
{
case PROP_ENABLED:
g_value_set_boolean (value, private->enabled);
break;
case PROP_COLOR_CONFIG:
g_value_set_object (value, private->config);
break;
case PROP_COLOR_MANAGED:
g_value_set_object (value, private->managed);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_color_display_set_color_config (PikaColorDisplay *display,
PikaColorConfig *config)
{
PikaColorDisplayPrivate *private = GET_PRIVATE (display);
g_return_if_fail (private->config == NULL);
if (config)
{
private->config = g_object_ref (config);
g_signal_connect_swapped (private->config, "notify",
G_CALLBACK (pika_color_display_changed),
display);
}
}
static void
pika_color_display_set_color_managed (PikaColorDisplay *display,
PikaColorManaged *managed)
{
PikaColorDisplayPrivate *private = GET_PRIVATE (display);
g_return_if_fail (private->managed == NULL);
if (managed)
{
private->managed = g_object_ref (managed);
g_signal_connect_swapped (private->managed, "profile-changed",
G_CALLBACK (pika_color_display_changed),
display);
}
}
/**
* pika_color_display_clone:
* @display: a #PikaColorDisplay
*
* Creates a copy of @display.
*
* Returns: (transfer full): a duplicate of @display.
*
* Since: 2.0
**/
PikaColorDisplay *
pika_color_display_clone (PikaColorDisplay *display)
{
g_return_val_if_fail (PIKA_IS_COLOR_DISPLAY (display), NULL);
return PIKA_COLOR_DISPLAY (pika_config_duplicate (PIKA_CONFIG (display)));
}
/**
* pika_color_display_convert_buffer:
* @display: a #PikaColorDisplay
* @buffer: a #GeglBuffer
* @area: area in @buffer to convert
*
* Converts all pixels in @area of @buffer.
*
* Since: 2.10
**/
void
pika_color_display_convert_buffer (PikaColorDisplay *display,
GeglBuffer *buffer,
GeglRectangle *area)
{
PikaColorDisplayPrivate *private;
g_return_if_fail (PIKA_IS_COLOR_DISPLAY (display));
g_return_if_fail (GEGL_IS_BUFFER (buffer));
private = GET_PRIVATE (display);
if (private->enabled &&
PIKA_COLOR_DISPLAY_GET_CLASS (display)->convert_buffer)
{
PIKA_COLOR_DISPLAY_GET_CLASS (display)->convert_buffer (display, buffer,
area);
}
}
/**
* pika_color_display_load_state:
* @display: a #PikaColorDisplay
* @state: a #PikaParasite
*
* Configures @display from the contents of the parasite @state.
* @state must be a properly serialized configuration for a
* #PikaColorDisplay, such as saved by pika_color_display_save_state().
*
* Since: 2.0
**/
void
pika_color_display_load_state (PikaColorDisplay *display,
PikaParasite *state)
{
g_return_if_fail (PIKA_IS_COLOR_DISPLAY (display));
g_return_if_fail (state != NULL);
pika_config_deserialize_parasite (PIKA_CONFIG (display),
state,
NULL, NULL);
}
/**
* pika_color_display_save_state:
* @display: a #PikaColorDisplay
*
* Saves the configuration state of @display as a new parasite.
*
* Returns: (transfer full): a #PikaParasite
*
* Since: 2.0
**/
PikaParasite *
pika_color_display_save_state (PikaColorDisplay *display)
{
g_return_val_if_fail (PIKA_IS_COLOR_DISPLAY (display), NULL);
return pika_config_serialize_to_parasite (PIKA_CONFIG (display),
"Display/Proof",
PIKA_PARASITE_PERSISTENT,
NULL);
}
/**
* pika_color_display_configure:
* @display: a #PikaColorDisplay
*
* Creates a configuration widget for @display which can be added to a
* container widget.
*
* Returns: (transfer full): a new configuration widget for @display, or
* %NULL if no specific widget exists.
*
* Since: 2.0
**/
GtkWidget *
pika_color_display_configure (PikaColorDisplay *display)
{
g_return_val_if_fail (PIKA_IS_COLOR_DISPLAY (display), NULL);
if (PIKA_COLOR_DISPLAY_GET_CLASS (display)->configure)
return PIKA_COLOR_DISPLAY_GET_CLASS (display)->configure (display);
return NULL;
}
void
pika_color_display_configure_reset (PikaColorDisplay *display)
{
g_return_if_fail (PIKA_IS_COLOR_DISPLAY (display));
pika_config_reset (PIKA_CONFIG (display));
}
void
pika_color_display_changed (PikaColorDisplay *display)
{
g_return_if_fail (PIKA_IS_COLOR_DISPLAY (display));
g_signal_emit (display, display_signals[CHANGED], 0);
}
void
pika_color_display_set_enabled (PikaColorDisplay *display,
gboolean enabled)
{
PikaColorDisplayPrivate *private;
g_return_if_fail (PIKA_IS_COLOR_DISPLAY (display));
private = GET_PRIVATE (display);
if (enabled != private->enabled)
{
g_object_set (display,
"enabled", enabled,
NULL);
}
}
gboolean
pika_color_display_get_enabled (PikaColorDisplay *display)
{
g_return_val_if_fail (PIKA_IS_COLOR_DISPLAY (display), FALSE);
return GET_PRIVATE (display)->enabled;
}
/**
* pika_color_display_get_config:
* @display:
*
* Returns: (transfer none): a pointer to the #PikaColorConfig
* object or %NULL.
*
* Since: 2.4
**/
PikaColorConfig *
pika_color_display_get_config (PikaColorDisplay *display)
{
g_return_val_if_fail (PIKA_IS_COLOR_DISPLAY (display), NULL);
return GET_PRIVATE (display)->config;
}
/**
* pika_color_display_get_managed:
* @display:
*
* Returns: (transfer none): a pointer to the #PikaColorManaged
* object or %NULL.
*
* Since: 2.4
**/
PikaColorManaged *
pika_color_display_get_managed (PikaColorDisplay *display)
{
g_return_val_if_fail (PIKA_IS_COLOR_DISPLAY (display), NULL);
return GET_PRIVATE (display)->managed;
}

View File

@ -0,0 +1,106 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolordisplay.c
* Copyright (C) 1999 Manish Singh <yosh@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_DISPLAY_H__
#define __PIKA_COLOR_DISPLAY_H__
G_BEGIN_DECLS
/* For information look at the html documentation */
#define PIKA_TYPE_COLOR_DISPLAY (pika_color_display_get_type ())
#define PIKA_COLOR_DISPLAY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_DISPLAY, PikaColorDisplay))
#define PIKA_COLOR_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_DISPLAY, PikaColorDisplayClass))
#define PIKA_IS_COLOR_DISPLAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_DISPLAY))
#define PIKA_IS_COLOR_DISPLAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_DISPLAY))
#define PIKA_COLOR_DISPLAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_DISPLAY, PikaColorDisplayClass))
typedef struct _PikaColorDisplayPrivate PikaColorDisplayPrivate;
typedef struct _PikaColorDisplayClass PikaColorDisplayClass;
struct _PikaColorDisplay
{
GObject parent_instance;
PikaColorDisplayPrivate *priv;
};
struct _PikaColorDisplayClass
{
GObjectClass parent_class;
const gchar *name;
const gchar *help_id;
const gchar *icon_name;
/* virtual functions */
void (* convert_buffer) (PikaColorDisplay *display,
GeglBuffer *buffer,
GeglRectangle *area);
GtkWidget * (* configure) (PikaColorDisplay *display);
/* signals */
void (* changed) (PikaColorDisplay *display);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_color_display_get_type (void) G_GNUC_CONST;
PikaColorDisplay * pika_color_display_clone (PikaColorDisplay *display);
void pika_color_display_convert_buffer (PikaColorDisplay *display,
GeglBuffer *buffer,
GeglRectangle *area);
void pika_color_display_load_state (PikaColorDisplay *display,
PikaParasite *state);
PikaParasite * pika_color_display_save_state (PikaColorDisplay *display);
GtkWidget * pika_color_display_configure (PikaColorDisplay *display);
void pika_color_display_configure_reset (PikaColorDisplay *display);
void pika_color_display_changed (PikaColorDisplay *display);
void pika_color_display_set_enabled (PikaColorDisplay *display,
gboolean enabled);
gboolean pika_color_display_get_enabled (PikaColorDisplay *display);
PikaColorConfig * pika_color_display_get_config (PikaColorDisplay *display);
PikaColorManaged * pika_color_display_get_managed (PikaColorDisplay *display);
G_END_DECLS
#endif /* __PIKA_COLOR_DISPLAY_H__ */

View File

@ -0,0 +1,460 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolordisplaystack.c
* Copyright (C) 2003 Michael Natterer <mitch@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikacolor/pikacolor.h"
#include "pikawidgetstypes.h"
#include "pikacolordisplay.h"
#include "pikacolordisplaystack.h"
#include "pikawidgetsmarshal.h"
/**
* SECTION: pikacolordisplaystack
* @title: PikaColorDisplayStack
* @short_description: A stack of color correction modules.
* @see_also: #PikaColorDisplay
*
* A stack of color correction modules.
**/
enum
{
CHANGED,
ADDED,
REMOVED,
REORDERED,
LAST_SIGNAL
};
struct _PikaColorDisplayStackPrivate
{
GList *filters;
};
#define GET_PRIVATE(obj) (((PikaColorDisplayStack *) (obj))->priv)
static void pika_color_display_stack_dispose (GObject *object);
static void pika_color_display_stack_display_changed (PikaColorDisplay *display,
PikaColorDisplayStack *stack);
static void pika_color_display_stack_display_enabled (PikaColorDisplay *display,
GParamSpec *pspec,
PikaColorDisplayStack *stack);
static void pika_color_display_stack_disconnect (PikaColorDisplayStack *stack,
PikaColorDisplay *display);
G_DEFINE_TYPE_WITH_PRIVATE (PikaColorDisplayStack, pika_color_display_stack,
G_TYPE_OBJECT)
#define parent_class pika_color_display_stack_parent_class
static guint stack_signals[LAST_SIGNAL] = { 0 };
static void
pika_color_display_stack_class_init (PikaColorDisplayStackClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
stack_signals[CHANGED] =
g_signal_new ("changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaColorDisplayStackClass, changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
stack_signals[ADDED] =
g_signal_new ("added",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaColorDisplayStackClass, added),
NULL, NULL,
_pika_widgets_marshal_VOID__OBJECT_INT,
G_TYPE_NONE, 2,
PIKA_TYPE_COLOR_DISPLAY,
G_TYPE_INT);
stack_signals[REMOVED] =
g_signal_new ("removed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaColorDisplayStackClass, removed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_COLOR_DISPLAY);
stack_signals[REORDERED] =
g_signal_new ("reordered",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaColorDisplayStackClass, reordered),
NULL, NULL,
_pika_widgets_marshal_VOID__OBJECT_INT,
G_TYPE_NONE, 2,
PIKA_TYPE_COLOR_DISPLAY,
G_TYPE_INT);
object_class->dispose = pika_color_display_stack_dispose;
klass->changed = NULL;
klass->added = NULL;
klass->removed = NULL;
klass->reordered = NULL;
}
static void
pika_color_display_stack_init (PikaColorDisplayStack *stack)
{
stack->priv = pika_color_display_stack_get_instance_private (stack);
}
static void
pika_color_display_stack_dispose (GObject *object)
{
PikaColorDisplayStack *stack = PIKA_COLOR_DISPLAY_STACK (object);
PikaColorDisplayStackPrivate *private = GET_PRIVATE (object);
if (private->filters)
{
GList *list;
for (list = private->filters; list; list = g_list_next (list))
{
PikaColorDisplay *display = list->data;
pika_color_display_stack_disconnect (stack, display);
g_object_unref (display);
}
g_list_free (private->filters);
private->filters = NULL;
}
G_OBJECT_CLASS (parent_class)->dispose (object);
}
/* public functions */
/**
* pika_color_display_stack_new:
*
* Creates a new stack of color correction modules.
*
* Returns: (transfer full): a newly allocated #PikaColorDisplayStack.
*
* Since: 2.0
**/
PikaColorDisplayStack *
pika_color_display_stack_new (void)
{
return g_object_new (PIKA_TYPE_COLOR_DISPLAY_STACK, NULL);
}
/**
* pika_color_display_stack_clone:
* @stack: a #PikaColorDisplayStack
*
* Creates a copy of @stack with all its display color modules also
* duplicated.
*
* Returns: (transfer full): a duplicate of @stack.
*
* Since: 2.0
**/
PikaColorDisplayStack *
pika_color_display_stack_clone (PikaColorDisplayStack *stack)
{
PikaColorDisplayStackPrivate *private;
PikaColorDisplayStack *clone;
GList *list;
g_return_val_if_fail (PIKA_IS_COLOR_DISPLAY_STACK (stack), NULL);
private = GET_PRIVATE (stack);
clone = g_object_new (PIKA_TYPE_COLOR_DISPLAY_STACK, NULL);
for (list = private->filters; list; list = g_list_next (list))
{
PikaColorDisplay *display;
display = pika_color_display_clone (list->data);
pika_color_display_stack_add (clone, display);
g_object_unref (display);
}
return clone;
}
/**
* pika_color_display_stack_changed:
* @stack: a #PikaColorDisplayStack
*
* Emit the "changed" signal of @stack.
*
* Since: 2.0
**/
void
pika_color_display_stack_changed (PikaColorDisplayStack *stack)
{
g_return_if_fail (PIKA_IS_COLOR_DISPLAY_STACK (stack));
g_signal_emit (stack, stack_signals[CHANGED], 0);
}
/**
* pika_color_display_stack_get_filters:
* @stack: a #PikaColorDisplayStack
*
* Gets the list of added color modules.
*
* Returns: (transfer none) (element-type PikaColorDisplay):
the list of @stack's display color modules.
*
* Since: 3.0
**/
GList *
pika_color_display_stack_get_filters (PikaColorDisplayStack *stack)
{
g_return_val_if_fail (PIKA_IS_COLOR_DISPLAY_STACK (stack), NULL);
return GET_PRIVATE (stack)->filters;
}
/**
* pika_color_display_stack_add:
* @stack: a #PikaColorDisplayStack
* @display: (transfer none): a #PikaColorDisplay
*
* Add the color module @display to @stack.
*
* Since: 2.0
**/
void
pika_color_display_stack_add (PikaColorDisplayStack *stack,
PikaColorDisplay *display)
{
PikaColorDisplayStackPrivate *private;
g_return_if_fail (PIKA_IS_COLOR_DISPLAY_STACK (stack));
g_return_if_fail (PIKA_IS_COLOR_DISPLAY (display));
private = GET_PRIVATE (stack);
g_return_if_fail (g_list_find (private->filters, display) == NULL);
private->filters = g_list_append (private->filters, g_object_ref (display));
g_signal_connect (display, "changed",
G_CALLBACK (pika_color_display_stack_display_changed),
G_OBJECT (stack));
g_signal_connect (display, "notify::enabled",
G_CALLBACK (pika_color_display_stack_display_enabled),
G_OBJECT (stack));
g_signal_emit (stack, stack_signals[ADDED], 0,
display, g_list_length (private->filters) - 1);
pika_color_display_stack_changed (stack);
}
/**
* pika_color_display_stack_remove:
* @stack: a #PikaColorDisplayStack
* @display: (transfer none): a #PikaColorDisplay
*
* Remove the color module @display from @stack.
*
* Since: 2.0
**/
void
pika_color_display_stack_remove (PikaColorDisplayStack *stack,
PikaColorDisplay *display)
{
PikaColorDisplayStackPrivate *private;
g_return_if_fail (PIKA_IS_COLOR_DISPLAY_STACK (stack));
g_return_if_fail (PIKA_IS_COLOR_DISPLAY (display));
private = GET_PRIVATE (stack);
g_return_if_fail (g_list_find (private->filters, display) != NULL);
pika_color_display_stack_disconnect (stack, display);
private->filters = g_list_remove (private->filters, display);
g_signal_emit (stack, stack_signals[REMOVED], 0, display);
pika_color_display_stack_changed (stack);
g_object_unref (display);
}
/**
* pika_color_display_stack_reorder_up:
* @stack: a #PikaColorDisplayStack
* @display: a #PikaColorDisplay
*
* Move the color module @display up in the filter list of @stack.
*
* Since: 2.0
**/
void
pika_color_display_stack_reorder_up (PikaColorDisplayStack *stack,
PikaColorDisplay *display)
{
PikaColorDisplayStackPrivate *private;
GList *list;
g_return_if_fail (PIKA_IS_COLOR_DISPLAY_STACK (stack));
g_return_if_fail (PIKA_IS_COLOR_DISPLAY (display));
private = GET_PRIVATE (stack);
list = g_list_find (private->filters, display);
g_return_if_fail (list != NULL);
if (list->prev)
{
list->data = list->prev->data;
list->prev->data = display;
g_signal_emit (stack, stack_signals[REORDERED], 0,
display, g_list_position (private->filters, list->prev));
pika_color_display_stack_changed (stack);
}
}
/**
* pika_color_display_stack_reorder_down:
* @stack: a #PikaColorDisplayStack
* @display: a #PikaColorDisplay
*
* Move the color module @display down in the filter list of @stack.
*
* Since: 2.0
**/
void
pika_color_display_stack_reorder_down (PikaColorDisplayStack *stack,
PikaColorDisplay *display)
{
PikaColorDisplayStackPrivate *private;
GList *list;
g_return_if_fail (PIKA_IS_COLOR_DISPLAY_STACK (stack));
g_return_if_fail (PIKA_IS_COLOR_DISPLAY (display));
private = GET_PRIVATE (stack);
list = g_list_find (private->filters, display);
g_return_if_fail (list != NULL);
if (list->next)
{
list->data = list->next->data;
list->next->data = display;
g_signal_emit (stack, stack_signals[REORDERED], 0,
display, g_list_position (private->filters, list->next));
pika_color_display_stack_changed (stack);
}
}
/**
* pika_color_display_stack_convert_buffer:
* @stack: a #PikaColorDisplayStack
* @buffer: a #GeglBuffer
* @area: area of @buffer to convert
*
* Runs all the stack's filters on all pixels in @area of @buffer.
*
* Since: 2.10
**/
void
pika_color_display_stack_convert_buffer (PikaColorDisplayStack *stack,
GeglBuffer *buffer,
GeglRectangle *area)
{
PikaColorDisplayStackPrivate *private;
GList *list;
g_return_if_fail (PIKA_IS_COLOR_DISPLAY_STACK (stack));
g_return_if_fail (GEGL_IS_BUFFER (buffer));
private = GET_PRIVATE (stack);
for (list = private->filters; list; list = g_list_next (list))
{
PikaColorDisplay *display = list->data;
pika_color_display_convert_buffer (display, buffer, area);
}
}
/* private functions */
static void
pika_color_display_stack_display_changed (PikaColorDisplay *display,
PikaColorDisplayStack *stack)
{
if (pika_color_display_get_enabled (display))
pika_color_display_stack_changed (stack);
}
static void
pika_color_display_stack_display_enabled (PikaColorDisplay *display,
GParamSpec *pspec,
PikaColorDisplayStack *stack)
{
pika_color_display_stack_changed (stack);
}
static void
pika_color_display_stack_disconnect (PikaColorDisplayStack *stack,
PikaColorDisplay *display)
{
g_signal_handlers_disconnect_by_func (display,
pika_color_display_stack_display_changed,
stack);
g_signal_handlers_disconnect_by_func (display,
pika_color_display_stack_display_enabled,
stack);
}

View File

@ -0,0 +1,102 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolordisplaystack.h
* Copyright (C) 2003 Michael Natterer <mitch@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_DISPLAY_STACK_H__
#define __PIKA_COLOR_DISPLAY_STACK_H__
G_BEGIN_DECLS
/* For information look at the html documentation */
#define PIKA_TYPE_COLOR_DISPLAY_STACK (pika_color_display_stack_get_type ())
#define PIKA_COLOR_DISPLAY_STACK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_DISPLAY_STACK, PikaColorDisplayStack))
#define PIKA_COLOR_DISPLAY_STACK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_DISPLAY_STACK, PikaColorDisplayStackClass))
#define PIKA_IS_COLOR_DISPLAY_STACK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_DISPLAY_STACK))
#define PIKA_IS_COLOR_DISPLAY_STACK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_DISPLAY_STACK))
#define PIKA_COLOR_DISPLAY_STACK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_DISPLAY_STACK, PikaColorDisplayStackClass))
typedef struct _PikaColorDisplayStackPrivate PikaColorDisplayStackPrivate;
typedef struct _PikaColorDisplayStackClass PikaColorDisplayStackClass;
struct _PikaColorDisplayStack
{
GObject parent_instance;
PikaColorDisplayStackPrivate *priv;
};
struct _PikaColorDisplayStackClass
{
GObjectClass parent_class;
void (* changed) (PikaColorDisplayStack *stack);
void (* added) (PikaColorDisplayStack *stack,
PikaColorDisplay *display,
gint position);
void (* removed) (PikaColorDisplayStack *stack,
PikaColorDisplay *display);
void (* reordered) (PikaColorDisplayStack *stack,
PikaColorDisplay *display,
gint position);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_color_display_stack_get_type (void) G_GNUC_CONST;
PikaColorDisplayStack * pika_color_display_stack_new (void);
PikaColorDisplayStack * pika_color_display_stack_clone (PikaColorDisplayStack *stack);
void pika_color_display_stack_changed (PikaColorDisplayStack *stack);
GList * pika_color_display_stack_get_filters (PikaColorDisplayStack *stack);
void pika_color_display_stack_add (PikaColorDisplayStack *stack,
PikaColorDisplay *display);
void pika_color_display_stack_remove (PikaColorDisplayStack *stack,
PikaColorDisplay *display);
void pika_color_display_stack_reorder_up (PikaColorDisplayStack *stack,
PikaColorDisplay *display);
void pika_color_display_stack_reorder_down (PikaColorDisplayStack *stack,
PikaColorDisplay *display);
void pika_color_display_stack_convert_buffer (PikaColorDisplayStack *stack,
GeglBuffer *buffer,
GeglRectangle *area);
G_END_DECLS
#endif /* __PIKA_COLOR_DISPLAY_STACK_H__ */

View File

@ -0,0 +1,349 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorhexentry.c
* Copyright (C) 2004 Sven Neumann <sven@gimp.org>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "libpikacolor/pikacolor.h"
#include "pikawidgetstypes.h"
#include "pikacellrenderercolor.h"
#include "pikacolorhexentry.h"
#include "pikahelpui.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikacolorhexentry
* @title: PikaColorHexEntry
* @short_description: Widget for entering a color's hex triplet.
*
* Widget for entering a color's hex triplet.
**/
enum
{
COLOR_CHANGED,
LAST_SIGNAL
};
enum
{
COLUMN_NAME,
COLUMN_COLOR,
NUM_COLUMNS
};
struct _PikaColorHexEntryPrivate
{
PikaRGB color;
};
#define GET_PRIVATE(obj) (((PikaColorHexEntry *) (obj))->priv)
static void pika_color_hex_entry_constructed (GObject *object);
static gboolean pika_color_hex_entry_events (GtkWidget *widget,
GdkEvent *event);
static gboolean pika_color_hex_entry_events (GtkWidget *widget,
GdkEvent *event);
static gboolean pika_color_hex_entry_matched (GtkEntryCompletion *completion,
GtkTreeModel *model,
GtkTreeIter *iter,
PikaColorHexEntry *entry);
G_DEFINE_TYPE_WITH_PRIVATE (PikaColorHexEntry, pika_color_hex_entry,
GTK_TYPE_ENTRY)
#define parent_class pika_color_hex_entry_parent_class
static guint entry_signals[LAST_SIGNAL] = { 0 };
static void
pika_color_hex_entry_class_init (PikaColorHexEntryClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
entry_signals[COLOR_CHANGED] =
g_signal_new ("color-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaColorHexEntryClass, color_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
object_class->constructed = pika_color_hex_entry_constructed;
klass->color_changed = NULL;
}
static void
pika_color_hex_entry_init (PikaColorHexEntry *entry)
{
PikaColorHexEntryPrivate *private;
GtkEntryCompletion *completion;
GtkCellRenderer *cell;
GtkListStore *store;
PikaRGB *colors;
const gchar **names;
gint num_colors;
gint i;
entry->priv = pika_color_hex_entry_get_instance_private (entry);
private = GET_PRIVATE (entry);
/* GtkEntry's minimum size is way too large, set a reasonable one
* for our use case
*/
gtk_entry_set_width_chars (GTK_ENTRY (entry), 8);
pika_help_set_help_data (GTK_WIDGET (entry),
_("Hexadecimal color notation as used in HTML and "
"CSS. This entry also accepts CSS color names."),
NULL);
pika_rgba_set (&private->color, 0.0, 0.0, 0.0, 1.0);
store = gtk_list_store_new (NUM_COLUMNS, G_TYPE_STRING, PIKA_TYPE_RGB);
pika_rgb_list_names (&names, &colors, &num_colors);
for (i = 0; i < num_colors; i++)
{
GtkTreeIter iter;
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
COLUMN_NAME, names[i],
COLUMN_COLOR, colors + i,
-1);
}
g_free (colors);
g_free (names);
completion = g_object_new (GTK_TYPE_ENTRY_COMPLETION,
"model", store,
NULL);
g_object_unref (store);
cell = pika_cell_renderer_color_new ();
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (completion), cell, FALSE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (completion), cell,
"color", COLUMN_COLOR,
NULL);
gtk_entry_completion_set_text_column (completion, COLUMN_NAME);
gtk_entry_set_completion (GTK_ENTRY (entry), completion);
g_object_unref (completion);
g_signal_connect (entry, "focus-out-event",
G_CALLBACK (pika_color_hex_entry_events),
NULL);
g_signal_connect (entry, "key-press-event",
G_CALLBACK (pika_color_hex_entry_events),
NULL);
g_signal_connect (completion, "match-selected",
G_CALLBACK (pika_color_hex_entry_matched),
entry);
}
static void
pika_color_hex_entry_constructed (GObject *object)
{
G_OBJECT_CLASS (parent_class)->constructed (object);
gtk_entry_set_text (GTK_ENTRY (object), "000000");
}
/**
* pika_color_hex_entry_new:
*
* Returns: a new #PikaColorHexEntry widget
*
* Since: 2.2
**/
GtkWidget *
pika_color_hex_entry_new (void)
{
return g_object_new (PIKA_TYPE_COLOR_HEX_ENTRY, NULL);
}
/**
* pika_color_hex_entry_set_color:
* @entry: a #PikaColorHexEntry widget
* @color: pointer to a #PikaRGB
*
* Sets the color displayed by a #PikaColorHexEntry. If the new color
* is different to the previously set color, the "color-changed"
* signal is emitted.
*
* Since: 2.2
**/
void
pika_color_hex_entry_set_color (PikaColorHexEntry *entry,
const PikaRGB *color)
{
PikaColorHexEntryPrivate *private;
g_return_if_fail (PIKA_IS_COLOR_HEX_ENTRY (entry));
g_return_if_fail (color != NULL);
private = GET_PRIVATE (entry);
if (pika_rgb_distance (&private->color, color) > 0.0)
{
gchar buffer[8];
guchar r, g, b;
pika_rgb_set (&private->color, color->r, color->g, color->b);
pika_rgb_clamp (&private->color);
pika_rgb_get_uchar (&private->color, &r, &g, &b);
g_snprintf (buffer, sizeof (buffer), "%.2x%.2x%.2x", r, g, b);
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
/* move cursor to the end */
gtk_editable_set_position (GTK_EDITABLE (entry), -1);
g_signal_emit (entry, entry_signals[COLOR_CHANGED], 0);
}
}
/**
* pika_color_hex_entry_get_color:
* @entry: a #PikaColorHexEntry widget
* @color: (out caller-allocates): pointer to a #PikaRGB
*
* Retrieves the color value displayed by a #PikaColorHexEntry.
*
* Since: 2.2
**/
void
pika_color_hex_entry_get_color (PikaColorHexEntry *entry,
PikaRGB *color)
{
PikaColorHexEntryPrivate *private;
g_return_if_fail (PIKA_IS_COLOR_HEX_ENTRY (entry));
g_return_if_fail (color != NULL);
private = GET_PRIVATE (entry);
*color = private->color;
}
static gboolean
pika_color_hex_entry_events (GtkWidget *widget,
GdkEvent *event)
{
PikaColorHexEntry *entry = PIKA_COLOR_HEX_ENTRY (widget);
PikaColorHexEntryPrivate *private = GET_PRIVATE (entry);
switch (event->type)
{
case GDK_KEY_PRESS:
{
GdkEventKey *kevent = (GdkEventKey *) event;
if (kevent->keyval != GDK_KEY_Return &&
kevent->keyval != GDK_KEY_KP_Enter &&
kevent->keyval != GDK_KEY_ISO_Enter)
break;
/* else fall through */
}
case GDK_FOCUS_CHANGE:
{
const gchar *text;
gchar buffer[8];
guchar r, g, b;
text = gtk_entry_get_text (GTK_ENTRY (widget));
pika_rgb_get_uchar (&private->color, &r, &g, &b);
g_snprintf (buffer, sizeof (buffer), "%.2x%.2x%.2x", r, g, b);
if (g_ascii_strcasecmp (buffer, text) != 0)
{
PikaRGB color;
gsize len = strlen (text);
if (len > 0 &&
(pika_rgb_parse_hex (&color, text, len) ||
pika_rgb_parse_name (&color, text, -1)))
{
pika_color_hex_entry_set_color (entry, &color);
}
else
{
gtk_entry_set_text (GTK_ENTRY (entry), buffer);
}
}
}
break;
default:
/* do nothing */
break;
}
return FALSE;
}
static gboolean
pika_color_hex_entry_matched (GtkEntryCompletion *completion,
GtkTreeModel *model,
GtkTreeIter *iter,
PikaColorHexEntry *entry)
{
gchar *name;
PikaRGB color;
gtk_tree_model_get (model, iter,
COLUMN_NAME, &name,
-1);
if (pika_rgb_parse_name (&color, name, -1))
pika_color_hex_entry_set_color (entry, &color);
g_free (name);
return TRUE;
}

View File

@ -0,0 +1,80 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorhexentry.h
* Copyright (C) 2004 Sven Neumann <sven@gimp.org>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_HEX_ENTRY_H__
#define __PIKA_COLOR_HEX_ENTRY_H__
G_BEGIN_DECLS
#define PIKA_TYPE_COLOR_HEX_ENTRY (pika_color_hex_entry_get_type ())
#define PIKA_COLOR_HEX_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_HEX_ENTRY, PikaColorHexEntry))
#define PIKA_COLOR_HEX_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_HEX_ENTRY, PikaColorHexEntryClass))
#define PIKA_IS_COLOR_HEX_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_HEX_ENTRY))
#define PIKA_IS_COLOR_HEX_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_HEX_ENTRY))
#define PIKA_COLOR_HEX_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_HEX_AREA, PikaColorHexEntryClass))
typedef struct _PikaColorHexEntryPrivate PikaColorHexEntryPrivate;
typedef struct _PikaColorHexEntryClass PikaColorHexEntryClass;
struct _PikaColorHexEntry
{
GtkEntry parent_instance;
PikaColorHexEntryPrivate *priv;
};
struct _PikaColorHexEntryClass
{
GtkEntryClass parent_class;
void (* color_changed) (PikaColorHexEntry *entry);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_color_hex_entry_get_type (void) G_GNUC_CONST;
GtkWidget * pika_color_hex_entry_new (void);
void pika_color_hex_entry_set_color (PikaColorHexEntry *entry,
const PikaRGB *color);
void pika_color_hex_entry_get_color (PikaColorHexEntry *entry,
PikaRGB *color);
G_END_DECLS
#endif /* __PIKA_COLOR_HEX_ENTRY_H__ */

View File

@ -0,0 +1,628 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolornotebook.c
* Copyright (C) 2002 Michael Natterer <mitch@gimp.org>
*
* based on color_notebook module
* Copyright (C) 1998 Austin Donnelly <austin@greenend.org.uk>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikacolor/pikacolor.h"
#include "pikawidgetstypes.h"
#include "pikacolornotebook.h"
#include "pikacolorscales.h"
#include "pikahelpui.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikacolornotebook
* @title: PikaColorNotebook
* @short_description: A #PikaColorSelector implementation.
*
* The #PikaColorNotebook widget is an implementation of a
* #PikaColorSelector. It serves as a container for
* #PikaColorSelectors.
**/
#define DEFAULT_TAB_ICON_SIZE GTK_ICON_SIZE_BUTTON
struct _PikaColorNotebookPrivate
{
GtkWidget *notebook;
GList *selectors;
PikaColorSelector *cur_page;
};
#define GET_PRIVATE(obj) (((PikaColorNotebook *) obj)->priv)
static void pika_color_notebook_style_updated (GtkWidget *widget);
static void pika_color_notebook_togg_visible (PikaColorSelector *selector,
gboolean visible);
static void pika_color_notebook_togg_sensitive (PikaColorSelector *selector,
gboolean sensitive);
static void pika_color_notebook_set_show_alpha (PikaColorSelector *selector,
gboolean show_alpha);
static void pika_color_notebook_set_color (PikaColorSelector *selector,
const PikaRGB *rgb,
const PikaHSV *hsv);
static void pika_color_notebook_set_channel (PikaColorSelector *selector,
PikaColorSelectorChannel channel);
static void pika_color_notebook_set_model_visible
(PikaColorSelector *selector,
PikaColorSelectorModel model,
gboolean gboolean);
static void pika_color_notebook_set_config (PikaColorSelector *selector,
PikaColorConfig *config);
static void pika_color_notebook_switch_page (GtkNotebook *gtk_notebook,
gpointer page,
guint page_num,
PikaColorNotebook *notebook);
static void pika_color_notebook_color_changed (PikaColorSelector *page,
const PikaRGB *rgb,
const PikaHSV *hsv,
PikaColorNotebook *notebook);
static void pika_color_notebook_channel_changed (PikaColorSelector *page,
PikaColorSelectorChannel channel,
PikaColorNotebook *notebook);
static void pika_color_notebook_model_visible_changed
(PikaColorSelector *page,
PikaColorSelectorModel model,
gboolean visible,
PikaColorNotebook *notebook);
static GtkWidget * pika_color_notebook_add_page (PikaColorNotebook *notebook,
GType page_type);
static void pika_color_notebook_remove_selector (GtkContainer *container,
GtkWidget *widget,
PikaColorNotebook *notebook);
G_DEFINE_TYPE_WITH_PRIVATE (PikaColorNotebook, pika_color_notebook,
PIKA_TYPE_COLOR_SELECTOR)
#define parent_class pika_color_notebook_parent_class
static void
pika_color_notebook_class_init (PikaColorNotebookClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
PikaColorSelectorClass *selector_class = PIKA_COLOR_SELECTOR_CLASS (klass);
widget_class->style_updated = pika_color_notebook_style_updated;
selector_class->name = "Notebook";
selector_class->help_id = "pika-colorselector-notebook";
selector_class->set_toggles_visible = pika_color_notebook_togg_visible;
selector_class->set_toggles_sensitive = pika_color_notebook_togg_sensitive;
selector_class->set_show_alpha = pika_color_notebook_set_show_alpha;
selector_class->set_color = pika_color_notebook_set_color;
selector_class->set_channel = pika_color_notebook_set_channel;
selector_class->set_model_visible = pika_color_notebook_set_model_visible;
selector_class->set_config = pika_color_notebook_set_config;
gtk_widget_class_install_style_property (widget_class,
g_param_spec_enum ("tab-icon-size",
NULL,
"Size for icons displayed in the tab",
GTK_TYPE_ICON_SIZE,
DEFAULT_TAB_ICON_SIZE,
G_PARAM_READABLE));
gtk_widget_class_set_css_name (widget_class, "PikaColorNotebook");
}
static void
pika_color_notebook_init (PikaColorNotebook *notebook)
{
PikaColorNotebookPrivate *private = GET_PRIVATE (notebook);
GType *selector_types;
guint n_selector_types;
guint i;
notebook->priv = pika_color_notebook_get_instance_private (notebook);
private = notebook->priv;
private->notebook = gtk_notebook_new ();
gtk_notebook_popup_enable (GTK_NOTEBOOK (private->notebook));
gtk_box_pack_start (GTK_BOX (notebook), private->notebook, TRUE, TRUE, 0);
gtk_widget_show (private->notebook);
g_signal_connect (private->notebook, "switch-page",
G_CALLBACK (pika_color_notebook_switch_page),
notebook);
g_signal_connect (private->notebook, "remove",
G_CALLBACK (pika_color_notebook_remove_selector),
notebook);
selector_types = g_type_children (PIKA_TYPE_COLOR_SELECTOR,
&n_selector_types);
if (n_selector_types == 2)
{
gtk_notebook_set_show_tabs (GTK_NOTEBOOK (private->notebook), FALSE);
gtk_notebook_set_show_border (GTK_NOTEBOOK (private->notebook), FALSE);
}
for (i = 0; i < n_selector_types; i++)
{
/* skip ourselves */
if (g_type_is_a (selector_types[i], PIKA_TYPE_COLOR_NOTEBOOK))
continue;
/* skip the "Scales" color selector */
if (g_type_is_a (selector_types[i], PIKA_TYPE_COLOR_SCALES))
continue;
pika_color_notebook_add_page (notebook, selector_types[i]);
}
g_free (selector_types);
}
static void
pika_color_notebook_style_updated (GtkWidget *widget)
{
PikaColorNotebookPrivate *private = GET_PRIVATE (widget);
GList *list;
GtkIconSize icon_size;
GTK_WIDGET_CLASS (parent_class)->style_updated (widget);
gtk_widget_style_get (widget,
"tab-icon-size", &icon_size,
NULL);
for (list = private->selectors; list; list = g_list_next (list))
{
PikaColorSelectorClass *selector_class;
GtkWidget *image;
selector_class = PIKA_COLOR_SELECTOR_GET_CLASS (list->data);
image = gtk_image_new_from_icon_name (selector_class->icon_name,
icon_size);
pika_help_set_help_data (image, gettext (selector_class->name), NULL);
gtk_notebook_set_tab_label (GTK_NOTEBOOK (private->notebook),
GTK_WIDGET (list->data),
image);
}
}
static void
pika_color_notebook_togg_visible (PikaColorSelector *selector,
gboolean visible)
{
PikaColorNotebookPrivate *private = GET_PRIVATE (selector);
GList *list;
for (list = private->selectors; list; list = g_list_next (list))
{
PikaColorSelector *child = list->data;
pika_color_selector_set_toggles_visible (child, visible);
}
}
static void
pika_color_notebook_togg_sensitive (PikaColorSelector *selector,
gboolean sensitive)
{
PikaColorNotebookPrivate *private = GET_PRIVATE (selector);
GList *list;
for (list = private->selectors; list; list = g_list_next (list))
{
PikaColorSelector *child = list->data;
pika_color_selector_set_toggles_sensitive (child, sensitive);
}
}
static void
pika_color_notebook_set_show_alpha (PikaColorSelector *selector,
gboolean show_alpha)
{
PikaColorNotebookPrivate *private = GET_PRIVATE (selector);
GList *list;
for (list = private->selectors; list; list = g_list_next (list))
{
PikaColorSelector *child = list->data;
pika_color_selector_set_show_alpha (child, show_alpha);
}
}
static void
pika_color_notebook_set_color (PikaColorSelector *selector,
const PikaRGB *rgb,
const PikaHSV *hsv)
{
PikaColorNotebookPrivate *private = GET_PRIVATE (selector);
g_signal_handlers_block_by_func (private->cur_page,
pika_color_notebook_color_changed,
selector);
pika_color_selector_set_color (private->cur_page, rgb, hsv);
g_signal_handlers_unblock_by_func (private->cur_page,
pika_color_notebook_color_changed,
selector);
}
static void
pika_color_notebook_set_channel (PikaColorSelector *selector,
PikaColorSelectorChannel channel)
{
PikaColorNotebookPrivate *private = GET_PRIVATE (selector);
g_signal_handlers_block_by_func (private->cur_page,
pika_color_notebook_channel_changed,
selector);
pika_color_selector_set_channel (private->cur_page, channel);
g_signal_handlers_unblock_by_func (private->cur_page,
pika_color_notebook_channel_changed,
selector);
}
static void
pika_color_notebook_set_model_visible (PikaColorSelector *selector,
PikaColorSelectorModel model,
gboolean visible)
{
PikaColorNotebookPrivate *private = GET_PRIVATE (selector);
g_signal_handlers_block_by_func (private->cur_page,
pika_color_notebook_model_visible_changed,
selector);
pika_color_selector_set_model_visible (private->cur_page, model, visible);
g_signal_handlers_unblock_by_func (private->cur_page,
pika_color_notebook_model_visible_changed,
selector);
}
static void
pika_color_notebook_set_config (PikaColorSelector *selector,
PikaColorConfig *config)
{
PikaColorNotebookPrivate *private = GET_PRIVATE (selector);
GList *list;
for (list = private->selectors; list; list = g_list_next (list))
{
PikaColorSelector *child = list->data;
pika_color_selector_set_config (child, config);
}
}
static void
pika_color_notebook_switch_page (GtkNotebook *gtk_notebook,
gpointer page,
guint page_num,
PikaColorNotebook *notebook)
{
PikaColorNotebookPrivate *private = GET_PRIVATE (notebook);
PikaColorSelector *selector = PIKA_COLOR_SELECTOR (notebook);
GtkWidget *page_widget;
PikaColorSelectorModel model;
page_widget = gtk_notebook_get_nth_page (gtk_notebook, page_num);
private->cur_page = PIKA_COLOR_SELECTOR (page_widget);
g_signal_handlers_block_by_func (private->cur_page,
pika_color_notebook_color_changed,
notebook);
g_signal_handlers_block_by_func (private->cur_page,
pika_color_notebook_channel_changed,
notebook);
g_signal_handlers_block_by_func (private->cur_page,
pika_color_notebook_model_visible_changed,
notebook);
pika_color_selector_set_color (private->cur_page,
&selector->rgb,
&selector->hsv);
pika_color_selector_set_channel (private->cur_page,
pika_color_selector_get_channel (selector));
for (model = PIKA_COLOR_SELECTOR_MODEL_RGB;
model <= PIKA_COLOR_SELECTOR_MODEL_HSV;
model++)
{
gboolean visible = pika_color_selector_get_model_visible (selector, model);
pika_color_selector_set_model_visible (private->cur_page, model,
visible);
}
g_signal_handlers_unblock_by_func (private->cur_page,
pika_color_notebook_color_changed,
notebook);
g_signal_handlers_unblock_by_func (private->cur_page,
pika_color_notebook_channel_changed,
notebook);
g_signal_handlers_unblock_by_func (private->cur_page,
pika_color_notebook_model_visible_changed,
notebook);
}
static void
pika_color_notebook_color_changed (PikaColorSelector *page,
const PikaRGB *rgb,
const PikaHSV *hsv,
PikaColorNotebook *notebook)
{
PikaColorSelector *selector = PIKA_COLOR_SELECTOR (notebook);
selector->rgb = *rgb;
selector->hsv = *hsv;
pika_color_selector_emit_color_changed (selector);
}
static void
pika_color_notebook_channel_changed (PikaColorSelector *page,
PikaColorSelectorChannel channel,
PikaColorNotebook *notebook)
{
PikaColorSelector *selector = PIKA_COLOR_SELECTOR (notebook);
pika_color_selector_set_channel (selector, channel);
}
static void
pika_color_notebook_model_visible_changed (PikaColorSelector *page,
PikaColorSelectorModel model,
gboolean visible,
PikaColorNotebook *notebook)
{
PikaColorSelector *selector = PIKA_COLOR_SELECTOR (notebook);
pika_color_selector_set_model_visible (selector, model, visible);
}
static GtkWidget *
pika_color_notebook_add_page (PikaColorNotebook *notebook,
GType page_type)
{
PikaColorNotebookPrivate *private = GET_PRIVATE (notebook);
PikaColorSelector *selector = PIKA_COLOR_SELECTOR (notebook);
PikaColorSelectorClass *selector_class;
GtkWidget *page;
GtkWidget *menu_widget;
GtkWidget *image;
GtkWidget *label;
gboolean show_alpha;
page = pika_color_selector_new (page_type,
&selector->rgb,
&selector->hsv,
pika_color_selector_get_channel (selector));
if (! page)
return NULL;
selector_class = PIKA_COLOR_SELECTOR_GET_CLASS (page);
show_alpha = pika_color_selector_get_show_alpha (PIKA_COLOR_SELECTOR (notebook));
pika_color_selector_set_show_alpha (PIKA_COLOR_SELECTOR (page), show_alpha);
menu_widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 4);
image = gtk_image_new_from_icon_name (selector_class->icon_name,
GTK_ICON_SIZE_MENU);
gtk_box_pack_start (GTK_BOX (menu_widget), image, FALSE, FALSE, 0);
gtk_widget_show (image);
label = gtk_label_new (gettext (selector_class->name));
gtk_box_pack_start (GTK_BOX (menu_widget), label, FALSE, FALSE, 0);
gtk_widget_show (label);
image = gtk_image_new_from_icon_name (selector_class->icon_name,
DEFAULT_TAB_ICON_SIZE);
pika_help_set_help_data (image, gettext (selector_class->name), NULL);
gtk_notebook_append_page_menu (GTK_NOTEBOOK (private->notebook),
page, image, menu_widget);
if (! private->cur_page)
private->cur_page = PIKA_COLOR_SELECTOR (page);
private->selectors = g_list_append (private->selectors, page);
gtk_widget_show (page);
g_signal_connect (page, "color-changed",
G_CALLBACK (pika_color_notebook_color_changed),
notebook);
g_signal_connect (page, "channel-changed",
G_CALLBACK (pika_color_notebook_channel_changed),
notebook);
g_signal_connect (page, "model-visible-changed",
G_CALLBACK (pika_color_notebook_model_visible_changed),
notebook);
return page;
}
static void
pika_color_notebook_remove_selector (GtkContainer *container,
GtkWidget *widget,
PikaColorNotebook *notebook)
{
notebook->priv->selectors = g_list_remove (notebook->priv->selectors,
widget);
if (! notebook->priv->selectors)
notebook->priv->cur_page = NULL;
}
/**
* pika_color_notebook_set_has_page:
* @notebook: A #PikaColorNotebook widget.
* @page_type: The #GType of the notebook page to add or remove.
* @has_page: Whether the page should be added or removed.
*
* This function adds and removed pages to / from a #PikaColorNotebook.
* The @page_type passed must be a #PikaColorSelector subtype.
*
* Returns: (transfer none): The new page widget, if @has_page was
* %TRUE, or %NULL if @has_page was %FALSE.
**/
GtkWidget *
pika_color_notebook_set_has_page (PikaColorNotebook *notebook,
GType page_type,
gboolean has_page)
{
GList *list;
g_return_val_if_fail (PIKA_IS_COLOR_NOTEBOOK (notebook), NULL);
g_return_val_if_fail (g_type_is_a (page_type, PIKA_TYPE_COLOR_SELECTOR),
NULL);
g_return_val_if_fail (! g_type_is_a (page_type, PIKA_TYPE_COLOR_NOTEBOOK),
NULL);
for (list = notebook->priv->selectors; list; list = g_list_next (list))
{
PikaColorSelector *page = list->data;
if (G_TYPE_FROM_INSTANCE (page) == page_type)
{
if (has_page)
return GTK_WIDGET (page);
gtk_container_remove (GTK_CONTAINER (notebook->priv->notebook),
GTK_WIDGET (page));
return NULL;
}
}
if (! has_page)
return NULL;
return pika_color_notebook_add_page (notebook, page_type);
}
/**
* pika_color_notebook_get_notebook:
* @notebook: A #PikaColorNotebook widget.
*
* Returns: (transfer none) (type GtkNotebook): The #GtkNotebook inside.
*
* Since: 3.0
**/
GtkWidget *
pika_color_notebook_get_notebook (PikaColorNotebook *notebook)
{
g_return_val_if_fail (PIKA_IS_COLOR_NOTEBOOK (notebook), NULL);
return notebook->priv->notebook;
}
/**
* pika_color_notebook_get_selectors:
* @notebook: A #PikaColorNotebook widget.
*
* Returns: (element-type PikaColorSelector) (transfer none): The
* notebook's list of #PikaColorSelector's.
*
* Since: 3.0
**/
GList *
pika_color_notebook_get_selectors (PikaColorNotebook *notebook)
{
g_return_val_if_fail (PIKA_IS_COLOR_NOTEBOOK (notebook), NULL);
return notebook->priv->selectors;
}
/**
* pika_color_notebook_get_current_selector:
* @notebook: A #PikaColorNotebook widget.
*
* Returns: (transfer none): The active page's #PikaColorSelector.
*
* Since: 3.0
**/
PikaColorSelector *
pika_color_notebook_get_current_selector (PikaColorNotebook *notebook)
{
g_return_val_if_fail (PIKA_IS_COLOR_NOTEBOOK (notebook), NULL);
return notebook->priv->cur_page;
}
/**
* pika_color_notebook_set_simulation:
* @notebook: A #PikaColorNotebook widget.
* @profile: A #PikaColorProfile object.
* @intent: A #PikaColorRenderingIntent enum.
* @bpc: A gboolean.
*
* Updates all selectors with the current simulation settings.
*
* Since: 3.0
**/
void
pika_color_notebook_set_simulation (PikaColorNotebook *notebook,
PikaColorProfile *profile,
PikaColorRenderingIntent intent,
gboolean bpc)
{
GList *list;
g_return_if_fail (PIKA_IS_COLOR_NOTEBOOK (notebook));
g_return_if_fail (profile == NULL || PIKA_IS_COLOR_PROFILE (profile));
for (list = notebook->priv->selectors; list; list = g_list_next (list))
{
PikaColorSelector *selector = list->data;
if (selector)
pika_color_selector_set_simulation (selector, profile, intent, bpc);
}
}

View File

@ -0,0 +1,88 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolornotebook.h
* Copyright (C) 2002 Michael Natterer <mitch@gimp.org>
*
* based on color_notebook module
* Copyright (C) 1998 Austin Donnelly <austin@greenend.org.uk>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_NOTEBOOK_H__
#define __PIKA_COLOR_NOTEBOOK_H__
#include <libpikawidgets/pikacolorselector.h>
G_BEGIN_DECLS
#define PIKA_TYPE_COLOR_NOTEBOOK (pika_color_notebook_get_type ())
#define PIKA_COLOR_NOTEBOOK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_NOTEBOOK, PikaColorNotebook))
#define PIKA_COLOR_NOTEBOOK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_NOTEBOOK, PikaColorNotebookClass))
#define PIKA_IS_COLOR_NOTEBOOK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_NOTEBOOK))
#define PIKA_IS_COLOR_NOTEBOOK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_NOTEBOOK))
#define PIKA_COLOR_NOTEBOOK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_NOTEBOOK, PikaColorNotebookClass))
typedef struct _PikaColorNotebookPrivate PikaColorNotebookPrivate;
typedef struct _PikaColorNotebookClass PikaColorNotebookClass;
struct _PikaColorNotebook
{
PikaColorSelector parent_instance;
PikaColorNotebookPrivate *priv;
};
struct _PikaColorNotebookClass
{
PikaColorSelectorClass parent_class;
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_color_notebook_get_type (void) G_GNUC_CONST;
GtkWidget * pika_color_notebook_set_has_page (PikaColorNotebook *notebook,
GType page_type,
gboolean has_page);
GtkWidget * pika_color_notebook_get_notebook (PikaColorNotebook *notebook);
GList * pika_color_notebook_get_selectors (PikaColorNotebook *notebook);
PikaColorSelector * pika_color_notebook_get_current_selector (PikaColorNotebook *notebook);
void pika_color_notebook_set_simulation (PikaColorNotebook *notebook,
PikaColorProfile *profile,
PikaColorRenderingIntent intent,
gboolean bpc);
G_END_DECLS
#endif /* __PIKA_COLOR_NOTEBOOK_H__ */

View File

@ -0,0 +1,360 @@
/* 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
*
* PikaColorProfileChooserDialog
* Copyright (C) 2006-2014 Sven Neumann <sven@gimp.org>
* Michael Natterer <mitch@gimp.org>
*
* 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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#ifdef PLATFORM_OSX
#include <AppKit/AppKit.h>
#endif
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikacolor/pikacolor.h"
#include "pikawidgetstypes.h"
#include "pikacolorprofilechooserdialog.h"
#include "pikacolorprofileview.h"
#include "pikadialog.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikacolorprofilechooserdialog
* @title: PikaColorProfileChooserDialog
* @short_description: A file chooser for selecting color profiles.
*
* A #GtkFileChooser subclass for selecting color profiles.
**/
struct _PikaColorProfileChooserDialogPrivate
{
PikaColorProfileView *profile_view;
};
static void pika_color_profile_chooser_dialog_constructed (GObject *object);
static gboolean pika_color_profile_chooser_dialog_delete_event (GtkWidget *widget,
GdkEventAny *event);
static void pika_color_profile_chooser_dialog_add_shortcut (PikaColorProfileChooserDialog *dialog);
static void pika_color_profile_chooser_dialog_update_preview (PikaColorProfileChooserDialog *dialog);
G_DEFINE_TYPE_WITH_PRIVATE (PikaColorProfileChooserDialog,
pika_color_profile_chooser_dialog,
GTK_TYPE_FILE_CHOOSER_DIALOG)
#define parent_class pika_color_profile_chooser_dialog_parent_class
static void
pika_color_profile_chooser_dialog_class_init (PikaColorProfileChooserDialogClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->constructed = pika_color_profile_chooser_dialog_constructed;
widget_class->delete_event = pika_color_profile_chooser_dialog_delete_event;
}
static void
pika_color_profile_chooser_dialog_init (PikaColorProfileChooserDialog *dialog)
{
dialog->priv =
pika_color_profile_chooser_dialog_get_instance_private (dialog);
}
static void
pika_color_profile_chooser_dialog_constructed (GObject *object)
{
PikaColorProfileChooserDialog *dialog;
GtkFileFilter *filter;
GtkWidget *scrolled_window;
GtkWidget *profile_view;
dialog = PIKA_COLOR_PROFILE_CHOOSER_DIALOG (object);
G_OBJECT_CLASS (parent_class)->constructed (object);
gtk_window_set_role (GTK_WINDOW (dialog), "pika-profile-chooser-dialog");
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("All files (*.*)"));
gtk_file_filter_add_pattern (filter, "*");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
filter = gtk_file_filter_new ();
gtk_file_filter_set_name (filter, _("ICC color profile (*.icc, *.icm)"));
gtk_file_filter_add_pattern (filter, "*.[Ii][Cc][Cc]");
gtk_file_filter_add_pattern (filter, "*.[Ii][Cc][Mm]");
gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog), filter);
gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (dialog), filter);
/* the preview widget */
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_widget_set_size_request (scrolled_window, 300, -1);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_SHADOW_IN);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
profile_view = pika_color_profile_view_new ();
gtk_container_add (GTK_CONTAINER (scrolled_window), profile_view);
gtk_widget_show (profile_view);
dialog->priv->profile_view = PIKA_COLOR_PROFILE_VIEW (profile_view);
gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (dialog),
scrolled_window);
g_signal_connect (dialog, "update-preview",
G_CALLBACK (pika_color_profile_chooser_dialog_update_preview),
NULL);
}
static gboolean
pika_color_profile_chooser_dialog_delete_event (GtkWidget *widget,
GdkEventAny *event)
{
return TRUE;
}
GtkWidget *
pika_color_profile_chooser_dialog_new (const gchar *title,
GtkWindow *parent,
GtkFileChooserAction action)
{
GtkWidget *dialog;
g_return_val_if_fail (title != NULL, NULL);
g_return_val_if_fail (parent == NULL || GTK_IS_WINDOW (parent), NULL);
dialog = g_object_new (PIKA_TYPE_COLOR_PROFILE_CHOOSER_DIALOG,
"title", title,
"action", action,
NULL);
if (parent)
gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
if (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog)) ==
GTK_FILE_CHOOSER_ACTION_SAVE)
{
gtk_dialog_add_buttons (GTK_DIALOG (dialog),
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Save"), GTK_RESPONSE_ACCEPT,
NULL);
gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog),
TRUE);
}
else
{
gtk_dialog_add_buttons (GTK_DIALOG (dialog),
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_Open"), GTK_RESPONSE_ACCEPT,
NULL);
}
pika_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_ACCEPT,
GTK_RESPONSE_CANCEL,
-1);
gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
pika_color_profile_chooser_dialog_add_shortcut (PIKA_COLOR_PROFILE_CHOOSER_DIALOG (dialog));
return dialog;
}
/* Add shortcuts for default ICC profile locations */
static gboolean
add_shortcut (PikaColorProfileChooserDialog *dialog,
const gchar *folder)
{
return (g_file_test (folder, G_FILE_TEST_IS_DIR) &&
gtk_file_chooser_add_shortcut_folder (GTK_FILE_CHOOSER (dialog),
folder, NULL));
}
static void
pika_color_profile_chooser_dialog_add_shortcut (PikaColorProfileChooserDialog *dialog)
{
gboolean save = (gtk_file_chooser_get_action (GTK_FILE_CHOOSER (dialog)) ==
GTK_FILE_CHOOSER_ACTION_SAVE);
#ifdef G_OS_WIN32
{
const gchar *prefix = g_getenv ("SystemRoot");
gchar *folder;
if (! prefix)
prefix = "c:\\windows";
folder = g_strconcat (prefix, "\\system32\\spool\\drivers\\color", NULL);
add_shortcut (dialog, folder);
g_free (folder);
}
#elif defined(PLATFORM_OSX)
{
NSAutoreleasePool *pool;
NSArray *path;
NSString *library_dir;
gchar *folder;
gboolean folder_set = FALSE;
pool = [[NSAutoreleasePool alloc] init];
if (save)
{
path = NSSearchPathForDirectoriesInDomains (NSLibraryDirectory,
NSUserDomainMask, YES);
library_dir = [path objectAtIndex:0];
folder = g_build_filename ([library_dir UTF8String],
"ColorSync", "Profiles", NULL);
folder_set = add_shortcut (dialog, folder);
g_free (folder);
}
if (! folder_set)
{
path = NSSearchPathForDirectoriesInDomains (NSLibraryDirectory,
NSSystemDomainMask, YES);
library_dir = [path objectAtIndex:0];
folder = g_build_filename ([library_dir UTF8String],
"ColorSync", "Profiles", NULL);
add_shortcut (dialog, folder);
g_free (folder);
}
[pool drain];
}
#else
{
gboolean folder_set = FALSE;
if (save)
{
gchar *folder = g_build_filename (g_get_user_data_dir (),
"color", "icc", NULL);
folder_set = add_shortcut (dialog, folder);
if (! folder_set)
{
g_free (folder);
/* Some software, like GNOME color, will save profiles in
* $XDG_DATA_HOME/icc/
*/
folder = g_build_filename (g_get_user_data_dir (),
"icc", NULL);
folder_set = add_shortcut (dialog, folder);
}
if (! folder_set)
{
g_free (folder);
folder = g_build_filename (g_get_home_dir (),
".color", "icc", NULL);
folder_set = add_shortcut (dialog, folder);
}
g_free (folder);
}
if (! folder_set)
add_shortcut (dialog, COLOR_PROFILE_DIRECTORY);
}
#endif
}
static void
pika_color_profile_chooser_dialog_update_preview (PikaColorProfileChooserDialog *dialog)
{
PikaColorProfile *profile;
GFile *file;
GError *error = NULL;
file = gtk_file_chooser_get_preview_file (GTK_FILE_CHOOSER (dialog));
if (! file)
{
pika_color_profile_view_set_profile (dialog->priv->profile_view, NULL);
return;
}
switch (g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL))
{
case G_FILE_TYPE_REGULAR:
profile = pika_color_profile_new_from_file (file, &error);
if (! profile)
{
pika_color_profile_view_set_error (dialog->priv->profile_view,
error->message);
g_clear_error (&error);
}
else
{
pika_color_profile_view_set_profile (dialog->priv->profile_view,
profile);
g_object_unref (profile);
}
break;
case G_FILE_TYPE_DIRECTORY:
pika_color_profile_view_set_error (dialog->priv->profile_view,
_("Folder"));
break;
default:
pika_color_profile_view_set_error (dialog->priv->profile_view,
_("Not a regular file."));
break;
}
g_object_unref (file);
}

View File

@ -0,0 +1,75 @@
/* 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
*
* PikaColorProfileChooserDialog
* Copyright (C) 2006-2014 Sven Neumann <sven@gimp.org>
* Michael Natterer <mitch@gimp.org>
*
* 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 <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_COLOR_PROFILE_CHOOSER_DIALOG_H__
#define __PIKA_COLOR_PROFILE_CHOOSER_DIALOG_H__
G_BEGIN_DECLS
#define PIKA_TYPE_COLOR_PROFILE_CHOOSER_DIALOG (pika_color_profile_chooser_dialog_get_type ())
#define PIKA_COLOR_PROFILE_CHOOSER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_PROFILE_CHOOSER_DIALOG, PikaColorProfileChooserDialog))
#define PIKA_COLOR_PROFILE_CHOOSER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_PROFILE_CHOOSER_DIALOG, PikaColorProfileChooserDialogClass))
#define PIKA_IS_COLOR_PROFILE_CHOOSER_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_PROFILE_CHOOSER_DIALOG))
#define PIKA_IS_COLOR_PROFILE_CHOOSER_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_PROFILE_CHOOSER_DIALOG))
#define PIKA_COLOR_PROFILE_CHOOSER_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_PROFILE_CHOOSER_DIALOG, PikaColorProfileChooserDialogClass))
typedef struct _PikaColorProfileChooserDialogClass PikaColorProfileChooserDialogClass;
typedef struct _PikaColorProfileChooserDialogPrivate PikaColorProfileChooserDialogPrivate;
struct _PikaColorProfileChooserDialog
{
GtkFileChooserDialog parent_instance;
PikaColorProfileChooserDialogPrivate *priv;
};
struct _PikaColorProfileChooserDialogClass
{
GtkFileChooserDialogClass parent_class;
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_color_profile_chooser_dialog_get_type (void) G_GNUC_CONST;
GtkWidget * pika_color_profile_chooser_dialog_new (const gchar *title,
GtkWindow *parent,
GtkFileChooserAction action);
G_END_DECLS
#endif /* __PIKA_COLOR_PROFILE_CHOOSER_DIALOG_H__ */

View File

@ -0,0 +1,557 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorprofilecombobox.c
* Copyright (C) 2007 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h"
#include "pikawidgetstypes.h"
#include "pikacolorprofilechooserdialog.h"
#include "pikacolorprofilecombobox.h"
#include "pikacolorprofilestore.h"
#include "pikacolorprofilestore-private.h"
/**
* SECTION: pikacolorprofilecombobox
* @title: PikaColorProfileComboBox
* @short_description: A combo box for selecting color profiles.
*
* A combo box for selecting color profiles.
**/
enum
{
PROP_0,
PROP_DIALOG,
PROP_MODEL
};
struct _PikaColorProfileComboBoxPrivate
{
GtkWidget *dialog;
GtkTreePath *last_path;
};
#define GET_PRIVATE(obj) (((PikaColorProfileComboBox *) (obj))->priv)
static void pika_color_profile_combo_box_finalize (GObject *object);
static void pika_color_profile_combo_box_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_color_profile_combo_box_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_color_profile_combo_box_changed (GtkComboBox *combo);
static gboolean pika_color_profile_row_separator_func (GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data);
static void pika_color_profile_combo_dialog_response (PikaColorProfileChooserDialog *dialog,
gint response,
PikaColorProfileComboBox *combo);
G_DEFINE_TYPE_WITH_PRIVATE (PikaColorProfileComboBox,
pika_color_profile_combo_box, GTK_TYPE_COMBO_BOX)
#define parent_class pika_color_profile_combo_box_parent_class
static void
pika_color_profile_combo_box_class_init (PikaColorProfileComboBoxClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkComboBoxClass *combo_class = GTK_COMBO_BOX_CLASS (klass);
object_class->set_property = pika_color_profile_combo_box_set_property;
object_class->get_property = pika_color_profile_combo_box_get_property;
object_class->finalize = pika_color_profile_combo_box_finalize;
combo_class->changed = pika_color_profile_combo_box_changed;
/**
* PikaColorProfileComboBox:dialog:
*
* #GtkDialog to present when the user selects the
* "Select color profile from disk..." item.
*
* Since: 2.4
*/
g_object_class_install_property (object_class,
PROP_DIALOG,
g_param_spec_object ("dialog",
"Dialog",
"The dialog to present when selecting profiles from disk",
GTK_TYPE_DIALOG,
G_PARAM_CONSTRUCT_ONLY |
PIKA_PARAM_READWRITE));
/**
* PikaColorProfileComboBox:model:
*
* Overrides the "model" property of the #GtkComboBox class.
* #PikaColorProfileComboBox requires the model to be a
* #PikaColorProfileStore.
*
* Since: 2.4
*/
g_object_class_install_property (object_class,
PROP_MODEL,
g_param_spec_object ("model",
"Model",
"The profile store used for this combo box",
PIKA_TYPE_COLOR_PROFILE_STORE,
PIKA_PARAM_READWRITE));
}
static void
pika_color_profile_combo_box_init (PikaColorProfileComboBox *combo_box)
{
GtkCellRenderer *cell;
combo_box->priv = pika_color_profile_combo_box_get_instance_private (combo_box);
cell = gtk_cell_renderer_text_new ();
g_object_set (cell,
"width-chars", 42,
"ellipsize", PANGO_ELLIPSIZE_END,
NULL);
gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo_box), cell, TRUE);
gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (combo_box), cell,
"text", PIKA_COLOR_PROFILE_STORE_LABEL,
NULL);
gtk_combo_box_set_row_separator_func (GTK_COMBO_BOX (combo_box),
pika_color_profile_row_separator_func,
NULL, NULL);
}
static void
pika_color_profile_combo_box_finalize (GObject *object)
{
PikaColorProfileComboBoxPrivate *private = GET_PRIVATE (object);
if (private->dialog)
{
if (PIKA_IS_COLOR_PROFILE_CHOOSER_DIALOG (private->dialog))
gtk_widget_destroy (private->dialog);
g_object_unref (private->dialog);
private->dialog = NULL;
}
g_clear_pointer (&private->last_path, gtk_tree_path_free);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_color_profile_combo_box_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaColorProfileComboBoxPrivate *private = GET_PRIVATE (object);
switch (property_id)
{
case PROP_DIALOG:
g_return_if_fail (private->dialog == NULL);
private->dialog = g_value_dup_object (value);
if (PIKA_IS_COLOR_PROFILE_CHOOSER_DIALOG (private->dialog))
g_signal_connect (private->dialog, "response",
G_CALLBACK (pika_color_profile_combo_dialog_response),
object);
break;
case PROP_MODEL:
gtk_combo_box_set_model (GTK_COMBO_BOX (object),
g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_color_profile_combo_box_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaColorProfileComboBoxPrivate *private = GET_PRIVATE (object);
switch (property_id)
{
case PROP_DIALOG:
g_value_set_object (value, private->dialog);
break;
case PROP_MODEL:
g_value_set_object (value,
gtk_combo_box_get_model (GTK_COMBO_BOX (object)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_color_profile_combo_box_changed (GtkComboBox *combo)
{
PikaColorProfileComboBoxPrivate *priv = GET_PRIVATE (combo);
GtkTreeModel *model = gtk_combo_box_get_model (combo);
GtkTreeIter iter;
gint type;
if (! gtk_combo_box_get_active_iter (combo, &iter))
return;
gtk_tree_model_get (model, &iter,
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE, &type,
-1);
switch (type)
{
case PIKA_COLOR_PROFILE_STORE_ITEM_DIALOG:
{
GtkWidget *parent = gtk_widget_get_toplevel (GTK_WIDGET (combo));
if (GTK_IS_WINDOW (parent))
gtk_window_set_transient_for (GTK_WINDOW (priv->dialog),
GTK_WINDOW (parent));
gtk_window_present (GTK_WINDOW (priv->dialog));
if (priv->last_path &&
gtk_tree_model_get_iter (model, &iter, priv->last_path))
{
gtk_combo_box_set_active_iter (combo, &iter);
}
}
break;
case PIKA_COLOR_PROFILE_STORE_ITEM_FILE:
if (priv->last_path)
gtk_tree_path_free (priv->last_path);
priv->last_path = gtk_tree_model_get_path (model, &iter);
_pika_color_profile_store_history_reorder (PIKA_COLOR_PROFILE_STORE (model),
&iter);
break;
default:
break;
}
}
/**
* pika_color_profile_combo_box_new:
* @dialog: a #GtkDialog to present when the user selects the
* "Select color profile from disk..." item
* @history: #GFile of the profilerc (or %NULL for no history)
*
* Create a combo-box widget for selecting color profiles. The combo-box
* is populated from the file specified as @history. This filename is
* typically created using the following code snippet:
* <informalexample><programlisting>
* gchar *history = pika_personal_rc_file ("profilerc");
* </programlisting></informalexample>
*
* The recommended @dialog type to use is a #PikaColorProfileChooserDialog.
* If a #PikaColorProfileChooserDialog is passed, #PikaColorProfileComboBox
* will take complete control over the dialog, which means connecting
* a GtkDialog::response() callback by itself, and take care of destroying
* the dialog when the combo box is destroyed.
*
* If another type of @dialog is passed, this has to be implemented
* separately.
*
* See also pika_color_profile_combo_box_new_with_model().
*
* Returns: a new #PikaColorProfileComboBox.
*
* Since: 2.4
**/
GtkWidget *
pika_color_profile_combo_box_new (GtkWidget *dialog,
GFile *history)
{
GtkWidget *combo;
GtkListStore *store;
g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
g_return_val_if_fail (history == NULL || G_IS_FILE (history), NULL);
store = pika_color_profile_store_new (history);
combo = pika_color_profile_combo_box_new_with_model (dialog,
GTK_TREE_MODEL (store));
g_object_unref (store);
return combo;
}
/**
* pika_color_profile_combo_box_new_with_model:
* @dialog: a #GtkDialog to present when the user selects the
* "Select color profile from disk..." item
* @model: a #PikaColorProfileStore object
*
* This constructor is useful when you want to create several
* combo-boxes for profile selection that all share the same
* #PikaColorProfileStore. This is for example done in the
* PIKA Preferences dialog.
*
* See also pika_color_profile_combo_box_new().
*
* Returns: a new #PikaColorProfileComboBox.
*
* Since: 2.4
**/
GtkWidget *
pika_color_profile_combo_box_new_with_model (GtkWidget *dialog,
GtkTreeModel *model)
{
g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
g_return_val_if_fail (PIKA_IS_COLOR_PROFILE_STORE (model), NULL);
return g_object_new (PIKA_TYPE_COLOR_PROFILE_COMBO_BOX,
"dialog", dialog,
"model", model,
NULL);
}
/**
* pika_color_profile_combo_box_add_file:
* @combo: a #PikaColorProfileComboBox
* @file: file of the profile to add (or %NULL)
* @label: label to use for the profile
* (may only be %NULL if @file is %NULL)
*
* This function delegates to the underlying
* #PikaColorProfileStore. Please refer to the documentation of
* pika_color_profile_store_add_file() for details.
*
* Since: 2.10
**/
void
pika_color_profile_combo_box_add_file (PikaColorProfileComboBox *combo,
GFile *file,
const gchar *label)
{
GtkTreeModel *model;
g_return_if_fail (PIKA_IS_COLOR_PROFILE_COMBO_BOX (combo));
g_return_if_fail (label != NULL || file == NULL);
g_return_if_fail (file == NULL || G_IS_FILE (file));
model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
pika_color_profile_store_add_file (PIKA_COLOR_PROFILE_STORE (model),
file, label);
}
/**
* pika_color_profile_combo_box_set_active_file:
* @combo: a #PikaColorProfileComboBox
* @file: file of the profile to select
* @label: label to use when adding a new entry (can be %NULL)
*
* Selects a color profile from the @combo and makes it the active
* item. If the profile is not listed in the @combo, then it is added
* with the given @label (or @file in case that @label is %NULL).
*
* Since: 2.10
**/
void
pika_color_profile_combo_box_set_active_file (PikaColorProfileComboBox *combo,
GFile *file,
const gchar *label)
{
PikaColorProfile *profile = NULL;
GtkTreeModel *model;
GtkTreeIter iter;
g_return_if_fail (PIKA_IS_COLOR_PROFILE_COMBO_BOX (combo));
g_return_if_fail (file == NULL || G_IS_FILE (file));
model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
if (file && ! (label && *label))
{
GError *error = NULL;
profile = pika_color_profile_new_from_file (file, &error);
if (! profile)
{
g_message ("%s", error->message);
g_clear_error (&error);
}
else
{
label = pika_color_profile_get_label (profile);
}
}
if (_pika_color_profile_store_history_add (PIKA_COLOR_PROFILE_STORE (model),
file, label, &iter))
{
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter);
}
if (profile)
g_object_unref (profile);
}
/**
* pika_color_profile_combo_box_set_active_profile:
* @combo: a #PikaColorProfileComboBox
* @profile: a #PikaColorProfile to set
*
* Selects a color profile from the @combo and makes it the active
* item.
*
* Since: 3.0
**/
void
pika_color_profile_combo_box_set_active_profile (PikaColorProfileComboBox *combo,
PikaColorProfile *profile)
{
GtkTreeModel *model;
GtkTreeIter iter;
g_return_if_fail (PIKA_IS_COLOR_PROFILE_COMBO_BOX (combo));
g_return_if_fail (profile == NULL || PIKA_IS_COLOR_PROFILE (profile));
model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
if (_pika_color_profile_store_history_find_profile (PIKA_COLOR_PROFILE_STORE (model),
profile, &iter))
{
gtk_combo_box_set_active_iter (GTK_COMBO_BOX (combo), &iter);
}
}
/**
* pika_color_profile_combo_box_get_active_file:
* @combo: a #PikaColorProfileComboBox
*
* Returns: (transfer none): The file of the currently selected
* color profile, release using g_object_unref() when it
* is not any longer needed.
*
* Since: 2.10
**/
GFile *
pika_color_profile_combo_box_get_active_file (PikaColorProfileComboBox *combo)
{
GtkTreeModel *model;
GtkTreeIter iter;
g_return_val_if_fail (PIKA_IS_COLOR_PROFILE_COMBO_BOX (combo), NULL);
model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter))
{
GFile *file;
gint type;
gtk_tree_model_get (model, &iter,
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE, &type,
PIKA_COLOR_PROFILE_STORE_FILE, &file,
-1);
if (type == PIKA_COLOR_PROFILE_STORE_ITEM_FILE)
return file;
if (file)
g_object_unref (file);
}
return NULL;
}
static gboolean
pika_color_profile_row_separator_func (GtkTreeModel *model,
GtkTreeIter *iter,
gpointer data)
{
gint type;
gtk_tree_model_get (model, iter,
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE, &type,
-1);
switch (type)
{
case PIKA_COLOR_PROFILE_STORE_ITEM_SEPARATOR_TOP:
case PIKA_COLOR_PROFILE_STORE_ITEM_SEPARATOR_BOTTOM:
return TRUE;
default:
return FALSE;
}
}
static void
pika_color_profile_combo_dialog_response (PikaColorProfileChooserDialog *dialog,
gint response,
PikaColorProfileComboBox *combo)
{
if (response == GTK_RESPONSE_ACCEPT)
{
GFile *file;
file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog));
if (file)
{
pika_color_profile_combo_box_set_active_file (combo, file, NULL);
g_object_unref (file);
}
}
gtk_widget_hide (GTK_WIDGET (dialog));
}

View File

@ -0,0 +1,87 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorprofilecombobox.h
* Copyright (C) 2007 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_PROFILE_COMBO_BOX_H__
#define __PIKA_COLOR_PROFILE_COMBO_BOX_H__
G_BEGIN_DECLS
#define PIKA_TYPE_COLOR_PROFILE_COMBO_BOX (pika_color_profile_combo_box_get_type ())
#define PIKA_COLOR_PROFILE_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_PROFILE_COMBO_BOX, PikaColorProfileComboBox))
#define PIKA_COLOR_PROFILE_COMBO_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_PROFILE_COMBO_BOX, PikaColorProfileComboBoxClass))
#define PIKA_IS_COLOR_PROFILE_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_PROFILE_COMBO_BOX))
#define PIKA_IS_COLOR_PROFILE_COMBO_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_PROFILE_COMBO_BOX))
#define PIKA_COLOR_PROFILE_COMBO_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_PROFILE_COMBO_BOX, PikaColorProfileComboBoxClass))
typedef struct _PikaColorProfileComboBoxPrivate PikaColorProfileComboBoxPrivate;
typedef struct _PikaColorProfileComboBoxClass PikaColorProfileComboBoxClass;
struct _PikaColorProfileComboBox
{
GtkComboBox parent_instance;
PikaColorProfileComboBoxPrivate *priv;
};
struct _PikaColorProfileComboBoxClass
{
GtkComboBoxClass parent_class;
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_color_profile_combo_box_get_type (void) G_GNUC_CONST;
GtkWidget * pika_color_profile_combo_box_new (GtkWidget *dialog,
GFile *history);
GtkWidget * pika_color_profile_combo_box_new_with_model (GtkWidget *dialog,
GtkTreeModel *model);
void pika_color_profile_combo_box_add_file (PikaColorProfileComboBox *combo,
GFile *file,
const gchar *label);
void pika_color_profile_combo_box_set_active_file (PikaColorProfileComboBox *combo,
GFile *file,
const gchar *label);
void pika_color_profile_combo_box_set_active_profile (PikaColorProfileComboBox *combo,
PikaColorProfile *profile);
GFile * pika_color_profile_combo_box_get_active_file (PikaColorProfileComboBox *combo);
G_END_DECLS
#endif /* __PIKA_COLOR_PROFILE_COMBO_BOX_H__ */

View File

@ -0,0 +1,57 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaprofilestore-private.h
* Copyright (C) 2007 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_COLOR_PROFILE_STORE_PRIVATE_H__
#define __PIKA_COLOR_PROFILE_STORE_PRIVATE_H__
typedef enum
{
PIKA_COLOR_PROFILE_STORE_ITEM_FILE,
PIKA_COLOR_PROFILE_STORE_ITEM_SEPARATOR_TOP,
PIKA_COLOR_PROFILE_STORE_ITEM_SEPARATOR_BOTTOM,
PIKA_COLOR_PROFILE_STORE_ITEM_DIALOG
} PikaColorProfileStoreItemType;
typedef enum
{
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE,
PIKA_COLOR_PROFILE_STORE_LABEL,
PIKA_COLOR_PROFILE_STORE_FILE,
PIKA_COLOR_PROFILE_STORE_INDEX
} PikaColorProfileStoreColumns;
G_GNUC_INTERNAL gboolean _pika_color_profile_store_history_add (PikaColorProfileStore *store,
GFile *file,
const gchar *label,
GtkTreeIter *iter);
G_GNUC_INTERNAL gboolean _pika_color_profile_store_history_find_profile
(PikaColorProfileStore *store,
PikaColorProfile *profile,
GtkTreeIter *iter);
G_GNUC_INTERNAL void _pika_color_profile_store_history_reorder (PikaColorProfileStore *store,
GtkTreeIter *iter);
#endif /* __PIKA_COLOR_PROFILE_STORE_PRIVATE_H__ */

View File

@ -0,0 +1,845 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaprofilestore.c
* Copyright (C) 2004-2008 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gtk/gtk.h>
#include <gegl.h>
#include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h"
#include "libpikaconfig/pikaconfig.h"
#include "pikawidgetstypes.h"
#include "pikacolorprofilestore.h"
#include "pikacolorprofilestore-private.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikacolorprofilestore
* @title: PikaColorProfileStore
* @short_description: A #GtkListStore subclass that keep color profiles.
*
* A #GtkListStore subclass that keep color profiles.
**/
#define HISTORY_SIZE 8
enum
{
PROP_0,
PROP_HISTORY
};
struct _PikaColorProfileStorePrivate
{
GFile *history;
};
#define GET_PRIVATE(obj) (((PikaColorProfileStore *) (obj))->priv)
static void pika_color_profile_store_constructed (GObject *object);
static void pika_color_profile_store_dispose (GObject *object);
static void pika_color_profile_store_finalize (GObject *object);
static void pika_color_profile_store_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_color_profile_store_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static gboolean pika_color_profile_store_history_insert (PikaColorProfileStore *store,
GtkTreeIter *iter,
GFile *file,
const gchar *label,
gint index);
static void pika_color_profile_store_get_separator (PikaColorProfileStore *store,
GtkTreeIter *iter,
gboolean top);
static gboolean pika_color_profile_store_save (PikaColorProfileStore *store,
GFile *file,
GError **error);
static gboolean pika_color_profile_store_load (PikaColorProfileStore *store,
GFile *file,
GError **error);
G_DEFINE_TYPE_WITH_PRIVATE (PikaColorProfileStore, pika_color_profile_store,
GTK_TYPE_LIST_STORE)
#define parent_class pika_color_profile_store_parent_class
static void
pika_color_profile_store_class_init (PikaColorProfileStoreClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = pika_color_profile_store_constructed;
object_class->dispose = pika_color_profile_store_dispose;
object_class->finalize = pika_color_profile_store_finalize;
object_class->set_property = pika_color_profile_store_set_property;
object_class->get_property = pika_color_profile_store_get_property;
/**
* PikaColorProfileStore:history:
*
* #GFile of the color history used to populate the profile store.
*
* Since: 2.4
*/
g_object_class_install_property (object_class,
PROP_HISTORY,
g_param_spec_object ("history",
"History",
"Filen of the color history used to populate the profile store",
G_TYPE_FILE,
G_PARAM_CONSTRUCT_ONLY |
PIKA_PARAM_READWRITE));
}
static void
pika_color_profile_store_init (PikaColorProfileStore *store)
{
GType types[] =
{
G_TYPE_INT, /* PIKA_COLOR_PROFILE_STORE_ITEM_TYPE */
G_TYPE_STRING, /* PIKA_COLOR_PROFILE_STORE_LABEL */
G_TYPE_FILE, /* PIKA_COLOR_PROFILE_STORE_FILE */
G_TYPE_INT /* PIKA_COLOR_PROFILE_STORE_INDEX */
};
store->priv = pika_color_profile_store_get_instance_private (store);
gtk_list_store_set_column_types (GTK_LIST_STORE (store),
G_N_ELEMENTS (types), types);
}
static void
pika_color_profile_store_constructed (GObject *object)
{
PikaColorProfileStore *store = PIKA_COLOR_PROFILE_STORE (object);
PikaColorProfileStorePrivate *private = GET_PRIVATE (store);
GtkTreeIter iter;
G_OBJECT_CLASS (parent_class)->constructed (object);
gtk_list_store_append (GTK_LIST_STORE (store), &iter);
gtk_list_store_set (GTK_LIST_STORE (store), &iter,
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE,
PIKA_COLOR_PROFILE_STORE_ITEM_DIALOG,
PIKA_COLOR_PROFILE_STORE_LABEL,
_("Select color profile from disk..."),
-1);
if (private->history)
pika_color_profile_store_load (store, private->history, NULL);
}
static void
pika_color_profile_store_dispose (GObject *object)
{
PikaColorProfileStore *store = PIKA_COLOR_PROFILE_STORE (object);
PikaColorProfileStorePrivate *private = GET_PRIVATE (store);
if (private->history)
pika_color_profile_store_save (store, private->history, NULL);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
pika_color_profile_store_finalize (GObject *object)
{
PikaColorProfileStorePrivate *private = GET_PRIVATE (object);
g_clear_object (&private->history);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_color_profile_store_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaColorProfileStorePrivate *private = GET_PRIVATE (object);
switch (property_id)
{
case PROP_HISTORY:
g_return_if_fail (private->history == NULL);
private->history = g_value_dup_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_color_profile_store_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaColorProfileStorePrivate *private = GET_PRIVATE (object);
switch (property_id)
{
case PROP_HISTORY:
g_value_set_object (value, private->history);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/**
* pika_color_profile_store_new:
* @history: #GFile of the profilerc (or %NULL for no history)
*
* Creates a new #PikaColorProfileStore object and populates it with
* last used profiles read from the file @history. The updated history
* is written back to disk when the store is disposed.
*
* The #GFile passed as @history is typically created using the
* following code snippet:
* <informalexample><programlisting>
* gchar *history = pika_personal_rc_file ("profilerc");
* </programlisting></informalexample>
*
* Returns: a new #PikaColorProfileStore
*
* Since: 2.4
**/
GtkListStore *
pika_color_profile_store_new (GFile *history)
{
g_return_val_if_fail (history == NULL || G_IS_FILE (history), NULL);
return g_object_new (PIKA_TYPE_COLOR_PROFILE_STORE,
"history", history,
NULL);
}
/**
* pika_color_profile_store_add_file:
* @store: a #PikaColorProfileStore
* @file: #GFile of the profile to add (or %NULL)
* @label: label to use for the profile
* (may only be %NULL if @file is %NULL)
*
* Adds a color profile item to the #PikaColorProfileStore. Items
* added with this function will be kept at the top, separated from
* the history of last used color profiles.
*
* This function is often used to add a selectable item for the %NULL
* file. If you pass %NULL for both @file and @label, the @label will
* be set to the string "None" for you (and translated for the user).
*
* Since: 2.10
**/
void
pika_color_profile_store_add_file (PikaColorProfileStore *store,
GFile *file,
const gchar *label)
{
GtkTreeIter separator;
GtkTreeIter iter;
g_return_if_fail (PIKA_IS_COLOR_PROFILE_STORE (store));
g_return_if_fail (label != NULL || file == NULL);
g_return_if_fail (file == NULL || G_IS_FILE (file));
if (! file && ! label)
label = C_("profile", "None");
pika_color_profile_store_get_separator (store, &separator, TRUE);
gtk_list_store_insert_before (GTK_LIST_STORE (store), &iter, &separator);
gtk_list_store_set (GTK_LIST_STORE (store), &iter,
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE,
PIKA_COLOR_PROFILE_STORE_ITEM_FILE,
PIKA_COLOR_PROFILE_STORE_FILE, file,
PIKA_COLOR_PROFILE_STORE_LABEL, label,
PIKA_COLOR_PROFILE_STORE_INDEX, -1,
-1);
}
/**
* _pika_color_profile_store_history_add:
* @store: a #PikaColorProfileStore
* @file: file of the profile to add (or %NULL)
* @label: label to use for the profile (or %NULL)
* @iter: a #GtkTreeIter
*
* Returns: %TRUE if the iter is valid and pointing to the item
*
* Since: 2.4
**/
gboolean
_pika_color_profile_store_history_add (PikaColorProfileStore *store,
GFile *file,
const gchar *label,
GtkTreeIter *iter)
{
GtkTreeModel *model;
gboolean iter_valid;
gint max = -1;
g_return_val_if_fail (PIKA_IS_COLOR_PROFILE_STORE (store), FALSE);
g_return_val_if_fail (iter != NULL, FALSE);
model = GTK_TREE_MODEL (store);
for (iter_valid = gtk_tree_model_get_iter_first (model, iter);
iter_valid;
iter_valid = gtk_tree_model_iter_next (model, iter))
{
gint type;
gint index;
GFile *this;
gtk_tree_model_get (model, iter,
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE, &type,
PIKA_COLOR_PROFILE_STORE_INDEX, &index,
-1);
if (type != PIKA_COLOR_PROFILE_STORE_ITEM_FILE)
continue;
if (index > max)
max = index;
/* check if we found a filename match */
gtk_tree_model_get (model, iter,
PIKA_COLOR_PROFILE_STORE_FILE, &this,
-1);
if ((this && file && g_file_equal (this, file)) ||
(! this && ! file))
{
/* update the label */
if (label && *label)
gtk_list_store_set (GTK_LIST_STORE (store), iter,
PIKA_COLOR_PROFILE_STORE_LABEL, label,
-1);
if (this)
g_object_unref (this);
return TRUE;
}
if (this)
g_object_unref (this);
}
if (! file)
return FALSE;
if (label && *label)
{
iter_valid = pika_color_profile_store_history_insert (store, iter,
file, label,
++max);
}
else
{
const gchar *utf8 = pika_file_get_utf8_name (file);
gchar *basename = g_path_get_basename (utf8);
iter_valid = pika_color_profile_store_history_insert (store, iter,
file, basename,
++max);
g_free (basename);
}
return iter_valid;
}
/**
* _pika_color_profile_store_history_find_profile:
* @store: a #PikaColorProfileStore
* @profile: a #PikaColorProfile to find (or %NULL)
* @iter: a #GtkTreeIter
*
* Returns: %TRUE if the iter is valid and pointing to the item
*
* Since: 3.0
**/
gboolean
_pika_color_profile_store_history_find_profile (PikaColorProfileStore *store,
PikaColorProfile *profile,
GtkTreeIter *iter)
{
GtkTreeModel *model;
gboolean iter_valid;
gint max = -1;
g_return_val_if_fail (PIKA_IS_COLOR_PROFILE_STORE (store), FALSE);
g_return_val_if_fail (iter != NULL, FALSE);
model = GTK_TREE_MODEL (store);
for (iter_valid = gtk_tree_model_get_iter_first (model, iter);
iter_valid;
iter_valid = gtk_tree_model_iter_next (model, iter))
{
gint type;
gint index;
GFile *file;
PikaColorProfile *combo_profile = NULL;
gtk_tree_model_get (model, iter,
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE, &type,
PIKA_COLOR_PROFILE_STORE_INDEX, &index,
-1);
if (type != PIKA_COLOR_PROFILE_STORE_ITEM_FILE)
continue;
if (index > max)
max = index;
/* check if we found a filename match */
gtk_tree_model_get (model, iter,
PIKA_COLOR_PROFILE_STORE_FILE, &file,
-1);
/* Convert file to PikaColorProfile */
if (file)
combo_profile = pika_color_profile_new_from_file (file, NULL);
if ((combo_profile && profile &&
pika_color_profile_is_equal (profile, combo_profile)) ||
(! file && ! profile))
{
if (file)
g_object_unref (file);
if (combo_profile)
g_object_unref (combo_profile);
return TRUE;
}
if (file)
g_object_unref (file);
if (combo_profile)
g_object_unref (combo_profile);
}
if (! profile)
return FALSE;
return iter_valid;
}
/**
* _pika_color_profile_store_history_reorder
* @store: a #PikaColorProfileStore
* @iter: a #GtkTreeIter
*
* Moves the entry pointed to by @iter to the front of the MRU list.
*
* Since: 2.4
**/
void
_pika_color_profile_store_history_reorder (PikaColorProfileStore *store,
GtkTreeIter *iter)
{
GtkTreeModel *model;
gint index;
gboolean iter_valid;
g_return_if_fail (PIKA_IS_COLOR_PROFILE_STORE (store));
g_return_if_fail (iter != NULL);
model = GTK_TREE_MODEL (store);
gtk_tree_model_get (model, iter,
PIKA_COLOR_PROFILE_STORE_INDEX, &index,
-1);
if (index == 0)
return; /* already at the top */
for (iter_valid = gtk_tree_model_get_iter_first (model, iter);
iter_valid;
iter_valid = gtk_tree_model_iter_next (model, iter))
{
gint type;
gint this_index;
gtk_tree_model_get (model, iter,
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE, &type,
PIKA_COLOR_PROFILE_STORE_INDEX, &this_index,
-1);
if (type == PIKA_COLOR_PROFILE_STORE_ITEM_FILE && this_index > -1)
{
if (this_index < index)
{
this_index++;
}
else if (this_index == index)
{
this_index = 0;
}
gtk_list_store_set (GTK_LIST_STORE (store), iter,
PIKA_COLOR_PROFILE_STORE_INDEX, this_index,
-1);
}
}
}
static gboolean
pika_color_profile_store_history_insert (PikaColorProfileStore *store,
GtkTreeIter *iter,
GFile *file,
const gchar *label,
gint index)
{
GtkTreeModel *model = GTK_TREE_MODEL (store);
GtkTreeIter sibling;
gboolean iter_valid;
g_return_val_if_fail (G_IS_FILE (file), FALSE);
g_return_val_if_fail (label != NULL, FALSE);
g_return_val_if_fail (index > -1, FALSE);
pika_color_profile_store_get_separator (store, iter, FALSE);
for (iter_valid = gtk_tree_model_get_iter_first (model, &sibling);
iter_valid;
iter_valid = gtk_tree_model_iter_next (model, &sibling))
{
gint type;
gint this_index;
gtk_tree_model_get (model, &sibling,
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE, &type,
PIKA_COLOR_PROFILE_STORE_INDEX, &this_index,
-1);
if (type == PIKA_COLOR_PROFILE_STORE_ITEM_SEPARATOR_BOTTOM)
{
gtk_list_store_insert_before (GTK_LIST_STORE (store),
iter, &sibling);
break;
}
if (type == PIKA_COLOR_PROFILE_STORE_ITEM_FILE && this_index > -1)
{
gchar *this_label;
gtk_tree_model_get (model, &sibling,
PIKA_COLOR_PROFILE_STORE_LABEL, &this_label,
-1);
if (this_label && g_utf8_collate (label, this_label) < 0)
{
gtk_list_store_insert_before (GTK_LIST_STORE (store),
iter, &sibling);
g_free (this_label);
break;
}
g_free (this_label);
}
}
if (iter_valid)
gtk_list_store_set (GTK_LIST_STORE (store), iter,
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE,
PIKA_COLOR_PROFILE_STORE_ITEM_FILE,
PIKA_COLOR_PROFILE_STORE_FILE, file,
PIKA_COLOR_PROFILE_STORE_LABEL, label,
PIKA_COLOR_PROFILE_STORE_INDEX, index,
-1);
return iter_valid;
}
static void
pika_color_profile_store_create_separator (PikaColorProfileStore *store,
GtkTreeIter *iter,
gboolean top)
{
if (top)
{
gtk_list_store_prepend (GTK_LIST_STORE (store), iter);
}
else
{
GtkTreeModel *model = GTK_TREE_MODEL (store);
GtkTreeIter sibling;
gboolean iter_valid;
for (iter_valid = gtk_tree_model_get_iter_first (model, &sibling);
iter_valid;
iter_valid = gtk_tree_model_iter_next (model, &sibling))
{
gint type;
gtk_tree_model_get (model, &sibling,
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE, &type,
-1);
if (type == PIKA_COLOR_PROFILE_STORE_ITEM_DIALOG)
break;
}
if (iter_valid)
gtk_list_store_insert_before (GTK_LIST_STORE (store), iter, &sibling);
}
gtk_list_store_set (GTK_LIST_STORE (store), iter,
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE,
top ?
PIKA_COLOR_PROFILE_STORE_ITEM_SEPARATOR_TOP :
PIKA_COLOR_PROFILE_STORE_ITEM_SEPARATOR_BOTTOM,
PIKA_COLOR_PROFILE_STORE_INDEX, -1,
-1);
}
static void
pika_color_profile_store_get_separator (PikaColorProfileStore *store,
GtkTreeIter *iter,
gboolean top)
{
GtkTreeModel *model = GTK_TREE_MODEL (store);
gboolean iter_valid;
gint needle;
needle = (top ?
PIKA_COLOR_PROFILE_STORE_ITEM_SEPARATOR_TOP :
PIKA_COLOR_PROFILE_STORE_ITEM_SEPARATOR_BOTTOM);
for (iter_valid = gtk_tree_model_get_iter_first (model, iter);
iter_valid;
iter_valid = gtk_tree_model_iter_next (model, iter))
{
gint type;
gtk_tree_model_get (model, iter,
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE, &type,
-1);
if (type == needle)
return;
}
pika_color_profile_store_create_separator (store, iter, top);
}
static GTokenType
pika_color_profile_store_load_profile (PikaColorProfileStore *store,
GScanner *scanner,
gint index)
{
GtkTreeIter iter;
gchar *label = NULL;
gchar *path = NULL;
if (pika_scanner_parse_string (scanner, &label) &&
pika_scanner_parse_string (scanner, &path))
{
GFile *file = NULL;
if (g_str_has_prefix (path, "file://"))
{
file = g_file_new_for_uri (path);
}
else
{
file = pika_file_new_for_config_path (path, NULL);
}
if (file)
{
if (g_file_query_file_type (file, 0, NULL) == G_FILE_TYPE_REGULAR)
{
pika_color_profile_store_history_insert (store, &iter,
file, label, index);
}
g_object_unref (file);
}
g_free (label);
g_free (path);
return G_TOKEN_RIGHT_PAREN;
}
g_free (label);
g_free (path);
return G_TOKEN_STRING;
}
static gboolean
pika_color_profile_store_load (PikaColorProfileStore *store,
GFile *file,
GError **error)
{
GScanner *scanner;
GTokenType token;
gint i = 0;
scanner = pika_scanner_new_file (file, error);
if (! scanner)
return FALSE;
g_scanner_scope_add_symbol (scanner, 0, "color-profile", NULL);
token = G_TOKEN_LEFT_PAREN;
while (g_scanner_peek_next_token (scanner) == token)
{
token = g_scanner_get_next_token (scanner);
switch (token)
{
case G_TOKEN_LEFT_PAREN:
token = G_TOKEN_SYMBOL;
break;
case G_TOKEN_SYMBOL:
token = pika_color_profile_store_load_profile (store, scanner, i++);
break;
case G_TOKEN_RIGHT_PAREN:
token = G_TOKEN_LEFT_PAREN;
break;
default: /* do nothing */
break;
}
}
if (token != G_TOKEN_LEFT_PAREN)
{
g_scanner_get_next_token (scanner);
g_scanner_unexp_token (scanner, token, NULL, NULL, NULL,
_("fatal parse error"), TRUE);
}
pika_scanner_unref (scanner);
return TRUE;
}
static gboolean
pika_color_profile_store_save (PikaColorProfileStore *store,
GFile *file,
GError **error)
{
PikaConfigWriter *writer;
GtkTreeModel *model;
GtkTreeIter iter;
gchar *labels[HISTORY_SIZE] = { NULL, };
GFile *files[HISTORY_SIZE] = { NULL, };
gboolean iter_valid;
gint i;
writer = pika_config_writer_new_from_file (file,
TRUE,
"PIKA color profile history",
error);
if (! writer)
return FALSE;
model = GTK_TREE_MODEL (store);
for (iter_valid = gtk_tree_model_get_iter_first (model, &iter);
iter_valid;
iter_valid = gtk_tree_model_iter_next (model, &iter))
{
gint type;
gint index;
gtk_tree_model_get (model, &iter,
PIKA_COLOR_PROFILE_STORE_ITEM_TYPE, &type,
PIKA_COLOR_PROFILE_STORE_INDEX, &index,
-1);
if (type == PIKA_COLOR_PROFILE_STORE_ITEM_FILE &&
index >= 0 &&
index < HISTORY_SIZE)
{
if (labels[index] || files[index])
g_warning ("%s: double index %d", G_STRFUNC, index);
gtk_tree_model_get (model, &iter,
PIKA_COLOR_PROFILE_STORE_LABEL,
&labels[index],
PIKA_COLOR_PROFILE_STORE_FILE,
&files[index],
-1);
}
}
for (i = 0; i < HISTORY_SIZE; i++)
{
if (files[i] && labels[i])
{
gchar *path = pika_file_get_config_path (files[i], NULL);
if (path)
{
pika_config_writer_open (writer, "color-profile");
pika_config_writer_string (writer, labels[i]);
pika_config_writer_string (writer, path);
pika_config_writer_close (writer);
g_free (path);
}
}
if (files[i])
g_object_unref (files[i]);
g_free (labels[i]);
}
return pika_config_writer_finish (writer,
"end of color profile history", error);
}

View File

@ -0,0 +1,76 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaprofilestore.h
* Copyright (C) 2007 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_PROFILE_STORE_H__
#define __PIKA_COLOR_PROFILE_STORE_H__
G_BEGIN_DECLS
#define PIKA_TYPE_COLOR_PROFILE_STORE (pika_color_profile_store_get_type ())
#define PIKA_COLOR_PROFILE_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_PROFILE_STORE, PikaColorProfileStore))
#define PIKA_COLOR_PROFILE_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_PROFILE_STORE, PikaColorProfileStoreClass))
#define PIKA_IS_COLOR_PROFILE_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_PROFILE_STORE))
#define PIKA_IS_COLOR_PROFILE_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_PROFILE_STORE))
#define PIKA_COLOR_PROFILE_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_PROFILE_STORE, PikaColorProfileStoreClass))
typedef struct _PikaColorProfileStorePrivate PikaColorProfileStorePrivate;
typedef struct _PikaColorProfileStoreClass PikaColorProfileStoreClass;
struct _PikaColorProfileStore
{
GtkListStore parent_instance;
PikaColorProfileStorePrivate *priv;
};
struct _PikaColorProfileStoreClass
{
GtkListStoreClass parent_class;
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_color_profile_store_get_type (void) G_GNUC_CONST;
GtkListStore * pika_color_profile_store_new (GFile *history);
void pika_color_profile_store_add_file (PikaColorProfileStore *store,
GFile *file,
const gchar *label);
G_END_DECLS
#endif /* __PIKA_COLOR_PROFILE_STORE_H__ */

View File

@ -0,0 +1,213 @@
/* 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
*
* PikaColorProfileView
* Copyright (C) 2014 Michael Natterer <mitch@gimp.org>
*
* 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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikacolor/pikacolor.h"
#include "pikawidgetstypes.h"
#include "pikacolorprofileview.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikacolorprofileview
* @title: PikaColorProfileView
* @short_description: A widget for viewing color profile properties
*
* A widget for viewing the properties of a #PikaColorProfile.
**/
struct _PikaColorProfileViewPrivate
{
PikaColorProfile *profile;
};
static void pika_color_profile_view_constructed (GObject *object);
static void pika_color_profile_view_finalize (GObject *object);
G_DEFINE_TYPE_WITH_PRIVATE (PikaColorProfileView, pika_color_profile_view,
GTK_TYPE_TEXT_VIEW)
#define parent_class pika_color_profile_view_parent_class
static void
pika_color_profile_view_class_init (PikaColorProfileViewClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = pika_color_profile_view_constructed;
object_class->finalize = pika_color_profile_view_finalize;
}
static void
pika_color_profile_view_init (PikaColorProfileView *view)
{
view->priv = pika_color_profile_view_get_instance_private (view);
}
static void
pika_color_profile_view_constructed (GObject *object)
{
GtkTextBuffer *buffer;
G_OBJECT_CLASS (parent_class)->constructed (object);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (object));
gtk_text_buffer_create_tag (buffer, "text",
NULL);
gtk_text_buffer_create_tag (buffer, "title",
"weight", PANGO_WEIGHT_BOLD,
"scale", PANGO_SCALE_LARGE,
NULL);
gtk_text_buffer_create_tag (buffer, "header",
"weight", PANGO_WEIGHT_BOLD,
NULL);
gtk_text_buffer_create_tag (buffer, "error",
"style", PANGO_STYLE_OBLIQUE,
NULL);
gtk_text_view_set_editable (GTK_TEXT_VIEW (object), FALSE);
gtk_text_view_set_wrap_mode (GTK_TEXT_VIEW (object), GTK_WRAP_WORD);
gtk_text_view_set_pixels_above_lines (GTK_TEXT_VIEW (object), 6);
gtk_text_view_set_left_margin (GTK_TEXT_VIEW (object), 6);
gtk_text_view_set_right_margin (GTK_TEXT_VIEW (object), 6);
}
static void
pika_color_profile_view_finalize (GObject *object)
{
PikaColorProfileView *view = PIKA_COLOR_PROFILE_VIEW (object);
g_clear_object (&view->priv->profile);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
GtkWidget *
pika_color_profile_view_new (void)
{
return g_object_new (PIKA_TYPE_COLOR_PROFILE_VIEW, NULL);
}
void
pika_color_profile_view_set_profile (PikaColorProfileView *view,
PikaColorProfile *profile)
{
GtkTextBuffer *buffer;
g_return_if_fail (PIKA_IS_COLOR_PROFILE_VIEW (view));
g_return_if_fail (profile == NULL || PIKA_IS_COLOR_PROFILE (profile));
if (profile == view->priv->profile)
return;
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
gtk_text_buffer_set_text (buffer, "", 0);
if (g_set_object (&view->priv->profile, profile) && profile)
{
GtkTextIter iter;
const gchar *text;
gtk_text_buffer_get_start_iter (buffer, &iter);
text = pika_color_profile_get_label (profile);
if (text && strlen (text))
{
gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
text, -1,
"title", NULL);
gtk_text_buffer_insert (buffer, &iter, "\n", 1);
}
text = pika_color_profile_get_model (profile);
if (text && strlen (text))
{
gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
text, -1,
"text", NULL);
gtk_text_buffer_insert (buffer, &iter, "\n", 1);
}
text = pika_color_profile_get_manufacturer (profile);
if (text && strlen (text))
{
gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
_("Manufacturer: "), -1,
"header", NULL);
gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
text, -1,
"text", NULL);
gtk_text_buffer_insert (buffer, &iter, "\n", 1);
}
text = pika_color_profile_get_copyright (profile);
if (text && strlen (text))
{
gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
_("Copyright: "), -1,
"header", NULL);
gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
text, -1,
"text", NULL);
gtk_text_buffer_insert (buffer, &iter, "\n", 1);
}
}
}
void
pika_color_profile_view_set_error (PikaColorProfileView *view,
const gchar *message)
{
GtkTextBuffer *buffer;
GtkTextIter iter;
g_return_if_fail (PIKA_IS_COLOR_PROFILE_VIEW (view));
g_return_if_fail (message != NULL);
buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (view));
gtk_text_buffer_set_text (buffer, "", 0);
gtk_text_buffer_get_start_iter (buffer, &iter);
gtk_text_buffer_insert_with_tags_by_name (buffer, &iter,
message, -1,
"error", NULL);
}

View File

@ -0,0 +1,76 @@
/* 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
*
* PikaColorProfileView
* Copyright (C) 2014 Michael Natterer <mitch@gimp.org>
*
* 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 <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_COLOR_PROFILE_VIEW_H__
#define __PIKA_COLOR_PROFILE_VIEW_H__
G_BEGIN_DECLS
#define PIKA_TYPE_COLOR_PROFILE_VIEW (pika_color_profile_view_get_type ())
#define PIKA_COLOR_PROFILE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_PROFILE_VIEW, PikaColorProfileView))
#define PIKA_COLOR_PROFILE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_PROFILE_VIEW, PikaColorProfileViewClass))
#define PIKA_IS_COLOR_PROFILE_VIEW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_PROFILE_VIEW))
#define PIKA_IS_COLOR_PROFILE_VIEW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_PROFILE_VIEW))
#define PIKA_COLOR_PROFILE_VIEW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_PROFILE_VIEW, PikaColorProfileViewClass))
typedef struct _PikaColorProfileViewClass PikaColorProfileViewClass;
typedef struct _PikaColorProfileViewPrivate PikaColorProfileViewPrivate;
struct _PikaColorProfileView
{
GtkTextView parent_instance;
PikaColorProfileViewPrivate *priv;
};
struct _PikaColorProfileViewClass
{
GtkTextViewClass parent_class;
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_color_profile_view_get_type (void) G_GNUC_CONST;
GtkWidget * pika_color_profile_view_new (void);
void pika_color_profile_view_set_profile (PikaColorProfileView *view,
PikaColorProfile *profile);
void pika_color_profile_view_set_error (PikaColorProfileView *view,
const gchar *message);
G_END_DECLS
#endif /* __PIKA_COLOR_PROFILE_VIEW_H__ */

View File

@ -0,0 +1,982 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorscale.c
* Copyright (C) 2002-2010 Sven Neumann <sven@gimp.org>
* Michael Natterer <mitch@gimp.org>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikaconfig/pikaconfig.h"
#include "libpikacolor/pikacolor.h"
#include "pikawidgetstypes.h"
#include "pikacairo-utils.h"
#include "pikacolorscale.h"
#include "pikawidgetsutils.h"
/**
* SECTION: pikacolorscale
* @title: PikaColorScale
* @short_description: Fancy colored sliders.
*
* Fancy colored sliders.
**/
enum
{
PROP_0,
PROP_CHANNEL
};
typedef struct _PikaLCH PikaLCH;
struct _PikaLCH
{
gdouble l, c, h, a;
};
struct _PikaColorScalePrivate
{
PikaColorConfig *config;
PikaColorTransform *transform;
guchar oog_color[3];
PikaColorSelectorChannel channel;
PikaRGB rgb;
PikaHSV hsv;
guchar *buf;
guint width;
guint height;
guint rowstride;
gboolean needs_render;
};
#define GET_PRIVATE(obj) (((PikaColorScale *) (obj))->priv)
static void pika_color_scale_dispose (GObject *object);
static void pika_color_scale_finalize (GObject *object);
static void pika_color_scale_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_color_scale_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_color_scale_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static gboolean pika_color_scale_draw (GtkWidget *widget,
cairo_t *cr);
static void pika_color_scale_render (PikaColorScale *scale);
static void pika_color_scale_render_alpha (PikaColorScale *scale);
static void pika_color_scale_create_transform (PikaColorScale *scale);
static void pika_color_scale_destroy_transform (PikaColorScale *scale);
static void pika_color_scale_notify_config (PikaColorConfig *config,
const GParamSpec *pspec,
PikaColorScale *scale);
G_DEFINE_TYPE_WITH_PRIVATE (PikaColorScale, pika_color_scale, GTK_TYPE_SCALE)
#define parent_class pika_color_scale_parent_class
static const Babl *fish_rgb_to_lch = NULL;
static const Babl *fish_lch_to_rgb = NULL;
static void
pika_color_scale_class_init (PikaColorScaleClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
object_class->dispose = pika_color_scale_dispose;
object_class->finalize = pika_color_scale_finalize;
object_class->get_property = pika_color_scale_get_property;
object_class->set_property = pika_color_scale_set_property;
widget_class->size_allocate = pika_color_scale_size_allocate;
widget_class->draw = pika_color_scale_draw;
/**
* PikaColorScale:channel:
*
* The channel which is edited by the color scale.
*
* Since: 2.8
*/
g_object_class_install_property (object_class, PROP_CHANNEL,
g_param_spec_enum ("channel",
"Channel",
"The channel which is edited by the color scale",
PIKA_TYPE_COLOR_SELECTOR_CHANNEL,
PIKA_COLOR_SELECTOR_VALUE,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
gtk_widget_class_set_css_name (widget_class, "PikaColorScale");
fish_rgb_to_lch = babl_fish (babl_format ("R'G'B'A double"),
babl_format ("CIE LCH(ab) double"));
fish_lch_to_rgb = babl_fish (babl_format ("CIE LCH(ab) double"),
babl_format ("R'G'B' double"));
}
static void
pika_color_scale_init (PikaColorScale *scale)
{
PikaColorScalePrivate *priv;
GtkRange *range = GTK_RANGE (scale);
GtkCssProvider *css;
scale->priv = pika_color_scale_get_instance_private (scale);
priv = scale->priv;
gtk_widget_set_can_focus (GTK_WIDGET (scale), TRUE);
gtk_range_set_slider_size_fixed (range, TRUE);
gtk_range_set_flippable (GTK_RANGE (scale), TRUE);
gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
priv->channel = PIKA_COLOR_SELECTOR_VALUE;
priv->needs_render = TRUE;
gtk_orientable_set_orientation (GTK_ORIENTABLE (range),
GTK_ORIENTATION_HORIZONTAL);
pika_rgba_set (&priv->rgb, 0.0, 0.0, 0.0, 1.0);
pika_rgb_to_hsv (&priv->rgb, &priv->hsv);
pika_widget_track_monitor (GTK_WIDGET (scale),
G_CALLBACK (pika_color_scale_destroy_transform),
NULL, NULL);
css = gtk_css_provider_new ();
gtk_css_provider_load_from_data (css,
"PikaColorScale {"
" padding: 2px 12px 2px 12px;"
" min-width: 24px;"
" min-height: 24px;"
"}\n"
"PikaColorScale contents trough {"
" min-width: 20px;"
" min-height: 20px;"
"}\n"
"PikaColorScale contents trough slider {"
" min-width: 12px;"
" min-height: 12px;"
" margin: -6px -6px -6px -6px;"
"}",
-1, NULL);
gtk_style_context_add_provider (gtk_widget_get_style_context (GTK_WIDGET (scale)),
GTK_STYLE_PROVIDER (css),
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
g_object_unref (css);
}
static void
pika_color_scale_dispose (GObject *object)
{
PikaColorScale *scale = PIKA_COLOR_SCALE (object);
pika_color_scale_set_color_config (scale, NULL);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
pika_color_scale_finalize (GObject *object)
{
PikaColorScalePrivate *priv = GET_PRIVATE (object);
g_clear_pointer (&priv->buf, g_free);
priv->width = 0;
priv->height = 0;
priv->rowstride = 0;
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_color_scale_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaColorScalePrivate *priv = GET_PRIVATE (object);
switch (property_id)
{
case PROP_CHANNEL:
g_value_set_enum (value, priv->channel);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_color_scale_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaColorScale *scale = PIKA_COLOR_SCALE (object);
switch (property_id)
{
case PROP_CHANNEL:
pika_color_scale_set_channel (scale, g_value_get_enum (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_color_scale_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
PikaColorScalePrivate *priv = GET_PRIVATE (widget);
GtkRange *range = GTK_RANGE (widget);
GdkRectangle range_rect;
GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
gtk_range_get_range_rect (range, &range_rect);
if (range_rect.width != priv->width ||
range_rect.height != priv->height)
{
priv->width = range_rect.width;
priv->height = range_rect.height;
priv->rowstride = priv->width * 4;
g_free (priv->buf);
priv->buf = g_new (guchar, priv->rowstride * priv->height);
priv->needs_render = TRUE;
}
}
static gboolean
pika_color_scale_draw (GtkWidget *widget,
cairo_t *cr)
{
PikaColorScale *scale = PIKA_COLOR_SCALE (widget);
PikaColorScalePrivate *priv = GET_PRIVATE (widget);
GtkRange *range = GTK_RANGE (widget);
GtkStyleContext *context = gtk_widget_get_style_context (widget);
GdkRectangle range_rect;
GdkRectangle area = { 0, };
cairo_surface_t *buffer;
gint slider_start;
gint slider_end;
gint slider_mid;
gint slider_size;
if (! priv->buf)
return FALSE;
gtk_range_get_range_rect (range, &range_rect);
gtk_range_get_slider_range (range, &slider_start, &slider_end);
slider_mid = slider_start + (slider_end - slider_start) / 2;
slider_size = 6;
if (priv->needs_render)
{
pika_color_scale_render (scale);
priv->needs_render = FALSE;
}
if (! priv->transform)
pika_color_scale_create_transform (scale);
if (priv->transform)
{
const Babl *format = babl_format ("cairo-RGB24");
guchar *buf = g_new (guchar, priv->rowstride * priv->height);
guchar *src = priv->buf;
guchar *dest = buf;
guint i;
for (i = 0; i < priv->height; i++)
{
pika_color_transform_process_pixels (priv->transform,
format, src,
format, dest,
priv->width);
src += priv->rowstride;
dest += priv->rowstride;
}
buffer = cairo_image_surface_create_for_data (buf,
CAIRO_FORMAT_RGB24,
priv->width,
priv->height,
priv->rowstride);
cairo_surface_set_user_data (buffer, NULL,
buf, (cairo_destroy_func_t) g_free);
}
else
{
buffer = cairo_image_surface_create_for_data (priv->buf,
CAIRO_FORMAT_RGB24,
priv->width,
priv->height,
priv->rowstride);
}
switch (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)))
{
case GTK_ORIENTATION_HORIZONTAL:
cairo_set_source_surface (cr, buffer,
range_rect.x, range_rect.y);
break;
case GTK_ORIENTATION_VERTICAL:
cairo_set_source_surface (cr, buffer,
range_rect.x, range_rect.y);
break;
}
cairo_surface_destroy (buffer);
if (! gtk_widget_is_sensitive (widget))
{
static cairo_pattern_t *pattern = NULL;
if (! pattern)
{
static const guchar stipple[] = { 0, 255, 0, 0,
255, 0, 0, 0 };
cairo_surface_t *surface;
gint stride;
stride = cairo_format_stride_for_width (CAIRO_FORMAT_A8, 2);
surface = cairo_image_surface_create_for_data ((guchar *) stipple,
CAIRO_FORMAT_A8,
2, 2, stride);
pattern = cairo_pattern_create_for_surface (surface);
cairo_surface_destroy (surface);
cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
}
cairo_mask (cr, pattern);
}
else
{
cairo_paint (cr);
}
if (gtk_widget_has_focus (widget))
gtk_render_focus (context, cr,
0, 0,
gtk_widget_get_allocated_width (widget),
gtk_widget_get_allocated_height (widget));
switch (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)))
{
case GTK_ORIENTATION_HORIZONTAL:
area.x = slider_mid - slider_size;
area.y = range_rect.y;
area.width = 2 * slider_size;
area.height = range_rect.height;
break;
case GTK_ORIENTATION_VERTICAL:
area.x = range_rect.x;
area.y = slider_mid - slider_size;
area.width = range_rect.width;
area.height = 2 * slider_size;
break;
}
if (gtk_widget_is_sensitive (widget))
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
else
cairo_set_source_rgb (cr, 0.2, 0.2, 0.2);
switch (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)))
{
case GTK_ORIENTATION_HORIZONTAL:
cairo_move_to (cr, area.x, area.y);
cairo_line_to (cr, area.x + area.width, area.y);
cairo_line_to (cr,
area.x + area.width / 2 + 0.5,
area.y + slider_size);
break;
case GTK_ORIENTATION_VERTICAL:
cairo_move_to (cr, area.x, area.y);
cairo_line_to (cr, area.x, area.y + area.height);
cairo_line_to (cr,
area.x + slider_size,
area.y + area.height / 2 + 0.5);
break;
}
cairo_close_path (cr);
cairo_fill (cr);
if (gtk_widget_is_sensitive (widget))
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
else
cairo_set_source_rgb (cr, 0.8, 0.8, 0.8);
switch (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)))
{
case GTK_ORIENTATION_HORIZONTAL:
cairo_move_to (cr, area.x, area.y + area.height);
cairo_line_to (cr, area.x + area.width, area.y + area.height);
cairo_line_to (cr,
area.x + area.width / 2 + 0.5,
area.y + area.height - slider_size);
break;
case GTK_ORIENTATION_VERTICAL:
cairo_move_to (cr, area.x + area.width, area.y);
cairo_line_to (cr, area.x + area.width, area.y + area.height);
cairo_line_to (cr,
area.x + area.width - slider_size,
area.y + area.height / 2 + 0.5);
break;
}
cairo_close_path (cr);
cairo_fill (cr);
return FALSE;
}
/**
* pika_color_scale_new:
* @orientation: the scale's orientation (horizontal or vertical)
* @channel: the scale's color channel
*
* Creates a new #PikaColorScale widget.
*
* Returns: a new #PikaColorScale widget
**/
GtkWidget *
pika_color_scale_new (GtkOrientation orientation,
PikaColorSelectorChannel channel)
{
PikaColorScale *scale = g_object_new (PIKA_TYPE_COLOR_SCALE,
"orientation", orientation,
"channel", channel,
NULL);
gtk_range_set_flippable (GTK_RANGE (scale),
orientation == GTK_ORIENTATION_HORIZONTAL);
return GTK_WIDGET (scale);
}
/**
* pika_color_scale_set_channel:
* @scale: a #PikaColorScale widget
* @channel: the new color channel
*
* Changes the color channel displayed by the @scale.
**/
void
pika_color_scale_set_channel (PikaColorScale *scale,
PikaColorSelectorChannel channel)
{
PikaColorScalePrivate *priv;
g_return_if_fail (PIKA_IS_COLOR_SCALE (scale));
priv = GET_PRIVATE (scale);
if (channel != priv->channel)
{
priv->channel = channel;
priv->needs_render = TRUE;
gtk_widget_queue_draw (GTK_WIDGET (scale));
g_object_notify (G_OBJECT (scale), "channel");
}
}
/**
* pika_color_scale_set_color:
* @scale: a #PikaColorScale widget
* @rgb: the new color as #PikaRGB
* @hsv: the new color as #PikaHSV
*
* Changes the color value of the @scale.
**/
void
pika_color_scale_set_color (PikaColorScale *scale,
const PikaRGB *rgb,
const PikaHSV *hsv)
{
PikaColorScalePrivate *priv;
g_return_if_fail (PIKA_IS_COLOR_SCALE (scale));
g_return_if_fail (rgb != NULL);
g_return_if_fail (hsv != NULL);
priv = GET_PRIVATE (scale);
priv->rgb = *rgb;
priv->hsv = *hsv;
priv->needs_render = TRUE;
gtk_widget_queue_draw (GTK_WIDGET (scale));
}
/**
* pika_color_scale_set_color_config:
* @scale: a #PikaColorScale widget.
* @config: a #PikaColorConfig object.
*
* Sets the color management configuration to use with this color scale.
*
* Since: 2.10
*/
void
pika_color_scale_set_color_config (PikaColorScale *scale,
PikaColorConfig *config)
{
PikaColorScalePrivate *priv;
g_return_if_fail (PIKA_IS_COLOR_SCALE (scale));
g_return_if_fail (config == NULL || PIKA_IS_COLOR_CONFIG (config));
priv = GET_PRIVATE (scale);
if (config != priv->config)
{
if (priv->config)
{
g_signal_handlers_disconnect_by_func (priv->config,
pika_color_scale_notify_config,
scale);
pika_color_scale_destroy_transform (scale);
}
g_set_object (&priv->config, config);
if (priv->config)
{
g_signal_connect (priv->config, "notify",
G_CALLBACK (pika_color_scale_notify_config),
scale);
pika_color_scale_notify_config (priv->config, NULL, scale);
}
}
}
/* as in gtkrange.c */
static gboolean
should_invert (GtkRange *range)
{
gboolean inverted = gtk_range_get_inverted (range);
gboolean flippable = gtk_range_get_flippable (range);
if (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)) ==
GTK_ORIENTATION_HORIZONTAL)
{
return
(inverted && !flippable) ||
(inverted && flippable &&
gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_LTR) ||
(!inverted && flippable &&
gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_RTL);
}
else
{
return inverted;
}
}
static void
pika_color_scale_render (PikaColorScale *scale)
{
PikaColorScalePrivate *priv = GET_PRIVATE (scale);
GtkRange *range = GTK_RANGE (scale);
PikaRGB rgb;
PikaHSV hsv;
PikaLCH lch;
gint multiplier = 1;
guint x, y;
gdouble *channel_value = NULL; /* shut up compiler */
gboolean from_hsv = FALSE;
gboolean from_lch = FALSE;
gboolean invert;
guchar *buf;
guchar *d;
if ((buf = priv->buf) == NULL)
return;
if (priv->channel == PIKA_COLOR_SELECTOR_ALPHA)
{
pika_color_scale_render_alpha (scale);
return;
}
rgb = priv->rgb;
hsv = priv->hsv;
babl_process (fish_rgb_to_lch, &rgb, &lch, 1);
switch (priv->channel)
{
case PIKA_COLOR_SELECTOR_HUE: channel_value = &hsv.h; break;
case PIKA_COLOR_SELECTOR_SATURATION: channel_value = &hsv.s; break;
case PIKA_COLOR_SELECTOR_VALUE: channel_value = &hsv.v; break;
case PIKA_COLOR_SELECTOR_RED: channel_value = &rgb.r; break;
case PIKA_COLOR_SELECTOR_GREEN: channel_value = &rgb.g; break;
case PIKA_COLOR_SELECTOR_BLUE: channel_value = &rgb.b; break;
case PIKA_COLOR_SELECTOR_ALPHA: channel_value = &rgb.a; break;
case PIKA_COLOR_SELECTOR_LCH_LIGHTNESS: channel_value = &lch.l; break;
case PIKA_COLOR_SELECTOR_LCH_CHROMA: channel_value = &lch.c; break;
case PIKA_COLOR_SELECTOR_LCH_HUE: channel_value = &lch.h; break;
}
switch (priv->channel)
{
case PIKA_COLOR_SELECTOR_HUE:
case PIKA_COLOR_SELECTOR_SATURATION:
case PIKA_COLOR_SELECTOR_VALUE:
from_hsv = TRUE;
break;
case PIKA_COLOR_SELECTOR_LCH_LIGHTNESS:
multiplier = 100;
from_lch = TRUE;
break;
case PIKA_COLOR_SELECTOR_LCH_CHROMA:
multiplier = 200;
from_lch = TRUE;
break;
case PIKA_COLOR_SELECTOR_LCH_HUE:
multiplier = 360;
from_lch = TRUE;
break;
default:
break;
}
invert = should_invert (range);
switch (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)))
{
case GTK_ORIENTATION_HORIZONTAL:
for (x = 0, d = buf; x < priv->width; x++, d += 4)
{
gdouble value = (gdouble) x * multiplier / (gdouble) (priv->width - 1);
guchar r, g, b;
if (invert)
value = multiplier - value;
*channel_value = value;
if (from_hsv)
pika_hsv_to_rgb (&hsv, &rgb);
else if (from_lch)
babl_process (fish_lch_to_rgb, &lch, &rgb, 1);
if (rgb.r < 0.0 || rgb.r > 1.0 ||
rgb.g < 0.0 || rgb.g > 1.0 ||
rgb.b < 0.0 || rgb.b > 1.0)
{
r = priv->oog_color[0];
g = priv->oog_color[1];
b = priv->oog_color[2];
}
else
{
pika_rgb_get_uchar (&rgb, &r, &g, &b);
}
PIKA_CAIRO_RGB24_SET_PIXEL (d, r, g, b);
}
d = buf + priv->rowstride;
for (y = 1; y < priv->height; y++)
{
memcpy (d, buf, priv->rowstride);
d += priv->rowstride;
}
break;
case GTK_ORIENTATION_VERTICAL:
for (y = 0; y < priv->height; y++)
{
gdouble value = (gdouble) y * multiplier / (gdouble) (priv->height - 1);
guchar r, g, b;
if (invert)
value = multiplier - value;
*channel_value = value;
if (from_hsv)
pika_hsv_to_rgb (&hsv, &rgb);
else if (from_lch)
babl_process (fish_lch_to_rgb, &lch, &rgb, 1);
if (rgb.r < 0.0 || rgb.r > 1.0 ||
rgb.g < 0.0 || rgb.g > 1.0 ||
rgb.b < 0.0 || rgb.b > 1.0)
{
r = priv->oog_color[0];
g = priv->oog_color[1];
b = priv->oog_color[2];
}
else
{
pika_rgb_get_uchar (&rgb, &r, &g, &b);
}
for (x = 0, d = buf; x < priv->width; x++, d += 4)
{
PIKA_CAIRO_RGB24_SET_PIXEL (d, r, g, b);
}
buf += priv->rowstride;
}
break;
}
}
static void
pika_color_scale_render_alpha (PikaColorScale *scale)
{
PikaColorScalePrivate *priv = GET_PRIVATE (scale);
GtkRange *range = GTK_RANGE (scale);
PikaRGB rgb;
gboolean invert;
gdouble a;
guint x, y;
guchar *buf;
guchar *d, *l;
invert = should_invert (range);
buf = priv->buf;
rgb = priv->rgb;
switch (gtk_orientable_get_orientation (GTK_ORIENTABLE (range)))
{
case GTK_ORIENTATION_HORIZONTAL:
{
guchar *light;
guchar *dark;
light = buf;
/* this won't work correctly for very thin scales */
dark = (priv->height > PIKA_CHECK_SIZE_SM ?
buf + PIKA_CHECK_SIZE_SM * priv->rowstride : light);
for (x = 0, d = light, l = dark; x < priv->width; x++)
{
if ((x % PIKA_CHECK_SIZE_SM) == 0)
{
guchar *t;
t = d;
d = l;
l = t;
}
a = (gdouble) x / (gdouble) (priv->width - 1);
if (invert)
a = 1.0 - a;
PIKA_CAIRO_RGB24_SET_PIXEL (l,
(PIKA_CHECK_LIGHT +
(rgb.r - PIKA_CHECK_LIGHT) * a) * 255.999,
(PIKA_CHECK_LIGHT +
(rgb.g - PIKA_CHECK_LIGHT) * a) * 255.999,
(PIKA_CHECK_LIGHT +
(rgb.b - PIKA_CHECK_LIGHT) * a) * 255.999);
l += 4;
PIKA_CAIRO_RGB24_SET_PIXEL (d,
(PIKA_CHECK_DARK +
(rgb.r - PIKA_CHECK_DARK) * a) * 255.999,
(PIKA_CHECK_DARK +
(rgb.g - PIKA_CHECK_DARK) * a) * 255.999,
(PIKA_CHECK_DARK +
(rgb.b - PIKA_CHECK_DARK) * a) * 255.999);
d += 4;
}
for (y = 0, d = buf; y < priv->height; y++, d += priv->rowstride)
{
if (y == 0 || y == PIKA_CHECK_SIZE_SM)
continue;
if ((y / PIKA_CHECK_SIZE_SM) & 1)
memcpy (d, dark, priv->rowstride);
else
memcpy (d, light, priv->rowstride);
}
}
break;
case GTK_ORIENTATION_VERTICAL:
{
guchar light[4] = {0xff, 0xff, 0xff, 0xff};
guchar dark[4] = {0xff, 0xff, 0xff, 0xff};
for (y = 0, d = buf; y < priv->height; y++, d += priv->rowstride)
{
a = (gdouble) y / (gdouble) (priv->height - 1);
if (invert)
a = 1.0 - a;
PIKA_CAIRO_RGB24_SET_PIXEL (light,
(PIKA_CHECK_LIGHT +
(rgb.r - PIKA_CHECK_LIGHT) * a) * 255.999,
(PIKA_CHECK_LIGHT +
(rgb.g - PIKA_CHECK_LIGHT) * a) * 255.999,
(PIKA_CHECK_LIGHT +
(rgb.b - PIKA_CHECK_LIGHT) * a) * 255.999);
PIKA_CAIRO_RGB24_SET_PIXEL (dark,
(PIKA_CHECK_DARK +
(rgb.r - PIKA_CHECK_DARK) * a) * 255.999,
(PIKA_CHECK_DARK +
(rgb.g - PIKA_CHECK_DARK) * a) * 255.999,
(PIKA_CHECK_DARK +
(rgb.b - PIKA_CHECK_DARK) * a) * 255.999);
for (x = 0, l = d; x < priv->width; x++, l += 4)
{
if (((x / PIKA_CHECK_SIZE_SM) ^ (y / PIKA_CHECK_SIZE_SM)) & 1)
{
l[0] = light[0];
l[1] = light[1];
l[2] = light[2];
l[3] = light[3];
}
else
{
l[0] = dark[0];
l[1] = dark[1];
l[2] = dark[2];
l[3] = dark[3];
}
}
}
}
break;
}
}
static void
pika_color_scale_create_transform (PikaColorScale *scale)
{
PikaColorScalePrivate *priv = GET_PRIVATE (scale);
if (priv->config)
{
static PikaColorProfile *profile = NULL;
const Babl *format = babl_format ("cairo-RGB24");
if (G_UNLIKELY (! profile))
profile = pika_color_profile_new_rgb_srgb ();
priv->transform = pika_widget_get_color_transform (GTK_WIDGET (scale),
priv->config,
profile,
format,
format,
NULL,
PIKA_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
FALSE);
}
}
static void
pika_color_scale_destroy_transform (PikaColorScale *scale)
{
PikaColorScalePrivate *priv = GET_PRIVATE (scale);
if (priv->transform)
{
g_object_unref (priv->transform);
priv->transform = NULL;
}
gtk_widget_queue_draw (GTK_WIDGET (scale));
}
static void
pika_color_scale_notify_config (PikaColorConfig *config,
const GParamSpec *pspec,
PikaColorScale *scale)
{
PikaColorScalePrivate *priv = GET_PRIVATE (scale);
PikaRGB color;
pika_color_scale_destroy_transform (scale);
pika_color_config_get_out_of_gamut_color (config, &color);
pika_rgb_get_uchar (&color,
priv->oog_color,
priv->oog_color + 1,
priv->oog_color + 2);
priv->needs_render = TRUE;
}

View File

@ -0,0 +1,83 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorscale.h
* Copyright (C) 2002 Sven Neumann <sven@gimp.org>
* Michael Natterer <mitch@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_SCALE_H__
#define __PIKA_COLOR_SCALE_H__
G_BEGIN_DECLS
#define PIKA_TYPE_COLOR_SCALE (pika_color_scale_get_type ())
#define PIKA_COLOR_SCALE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_SCALE, PikaColorScale))
#define PIKA_COLOR_SCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_SCALE, PikaColorScaleClass))
#define PIKA_IS_COLOR_SCALE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_SCALE))
#define PIKA_IS_COLOR_SCALE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_SCALE))
#define PIKA_COLOR_SCALE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_SCALE, PikaColorScaleClass))
typedef struct _PikaColorScalePrivate PikaColorScalePrivate;
typedef struct _PikaColorScaleClass PikaColorScaleClass;
struct _PikaColorScale
{
GtkScale parent_instance;
PikaColorScalePrivate *priv;
};
struct _PikaColorScaleClass
{
GtkScaleClass parent_class;
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_color_scale_get_type (void) G_GNUC_CONST;
GtkWidget * pika_color_scale_new (GtkOrientation orientation,
PikaColorSelectorChannel channel);
void pika_color_scale_set_channel (PikaColorScale *scale,
PikaColorSelectorChannel channel);
void pika_color_scale_set_color (PikaColorScale *scale,
const PikaRGB *rgb,
const PikaHSV *hsv);
void pika_color_scale_set_color_config (PikaColorScale *scale,
PikaColorConfig *config);
G_END_DECLS
#endif /* __PIKA_COLOR_SCALE_H__ */

View File

@ -0,0 +1,112 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorscaleentry.c
* Copyright (C) 2020 Jehan
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikacolor/pikacolor.h"
#include "libpikamath/pikamath.h"
#include "libpikabase/pikabase.h"
#include "pikawidgets.h"
/**
* SECTION: pikacolorscaleentry
* @title: PikaColorScaleEntry
* @short_description: Widget containing a color scale, a spin button
* and a label.
*
* This widget is a subclass of #PikaScaleEntry showing a
* #PikaColorScale instead of a #GtkScale.
**/
struct _PikaColorScaleEntry
{
PikaScaleEntry parent_instance;
};
static GtkWidget * pika_color_scale_entry_new_range_widget (GtkAdjustment *adjustment);
G_DEFINE_TYPE (PikaColorScaleEntry, pika_color_scale_entry, PIKA_TYPE_SCALE_ENTRY)
#define parent_class pika_color_scale_entry_parent_class
static void
pika_color_scale_entry_class_init (PikaColorScaleEntryClass *klass)
{
PikaScaleEntryClass *entry_class = PIKA_SCALE_ENTRY_CLASS (klass);
entry_class->new_range_widget = pika_color_scale_entry_new_range_widget;
}
static void
pika_color_scale_entry_init (PikaColorScaleEntry *entry)
{
}
static GtkWidget *
pika_color_scale_entry_new_range_widget (GtkAdjustment *adjustment)
{
GtkWidget *scale;
g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), NULL);
scale = pika_color_scale_new (GTK_ORIENTATION_HORIZONTAL,
PIKA_COLOR_SELECTOR_VALUE);
gtk_range_set_adjustment (GTK_RANGE (scale), adjustment);
return scale;
}
/**
* pika_color_scale_entry_new:
* @text: The text for the #GtkLabel.
* @value: The initial value.
* @lower: The lower boundary.
* @upper: The upper boundary.
* @digits: The number of decimal digits.
*
* Returns: (transfer full): The new #PikaColorScale widget.
**/
GtkWidget *
pika_color_scale_entry_new (const gchar *text,
gdouble value,
gdouble lower,
gdouble upper,
guint digits)
{
GtkWidget *entry;
entry = g_object_new (PIKA_TYPE_COLOR_SCALE_ENTRY,
"label", text,
"value", value,
"lower", lower,
"upper", upper,
"digits", digits,
NULL);
return entry;
}

View File

@ -0,0 +1,45 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorscaleentry.h
* Copyright (C) 2020 Jehan
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_SCALE_ENTRY_H__
#define __PIKA_COLOR_SCALE_ENTRY_H__
#include <libpikawidgets/pikascaleentry.h>
G_BEGIN_DECLS
#define PIKA_TYPE_COLOR_SCALE_ENTRY (pika_color_scale_entry_get_type ())
G_DECLARE_FINAL_TYPE (PikaColorScaleEntry, pika_color_scale_entry, PIKA, COLOR_SCALE_ENTRY, PikaScaleEntry)
GtkWidget * pika_color_scale_entry_new (const gchar *text,
gdouble value,
gdouble lower,
gdouble upper,
guint digits);
G_END_DECLS
#endif /* __PIKA_COLOR_SCALE_ENTRY_H__ */

View File

@ -0,0 +1,926 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorscales.c
* Copyright (C) 2002 Michael Natterer <mitch@gimp.org>
*
* based on color_notebook module
* Copyright (C) 1998 Austin Donnelly <austin@greenend.org.uk>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h"
#include "libpikamath/pikamath.h"
#include "pikawidgetstypes.h"
#include "pikacolorscale.h"
#include "pikacolorscales.h"
#include "pikawidgets.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikacolorscales
* @title: PikaColorScales
* @short_description: A #PikaColorSelector implementation.
*
* The #PikaColorScales widget is an implementation of a
* #PikaColorSelector. It shows a group of #PikaColorScale widgets
* that allow to adjust the HSV, LCH, and RGB color channels.
**/
enum
{
PROP_0,
PROP_SHOW_RGB_U8,
PROP_SHOW_HSV
};
enum
{
PIKA_COLOR_SELECTOR_RED_U8 = PIKA_COLOR_SELECTOR_LCH_HUE + 1,
PIKA_COLOR_SELECTOR_GREEN_U8,
PIKA_COLOR_SELECTOR_BLUE_U8,
PIKA_COLOR_SELECTOR_ALPHA_U8
};
typedef struct _PikaLCH PikaLCH;
struct _PikaLCH
{
gdouble l, c, h, a;
};
typedef struct _ColorScale ColorScale;
struct _ColorScale
{
PikaColorSelectorChannel channel;
gdouble default_value;
gdouble scale_min_value;
gdouble scale_max_value;
gdouble scale_inc;
gdouble spin_min_value;
gdouble spin_max_value;
};
#define PIKA_COLOR_SCALES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_SCALES, PikaColorScalesClass))
#define PIKA_IS_COLOR_SCALES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_SCALES))
#define PIKA_COLOR_SCALES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_SCALES, PikaColorScalesClass))
typedef struct _PikaColorScalesClass PikaColorScalesClass;
struct _PikaColorScales
{
PikaColorSelector parent_instance;
gboolean show_rgb_u8;
GBinding *show_rgb_u8_binding;
GBinding *show_hsv_binding;
GtkWidget *lch_group;
GtkWidget *hsv_group;
GtkWidget *rgb_percent_group;
GtkWidget *rgb_u8_group;
GtkWidget *alpha_percent_group;
GtkWidget *alpha_u8_group;
GtkWidget *dummy_u8_toggle;
GtkWidget *toggles[14];
GtkWidget *scales[14];
};
struct _PikaColorScalesClass
{
PikaColorSelectorClass parent_class;
};
static void pika_color_scales_dispose (GObject *object);
static void pika_color_scales_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_color_scales_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_color_scales_togg_sensitive (PikaColorSelector *selector,
gboolean sensitive);
static void pika_color_scales_togg_visible (PikaColorSelector *selector,
gboolean visible);
static void pika_color_scales_set_show_alpha (PikaColorSelector *selector,
gboolean show_alpha);
static void pika_color_scales_set_color (PikaColorSelector *selector,
const PikaRGB *rgb,
const PikaHSV *hsv);
static void pika_color_scales_set_channel (PikaColorSelector *selector,
PikaColorSelectorChannel channel);
static void pika_color_scales_set_model_visible
(PikaColorSelector *selector,
PikaColorSelectorModel model,
gboolean visible);
static void pika_color_scales_set_config (PikaColorSelector *selector,
PikaColorConfig *config);
static void pika_color_scales_update_visible (PikaColorScales *scales);
static void pika_color_scales_update_scales (PikaColorScales *scales,
gint skip);
static void pika_color_scales_toggle_changed (GtkWidget *widget,
PikaColorScales *scales);
static void pika_color_scales_scale_changed (GtkWidget *scale,
PikaColorScales *scales);
static void pika_color_scales_toggle_lch_hsv (GtkToggleButton *toggle,
PikaColorScales *scales);
G_DEFINE_TYPE (PikaColorScales, pika_color_scales, PIKA_TYPE_COLOR_SELECTOR)
#define parent_class pika_color_scales_parent_class
static const Babl *fish_rgb_to_lch = NULL;
static const Babl *fish_lch_to_rgb = NULL;
static const ColorScale scale_defs[] =
{
{ PIKA_COLOR_SELECTOR_HUE, 0, 0, 360, 30, 0, 360 },
{ PIKA_COLOR_SELECTOR_SATURATION, 0, 0, 100, 10, 0, 500 },
{ PIKA_COLOR_SELECTOR_VALUE, 0, 0, 100, 10, 0, 500 },
{ PIKA_COLOR_SELECTOR_RED, 0, 0, 100, 10, -500, 500 },
{ PIKA_COLOR_SELECTOR_GREEN, 0, 0, 100, 10, -500, 500 },
{ PIKA_COLOR_SELECTOR_BLUE, 0, 0, 100, 10, -500, 500 },
{ PIKA_COLOR_SELECTOR_ALPHA, 0, 0, 100, 10, 0, 100 },
{ PIKA_COLOR_SELECTOR_LCH_LIGHTNESS, 0, 0, 100, 10, 0, 300 },
{ PIKA_COLOR_SELECTOR_LCH_CHROMA, 0, 0, 200, 10, 0, 300 },
{ PIKA_COLOR_SELECTOR_LCH_HUE, 0, 0, 360, 30, 0, 360 },
{ (PikaColorSelectorChannel) PIKA_COLOR_SELECTOR_RED_U8,
0, 0, 255, 16, -1275, 1275 },
{ (PikaColorSelectorChannel) PIKA_COLOR_SELECTOR_GREEN_U8,
0, 0, 255, 16, -1275, 1275 },
{ (PikaColorSelectorChannel) PIKA_COLOR_SELECTOR_BLUE_U8,
0, 0, 255, 16, -1275, 1275 },
{ (PikaColorSelectorChannel) PIKA_COLOR_SELECTOR_ALPHA_U8,
0, 0, 255, 16, 0, 255 }
};
static void
pika_color_scales_class_init (PikaColorScalesClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
PikaColorSelectorClass *selector_class = PIKA_COLOR_SELECTOR_CLASS (klass);
object_class->dispose = pika_color_scales_dispose;
object_class->get_property = pika_color_scales_get_property;
object_class->set_property = pika_color_scales_set_property;
selector_class->name = _("Scales");
selector_class->help_id = "pika-colorselector-scales";
selector_class->icon_name = PIKA_ICON_DIALOG_TOOL_OPTIONS;
selector_class->set_toggles_visible = pika_color_scales_togg_visible;
selector_class->set_toggles_sensitive = pika_color_scales_togg_sensitive;
selector_class->set_show_alpha = pika_color_scales_set_show_alpha;
selector_class->set_color = pika_color_scales_set_color;
selector_class->set_channel = pika_color_scales_set_channel;
selector_class->set_model_visible = pika_color_scales_set_model_visible;
selector_class->set_config = pika_color_scales_set_config;
g_object_class_install_property (object_class, PROP_SHOW_RGB_U8,
g_param_spec_boolean ("show-rgb-u8",
"Show RGB 0..255",
"Show RGB 0..255 scales",
FALSE,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_SHOW_HSV,
g_param_spec_boolean ("show-hsv",
"Show HSV",
"Show HSV instead of LCH",
FALSE,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
gtk_widget_class_set_css_name (widget_class, "PikaColorScales");
fish_rgb_to_lch = babl_fish (babl_format ("R'G'B'A double"),
babl_format ("CIE LCH(ab) alpha double"));
fish_lch_to_rgb = babl_fish (babl_format ("CIE LCH(ab) alpha double"),
babl_format ("R'G'B'A double"));
}
static GtkWidget *
create_group (PikaColorScales *scales,
GSList **radio_group,
GtkSizeGroup *size_group0,
GtkSizeGroup *size_group1,
GtkSizeGroup *size_group2,
PikaColorSelectorChannel first_channel,
PikaColorSelectorChannel last_channel)
{
PikaColorSelector *selector = PIKA_COLOR_SELECTOR (scales);
GtkWidget *grid;
GEnumClass *enum_class;
gint row;
gint i;
grid = gtk_grid_new ();
gtk_grid_set_row_spacing (GTK_GRID (grid), 1);
gtk_grid_set_column_spacing (GTK_GRID (grid), 1);
enum_class = g_type_class_ref (PIKA_TYPE_COLOR_SELECTOR_CHANNEL);
for (i = first_channel, row = 0; i <= last_channel; i++, row++)
{
const PikaEnumDesc *enum_desc;
gint enum_value = i;
gboolean is_u8 = FALSE;
if (enum_value >= PIKA_COLOR_SELECTOR_RED_U8 &&
enum_value <= PIKA_COLOR_SELECTOR_ALPHA_U8)
{
enum_value -= 7;
is_u8 = TRUE;
}
enum_desc = pika_enum_get_desc (enum_class, enum_value);
if (i == PIKA_COLOR_SELECTOR_ALPHA ||
i == PIKA_COLOR_SELECTOR_ALPHA_U8)
{
/* just to allocate the space via the size group */
scales->toggles[i] = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
}
else
{
scales->toggles[i] = gtk_radio_button_new (*radio_group);
*radio_group =
gtk_radio_button_get_group (GTK_RADIO_BUTTON (scales->toggles[i]));
if (enum_value == pika_color_selector_get_channel (selector))
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scales->toggles[i]),
TRUE);
if (is_u8)
{
/* bind the RGB U8 toggles to the RGB percent toggles */
g_object_bind_property (scales->toggles[i - 7], "active",
scales->toggles[i], "active",
G_BINDING_SYNC_CREATE |
G_BINDING_BIDIRECTIONAL);
}
else
{
g_signal_connect (scales->toggles[i], "toggled",
G_CALLBACK (pika_color_scales_toggle_changed),
scales);
}
}
gtk_grid_attach (GTK_GRID (grid), scales->toggles[i], 0, row, 1, 1);
if (pika_color_selector_get_toggles_visible (selector))
gtk_widget_show (scales->toggles[i]);
pika_help_set_help_data (scales->toggles[i],
gettext (enum_desc->value_help), NULL);
gtk_size_group_add_widget (size_group0, scales->toggles[i]);
scales->scales[i] =
pika_color_scale_entry_new (gettext (enum_desc->value_desc),
scale_defs[i].default_value,
scale_defs[i].spin_min_value,
scale_defs[i].spin_max_value,
1);
gtk_grid_attach (GTK_GRID (grid), scales->scales[i], 1, row, 3, 1);
pika_label_spin_set_increments (PIKA_LABEL_SPIN (scales->scales[i]),
1.0, scale_defs[i].scale_inc);
pika_help_set_help_data (scales->scales[i],
gettext (enum_desc->value_help),
NULL);
gtk_widget_show (scales->scales[i]);
pika_scale_entry_set_bounds (PIKA_SCALE_ENTRY (scales->scales[i]),
scale_defs[i].scale_min_value,
scale_defs[i].scale_max_value,
TRUE);
g_object_add_weak_pointer (G_OBJECT (scales->scales[i]),
(gpointer) &scales->scales[i]);
pika_color_scale_set_channel (PIKA_COLOR_SCALE (pika_scale_entry_get_range (PIKA_SCALE_ENTRY (scales->scales[i]))),
enum_value);
gtk_size_group_add_widget (size_group1, scales->scales[i]);
gtk_size_group_add_widget (size_group2,
pika_label_spin_get_spin_button (PIKA_LABEL_SPIN (scales->scales[i])));
g_signal_connect (scales->scales[i], "value-changed",
G_CALLBACK (pika_color_scales_scale_changed),
scales);
}
g_type_class_unref (enum_class);
return grid;
}
static void
pika_color_scales_init (PikaColorScales *scales)
{
PikaColorSelector *selector = PIKA_COLOR_SELECTOR (scales);
GtkSizeGroup *size_group0;
GtkSizeGroup *size_group1;
GtkSizeGroup *size_group2;
GtkWidget *hbox;
GtkWidget *radio1;
GtkWidget *radio2;
GtkWidget *grid;
GSList *main_group;
GSList *u8_group;
gtk_box_set_spacing (GTK_BOX (scales), 5);
scales->show_rgb_u8_binding = NULL;
scales->show_hsv_binding = NULL;
/* don't need the toggles for our own operation */
selector->toggles_visible = FALSE;
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
gtk_box_pack_start (GTK_BOX (scales), hbox, 0, 0, FALSE);
gtk_widget_show (hbox);
main_group = NULL;
u8_group = NULL;
scales->dummy_u8_toggle = gtk_radio_button_new (NULL);
g_object_ref_sink (scales->dummy_u8_toggle);
u8_group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (scales->dummy_u8_toggle));
size_group0 = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
size_group1 = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
size_group2 = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
scales->rgb_percent_group =
grid = create_group (scales, &main_group,
size_group0, size_group1, size_group2,
PIKA_COLOR_SELECTOR_RED,
PIKA_COLOR_SELECTOR_BLUE);
gtk_box_pack_start (GTK_BOX (scales), grid, FALSE, FALSE, 0);
scales->rgb_u8_group =
grid = create_group (scales, &u8_group,
size_group0, size_group1, size_group2,
(PikaColorSelectorChannel) PIKA_COLOR_SELECTOR_RED_U8,
(PikaColorSelectorChannel) PIKA_COLOR_SELECTOR_BLUE_U8);
gtk_box_pack_start (GTK_BOX (scales), grid, FALSE, FALSE, 0);
scales->lch_group =
grid = create_group (scales, &main_group,
size_group0, size_group1, size_group2,
PIKA_COLOR_SELECTOR_LCH_LIGHTNESS,
PIKA_COLOR_SELECTOR_LCH_HUE);
gtk_box_pack_start (GTK_BOX (scales), grid, FALSE, FALSE, 0);
scales->hsv_group =
grid = create_group (scales, &main_group,
size_group0, size_group1, size_group2,
PIKA_COLOR_SELECTOR_HUE,
PIKA_COLOR_SELECTOR_VALUE);
gtk_box_pack_start (GTK_BOX (scales), grid, FALSE, FALSE, 0);
scales->alpha_percent_group =
grid = create_group (scales, &main_group,
size_group0, size_group1, size_group2,
PIKA_COLOR_SELECTOR_ALPHA,
PIKA_COLOR_SELECTOR_ALPHA);
gtk_box_pack_start (GTK_BOX (scales), grid, FALSE, FALSE, 0);
scales->alpha_u8_group =
grid = create_group (scales, &u8_group,
size_group0, size_group1, size_group2,
(PikaColorSelectorChannel) PIKA_COLOR_SELECTOR_ALPHA_U8,
(PikaColorSelectorChannel) PIKA_COLOR_SELECTOR_ALPHA_U8);
gtk_box_pack_start (GTK_BOX (scales), grid, FALSE, FALSE, 0);
g_object_unref (size_group0);
g_object_unref (size_group1);
g_object_unref (size_group2);
radio1 = gtk_radio_button_new_with_label (NULL, _("0..100"));
radio2 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (radio1),
_("0..255"));
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (radio1), FALSE);
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (radio2), FALSE);
gtk_box_pack_start (GTK_BOX (hbox), radio1, FALSE, FALSE, 0);
gtk_box_pack_start (GTK_BOX (hbox), radio2, FALSE, FALSE, 0);
gtk_widget_show (radio1);
gtk_widget_show (radio2);
if (scales->show_rgb_u8)
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio2), TRUE);
else
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio1), TRUE);
g_object_bind_property (G_OBJECT (radio2), "active",
G_OBJECT (scales), "show-rgb-u8",
G_BINDING_SYNC_CREATE |
G_BINDING_BIDIRECTIONAL);
radio1 = gtk_radio_button_new_with_label (NULL, _("LCh"));
radio2 = gtk_radio_button_new_with_label_from_widget (GTK_RADIO_BUTTON (radio1),
_("HSV"));
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (radio1), FALSE);
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (radio2), FALSE);
gtk_box_pack_end (GTK_BOX (hbox), radio2, FALSE, FALSE, 0);
gtk_box_pack_end (GTK_BOX (hbox), radio1, FALSE, FALSE, 0);
gtk_widget_show (radio1);
gtk_widget_show (radio2);
if (pika_color_selector_get_model_visible (selector,
PIKA_COLOR_SELECTOR_MODEL_HSV))
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio2), TRUE);
else
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (radio1), TRUE);
g_object_bind_property (G_OBJECT (radio2), "active",
G_OBJECT (scales), "show-hsv",
G_BINDING_SYNC_CREATE |
G_BINDING_BIDIRECTIONAL);
g_signal_connect (radio1, "toggled",
G_CALLBACK (pika_color_scales_toggle_lch_hsv),
scales);
pika_color_scales_update_visible (scales);
}
static void
pika_color_scales_dispose (GObject *object)
{
PikaColorScales *scales = PIKA_COLOR_SCALES (object);
g_clear_object (&scales->dummy_u8_toggle);
g_clear_pointer (&scales->show_rgb_u8_binding, g_binding_unbind);
g_clear_pointer (&scales->show_hsv_binding, g_binding_unbind);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
static void
pika_color_scales_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaColorScales *scales = PIKA_COLOR_SCALES (object);
gboolean hsv;
switch (property_id)
{
case PROP_SHOW_RGB_U8:
g_value_set_boolean (value, scales->show_rgb_u8);
break;
case PROP_SHOW_HSV:
hsv = pika_color_selector_get_model_visible (PIKA_COLOR_SELECTOR (object),
PIKA_COLOR_SELECTOR_MODEL_HSV);
g_value_set_boolean (value, hsv);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_color_scales_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaColorScales *scales = PIKA_COLOR_SCALES (object);
gboolean show_hsv;
switch (property_id)
{
case PROP_SHOW_RGB_U8:
pika_color_scales_set_show_rgb_u8 (scales, g_value_get_boolean (value));
break;
case PROP_SHOW_HSV:
show_hsv = g_value_get_boolean (value);
pika_color_selector_set_model_visible (PIKA_COLOR_SELECTOR (object),
PIKA_COLOR_SELECTOR_MODEL_LCH,
! show_hsv);
pika_color_selector_set_model_visible (PIKA_COLOR_SELECTOR (object),
PIKA_COLOR_SELECTOR_MODEL_HSV,
show_hsv);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_color_scales_togg_sensitive (PikaColorSelector *selector,
gboolean sensitive)
{
PikaColorScales *scales = PIKA_COLOR_SCALES (selector);
gint i;
for (i = 0; i < G_N_ELEMENTS (scale_defs); i++)
if (scales->toggles[i])
gtk_widget_set_sensitive (scales->toggles[i], sensitive);
}
static void
pika_color_scales_togg_visible (PikaColorSelector *selector,
gboolean visible)
{
PikaColorScales *scales = PIKA_COLOR_SCALES (selector);
gint i;
for (i = 0; i < G_N_ELEMENTS (scale_defs); i++)
if (scales->toggles[i])
gtk_widget_set_visible (scales->toggles[i], visible);
}
static void
pika_color_scales_set_show_alpha (PikaColorSelector *selector,
gboolean show_alpha)
{
pika_color_scales_update_visible (PIKA_COLOR_SCALES (selector));
}
static void
pika_color_scales_set_color (PikaColorSelector *selector,
const PikaRGB *rgb,
const PikaHSV *hsv)
{
PikaColorScales *scales = PIKA_COLOR_SCALES (selector);
pika_color_scales_update_scales (scales, -1);
}
static void
pika_color_scales_set_channel (PikaColorSelector *selector,
PikaColorSelectorChannel channel)
{
PikaColorScales *scales = PIKA_COLOR_SCALES (selector);
if (GTK_IS_RADIO_BUTTON (scales->toggles[channel]))
{
g_signal_handlers_block_by_func (scales->toggles[channel],
pika_color_scales_toggle_changed,
scales);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scales->toggles[channel]),
TRUE);
g_signal_handlers_unblock_by_func (scales->toggles[channel],
pika_color_scales_toggle_changed,
scales);
}
}
static void
pika_color_scales_set_model_visible (PikaColorSelector *selector,
PikaColorSelectorModel model,
gboolean visible)
{
pika_color_scales_update_visible (PIKA_COLOR_SCALES (selector));
}
static void
pika_color_scales_set_config (PikaColorSelector *selector,
PikaColorConfig *config)
{
PikaColorScales *scales = PIKA_COLOR_SCALES (selector);
gint i;
g_clear_pointer (&scales->show_rgb_u8_binding, g_binding_unbind);
g_clear_pointer (&scales->show_hsv_binding, g_binding_unbind);
if (config)
{
scales->show_rgb_u8_binding = g_object_bind_property (config, "show-rgb-u8",
scales, "show-rgb-u8",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
scales->show_hsv_binding = g_object_bind_property (config, "show-hsv",
scales, "show-hsv",
G_BINDING_SYNC_CREATE | G_BINDING_BIDIRECTIONAL);
}
for (i = 0; i < G_N_ELEMENTS (scale_defs); i++)
{
if (scales->scales[i])
pika_color_scale_set_color_config (PIKA_COLOR_SCALE (pika_scale_entry_get_range (PIKA_SCALE_ENTRY (scales->scales[i]))),
config);
}
}
/* public functions */
void
pika_color_scales_set_show_rgb_u8 (PikaColorScales *scales,
gboolean show_rgb_u8)
{
g_return_if_fail (PIKA_IS_COLOR_SCALES (scales));
show_rgb_u8 = show_rgb_u8 ? TRUE : FALSE;
if (show_rgb_u8 != scales->show_rgb_u8)
{
scales->show_rgb_u8 = show_rgb_u8;
g_object_notify (G_OBJECT (scales), "show-rgb-u8");
pika_color_scales_update_visible (scales);
}
}
gboolean
pika_color_scales_get_show_rgb_u8 (PikaColorScales *scales)
{
g_return_val_if_fail (PIKA_IS_COLOR_SCALES (scales), FALSE);
return scales->show_rgb_u8;
}
/* private functions */
static void
pika_color_scales_update_visible (PikaColorScales *scales)
{
PikaColorSelector *selector = PIKA_COLOR_SELECTOR (scales);
gboolean show_alpha;
gboolean rgb_visible;
gboolean lch_visible;
gboolean hsv_visible;
show_alpha = pika_color_selector_get_show_alpha (selector);
rgb_visible = pika_color_selector_get_model_visible (selector,
PIKA_COLOR_SELECTOR_MODEL_RGB);
lch_visible = pika_color_selector_get_model_visible (selector,
PIKA_COLOR_SELECTOR_MODEL_LCH);
hsv_visible = pika_color_selector_get_model_visible (selector,
PIKA_COLOR_SELECTOR_MODEL_HSV);
gtk_widget_set_visible (scales->rgb_u8_group,
rgb_visible && scales->show_rgb_u8);
gtk_widget_set_visible (scales->rgb_percent_group,
rgb_visible && ! scales->show_rgb_u8);
gtk_widget_set_visible (scales->lch_group, lch_visible);
gtk_widget_set_visible (scales->hsv_group, hsv_visible);
gtk_widget_set_visible (scales->alpha_percent_group,
show_alpha && ! scales->show_rgb_u8);
gtk_widget_set_visible (scales->alpha_u8_group,
show_alpha && scales->show_rgb_u8);
}
static void
pika_color_scales_update_scales (PikaColorScales *scales,
gint skip)
{
PikaColorSelector *selector = PIKA_COLOR_SELECTOR (scales);
PikaLCH lch;
gdouble values[G_N_ELEMENTS (scale_defs)];
gint i;
babl_process (fish_rgb_to_lch, &selector->rgb, &lch, 1);
values[PIKA_COLOR_SELECTOR_HUE] = selector->hsv.h * 360.0;
values[PIKA_COLOR_SELECTOR_SATURATION] = selector->hsv.s * 100.0;
values[PIKA_COLOR_SELECTOR_VALUE] = selector->hsv.v * 100.0;
values[PIKA_COLOR_SELECTOR_RED] = selector->rgb.r * 100.0;
values[PIKA_COLOR_SELECTOR_GREEN] = selector->rgb.g * 100.0;
values[PIKA_COLOR_SELECTOR_BLUE] = selector->rgb.b * 100.0;
values[PIKA_COLOR_SELECTOR_ALPHA] = selector->rgb.a * 100.0;
values[PIKA_COLOR_SELECTOR_LCH_LIGHTNESS] = lch.l;
values[PIKA_COLOR_SELECTOR_LCH_CHROMA] = lch.c;
values[PIKA_COLOR_SELECTOR_LCH_HUE] = lch.h;
values[PIKA_COLOR_SELECTOR_RED_U8] = selector->rgb.r * 255.0;
values[PIKA_COLOR_SELECTOR_GREEN_U8] = selector->rgb.g * 255.0;
values[PIKA_COLOR_SELECTOR_BLUE_U8] = selector->rgb.b * 255.0;
values[PIKA_COLOR_SELECTOR_ALPHA_U8] = selector->rgb.a * 255.0;
for (i = 0; i < G_N_ELEMENTS (scale_defs); i++)
{
if (i != skip)
{
g_signal_handlers_block_by_func (scales->scales[i],
pika_color_scales_scale_changed,
scales);
pika_label_spin_set_value (PIKA_LABEL_SPIN (scales->scales[i]), values[i]);
g_signal_handlers_unblock_by_func (scales->scales[i],
pika_color_scales_scale_changed,
scales);
}
pika_color_scale_set_color (PIKA_COLOR_SCALE (pika_scale_entry_get_range (PIKA_SCALE_ENTRY (scales->scales[i]))),
&selector->rgb, &selector->hsv);
}
}
static void
pika_color_scales_toggle_changed (GtkWidget *widget,
PikaColorScales *scales)
{
PikaColorSelector *selector = PIKA_COLOR_SELECTOR (scales);
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)))
{
gint i;
for (i = 0; i < G_N_ELEMENTS (scale_defs); i++)
{
if (widget == scales->toggles[i])
{
pika_color_selector_set_channel (selector, i);
if (i < PIKA_COLOR_SELECTOR_RED ||
i > PIKA_COLOR_SELECTOR_BLUE)
{
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (scales->dummy_u8_toggle),
TRUE);
}
break;
}
}
}
}
static void
pika_color_scales_scale_changed (GtkWidget *scale,
PikaColorScales *scales)
{
PikaColorSelector *selector = PIKA_COLOR_SELECTOR (scales);
gdouble value = pika_label_spin_get_value (PIKA_LABEL_SPIN (scale));
PikaLCH lch;
gint i;
for (i = 0; i < G_N_ELEMENTS (scale_defs); i++)
if (scales->scales[i] == scale)
break;
switch (i)
{
case PIKA_COLOR_SELECTOR_HUE:
selector->hsv.h = value / 360.0;
break;
case PIKA_COLOR_SELECTOR_SATURATION:
selector->hsv.s = value / 100.0;
break;
case PIKA_COLOR_SELECTOR_VALUE:
selector->hsv.v = value / 100.0;
break;
case PIKA_COLOR_SELECTOR_RED:
selector->rgb.r = value / 100.0;
break;
case PIKA_COLOR_SELECTOR_GREEN:
selector->rgb.g = value / 100.0;
break;
case PIKA_COLOR_SELECTOR_BLUE:
selector->rgb.b = value / 100.0;
break;
case PIKA_COLOR_SELECTOR_ALPHA:
selector->hsv.a = selector->rgb.a = value / 100.0;
break;
case PIKA_COLOR_SELECTOR_LCH_LIGHTNESS:
babl_process (fish_rgb_to_lch, &selector->rgb, &lch, 1);
lch.l = value;
break;
case PIKA_COLOR_SELECTOR_LCH_CHROMA:
babl_process (fish_rgb_to_lch, &selector->rgb, &lch, 1);
lch.c = value;
break;
case PIKA_COLOR_SELECTOR_LCH_HUE:
babl_process (fish_rgb_to_lch, &selector->rgb, &lch, 1);
lch.h = value;
break;
case PIKA_COLOR_SELECTOR_RED_U8:
selector->rgb.r = value / 255.0;
break;
case PIKA_COLOR_SELECTOR_GREEN_U8:
selector->rgb.g = value / 255.0;
break;
case PIKA_COLOR_SELECTOR_BLUE_U8:
selector->rgb.b = value / 255.0;
break;
case PIKA_COLOR_SELECTOR_ALPHA_U8:
selector->hsv.a = selector->rgb.a = value / 255.0;
break;
}
if ((i >= PIKA_COLOR_SELECTOR_HUE) &&
(i <= PIKA_COLOR_SELECTOR_VALUE))
{
pika_hsv_to_rgb (&selector->hsv, &selector->rgb);
}
else if ((i >= PIKA_COLOR_SELECTOR_LCH_LIGHTNESS) &&
(i <= PIKA_COLOR_SELECTOR_LCH_HUE))
{
babl_process (fish_lch_to_rgb, &lch, &selector->rgb, 1);
pika_rgb_to_hsv (&selector->rgb, &selector->hsv);
}
else if ((i >= PIKA_COLOR_SELECTOR_RED) &&
(i <= PIKA_COLOR_SELECTOR_BLUE))
{
pika_rgb_to_hsv (&selector->rgb, &selector->hsv);
}
else if ((i >= PIKA_COLOR_SELECTOR_RED_U8) &&
(i <= PIKA_COLOR_SELECTOR_BLUE_U8))
{
pika_rgb_to_hsv (&selector->rgb, &selector->hsv);
}
pika_color_scales_update_scales (scales, i);
pika_color_selector_emit_color_changed (selector);
}
static void
pika_color_scales_toggle_lch_hsv (GtkToggleButton *toggle,
PikaColorScales *scales)
{
PikaColorSelector *selector = PIKA_COLOR_SELECTOR (scales);
gboolean show_hsv = ! gtk_toggle_button_get_active (toggle);
pika_color_selector_set_model_visible (selector,
PIKA_COLOR_SELECTOR_MODEL_LCH,
! show_hsv);
pika_color_selector_set_model_visible (selector,
PIKA_COLOR_SELECTOR_MODEL_HSV,
show_hsv);
g_object_set (scales, "show-hsv", show_hsv, NULL);
}

View File

@ -0,0 +1,49 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorscales.h
* Copyright (C) 2002 Michael Natterer <mitch@gimp.org>
*
* based on color_notebook module
* Copyright (C) 1998 Austin Donnelly <austin@greenend.org.uk>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_SCALES_H__
#define __PIKA_COLOR_SCALES_H__
G_BEGIN_DECLS
#define PIKA_TYPE_COLOR_SCALES (pika_color_scales_get_type ())
#define PIKA_COLOR_SCALES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_SCALES, PikaColorScales))
#define PIKA_IS_COLOR_SCALES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_SCALES))
GType pika_color_scales_get_type (void) G_GNUC_CONST;
void pika_color_scales_set_show_rgb_u8 (PikaColorScales *scales,
gboolean show_rgb_u8);
gboolean pika_color_scales_get_show_rgb_u8 (PikaColorScales *scales);
G_END_DECLS
#endif /* __PIKA_COLOR_SCALES_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,41 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorselect.h
* Copyright (C) 2002 Michael Natterer <mitch@gimp.org>
*
* based on color_notebook module
* Copyright (C) 1998 Austin Donnelly <austin@greenend.org.uk>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_COLOR_SELECT_H__
#define __PIKA_COLOR_SELECT_H__
G_BEGIN_DECLS
#define PIKA_TYPE_COLOR_SELECT (pika_color_select_get_type ())
#define PIKA_COLOR_SELECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_SELECT, PikaColorSelect))
#define PIKA_IS_COLOR_SELECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_SELECT))
GType pika_color_select_get_type (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __PIKA_COLOR_SELECT_H__ */

View File

@ -0,0 +1,823 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorselection.c
* Copyright (C) 2003 Michael Natterer <mitch@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikacolor/pikacolor.h"
#include "libpikaconfig/pikaconfig.h"
#include "pikawidgetstypes.h"
#include "pikacolorarea.h"
#include "pikacolornotebook.h"
#include "pikacolorscales.h"
#include "pikacolorselect.h"
#include "pikacolorselection.h"
#include "pikahelpui.h"
#include "pikaicons.h"
#include "pikawidgets.h"
#include "pikawidgets-private.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikacolorselection
* @title: PikaColorSelection
* @short_description: Widget for doing a color selection.
*
* Widget for doing a color selection.
**/
#define COLOR_AREA_SIZE 20
typedef enum
{
UPDATE_NOTEBOOK = 1 << 0,
UPDATE_SCALES = 1 << 1,
UPDATE_ENTRY = 1 << 2,
UPDATE_COLOR = 1 << 3
} UpdateType;
#define UPDATE_ALL (UPDATE_NOTEBOOK | \
UPDATE_SCALES | \
UPDATE_ENTRY | \
UPDATE_COLOR)
enum
{
COLOR_CHANGED,
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_CONFIG
};
struct _PikaColorSelectionPrivate
{
gboolean show_alpha;
PikaHSV hsv;
PikaRGB rgb;
PikaColorSelectorChannel channel;
GtkWidget *left_vbox;
GtkWidget *right_vbox;
GtkWidget *notebook;
GtkWidget *scales;
GtkWidget *new_color;
GtkWidget *old_color;
};
#define GET_PRIVATE(obj) (((PikaColorSelection *) (obj))->priv)
static void pika_color_selection_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_color_selection_switch_page (GtkWidget *widget,
gpointer page,
guint page_num,
PikaColorSelection *selection);
static void pika_color_selection_notebook_changed (PikaColorSelector *selector,
const PikaRGB *rgb,
const PikaHSV *hsv,
PikaColorSelection *selection);
static void pika_color_selection_scales_changed (PikaColorSelector *selector,
const PikaRGB *rgb,
const PikaHSV *hsv,
PikaColorSelection *selection);
static void pika_color_selection_color_picked (GtkWidget *widget,
const PikaRGB *rgb,
PikaColorSelection *selection);
static void pika_color_selection_entry_changed (PikaColorHexEntry *entry,
PikaColorSelection *selection);
static void pika_color_selection_channel_changed (PikaColorSelector *selector,
PikaColorSelectorChannel channel,
PikaColorSelection *selection);
static void pika_color_selection_new_color_changed (GtkWidget *widget,
PikaColorSelection *selection);
static void pika_color_selection_update (PikaColorSelection *selection,
UpdateType update);
G_DEFINE_TYPE_WITH_PRIVATE (PikaColorSelection, pika_color_selection,
GTK_TYPE_BOX)
#define parent_class pika_color_selection_parent_class
static guint selection_signals[LAST_SIGNAL] = { 0, };
static void
pika_color_selection_class_init (PikaColorSelectionClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = pika_color_selection_set_property;
klass->color_changed = NULL;
g_object_class_install_property (object_class, PROP_CONFIG,
g_param_spec_object ("config",
"Config",
"The color config used by this color selection",
PIKA_TYPE_COLOR_CONFIG,
G_PARAM_WRITABLE));
selection_signals[COLOR_CHANGED] =
g_signal_new ("color-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaColorSelectionClass, color_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (klass), "PikaColorSelection");
}
static void
pika_color_selection_init (PikaColorSelection *selection)
{
PikaColorSelectionPrivate *priv;
GtkWidget *main_hbox;
GtkWidget *hbox;
GtkWidget *vbox;
GtkWidget *frame;
GtkWidget *label;
GtkWidget *entry;
GtkWidget *button;
GtkSizeGroup *new_group;
GtkSizeGroup *old_group;
selection->priv = pika_color_selection_get_instance_private (selection);
priv = selection->priv;
priv->show_alpha = TRUE;
gtk_orientable_set_orientation (GTK_ORIENTABLE (selection),
GTK_ORIENTATION_VERTICAL);
pika_rgba_set (&priv->rgb, 0.0, 0.0, 0.0, 1.0);
pika_rgb_to_hsv (&priv->rgb, &priv->hsv);
priv->channel = PIKA_COLOR_SELECTOR_RED;
main_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (selection), main_hbox, TRUE, TRUE, 0);
gtk_widget_show (main_hbox);
/* The left vbox with the notebook */
priv->left_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_box_pack_start (GTK_BOX (main_hbox), priv->left_vbox,
TRUE, TRUE, 0);
gtk_widget_show (priv->left_vbox);
if (_pika_ensure_modules_func)
{
g_type_class_ref (PIKA_TYPE_COLOR_SELECT);
_pika_ensure_modules_func ();
}
priv->notebook = pika_color_selector_new (PIKA_TYPE_COLOR_NOTEBOOK,
&priv->rgb,
&priv->hsv,
priv->channel);
if (_pika_ensure_modules_func)
g_type_class_unref (g_type_class_peek (PIKA_TYPE_COLOR_SELECT));
pika_color_selector_set_toggles_visible
(PIKA_COLOR_SELECTOR (priv->notebook), FALSE);
gtk_box_pack_start (GTK_BOX (priv->left_vbox), priv->notebook,
TRUE, TRUE, 0);
gtk_widget_show (priv->notebook);
g_signal_connect (priv->notebook, "color-changed",
G_CALLBACK (pika_color_selection_notebook_changed),
selection);
g_signal_connect (pika_color_notebook_get_notebook (PIKA_COLOR_NOTEBOOK (priv->notebook)),
"switch-page",
G_CALLBACK (pika_color_selection_switch_page),
selection);
/* The hbox for the color_areas */
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_end (GTK_BOX (priv->left_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
/* The labels */
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0);
gtk_widget_show (vbox);
label = gtk_label_new (_("Current:"));
gtk_label_set_xalign (GTK_LABEL (label), 1.0);
gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
gtk_widget_show (label);
new_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
gtk_size_group_add_widget (new_group, label);
g_object_unref (new_group);
label = gtk_label_new (_("Old:"));
gtk_label_set_xalign (GTK_LABEL (label), 1.0);
gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
gtk_widget_show (label);
old_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
gtk_size_group_add_widget (old_group, label);
g_object_unref (old_group);
/* The color areas */
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
gtk_widget_show (frame);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
gtk_container_add (GTK_CONTAINER (frame), vbox);
gtk_widget_show (vbox);
priv->new_color = pika_color_area_new (&priv->rgb,
priv->show_alpha ?
PIKA_COLOR_AREA_SMALL_CHECKS :
PIKA_COLOR_AREA_FLAT,
GDK_BUTTON1_MASK |
GDK_BUTTON2_MASK);
gtk_size_group_add_widget (new_group, priv->new_color);
gtk_box_pack_start (GTK_BOX (vbox), priv->new_color, FALSE, FALSE, 0);
gtk_widget_show (priv->new_color);
g_signal_connect (priv->new_color, "color-changed",
G_CALLBACK (pika_color_selection_new_color_changed),
selection);
priv->old_color = pika_color_area_new (&priv->rgb,
priv->show_alpha ?
PIKA_COLOR_AREA_SMALL_CHECKS :
PIKA_COLOR_AREA_FLAT,
GDK_BUTTON1_MASK |
GDK_BUTTON2_MASK);
gtk_drag_dest_unset (priv->old_color);
gtk_size_group_add_widget (old_group, priv->old_color);
gtk_box_pack_start (GTK_BOX (vbox), priv->old_color, FALSE, FALSE, 0);
gtk_widget_show (priv->old_color);
/* The right vbox with color scales */
priv->right_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
gtk_box_pack_start (GTK_BOX (main_hbox), priv->right_vbox,
TRUE, TRUE, 0);
gtk_widget_show (priv->right_vbox);
priv->scales = pika_color_selector_new (PIKA_TYPE_COLOR_SCALES,
&priv->rgb,
&priv->hsv,
priv->channel);
pika_color_selector_set_toggles_visible
(PIKA_COLOR_SELECTOR (priv->scales), TRUE);
pika_color_selector_set_show_alpha (PIKA_COLOR_SELECTOR (priv->scales),
priv->show_alpha);
gtk_box_pack_start (GTK_BOX (priv->right_vbox), priv->scales,
TRUE, TRUE, 0);
gtk_widget_show (priv->scales);
g_signal_connect (priv->scales, "channel-changed",
G_CALLBACK (pika_color_selection_channel_changed),
selection);
g_signal_connect (priv->scales, "color-changed",
G_CALLBACK (pika_color_selection_scales_changed),
selection);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
gtk_box_pack_start (GTK_BOX (priv->right_vbox), hbox, FALSE, FALSE, 0);
gtk_widget_show (hbox);
/* The color picker */
button = pika_pick_button_new ();
gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_signal_connect (button, "color-picked",
G_CALLBACK (pika_color_selection_color_picked),
selection);
/* The hex triplet entry */
entry = pika_color_hex_entry_new ();
gtk_box_pack_end (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
gtk_widget_show (entry);
label = gtk_label_new_with_mnemonic (_("HTML _notation:"));
gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
g_object_set_data (G_OBJECT (selection), "color-hex-entry", entry);
g_signal_connect (entry, "color-changed",
G_CALLBACK (pika_color_selection_entry_changed),
selection);
}
static void
pika_color_selection_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaColorSelection *selection = PIKA_COLOR_SELECTION (object);
switch (property_id)
{
case PROP_CONFIG:
pika_color_selection_set_config (selection, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/**
* pika_color_selection_new:
*
* Creates a new #PikaColorSelection widget.
*
* Returns: The new #PikaColorSelection widget.
**/
GtkWidget *
pika_color_selection_new (void)
{
return g_object_new (PIKA_TYPE_COLOR_SELECTION, NULL);
}
/**
* pika_color_selection_set_show_alpha:
* @selection: A #PikaColorSelection widget.
* @show_alpha: The new @show_alpha setting.
*
* Sets the @show_alpha property of the @selection widget.
**/
void
pika_color_selection_set_show_alpha (PikaColorSelection *selection,
gboolean show_alpha)
{
PikaColorSelectionPrivate *priv;
g_return_if_fail (PIKA_IS_COLOR_SELECTION (selection));
priv = GET_PRIVATE (selection);
if (show_alpha != priv->show_alpha)
{
priv->show_alpha = show_alpha ? TRUE : FALSE;
pika_color_selector_set_show_alpha
(PIKA_COLOR_SELECTOR (priv->notebook), priv->show_alpha);
pika_color_selector_set_show_alpha
(PIKA_COLOR_SELECTOR (priv->scales), priv->show_alpha);
pika_color_area_set_type (PIKA_COLOR_AREA (priv->new_color),
priv->show_alpha ?
PIKA_COLOR_AREA_SMALL_CHECKS :
PIKA_COLOR_AREA_FLAT);
pika_color_area_set_type (PIKA_COLOR_AREA (priv->old_color),
priv->show_alpha ?
PIKA_COLOR_AREA_SMALL_CHECKS :
PIKA_COLOR_AREA_FLAT);
}
}
/**
* pika_color_selection_get_show_alpha:
* @selection: A #PikaColorSelection widget.
*
* Returns the @selection's @show_alpha property.
*
* Returns: %TRUE if the #PikaColorSelection has alpha controls.
**/
gboolean
pika_color_selection_get_show_alpha (PikaColorSelection *selection)
{
g_return_val_if_fail (PIKA_IS_COLOR_SELECTION (selection), FALSE);
return GET_PRIVATE (selection)->show_alpha;
}
/**
* pika_color_selection_set_color:
* @selection: A #PikaColorSelection widget.
* @color: The @color to set as current color.
*
* Sets the #PikaColorSelection's current color to the new @color.
**/
void
pika_color_selection_set_color (PikaColorSelection *selection,
const PikaRGB *color)
{
PikaColorSelectionPrivate *priv;
g_return_if_fail (PIKA_IS_COLOR_SELECTION (selection));
g_return_if_fail (color != NULL);
priv = GET_PRIVATE (selection);
priv->rgb = *color;
pika_rgb_to_hsv (&priv->rgb, &priv->hsv);
pika_color_selection_update (selection, UPDATE_ALL);
pika_color_selection_color_changed (selection);
}
/**
* pika_color_selection_get_color:
* @selection: A #PikaColorSelection widget.
* @color: (out caller-allocates): Return location for the
* @selection's current @color.
*
* This function returns the #PikaColorSelection's current color.
**/
void
pika_color_selection_get_color (PikaColorSelection *selection,
PikaRGB *color)
{
g_return_if_fail (PIKA_IS_COLOR_SELECTION (selection));
g_return_if_fail (color != NULL);
*color = GET_PRIVATE (selection)->rgb;
}
/**
* pika_color_selection_set_old_color:
* @selection: A #PikaColorSelection widget.
* @color: The @color to set as old color.
*
* Sets the #PikaColorSelection's old color.
**/
void
pika_color_selection_set_old_color (PikaColorSelection *selection,
const PikaRGB *color)
{
PikaColorSelectionPrivate *priv;
g_return_if_fail (PIKA_IS_COLOR_SELECTION (selection));
g_return_if_fail (color != NULL);
priv = GET_PRIVATE (selection);
pika_color_area_set_color (PIKA_COLOR_AREA (priv->old_color), color);
}
/**
* pika_color_selection_get_old_color:
* @selection: A #PikaColorSelection widget.
* @color: (out caller-allocates): Return location for the
* @selection's old @color.
*
* This function returns the #PikaColorSelection's old color.
**/
void
pika_color_selection_get_old_color (PikaColorSelection *selection,
PikaRGB *color)
{
PikaColorSelectionPrivate *priv;
g_return_if_fail (PIKA_IS_COLOR_SELECTION (selection));
g_return_if_fail (color != NULL);
priv = GET_PRIVATE (selection);
pika_color_area_get_color (PIKA_COLOR_AREA (priv->old_color), color);
}
/**
* pika_color_selection_reset:
* @selection: A #PikaColorSelection widget.
*
* Sets the #PikaColorSelection's current color to its old color.
**/
void
pika_color_selection_reset (PikaColorSelection *selection)
{
PikaColorSelectionPrivate *priv;
PikaRGB color;
g_return_if_fail (PIKA_IS_COLOR_SELECTION (selection));
priv = GET_PRIVATE (selection);
pika_color_area_get_color (PIKA_COLOR_AREA (priv->old_color), &color);
pika_color_selection_set_color (selection, &color);
}
/**
* pika_color_selection_color_changed:
* @selection: A #PikaColorSelection widget.
*
* Emits the "color-changed" signal.
**/
void
pika_color_selection_color_changed (PikaColorSelection *selection)
{
g_return_if_fail (PIKA_IS_COLOR_SELECTION (selection));
g_signal_emit (selection, selection_signals[COLOR_CHANGED], 0);
}
/**
* pika_color_selection_set_simulation:
* @selection: A #PikaColorSelection widget.
* @profile: A #PikaColorProfile object.
* @intent: A #PikaColorRenderingIntent enum.
* @bpc: A gboolean.
*
* Sets the simulation options to use with this color selection.
*
* Since: 3.0
*/
void
pika_color_selection_set_simulation (PikaColorSelection *selection,
PikaColorProfile *profile,
PikaColorRenderingIntent intent,
gboolean bpc)
{
g_return_if_fail (PIKA_IS_COLOR_SELECTION (selection));
pika_color_notebook_set_simulation (PIKA_COLOR_NOTEBOOK (selection->priv->notebook),
profile,
intent,
bpc);
g_signal_emit (selection, selection_signals[COLOR_CHANGED], 0);
}
/**
* pika_color_selection_set_config:
* @selection: A #PikaColorSelection widget.
* @config: A #PikaColorConfig object.
*
* Sets the color management configuration to use with this color selection.
*
* Since: 2.4
*/
void
pika_color_selection_set_config (PikaColorSelection *selection,
PikaColorConfig *config)
{
PikaColorSelectionPrivate *priv;
g_return_if_fail (PIKA_IS_COLOR_SELECTION (selection));
g_return_if_fail (config == NULL || PIKA_IS_COLOR_CONFIG (config));
priv = GET_PRIVATE (selection);
pika_color_selector_set_config (PIKA_COLOR_SELECTOR (priv->notebook),
config);
pika_color_selector_set_config (PIKA_COLOR_SELECTOR (priv->scales),
config);
pika_color_area_set_color_config (PIKA_COLOR_AREA (priv->old_color),
config);
pika_color_area_set_color_config (PIKA_COLOR_AREA (priv->new_color),
config);
}
/**
* pika_color_selection_get_notebook:
* @selection: A #PikaColorSelection widget.
*
* Returns: (transfer none): The selection's #PikaColorNotebook.
*
* Since: 3.0
*/
GtkWidget *
pika_color_selection_get_notebook (PikaColorSelection *selection)
{
g_return_val_if_fail (PIKA_IS_COLOR_SELECTION (selection), NULL);
return GET_PRIVATE (selection)->notebook;
}
/**
* pika_color_selection_get_right_vbox:
* @selection: A #PikaColorSelection widget.
*
* Returns: (transfer none) (type GtkBox): The selection's right #GtkBox which
* contains the color scales.
*
* Since: 3.0
*/
GtkWidget *
pika_color_selection_get_right_vbox (PikaColorSelection *selection)
{
g_return_val_if_fail (PIKA_IS_COLOR_SELECTION (selection), NULL);
return GET_PRIVATE (selection)->right_vbox;
}
/* private functions */
static void
pika_color_selection_switch_page (GtkWidget *widget,
gpointer page,
guint page_num,
PikaColorSelection *selection)
{
PikaColorSelectionPrivate *priv = GET_PRIVATE (selection);
PikaColorNotebook *notebook = PIKA_COLOR_NOTEBOOK (priv->notebook);
PikaColorSelector *current;
gboolean sensitive;
current = pika_color_notebook_get_current_selector (notebook);
sensitive = (PIKA_COLOR_SELECTOR_GET_CLASS (current)->set_channel != NULL);
pika_color_selector_set_toggles_sensitive
(PIKA_COLOR_SELECTOR (priv->scales), sensitive);
}
static void
pika_color_selection_notebook_changed (PikaColorSelector *selector,
const PikaRGB *rgb,
const PikaHSV *hsv,
PikaColorSelection *selection)
{
PikaColorSelectionPrivate *priv = GET_PRIVATE (selection);
priv->hsv = *hsv;
priv->rgb = *rgb;
pika_color_selection_update (selection,
UPDATE_SCALES | UPDATE_ENTRY | UPDATE_COLOR);
pika_color_selection_color_changed (selection);
}
static void
pika_color_selection_scales_changed (PikaColorSelector *selector,
const PikaRGB *rgb,
const PikaHSV *hsv,
PikaColorSelection *selection)
{
PikaColorSelectionPrivate *priv = GET_PRIVATE (selection);
priv->rgb = *rgb;
priv->hsv = *hsv;
pika_color_selection_update (selection,
UPDATE_ENTRY | UPDATE_NOTEBOOK | UPDATE_COLOR);
pika_color_selection_color_changed (selection);
}
static void
pika_color_selection_color_picked (GtkWidget *widget,
const PikaRGB *rgb,
PikaColorSelection *selection)
{
pika_color_selection_set_color (selection, rgb);
}
static void
pika_color_selection_entry_changed (PikaColorHexEntry *entry,
PikaColorSelection *selection)
{
PikaColorSelectionPrivate *priv = GET_PRIVATE (selection);
pika_color_hex_entry_get_color (entry, &priv->rgb);
pika_rgb_to_hsv (&priv->rgb, &priv->hsv);
pika_color_selection_update (selection,
UPDATE_NOTEBOOK | UPDATE_SCALES | UPDATE_COLOR);
pika_color_selection_color_changed (selection);
}
static void
pika_color_selection_channel_changed (PikaColorSelector *selector,
PikaColorSelectorChannel channel,
PikaColorSelection *selection)
{
PikaColorSelectionPrivate *priv = GET_PRIVATE (selection);
priv->channel = channel;
pika_color_selector_set_channel (PIKA_COLOR_SELECTOR (priv->notebook),
priv->channel);
}
static void
pika_color_selection_new_color_changed (GtkWidget *widget,
PikaColorSelection *selection)
{
PikaColorSelectionPrivate *priv = GET_PRIVATE (selection);
pika_color_area_get_color (PIKA_COLOR_AREA (widget), &priv->rgb);
pika_rgb_to_hsv (&priv->rgb, &priv->hsv);
pika_color_selection_update (selection,
UPDATE_NOTEBOOK | UPDATE_SCALES | UPDATE_ENTRY);
pika_color_selection_color_changed (selection);
}
static void
pika_color_selection_update (PikaColorSelection *selection,
UpdateType update)
{
PikaColorSelectionPrivate *priv = GET_PRIVATE (selection);
if (update & UPDATE_NOTEBOOK)
{
g_signal_handlers_block_by_func (priv->notebook,
pika_color_selection_notebook_changed,
selection);
pika_color_selector_set_color (PIKA_COLOR_SELECTOR (priv->notebook),
&priv->rgb,
&priv->hsv);
g_signal_handlers_unblock_by_func (priv->notebook,
pika_color_selection_notebook_changed,
selection);
}
if (update & UPDATE_SCALES)
{
g_signal_handlers_block_by_func (priv->scales,
pika_color_selection_scales_changed,
selection);
pika_color_selector_set_color (PIKA_COLOR_SELECTOR (priv->scales),
&priv->rgb,
&priv->hsv);
g_signal_handlers_unblock_by_func (priv->scales,
pika_color_selection_scales_changed,
selection);
}
if (update & UPDATE_ENTRY)
{
PikaColorHexEntry *entry;
entry = g_object_get_data (G_OBJECT (selection), "color-hex-entry");
g_signal_handlers_block_by_func (entry,
pika_color_selection_entry_changed,
selection);
pika_color_hex_entry_set_color (entry, &priv->rgb);
g_signal_handlers_unblock_by_func (entry,
pika_color_selection_entry_changed,
selection);
}
if (update & UPDATE_COLOR)
{
g_signal_handlers_block_by_func (priv->new_color,
pika_color_selection_new_color_changed,
selection);
pika_color_area_set_color (PIKA_COLOR_AREA (priv->new_color),
&priv->rgb);
g_signal_handlers_unblock_by_func (priv->new_color,
pika_color_selection_new_color_changed,
selection);
}
}

View File

@ -0,0 +1,106 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorselection.h
* Copyright (C) 2003 Michael Natterer <mitch@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_SELECTION_H__
#define __PIKA_COLOR_SELECTION_H__
G_BEGIN_DECLS
/* For information look at the html documentation */
#define PIKA_TYPE_COLOR_SELECTION (pika_color_selection_get_type ())
#define PIKA_COLOR_SELECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_SELECTION, PikaColorSelection))
#define PIKA_COLOR_SELECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_SELECTION, PikaColorSelectionClass))
#define PIKA_IS_COLOR_SELECTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_SELECTION))
#define PIKA_IS_COLOR_SELECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_SELECTION))
#define PIKA_COLOR_SELECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_SELECTION, PikaColorSelectionClass))
typedef struct _PikaColorSelectionPrivate PikaColorSelectionPrivate;
typedef struct _PikaColorSelectionClass PikaColorSelectionClass;
struct _PikaColorSelection
{
GtkBox parent_instance;
PikaColorSelectionPrivate *priv;
};
struct _PikaColorSelectionClass
{
GtkBoxClass parent_class;
void (* color_changed) (PikaColorSelection *selection);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_color_selection_get_type (void) G_GNUC_CONST;
GtkWidget * pika_color_selection_new (void);
void pika_color_selection_set_show_alpha (PikaColorSelection *selection,
gboolean show_alpha);
gboolean pika_color_selection_get_show_alpha (PikaColorSelection *selection);
void pika_color_selection_set_color (PikaColorSelection *selection,
const PikaRGB *color);
void pika_color_selection_get_color (PikaColorSelection *selection,
PikaRGB *color);
void pika_color_selection_set_old_color (PikaColorSelection *selection,
const PikaRGB *color);
void pika_color_selection_get_old_color (PikaColorSelection *selection,
PikaRGB *color);
void pika_color_selection_reset (PikaColorSelection *selection);
void pika_color_selection_color_changed (PikaColorSelection *selection);
void pika_color_selection_set_simulation (PikaColorSelection *selection,
PikaColorProfile *profile,
PikaColorRenderingIntent intent,
gboolean bpc);
void pika_color_selection_set_config (PikaColorSelection *selection,
PikaColorConfig *config);
GtkWidget * pika_color_selection_get_notebook (PikaColorSelection *selection);
GtkWidget * pika_color_selection_get_right_vbox (PikaColorSelection *selection);
G_END_DECLS
#endif /* __PIKA_COLOR_SELECTION_H__ */

View File

@ -0,0 +1,668 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorselector.c
* Copyright (C) 2002 Michael Natterer <mitch@gimp.org>
*
* based on:
* Colour selector module
* Copyright (C) 1999 Austin Donnelly <austin@greenend.org.uk>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikacolor/pikacolor.h"
#include "libpikaconfig/pikaconfig.h"
#include "pikawidgetstypes.h"
#include "pikacolorselector.h"
#include "pikaicons.h"
#include "pikawidgetsmarshal.h"
/**
* SECTION: pikacolorselector
* @title: PikaColorSelector
* @short_description: Pluggable PIKA color selector modules.
* @see_also: #GModule, #GTypeModule, #PikaModule
*
* Functions and definitions for creating pluggable PIKA color
* selector modules.
**/
enum
{
COLOR_CHANGED,
CHANNEL_CHANGED,
MODEL_VISIBLE_CHANGED,
LAST_SIGNAL
};
struct _PikaColorSelectorPrivate
{
gboolean model_visible[3];
};
#define GET_PRIVATE(obj) (((PikaColorSelector *) (obj))->priv)
static void pika_color_selector_dispose (GObject *object);
G_DEFINE_TYPE_WITH_PRIVATE (PikaColorSelector, pika_color_selector,
GTK_TYPE_BOX)
#define parent_class pika_color_selector_parent_class
static guint selector_signals[LAST_SIGNAL] = { 0 };
static void
pika_color_selector_class_init (PikaColorSelectorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->dispose = pika_color_selector_dispose;
selector_signals[COLOR_CHANGED] =
g_signal_new ("color-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaColorSelectorClass, color_changed),
NULL, NULL,
_pika_widgets_marshal_VOID__BOXED_BOXED,
G_TYPE_NONE, 2,
PIKA_TYPE_RGB,
PIKA_TYPE_RGB);
selector_signals[CHANNEL_CHANGED] =
g_signal_new ("channel-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaColorSelectorClass, channel_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
PIKA_TYPE_COLOR_SELECTOR_CHANNEL);
selector_signals[MODEL_VISIBLE_CHANGED] =
g_signal_new ("model-visible-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaColorSelectorClass, model_visible_changed),
NULL, NULL,
_pika_widgets_marshal_VOID__ENUM_BOOLEAN,
G_TYPE_NONE, 2,
PIKA_TYPE_COLOR_SELECTOR_MODEL,
G_TYPE_BOOLEAN);
klass->name = "Unnamed";
klass->help_id = NULL;
klass->icon_name = PIKA_ICON_PALETTE;
klass->set_toggles_visible = NULL;
klass->set_toggles_sensitive = NULL;
klass->set_show_alpha = NULL;
klass->set_color = NULL;
klass->set_channel = NULL;
klass->set_model_visible = NULL;
klass->color_changed = NULL;
klass->channel_changed = NULL;
klass->model_visible_changed = NULL;
klass->set_config = NULL;
}
static void
pika_color_selector_init (PikaColorSelector *selector)
{
PikaColorSelectorPrivate *priv;
selector->priv = pika_color_selector_get_instance_private (selector);
priv = GET_PRIVATE (selector);
selector->toggles_visible = TRUE;
selector->toggles_sensitive = TRUE;
selector->show_alpha = TRUE;
gtk_orientable_set_orientation (GTK_ORIENTABLE (selector),
GTK_ORIENTATION_VERTICAL);
pika_rgba_set (&selector->rgb, 0.0, 0.0, 0.0, 1.0);
pika_rgb_to_hsv (&selector->rgb, &selector->hsv);
selector->channel = PIKA_COLOR_SELECTOR_RED;
priv->model_visible[PIKA_COLOR_SELECTOR_MODEL_RGB] = TRUE;
priv->model_visible[PIKA_COLOR_SELECTOR_MODEL_LCH] = TRUE;
priv->model_visible[PIKA_COLOR_SELECTOR_MODEL_HSV] = FALSE;
}
static void
pika_color_selector_dispose (GObject *object)
{
pika_color_selector_set_config (PIKA_COLOR_SELECTOR (object), NULL);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
/* public functions */
/**
* pika_color_selector_new:
* @selector_type: The #GType of the selector to create.
* @rgb: The initial color to be edited.
* @hsv: The same color in HSV.
* @channel: The selector's initial channel.
*
* Creates a new #PikaColorSelector widget of type @selector_type.
*
* Note that this is mostly internal API to be used by other widgets.
*
* Please use pika_color_selection_new() for the "PIKA-typical" color
* selection widget. Also see pika_color_button_new().
*
* Retunn value: the new #PikaColorSelector widget.
**/
GtkWidget *
pika_color_selector_new (GType selector_type,
const PikaRGB *rgb,
const PikaHSV *hsv,
PikaColorSelectorChannel channel)
{
PikaColorSelector *selector;
g_return_val_if_fail (g_type_is_a (selector_type, PIKA_TYPE_COLOR_SELECTOR),
NULL);
g_return_val_if_fail (rgb != NULL, NULL);
g_return_val_if_fail (hsv != NULL, NULL);
selector = g_object_new (selector_type, NULL);
pika_color_selector_set_color (selector, rgb, hsv);
pika_color_selector_set_channel (selector, channel);
return GTK_WIDGET (selector);
}
/**
* pika_color_selector_set_toggles_visible:
* @selector: A #PikaColorSelector widget.
* @visible: The new @visible setting.
*
* Sets the @visible property of the @selector's toggles.
*
* This function has no effect if this @selector instance has no
* toggles to switch channels.
**/
void
pika_color_selector_set_toggles_visible (PikaColorSelector *selector,
gboolean visible)
{
g_return_if_fail (PIKA_IS_COLOR_SELECTOR (selector));
if (selector->toggles_visible != visible)
{
PikaColorSelectorClass *selector_class;
selector->toggles_visible = visible ? TRUE : FALSE;
selector_class = PIKA_COLOR_SELECTOR_GET_CLASS (selector);
if (selector_class->set_toggles_visible)
selector_class->set_toggles_visible (selector, visible);
}
}
/**
* pika_color_selector_get_toggles_visible:
* @selector: A #PikaColorSelector widget.
*
* Returns the @visible property of the @selector's toggles.
*
* Returns: %TRUE if the #PikaColorSelector's toggles are visible.
*
* Since: 2.10
**/
gboolean
pika_color_selector_get_toggles_visible (PikaColorSelector *selector)
{
g_return_val_if_fail (PIKA_IS_COLOR_SELECTOR (selector), FALSE);
return selector->toggles_visible;
}
/**
* pika_color_selector_set_toggles_sensitive:
* @selector: A #PikaColorSelector widget.
* @sensitive: The new @sensitive setting.
*
* Sets the @sensitive property of the @selector's toggles.
*
* This function has no effect if this @selector instance has no
* toggles to switch channels.
**/
void
pika_color_selector_set_toggles_sensitive (PikaColorSelector *selector,
gboolean sensitive)
{
g_return_if_fail (PIKA_IS_COLOR_SELECTOR (selector));
if (selector->toggles_sensitive != sensitive)
{
PikaColorSelectorClass *selector_class;
selector->toggles_sensitive = sensitive ? TRUE : FALSE;
selector_class = PIKA_COLOR_SELECTOR_GET_CLASS (selector);
if (selector_class->set_toggles_sensitive)
selector_class->set_toggles_sensitive (selector, sensitive);
}
}
/**
* pika_color_selector_get_toggles_sensitive:
* @selector: A #PikaColorSelector widget.
*
* Returns the @sensitive property of the @selector's toggles.
*
* Returns: %TRUE if the #PikaColorSelector's toggles are sensitive.
*
* Since: 2.10
**/
gboolean
pika_color_selector_get_toggles_sensitive (PikaColorSelector *selector)
{
g_return_val_if_fail (PIKA_IS_COLOR_SELECTOR (selector), FALSE);
return selector->toggles_sensitive;
}
/**
* pika_color_selector_set_show_alpha:
* @selector: A #PikaColorSelector widget.
* @show_alpha: The new @show_alpha setting.
*
* Sets the @show_alpha property of the @selector widget.
**/
void
pika_color_selector_set_show_alpha (PikaColorSelector *selector,
gboolean show_alpha)
{
g_return_if_fail (PIKA_IS_COLOR_SELECTOR (selector));
if (show_alpha != selector->show_alpha)
{
PikaColorSelectorClass *selector_class;
selector->show_alpha = show_alpha ? TRUE : FALSE;
selector_class = PIKA_COLOR_SELECTOR_GET_CLASS (selector);
if (selector_class->set_show_alpha)
selector_class->set_show_alpha (selector, show_alpha);
}
}
/**
* pika_color_selector_get_show_alpha:
* @selector: A #PikaColorSelector widget.
*
* Returns the @selector's @show_alpha property.
*
* Returns: %TRUE if the #PikaColorSelector has alpha controls.
*
* Since: 2.10
**/
gboolean
pika_color_selector_get_show_alpha (PikaColorSelector *selector)
{
g_return_val_if_fail (PIKA_IS_COLOR_SELECTOR (selector), FALSE);
return selector->show_alpha;
}
/**
* pika_color_selector_set_color:
* @selector: A #PikaColorSelector widget.
* @rgb: The new color.
* @hsv: The same color in HSV.
*
* Sets the color shown in the @selector widget.
**/
void
pika_color_selector_set_color (PikaColorSelector *selector,
const PikaRGB *rgb,
const PikaHSV *hsv)
{
PikaColorSelectorClass *selector_class;
g_return_if_fail (PIKA_IS_COLOR_SELECTOR (selector));
g_return_if_fail (rgb != NULL);
g_return_if_fail (hsv != NULL);
selector->rgb = *rgb;
selector->hsv = *hsv;
selector_class = PIKA_COLOR_SELECTOR_GET_CLASS (selector);
if (selector_class->set_color)
selector_class->set_color (selector, rgb, hsv);
pika_color_selector_emit_color_changed (selector);
}
/**
* pika_color_selector_get_color:
* @selector: A #PikaColorSelector widget.
* @rgb: (out caller-allocates): Return location for the color.
* @hsv: (out caller-allocates): Return location for the same same
* color in HSV.
*
* Retrieves the color shown in the @selector widget.
*
* Since: 2.10
**/
void
pika_color_selector_get_color (PikaColorSelector *selector,
PikaRGB *rgb,
PikaHSV *hsv)
{
g_return_if_fail (PIKA_IS_COLOR_SELECTOR (selector));
g_return_if_fail (rgb != NULL);
g_return_if_fail (hsv != NULL);
*rgb = selector->rgb;
*hsv = selector->hsv;
}
/**
* pika_color_selector_set_channel:
* @selector: A #PikaColorSelector widget.
* @channel: The new @channel setting.
*
* Sets the @channel property of the @selector widget.
*
* Changes between displayed channels if this @selector instance has
* the ability to show different channels.
* This will also update the color model if needed.
**/
void
pika_color_selector_set_channel (PikaColorSelector *selector,
PikaColorSelectorChannel channel)
{
g_return_if_fail (PIKA_IS_COLOR_SELECTOR (selector));
if (channel != selector->channel)
{
PikaColorSelectorClass *selector_class;
PikaColorSelectorModel model = -1;
selector->channel = channel;
switch (channel)
{
case PIKA_COLOR_SELECTOR_RED:
case PIKA_COLOR_SELECTOR_GREEN:
case PIKA_COLOR_SELECTOR_BLUE:
model = PIKA_COLOR_SELECTOR_MODEL_RGB;
break;
case PIKA_COLOR_SELECTOR_HUE:
case PIKA_COLOR_SELECTOR_SATURATION:
case PIKA_COLOR_SELECTOR_VALUE:
model = PIKA_COLOR_SELECTOR_MODEL_HSV;
break;
case PIKA_COLOR_SELECTOR_LCH_LIGHTNESS:
case PIKA_COLOR_SELECTOR_LCH_CHROMA:
case PIKA_COLOR_SELECTOR_LCH_HUE:
model = PIKA_COLOR_SELECTOR_MODEL_LCH;
break;
case PIKA_COLOR_SELECTOR_ALPHA:
/* Alpha channel does not change the color model. */
break;
default:
/* Should not happen. */
g_return_if_reached ();
break;
}
selector_class = PIKA_COLOR_SELECTOR_GET_CLASS (selector);
if (selector_class->set_channel)
selector_class->set_channel (selector, channel);
pika_color_selector_emit_channel_changed (selector);
if (model != -1)
{
/* make visibility of LCH and HSV mutuallky exclusive */
if (model == PIKA_COLOR_SELECTOR_MODEL_HSV)
{
pika_color_selector_set_model_visible (selector,
PIKA_COLOR_SELECTOR_MODEL_LCH,
FALSE);
}
else if (model == PIKA_COLOR_SELECTOR_MODEL_LCH)
{
pika_color_selector_set_model_visible (selector,
PIKA_COLOR_SELECTOR_MODEL_HSV,
FALSE);
}
pika_color_selector_set_model_visible (selector, model, TRUE);
}
}
}
/**
* pika_color_selector_get_channel:
* @selector: A #PikaColorSelector widget.
*
* Returns the @selector's current channel.
*
* Returns: The #PikaColorSelectorChannel currently shown by the
* @selector.
*
* Since: 2.10
**/
PikaColorSelectorChannel
pika_color_selector_get_channel (PikaColorSelector *selector)
{
g_return_val_if_fail (PIKA_IS_COLOR_SELECTOR (selector),
PIKA_COLOR_SELECTOR_RED);
return selector->channel;
}
/**
* pika_color_selector_set_model_visible:
* @selector: A #PikaColorSelector widget.
* @model: The affected #PikaColorSelectorModel.
* @visible: The new visible setting.
*
* Sets the @model visible/invisible on the @selector widget.
*
* Toggles visibility of displayed models if this @selector instance
* has the ability to show different color models.
*
* Since: 2.10
**/
void
pika_color_selector_set_model_visible (PikaColorSelector *selector,
PikaColorSelectorModel model,
gboolean visible)
{
PikaColorSelectorPrivate *priv;
g_return_if_fail (PIKA_IS_COLOR_SELECTOR (selector));
priv = GET_PRIVATE (selector);
visible = visible ? TRUE : FALSE;
if (visible != priv->model_visible[model])
{
PikaColorSelectorClass *selector_class;
priv->model_visible[model] = visible;
selector_class = PIKA_COLOR_SELECTOR_GET_CLASS (selector);
if (selector_class->set_model_visible)
selector_class->set_model_visible (selector, model, visible);
pika_color_selector_emit_model_visible_changed (selector, model);
}
}
/**
* pika_color_selector_get_model_visible:
* @selector: A #PikaColorSelector widget.
* @model: The #PikaColorSelectorModel.
*
* Returns: whether @model is visible in @selector.
*
* Since: 2.10
**/
gboolean
pika_color_selector_get_model_visible (PikaColorSelector *selector,
PikaColorSelectorModel model)
{
PikaColorSelectorPrivate *priv;
g_return_val_if_fail (PIKA_IS_COLOR_SELECTOR (selector), FALSE);
priv = GET_PRIVATE (selector);
return priv->model_visible[model];
}
/**
* pika_color_selector_emit_color_changed:
* @selector: A #PikaColorSelector widget.
*
* Emits the "color-changed" signal.
*/
void
pika_color_selector_emit_color_changed (PikaColorSelector *selector)
{
g_return_if_fail (PIKA_IS_COLOR_SELECTOR (selector));
g_signal_emit (selector, selector_signals[COLOR_CHANGED], 0,
&selector->rgb, &selector->hsv);
}
/**
* pika_color_selector_emit_channel_changed:
* @selector: A #PikaColorSelector widget.
*
* Emits the "channel-changed" signal.
*/
void
pika_color_selector_emit_channel_changed (PikaColorSelector *selector)
{
g_return_if_fail (PIKA_IS_COLOR_SELECTOR (selector));
g_signal_emit (selector, selector_signals[CHANNEL_CHANGED], 0,
selector->channel);
}
/**
* pika_color_selector_emit_model_visible_changed:
* @selector: A #PikaColorSelector widget.
* @model: The #PikaColorSelectorModel where visibility changed.
*
* Emits the "model-visible-changed" signal.
*
* Since: 2.10
*/
void
pika_color_selector_emit_model_visible_changed (PikaColorSelector *selector,
PikaColorSelectorModel model)
{
PikaColorSelectorPrivate *priv;
g_return_if_fail (PIKA_IS_COLOR_SELECTOR (selector));
priv = GET_PRIVATE (selector);
g_signal_emit (selector, selector_signals[MODEL_VISIBLE_CHANGED], 0,
model, priv->model_visible[model]);
}
/**
* pika_color_selector_set_config:
* @selector: a #PikaColorSelector widget.
* @config: a #PikaColorConfig object.
*
* Sets the color management configuration to use with this color selector.
*
* Since: 2.4
*/
void
pika_color_selector_set_config (PikaColorSelector *selector,
PikaColorConfig *config)
{
PikaColorSelectorClass *selector_class;
g_return_if_fail (PIKA_IS_COLOR_SELECTOR (selector));
g_return_if_fail (config == NULL || PIKA_IS_COLOR_CONFIG (config));
selector_class = PIKA_COLOR_SELECTOR_GET_CLASS (selector);
if (selector_class->set_config)
selector_class->set_config (selector, config);
}
/**
* pika_color_selector_set_simulation
* @selector: a #PikaColorSelector widget.
* @profile: a #PikaColorProfile object.
* @intent: a #PikaColorRenderingIntent enum.
* @bpc: a gboolean.
*
* Sets the simulation options to use with this color selector.
*
* Since: 3.0
*/
void
pika_color_selector_set_simulation (PikaColorSelector *selector,
PikaColorProfile *profile,
PikaColorRenderingIntent intent,
gboolean bpc)
{
PikaColorSelectorClass *selector_class;
g_return_if_fail (PIKA_IS_COLOR_SELECTOR (selector));
g_return_if_fail (profile == NULL || PIKA_IS_COLOR_PROFILE (profile));
selector_class = PIKA_COLOR_SELECTOR_GET_CLASS (selector);
if (selector_class->set_simulation)
selector_class->set_simulation (selector, profile, intent, bpc);
}

View File

@ -0,0 +1,187 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorselector.h
* Copyright (C) 2002 Michael Natterer <mitch@gimp.org>
*
* based on:
* Colour selector module
* Copyright (C) 1999 Austin Donnelly <austin@greenend.org.uk>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_COLOR_SELECTOR_H__
#define __PIKA_COLOR_SELECTOR_H__
G_BEGIN_DECLS
/* For information look at the html documentation */
/**
* PIKA_COLOR_SELECTOR_SIZE:
*
* The suggested size for a color area in a #PikaColorSelector
* implementation.
**/
#define PIKA_COLOR_SELECTOR_SIZE 150
/**
* PIKA_COLOR_SELECTOR_BAR_SIZE:
*
* The suggested width for a color bar in a #PikaColorSelector
* implementation.
**/
#define PIKA_COLOR_SELECTOR_BAR_SIZE 15
#define PIKA_TYPE_COLOR_SELECTOR (pika_color_selector_get_type ())
#define PIKA_COLOR_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_COLOR_SELECTOR, PikaColorSelector))
#define PIKA_COLOR_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_COLOR_SELECTOR, PikaColorSelectorClass))
#define PIKA_IS_COLOR_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_COLOR_SELECTOR))
#define PIKA_IS_COLOR_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_COLOR_SELECTOR))
#define PIKA_COLOR_SELECTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_COLOR_SELECTOR, PikaColorSelectorClass))
typedef struct _PikaColorSelectorPrivate PikaColorSelectorPrivate;
typedef struct _PikaColorSelectorClass PikaColorSelectorClass;
struct _PikaColorSelector
{
GtkBox parent_instance;
PikaColorSelectorPrivate *priv;
/* FIXME MOVE TO PRIVATE */
gboolean toggles_visible;
gboolean toggles_sensitive;
gboolean show_alpha;
PikaRGB rgb;
PikaHSV hsv;
PikaColorSelectorChannel channel;
};
struct _PikaColorSelectorClass
{
GtkBoxClass parent_class;
const gchar *name;
const gchar *help_id;
const gchar *icon_name;
/* virtual functions */
void (* set_toggles_visible) (PikaColorSelector *selector,
gboolean visible);
void (* set_toggles_sensitive) (PikaColorSelector *selector,
gboolean sensitive);
void (* set_show_alpha) (PikaColorSelector *selector,
gboolean show_alpha);
void (* set_color) (PikaColorSelector *selector,
const PikaRGB *rgb,
const PikaHSV *hsv);
void (* set_channel) (PikaColorSelector *selector,
PikaColorSelectorChannel channel);
void (* set_model_visible) (PikaColorSelector *selector,
PikaColorSelectorModel model,
gboolean visible);
void (* set_config) (PikaColorSelector *selector,
PikaColorConfig *config);
void (* set_simulation) (PikaColorSelector *selector,
PikaColorProfile *profile,
PikaColorRenderingIntent intent,
gboolean bpc);
/* signals */
void (* color_changed) (PikaColorSelector *selector,
const PikaRGB *rgb,
const PikaHSV *hsv);
void (* channel_changed) (PikaColorSelector *selector,
PikaColorSelectorChannel channel);
void (* model_visible_changed) (PikaColorSelector *selector,
PikaColorSelectorModel model,
gboolean visible);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_color_selector_get_type (void) G_GNUC_CONST;
GtkWidget * pika_color_selector_new (GType selector_type,
const PikaRGB *rgb,
const PikaHSV *hsv,
PikaColorSelectorChannel channel);
void pika_color_selector_set_toggles_visible (PikaColorSelector *selector,
gboolean visible);
gboolean pika_color_selector_get_toggles_visible (PikaColorSelector *selector);
void pika_color_selector_set_toggles_sensitive (PikaColorSelector *selector,
gboolean sensitive);
gboolean pika_color_selector_get_toggles_sensitive (PikaColorSelector *selector);
void pika_color_selector_set_show_alpha (PikaColorSelector *selector,
gboolean show_alpha);
gboolean pika_color_selector_get_show_alpha (PikaColorSelector *selector);
void pika_color_selector_set_color (PikaColorSelector *selector,
const PikaRGB *rgb,
const PikaHSV *hsv);
void pika_color_selector_get_color (PikaColorSelector *selector,
PikaRGB *rgb,
PikaHSV *hsv);
void pika_color_selector_set_channel (PikaColorSelector *selector,
PikaColorSelectorChannel channel);
PikaColorSelectorChannel
pika_color_selector_get_channel (PikaColorSelector *selector);
void pika_color_selector_set_model_visible (PikaColorSelector *selector,
PikaColorSelectorModel model,
gboolean visible);
gboolean pika_color_selector_get_model_visible (PikaColorSelector *selector,
PikaColorSelectorModel model);
void pika_color_selector_emit_color_changed (PikaColorSelector *selector);
void pika_color_selector_emit_channel_changed (PikaColorSelector *selector);
void pika_color_selector_emit_model_visible_changed (PikaColorSelector *selector,
PikaColorSelectorModel model);
void pika_color_selector_set_config (PikaColorSelector *selector,
PikaColorConfig *config);
void pika_color_selector_set_simulation (PikaColorSelector *selector,
PikaColorProfile *profile,
PikaColorRenderingIntent intent,
gboolean bpc);
G_END_DECLS
#endif /* __PIKA_COLOR_SELECTOR_H__ */

View File

@ -0,0 +1,264 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacontroller.c
* Copyright (C) 2004 Michael Natterer <mitch@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "libpikacolor/pikacolor.h"
#include "libpikaconfig/pikaconfig.h"
#include "pikawidgetstypes.h"
#include "pikawidgetsmarshal.h"
#define PIKA_ENABLE_CONTROLLER_UNDER_CONSTRUCTION
#include "pikacontroller.h"
#include "pikaicons.h"
/**
* SECTION: pikacontroller
* @title: PikaController
* @short_description: Pluggable PIKA input controller modules.
*
* An abstract interface for implementing arbitrary input controllers.
**/
enum
{
PROP_0,
PROP_NAME,
PROP_STATE
};
enum
{
EVENT,
LAST_SIGNAL
};
static void pika_controller_finalize (GObject *object);
static void pika_controller_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_controller_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE_WITH_CODE (PikaController, pika_controller, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (PIKA_TYPE_CONFIG, NULL))
#define parent_class pika_controller_parent_class
static guint controller_signals[LAST_SIGNAL] = { 0 };
static void
pika_controller_class_init (PikaControllerClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = pika_controller_finalize;
object_class->set_property = pika_controller_set_property;
object_class->get_property = pika_controller_get_property;
klass->name = "Unnamed";
klass->help_domain = NULL;
klass->help_id = NULL;
klass->icon_name = PIKA_ICON_CONTROLLER;
klass->get_n_events = NULL;
klass->get_event_name = NULL;
klass->event = NULL;
g_object_class_install_property (object_class, PROP_NAME,
g_param_spec_string ("name",
"Name",
"The controller's name",
"Unnamed Controller",
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
g_object_class_install_property (object_class, PROP_STATE,
g_param_spec_string ("state",
"State",
"The controller's state, as human-readable string",
"Unknown",
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
controller_signals[EVENT] =
g_signal_new ("event",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (PikaControllerClass, event),
g_signal_accumulator_true_handled, NULL,
_pika_widgets_marshal_BOOLEAN__POINTER,
G_TYPE_BOOLEAN, 1,
G_TYPE_POINTER);
}
static void
pika_controller_init (PikaController *controller)
{
}
static void
pika_controller_finalize (GObject *object)
{
PikaController *controller = PIKA_CONTROLLER (object);
g_clear_pointer (&controller->name, g_free);
g_clear_pointer (&controller->state, g_free);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_controller_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaController *controller = PIKA_CONTROLLER (object);
switch (property_id)
{
case PROP_NAME:
if (controller->name)
g_free (controller->name);
controller->name = g_value_dup_string (value);
break;
case PROP_STATE:
if (controller->state)
g_free (controller->state);
controller->state = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_controller_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaController *controller = PIKA_CONTROLLER (object);
switch (property_id)
{
case PROP_NAME:
g_value_set_string (value, controller->name);
break;
case PROP_STATE:
g_value_set_string (value, controller->state);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
PikaController *
pika_controller_new (GType controller_type)
{
PikaController *controller;
g_return_val_if_fail (g_type_is_a (controller_type, PIKA_TYPE_CONTROLLER),
NULL);
controller = g_object_new (controller_type, NULL);
return controller;
}
gint
pika_controller_get_n_events (PikaController *controller)
{
g_return_val_if_fail (PIKA_IS_CONTROLLER (controller), 0);
if (PIKA_CONTROLLER_GET_CLASS (controller)->get_n_events)
return PIKA_CONTROLLER_GET_CLASS (controller)->get_n_events (controller);
return 0;
}
const gchar *
pika_controller_get_event_name (PikaController *controller,
gint event_id)
{
const gchar *name = NULL;
g_return_val_if_fail (PIKA_IS_CONTROLLER (controller), NULL);
if (PIKA_CONTROLLER_GET_CLASS (controller)->get_event_name)
name = PIKA_CONTROLLER_GET_CLASS (controller)->get_event_name (controller,
event_id);
if (! name)
name = "<invalid event id>";
return name;
}
const gchar *
pika_controller_get_event_blurb (PikaController *controller,
gint event_id)
{
const gchar *blurb = NULL;
g_return_val_if_fail (PIKA_IS_CONTROLLER (controller), NULL);
if (PIKA_CONTROLLER_GET_CLASS (controller)->get_event_blurb)
blurb = PIKA_CONTROLLER_GET_CLASS (controller)->get_event_blurb (controller,
event_id);
if (! blurb)
blurb = "<invalid event id>";
return blurb;
}
gboolean
pika_controller_event (PikaController *controller,
const PikaControllerEvent *event)
{
gboolean retval = FALSE;
g_return_val_if_fail (PIKA_IS_CONTROLLER (controller), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
g_signal_emit (controller, controller_signals[EVENT], 0,
event, &retval);
return retval;
}

View File

@ -0,0 +1,191 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacontroller.h
* Copyright (C) 2004 Michael Natterer <mitch@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#ifndef PIKA_ENABLE_CONTROLLER_UNDER_CONSTRUCTION
#error PikaController is unstable API under construction
#endif
#ifndef __PIKA_CONTROLLER_H__
#define __PIKA_CONTROLLER_H__
G_BEGIN_DECLS
/* For information look at the html documentation */
/**
* PikaControllerEventType:
* @PIKA_CONTROLLER_EVENT_TRIGGER: the event is a simple trigger
* @PIKA_CONTROLLER_EVENT_VALUE: the event carries a double value
*
* Event types for #PikaController.
**/
typedef enum
{
PIKA_CONTROLLER_EVENT_TRIGGER,
PIKA_CONTROLLER_EVENT_VALUE
} PikaControllerEventType;
typedef struct _PikaControllerEventAny PikaControllerEventAny;
typedef struct _PikaControllerEventTrigger PikaControllerEventTrigger;
typedef struct _PikaControllerEventValue PikaControllerEventValue;
typedef union _PikaControllerEvent PikaControllerEvent;
/**
* PikaControllerEventAny:
* @type: The event's #PikaControllerEventType
* @source: The event's source #PikaController
* @event_id: The event's ID
*
* Generic controller event. Every event has these three members at the
* beginning of its struct
**/
struct _PikaControllerEventAny
{
PikaControllerEventType type;
PikaController *source;
gint event_id;
};
/**
* PikaControllerEventTrigger:
* @type: The event's #PikaControllerEventType
* @source: The event's source #PikaController
* @event_id: The event's ID
*
* Trigger controller event.
**/
struct _PikaControllerEventTrigger
{
PikaControllerEventType type;
PikaController *source;
gint event_id;
};
/**
* PikaControllerEventValue:
* @type: The event's #PikaControllerEventType
* @source: The event's source #PikaController
* @event_id: The event's ID
* @value: The event's value
*
* Value controller event.
**/
struct _PikaControllerEventValue
{
PikaControllerEventType type;
PikaController *source;
gint event_id;
GValue value;
};
/**
* PikaControllerEvent:
* @type: The event type
* @any: PikaControllerEventAny
* @trigger: PikaControllerEventTrigger
* @value: PikaControllerEventValue
*
* A union to hjold all event event types
**/
union _PikaControllerEvent
{
PikaControllerEventType type;
PikaControllerEventAny any;
PikaControllerEventTrigger trigger;
PikaControllerEventValue value;
};
#define PIKA_TYPE_CONTROLLER (pika_controller_get_type ())
#define PIKA_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_CONTROLLER, PikaController))
#define PIKA_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_CONTROLLER, PikaControllerClass))
#define PIKA_IS_CONTROLLER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_CONTROLLER))
#define PIKA_IS_CONTROLLER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_CONTROLLER))
#define PIKA_CONTROLLER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_CONTROLLER, PikaControllerClass))
typedef struct _PikaControllerPrivate PikaControllerPrivate;
typedef struct _PikaControllerClass PikaControllerClass;
struct _PikaController
{
GObject parent_instance;
PikaControllerPrivate *priv;
/* FIXME MOVE TO PRIVATE */
gchar *name;
gchar *state;
};
struct _PikaControllerClass
{
GObjectClass parent_class;
const gchar *name;
const gchar *help_domain;
const gchar *help_id;
const gchar *icon_name;
/* virtual functions */
gint (* get_n_events) (PikaController *controller);
const gchar * (* get_event_name) (PikaController *controller,
gint event_id);
const gchar * (* get_event_blurb) (PikaController *controller,
gint event_id);
/* signals */
gboolean (* event) (PikaController *controller,
const PikaControllerEvent *event);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_controller_get_type (void) G_GNUC_CONST;
PikaController * pika_controller_new (GType controller_type);
gint pika_controller_get_n_events (PikaController *controller);
const gchar * pika_controller_get_event_name (PikaController *controller,
gint event_id);
const gchar * pika_controller_get_event_blurb (PikaController *controller,
gint event_id);
/* protected */
gboolean pika_controller_event (PikaController *controller,
const PikaControllerEvent *event);
G_END_DECLS
#endif /* __PIKA_CONTROLLER_H__ */

726
libpikawidgets/pikadialog.c Normal file
View File

@ -0,0 +1,726 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikadialog.c
* Copyright (C) 2000-2003 Michael Natterer <mitch@gimp.org>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "pikawidgetstypes.h"
#include "pikadialog.h"
#include "pikahelpui.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikadialog
* @title: PikaDialog
* @short_description: Constructors for #GtkDialog's and action_areas as
* well as other dialog-related stuff.
*
* Constructors for #GtkDialog's and action_areas as well as other
* dialog-related stuff.
**/
enum
{
PROP_0,
PROP_HELP_FUNC,
PROP_HELP_ID,
PROP_PARENT
};
struct _PikaDialogPrivate
{
PikaHelpFunc help_func;
gchar *help_id;
GtkWidget *help_button;
};
#define GET_PRIVATE(obj) (((PikaDialog *) (obj))->priv)
static void pika_dialog_constructed (GObject *object);
static void pika_dialog_dispose (GObject *object);
static void pika_dialog_finalize (GObject *object);
static void pika_dialog_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_dialog_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_dialog_hide (GtkWidget *widget);
static gboolean pika_dialog_delete_event (GtkWidget *widget,
GdkEventAny *event);
static void pika_dialog_close (GtkDialog *dialog);
static void pika_dialog_response (GtkDialog *dialog,
gint response_id);
G_DEFINE_TYPE_WITH_PRIVATE (PikaDialog, pika_dialog, GTK_TYPE_DIALOG)
#define parent_class pika_dialog_parent_class
static gboolean show_help_button = TRUE;
static void
pika_dialog_class_init (PikaDialogClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
GtkDialogClass *dialog_class = GTK_DIALOG_CLASS (klass);
object_class->constructed = pika_dialog_constructed;
object_class->dispose = pika_dialog_dispose;
object_class->finalize = pika_dialog_finalize;
object_class->set_property = pika_dialog_set_property;
object_class->get_property = pika_dialog_get_property;
widget_class->hide = pika_dialog_hide;
widget_class->delete_event = pika_dialog_delete_event;
dialog_class->close = pika_dialog_close;
/**
* PikaDialog:help-func:
*
* Since: 2.2
**/
g_object_class_install_property (object_class, PROP_HELP_FUNC,
g_param_spec_pointer ("help-func",
"Help Func",
"The help function to call when F1 is hit",
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
/**
* PikaDialog:help-id:
*
* Since: 2.2
**/
g_object_class_install_property (object_class, PROP_HELP_ID,
g_param_spec_string ("help-id",
"Help ID",
"The help ID to pass to help-func",
NULL,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
/**
* PikaDialog:parent:
*
* Since: 2.8
**/
g_object_class_install_property (object_class, PROP_PARENT,
g_param_spec_object ("parent",
"Parent",
"The dialog's parent widget",
GTK_TYPE_WIDGET,
PIKA_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY));
}
static void
pika_dialog_init (PikaDialog *dialog)
{
dialog->priv = pika_dialog_get_instance_private (dialog);
g_signal_connect (dialog, "response",
G_CALLBACK (pika_dialog_response),
NULL);
}
static void
pika_dialog_constructed (GObject *object)
{
PikaDialogPrivate *private = GET_PRIVATE (object);
G_OBJECT_CLASS (parent_class)->constructed (object);
if (private->help_func)
pika_help_connect (GTK_WIDGET (object),
private->help_func, private->help_id,
object, NULL);
if (show_help_button && private->help_func && private->help_id)
{
private->help_button = gtk_dialog_add_button (GTK_DIALOG (object),
_("_Help"),
GTK_RESPONSE_HELP);
}
}
static void
pika_dialog_dispose (GObject *object)
{
GdkDisplay *display = NULL;
if (g_main_depth () == 0)
{
display = gtk_widget_get_display (GTK_WIDGET (object));
g_object_ref (display);
}
G_OBJECT_CLASS (parent_class)->dispose (object);
if (display)
{
gdk_display_flush (display);
g_object_unref (display);
}
}
static void
pika_dialog_finalize (GObject *object)
{
PikaDialogPrivate *private = GET_PRIVATE (object);
g_clear_pointer (&private->help_id, g_free);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_dialog_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaDialogPrivate *private = GET_PRIVATE (object);
switch (property_id)
{
case PROP_HELP_FUNC:
private->help_func = g_value_get_pointer (value);
break;
case PROP_HELP_ID:
g_free (private->help_id);
private->help_id = g_value_dup_string (value);
pika_help_set_help_data (GTK_WIDGET (object), NULL, private->help_id);
break;
case PROP_PARENT:
{
GtkWidget *parent = g_value_get_object (value);
if (parent)
{
if (GTK_IS_WINDOW (parent))
{
gtk_window_set_transient_for (GTK_WINDOW (object),
GTK_WINDOW (parent));
}
else
{
GtkWidget *toplevel;
toplevel = gtk_widget_get_toplevel (parent);
if (GTK_IS_WINDOW (toplevel))
{
gtk_window_set_transient_for (GTK_WINDOW (object),
GTK_WINDOW (toplevel));
}
else
{
gtk_window_set_screen (GTK_WINDOW (object),
gtk_widget_get_screen (parent));
gtk_window_set_position (GTK_WINDOW (object),
GTK_WIN_POS_MOUSE);
}
}
}
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_dialog_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaDialogPrivate *private = GET_PRIVATE (object);
switch (property_id)
{
case PROP_HELP_FUNC:
g_value_set_pointer (value, private->help_func);
break;
case PROP_HELP_ID:
g_value_set_string (value, private->help_id);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_dialog_hide (GtkWidget *widget)
{
/* set focus to NULL so focus_out callbacks are invoked synchronously */
gtk_window_set_focus (GTK_WINDOW (widget), NULL);
GTK_WIDGET_CLASS (parent_class)->hide (widget);
}
static gboolean
pika_dialog_delete_event (GtkWidget *widget,
GdkEventAny *event)
{
return TRUE;
}
static void
pika_dialog_close (GtkDialog *dialog)
{
/* Synthesize delete_event to close dialog. */
GtkWidget *widget = GTK_WIDGET (dialog);
if (gtk_widget_get_window (widget))
{
GdkEvent *event = gdk_event_new (GDK_DELETE);
event->any.window = g_object_ref (gtk_widget_get_window (widget));
event->any.send_event = TRUE;
gtk_main_do_event (event);
gdk_event_free (event);
}
}
static void
pika_dialog_response (GtkDialog *dialog,
gint response_id)
{
PikaDialogPrivate *private = GET_PRIVATE (dialog);
GtkWidget *widget = gtk_dialog_get_widget_for_response (dialog,
response_id);
if (widget &&
(! GTK_IS_BUTTON (widget) ||
gtk_widget_get_focus_on_click (widget)))
{
gtk_widget_grab_focus (widget);
}
/* if our own help button was activated, abort "response" and
* call our help callback.
*/
if (response_id == GTK_RESPONSE_HELP &&
widget == private->help_button)
{
g_signal_stop_emission_by_name (dialog, "response");
if (private->help_func)
private->help_func (private->help_id, dialog);
}
}
/**
* pika_dialog_new: (skip)
* @title: The dialog's title which will be set with
* gtk_window_set_title().
* @role: The dialog's @role which will be set with
* gtk_window_set_role().
* @parent: (nullable): The @parent widget of this dialog.
* @flags: The @flags (see the #GtkDialog documentation).
* @help_func: The function which will be called if the user presses "F1".
* @help_id: The help_id which will be passed to @help_func.
* @...: A %NULL-terminated @va_list destribing the
* action_area buttons.
*
* Creates a new @PikaDialog widget.
*
* This function simply packs the action_area arguments passed in "..."
* into a @va_list variable and passes everything to pika_dialog_new_valist().
*
* For a description of the format of the @va_list describing the
* action_area buttons see gtk_dialog_new_with_buttons().
*
* Returns: A #PikaDialog.
**/
GtkWidget *
pika_dialog_new (const gchar *title,
const gchar *role,
GtkWidget *parent,
GtkDialogFlags flags,
PikaHelpFunc help_func,
const gchar *help_id,
...)
{
GtkWidget *dialog;
va_list args;
g_return_val_if_fail (parent == NULL || GTK_IS_WIDGET (parent), NULL);
g_return_val_if_fail (title != NULL, NULL);
g_return_val_if_fail (role != NULL, NULL);
va_start (args, help_id);
dialog = pika_dialog_new_valist (title, role,
parent, flags,
help_func, help_id,
args);
va_end (args);
return dialog;
}
/**
* pika_dialog_new_valist: (skip)
* @title: The dialog's title which will be set with
* gtk_window_set_title().
* @role: The dialog's @role which will be set with
* gtk_window_set_role().
* @parent: The @parent widget of this dialog or %NULL.
* @flags: The @flags (see the #GtkDialog documentation).
* @help_func: The function which will be called if the user presses "F1".
* @help_id: The help_id which will be passed to @help_func.
* @args: A @va_list destribing the action_area buttons.
*
* Creates a new @PikaDialog widget. If a GtkWindow is specified as
* @parent then the dialog will be made transient for this window.
*
* For a description of the format of the @va_list describing the
* action_area buttons see gtk_dialog_new_with_buttons().
*
* Returns: A #PikaDialog.
**/
GtkWidget *
pika_dialog_new_valist (const gchar *title,
const gchar *role,
GtkWidget *parent,
GtkDialogFlags flags,
PikaHelpFunc help_func,
const gchar *help_id,
va_list args)
{
GtkWidget *dialog;
gboolean use_header_bar;
g_return_val_if_fail (title != NULL, NULL);
g_return_val_if_fail (role != NULL, NULL);
g_return_val_if_fail (parent == NULL || GTK_IS_WIDGET (parent), NULL);
g_object_get (gtk_settings_get_default (),
"gtk-dialogs-use-header", &use_header_bar,
NULL);
dialog = g_object_new (PIKA_TYPE_DIALOG,
"title", title,
"role", role,
"modal", (flags & GTK_DIALOG_MODAL),
"help-func", help_func,
"help-id", help_id,
"parent", parent,
"use-header-bar", use_header_bar,
NULL);
if (parent)
{
if (flags & GTK_DIALOG_DESTROY_WITH_PARENT)
g_signal_connect_object (parent, "destroy",
G_CALLBACK (pika_dialog_close),
dialog, G_CONNECT_SWAPPED);
}
pika_dialog_add_buttons_valist (PIKA_DIALOG (dialog), args);
return dialog;
}
/**
* pika_dialog_add_button:
* @dialog: The @dialog to add a button to.
* @button_text: text of button, or stock ID.
* @response_id: response ID for the button.
*
* This function is essentially the same as gtk_dialog_add_button()
* except it ensures there is only one help button and automatically
* sets the RESPONSE_OK widget as the default response.
*
* Returns: (type Gtk.Widget) (transfer none): the button widget that was added.
**/
GtkWidget *
pika_dialog_add_button (PikaDialog *dialog,
const gchar *button_text,
gint response_id)
{
GtkWidget *button;
gboolean use_header_bar;
/* hide the automatically added help button if another one is added */
if (response_id == GTK_RESPONSE_HELP)
{
PikaDialogPrivate *private = GET_PRIVATE (dialog);
if (private->help_button)
{
gtk_widget_destroy (private->help_button);
private->help_button = NULL;
}
}
button = gtk_dialog_add_button (GTK_DIALOG (dialog), button_text,
response_id);
g_object_get (dialog,
"use-header-bar", &use_header_bar,
NULL);
if (use_header_bar &&
(response_id == GTK_RESPONSE_OK ||
response_id == GTK_RESPONSE_CANCEL ||
response_id == GTK_RESPONSE_CLOSE))
{
GtkWidget *header = gtk_dialog_get_header_bar (GTK_DIALOG (dialog));
if (response_id == GTK_RESPONSE_OK)
gtk_dialog_set_default_response (GTK_DIALOG (dialog),
GTK_RESPONSE_OK);
gtk_container_child_set (GTK_CONTAINER (header), button,
"position", 0,
NULL);
}
return button;
}
/**
* pika_dialog_add_buttons: (skip)
* @dialog: The @dialog to add buttons to.
* @...: button_text-response_id pairs.
*
* This function is essentially the same as gtk_dialog_add_buttons()
* except it calls pika_dialog_add_button() instead of gtk_dialog_add_button()
**/
void
pika_dialog_add_buttons (PikaDialog *dialog,
...)
{
va_list args;
va_start (args, dialog);
pika_dialog_add_buttons_valist (dialog, args);
va_end (args);
}
/**
* pika_dialog_add_buttons_valist: (skip)
* @dialog: The @dialog to add buttons to.
* @args: The buttons as va_list.
*
* This function is essentially the same as pika_dialog_add_buttons()
* except it takes a va_list instead of '...'
**/
void
pika_dialog_add_buttons_valist (PikaDialog *dialog,
va_list args)
{
const gchar *button_text;
gint response_id;
g_return_if_fail (PIKA_IS_DIALOG (dialog));
while ((button_text = va_arg (args, const gchar *)))
{
response_id = va_arg (args, gint);
pika_dialog_add_button (dialog, button_text, response_id);
}
}
typedef struct
{
GtkDialog *dialog;
gint response_id;
GMainLoop *loop;
gboolean destroyed;
} RunInfo;
static void
run_shutdown_loop (RunInfo *ri)
{
if (g_main_loop_is_running (ri->loop))
g_main_loop_quit (ri->loop);
}
static void
run_unmap_handler (GtkDialog *dialog,
RunInfo *ri)
{
run_shutdown_loop (ri);
}
static void
run_response_handler (GtkDialog *dialog,
gint response_id,
RunInfo *ri)
{
ri->response_id = response_id;
run_shutdown_loop (ri);
}
static gint
run_delete_handler (GtkDialog *dialog,
GdkEventAny *event,
RunInfo *ri)
{
run_shutdown_loop (ri);
return TRUE; /* Do not destroy */
}
static void
run_destroy_handler (GtkDialog *dialog,
RunInfo *ri)
{
/* shutdown_loop will be called by run_unmap_handler */
ri->destroyed = TRUE;
}
/**
* pika_dialog_run:
* @dialog: a #PikaDialog
*
* This function does exactly the same as gtk_dialog_run() except it
* does not make the dialog modal while the #GMainLoop is running.
*
* Returns: response ID
**/
gint
pika_dialog_run (PikaDialog *dialog)
{
RunInfo ri = { NULL, GTK_RESPONSE_NONE, NULL };
gulong response_handler;
gulong unmap_handler;
gulong destroy_handler;
gulong delete_handler;
g_return_val_if_fail (PIKA_IS_DIALOG (dialog), -1);
g_object_ref (dialog);
gtk_window_present (GTK_WINDOW (dialog));
response_handler = g_signal_connect (dialog, "response",
G_CALLBACK (run_response_handler),
&ri);
unmap_handler = g_signal_connect (dialog, "unmap",
G_CALLBACK (run_unmap_handler),
&ri);
delete_handler = g_signal_connect (dialog, "delete-event",
G_CALLBACK (run_delete_handler),
&ri);
destroy_handler = g_signal_connect (dialog, "destroy",
G_CALLBACK (run_destroy_handler),
&ri);
ri.loop = g_main_loop_new (NULL, FALSE);
g_main_loop_run (ri.loop);
g_main_loop_unref (ri.loop);
ri.loop = NULL;
ri.destroyed = FALSE;
if (!ri.destroyed)
{
g_signal_handler_disconnect (dialog, response_handler);
g_signal_handler_disconnect (dialog, unmap_handler);
g_signal_handler_disconnect (dialog, delete_handler);
g_signal_handler_disconnect (dialog, destroy_handler);
}
g_object_unref (dialog);
return ri.response_id;
}
/**
* pika_dialog_set_alternative_button_order_from_array:
* @dialog: The #PikaDialog
* @n_buttons: The size of @order
* @order: (array length=n_buttons): array of buttons' response ids.
*
* Reorder @dialog's buttons if [property@Gtk.Settings:gtk-alternative-button-order]
* is set to TRUE. This is mostly a wrapper around the GTK function
* [method@Gtk.Dialog.set_alternative_button_order], except it won't
* output a deprecation warning.
*
* Since: 3.0
**/
void
pika_dialog_set_alternative_button_order_from_array (PikaDialog *dialog,
gint n_buttons,
gint *order)
{
/* since we don't know yet what to do about alternative button order,
* just hide the warnings for now...
*/
G_GNUC_BEGIN_IGNORE_DEPRECATIONS;
gtk_dialog_set_alternative_button_order_from_array (GTK_DIALOG (dialog), n_buttons, order);
G_GNUC_END_IGNORE_DEPRECATIONS;
}
/**
* pika_dialogs_show_help_button: (skip)
* @show: whether a help button should be added when creating a PikaDialog
*
* This function is for internal use only.
*
* Since: 2.2
**/
void
pika_dialogs_show_help_button (gboolean show)
{
show_help_button = show ? TRUE : FALSE;
}

117
libpikawidgets/pikadialog.h Normal file
View File

@ -0,0 +1,117 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikadialog.h
* Copyright (C) 2000-2003 Michael Natterer <mitch@gimp.org>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_DIALOG_H__
#define __PIKA_DIALOG_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
#define PIKA_TYPE_DIALOG (pika_dialog_get_type ())
#define PIKA_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_DIALOG, PikaDialog))
#define PIKA_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_DIALOG, PikaDialogClass))
#define PIKA_IS_DIALOG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_DIALOG))
#define PIKA_IS_DIALOG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_DIALOG))
#define PIKA_DIALOG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_DIALOG, PikaDialogClass))
typedef struct _PikaDialogPrivate PikaDialogPrivate;
typedef struct _PikaDialogClass PikaDialogClass;
struct _PikaDialog
{
GtkDialog parent_instance;
PikaDialogPrivate *priv;
};
struct _PikaDialogClass
{
GtkDialogClass parent_class;
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_dialog_get_type (void) G_GNUC_CONST;
GtkWidget * pika_dialog_new (const gchar *title,
const gchar *role,
GtkWidget *parent,
GtkDialogFlags flags,
PikaHelpFunc help_func,
const gchar *help_id,
...) G_GNUC_NULL_TERMINATED;
GtkWidget * pika_dialog_new_valist (const gchar *title,
const gchar *role,
GtkWidget *parent,
GtkDialogFlags flags,
PikaHelpFunc help_func,
const gchar *help_id,
va_list args);
GtkWidget * pika_dialog_add_button (PikaDialog *dialog,
const gchar *button_text,
gint response_id);
void pika_dialog_add_buttons (PikaDialog *dialog,
...) G_GNUC_NULL_TERMINATED;
void pika_dialog_add_buttons_valist (PikaDialog *dialog,
va_list args);
gint pika_dialog_run (PikaDialog *dialog);
void pika_dialog_set_alternative_button_order_from_array
(PikaDialog *dialog,
gint n_buttons,
gint *order);
/* for internal use only! */
void pika_dialogs_show_help_button (gboolean show);
/* pika_dialog_set_alternative_button_order() doesn't need a dedicated
* wrapper function because anyway it won't be introspectable.
* GObject-Introspection bindings will have to use
* pika_dialog_set_alternative_button_order_from_array().
*/
#define pika_dialog_set_alternative_button_order(d,f...) \
G_GNUC_BEGIN_IGNORE_DEPRECATIONS; \
gtk_dialog_set_alternative_button_order(d,f); \
G_GNUC_END_IGNORE_DEPRECATIONS;
G_END_DECLS
#endif /* __PIKA_DIALOG_H__ */

666
libpikawidgets/pikaeevl.c Normal file
View File

@ -0,0 +1,666 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaeevl.c
* Copyright (C) 2008 Fredrik Alstromer <roe@excu.se>
* Copyright (C) 2008 Martin Nordholts <martinn@svn.gnome.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
/* Introducing eevl eva, the evaluator. A straightforward recursive
* descent parser, no fuss, no new dependencies. The lexer is hand
* coded, tedious, not extremely fast but works. It evaluates the
* expression as it goes along, and does not create a parse tree or
* anything, and will not optimize anything. It uses doubles for
* precision, with the given use case, that's enough to combat any
* rounding errors (as opposed to optimizing the evaluation).
*
* It relies on external unit resolving through a callback and does
* elementary dimensionality constraint check (e.g. "2 mm + 3 px * 4
* in" is an error, as L + L^2 is a mismatch). It uses setjmp/longjmp
* for try/catch like pattern on error, it uses g_strtod() for numeric
* conversions and it's non-destructive in terms of the parameters, and
* it's reentrant.
*
* EBNF:
*
* expression ::= term { ('+' | '-') term }* |
* <empty string> ;
*
* term ::= ratio { ( '*' | '/' ) ratio }* ;
*
* ratio ::= signed factor { ':' signed factor }* ;
*
* signed factor ::= ( '+' | '-' )? factor ;
*
* factor ::= quantity ( '^' signed factor )? ;
*
* quantity ::= number unit? | '(' expression ')' ;
*
* number ::= ? what g_strtod() consumes ? ;
*
* unit ::= simple unit ( '^' signed factor )? ;
*
* simple unit ::= ? what not g_strtod() consumes and not whitespace ? ;
*
* The code should match the EBNF rather closely (except for the
* non-terminal unit factor, which is inlined into factor) for
* maintainability reasons.
*
* It will allow 1++1 and 1+-1 (resulting in 2 and 0, respectively),
* but I figured one might want that, and I don't think it's going to
* throw anyone off.
*/
#include "config.h"
#include <setjmp.h>
#include <string.h>
#include <glib-object.h>
#include "libpikamath/pikamath.h"
#include "pikaeevl.h"
#include "pikawidgets-error.h"
#include "libpika/libpika-intl.h"
typedef enum
{
PIKA_EEVL_TOKEN_NUM = 30000,
PIKA_EEVL_TOKEN_IDENTIFIER = 30001,
PIKA_EEVL_TOKEN_ANY = 40000,
PIKA_EEVL_TOKEN_END = 50000
} PikaEevlTokenType;
typedef struct
{
PikaEevlTokenType type;
union
{
gdouble fl;
struct
{
const gchar *c;
gint size;
};
} value;
} PikaEevlToken;
typedef struct
{
const gchar *string;
PikaEevlOptions options;
PikaEevlToken current_token;
const gchar *start_of_current_token;
jmp_buf catcher;
const gchar *error_message;
} PikaEevl;
static void pika_eevl_init (PikaEevl *eva,
const gchar *string,
const PikaEevlOptions *options);
static PikaEevlQuantity pika_eevl_complete (PikaEevl *eva);
static PikaEevlQuantity pika_eevl_expression (PikaEevl *eva);
static PikaEevlQuantity pika_eevl_term (PikaEevl *eva);
static PikaEevlQuantity pika_eevl_ratio (PikaEevl *eva);
static PikaEevlQuantity pika_eevl_signed_factor (PikaEevl *eva);
static PikaEevlQuantity pika_eevl_factor (PikaEevl *eva);
static PikaEevlQuantity pika_eevl_quantity (PikaEevl *eva);
static gboolean pika_eevl_accept (PikaEevl *eva,
PikaEevlTokenType token_type,
PikaEevlToken *consumed_token);
static void pika_eevl_lex (PikaEevl *eva);
static void pika_eevl_lex_accept_count (PikaEevl *eva,
gint count,
PikaEevlTokenType token_type);
static void pika_eevl_lex_accept_to (PikaEevl *eva,
gchar *to,
PikaEevlTokenType token_type);
static void pika_eevl_move_past_whitespace (PikaEevl *eva);
static gboolean pika_eevl_unit_identifier_start (gunichar c);
static gboolean pika_eevl_unit_identifier_continue (gunichar c);
static gint pika_eevl_unit_identifier_size (const gchar *s,
gint start);
static void pika_eevl_expect (PikaEevl *eva,
PikaEevlTokenType token_type,
PikaEevlToken *value);
static void pika_eevl_error (PikaEevl *eva,
gchar *msg);
/**
* pika_eevl_evaluate:
* @string: The NULL-terminated string to be evaluated.
* @options: Evaluations options.
* @result: Result of evaluation.
* @error_pos: Will point to the position within the string,
* before which the parse / evaluation error
* occurred. Will be set to null if no error occurred.
* @error_message: Will point to a static string with a semi-descriptive
* error message if parsing / evaluation failed.
*
* Evaluates the given arithmetic expression, along with an optional dimension
* analysis, and basic unit conversions.
*
* All units conversions factors are relative to some implicit
* base-unit (which in PIKA is inches). This is also the unit of the
* returned value.
*
* Returns: A #PikaEevlQuantity with a value given in the base unit along with
* the order of the dimension (i.e. if the base unit is inches, a dimension
* order of two means in^2).
**/
gboolean
pika_eevl_evaluate (const gchar *string,
const PikaEevlOptions *options,
PikaEevlQuantity *result,
const gchar **error_pos,
GError **error)
{
PikaEevl eva;
g_return_val_if_fail (g_utf8_validate (string, -1, NULL), FALSE);
g_return_val_if_fail (options != NULL, FALSE);
g_return_val_if_fail (options->unit_resolver_proc != NULL, FALSE);
g_return_val_if_fail (result != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
pika_eevl_init (&eva,
string,
options);
if (!setjmp (eva.catcher)) /* try... */
{
*result = pika_eevl_complete (&eva);
return TRUE;
}
else /* catch.. */
{
if (error_pos)
*error_pos = eva.start_of_current_token;
g_set_error_literal (error,
PIKA_WIDGETS_ERROR,
PIKA_WIDGETS_PARSE_ERROR,
eva.error_message);
return FALSE;
}
}
static void
pika_eevl_init (PikaEevl *eva,
const gchar *string,
const PikaEevlOptions *options)
{
eva->string = string;
eva->options = *options;
eva->current_token.type = PIKA_EEVL_TOKEN_END;
eva->error_message = NULL;
/* Preload symbol... */
pika_eevl_lex (eva);
}
static PikaEevlQuantity
pika_eevl_complete (PikaEevl *eva)
{
PikaEevlQuantity result = {0, 0};
PikaEevlQuantity default_unit_factor;
gdouble default_unit_offset;
/* Empty expression evaluates to 0 */
if (pika_eevl_accept (eva, PIKA_EEVL_TOKEN_END, NULL))
return result;
result = pika_eevl_expression (eva);
/* There should be nothing left to parse by now */
pika_eevl_expect (eva, PIKA_EEVL_TOKEN_END, 0);
eva->options.unit_resolver_proc (NULL,
&default_unit_factor,
&default_unit_offset,
eva->options.data);
/* Entire expression is dimensionless, apply default unit if
* applicable
*/
if (result.dimension == 0 && default_unit_factor.dimension != 0)
{
result.value /= default_unit_factor.value;
result.value += default_unit_offset;
result.dimension = default_unit_factor.dimension;
}
return result;
}
static PikaEevlQuantity
pika_eevl_expression (PikaEevl *eva)
{
gboolean subtract;
PikaEevlQuantity evaluated_terms;
evaluated_terms = pika_eevl_term (eva);
/* continue evaluating terms, chained with + or -. */
for (subtract = FALSE;
pika_eevl_accept (eva, '+', NULL) ||
(subtract = pika_eevl_accept (eva, '-', NULL));
subtract = FALSE)
{
PikaEevlQuantity new_term = pika_eevl_term (eva);
/* If dimensions mismatch, attempt default unit assignment */
if (new_term.dimension != evaluated_terms.dimension)
{
PikaEevlQuantity default_unit_factor;
gdouble default_unit_offset;
eva->options.unit_resolver_proc (NULL,
&default_unit_factor,
&default_unit_offset,
eva->options.data);
if (new_term.dimension == 0 &&
evaluated_terms.dimension == default_unit_factor.dimension)
{
new_term.value /= default_unit_factor.value;
new_term.value += default_unit_offset;
new_term.dimension = default_unit_factor.dimension;
}
else if (evaluated_terms.dimension == 0 &&
new_term.dimension == default_unit_factor.dimension)
{
evaluated_terms.value /= default_unit_factor.value;
evaluated_terms.value += default_unit_offset;
evaluated_terms.dimension = default_unit_factor.dimension;
}
else
{
pika_eevl_error (eva, "Dimension mismatch during addition");
}
}
evaluated_terms.value += (subtract ? -new_term.value : new_term.value);
}
return evaluated_terms;
}
static PikaEevlQuantity
pika_eevl_term (PikaEevl *eva)
{
gboolean division;
PikaEevlQuantity evaluated_ratios;
evaluated_ratios = pika_eevl_ratio (eva);
for (division = FALSE;
pika_eevl_accept (eva, '*', NULL) ||
(division = pika_eevl_accept (eva, '/', NULL));
division = FALSE)
{
PikaEevlQuantity new_ratio = pika_eevl_ratio (eva);
if (division)
{
evaluated_ratios.value /= new_ratio.value;
evaluated_ratios.dimension -= new_ratio.dimension;
}
else
{
evaluated_ratios.value *= new_ratio.value;
evaluated_ratios.dimension += new_ratio.dimension;
}
}
return evaluated_ratios;
}
static PikaEevlQuantity
pika_eevl_ratio (PikaEevl *eva)
{
PikaEevlQuantity evaluated_signed_factors;
if (! eva->options.ratio_expressions)
return pika_eevl_signed_factor (eva);
evaluated_signed_factors = pika_eevl_signed_factor (eva);
while (pika_eevl_accept (eva, ':', NULL))
{
PikaEevlQuantity new_signed_factor = pika_eevl_signed_factor (eva);
if (eva->options.ratio_invert)
{
PikaEevlQuantity temp;
temp = evaluated_signed_factors;
evaluated_signed_factors = new_signed_factor;
new_signed_factor = temp;
}
evaluated_signed_factors.value *= eva->options.ratio_quantity.value /
new_signed_factor.value;
evaluated_signed_factors.dimension += eva->options.ratio_quantity.dimension -
new_signed_factor.dimension;
}
return evaluated_signed_factors;
}
static PikaEevlQuantity
pika_eevl_signed_factor (PikaEevl *eva)
{
PikaEevlQuantity result;
gboolean negate = FALSE;
if (! pika_eevl_accept (eva, '+', NULL))
negate = pika_eevl_accept (eva, '-', NULL);
result = pika_eevl_factor (eva);
if (negate) result.value = -result.value;
return result;
}
static PikaEevlQuantity
pika_eevl_factor (PikaEevl *eva)
{
PikaEevlQuantity evaluated_factor;
evaluated_factor = pika_eevl_quantity (eva);
if (pika_eevl_accept (eva, '^', NULL))
{
PikaEevlQuantity evaluated_exponent;
evaluated_exponent = pika_eevl_signed_factor (eva);
if (evaluated_exponent.dimension != 0)
pika_eevl_error (eva, "Exponent is not a dimensionless quantity");
evaluated_factor.value = pow (evaluated_factor.value,
evaluated_exponent.value);
evaluated_factor.dimension *= evaluated_exponent.value;
}
return evaluated_factor;
}
static PikaEevlQuantity
pika_eevl_quantity (PikaEevl *eva)
{
PikaEevlQuantity evaluated_quantity = { 0, 0 };
PikaEevlToken consumed_token;
if (pika_eevl_accept (eva,
PIKA_EEVL_TOKEN_NUM,
&consumed_token))
{
evaluated_quantity.value = consumed_token.value.fl;
}
else if (pika_eevl_accept (eva, '(', NULL))
{
evaluated_quantity = pika_eevl_expression (eva);
pika_eevl_expect (eva, ')', 0);
}
else
{
pika_eevl_error (eva, "Expected number or '('");
}
if (eva->current_token.type == PIKA_EEVL_TOKEN_IDENTIFIER)
{
gchar *identifier;
PikaEevlQuantity factor;
gdouble offset;
pika_eevl_accept (eva,
PIKA_EEVL_TOKEN_ANY,
&consumed_token);
identifier = g_newa (gchar, consumed_token.value.size + 1);
strncpy (identifier, consumed_token.value.c, consumed_token.value.size);
identifier[consumed_token.value.size] = '\0';
if (eva->options.unit_resolver_proc (identifier,
&factor,
&offset,
eva->options.data))
{
if (pika_eevl_accept (eva, '^', NULL))
{
PikaEevlQuantity evaluated_exponent;
evaluated_exponent = pika_eevl_signed_factor (eva);
if (evaluated_exponent.dimension != 0)
{
pika_eevl_error (eva,
"Exponent is not a dimensionless quantity");
}
if (offset != 0.0)
{
pika_eevl_error (eva,
"Invalid unit exponent");
}
factor.value = pow (factor.value, evaluated_exponent.value);
factor.dimension *= evaluated_exponent.value;
}
evaluated_quantity.value /= factor.value;
evaluated_quantity.value += offset;
evaluated_quantity.dimension += factor.dimension;
}
else
{
pika_eevl_error (eva, "Unit was not resolved");
}
}
return evaluated_quantity;
}
static gboolean
pika_eevl_accept (PikaEevl *eva,
PikaEevlTokenType token_type,
PikaEevlToken *consumed_token)
{
gboolean existed = FALSE;
if (token_type == eva->current_token.type ||
token_type == PIKA_EEVL_TOKEN_ANY)
{
existed = TRUE;
if (consumed_token)
*consumed_token = eva->current_token;
/* Parse next token */
pika_eevl_lex (eva);
}
return existed;
}
static void
pika_eevl_lex (PikaEevl *eva)
{
const gchar *s;
pika_eevl_move_past_whitespace (eva);
s = eva->string;
eva->start_of_current_token = s;
if (! s || s[0] == '\0')
{
/* We're all done */
eva->current_token.type = PIKA_EEVL_TOKEN_END;
}
else if (s[0] == '+' || s[0] == '-')
{
/* Snatch these before the g_strtod() does, otherwise they might
* be used in a numeric conversion.
*/
pika_eevl_lex_accept_count (eva, 1, s[0]);
}
else
{
/* Attempt to parse a numeric value */
gchar *endptr = NULL;
gdouble value = g_strtod (s, &endptr);
if (endptr && endptr != s)
{
/* A numeric could be parsed, use it */
eva->current_token.value.fl = value;
pika_eevl_lex_accept_to (eva, endptr, PIKA_EEVL_TOKEN_NUM);
}
else if (pika_eevl_unit_identifier_start (s[0]))
{
/* Unit identifier */
eva->current_token.value.c = s;
eva->current_token.value.size = pika_eevl_unit_identifier_size (s, 0);
pika_eevl_lex_accept_count (eva,
eva->current_token.value.size,
PIKA_EEVL_TOKEN_IDENTIFIER);
}
else
{
/* Everything else is a single character token */
pika_eevl_lex_accept_count (eva, 1, s[0]);
}
}
}
static void
pika_eevl_lex_accept_count (PikaEevl *eva,
gint count,
PikaEevlTokenType token_type)
{
eva->current_token.type = token_type;
eva->string += count;
}
static void
pika_eevl_lex_accept_to (PikaEevl *eva,
gchar *to,
PikaEevlTokenType token_type)
{
eva->current_token.type = token_type;
eva->string = to;
}
static void
pika_eevl_move_past_whitespace (PikaEevl *eva)
{
if (! eva->string)
return;
while (g_ascii_isspace (*eva->string))
eva->string++;
}
static gboolean
pika_eevl_unit_identifier_start (gunichar c)
{
return (g_unichar_isalpha (c) ||
c == (gunichar) '%' ||
c == (gunichar) '\'');
}
static gboolean
pika_eevl_unit_identifier_continue (gunichar c)
{
return (pika_eevl_unit_identifier_start (c) ||
g_unichar_isdigit (c));
}
/**
* pika_eevl_unit_identifier_size:
* @s:
* @start:
*
* Returns: Size of identifier in bytes (not including NULL
* terminator).
**/
static gint
pika_eevl_unit_identifier_size (const gchar *string,
gint start_offset)
{
const gchar *start = g_utf8_offset_to_pointer (string, start_offset);
const gchar *s = start;
gunichar c = g_utf8_get_char (s);
gint length = 0;
if (pika_eevl_unit_identifier_start (c))
{
s = g_utf8_next_char (s);
c = g_utf8_get_char (s);
length++;
while (pika_eevl_unit_identifier_continue (c))
{
s = g_utf8_next_char (s);
c = g_utf8_get_char (s);
length++;
}
}
return g_utf8_offset_to_pointer (start, length) - start;
}
static void
pika_eevl_expect (PikaEevl *eva,
PikaEevlTokenType token_type,
PikaEevlToken *value)
{
if (! pika_eevl_accept (eva, token_type, value))
pika_eevl_error (eva, "Unexpected token");
}
static void
pika_eevl_error (PikaEevl *eva,
gchar *msg)
{
eva->error_message = msg;
longjmp (eva->catcher, 1);
}

99
libpikawidgets/pikaeevl.h Normal file
View File

@ -0,0 +1,99 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaeevl.h
* Copyright (C) 2008-2009 Fredrik Alstromer <roe@excu.se>
* Copyright (C) 2008-2009 Martin Nordholts <martinn@svn.gnome.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#ifndef __PIKA_EEVL_H__
#define __PIKA_EEVL_H__
G_BEGIN_DECLS
/**
* PikaEevlQuantity:
* @value: In reference units.
* @dimension: in has a dimension of 1, in^2 has a dimension of 2 etc
*/
typedef struct
{
gdouble value;
gint dimension;
} PikaEevlQuantity;
/**
* PikaEevlUnitResolverProc:
* @identifier: Identifier of unit to resolve or %NULL if default unit
* should be resolved.
* @factor: Units per reference unit. For example, in PIKA the
* reference unit is inches so resolving "mm" should
* return 25.4 since there are 25.4 millimeters per inch.
* @offset: Offset to apply after scaling the value according to @factor.
* @data: Data given to pika_eevl_evaluate().
*
* Returns: If the unit was successfully resolved or not.
*
*/
typedef gboolean (* PikaEevlUnitResolverProc) (const gchar *identifier,
PikaEevlQuantity *factor,
gdouble *offset,
gpointer data);
/**
* PikaEevlOptions:
* @unit_resolver_proc: Unit resolver callback.
* @data: Data passed to unit resolver.
* @ratio_expressions: Allow ratio expressions
* @ratio_invert: Invert ratios
* @ratio_quantity: Quantity to multiply ratios by
*/
typedef struct
{
PikaEevlUnitResolverProc unit_resolver_proc;
gpointer data;
gboolean ratio_expressions;
gboolean ratio_invert;
PikaEevlQuantity ratio_quantity;
} PikaEevlOptions;
#define PIKA_EEVL_OPTIONS_INIT \
((const PikaEevlOptions) \
{ \
.unit_resolver_proc = NULL, \
.data = NULL, \
\
.ratio_expressions = FALSE, \
.ratio_invert = FALSE, \
.ratio_quantity = {0.0, 0} \
})
gboolean pika_eevl_evaluate (const gchar *string,
const PikaEevlOptions *options,
PikaEevlQuantity *result,
const gchar **error_pos,
GError **error);
G_END_DECLS
#endif /* __PIKA_EEVL_H__ */

View File

@ -0,0 +1,211 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaenumcombobox.c
* Copyright (C) 2004 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "pikawidgetstypes.h"
#include "pikaenumcombobox.h"
#include "pikaenumstore.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikaenumcombobox
* @title: PikaEnumComboBox
* @short_description: A #PikaIntComboBox subclass for selecting an enum value.
*
* A #GtkComboBox subclass for selecting an enum value.
**/
enum
{
PROP_0,
PROP_MODEL
};
static void pika_enum_combo_box_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec);
static void pika_enum_combo_box_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE (PikaEnumComboBox, pika_enum_combo_box,
PIKA_TYPE_INT_COMBO_BOX)
#define parent_class pika_enum_combo_box_parent_class
static void
pika_enum_combo_box_class_init (PikaEnumComboBoxClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->set_property = pika_enum_combo_box_set_property;
object_class->get_property = pika_enum_combo_box_get_property;
/* override the "model" property of GtkComboBox */
g_object_class_install_property (object_class,
PROP_MODEL,
g_param_spec_object ("model",
"Model",
"The enum store used by this combo box",
PIKA_TYPE_ENUM_STORE,
PIKA_PARAM_READWRITE));
}
static void
pika_enum_combo_box_init (PikaEnumComboBox *combo_box)
{
}
static void
pika_enum_combo_box_set_property (GObject *object,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
GtkComboBox *combo_box = GTK_COMBO_BOX (object);
switch (prop_id)
{
case PROP_MODEL:
gtk_combo_box_set_model (combo_box, g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
pika_enum_combo_box_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkComboBox *combo_box = GTK_COMBO_BOX (object);
switch (prop_id)
{
case PROP_MODEL:
g_value_set_object (value, gtk_combo_box_get_model (combo_box));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
/**
* pika_enum_combo_box_new:
* @enum_type: the #GType of an enum.
*
* Creates a #GtkComboBox readily filled with all enum values from a
* given @enum_type. The enum needs to be registered to the type
* system. It should also have %PikaEnumDesc descriptions registered
* that contain translatable value names. This is the case for the
* enums used in the PIKA PDB functions.
*
* This is just a convenience function. If you need more control over
* the enum values that appear in the combo_box, you can create your
* own #PikaEnumStore and use pika_enum_combo_box_new_with_model().
*
* Returns: a new #PikaEnumComboBox.
*
* Since: 2.4
**/
GtkWidget *
pika_enum_combo_box_new (GType enum_type)
{
GtkListStore *store;
GtkWidget *combo_box;
g_return_val_if_fail (G_TYPE_IS_ENUM (enum_type), NULL);
store = pika_enum_store_new (enum_type);
combo_box = g_object_new (PIKA_TYPE_ENUM_COMBO_BOX,
"model", store,
NULL);
g_object_unref (store);
return combo_box;
}
/**
* pika_enum_combo_box_new_with_model
* @enum_store: a #PikaEnumStore to use as the model
*
* Creates a #GtkComboBox for the given @enum_store.
*
* Returns: a new #PikaEnumComboBox.
*
* Since: 2.4
**/
GtkWidget *
pika_enum_combo_box_new_with_model (PikaEnumStore *enum_store)
{
g_return_val_if_fail (PIKA_IS_ENUM_STORE (enum_store), NULL);
return g_object_new (PIKA_TYPE_ENUM_COMBO_BOX,
"model", enum_store,
NULL);
}
/**
* pika_enum_combo_box_set_icon_prefix:
* @combo_box: a #PikaEnumComboBox
* @icon_prefix: a prefix to create icon names from enum values
*
* Attempts to create icons for all items in the @combo_box. See
* pika_enum_store_set_icon_prefix() to find out what to use as
* @icon_prefix.
*
* Since: 2.10
**/
void
pika_enum_combo_box_set_icon_prefix (PikaEnumComboBox *combo_box,
const gchar *icon_prefix)
{
GtkTreeModel *model;
g_return_if_fail (PIKA_IS_ENUM_COMBO_BOX (combo_box));
model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo_box));
pika_enum_store_set_icon_prefix (PIKA_ENUM_STORE (model), icon_prefix);
}

View File

@ -0,0 +1,77 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaenumcombobox.h
* Copyright (C) 2004 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_ENUM_COMBO_BOX_H__
#define __PIKA_ENUM_COMBO_BOX_H__
#include <libpikawidgets/pikaintcombobox.h>
G_BEGIN_DECLS
#define PIKA_TYPE_ENUM_COMBO_BOX (pika_enum_combo_box_get_type ())
#define PIKA_ENUM_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_ENUM_COMBO_BOX, PikaEnumComboBox))
#define PIKA_ENUM_COMBO_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_ENUM_COMBO_BOX, PikaEnumComboBoxClass))
#define PIKA_IS_ENUM_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_ENUM_COMBO_BOX))
#define PIKA_IS_ENUM_COMBO_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_ENUM_COMBO_BOX))
#define PIKA_ENUM_COMBO_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_ENUM_COMBO_BOX, PikaEnumComboBoxClass))
typedef struct _PikaEnumComboBoxPrivate PikaEnumComboBoxPrivate;
typedef struct _PikaEnumComboBoxClass PikaEnumComboBoxClass;
struct _PikaEnumComboBox
{
PikaIntComboBox parent_instance;
PikaEnumComboBoxPrivate *priv;
};
struct _PikaEnumComboBoxClass
{
PikaIntComboBoxClass parent_class;
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_enum_combo_box_get_type (void) G_GNUC_CONST;
GtkWidget * pika_enum_combo_box_new (GType enum_type);
GtkWidget * pika_enum_combo_box_new_with_model (PikaEnumStore *enum_store);
void pika_enum_combo_box_set_icon_prefix (PikaEnumComboBox *combo_box,
const gchar *icon_prefix);
G_END_DECLS
#endif /* __PIKA_ENUM_COMBO_BOX_H__ */

View File

@ -0,0 +1,231 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaenumlabel.c
* Copyright (C) 2005 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "pikawidgetstypes.h"
#include "pikaenumlabel.h"
/**
* SECTION: pikaenumlabel
* @title: PikaEnumLabel
* @short_description: A #GtkLabel subclass that displays an enum value.
*
* A #GtkLabel subclass that displays an enum value.
**/
enum
{
PROP_0,
PROP_ENUM_TYPE,
PROP_ENUM_VALUE
};
struct _PikaEnumLabelPrivate
{
GEnumClass *enum_class;
};
#define GET_PRIVATE(obj) (((PikaEnumLabel *) (obj))->priv)
static void pika_enum_label_finalize (GObject *object);
static void pika_enum_label_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_enum_label_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE_WITH_PRIVATE (PikaEnumLabel, pika_enum_label, GTK_TYPE_LABEL)
#define parent_class pika_enum_label_parent_class
static void
pika_enum_label_class_init (PikaEnumLabelClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = pika_enum_label_finalize;
object_class->get_property = pika_enum_label_get_property;
object_class->set_property = pika_enum_label_set_property;
/**
* PikaEnumLabel:enum-type:
*
* The #GType of the enum.
*
* Since: 2.8
**/
g_object_class_install_property (object_class, PROP_ENUM_TYPE,
g_param_spec_gtype ("enum-type",
"Enum Type",
"The type of the displayed enum",
G_TYPE_NONE,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
/**
* PikaEnumLabel:enum-value:
*
* The value to display.
*
* Since: 2.8
**/
g_object_class_install_property (object_class, PROP_ENUM_VALUE,
g_param_spec_int ("enum-value",
"Enum Value",
"The enum value to display",
G_MININT, G_MAXINT, 0,
PIKA_PARAM_WRITABLE |
G_PARAM_CONSTRUCT));
}
static void
pika_enum_label_init (PikaEnumLabel *enum_label)
{
enum_label->priv = pika_enum_label_get_instance_private (enum_label);
}
static void
pika_enum_label_finalize (GObject *object)
{
PikaEnumLabelPrivate *private = GET_PRIVATE (object);
g_clear_pointer (&private->enum_class, g_type_class_unref);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_enum_label_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaEnumLabelPrivate *private = GET_PRIVATE (object);
switch (property_id)
{
case PROP_ENUM_TYPE:
if (private->enum_class)
g_value_set_gtype (value, G_TYPE_FROM_CLASS (private->enum_class));
else
g_value_set_gtype (value, G_TYPE_NONE);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_enum_label_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaEnumLabel *label = PIKA_ENUM_LABEL (object);
PikaEnumLabelPrivate *private = GET_PRIVATE (label);
switch (property_id)
{
case PROP_ENUM_TYPE:
private->enum_class = g_type_class_ref (g_value_get_gtype (value));
break;
case PROP_ENUM_VALUE:
pika_enum_label_set_value (label, g_value_get_int (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/**
* pika_enum_label_new:
* @enum_type: the #GType of an enum
* @value: an enum value
*
* Returns: a new #PikaEnumLabel.
*
* Since: 2.4
**/
GtkWidget *
pika_enum_label_new (GType enum_type,
gint value)
{
g_return_val_if_fail (G_TYPE_IS_ENUM (enum_type), NULL);
return g_object_new (PIKA_TYPE_ENUM_LABEL,
"enum-type", enum_type,
"enum-value", value,
NULL);
}
/**
* pika_enum_label_set_value
* @label: a #PikaEnumLabel
* @value: an enum value
*
* Since: 2.4
**/
void
pika_enum_label_set_value (PikaEnumLabel *label,
gint value)
{
PikaEnumLabelPrivate *private;
const gchar *nick;
const gchar *desc;
g_return_if_fail (PIKA_IS_ENUM_LABEL (label));
private = GET_PRIVATE (label);
if (! pika_enum_get_value (G_TYPE_FROM_CLASS (private->enum_class), value,
NULL, &nick, &desc, NULL))
{
g_warning ("%s: %d is not valid for enum of type '%s'",
G_STRLOC, value,
g_type_name (G_TYPE_FROM_CLASS (private->enum_class)));
return;
}
if (! desc)
desc = nick;
gtk_label_set_text (GTK_LABEL (label), desc);
}

View File

@ -0,0 +1,76 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaenumlabel.h
* Copyright (C) 2005 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_ENUM__LABEL_H__
#define __PIKA_ENUM__LABEL_H__
G_BEGIN_DECLS
#define PIKA_TYPE_ENUM_LABEL (pika_enum_label_get_type ())
#define PIKA_ENUM_LABEL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_ENUM_LABEL, PikaEnumLabel))
#define PIKA_ENUM_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_ENUM_LABEL, PikaEnumLabelClass))
#define PIKA_IS_ENUM_LABEL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_ENUM_LABEL))
#define PIKA_IS_ENUM_LABEL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_ENUM_LABEL))
#define PIKA_ENUM_LABEL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_ENUM_LABEL, PikaEnumLabelClass))
typedef struct _PikaEnumLabelPrivate PikaEnumLabelPrivate;
typedef struct _PikaEnumLabelClass PikaEnumLabelClass;
struct _PikaEnumLabel
{
GtkLabel parent_instance;
PikaEnumLabelPrivate *priv;
};
struct _PikaEnumLabelClass
{
GtkLabelClass parent_class;
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_enum_label_get_type (void) G_GNUC_CONST;
GtkWidget * pika_enum_label_new (GType enum_type,
gint value);
void pika_enum_label_set_value (PikaEnumLabel *label,
gint value);
G_END_DECLS
#endif /* __PIKA_ENUM_LABEL_H__ */

View File

@ -0,0 +1,395 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaenumstore.c
* Copyright (C) 2004-2007 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "pikawidgetstypes.h"
#include "pikaenumstore.h"
/**
* SECTION: pikaenumstore
* @title: PikaEnumStore
* @short_description: A #PikaIntStore subclass that keeps enum values.
*
* A #PikaIntStore subclass that keeps enum values.
**/
enum
{
PROP_0,
PROP_ENUM_TYPE
};
struct _PikaEnumStorePrivate
{
GEnumClass *enum_class;
};
#define GET_PRIVATE(obj) (((PikaEnumStore *) (obj))->priv)
static void pika_enum_store_finalize (GObject *object);
static void pika_enum_store_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_enum_store_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_enum_store_add_value (GtkListStore *store,
GEnumValue *value);
G_DEFINE_TYPE_WITH_PRIVATE (PikaEnumStore, pika_enum_store, PIKA_TYPE_INT_STORE)
#define parent_class pika_enum_store_parent_class
static void
pika_enum_store_class_init (PikaEnumStoreClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = pika_enum_store_finalize;
object_class->set_property = pika_enum_store_set_property;
object_class->get_property = pika_enum_store_get_property;
/**
* PikaEnumStore:enum-type:
*
* Sets the #GType of the enum to be used in the store.
*
* Since: 2.4
*/
g_object_class_install_property (object_class,
PROP_ENUM_TYPE,
g_param_spec_gtype ("enum-type",
"Enum Type",
"The type of the enum",
G_TYPE_ENUM,
G_PARAM_CONSTRUCT_ONLY |
PIKA_PARAM_READWRITE));
}
static void
pika_enum_store_init (PikaEnumStore *store)
{
store->priv = pika_enum_store_get_instance_private (store);
}
static void
pika_enum_store_finalize (GObject *object)
{
PikaEnumStorePrivate *priv = GET_PRIVATE (object);
g_clear_pointer (&priv->enum_class, g_type_class_unref);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_enum_store_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaEnumStorePrivate *priv = GET_PRIVATE (object);
switch (property_id)
{
case PROP_ENUM_TYPE:
g_return_if_fail (priv->enum_class == NULL);
priv->enum_class = g_type_class_ref (g_value_get_gtype (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_enum_store_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaEnumStorePrivate *priv = GET_PRIVATE (object);
switch (property_id)
{
case PROP_ENUM_TYPE:
g_value_set_gtype (value, (priv->enum_class ?
G_TYPE_FROM_CLASS (priv->enum_class) :
G_TYPE_NONE));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_enum_store_add_value (GtkListStore *store,
GEnumValue *value)
{
PikaEnumStorePrivate *priv = GET_PRIVATE (store);
GtkTreeIter iter = { 0, };
const gchar *desc;
const gchar *abbrev;
gchar *stripped;
desc = pika_enum_value_get_desc (priv->enum_class, value);
abbrev = pika_enum_value_get_abbrev (priv->enum_class, value);
/* no mnemonics in combo boxes */
stripped = pika_strip_uline (desc);
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
PIKA_INT_STORE_VALUE, value->value,
PIKA_INT_STORE_LABEL, stripped,
PIKA_INT_STORE_ABBREV, abbrev,
-1);
g_free (stripped);
}
/**
* pika_enum_store_new:
* @enum_type: the #GType of an enum.
*
* Creates a new #PikaEnumStore, derived from #GtkListStore and fills
* it with enum values. The enum needs to be registered to the type
* system and should have translatable value names.
*
* Returns: a new #PikaEnumStore.
*
* Since: 2.4
**/
GtkListStore *
pika_enum_store_new (GType enum_type)
{
GtkListStore *store;
GEnumClass *enum_class;
g_return_val_if_fail (G_TYPE_IS_ENUM (enum_type), NULL);
enum_class = g_type_class_ref (enum_type);
store = pika_enum_store_new_with_range (enum_type,
enum_class->minimum,
enum_class->maximum);
g_type_class_unref (enum_class);
return store;
}
/**
* pika_enum_store_new_with_range:
* @enum_type: the #GType of an enum.
* @minimum: the minimum value to include
* @maximum: the maximum value to include
*
* Creates a new #PikaEnumStore like pika_enum_store_new() but allows
* to limit the enum values to a certain range. Values smaller than
* @minimum or larger than @maximum are not added to the store.
*
* Returns: a new #PikaEnumStore.
*
* Since: 2.4
**/
GtkListStore *
pika_enum_store_new_with_range (GType enum_type,
gint minimum,
gint maximum)
{
PikaEnumStorePrivate *priv;
GtkListStore *store;
GEnumValue *value;
g_return_val_if_fail (G_TYPE_IS_ENUM (enum_type), NULL);
store = g_object_new (PIKA_TYPE_ENUM_STORE,
"enum-type", enum_type,
NULL);
priv = GET_PRIVATE (store);
for (value = priv->enum_class->values;
value->value_name;
value++)
{
if (value->value < minimum || value->value > maximum)
continue;
pika_enum_store_add_value (store, value);
}
return store;
}
/**
* pika_enum_store_new_with_values: (skip)
* @enum_type: the #GType of an enum.
* @n_values: the number of enum values to include
* @...: a list of enum values (exactly @n_values)
*
* Creates a new #PikaEnumStore like pika_enum_store_new() but allows
* to explicitly list the enum values that should be added to the
* store.
*
* Returns: a new #PikaEnumStore.
*
* Since: 2.4
**/
GtkListStore *
pika_enum_store_new_with_values (GType enum_type,
gint n_values,
...)
{
GtkListStore *store;
va_list args;
va_start (args, n_values);
store = pika_enum_store_new_with_values_valist (enum_type, n_values, args);
va_end (args);
return store;
}
/**
* pika_enum_store_new_with_values_valist: (skip)
* @enum_type: the #GType of an enum.
* @n_values: the number of enum values to include
* @args: a va_list of enum values (exactly @n_values)
*
* See pika_enum_store_new_with_values().
*
* Returns: a new #PikaEnumStore.
*
* Since: 2.4
**/
GtkListStore *
pika_enum_store_new_with_values_valist (GType enum_type,
gint n_values,
va_list args)
{
PikaEnumStorePrivate *priv;
GtkListStore *store;
GEnumValue *value;
gint i;
g_return_val_if_fail (G_TYPE_IS_ENUM (enum_type), NULL);
g_return_val_if_fail (n_values > 1, NULL);
store = g_object_new (PIKA_TYPE_ENUM_STORE,
"enum-type", enum_type,
NULL);
priv = GET_PRIVATE (store);
for (i = 0; i < n_values; i++)
{
value = g_enum_get_value (priv->enum_class,
va_arg (args, gint));
if (value)
pika_enum_store_add_value (store, value);
}
return store;
}
/**
* pika_enum_store_set_icon_prefix:
* @store: a #PikaEnumStore
* @icon_prefix: a prefix to create icon names from enum values
*
* Creates an icon name for each enum value in the @store by appending
* the value's nick to the given @icon_prefix, separated by a hyphen.
*
* See also: pika_enum_combo_box_set_icon_prefix().
*
* Since: 2.10
**/
void
pika_enum_store_set_icon_prefix (PikaEnumStore *store,
const gchar *icon_prefix)
{
PikaEnumStorePrivate *priv;
GtkTreeModel *model;
GtkTreeIter iter;
gboolean iter_valid;
g_return_if_fail (PIKA_IS_ENUM_STORE (store));
priv = GET_PRIVATE (store);
model = GTK_TREE_MODEL (store);
for (iter_valid = gtk_tree_model_get_iter_first (model, &iter);
iter_valid;
iter_valid = gtk_tree_model_iter_next (model, &iter))
{
gchar *icon_name = NULL;
if (icon_prefix)
{
GEnumValue *enum_value;
gint value;
gtk_tree_model_get (model, &iter,
PIKA_INT_STORE_VALUE, &value,
-1);
enum_value = g_enum_get_value (priv->enum_class, value);
if (enum_value)
{
icon_name = g_strconcat (icon_prefix, "-",
enum_value->value_nick,
NULL);
}
}
gtk_list_store_set (GTK_LIST_STORE (store), &iter,
PIKA_INT_STORE_ICON_NAME, icon_name,
-1);
if (icon_name)
g_free (icon_name);
}
}

View File

@ -0,0 +1,86 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaenumstore.h
* Copyright (C) 2004 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_ENUM_STORE_H__
#define __PIKA_ENUM_STORE_H__
#include <libpikawidgets/pikaintstore.h>
G_BEGIN_DECLS
#define PIKA_TYPE_ENUM_STORE (pika_enum_store_get_type ())
#define PIKA_ENUM_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_ENUM_STORE, PikaEnumStore))
#define PIKA_ENUM_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_ENUM_STORE, PikaEnumStoreClass))
#define PIKA_IS_ENUM_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_ENUM_STORE))
#define PIKA_IS_ENUM_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_ENUM_STORE))
#define PIKA_ENUM_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_ENUM_STORE, PikaEnumStoreClass))
typedef struct _PikaEnumStorePrivate PikaEnumStorePrivate;
typedef struct _PikaEnumStoreClass PikaEnumStoreClass;
struct _PikaEnumStore
{
PikaIntStore parent_instance;
PikaEnumStorePrivate *priv;
};
struct _PikaEnumStoreClass
{
PikaIntStoreClass parent_class;
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_enum_store_get_type (void) G_GNUC_CONST;
GtkListStore * pika_enum_store_new (GType enum_type);
GtkListStore * pika_enum_store_new_with_range (GType enum_type,
gint minimum,
gint maximum);
GtkListStore * pika_enum_store_new_with_values (GType enum_type,
gint n_values,
...);
GtkListStore * pika_enum_store_new_with_values_valist (GType enum_type,
gint n_values,
va_list args);
void pika_enum_store_set_icon_prefix (PikaEnumStore *store,
const gchar *icon_prefix);
G_END_DECLS
#endif /* __PIKA_ENUM_STORE_H__ */

View File

@ -0,0 +1,476 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaenumwidgets.c
* Copyright (C) 2002-2004 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "pikawidgetstypes.h"
#include "pikaenumwidgets.h"
#include "pikaframe.h"
#include "pikahelpui.h"
/**
* SECTION: pikaenumwidgets
* @title: PikaEnumWidgets
* @short_description: A set of utility functions to create widgets
* based on enums.
*
* A set of utility functions to create widgets based on enums.
**/
/**
* pika_enum_radio_box_new:
* @enum_type: the #GType of an enum.
* @callback: (nullable): a callback to connect to the "toggled" signal of each
* #GtkRadioButton that is created.
* @callback_data: data to pass to the @callback.
* @callback_data_destroy: Destroy function for @callback_data.
* @first_button: (out) (optional) (transfer none):
* Returns the first button in the created group.
*
* Creates a new group of #GtkRadioButtons representing the enum
* values. A group of radiobuttons is a good way to represent enums
* with up to three or four values. Often it is better to use a
* #PikaEnumComboBox instead.
*
* Returns: (transfer full): a new #GtkBox holding a group of #GtkRadioButtons.
*
* Since: 2.4
**/
GtkWidget *
pika_enum_radio_box_new (GType enum_type,
GCallback callback,
gpointer callback_data,
GDestroyNotify callback_data_destroy,
GtkWidget **first_button)
{
GEnumClass *enum_class;
GtkWidget *vbox;
g_return_val_if_fail (G_TYPE_IS_ENUM (enum_type), NULL);
enum_class = g_type_class_ref (enum_type);
vbox = pika_enum_radio_box_new_with_range (enum_type,
enum_class->minimum,
enum_class->maximum,
callback, callback_data,
callback_data_destroy,
first_button);
g_type_class_unref (enum_class);
return vbox;
}
/**
* pika_enum_radio_box_new_with_range:
* @minimum: the minimum enum value
* @maximum: the maximum enum value
* @enum_type: the #GType of an enum.
* @callback: (nullable): a callback to connect to the "toggled" signal of each
* #GtkRadioButton that is created.
* @callback_data: data to pass to the @callback.
* @callback_data_destroy: Destroy function for @callback_data.
* @first_button: (out) (optional) (transfer none):
* Returns the first button in the created group.
*
* Just like pika_enum_radio_box_new(), this function creates a group
* of radio buttons, but additionally it supports limiting the range
* of available enum values.
*
* Returns: (transfer full): a new vertical #GtkBox holding a group of
* #GtkRadioButtons
*
* Since: 2.4
**/
GtkWidget *
pika_enum_radio_box_new_with_range (GType enum_type,
gint minimum,
gint maximum,
GCallback callback,
gpointer callback_data,
GDestroyNotify callback_data_destroy,
GtkWidget **first_button)
{
GtkWidget *vbox;
GtkWidget *button;
GEnumClass *enum_class;
GEnumValue *value;
GSList *group = NULL;
g_return_val_if_fail (G_TYPE_IS_ENUM (enum_type), NULL);
enum_class = g_type_class_ref (enum_type);
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 1);
g_object_weak_ref (G_OBJECT (vbox),
(GWeakNotify) g_type_class_unref, enum_class);
if (callback_data_destroy)
g_object_weak_ref (G_OBJECT (vbox),
(GWeakNotify) callback_data_destroy, callback_data);
if (first_button)
*first_button = NULL;
for (value = enum_class->values; value->value_name; value++)
{
const gchar *desc;
if (value->value < minimum || value->value > maximum)
continue;
desc = pika_enum_value_get_desc (enum_class, value);
button = gtk_radio_button_new_with_mnemonic (group, desc);
if (first_button && *first_button == NULL)
*first_button = button;
group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_object_set_data (G_OBJECT (button), "pika-item-data",
GINT_TO_POINTER (value->value));
if (callback)
g_signal_connect (button, "toggled",
callback,
callback_data);
}
return vbox;
}
/**
* pika_enum_radio_frame_new:
* @enum_type: the #GType of an enum.
* @label_widget: (nullable): a #GtkWidget to use as label for the frame
* that will hold the radio box.
* @callback: (nullable): a callback to connect to the "toggled" signal of each
* #GtkRadioButton that is created.
* @callback_data: data to pass to the @callback.
* @callback_data_destroy: Destroy function for @callback_data.
* @first_button: (out) (optional) (transfer none):
* Returns the first button in the created group.
*
* Calls pika_enum_radio_box_new() and puts the resulting vbox into a
* #GtkFrame.
*
* Returns: (transfer full): a new #GtkFrame holding a group of #GtkRadioButtons.
*
* Since: 2.4
**/
GtkWidget *
pika_enum_radio_frame_new (GType enum_type,
GtkWidget *label_widget,
GCallback callback,
gpointer callback_data,
GDestroyNotify callback_data_destroy,
GtkWidget **first_button)
{
GtkWidget *frame;
GtkWidget *radio_box;
g_return_val_if_fail (G_TYPE_IS_ENUM (enum_type), NULL);
g_return_val_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget),
NULL);
frame = pika_frame_new (NULL);
if (label_widget)
{
gtk_frame_set_label_widget (GTK_FRAME (frame), label_widget);
gtk_widget_show (label_widget);
}
radio_box = pika_enum_radio_box_new (enum_type,
callback, callback_data,
callback_data_destroy,
first_button);
gtk_container_add (GTK_CONTAINER (frame), radio_box);
gtk_widget_show (radio_box);
return frame;
}
/**
* pika_enum_radio_frame_new_with_range:
* @enum_type: the #GType of an enum.
* @minimum: the minimum enum value
* @maximum: the maximum enum value
* @label_widget: (nullable): a widget to put into the frame that will hold the radio box.
* @callback: (nullable): a callback to connect to the "toggled" signal of each
* #GtkRadioButton that is created.
* @callback_data: data to pass to the @callback.
* @callback_data_destroy: Destroy function for @callback_data.
* @first_button: (out) (optional) (transfer none):
* Returns the first button in the created group.
*
* Calls pika_enum_radio_box_new_with_range() and puts the resulting
* vertical box into a #GtkFrame.
*
* Returns: (transfer full): a new #GtkFrame holding a group of #GtkRadioButtons.
*
* Since: 2.4
**/
GtkWidget *
pika_enum_radio_frame_new_with_range (GType enum_type,
gint minimum,
gint maximum,
GtkWidget *label_widget,
GCallback callback,
gpointer callback_data,
GDestroyNotify callback_data_destroy,
GtkWidget **first_button)
{
GtkWidget *frame;
GtkWidget *radio_box;
g_return_val_if_fail (G_TYPE_IS_ENUM (enum_type), NULL);
g_return_val_if_fail (label_widget == NULL || GTK_IS_WIDGET (label_widget),
NULL);
frame = pika_frame_new (NULL);
if (label_widget)
{
gtk_frame_set_label_widget (GTK_FRAME (frame), label_widget);
gtk_widget_show (label_widget);
}
radio_box = pika_enum_radio_box_new_with_range (enum_type,
minimum,
maximum,
callback, callback_data,
callback_data_destroy,
first_button);
gtk_container_add (GTK_CONTAINER (frame), radio_box);
gtk_widget_show (radio_box);
return frame;
}
/**
* pika_enum_icon_box_new:
* @enum_type: the #GType of an enum.
* @icon_prefix: the prefix of the group of icon names to use.
* @icon_size: the icon size for the icons
* @callback: (nullable): a callback to connect to the "toggled" signal of each
* #GtkRadioButton that is created.
* @callback_data: data to pass to the @callback.
* @callback_data_destroy: Destroy function for @callback_data.
* @first_button: (out) (optional) (transfer none):
* Returns the first button in the created group.
*
* Creates a horizontal box of radio buttons with named icons. The
* icon name for each icon is created by appending the enum_value's
* nick to the given @icon_prefix.
*
* Returns: (transfer full): a new horizontal #GtkBox holding a group of #GtkRadioButtons.
*
* Since: 2.10
**/
GtkWidget *
pika_enum_icon_box_new (GType enum_type,
const gchar *icon_prefix,
GtkIconSize icon_size,
GCallback callback,
gpointer callback_data,
GDestroyNotify callback_data_destroy,
GtkWidget **first_button)
{
GEnumClass *enum_class;
GtkWidget *box;
g_return_val_if_fail (G_TYPE_IS_ENUM (enum_type), NULL);
enum_class = g_type_class_ref (enum_type);
box = pika_enum_icon_box_new_with_range (enum_type,
enum_class->minimum,
enum_class->maximum,
icon_prefix, icon_size,
callback, callback_data,
callback_data_destroy,
first_button);
g_type_class_unref (enum_class);
return box;
}
/**
* pika_enum_icon_box_new_with_range:
* @enum_type: the #GType of an enum.
* @minimum: the minumim enum value
* @maximum: the maximum enum value
* @icon_prefix: the prefix of the group of icon names to use.
* @icon_size: the icon size for the icons
* @callback: (nullable): a callback to connect to the "toggled" signal of each
* #GtkRadioButton that is created.
* @callback_data: data to pass to the @callback.
* @callback_data_destroy: Destroy function for @callback_data.
* @first_button: (out) (optional) (transfer none):
* Returns the first button in the created group.
*
* Just like pika_enum_icon_box_new(), this function creates a group
* of radio buttons, but additionally it supports limiting the range
* of available enum values.
*
* Returns: (transfer full): a new horizontal #GtkBox holding a group of #GtkRadioButtons.
*
* Since: 2.10
**/
GtkWidget *
pika_enum_icon_box_new_with_range (GType enum_type,
gint minimum,
gint maximum,
const gchar *icon_prefix,
GtkIconSize icon_size,
GCallback callback,
gpointer callback_data,
GDestroyNotify callback_data_destroy,
GtkWidget **first_button)
{
GtkWidget *hbox;
GtkWidget *button;
GtkWidget *image;
GEnumClass *enum_class;
GEnumValue *value;
gchar *icon_name;
GSList *group = NULL;
g_return_val_if_fail (G_TYPE_IS_ENUM (enum_type), NULL);
g_return_val_if_fail (icon_prefix != NULL, NULL);
enum_class = g_type_class_ref (enum_type);
hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
g_object_weak_ref (G_OBJECT (hbox),
(GWeakNotify) g_type_class_unref, enum_class);
if (callback_data_destroy)
g_object_weak_ref (G_OBJECT (hbox),
(GWeakNotify) callback_data_destroy, callback_data);
if (first_button)
*first_button = NULL;
for (value = enum_class->values; value->value_name; value++)
{
if (value->value < minimum || value->value > maximum)
continue;
button = gtk_radio_button_new (group);
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
gtk_toggle_button_set_mode (GTK_TOGGLE_BUTTON (button), FALSE);
if (first_button && *first_button == NULL)
*first_button = button;
icon_name = g_strconcat (icon_prefix, "-", value->value_nick, NULL);
image = gtk_image_new_from_icon_name (icon_name, icon_size);
g_free (icon_name);
if (image)
{
gtk_container_add (GTK_CONTAINER (button), image);
gtk_widget_show (image);
}
pika_help_set_help_data (button,
pika_enum_value_get_desc (enum_class, value),
NULL);
group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_object_set_data (G_OBJECT (button), "pika-item-data",
GINT_TO_POINTER (value->value));
if (callback)
g_signal_connect (button, "toggled",
callback,
callback_data);
}
return hbox;
}
/**
* pika_enum_icon_box_set_child_padding:
* @icon_box: an icon box widget
* @xpad: horizontal padding
* @ypad: vertical padding
*
* Sets the padding of all buttons in a box created by
* pika_enum_icon_box_new().
*
* Since: 2.10
**/
void
pika_enum_icon_box_set_child_padding (GtkWidget *icon_box,
gint xpad,
gint ypad)
{
GList *children;
GList *list;
g_return_if_fail (GTK_IS_CONTAINER (icon_box));
children = gtk_container_get_children (GTK_CONTAINER (icon_box));
for (list = children; list; list = g_list_next (list))
{
GtkWidget *child = gtk_bin_get_child (GTK_BIN (list->data));
gint start, end;
gint top, bottom;
g_object_get (child,
"margin-start", &start,
"margin-end", &end,
"margin-top", &top,
"margin-bottom", &bottom,
NULL);
g_object_set (child,
"margin-start", xpad < 0 ? start : xpad,
"margin-end", xpad < 0 ? end : xpad,
"margin-top", ypad < 0 ? top : ypad,
"margin-bottom", ypad < 0 ? bottom : ypad,
NULL);
}
g_list_free (children);
}

View File

@ -0,0 +1,82 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaenumwidgets.h
* Copyright (C) 2002-2004 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_ENUM_WIDGETS_H__
#define __PIKA_ENUM_WIDGETS_H__
G_BEGIN_DECLS
GtkWidget * pika_enum_radio_box_new (GType enum_type,
GCallback callback,
gpointer callback_data,
GDestroyNotify callback_data_destroy,
GtkWidget **first_button);
GtkWidget * pika_enum_radio_box_new_with_range (GType enum_type,
gint minimum,
gint maximum,
GCallback callback,
gpointer callback_data,
GDestroyNotify callback_data_destroy,
GtkWidget **first_button);
GtkWidget * pika_enum_radio_frame_new (GType enum_type,
GtkWidget *label_widget,
GCallback callback,
gpointer callback_data,
GDestroyNotify callback_data_destroy,
GtkWidget **first_button);
GtkWidget * pika_enum_radio_frame_new_with_range (GType enum_type,
gint minimum,
gint maximum,
GtkWidget *label_widget,
GCallback callback,
gpointer callback_data,
GDestroyNotify callback_data_destroy,
GtkWidget **first_button);
GtkWidget * pika_enum_icon_box_new (GType enum_type,
const gchar *icon_prefix,
GtkIconSize icon_size,
GCallback callback,
gpointer callback_data,
GDestroyNotify callback_data_destroy,
GtkWidget **first_button);
GtkWidget * pika_enum_icon_box_new_with_range (GType enum_type,
gint minimum,
gint maximum,
const gchar *icon_prefix,
GtkIconSize icon_size,
GCallback callback,
gpointer callback_data,
GDestroyNotify callback_data_destroy,
GtkWidget **first_button);
void pika_enum_icon_box_set_child_padding (GtkWidget *icon_box,
gint xpad,
gint ypad);
G_END_DECLS
#endif /* __PIKA_ENUM_WIDGETS_H__ */

View File

@ -0,0 +1,530 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikafileentry.c
* Copyright (C) 1999-2004 Michael Natterer <mitch@gimp.org>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "pikawidgetstypes.h"
#include "pikadialog.h"
#undef PIKA_DISABLE_DEPRECATED
#include "pikafileentry.h"
#include "pikahelpui.h"
#include "pikaicons.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikafileentry
* @title: PikaFileEntry
* @short_description: Widget for entering a filename.
* @see_also: #PikaPathEditor
*
* This widget is used to enter filenames or directories.
*
* There is a #GtkEntry for entering the filename manually and a "..."
* button which will pop up a #GtkFileChooserDialog.
*
* You can restrict the #PikaFileEntry to directories. In this
* case the filename listbox of the #GtkFileChooser dialog will be
* set to directory mode.
*
* If you specify @check_valid as %TRUE in pika_file_entry_new() the
* entered filename will be checked for validity and a pixmap will be
* shown which indicates if the file exists or not.
*
* Whenever the user changes the filename, the "filename_changed"
* signal will be emitted.
**/
enum
{
FILENAME_CHANGED,
LAST_SIGNAL
};
struct _PikaFileEntryPrivate
{
GtkWidget *file_exists;
GtkWidget *entry;
GtkWidget *browse_button;
GtkWidget *file_dialog;
gchar *title;
gboolean dir_only;
gboolean check_valid;
};
static void pika_file_entry_dispose (GObject *object);
static void pika_file_entry_entry_changed (GtkWidget *widget,
GtkWidget *button);
static void pika_file_entry_entry_activate (GtkWidget *widget,
PikaFileEntry *entry);
static gint pika_file_entry_entry_focus_out (GtkWidget *widget,
GdkEvent *event,
PikaFileEntry *entry);
static void pika_file_entry_file_manager_clicked (GtkWidget *widget,
PikaFileEntry *entry);
static void pika_file_entry_browse_clicked (GtkWidget *widget,
PikaFileEntry *entry);
static void pika_file_entry_check_filename (PikaFileEntry *entry);
G_DEFINE_TYPE_WITH_PRIVATE (PikaFileEntry, pika_file_entry, GTK_TYPE_BOX)
#define parent_class pika_file_entry_parent_class
static guint pika_file_entry_signals[LAST_SIGNAL] = { 0 };
static void
pika_file_entry_class_init (PikaFileEntryClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
/**
* PikaFileEntry::filename-changed:
*
* This signal is emitted whenever the user changes the filename.
**/
pika_file_entry_signals[FILENAME_CHANGED] =
g_signal_new ("filename-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaFileEntryClass, filename_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
object_class->dispose = pika_file_entry_dispose;
klass->filename_changed = NULL;
}
static void
pika_file_entry_init (PikaFileEntry *entry)
{
GtkWidget *image;
GtkWidget *button;
entry->priv = pika_file_entry_get_instance_private (entry);
entry->priv->title = NULL;
entry->priv->file_dialog = NULL;
entry->priv->check_valid = FALSE;
entry->priv->file_exists = NULL;
gtk_orientable_set_orientation (GTK_ORIENTABLE (entry),
GTK_ORIENTATION_HORIZONTAL);
gtk_box_set_spacing (GTK_BOX (entry), 4);
gtk_box_set_homogeneous (GTK_BOX (entry), FALSE);
button = gtk_button_new ();
gtk_box_pack_end (GTK_BOX (entry), button, FALSE, FALSE, 0);
gtk_widget_show (button);
gtk_widget_set_sensitive (button, FALSE);
image = gtk_image_new_from_icon_name (PIKA_ICON_FILE_MANAGER,
GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_widget_show (image);
g_signal_connect (button, "clicked",
G_CALLBACK (pika_file_entry_file_manager_clicked),
entry);
pika_help_set_help_data (button,
_("Show file location in the file manager"),
NULL);
entry->priv->browse_button = gtk_button_new ();
gtk_box_pack_end (GTK_BOX (entry), entry->priv->browse_button, FALSE, FALSE, 0);
gtk_widget_show (entry->priv->browse_button);
image = gtk_image_new_from_icon_name (PIKA_ICON_DOCUMENT_OPEN,
GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (entry->priv->browse_button), image);
gtk_widget_show (image);
g_signal_connect (entry->priv->browse_button, "clicked",
G_CALLBACK (pika_file_entry_browse_clicked),
entry);
entry->priv->entry = gtk_entry_new ();
gtk_box_pack_end (GTK_BOX (entry), entry->priv->entry, TRUE, TRUE, 0);
gtk_widget_show (entry->priv->entry);
g_signal_connect (entry->priv->entry, "changed",
G_CALLBACK (pika_file_entry_entry_changed),
button);
g_signal_connect (entry->priv->entry, "activate",
G_CALLBACK (pika_file_entry_entry_activate),
entry);
g_signal_connect (entry->priv->entry, "focus-out-event",
G_CALLBACK (pika_file_entry_entry_focus_out),
entry);
}
static void
pika_file_entry_dispose (GObject *object)
{
PikaFileEntry *entry = PIKA_FILE_ENTRY (object);
g_clear_pointer (&entry->priv->file_dialog, gtk_widget_destroy);
g_clear_pointer (&entry->priv->title, g_free);
G_OBJECT_CLASS (parent_class)->dispose (object);
}
/**
* pika_file_entry_new:
* @title: The title of the #PikaFileEntry dialog.
* @filename: The initial filename.
* @dir_only: %TRUE if the file entry should accept directories only.
* @check_valid: %TRUE if the widget should check if the entered file
* really exists.
*
* You should use #GtkFileChooserButton instead.
*
* Returns: A pointer to the new #PikaFileEntry widget.
**/
GtkWidget *
pika_file_entry_new (const gchar *title,
const gchar *filename,
gboolean dir_only,
gboolean check_valid)
{
PikaFileEntry *entry;
entry = g_object_new (PIKA_TYPE_FILE_ENTRY, NULL);
entry->priv->title = g_strdup (title);
entry->priv->dir_only = dir_only;
entry->priv->check_valid = check_valid;
pika_help_set_help_data (entry->priv->browse_button,
entry->priv->dir_only ?
_("Open a file selector to browse your folders") :
_("Open a file selector to browse your files"),
NULL);
if (check_valid)
{
entry->priv->file_exists = gtk_image_new_from_icon_name ("gtk-no",
GTK_ICON_SIZE_BUTTON);
gtk_box_pack_start (GTK_BOX (entry), entry->priv->file_exists, FALSE, FALSE, 0);
gtk_widget_show (entry->priv->file_exists);
pika_help_set_help_data (entry->priv->file_exists,
entry->priv->dir_only ?
_("Indicates whether or not the folder exists") :
_("Indicates whether or not the file exists"),
NULL);
}
pika_file_entry_set_filename (entry, filename);
return GTK_WIDGET (entry);
}
/**
* pika_file_entry_get_filename:
* @entry: The file entry you want to know the filename from.
*
* Note that you have to g_free() the returned string.
*
* Returns: The file or directory the user has entered.
**/
gchar *
pika_file_entry_get_filename (PikaFileEntry *entry)
{
gchar *utf8;
gchar *filename;
g_return_val_if_fail (PIKA_IS_FILE_ENTRY (entry), NULL);
utf8 = gtk_editable_get_chars (GTK_EDITABLE (entry->priv->entry), 0, -1);
filename = g_filename_from_utf8 (utf8, -1, NULL, NULL, NULL);
g_free (utf8);
return filename;
}
/**
* pika_file_entry_set_filename:
* @entry: The file entry you want to set the filename for.
* @filename: The new filename.
*
* If you specified @check_valid as %TRUE in pika_file_entry_new()
* the #PikaFileEntry will immediately check the validity of the file
* name.
**/
void
pika_file_entry_set_filename (PikaFileEntry *entry,
const gchar *filename)
{
gchar *utf8;
g_return_if_fail (PIKA_IS_FILE_ENTRY (entry));
if (filename)
utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
else
utf8 = g_strdup ("");
gtk_entry_set_text (GTK_ENTRY (entry->priv->entry), utf8);
g_free (utf8);
/* update everything
*/
pika_file_entry_entry_activate (entry->priv->entry, entry);
}
/**
* pika_file_entry_get_entry:
* @entry: The #PikaFileEntry.
*
* Returns: (transfer none): the #GtkEntry internally used by the
* widget. The object belongs to @entry and should not be
* freed.
**/
GtkWidget *
pika_file_entry_get_entry (PikaFileEntry *entry)
{
return entry->priv->entry;
}
/* Private Functions */
static void
pika_file_entry_entry_changed (GtkWidget *widget,
GtkWidget *button)
{
const gchar *text = gtk_entry_get_text (GTK_ENTRY (widget));
if (text && strlen (text))
gtk_widget_set_sensitive (button, TRUE);
else
gtk_widget_set_sensitive (button, FALSE);
}
static void
pika_file_entry_entry_activate (GtkWidget *widget,
PikaFileEntry *entry)
{
gchar *utf8;
gchar *filename;
gint len;
/* filenames still need more sanity checking
* (erase double G_DIR_SEPARATORS, ...)
*/
utf8 = gtk_editable_get_chars (GTK_EDITABLE (widget), 0, -1);
utf8 = g_strstrip (utf8);
while (((len = strlen (utf8)) > 1) &&
(utf8[len - 1] == G_DIR_SEPARATOR))
utf8[len - 1] = '\0';
filename = g_filename_from_utf8 (utf8, -1, NULL, NULL, NULL);
g_signal_handlers_block_by_func (entry->priv->entry,
pika_file_entry_entry_activate,
entry);
gtk_entry_set_text (GTK_ENTRY (entry->priv->entry), utf8);
g_signal_handlers_unblock_by_func (entry->priv->entry,
pika_file_entry_entry_activate,
entry);
if (entry->priv->file_dialog)
gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (entry->priv->file_dialog),
filename);
g_free (filename);
g_free (utf8);
pika_file_entry_check_filename (entry);
gtk_editable_set_position (GTK_EDITABLE (entry->priv->entry), -1);
g_signal_emit (entry, pika_file_entry_signals[FILENAME_CHANGED], 0);
}
static gboolean
pika_file_entry_entry_focus_out (GtkWidget *widget,
GdkEvent *event,
PikaFileEntry *entry)
{
pika_file_entry_entry_activate (widget, entry);
return FALSE;
}
/* local callback of pika_file_entry_browse_clicked() */
static void
pika_file_entry_chooser_response (GtkWidget *dialog,
gint response_id,
PikaFileEntry *entry)
{
if (response_id == GTK_RESPONSE_OK)
{
gchar *filename;
filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
pika_file_entry_set_filename (entry, filename);
g_free (filename);
}
gtk_widget_hide (dialog);
}
static void
pika_file_entry_file_manager_clicked (GtkWidget *widget,
PikaFileEntry *entry)
{
gchar *utf8;
GFile *file;
GError *error = NULL;
utf8 = gtk_editable_get_chars (GTK_EDITABLE (entry->priv->entry), 0, -1);
file = g_file_parse_name (utf8);
g_free (utf8);
if (! pika_file_show_in_file_manager (file, &error))
{
g_message (_("Can't show file in file manager: %s"),
error->message);
g_clear_error (&error);
}
g_object_unref (file);
}
static void
pika_file_entry_browse_clicked (GtkWidget *widget,
PikaFileEntry *entry)
{
GtkFileChooser *chooser;
gchar *utf8;
gchar *filename;
utf8 = gtk_editable_get_chars (GTK_EDITABLE (entry->priv->entry), 0, -1);
filename = g_filename_from_utf8 (utf8, -1, NULL, NULL, NULL);
g_free (utf8);
if (! entry->priv->file_dialog)
{
const gchar *title = entry->priv->title;
if (! title)
{
if (entry->priv->dir_only)
title = _("Select Folder");
else
title = _("Select File");
}
entry->priv->file_dialog =
gtk_file_chooser_dialog_new (title, NULL,
entry->priv->dir_only ?
GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER :
GTK_FILE_CHOOSER_ACTION_OPEN,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_OK,
NULL);
pika_dialog_set_alternative_button_order (GTK_DIALOG (entry->priv->file_dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
chooser = GTK_FILE_CHOOSER (entry->priv->file_dialog);
gtk_window_set_position (GTK_WINDOW (chooser), GTK_WIN_POS_MOUSE);
gtk_window_set_role (GTK_WINDOW (chooser),
"pika-file-entry-file-dialog");
g_signal_connect (chooser, "response",
G_CALLBACK (pika_file_entry_chooser_response),
entry);
g_signal_connect (chooser, "delete-event",
G_CALLBACK (gtk_true),
NULL);
g_signal_connect_swapped (entry, "unmap",
G_CALLBACK (gtk_widget_hide),
chooser);
}
else
{
chooser = GTK_FILE_CHOOSER (entry->priv->file_dialog);
}
gtk_file_chooser_set_filename (chooser, filename);
g_free (filename);
gtk_window_set_screen (GTK_WINDOW (chooser), gtk_widget_get_screen (widget));
gtk_window_present (GTK_WINDOW (chooser));
}
static void
pika_file_entry_check_filename (PikaFileEntry *entry)
{
gchar *utf8;
gchar *filename;
gboolean exists;
if (! entry->priv->check_valid || ! entry->priv->file_exists)
return;
utf8 = gtk_editable_get_chars (GTK_EDITABLE (entry->priv->entry), 0, -1);
filename = g_filename_from_utf8 (utf8, -1, NULL, NULL, NULL);
g_free (utf8);
if (entry->priv->dir_only)
exists = g_file_test (filename, G_FILE_TEST_IS_DIR);
else
exists = g_file_test (filename, G_FILE_TEST_IS_REGULAR);
g_free (filename);
gtk_image_set_from_icon_name (GTK_IMAGE (entry->priv->file_exists),
exists ? "gtk-yes" : "gtk-no",
GTK_ICON_SIZE_BUTTON);
}

View File

@ -0,0 +1,90 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikafileentry.h
* Copyright (C) 1999-2004 Michael Natterer <mitch@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#ifndef PIKA_DISABLE_DEPRECATED
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_FILE_ENTRY_H__
#define __PIKA_FILE_ENTRY_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
#define PIKA_TYPE_FILE_ENTRY (pika_file_entry_get_type ())
#define PIKA_FILE_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_FILE_ENTRY, PikaFileEntry))
#define PIKA_FILE_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_FILE_ENTRY, PikaFileEntryClass))
#define PIKA_IS_FILE_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, PIKA_TYPE_FILE_ENTRY))
#define PIKA_IS_FILE_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_FILE_ENTRY))
#define PIKA_FILE_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_FILE_ENTRY, PikaFileEntryClass))
typedef struct _PikaFileEntryPrivate PikaFileEntryPrivate;
typedef struct _PikaFileEntryClass PikaFileEntryClass;
struct _PikaFileEntry
{
GtkBox parent_instance;
PikaFileEntryPrivate *priv;
};
struct _PikaFileEntryClass
{
GtkBoxClass parent_class;
void (* filename_changed) (PikaFileEntry *entry);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_file_entry_get_type (void) G_GNUC_CONST;
GtkWidget * pika_file_entry_new (const gchar *title,
const gchar *filename,
gboolean dir_only,
gboolean check_valid);
gchar * pika_file_entry_get_filename (PikaFileEntry *entry);
void pika_file_entry_set_filename (PikaFileEntry *entry,
const gchar *filename);
GtkWidget * pika_file_entry_get_entry (PikaFileEntry *entry);
G_END_DECLS
#endif /* __PIKA_FILE_ENTRY_H__ */
#endif /* PIKA_DISABLE_DEPRECATED */

264
libpikawidgets/pikaframe.c Normal file
View File

@ -0,0 +1,264 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaframe.c
* Copyright (C) 2004 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <babl/babl.h>
#include <gtk/gtk.h>
#include "pikawidgetstypes.h"
#include "pikaframe.h"
#include "pikawidgetsutils.h"
/**
* SECTION: pikaframe
* @title: PikaFrame
* @short_description: A widget providing a HIG-compliant subclass
* of #GtkFrame.
*
* A widget providing a HIG-compliant subclass of #GtkFrame.
**/
#define DEFAULT_LABEL_SPACING 6
#define DEFAULT_LABEL_BOLD TRUE
#define PIKA_FRAME_INDENT_KEY "pika-frame-indent"
#define PIKA_FRAME_IN_EXPANDER_KEY "pika-frame-in-expander"
static void pika_frame_style_updated (GtkWidget *widget);
static gboolean pika_frame_draw (GtkWidget *widget,
cairo_t *cr);
static void pika_frame_label_widget_notify (PikaFrame *frame);
static void pika_frame_child_added (PikaFrame *frame,
GtkWidget *child,
gpointer user_data);
static void pika_frame_apply_margins (PikaFrame *frame);
static gint pika_frame_get_indent (PikaFrame *frame);
static gint pika_frame_get_label_spacing (PikaFrame *frame);
G_DEFINE_TYPE (PikaFrame, pika_frame, GTK_TYPE_FRAME)
#define parent_class pika_frame_parent_class
static void
pika_frame_class_init (PikaFrameClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
widget_class->style_updated = pika_frame_style_updated;
widget_class->draw = pika_frame_draw;
gtk_widget_class_install_style_property (widget_class,
g_param_spec_boolean ("label-bold",
"Label Bold",
"Whether the frame's label should be bold",
DEFAULT_LABEL_BOLD,
G_PARAM_READABLE));
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("label-spacing",
"Label Spacing",
"The spacing between the label and the frame content",
0,
G_MAXINT,
DEFAULT_LABEL_SPACING,
G_PARAM_READABLE));
}
static void
pika_frame_init (PikaFrame *frame)
{
g_signal_connect (frame, "notify::label-widget",
G_CALLBACK (pika_frame_label_widget_notify),
NULL);
g_signal_connect (frame, "add",
G_CALLBACK (pika_frame_child_added),
NULL);
}
static void
pika_frame_style_updated (GtkWidget *widget)
{
GTK_WIDGET_CLASS (parent_class)->style_updated (widget);
/* font changes invalidate the indentation */
g_object_set_data (G_OBJECT (widget), PIKA_FRAME_INDENT_KEY, NULL);
pika_frame_label_widget_notify (PIKA_FRAME (widget));
pika_frame_apply_margins (PIKA_FRAME (widget));
}
static gboolean
pika_frame_draw (GtkWidget *widget,
cairo_t *cr)
{
GtkWidgetClass *widget_class = g_type_class_peek_parent (parent_class);
return widget_class->draw (widget, cr);
}
static void
pika_frame_label_widget_notify (PikaFrame *frame)
{
GtkWidget *label_widget = gtk_frame_get_label_widget (GTK_FRAME (frame));
if (label_widget)
{
GtkLabel *label = NULL;
if (GTK_IS_LABEL (label_widget))
{
gfloat xalign, yalign;
label = GTK_LABEL (label_widget);
gtk_frame_get_label_align (GTK_FRAME (frame), &xalign, &yalign);
gtk_label_set_xalign (GTK_LABEL (label), xalign);
gtk_label_set_yalign (GTK_LABEL (label), yalign);
}
else if (GTK_IS_BIN (label_widget))
{
GtkWidget *child = gtk_bin_get_child (GTK_BIN (label_widget));
if (GTK_IS_LABEL (child))
label = GTK_LABEL (child);
}
if (label)
{
gboolean bold;
gtk_widget_style_get (GTK_WIDGET (frame),
"label-bold", &bold,
NULL);
pika_label_set_attributes (label,
PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
-1);
}
}
}
static void
pika_frame_child_added (PikaFrame *frame,
GtkWidget *child,
gpointer user_data)
{
pika_frame_apply_margins (frame);
}
static void
pika_frame_apply_margins (PikaFrame *frame)
{
GtkWidget *child = gtk_bin_get_child (GTK_BIN (frame));
if (child)
{
gtk_widget_set_margin_start (child, pika_frame_get_indent (frame));
gtk_widget_set_margin_top (child, pika_frame_get_label_spacing (frame));
}
}
static gint
pika_frame_get_indent (PikaFrame *frame)
{
gint width = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (frame),
PIKA_FRAME_INDENT_KEY));
if (! width)
{
PangoLayout *layout;
/* the HIG suggests to use four spaces so do just that */
layout = gtk_widget_create_pango_layout (GTK_WIDGET (frame), " ");
pango_layout_get_pixel_size (layout, &width, NULL);
g_object_unref (layout);
g_object_set_data (G_OBJECT (frame),
PIKA_FRAME_INDENT_KEY, GINT_TO_POINTER (width));
}
return width;
}
static gint
pika_frame_get_label_spacing (PikaFrame *frame)
{
GtkWidget *label_widget = gtk_frame_get_label_widget (GTK_FRAME (frame));
gint spacing = 0;
if ((label_widget && gtk_widget_get_visible (label_widget)) ||
(g_object_get_data (G_OBJECT (frame), PIKA_FRAME_IN_EXPANDER_KEY)))
{
gtk_widget_style_get (GTK_WIDGET (frame),
"label-spacing", &spacing,
NULL);
}
return spacing;
}
/**
* pika_frame_new:
* @label: (nullable): text to set as the frame's title label (or %NULL for no title)
*
* Creates a #PikaFrame widget. A #PikaFrame is a HIG-compliant
* variant of #GtkFrame. It doesn't render a frame at all but
* otherwise behaves like a frame. The frame's title is rendered in
* bold and the frame content is indented four spaces as suggested by
* the GNOME HIG (see https://developer.gnome.org/hig/stable/).
*
* Returns: a new #PikaFrame widget
*
* Since: 2.2
**/
GtkWidget *
pika_frame_new (const gchar *label)
{
GtkWidget *frame;
gboolean expander = FALSE;
/* somewhat hackish, should perhaps be an object property of PikaFrame */
if (label && strcmp (label, "<expander>") == 0)
{
expander = TRUE;
label = NULL;
}
frame = g_object_new (PIKA_TYPE_FRAME,
"label", label,
NULL);
if (expander)
g_object_set_data (G_OBJECT (frame),
PIKA_FRAME_IN_EXPANDER_KEY, (gpointer) TRUE);
return frame;
}

View File

@ -0,0 +1,74 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaframe.h
* Copyright (C) 2004 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_FRAME_H__
#define __PIKA_FRAME_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
#define PIKA_TYPE_FRAME (pika_frame_get_type ())
#define PIKA_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_FRAME, PikaFrame))
#define PIKA_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_FRAME, PikaFrameClass))
#define PIKA_IS_FRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_FRAME))
#define PIKA_IS_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_FRAME))
#define PIKA_FRAME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_FRAME, PikaFrameClass))
typedef struct _PikaFramePrivate PikaFramePrivate;
typedef struct _PikaFrameClass PikaFrameClass;
struct _PikaFrame
{
GtkFrame parent_instance;
PikaFramePrivate *priv;
};
struct _PikaFrameClass
{
GtkFrameClass parent_class;
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_frame_get_type (void) G_GNUC_CONST;
GtkWidget * pika_frame_new (const gchar *label);
G_END_DECLS
#endif /* __PIKA_FRAME_H__ */

651
libpikawidgets/pikahelpui.c Normal file
View File

@ -0,0 +1,651 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikahelpui.c
* Copyright (C) 2000-2003 Michael Natterer <mitch@gimp.org>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "pikawidgets.h"
#include "pikawidgets-private.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikahelpui
* @title: PikaHelpUI
* @short_description: Functions for setting tooltip and help identifier
* used by the PIKA help system.
*
* Functions for setting tooltip and help identifier used by the PIKA
* help system.
**/
typedef enum
{
PIKA_WIDGET_HELP_TOOLTIP = GTK_WIDGET_HELP_TOOLTIP,
PIKA_WIDGET_HELP_WHATS_THIS = GTK_WIDGET_HELP_WHATS_THIS,
PIKA_WIDGET_HELP_TYPE_HELP = 0xff
} PikaWidgetHelpType;
/* local function prototypes */
static const gchar * pika_help_get_help_data (GtkWidget *widget,
GtkWidget **help_widget,
gpointer *ret_data);
static gboolean pika_help_callback (GtkWidget *widget,
PikaWidgetHelpType help_type,
PikaHelpFunc help_func);
static void pika_help_menu_item_set_tooltip (GtkWidget *widget,
const gchar *tooltip,
const gchar *help_id);
static gboolean pika_help_menu_item_query_tooltip (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_mode,
GtkTooltip *tooltip);
static gboolean pika_context_help_idle_start (gpointer widget);
static gboolean pika_context_help_button_press (GtkWidget *widget,
GdkEventButton *bevent,
gpointer data);
static gboolean pika_context_help_key_press (GtkWidget *widget,
GdkEventKey *kevent,
gpointer data);
static gboolean pika_context_help_idle_show_help (gpointer data);
/* public functions */
/**
* pika_standard_help_func:
* @help_id: A unique help identifier.
* @help_data: The @help_data passed to pika_help_connect().
*
* This is the standard PIKA help function which does nothing but calling
* pika_help(). It is the right function to use in almost all cases.
**/
void
pika_standard_help_func (const gchar *help_id,
gpointer help_data)
{
if (! _pika_standard_help_func)
{
g_warning ("%s: you must call pika_widgets_init() before using "
"the help system", G_STRFUNC);
return;
}
(* _pika_standard_help_func) (help_id, help_data);
}
/**
* pika_help_connect:
* @widget: The widget you want to connect the help accelerator for.
* Will be a #GtkWindow in most cases.
* @help_func: The function which will be called if the user presses "F1".
* @help_id: The @help_id which will be passed to @help_func.
* @help_data: The @help_data pointer which will be passed to @help_func.
* @help_data_destroy: Destroy function for @help_data.
*
* Note that this function is automatically called by all libpika dialog
* constructors. You only have to call it for windows/dialogs you created
* "manually".
**/
void
pika_help_connect (GtkWidget *widget,
PikaHelpFunc help_func,
const gchar *help_id,
gpointer help_data,
GDestroyNotify help_data_destroy)
{
static gboolean initialized = FALSE;
g_return_if_fail (GTK_IS_WIDGET (widget));
g_return_if_fail (help_func != NULL);
/* set up the help signals
*/
if (! initialized)
{
GtkBindingSet *binding_set;
binding_set =
gtk_binding_set_by_class (g_type_class_peek (GTK_TYPE_WIDGET));
gtk_binding_entry_add_signal (binding_set, GDK_KEY_F1, 0,
"show-help", 1,
GTK_TYPE_WIDGET_HELP_TYPE,
PIKA_WIDGET_HELP_TYPE_HELP);
gtk_binding_entry_add_signal (binding_set, GDK_KEY_KP_F1, 0,
"show-help", 1,
GTK_TYPE_WIDGET_HELP_TYPE,
PIKA_WIDGET_HELP_TYPE_HELP);
initialized = TRUE;
}
pika_help_set_help_data (widget, NULL, help_id);
g_object_set_data_full (G_OBJECT (widget), "pika-help-data",
help_data, help_data_destroy);
g_signal_connect (widget, "show-help",
G_CALLBACK (pika_help_callback),
help_func);
gtk_widget_add_events (widget, GDK_BUTTON_PRESS_MASK);
}
/**
* pika_help_set_help_data:
* @widget: The #GtkWidget you want to set a @tooltip and/or @help_id for.
* @tooltip: The text for this widget's tooltip (or %NULL).
* @help_id: The @help_id for the #GtkTipsQuery tooltips inspector.
*
* The reason why we don't use gtk_widget_set_tooltip_text() is that
* elements in the PIKA user interface should, if possible, also have
* a @help_id set for context-sensitive help.
*
* This function can be called with %NULL for @tooltip. Use this feature
* if you want to set a help link for a widget which shouldn't have
* a visible tooltip.
**/
void
pika_help_set_help_data (GtkWidget *widget,
const gchar *tooltip,
const gchar *help_id)
{
g_return_if_fail (GTK_IS_WIDGET (widget));
gtk_widget_set_tooltip_text (widget, tooltip);
if (GTK_IS_MENU_ITEM (widget))
pika_help_menu_item_set_tooltip (widget, tooltip, help_id);
g_object_set_qdata (G_OBJECT (widget), PIKA_HELP_ID, (gpointer) help_id);
}
/**
* pika_help_set_help_data_with_markup:
* @widget: The #GtkWidget you want to set a @tooltip and/or @help_id for.
* @tooltip: The markup for this widget's tooltip (or %NULL).
* @help_id: The @help_id for the #GtkTipsQuery tooltips inspector.
*
* Just like pika_help_set_help_data(), but supports to pass text
* which is marked up with <link linkend="PangoMarkupFormat">Pango
* text markup language</link>.
*
* Since: 2.6
**/
void
pika_help_set_help_data_with_markup (GtkWidget *widget,
const gchar *tooltip,
const gchar *help_id)
{
g_return_if_fail (GTK_IS_WIDGET (widget));
gtk_widget_set_tooltip_markup (widget, tooltip);
if (GTK_IS_MENU_ITEM (widget))
pika_help_menu_item_set_tooltip (widget, tooltip, help_id);
g_object_set_qdata (G_OBJECT (widget), PIKA_HELP_ID, (gpointer) help_id);
}
/**
* pika_context_help:
* @widget: Any #GtkWidget on the screen.
*
* This function invokes the context help inspector.
*
* The mouse cursor will turn turn into a question mark and the user can
* click on any widget of the application which started the inspector.
*
* If the widget the user clicked on has a @help_id string attached
* (see pika_help_set_help_data()), the corresponding help page will
* be displayed. Otherwise the help system will ascend the widget hierarchy
* until it finds an attached @help_id string (which should be the
* case at least for every window/dialog).
**/
void
pika_context_help (GtkWidget *widget)
{
g_return_if_fail (GTK_IS_WIDGET (widget));
pika_help_callback (widget, PIKA_WIDGET_HELP_WHATS_THIS, NULL);
}
/**
* pika_help_id_quark:
*
* This function returns the #GQuark which should be used as key when
* attaching help IDs to widgets and objects.
*
* Returns: The #GQuark.
*
* Since: 2.2
**/
GQuark
pika_help_id_quark (void)
{
static GQuark quark = 0;
if (! quark)
quark = g_quark_from_static_string ("pika-help-id");
return quark;
}
/* private functions */
static const gchar *
pika_help_get_help_data (GtkWidget *widget,
GtkWidget **help_widget,
gpointer *ret_data)
{
const gchar *help_id = NULL;
gpointer help_data = NULL;
for (; widget; widget = gtk_widget_get_parent (widget))
{
help_id = g_object_get_qdata (G_OBJECT (widget), PIKA_HELP_ID);
help_data = g_object_get_data (G_OBJECT (widget), "pika-help-data");
if (help_id)
{
if (help_widget)
*help_widget = widget;
if (ret_data)
*ret_data = help_data;
return help_id;
}
}
if (help_widget)
*help_widget = NULL;
if (ret_data)
*ret_data = NULL;
return NULL;
}
static gboolean
pika_help_callback (GtkWidget *widget,
PikaWidgetHelpType help_type,
PikaHelpFunc help_func)
{
switch (help_type)
{
case PIKA_WIDGET_HELP_TYPE_HELP:
if (help_func)
{
help_func (g_object_get_qdata (G_OBJECT (widget), PIKA_HELP_ID),
g_object_get_data (G_OBJECT (widget), "pika-help-data"));
}
return TRUE;
case PIKA_WIDGET_HELP_WHATS_THIS:
g_idle_add (pika_context_help_idle_start, widget);
return TRUE;
default:
break;
}
return FALSE;
}
static void
pika_help_menu_item_set_tooltip (GtkWidget *widget,
const gchar *tooltip,
const gchar *help_id)
{
g_return_if_fail (GTK_IS_MENU_ITEM (widget));
g_object_set (widget, "has-tooltip", FALSE, NULL);
g_signal_handlers_disconnect_by_func (widget,
pika_help_menu_item_query_tooltip,
NULL);
if (tooltip && help_id)
g_signal_connect (widget, "query-tooltip",
G_CALLBACK (pika_help_menu_item_query_tooltip),
NULL);
if (tooltip)
g_object_set (widget, "has-tooltip", TRUE, NULL);
}
static gboolean
pika_help_menu_item_query_tooltip (GtkWidget *widget,
gint x,
gint y,
gboolean keyboard_mode,
GtkTooltip *tooltip)
{
GtkWidget *vbox;
GtkWidget *label;
gchar *text;
gboolean use_markup = TRUE;
text = gtk_widget_get_tooltip_markup (widget);
if (! text)
{
text = gtk_widget_get_tooltip_text (widget);
use_markup = FALSE;
}
if (! text)
return FALSE;
vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
label = gtk_label_new (text);
gtk_label_set_use_markup (GTK_LABEL (label), use_markup);
gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
gtk_label_set_xalign (GTK_LABEL (label), 0.0);
gtk_box_pack_start (GTK_BOX (vbox), label, TRUE, TRUE, 0);
gtk_widget_show (label);
g_free (text);
label = gtk_label_new (_("Press F1 for more help"));
pika_label_set_attributes (GTK_LABEL (label),
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
PANGO_ATTR_SCALE, PANGO_SCALE_SMALL,
-1);
gtk_label_set_xalign (GTK_LABEL (label), 1.0);
gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, FALSE, 0);
gtk_widget_show (label);
gtk_tooltip_set_custom (tooltip, vbox);
return TRUE;
}
/* Do all the actual context help calls in idle functions and check for
* some widget holding a grab before starting the query because strange
* things happen if (1) the help browser pops up while the query has
* grabbed the pointer or (2) the query grabs the pointer while some
* other part of PIKA has grabbed it (e.g. a tool, eek)
*/
static gboolean
pika_context_help_idle_start (gpointer widget)
{
if (! gtk_grab_get_current ())
{
GdkDisplay *display;
GtkWidget *invisible;
GdkCursor *cursor;
GdkGrabStatus status;
invisible = gtk_invisible_new_for_screen (gtk_widget_get_screen (widget));
gtk_widget_show (invisible);
display = gtk_widget_get_display (invisible);
cursor = gdk_cursor_new_for_display (display, GDK_QUESTION_ARROW);
status = gdk_seat_grab (gdk_display_get_default_seat (display),
gtk_widget_get_window (invisible),
GDK_SEAT_CAPABILITY_ALL, TRUE,
cursor,
NULL, NULL, NULL);
g_object_unref (cursor);
if (status != GDK_GRAB_SUCCESS)
{
gtk_widget_destroy (invisible);
return FALSE;
}
gtk_grab_add (invisible);
g_signal_connect (invisible, "button-press-event",
G_CALLBACK (pika_context_help_button_press),
NULL);
g_signal_connect (invisible, "key-press-event",
G_CALLBACK (pika_context_help_key_press),
NULL);
}
return FALSE;
}
/* find widget code shamelessly stolen from gtkinspector */
typedef struct
{
gint x;
gint y;
gboolean found;
gboolean first;
GtkWidget *res_widget;
} FindWidgetData;
static void
find_widget (GtkWidget *widget,
FindWidgetData *data)
{
GtkAllocation new_allocation;
gint x_offset = 0;
gint y_offset = 0;
gtk_widget_get_allocation (widget, &new_allocation);
if (data->found || !gtk_widget_get_mapped (widget))
return;
/* Note that in the following code, we only count the
* position as being inside a WINDOW widget if it is inside
* widget->window; points that are outside of widget->window
* but within the allocation are not counted. This is consistent
* with the way we highlight drag targets.
*/
if (gtk_widget_get_has_window (widget))
{
new_allocation.x = 0;
new_allocation.y = 0;
}
if (gtk_widget_get_parent (widget) && !data->first)
{
GdkWindow *window;
window = gtk_widget_get_window (widget);
while (window != gtk_widget_get_window (gtk_widget_get_parent (widget)))
{
gint tx, ty, twidth, theight;
if (window == NULL)
return;
twidth = gdk_window_get_width (window);
theight = gdk_window_get_height (window);
if (new_allocation.x < 0)
{
new_allocation.width += new_allocation.x;
new_allocation.x = 0;
}
if (new_allocation.y < 0)
{
new_allocation.height += new_allocation.y;
new_allocation.y = 0;
}
if (new_allocation.x + new_allocation.width > twidth)
new_allocation.width = twidth - new_allocation.x;
if (new_allocation.y + new_allocation.height > theight)
new_allocation.height = theight - new_allocation.y;
gdk_window_get_position (window, &tx, &ty);
new_allocation.x += tx;
x_offset += tx;
new_allocation.y += ty;
y_offset += ty;
window = gdk_window_get_parent (window);
}
}
if ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
(data->x < new_allocation.x + new_allocation.width) &&
(data->y < new_allocation.y + new_allocation.height))
{
/* First, check if the drag is in a valid drop site in
* one of our children
*/
if (GTK_IS_CONTAINER (widget))
{
FindWidgetData new_data = *data;
new_data.x -= x_offset;
new_data.y -= y_offset;
new_data.found = FALSE;
new_data.first = FALSE;
gtk_container_forall (GTK_CONTAINER (widget),
(GtkCallback)find_widget,
&new_data);
data->found = new_data.found;
if (data->found)
data->res_widget = new_data.res_widget;
}
/* If not, and this widget is registered as a drop site, check to
* emit "drag_motion" to check if we are actually in
* a drop site.
*/
if (!data->found)
{
data->found = TRUE;
data->res_widget = widget;
}
}
}
static GtkWidget *
find_widget_at_pointer (GdkDevice *device)
{
GtkWidget *widget = NULL;
GdkWindow *pointer_window;
gint x, y;
FindWidgetData data;
pointer_window = gdk_device_get_window_at_position (device, NULL, NULL);
if (pointer_window)
{
gpointer widget_ptr;
gdk_window_get_user_data (pointer_window, &widget_ptr);
widget = widget_ptr;
}
if (widget)
{
gdk_window_get_device_position (gtk_widget_get_window (widget),
device, &x, &y, NULL);
data.x = x;
data.y = y;
data.found = FALSE;
data.first = TRUE;
find_widget (widget, &data);
if (data.found)
return data.res_widget;
return widget;
}
return NULL;
}
static gboolean
pika_context_help_button_press (GtkWidget *widget,
GdkEventButton *bevent,
gpointer data)
{
GdkDisplay *display = gtk_widget_get_display (widget);
GdkSeat *seat = gdk_display_get_default_seat (display);
GdkDevice *device = gdk_seat_get_pointer (seat);
GtkWidget *event_widget = find_widget_at_pointer (device);
if (event_widget && bevent->button == 1 && bevent->type == GDK_BUTTON_PRESS)
{
gtk_grab_remove (widget);
gdk_seat_ungrab (seat);
gtk_widget_destroy (widget);
if (event_widget != widget)
g_idle_add (pika_context_help_idle_show_help, event_widget);
}
return TRUE;
}
static gboolean
pika_context_help_key_press (GtkWidget *widget,
GdkEventKey *kevent,
gpointer data)
{
if (kevent->keyval == GDK_KEY_Escape)
{
GdkDisplay *display = gtk_widget_get_display (widget);
gtk_grab_remove (widget);
gdk_seat_ungrab (gdk_display_get_default_seat (display));
gtk_widget_destroy (widget);
}
return TRUE;
}
static gboolean
pika_context_help_idle_show_help (gpointer data)
{
GtkWidget *help_widget;
const gchar *help_id = NULL;
gpointer help_data = NULL;
help_id = pika_help_get_help_data (GTK_WIDGET (data), &help_widget,
&help_data);
if (help_id)
pika_standard_help_func (help_id, help_data);
return FALSE;
}

View File

@ -0,0 +1,74 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* pikahelpui.h
* Copyright (C) 2000-2003 Michael Natterer <mitch@gimp.org>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_HELP_UI_H__
#define __PIKA_HELP_UI_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
/* the standard pika help function
*/
void pika_standard_help_func (const gchar *help_id,
gpointer help_data);
/* connect the help callback of a window */
void pika_help_connect (GtkWidget *widget,
PikaHelpFunc help_func,
const gchar *help_id,
gpointer help_data,
GDestroyNotify help_data_destroy);
/* set help data for non-window widgets */
void pika_help_set_help_data (GtkWidget *widget,
const gchar *tooltip,
const gchar *help_id);
/* set help data with markup for non-window widgets */
void pika_help_set_help_data_with_markup (GtkWidget *widget,
const gchar *tooltip,
const gchar *help_id);
/* activate the context help inspector */
void pika_context_help (GtkWidget *widget);
/**
* PIKA_HELP_ID:
*
* The #GQuark used to attach PIKA help IDs to widgets.
*
* Since: 2.2
**/
#define PIKA_HELP_ID (pika_help_id_quark ())
GQuark pika_help_id_quark (void) G_GNUC_CONST;
G_END_DECLS
#endif /* __PIKA_HELP_UI_H__ */

View File

@ -0,0 +1,224 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikahintbox.c
* Copyright (C) 2006 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "pikawidgets.h"
/**
* SECTION: pikahintbox
* @title: PikaHintBox
* @short_description: Displays a wilber icon and a text.
*
* Displays a wilber icon and a text.
**/
enum
{
PROP_0,
PROP_ICON_NAME,
PROP_HINT
};
struct _PikaHintBoxPrivate
{
gchar *icon_name;
gchar *hint;
};
static void pika_hint_box_constructed (GObject *object);
static void pika_hint_box_finalize (GObject *object);
static void pika_hint_box_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_hint_box_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
G_DEFINE_TYPE_WITH_PRIVATE (PikaHintBox, pika_hint_box, GTK_TYPE_BOX)
#define parent_class pika_hint_box_parent_class
static void
pika_hint_box_class_init (PikaHintBoxClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = pika_hint_box_constructed;
object_class->finalize = pika_hint_box_finalize;
object_class->set_property = pika_hint_box_set_property;
object_class->get_property = pika_hint_box_get_property;
g_object_class_install_property (object_class, PROP_ICON_NAME,
g_param_spec_string ("icon-name",
"Icon Name",
"The icon to show next to the hint",
PIKA_ICON_DIALOG_INFORMATION,
G_PARAM_CONSTRUCT_ONLY |
PIKA_PARAM_READWRITE));
g_object_class_install_property (object_class, PROP_HINT,
g_param_spec_string ("hint",
"Hint",
"The hint to display",
NULL,
G_PARAM_CONSTRUCT_ONLY |
PIKA_PARAM_READWRITE));
}
static void
pika_hint_box_init (PikaHintBox *box)
{
box->priv = pika_hint_box_get_instance_private (box);
gtk_orientable_set_orientation (GTK_ORIENTABLE (box),
GTK_ORIENTATION_HORIZONTAL);
}
static void
pika_hint_box_constructed (GObject *object)
{
PikaHintBox *box = PIKA_HINT_BOX (object);
GtkWidget *image = NULL;
GtkWidget *label;
G_OBJECT_CLASS (parent_class)->constructed (object);
gtk_box_set_spacing (GTK_BOX (box), 12);
if (box->priv->icon_name)
{
image = gtk_image_new_from_icon_name (box->priv->icon_name,
GTK_ICON_SIZE_DIALOG);
}
if (image)
{
gtk_box_pack_start (GTK_BOX (box), image, FALSE, FALSE, 0);
gtk_widget_set_visible (image, TRUE);
}
label = g_object_new (GTK_TYPE_LABEL,
"label", box->priv->hint,
"wrap", TRUE,
"justify", GTK_JUSTIFY_LEFT,
"xalign", 0.0,
"yalign", 0.5,
NULL);
pika_label_set_attributes (GTK_LABEL (label),
PANGO_ATTR_STYLE, PANGO_STYLE_ITALIC,
-1);
gtk_box_pack_start (GTK_BOX (box), label, FALSE, FALSE, 0);
gtk_widget_set_visible (label, TRUE);
}
static void
pika_hint_box_finalize (GObject *object)
{
PikaHintBox *box = PIKA_HINT_BOX (object);
g_clear_pointer (&box->priv->icon_name, g_free);
g_clear_pointer (&box->priv->hint, g_free);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_hint_box_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaHintBox *box = PIKA_HINT_BOX (object);
switch (property_id)
{
case PROP_ICON_NAME:
box->priv->icon_name = g_value_dup_string (value);
break;
case PROP_HINT:
box->priv->hint = g_value_dup_string (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_hint_box_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaHintBox *box = PIKA_HINT_BOX (object);
switch (property_id)
{
case PROP_ICON_NAME:
g_value_set_string (value, box->priv->icon_name);
break;
case PROP_HINT:
g_value_set_string (value, box->priv->hint);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/**
* pika_hint_box_new:
* @hint: text to display as a user hint
*
* Creates a new widget that shows a text label showing @hint,
* decorated with a PIKA_ICON_INFO wilber icon.
*
* Returns: a new widget
*
* Since PIKA 2.4
**/
GtkWidget *
pika_hint_box_new (const gchar *hint)
{
g_return_val_if_fail (hint != NULL, NULL);
return g_object_new (PIKA_TYPE_HINT_BOX,
"hint", hint,
NULL);
}

View File

@ -0,0 +1,75 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikahintbox.h
* Copyright (C) 2006 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_HINT_BOX_H__
#define __PIKA_HINT_BOX_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
#define PIKA_TYPE_HINT_BOX (pika_hint_box_get_type ())
#define PIKA_HINT_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_HINT_BOX, PikaHintBox))
#define PIKA_HINT_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_HINT_BOX, PikaHintBoxClass))
#define PIKA_IS_HINT_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_HINT_BOX))
#define PIKA_IS_HINT_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_HINT_BOX))
#define PIKA_HINT_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_HINT_BOX, PikaHintBoxClass))
typedef struct _PikaHintBoxPrivate PikaHintBoxPrivate;
typedef struct _PikaHintBoxClass PikaHintBoxClass;
struct _PikaHintBox
{
GtkBox parent_instance;
PikaHintBoxPrivate *priv;
};
struct _PikaHintBoxClass
{
GtkBoxClass parent_class;
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_hint_box_get_type (void) G_GNUC_CONST;
GtkWidget * pika_hint_box_new (const gchar *hint);
G_END_DECLS
#endif /* __PIKA_HINT_BOX_H__ */

314
libpikawidgets/pikaicons.c Normal file
View File

@ -0,0 +1,314 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaicons.c
* Copyright (C) 2001-2015 Michael Natterer <mitch@gimp.org>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "pikaicons.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikaicons
* @title: PikaIcons
* @short_description: Prebuilt common menu/toolbar items and
* corresponding icons
*
* PIKA registers a set of menu/toolbar items and corresponding icons
* in addition to the standard GTK+ stock items. These can be used
* just like GTK+ stock items. PIKA also overrides a few of the GTK+
* icons (namely the ones in dialog size).
*
* Stock icons may have a RTL variant which gets used for
* right-to-left locales.
**/
#define LIBPIKA_DOMAIN GETTEXT_PACKAGE "-libpika"
#define PIKA_TOILET_PAPER "pika-toilet-paper"
#define PIKA_DEFAULT_ICON_THEME "Symbolic"
static GFile *icon_theme_path = NULL;
static GFile *default_search_path = NULL;
static void
pika_icons_change_icon_theme (GFile *new_search_path)
{
GFile *old_search_path = g_file_get_parent (icon_theme_path);
if (! default_search_path)
default_search_path = pika_data_directory_file ("icons", NULL);
if (! g_file_equal (new_search_path, old_search_path))
{
GtkIconTheme *icon_theme = gtk_icon_theme_get_default ();
if (g_file_equal (old_search_path, default_search_path))
{
/* if the old icon theme is in the default search path,
* simply prepend the new theme's path
*/
gchar *path_str = g_file_get_path (new_search_path);
gtk_icon_theme_prepend_search_path (icon_theme, path_str);
g_free (path_str);
}
else
{
/* if the old theme is not in the default search path,
* we need to deal with the search path's first element
*/
gchar **paths;
gint n_paths;
gtk_icon_theme_get_search_path (icon_theme, &paths, &n_paths);
if (g_file_equal (new_search_path, default_search_path))
{
/* when switching to a theme in the default path, remove
* the first search path element, the default search path
* is still in the search path
*/
gtk_icon_theme_set_search_path (icon_theme,
(const gchar **) paths + 1,
n_paths - 1);
}
else
{
/* when switching between two non-default search paths, replace
* the first element of the search path with the new
* theme's path
*/
g_free (paths[0]);
paths[0] = g_file_get_path (new_search_path);
gtk_icon_theme_set_search_path (icon_theme,
(const gchar **) paths, n_paths);
}
g_strfreev (paths);
}
}
g_object_unref (old_search_path);
}
static void
pika_icons_notify_system_icon_theme (GObject *settings,
GParamSpec *param,
gpointer unused)
{
GdkScreen *screen = gdk_screen_get_default ();
GValue value = G_VALUE_INIT;
g_value_init (&value, G_TYPE_STRING);
if (gdk_screen_get_setting (screen, "gtk-icon-theme-name", &value))
{
const gchar *new_system_icon_theme = g_value_get_string (&value);
gchar *cur_system_icon_theme = NULL;
g_object_get (settings,
"gtk-fallback-icon-theme", &cur_system_icon_theme,
NULL);
if (g_strcmp0 (cur_system_icon_theme, new_system_icon_theme))
{
g_object_set (settings,
"gtk-fallback-icon-theme", new_system_icon_theme,
NULL);
g_object_notify (settings, "gtk-icon-theme-name");
}
g_free (cur_system_icon_theme);
}
g_value_unset (&value);
}
static gboolean
pika_icons_sanity_check (GFile *path,
const gchar *theme_name)
{
gboolean exists = FALSE;
GFile *child = g_file_get_child (path, theme_name);
if (g_file_query_exists (child, NULL))
{
GFile *index = g_file_get_child (child, "index.theme");
if (g_file_query_exists (index, NULL))
exists = TRUE;
else
g_printerr ("%s: Icon theme path has no '%s/index.theme': %s\n",
G_STRFUNC, theme_name, pika_file_get_utf8_name (path));
g_object_unref (index);
}
else
g_printerr ("%s: Icon theme path has no '%s' subdirectory: %s\n",
G_STRFUNC, theme_name, pika_file_get_utf8_name (path));
g_object_unref (child);
return exists;
}
void
pika_icons_set_icon_theme (GFile *path)
{
gchar *icon_theme_name;
GFile *search_path;
g_return_if_fail (path == NULL || G_IS_FILE (path));
if (path)
path = g_object_ref (path);
else
path = pika_data_directory_file ("icons", PIKA_DEFAULT_ICON_THEME, NULL);
search_path = g_file_get_parent (path);
icon_theme_name = g_file_get_basename (path);
if (pika_icons_sanity_check (search_path, "hicolor") &&
pika_icons_sanity_check (search_path, icon_theme_name))
{
if (icon_theme_path)
{
/* this is an icon theme change */
pika_icons_change_icon_theme (search_path);
if (! g_file_equal (icon_theme_path, path))
{
g_object_unref (icon_theme_path);
icon_theme_path = g_object_ref (path);
}
g_object_set (gtk_settings_get_for_screen (gdk_screen_get_default ()),
"gtk-icon-theme-name", icon_theme_name,
NULL);
}
else
{
/* this is the first call upon initialization */
icon_theme_path = g_object_ref (path);
}
}
g_free (icon_theme_name);
g_object_unref (search_path);
g_object_unref (path);
}
/**
* pika_icons_init:
*
* Initializes the PIKA stock icon factory.
*
* You don't need to call this function as pika_ui_init() already does
* this for you.
*/
void
pika_icons_init (void)
{
static gboolean initialized = FALSE;
GtkSettings *settings;
GdkPixbuf *pixbuf;
GError *error = NULL;
gchar *icons_dir;
gchar *system_icon_theme;
gchar *pika_icon_theme;
if (initialized)
return;
/* always prepend the default icon theme, it's never removed from
* the path again and acts as fallback for missing icons in other
* themes.
*/
if (! default_search_path)
default_search_path = pika_data_directory_file ("icons",
NULL);
icons_dir = g_file_get_path (default_search_path);
gtk_icon_theme_prepend_search_path (gtk_icon_theme_get_default (),
icons_dir);
g_free (icons_dir);
/* if an icon theme was chosen before init(), change to it */
if (icon_theme_path)
{
GFile *search_path = g_file_get_parent (icon_theme_path);
if (!g_file_equal (search_path, default_search_path))
{
gchar *icon_dir = g_file_get_path (search_path);
gtk_icon_theme_prepend_search_path (gtk_icon_theme_get_default (),
icon_dir);
g_free (icon_dir);
}
g_object_unref (search_path);
pika_icon_theme = g_file_get_basename (icon_theme_path);
}
else
{
pika_icon_theme = g_strdup (PIKA_DEFAULT_ICON_THEME);
}
settings = gtk_settings_get_for_screen (gdk_screen_get_default ());
g_object_get (settings, "gtk-icon-theme-name", &system_icon_theme, NULL);
g_object_set (settings,
"gtk-fallback-icon-theme", system_icon_theme,
"gtk-icon-theme-name", pika_icon_theme,
NULL);
g_free (pika_icon_theme);
g_free (system_icon_theme);
g_signal_connect (settings, "notify::gtk-icon-theme-name",
G_CALLBACK (pika_icons_notify_system_icon_theme), NULL);
pixbuf = gdk_pixbuf_new_from_resource ("/technology.heckin/icons/64/pika-mascot-eek.png",
&error);
if (pixbuf)
{
gtk_icon_theme_add_builtin_icon (PIKA_ICON_MASCOT_EEK, 64, pixbuf);
g_object_unref (pixbuf);
}
else
{
g_critical ("Failed to create icon image: %s", error->message);
g_clear_error (&error);
}
initialized = TRUE;
}

435
libpikawidgets/pikaicons.h Normal file
View File

@ -0,0 +1,435 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaicons.h
* Copyright (C) 2001-2015 Michael Natterer <mitch@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_ICONS_H__
#define __PIKA_ICONS_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
/* random actions that don't fit in any category */
#define PIKA_ICON_ATTACH "pika-attach"
#define PIKA_ICON_DETACH "pika-detach"
#define PIKA_ICON_INVERT "pika-invert"
#define PIKA_ICON_RECORD "media-record"
#define PIKA_ICON_RESET "pika-reset"
#define PIKA_ICON_SHRED "pika-shred"
/* random states/things that don't fit in any category */
#define PIKA_ICON_BUSINESS_CARD "pika-business-card"
#define PIKA_ICON_CHAR_PICKER "pika-char-picker"
#define PIKA_ICON_CURSOR "pika-cursor"
#define PIKA_ICON_DISPLAY "pika-display"
#define PIKA_ICON_GEGL "pika-gegl"
#define PIKA_ICON_LINKED "pika-linked"
#define PIKA_ICON_MARKER "pika-marker"
#define PIKA_ICON_SMARTPHONE "pika-smartphone"
#define PIKA_ICON_TRANSPARENCY "pika-transparency"
#define PIKA_ICON_VIDEO "pika-video"
#define PIKA_ICON_VISIBLE "pika-visible"
#define PIKA_ICON_WEB "pika-web"
/* random objects/entities that don't fit in any category */
#define PIKA_ICON_BRUSH PIKA_ICON_TOOL_PAINTBRUSH
#define PIKA_ICON_BUFFER PIKA_ICON_EDIT_PASTE
#define PIKA_ICON_COLORMAP "pika-colormap"
#define PIKA_ICON_DYNAMICS "pika-dynamics"
#define PIKA_ICON_FILE_MANAGER "pika-file-manager"
#define PIKA_ICON_FONT "gtk-select-font"
#define PIKA_ICON_GRADIENT PIKA_ICON_TOOL_GRADIENT
#define PIKA_ICON_GRID "pika-grid"
#define PIKA_ICON_INPUT_DEVICE "pika-input-device"
#define PIKA_ICON_MYPAINT_BRUSH PIKA_ICON_TOOL_MYPAINT_BRUSH
#define PIKA_ICON_PALETTE "gtk-select-color"
#define PIKA_ICON_PATTERN "pika-pattern"
#define PIKA_ICON_PLUGIN "pika-plugin"
#define PIKA_ICON_SAMPLE_POINT "pika-sample-point"
#define PIKA_ICON_SYMMETRY "pika-symmetry"
#define PIKA_ICON_TEMPLATE "pika-template"
#define PIKA_ICON_TOOL_PRESET "pika-tool-preset"
/* not really icons */
#define PIKA_ICON_FRAME "pika-frame"
#define PIKA_ICON_TEXTURE "pika-texture"
/* icons that follow, or at least try to follow the FDO naming and
* category conventions; and groups of icons with a common prefix;
* all sorted alphabetically
*
* see also:
* https://specifications.freedesktop.org/icon-naming-spec/latest/ar01s04.html
*
* When icons are available as standard Freedesktop icons, we use these
* in priority. As a fallback, we use standard GTK+ icons. As last
* fallback, we create our own icons under the "pika-" namespace.
*/
#define PIKA_ICON_APPLICATION_EXIT "application-exit"
#define PIKA_ICON_ASPECT_PORTRAIT "pika-portrait"
#define PIKA_ICON_ASPECT_LANDSCAPE "pika-landscape"
#define PIKA_ICON_CAP_BUTT "pika-cap-butt"
#define PIKA_ICON_CAP_ROUND "pika-cap-round"
#define PIKA_ICON_CAP_SQUARE "pika-cap-square"
#define PIKA_ICON_CENTER "pika-center"
#define PIKA_ICON_CENTER_HORIZONTAL "pika-hcenter"
#define PIKA_ICON_CENTER_VERTICAL "pika-vcenter"
#define PIKA_ICON_CHAIN_HORIZONTAL "pika-hchain"
#define PIKA_ICON_CHAIN_HORIZONTAL_BROKEN "pika-hchain-broken"
#define PIKA_ICON_CHAIN_VERTICAL "pika-vchain"
#define PIKA_ICON_CHAIN_VERTICAL_BROKEN "pika-vchain-broken"
#define PIKA_ICON_CHANNEL "pika-channel"
#define PIKA_ICON_CHANNEL_ALPHA "pika-channel-alpha"
#define PIKA_ICON_CHANNEL_BLUE "pika-channel-blue"
#define PIKA_ICON_CHANNEL_GRAY "pika-channel-gray"
#define PIKA_ICON_CHANNEL_GREEN "pika-channel-green"
#define PIKA_ICON_CHANNEL_INDEXED "pika-channel-indexed"
#define PIKA_ICON_CHANNEL_RED "pika-channel-red"
#define PIKA_ICON_CLOSE "pika-close"
#define PIKA_ICON_CLOSE_ALL "pika-close-all"
#define PIKA_ICON_COLOR_PICKER_BLACK "pika-color-picker-black"
#define PIKA_ICON_COLOR_PICKER_GRAY "pika-color-picker-gray"
#define PIKA_ICON_COLOR_PICKER_WHITE "pika-color-picker-white"
#define PIKA_ICON_COLOR_PICK_FROM_SCREEN "pika-color-pick-from-screen"
#define PIKA_ICON_COLOR_SELECTOR_CMYK "pika-color-cmyk"
#define PIKA_ICON_COLOR_SELECTOR_TRIANGLE "pika-color-triangle"
#define PIKA_ICON_COLOR_SELECTOR_WATER "pika-color-water"
#define PIKA_ICON_COLOR_SPACE_LINEAR "pika-color-space-linear"
#define PIKA_ICON_COLOR_SPACE_NON_LINEAR "pika-color-space-non-linear"
#define PIKA_ICON_COLOR_SPACE_PERCEPTUAL "pika-color-space-perceptual"
#define PIKA_ICON_COLORS_DEFAULT "pika-default-colors"
#define PIKA_ICON_COLORS_SWAP "pika-swap-colors"
#define PIKA_ICON_CONTROLLER "pika-controller"
#define PIKA_ICON_CONTROLLER_KEYBOARD "pika-controller-keyboard"
#define PIKA_ICON_CONTROLLER_LINUX_INPUT "pika-controller-linux-input"
#define PIKA_ICON_CONTROLLER_MIDI "pika-controller-midi"
#define PIKA_ICON_CONTROLLER_MOUSE PIKA_ICON_CURSOR
#define PIKA_ICON_CONTROLLER_WHEEL "pika-controller-wheel"
#define PIKA_ICON_CONVERT_RGB "pika-convert-rgb"
#define PIKA_ICON_CONVERT_GRAYSCALE "pika-convert-grayscale"
#define PIKA_ICON_CONVERT_INDEXED "pika-convert-indexed"
#define PIKA_ICON_CONVERT_PRECISION PIKA_ICON_CONVERT_RGB
#define PIKA_ICON_CURVE_FREE "pika-curve-free"
#define PIKA_ICON_CURVE_SMOOTH "pika-curve-smooth"
#define PIKA_ICON_DIALOG_CHANNELS "pika-channels"
#define PIKA_ICON_DIALOG_DASHBOARD "pika-dashboard"
#define PIKA_ICON_DIALOG_DEVICE_STATUS "pika-device-status"
#define PIKA_ICON_DIALOG_ERROR "dialog-error"
#define PIKA_ICON_DIALOG_IMAGES "pika-images"
#define PIKA_ICON_DIALOG_INFORMATION "dialog-information"
#define PIKA_ICON_DIALOG_LAYERS "pika-layers"
#define PIKA_ICON_DIALOG_NAVIGATION "pika-navigation"
#define PIKA_ICON_DIALOG_PATHS "pika-paths"
#define PIKA_ICON_DIALOG_QUESTION "dialog-question"
#define PIKA_ICON_DIALOG_RESHOW_FILTER "pika-reshow-filter"
#define PIKA_ICON_DIALOG_TOOLS "pika-tools"
#define PIKA_ICON_DIALOG_TOOL_OPTIONS "pika-tool-options"
#define PIKA_ICON_DIALOG_UNDO_HISTORY "pika-undo-history"
#define PIKA_ICON_DIALOG_WARNING "dialog-warning"
#define PIKA_ICON_DISPLAY_FILTER "pika-display-filter"
#define PIKA_ICON_DISPLAY_FILTER_CLIP_WARNING "pika-display-filter-clip-warning"
#define PIKA_ICON_DISPLAY_FILTER_COLORBLIND "pika-display-filter-colorblind"
#define PIKA_ICON_DISPLAY_FILTER_CONTRAST "pika-display-filter-contrast"
#define PIKA_ICON_DISPLAY_FILTER_GAMMA "pika-display-filter-gamma"
#define PIKA_ICON_DISPLAY_FILTER_LCMS "pika-display-filter-lcms"
#define PIKA_ICON_DISPLAY_FILTER_PROOF "pika-display-filter-proof"
#define PIKA_ICON_LOCK "pika-lock"
#define PIKA_ICON_LOCK_ALPHA "pika-lock-alpha"
#define PIKA_ICON_LOCK_CONTENT "pika-lock-content"
#define PIKA_ICON_LOCK_POSITION "pika-lock-position"
#define PIKA_ICON_LOCK_VISIBILITY "pika-lock-visibility"
#define PIKA_ICON_LOCK_MULTI "pika-lock-multi"
#define PIKA_ICON_DOCUMENT_NEW "document-new"
#define PIKA_ICON_DOCUMENT_OPEN "document-open"
#define PIKA_ICON_DOCUMENT_OPEN_RECENT "document-open-recent"
#define PIKA_ICON_DOCUMENT_PAGE_SETUP "document-page-setup"
#define PIKA_ICON_DOCUMENT_PRINT "document-print"
#define PIKA_ICON_DOCUMENT_PRINT_RESOLUTION "document-print"
#define PIKA_ICON_DOCUMENT_PROPERTIES "document-properties"
#define PIKA_ICON_DOCUMENT_REVERT "document-revert"
#define PIKA_ICON_DOCUMENT_SAVE "document-save"
#define PIKA_ICON_DOCUMENT_SAVE_AS "document-save-as"
#define PIKA_ICON_EDIT "gtk-edit"
#define PIKA_ICON_EDIT_CLEAR "edit-clear"
#define PIKA_ICON_EDIT_COPY "edit-copy"
#define PIKA_ICON_EDIT_CUT "edit-cut"
#define PIKA_ICON_EDIT_DELETE "edit-delete"
#define PIKA_ICON_EDIT_FIND "edit-find"
#define PIKA_ICON_EDIT_PASTE "edit-paste"
#define PIKA_ICON_EDIT_PASTE_AS_NEW "pika-paste-as-new"
#define PIKA_ICON_EDIT_PASTE_INTO "pika-paste-into"
#define PIKA_ICON_EDIT_REDO "edit-redo"
#define PIKA_ICON_EDIT_UNDO "edit-undo"
#define PIKA_ICON_EVEN_HORIZONTAL_GAP "pika-even-horizontal-gap"
#define PIKA_ICON_EVEN_VERTICAL_GAP "pika-even-vertical-gap"
#define PIKA_ICON_FILL_HORIZONTAL "pika-hfill"
#define PIKA_ICON_FILL_VERTICAL "pika-vfill"
#define PIKA_ICON_FOLDER_NEW "folder-new"
#define PIKA_ICON_FORMAT_INDENT_MORE "format-indent-more"
#define PIKA_ICON_FORMAT_INDENT_LESS "format-indent-less"
#define PIKA_ICON_FORMAT_JUSTIFY_CENTER "format-justify-center"
#define PIKA_ICON_FORMAT_JUSTIFY_FILL "format-justify-fill"
#define PIKA_ICON_FORMAT_JUSTIFY_LEFT "format-justify-left"
#define PIKA_ICON_FORMAT_JUSTIFY_RIGHT "format-justify-right"
#define PIKA_ICON_FORMAT_TEXT_BOLD "format-text-bold"
#define PIKA_ICON_FORMAT_TEXT_ITALIC "format-text-italic"
#define PIKA_ICON_FORMAT_TEXT_STRIKETHROUGH "format-text-strikethrough"
#define PIKA_ICON_FORMAT_TEXT_UNDERLINE "format-text-underline"
#define PIKA_ICON_FORMAT_TEXT_DIRECTION_LTR "format-text-direction-ltr"
#define PIKA_ICON_FORMAT_TEXT_DIRECTION_RTL "format-text-direction-rtl"
#define PIKA_ICON_FORMAT_TEXT_DIRECTION_TTB_RTL "pika-text-dir-ttb-rtl" /* use FDO */
#define PIKA_ICON_FORMAT_TEXT_DIRECTION_TTB_RTL_UPRIGHT "pika-text-dir-ttb-rtl-upright" /* use FDO */
#define PIKA_ICON_FORMAT_TEXT_DIRECTION_TTB_LTR "pika-text-dir-ttb-ltr" /* use FDO */
#define PIKA_ICON_FORMAT_TEXT_DIRECTION_TTB_LTR_UPRIGHT "pika-text-dir-ttb-ltr-upright" /* use FDO */
#define PIKA_ICON_FORMAT_TEXT_SPACING_LETTER "pika-letter-spacing"
#define PIKA_ICON_FORMAT_TEXT_SPACING_LINE "pika-line-spacing"
#define PIKA_ICON_GRADIENT_LINEAR "pika-gradient-linear"
#define PIKA_ICON_GRADIENT_BILINEAR "pika-gradient-bilinear"
#define PIKA_ICON_GRADIENT_RADIAL "pika-gradient-radial"
#define PIKA_ICON_GRADIENT_SQUARE "pika-gradient-square"
#define PIKA_ICON_GRADIENT_CONICAL_SYMMETRIC "pika-gradient-conical-symmetric"
#define PIKA_ICON_GRADIENT_CONICAL_ASYMMETRIC "pika-gradient-conical-asymmetric"
#define PIKA_ICON_GRADIENT_SHAPEBURST_ANGULAR "pika-gradient-shapeburst-angular"
#define PIKA_ICON_GRADIENT_SHAPEBURST_SPHERICAL "pika-gradient-shapeburst-spherical"
#define PIKA_ICON_GRADIENT_SHAPEBURST_DIMPLED "pika-gradient-shapeburst-dimpled"
#define PIKA_ICON_GRADIENT_SPIRAL_CLOCKWISE "pika-gradient-spiral-clockwise"
#define PIKA_ICON_GRADIENT_SPIRAL_ANTICLOCKWISE "pika-gradient-spiral-anticlockwise"
#define PIKA_ICON_GRAVITY_EAST "pika-gravity-east"
#define PIKA_ICON_GRAVITY_NORTH "pika-gravity-north"
#define PIKA_ICON_GRAVITY_NORTH_EAST "pika-gravity-north-east"
#define PIKA_ICON_GRAVITY_NORTH_WEST "pika-gravity-north-west"
#define PIKA_ICON_GRAVITY_SOUTH "pika-gravity-south"
#define PIKA_ICON_GRAVITY_SOUTH_EAST "pika-gravity-south-east"
#define PIKA_ICON_GRAVITY_SOUTH_WEST "pika-gravity-south-west"
#define PIKA_ICON_GRAVITY_WEST "pika-gravity-west"
#define PIKA_ICON_GO_BOTTOM "go-bottom"
#define PIKA_ICON_GO_DOWN "go-down"
#define PIKA_ICON_GO_FIRST "go-first"
#define PIKA_ICON_GO_HOME "go-home"
#define PIKA_ICON_GO_LAST "go-last"
#define PIKA_ICON_GO_TOP "go-top"
#define PIKA_ICON_GO_UP "go-up"
#define PIKA_ICON_GO_PREVIOUS "go-previous"
#define PIKA_ICON_GO_NEXT "go-next"
#define PIKA_ICON_HELP "system-help"
#define PIKA_ICON_HELP_ABOUT "help-about"
#define PIKA_ICON_HELP_USER_MANUAL "pika-user-manual"
#define PIKA_ICON_HISTOGRAM "pika-histogram"
#define PIKA_ICON_HISTOGRAM_LINEAR "pika-histogram-linear"
#define PIKA_ICON_HISTOGRAM_LOGARITHMIC "pika-histogram-logarithmic"
#define PIKA_ICON_IMAGE "pika-image"
#define PIKA_ICON_IMAGE_OPEN "pika-image-open"
#define PIKA_ICON_IMAGE_RELOAD "pika-image-reload"
#define PIKA_ICON_JOIN_MITER "pika-join-miter"
#define PIKA_ICON_JOIN_ROUND "pika-join-round"
#define PIKA_ICON_JOIN_BEVEL "pika-join-bevel"
#define PIKA_ICON_LAYER "pika-layer"
#define PIKA_ICON_LAYER_ANCHOR "pika-anchor"
#define PIKA_ICON_LAYER_FLOATING_SELECTION "pika-floating-selection"
#define PIKA_ICON_LAYER_MASK "pika-layer-mask"
#define PIKA_ICON_LAYER_MERGE_DOWN "pika-merge-down"
#define PIKA_ICON_LAYER_TEXT_LAYER "pika-text-layer"
#define PIKA_ICON_LAYER_TO_IMAGESIZE "pika-layer-to-imagesize"
#define PIKA_ICON_LIST "pika-list"
#define PIKA_ICON_LIST_ADD "list-add"
#define PIKA_ICON_LIST_REMOVE "list-remove"
#define PIKA_ICON_MENU_LEFT "pika-menu-left"
#define PIKA_ICON_MENU_RIGHT "pika-menu-right"
#define PIKA_ICON_OBJECT_DUPLICATE "pika-duplicate"
#define PIKA_ICON_OBJECT_FLIP_HORIZONTAL "object-flip-horizontal"
#define PIKA_ICON_OBJECT_FLIP_VERTICAL "object-flip-vertical"
#define PIKA_ICON_OBJECT_RESIZE "pika-resize"
#define PIKA_ICON_OBJECT_ROTATE_180 "pika-rotate-180"
#define PIKA_ICON_OBJECT_ROTATE_270 "object-rotate-left"
#define PIKA_ICON_OBJECT_ROTATE_90 "object-rotate-right"
#define PIKA_ICON_OBJECT_SCALE "pika-scale"
#define PIKA_ICON_PATH "pika-path"
#define PIKA_ICON_PATH_STROKE "pika-path-stroke"
#define PIKA_ICON_PIVOT_CENTER "pika-pivot-center"
#define PIKA_ICON_PIVOT_EAST "pika-pivot-east"
#define PIKA_ICON_PIVOT_NORTH "pika-pivot-north"
#define PIKA_ICON_PIVOT_NORTH_EAST "pika-pivot-north-east"
#define PIKA_ICON_PIVOT_NORTH_WEST "pika-pivot-north-west"
#define PIKA_ICON_PIVOT_SOUTH "pika-pivot-south"
#define PIKA_ICON_PIVOT_SOUTH_EAST "pika-pivot-south-east"
#define PIKA_ICON_PIVOT_SOUTH_WEST "pika-pivot-south-west"
#define PIKA_ICON_PIVOT_WEST "pika-pivot-west"
#define PIKA_ICON_PREFERENCES_SYSTEM "preferences-system"
#define PIKA_ICON_PROCESS_STOP "process-stop"
#define PIKA_ICON_QUICK_MASK_OFF "pika-quick-mask-off"
#define PIKA_ICON_QUICK_MASK_ON "pika-quick-mask-on"
#define PIKA_ICON_SELECTION "pika-selection"
#define PIKA_ICON_SELECTION_ADD "pika-selection-add"
#define PIKA_ICON_SELECTION_ALL "pika-selection-all"
#define PIKA_ICON_SELECTION_BORDER "pika-selection-border"
#define PIKA_ICON_SELECTION_GROW "pika-selection-grow"
#define PIKA_ICON_SELECTION_INTERSECT "pika-selection-intersect"
#define PIKA_ICON_SELECTION_NONE "pika-selection-none"
#define PIKA_ICON_SELECTION_REPLACE "pika-selection-replace"
#define PIKA_ICON_SELECTION_SHRINK "pika-selection-shrink"
#define PIKA_ICON_SELECTION_STROKE "pika-selection-stroke"
#define PIKA_ICON_SELECTION_SUBTRACT "pika-selection-subtract"
#define PIKA_ICON_SELECTION_TO_CHANNEL "pika-selection-to-channel"
#define PIKA_ICON_SELECTION_TO_PATH "pika-selection-to-path"
#define PIKA_ICON_SHAPE_CIRCLE "pika-shape-circle"
#define PIKA_ICON_SHAPE_DIAMOND "pika-shape-diamond"
#define PIKA_ICON_SHAPE_SQUARE "pika-shape-square"
#define PIKA_ICON_SYSTEM_RUN "system-run"
#define PIKA_ICON_TOOL_AIRBRUSH "pika-tool-airbrush"
#define PIKA_ICON_TOOL_ALIGN "pika-tool-align"
#define PIKA_ICON_TOOL_BLUR "pika-tool-blur"
#define PIKA_ICON_TOOL_BRIGHTNESS_CONTRAST "pika-tool-brightness-contrast"
#define PIKA_ICON_TOOL_BUCKET_FILL "pika-tool-bucket-fill"
#define PIKA_ICON_TOOL_BY_COLOR_SELECT "pika-tool-by-color-select"
#define PIKA_ICON_TOOL_CAGE "pika-tool-cage"
#define PIKA_ICON_TOOL_CLONE "pika-tool-clone"
#define PIKA_ICON_TOOL_COLORIZE "pika-tool-colorize"
#define PIKA_ICON_TOOL_COLOR_BALANCE "pika-tool-color-balance"
#define PIKA_ICON_TOOL_COLOR_PICKER "pika-tool-color-picker"
#define PIKA_ICON_TOOL_COLOR_TEMPERATURE "pika-tool-color-temperature"
#define PIKA_ICON_TOOL_CROP "pika-tool-crop"
#define PIKA_ICON_TOOL_CURVES "pika-tool-curves"
#define PIKA_ICON_TOOL_DESATURATE "pika-tool-desaturate"
#define PIKA_ICON_TOOL_DODGE "pika-tool-dodge"
#define PIKA_ICON_TOOL_ELLIPSE_SELECT "pika-tool-ellipse-select"
#define PIKA_ICON_TOOL_ERASER "pika-tool-eraser"
#define PIKA_ICON_TOOL_EXPOSURE "pika-tool-exposure"
#define PIKA_ICON_TOOL_FLIP "pika-tool-flip"
#define PIKA_ICON_TOOL_FOREGROUND_SELECT "pika-tool-foreground-select"
#define PIKA_ICON_TOOL_FREE_SELECT "pika-tool-free-select"
#define PIKA_ICON_TOOL_FUZZY_SELECT "pika-tool-fuzzy-select"
#define PIKA_ICON_TOOL_GRADIENT "pika-tool-gradient"
#define PIKA_ICON_TOOL_HANDLE_TRANSFORM "pika-tool-handle-transform"
#define PIKA_ICON_TOOL_HEAL "pika-tool-heal"
#define PIKA_ICON_TOOL_HUE_SATURATION "pika-tool-hue-saturation"
#define PIKA_ICON_TOOL_INK "pika-tool-ink"
#define PIKA_ICON_TOOL_ISCISSORS "pika-tool-iscissors"
#define PIKA_ICON_TOOL_LEVELS "pika-tool-levels"
#define PIKA_ICON_TOOL_MEASURE "pika-tool-measure"
#define PIKA_ICON_TOOL_MOVE "pika-tool-move"
#define PIKA_ICON_TOOL_MYPAINT_BRUSH "pika-tool-mypaint-brush"
#define PIKA_ICON_TOOL_N_POINT_DEFORMATION "pika-tool-n-point-deformation"
#define PIKA_ICON_TOOL_OFFSET "pika-tool-offset"
#define PIKA_ICON_TOOL_PAINTBRUSH "pika-tool-paintbrush"
#define PIKA_ICON_TOOL_PAINT_SELECT "pika-tool-paint-select"
#define PIKA_ICON_TOOL_PATH "pika-tool-path"
#define PIKA_ICON_TOOL_PENCIL "pika-tool-pencil"
#define PIKA_ICON_TOOL_PERSPECTIVE "pika-tool-perspective"
#define PIKA_ICON_TOOL_PERSPECTIVE_CLONE "pika-tool-perspective-clone"
#define PIKA_ICON_TOOL_POSTERIZE "pika-tool-posterize"
#define PIKA_ICON_TOOL_RECT_SELECT "pika-tool-rect-select"
#define PIKA_ICON_TOOL_ROTATE "pika-tool-rotate"
#define PIKA_ICON_TOOL_SCALE "pika-tool-scale"
#define PIKA_ICON_TOOL_SEAMLESS_CLONE "pika-tool-seamless-clone"
#define PIKA_ICON_TOOL_SHADOWS_HIGHLIGHTS "pika-tool-shadows-highlights"
#define PIKA_ICON_TOOL_SHEAR "pika-tool-shear"
#define PIKA_ICON_TOOL_SMUDGE "pika-tool-smudge"
#define PIKA_ICON_TOOL_TEXT "pika-tool-text"
#define PIKA_ICON_TOOL_THRESHOLD "pika-tool-threshold"
#define PIKA_ICON_TOOL_TRANSFORM_3D "pika-tool-transform-3d"
#define PIKA_ICON_TOOL_UNIFIED_TRANSFORM "pika-tool-unified-transform"
#define PIKA_ICON_TOOL_WARP "pika-tool-warp"
#define PIKA_ICON_TOOL_ZOOM "pika-tool-zoom"
#define PIKA_ICON_TRANSFORM_3D_CAMERA "pika-transform-3d-camera"
#define PIKA_ICON_TRANSFORM_3D_MOVE "pika-transform-3d-move"
#define PIKA_ICON_TRANSFORM_3D_ROTATE "pika-transform-3d-rotate"
#define PIKA_ICON_VIEW_REFRESH "view-refresh"
#define PIKA_ICON_VIEW_FULLSCREEN "view-fullscreen"
#define PIKA_ICON_MASCOT "pika-mascot"
#define PIKA_ICON_MASCOT_EEK "pika-mascot-eek"
#define PIKA_ICON_WINDOW_CLOSE "window-close"
#define PIKA_ICON_WINDOW_MOVE_TO_SCREEN "pika-move-to-screen"
#define PIKA_ICON_WINDOW_NEW "window-new"
#define PIKA_ICON_ZOOM_IN "zoom-in"
#define PIKA_ICON_ZOOM_ORIGINAL "zoom-original"
#define PIKA_ICON_ZOOM_OUT "zoom-out"
#define PIKA_ICON_ZOOM_FIT_BEST "zoom-fit-best"
#define PIKA_ICON_ZOOM_FOLLOW_WINDOW "pika-zoom-follow-window"
void pika_icons_init (void);
void pika_icons_set_icon_theme (GFile *path);
G_END_DECLS
#endif /* __PIKA_ICONS_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,128 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaintcombobox.h
* Copyright (C) 2004 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_INT_COMBO_BOX_H__
#define __PIKA_INT_COMBO_BOX_H__
G_BEGIN_DECLS
#define PIKA_TYPE_INT_COMBO_BOX (pika_int_combo_box_get_type ())
#define PIKA_INT_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_INT_COMBO_BOX, PikaIntComboBox))
#define PIKA_INT_COMBO_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_INT_COMBO_BOX, PikaIntComboBoxClass))
#define PIKA_IS_INT_COMBO_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_INT_COMBO_BOX))
#define PIKA_IS_INT_COMBO_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_INT_COMBO_BOX))
#define PIKA_INT_COMBO_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_INT_COMBO_BOX, PikaIntComboBoxClass))
typedef struct _PikaIntComboBoxPrivate PikaIntComboBoxPrivate;
typedef struct _PikaIntComboBoxClass PikaIntComboBoxClass;
struct _PikaIntComboBox
{
GtkComboBox parent_instance;
PikaIntComboBoxPrivate *priv;
};
struct _PikaIntComboBoxClass
{
GtkComboBoxClass parent_class;
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
/**
* PikaIntSensitivityFunc:
* @value:
* @data: (closure):
*/
typedef gboolean (* PikaIntSensitivityFunc) (gint value,
gpointer data);
GType pika_int_combo_box_get_type (void) G_GNUC_CONST;
GtkWidget * pika_int_combo_box_new (const gchar *first_label,
gint first_value,
...) G_GNUC_NULL_TERMINATED;
GtkWidget * pika_int_combo_box_new_valist (const gchar *first_label,
gint first_value,
va_list values);
GtkWidget * pika_int_combo_box_new_array (gint n_values,
const gchar *labels[]);
void pika_int_combo_box_prepend (PikaIntComboBox *combo_box,
...);
void pika_int_combo_box_append (PikaIntComboBox *combo_box,
...);
gboolean pika_int_combo_box_set_active (PikaIntComboBox *combo_box,
gint value);
gboolean pika_int_combo_box_get_active (PikaIntComboBox *combo_box,
gint *value);
gboolean
pika_int_combo_box_set_active_by_user_data (PikaIntComboBox *combo_box,
gpointer user_data);
gboolean
pika_int_combo_box_get_active_user_data (PikaIntComboBox *combo_box,
gpointer *user_data);
gulong pika_int_combo_box_connect (PikaIntComboBox *combo_box,
gint value,
GCallback callback,
gpointer data,
GDestroyNotify data_destroy);
void pika_int_combo_box_set_label (PikaIntComboBox *combo_box,
const gchar *label);
const gchar * pika_int_combo_box_get_label (PikaIntComboBox *combo_box);
void pika_int_combo_box_set_layout (PikaIntComboBox *combo_box,
PikaIntComboBoxLayout layout);
PikaIntComboBoxLayout
pika_int_combo_box_get_layout (PikaIntComboBox *combo_box);
void pika_int_combo_box_set_sensitivity (PikaIntComboBox *combo_box,
PikaIntSensitivityFunc func,
gpointer data,
GDestroyNotify destroy);
G_END_DECLS
#endif /* __PIKA_INT_COMBO_BOX_H__ */

View File

@ -0,0 +1,789 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaintradioframe.c
* Copyright (C) 2022 Jehan
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <libintl.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "pikawidgetstypes.h"
#include "pikaintradioframe.h"
#include "pikaintstore.h"
/**
* SECTION: pikaintradioframe
* @title: PikaIntRadioFrame
* @short_description: A widget providing radio buttons for integer
* values (e.g. enums).
*
* A widget providing a frame with title, containing grouped radio
* buttons, each associated with an integer value and random user data.
**/
enum
{
PROP_0,
PROP_VALUE,
PROP_STORE,
};
typedef struct _PikaIntRadioFramePrivate PikaIntRadioFramePrivate;
struct _PikaIntRadioFramePrivate
{
gchar *label;
PikaIntStore *store;
GSList *group;
gint value;
GtkWidget *box;
PikaIntRadioFrameSensitivityFunc sensitivity_func;
gpointer sensitivity_data;
GDestroyNotify sensitivity_destroy;
};
#define GET_PRIVATE(obj) ((PikaIntRadioFramePrivate *) pika_int_radio_frame_get_instance_private ((PikaIntRadioFrame *) obj))
static void pika_int_radio_frame_constructed (GObject *object);
static void pika_int_radio_frame_finalize (GObject *object);
static void pika_int_radio_frame_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_int_radio_frame_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static gboolean pika_int_radio_frame_draw (GtkWidget *widget,
cairo_t *cr,
gpointer user_data);
static void pika_int_radio_frame_fill (PikaIntRadioFrame *frame);
static void pika_int_radio_frame_set_store (PikaIntRadioFrame *frame,
PikaIntStore *store);
static void pika_int_radio_frame_update_sensitivity (PikaIntRadioFrame *frame);
static void pika_int_radio_frame_button_toggled (GtkToggleButton *button,
PikaIntRadioFrame *frame);
G_DEFINE_TYPE_WITH_PRIVATE (PikaIntRadioFrame, pika_int_radio_frame,
PIKA_TYPE_FRAME)
#define parent_class pika_int_radio_frame_parent_class
static void
pika_int_radio_frame_class_init (PikaIntRadioFrameClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = pika_int_radio_frame_constructed;
object_class->finalize = pika_int_radio_frame_finalize;
object_class->set_property = pika_int_radio_frame_set_property;
object_class->get_property = pika_int_radio_frame_get_property;
/**
* PikaIntRadioFrame:value:
*
* The active value
*
* Since: 3.0
*/
g_object_class_install_property (object_class, PROP_VALUE,
g_param_spec_int ("value",
"Value",
"Value of active item",
G_MININT, G_MAXINT, 0,
PIKA_PARAM_READWRITE |
G_PARAM_EXPLICIT_NOTIFY));
/**
* PikaIntRadioFrame:store:
*
* The %PikaIntStore from which the radio frame takes the values shown
* in the list.
*
* Since: 3.0
*/
g_object_class_install_property (object_class,
PROP_STORE,
g_param_spec_object ("store",
"PikaRadioFrame int store",
"The int store for the radio frame",
PIKA_TYPE_INT_STORE,
PIKA_PARAM_READWRITE |
G_PARAM_EXPLICIT_NOTIFY));
}
static void
pika_int_radio_frame_init (PikaIntRadioFrame *radio_frame)
{
PikaIntRadioFramePrivate *priv = GET_PRIVATE (radio_frame);
priv->box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 2);
gtk_container_add (GTK_CONTAINER (radio_frame), priv->box);
gtk_widget_show (GTK_WIDGET (priv->box));
}
static void
pika_int_radio_frame_constructed (GObject *object)
{
G_OBJECT_CLASS (parent_class)->constructed (object);
g_signal_connect (object, "draw",
G_CALLBACK (pika_int_radio_frame_draw),
NULL);
}
static void
pika_int_radio_frame_finalize (GObject *object)
{
PikaIntRadioFramePrivate *priv = GET_PRIVATE (object);
g_clear_pointer (&priv->label, g_free);
g_clear_object (&priv->store);
g_clear_pointer (&priv->group, g_slist_free);
if (priv->sensitivity_destroy)
{
GDestroyNotify d = priv->sensitivity_destroy;
priv->sensitivity_destroy = NULL;
d (priv->sensitivity_data);
}
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_int_radio_frame_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
switch (property_id)
{
case PROP_VALUE:
pika_int_radio_frame_set_active (PIKA_INT_RADIO_FRAME (object),
g_value_get_int (value));
break;
case PROP_STORE:
pika_int_radio_frame_set_store (PIKA_INT_RADIO_FRAME (object),
g_value_get_object (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_int_radio_frame_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaIntRadioFramePrivate *priv = GET_PRIVATE (object);
switch (property_id)
{
case PROP_VALUE:
g_value_set_int (value, priv->value);
break;
case PROP_STORE:
g_value_set_object (value, priv->store);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
/* Public functions */
/**
* pika_int_radio_frame_new_from_store:
* @title: the frame label.
* @store: the %PikaIntStore to generate radio buttons from.
*
* Creates a %PikaIntRadioFrame containing radio buttons for each item
* in the @store. The created widget takes ownership of @store.
*
* If you need to construct an empty #PikaIntRadioFrame, it's best to use
* g_object_new (PIKA_TYPE_INT_RADIO_FRAME, NULL).
*
* Returns: a new #PikaIntRadioFrame.
*
* Since: 3.0
**/
GtkWidget *
pika_int_radio_frame_new_from_store (const gchar *title,
PikaIntStore *store)
{
GtkWidget *radio_frame;
radio_frame = g_object_new (PIKA_TYPE_INT_RADIO_FRAME,
"label", title,
"store", store,
NULL);
return radio_frame;
}
/**
* pika_int_radio_frame_new: (skip)
* @first_label: the label of the first item
* @first_value: the value of the first item
* @...: a %NULL terminated list of more label, value pairs
*
* Creates a GtkComboBox that has integer values associated with each
* item. The items to fill the combo box with are specified as a %NULL
* terminated list of label/value pairs.
*
* If you need to construct an empty #PikaIntRadioFrame, it's best to use
* g_object_new (PIKA_TYPE_INT_RADIO_FRAME, NULL).
*
* Returns: a new #PikaIntRadioFrame.
*
* Since: 3.0
**/
GtkWidget *
pika_int_radio_frame_new (const gchar *first_label,
gint first_value,
...)
{
GtkWidget *radio_frame;
va_list args;
va_start (args, first_value);
radio_frame = pika_int_radio_frame_new_valist (first_label, first_value, args);
va_end (args);
return radio_frame;
}
/**
* pika_int_radio_frame_new_valist: (skip)
* @first_label: the label of the first item
* @first_value: the value of the first item
* @values: a va_list with more values
*
* A variant of pika_int_radio_frame_new() that takes a va_list of
* label/value pairs.
*
* Returns: a new #PikaIntRadioFrame.
*
* Since: 3.0
**/
GtkWidget *
pika_int_radio_frame_new_valist (const gchar *first_label,
gint first_value,
va_list values)
{
GtkWidget *radio_frame;
GtkListStore *store;
store = pika_int_store_new_valist (first_label, first_value, values);
radio_frame = g_object_new (PIKA_TYPE_INT_RADIO_FRAME,
"store", store,
NULL);
return radio_frame;
}
/**
* pika_int_radio_frame_new_array: (rename-to pika_int_radio_frame_new)
* @labels: (array zero-terminated=1): a %NULL-terminated array of labels.
*
* A variant of pika_int_radio_frame_new() that takes an array of labels.
* The array indices are used as values.
*
* Returns: a new #PikaIntRadioFrame.
*
* Since: 3.0
**/
GtkWidget *
pika_int_radio_frame_new_array (const gchar *labels[])
{
GtkWidget *frame;
PikaIntRadioFramePrivate *priv;
GtkListStore *store;
gint i;
g_return_val_if_fail (labels != NULL, NULL);
frame = g_object_new (PIKA_TYPE_INT_RADIO_FRAME, NULL);
priv = GET_PRIVATE (frame);
store = GTK_LIST_STORE (priv->store);
for (i = 0; labels[i] != NULL; i++)
{
GtkTreeIter iter;
if (labels[i])
{
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
PIKA_INT_STORE_VALUE, i,
PIKA_INT_STORE_LABEL, labels[i],
-1);
}
}
return frame;
}
/**
* pika_int_radio_frame_prepend: (skip)
* @radio_frame: a #PikaIntRadioFrame
* @...: pairs of column number and value, terminated with -1
*
* This function provides a convenient way to prepend items to a
* #PikaIntRadioFrame. It prepends a row to the @radio_frame's list store
* and calls gtk_list_store_set() for you.
*
* The column number must be taken from the enum #PikaIntStoreColumns.
*
* Since: 3.0
**/
void
pika_int_radio_frame_prepend (PikaIntRadioFrame *radio_frame,
...)
{
GtkListStore *store;
PikaIntRadioFramePrivate *priv;
GtkTreeIter iter;
va_list args;
g_return_if_fail (PIKA_IS_INT_RADIO_FRAME (radio_frame));
priv = GET_PRIVATE (radio_frame);
store = GTK_LIST_STORE (priv->store);
va_start (args, radio_frame);
gtk_list_store_prepend (store, &iter);
gtk_list_store_set_valist (store, &iter, args);
va_end (args);
}
/**
* pika_int_radio_frame_append: (skip)
* @radio_frame: a #PikaIntRadioFrame
* @...: pairs of column number and value, terminated with -1
*
* This function provides a convenient way to append items to a
* #PikaIntRadioFrame. It appends a row to the @radio_frame's list store
* and calls gtk_list_store_set() for you.
*
* The column number must be taken from the enum #PikaIntStoreColumns.
*
* Since: 3.0
**/
void
pika_int_radio_frame_append (PikaIntRadioFrame *radio_frame,
...)
{
GtkListStore *store;
PikaIntRadioFramePrivate *priv;
GtkTreeIter iter;
va_list args;
g_return_if_fail (PIKA_IS_INT_RADIO_FRAME (radio_frame));
priv = GET_PRIVATE (radio_frame);
store = GTK_LIST_STORE (priv->store);
va_start (args, radio_frame);
gtk_list_store_append (store, &iter);
gtk_list_store_set_valist (store, &iter, args);
va_end (args);
}
/**
* pika_int_radio_frame_set_active:
* @radio_frame: a #PikaIntRadioFrame
* @value: an integer value
*
* Looks up the item that belongs to the given @value and makes it the
* selected item in the @radio_frame.
*
* Returns: %TRUE on success (value changed or not) or %FALSE if there
* was no item for this value.
*
* Since: 3.0
**/
gboolean
pika_int_radio_frame_set_active (PikaIntRadioFrame *frame,
gint value)
{
PikaIntRadioFramePrivate *priv = GET_PRIVATE (frame);
GtkWidget *button;
GSList *iter = priv->group;
g_return_val_if_fail (PIKA_IS_INT_RADIO_FRAME (frame), FALSE);
for (; iter; iter = g_slist_next (iter))
{
button = GTK_WIDGET (iter->data);
if (g_object_get_data (G_OBJECT (button), "pika-radio-frame-value") ==
GINT_TO_POINTER (value))
{
if (! gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)))
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), TRUE);
return TRUE;
}
}
return FALSE;
}
/**
* pika_int_radio_frame_get_active:
* @radio_frame: a #PikaIntRadioFrame
*
* Returns: the value of the active item.
*
* Since:3.0
**/
gint
pika_int_radio_frame_get_active (PikaIntRadioFrame *frame)
{
PikaIntRadioFramePrivate *priv = GET_PRIVATE (frame);
g_return_val_if_fail (PIKA_IS_INT_RADIO_FRAME (frame), FALSE);
return priv->value;
}
/**
* pika_int_radio_frame_set_active_by_user_data:
* @radio_frame: a #PikaIntRadioFrame
* @user_data: an integer value
*
* Looks up the item that has the given @user_data and makes it the
* selected item in the @radio_frame.
*
* Returns: %TRUE on success or %FALSE if there was no item for
* this user-data.
*
* Since: 3.0
**/
gboolean
pika_int_radio_frame_set_active_by_user_data (PikaIntRadioFrame *radio_frame,
gpointer user_data)
{
PikaIntRadioFramePrivate *priv;
GtkTreeIter iter;
g_return_val_if_fail (PIKA_IS_INT_RADIO_FRAME (radio_frame), FALSE);
priv = GET_PRIVATE (radio_frame);
if (pika_int_store_lookup_by_user_data (GTK_TREE_MODEL (priv->store), user_data, &iter))
{
gint value;
gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
PIKA_INT_STORE_VALUE, &value,
-1);
pika_int_radio_frame_set_active (radio_frame, value);
return TRUE;
}
return FALSE;
}
/**
* pika_int_radio_frame_get_active_user_data:
* @radio_frame: a #PikaIntRadioFrame
* @user_data: (out) (transfer none): return location for the gpointer value
*
* Retrieves the user-data of the selected (active) item in the @radio_frame.
*
* Returns: %TRUE if @user_data has been set or %FALSE if no item was
* active.
*
* Since: 3.0
**/
gboolean
pika_int_radio_frame_get_active_user_data (PikaIntRadioFrame *radio_frame,
gpointer *user_data)
{
PikaIntRadioFramePrivate *priv;
GtkTreeIter iter;
g_return_val_if_fail (PIKA_IS_INT_RADIO_FRAME (radio_frame), FALSE);
g_return_val_if_fail (user_data != NULL, FALSE);
priv = GET_PRIVATE (radio_frame);
if (pika_int_store_lookup_by_value (GTK_TREE_MODEL (priv->store), priv->value, &iter))
{
gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &iter,
PIKA_INT_STORE_USER_DATA, user_data,
-1);
return TRUE;
}
return FALSE;
}
/**
* pika_int_radio_frame_set_sensitivity:
* @radio_frame: a #PikaIntRadioFrame
* @func: a function that returns a boolean value, or %NULL to unset
* @data: data to pass to @func
* @destroy: destroy notification for @data
*
* Sets a function that is used to decide about the sensitivity of radio
* buttons in the @radio_frame. Use this if you want to set certain
* radio buttons insensitive.
*
* Calling gtk_widget_queue_draw() on the @radio_frame will cause the
* sensitivity to be updated.
*
* Since: 3.0
**/
void
pika_int_radio_frame_set_sensitivity (PikaIntRadioFrame *radio_frame,
PikaIntRadioFrameSensitivityFunc func,
gpointer data,
GDestroyNotify destroy)
{
PikaIntRadioFramePrivate *priv;
g_return_if_fail (PIKA_IS_INT_RADIO_FRAME (radio_frame));
priv = GET_PRIVATE (radio_frame);
if (priv->sensitivity_destroy)
{
GDestroyNotify destroy = priv->sensitivity_destroy;
priv->sensitivity_destroy = NULL;
destroy (priv->sensitivity_data);
}
priv->sensitivity_func = func;
priv->sensitivity_data = data;
priv->sensitivity_destroy = destroy;
}
/* Private functions */
static gboolean
pika_int_radio_frame_draw (GtkWidget *widget,
cairo_t *cr,
gpointer user_data)
{
pika_int_radio_frame_update_sensitivity (PIKA_INT_RADIO_FRAME (widget));
return FALSE;
}
static void
pika_int_radio_frame_fill (PikaIntRadioFrame *frame)
{
PikaIntRadioFramePrivate *priv;
g_return_if_fail (PIKA_IS_INT_RADIO_FRAME (frame));
priv = GET_PRIVATE (frame);
g_clear_pointer (&priv->group, g_slist_free);
gtk_container_foreach (GTK_CONTAINER (priv->box),
(GtkCallback) gtk_widget_destroy, NULL);
if (priv->store)
{
GtkTreeModel *model;
GSList *group = NULL;
GtkTreeIter iter;
gboolean iter_valid;
model = GTK_TREE_MODEL (priv->store);
for (iter_valid = gtk_tree_model_get_iter_first (model, &iter);
iter_valid;
iter_valid = gtk_tree_model_iter_next (model, &iter))
{
GtkWidget *button;
gchar *label;
gint value;
gtk_tree_model_get (model, &iter,
PIKA_INT_STORE_LABEL, &label,
PIKA_INT_STORE_VALUE, &value,
-1);
button = gtk_radio_button_new_with_mnemonic (group, label);
gtk_box_pack_start (GTK_BOX (priv->box), button, FALSE, FALSE, 0);
gtk_widget_show (button);
g_free (label);
group = gtk_radio_button_get_group (GTK_RADIO_BUTTON (button));
g_object_set_data (G_OBJECT (button), "pika-radio-frame-value",
GINT_TO_POINTER (value));
g_signal_connect (button, "toggled",
G_CALLBACK (pika_int_radio_frame_button_toggled),
frame);
}
priv->group = g_slist_copy (group);
pika_int_radio_frame_set_active (frame, priv->value);
}
}
static void
pika_int_radio_frame_set_store (PikaIntRadioFrame *frame,
PikaIntStore *store)
{
PikaIntRadioFramePrivate *priv;
g_return_if_fail (PIKA_IS_INT_RADIO_FRAME (frame));
g_return_if_fail (PIKA_IS_INT_STORE (store));
priv = GET_PRIVATE (frame);
if (priv->store == store)
return;
if (priv->store)
{
g_signal_handlers_disconnect_by_func (priv->store,
(GCallback) pika_int_radio_frame_fill,
NULL);
g_object_unref (priv->store);
}
priv->store = g_object_ref (store);
if (priv->store)
{
g_signal_connect_object (priv->store, "row-changed",
(GCallback) pika_int_radio_frame_fill,
frame, G_CONNECT_SWAPPED);
g_signal_connect_object (priv->store, "row-deleted",
(GCallback) pika_int_radio_frame_fill,
frame, G_CONNECT_SWAPPED);
g_signal_connect_object (priv->store, "row-inserted",
(GCallback) pika_int_radio_frame_fill,
frame, G_CONNECT_SWAPPED);
g_signal_connect_object (priv->store, "rows-reordered",
(GCallback) pika_int_radio_frame_fill,
frame, G_CONNECT_SWAPPED);
}
pika_int_radio_frame_fill (frame);
g_object_notify (G_OBJECT (frame), "store");
}
static void
pika_int_radio_frame_update_sensitivity (PikaIntRadioFrame *frame)
{
PikaIntRadioFramePrivate *priv = GET_PRIVATE (frame);
GSList *iter = priv->group;
g_return_if_fail (PIKA_IS_INT_RADIO_FRAME (frame));
if (! priv->sensitivity_func)
return;
for (; iter; iter = g_slist_next (iter))
{
GtkWidget *button = GTK_WIDGET (iter->data);
GtkTreeIter tree_iter;
gint value;
value = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "pika-radio-frame-value"));
gtk_widget_set_sensitive (button, TRUE);
if (pika_int_store_lookup_by_value (GTK_TREE_MODEL (priv->store), value, &tree_iter))
{
gpointer user_data;
gint new_value = value;
gtk_tree_model_get (GTK_TREE_MODEL (priv->store), &tree_iter,
PIKA_INT_STORE_USER_DATA, &user_data,
-1);
if (! priv->sensitivity_func (value, user_data, &new_value,
priv->sensitivity_data))
{
if (new_value != value)
pika_int_radio_frame_set_active (frame, new_value);
gtk_widget_set_sensitive (button, FALSE);
}
}
}
}
static void
pika_int_radio_frame_button_toggled (GtkToggleButton *button,
PikaIntRadioFrame *frame)
{
g_return_if_fail (PIKA_IS_INT_RADIO_FRAME (frame));
g_return_if_fail (GTK_IS_RADIO_BUTTON (button));
if (gtk_toggle_button_get_active (button))
{
PikaIntRadioFramePrivate *priv = GET_PRIVATE (frame);
gint value;
value = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (button), "pika-radio-frame-value"));
if (priv->value != value)
{
priv->value = value;
g_object_notify (G_OBJECT (frame), "value");
}
}
}

View File

@ -0,0 +1,128 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaintradioframe.h
* Copyright (C) 2022 Jehan
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#include <libpikawidgets/pikaframe.h>
#ifndef __PIKA_INT_RADIO_FRAME_H__
#define __PIKA_INT_RADIO_FRAME_H__
G_BEGIN_DECLS
#define PIKA_TYPE_INT_RADIO_FRAME (pika_int_radio_frame_get_type ())
#define PIKA_INT_RADIO_FRAME(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_INT_RADIO_FRAME, PikaIntRadioFrame))
#define PIKA_INT_RADIO_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_INT_RADIO_FRAME, PikaIntRadioFrameClass))
#define PIKA_IS_INT_RADIO_FRAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_INT_RADIO_FRAME))
#define PIKA_IS_INT_RADIO_FRAME_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_INT_RADIO_FRAME))
#define PIKA_INT_RADIO_FRAME_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_INT_RADIO_FRAME, PikaIntRadioFrameClass))
typedef struct _PikaIntRadioFrameClass PikaIntRadioFrameClass;
struct _PikaIntRadioFrame
{
PikaFrame parent_instance;
};
struct _PikaIntRadioFrameClass
{
PikaFrameClass parent_class;
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
/**
* PikaIntRadioFrameSensitivityFunc:
* @value: the value associated with a radio button.
* @user_data: the data associated with a radio button.
* @new_value: the value to check instead if the function returns %FALSE.
* @data: (closure): the data set in pika_int_radio_frame_set_sensitivity()
*
* Signature for a function called on each radio button value and data,
* each time the %PikaIntRadioFrame is drawn, to make some radio button
* insensitive.
* If the function returns %FALSE, it usually means that the value is
* not a valid choice in current situation. In this case, you might want
* to toggle instead another value automatically. Set @new_value to the
* value to toggle. If you leave this untouched, the radio button will
* stay toggled despite being insensitive. This is up to you to decide
* whether this is meaningful.
*
* Returns: %TRUE if the button stays sensitive, %FALSE otherwise.
*/
typedef gboolean (* PikaIntRadioFrameSensitivityFunc) (gint value,
gpointer user_data,
gint *new_value,
gpointer data);
GType pika_int_radio_frame_get_type (void) G_GNUC_CONST;
GtkWidget * pika_int_radio_frame_new_from_store (const gchar *title,
PikaIntStore *store);
GtkWidget * pika_int_radio_frame_new (const gchar *first_label,
gint first_value,
...) G_GNUC_NULL_TERMINATED;
GtkWidget * pika_int_radio_frame_new_valist (const gchar *first_label,
gint first_value,
va_list values);
GtkWidget * pika_int_radio_frame_new_array (const gchar *labels[]);
void pika_int_radio_frame_prepend (PikaIntRadioFrame *radio_frame,
...);
void pika_int_radio_frame_append (PikaIntRadioFrame *radio_frame,
...);
gboolean pika_int_radio_frame_set_active (PikaIntRadioFrame *radio_frame,
gint value);
gint pika_int_radio_frame_get_active (PikaIntRadioFrame *radio_frame);
gboolean
pika_int_radio_frame_set_active_by_user_data (PikaIntRadioFrame *radio_frame,
gpointer user_data);
gboolean
pika_int_radio_frame_get_active_user_data (PikaIntRadioFrame *radio_frame,
gpointer *user_data);
void pika_int_radio_frame_set_sensitivity (PikaIntRadioFrame *radio_frame,
PikaIntRadioFrameSensitivityFunc func,
gpointer data,
GDestroyNotify destroy);
G_END_DECLS
#endif /* __PIKA_INT_RADIO_FRAME_H__ */

View File

@ -0,0 +1,452 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaintstore.c
* Copyright (C) 2004-2007 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "pikawidgetstypes.h"
#include "pikaintstore.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikaintstore
* @title: PikaIntStore
* @short_description: A model for integer based name-value pairs
* (e.g. enums)
*
* A model for integer based name-value pairs (e.g. enums)
**/
enum
{
PROP_0,
PROP_USER_DATA_TYPE
};
struct _PikaIntStorePrivate
{
GtkTreeIter *empty_iter;
GType user_data_type;
};
#define GET_PRIVATE(obj) (((PikaIntStore *) (obj))->priv)
static void pika_int_store_tree_model_init (GtkTreeModelIface *iface);
static void pika_int_store_constructed (GObject *object);
static void pika_int_store_finalize (GObject *object);
static void pika_int_store_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_int_store_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_int_store_row_inserted (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter);
static void pika_int_store_row_deleted (GtkTreeModel *model,
GtkTreePath *path);
static void pika_int_store_add_empty (PikaIntStore *store);
G_DEFINE_TYPE_WITH_CODE (PikaIntStore, pika_int_store, GTK_TYPE_LIST_STORE,
G_ADD_PRIVATE (PikaIntStore)
G_IMPLEMENT_INTERFACE (GTK_TYPE_TREE_MODEL,
pika_int_store_tree_model_init))
#define parent_class pika_int_store_parent_class
static GtkTreeModelIface *parent_iface = NULL;
static void
pika_int_store_class_init (PikaIntStoreClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = pika_int_store_constructed;
object_class->finalize = pika_int_store_finalize;
object_class->set_property = pika_int_store_set_property;
object_class->get_property = pika_int_store_get_property;
/**
* PikaIntStore:user-data-type:
*
* Sets the #GType for the PIKA_INT_STORE_USER_DATA column.
*
* You need to set this property when constructing the store if you want
* to use the PIKA_INT_STORE_USER_DATA column and want to have the store
* handle ref-counting of your user data.
*
* Since: 2.4
*/
g_object_class_install_property (object_class,
PROP_USER_DATA_TYPE,
g_param_spec_gtype ("user-data-type",
"User Data Type",
"The GType of the user_data column",
G_TYPE_NONE,
G_PARAM_CONSTRUCT_ONLY |
PIKA_PARAM_READWRITE));
}
static void
pika_int_store_tree_model_init (GtkTreeModelIface *iface)
{
parent_iface = g_type_interface_peek_parent (iface);
iface->row_inserted = pika_int_store_row_inserted;
iface->row_deleted = pika_int_store_row_deleted;
}
static void
pika_int_store_init (PikaIntStore *store)
{
store->priv = pika_int_store_get_instance_private (store);
}
static void
pika_int_store_constructed (GObject *object)
{
PikaIntStore *store = PIKA_INT_STORE (object);
PikaIntStorePrivate *priv = GET_PRIVATE (store);
GType types[PIKA_INT_STORE_NUM_COLUMNS];
G_OBJECT_CLASS (parent_class)->constructed (object);
types[PIKA_INT_STORE_VALUE] = G_TYPE_INT;
types[PIKA_INT_STORE_LABEL] = G_TYPE_STRING;
types[PIKA_INT_STORE_ABBREV] = G_TYPE_STRING;
types[PIKA_INT_STORE_ICON_NAME] = G_TYPE_STRING;
types[PIKA_INT_STORE_PIXBUF] = GDK_TYPE_PIXBUF;
types[PIKA_INT_STORE_USER_DATA] = (priv->user_data_type != G_TYPE_NONE ?
priv->user_data_type : G_TYPE_POINTER);
gtk_list_store_set_column_types (GTK_LIST_STORE (store),
PIKA_INT_STORE_NUM_COLUMNS, types);
pika_int_store_add_empty (store);
}
static void
pika_int_store_finalize (GObject *object)
{
PikaIntStorePrivate *priv = GET_PRIVATE (object);
g_clear_pointer (&priv->empty_iter, gtk_tree_iter_free);
G_OBJECT_CLASS (parent_class)->finalize (object);
}
static void
pika_int_store_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaIntStorePrivate *priv = GET_PRIVATE (object);
switch (property_id)
{
case PROP_USER_DATA_TYPE:
priv->user_data_type = g_value_get_gtype (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_int_store_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaIntStorePrivate *priv = GET_PRIVATE (object);
switch (property_id)
{
case PROP_USER_DATA_TYPE:
g_value_set_gtype (value, priv->user_data_type);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_int_store_row_inserted (GtkTreeModel *model,
GtkTreePath *path,
GtkTreeIter *iter)
{
PikaIntStore *store = PIKA_INT_STORE (model);
PikaIntStorePrivate *priv = GET_PRIVATE (store);
if (parent_iface->row_inserted)
parent_iface->row_inserted (model, path, iter);
if (priv->empty_iter &&
memcmp (iter, priv->empty_iter, sizeof (GtkTreeIter)))
{
gtk_list_store_remove (GTK_LIST_STORE (store), priv->empty_iter);
gtk_tree_iter_free (priv->empty_iter);
priv->empty_iter = NULL;
}
}
static void
pika_int_store_row_deleted (GtkTreeModel *model,
GtkTreePath *path)
{
if (parent_iface->row_deleted)
parent_iface->row_deleted (model, path);
}
static void
pika_int_store_add_empty (PikaIntStore *store)
{
PikaIntStorePrivate *priv = GET_PRIVATE (store);
GtkTreeIter iter = { 0, };
g_return_if_fail (priv->empty_iter == NULL);
gtk_list_store_prepend (GTK_LIST_STORE (store), &iter);
gtk_list_store_set (GTK_LIST_STORE (store), &iter,
PIKA_INT_STORE_VALUE, -1,
/* This string appears in an empty menu as in
* "nothing selected and nothing to select"
*/
PIKA_INT_STORE_LABEL, (_("(Empty)")),
-1);
priv->empty_iter = gtk_tree_iter_copy (&iter);
}
/**
* pika_int_store_new: (skip)
* @first_label: the label of the first item
* @first_value: the value of the first item
* @...: a %NULL terminated list of more label, value pairs
*
* Creates a #GtkListStore with a number of useful columns.
* #PikaIntStore is especially useful if the items you want to store
* are identified using an integer value.
*
* If you need to construct an empty #PikaIntStore, it's best to use
* g_object_new (PIKA_TYPE_INT_STORE, NULL).
*
* Returns: a new #PikaIntStore.
*
* Since: 2.2
**/
GtkListStore *
pika_int_store_new (const gchar *first_label,
gint first_value,
...)
{
GtkListStore *store;
va_list args;
va_start (args, first_value);
store = pika_int_store_new_valist (first_label, first_value, args);
va_end (args);
return store;
}
/**
* pika_int_store_new_valist: (skip)
* @first_label: the label of the first item
* @first_value: the value of the first item
* @values: a va_list with more values
*
* A variant of pika_int_store_new() that takes a va_list of
* label/value pairs.
*
* Returns: a new #PikaIntStore.
*
* Since: 3.0
**/
GtkListStore *
pika_int_store_new_valist (const gchar *first_label,
gint first_value,
va_list values)
{
GtkListStore *store;
const gchar *label;
gint value;
store = g_object_new (PIKA_TYPE_INT_STORE, NULL);
for (label = first_label, value = first_value;
label;
label = va_arg (values, const gchar *), value = va_arg (values, gint))
{
GtkTreeIter iter = { 0, };
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
PIKA_INT_STORE_VALUE, value,
PIKA_INT_STORE_LABEL, label,
-1);
}
return store;
}
/**
* pika_int_store_new_array: (rename-to pika_int_store_new)
* @n_values: the number of values
* @labels: (array length=n_values): an array of labels
*
* A variant of pika_int_store_new() that takes an array of labels.
* The array indices are used as values.
*
* Returns: a new #GtkListStore.
*
* Since: 3.0
**/
GtkListStore *
pika_int_store_new_array (gint n_values,
const gchar *labels[])
{
GtkListStore *store;
gint i;
g_return_val_if_fail (n_values >= 0, NULL);
g_return_val_if_fail (labels != NULL || n_values == 0, NULL);
store = g_object_new (PIKA_TYPE_INT_STORE, NULL);
for (i = 0; i < n_values; i++)
{
GtkTreeIter iter;
if (labels[i])
{
gtk_list_store_append (store, &iter);
gtk_list_store_set (store, &iter,
PIKA_INT_STORE_VALUE, i,
PIKA_INT_STORE_LABEL, gettext (labels[i]),
-1);
}
}
return store;
}
/**
* pika_int_store_lookup_by_value:
* @model: a #PikaIntStore
* @value: an integer value to lookup in the @model
* @iter: (out): return location for the iter of the given @value
*
* Iterate over the @model looking for @value.
*
* Returns: %TRUE if the value has been located and @iter is
* valid, %FALSE otherwise.
*
* Since: 2.2
**/
gboolean
pika_int_store_lookup_by_value (GtkTreeModel *model,
gint value,
GtkTreeIter *iter)
{
gboolean iter_valid;
g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE);
g_return_val_if_fail (iter != NULL, FALSE);
for (iter_valid = gtk_tree_model_get_iter_first (model, iter);
iter_valid;
iter_valid = gtk_tree_model_iter_next (model, iter))
{
gint this;
gtk_tree_model_get (model, iter,
PIKA_INT_STORE_VALUE, &this,
-1);
if (this == value)
break;
}
return iter_valid;
}
/**
* pika_int_store_lookup_by_user_data:
* @model: a #PikaIntStore
* @user_data: a gpointer "user-data" to lookup in the @model
* @iter: (out): return location for the iter of the given @user_data
*
* Iterate over the @model looking for @user_data.
*
* Returns: %TRUE if the user-data has been located and @iter is
* valid, %FALSE otherwise.
*
* Since: 2.10
**/
gboolean
pika_int_store_lookup_by_user_data (GtkTreeModel *model,
gpointer user_data,
GtkTreeIter *iter)
{
gboolean iter_valid = FALSE;
g_return_val_if_fail (GTK_IS_TREE_MODEL (model), FALSE);
g_return_val_if_fail (iter != NULL, FALSE);
for (iter_valid = gtk_tree_model_get_iter_first (model, iter);
iter_valid;
iter_valid = gtk_tree_model_iter_next (model, iter))
{
gpointer this;
gtk_tree_model_get (model, iter,
PIKA_INT_STORE_USER_DATA, &this,
-1);
if (this == user_data)
break;
}
return (gboolean) iter_valid;
}

View File

@ -0,0 +1,111 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaintstore.c
* Copyright (C) 2004 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_INT_STORE_H__
#define __PIKA_INT_STORE_H__
G_BEGIN_DECLS
/**
* PikaIntStoreColumns:
* @PIKA_INT_STORE_VALUE: the integer value
* @PIKA_INT_STORE_LABEL: a human-readable label
* @PIKA_INT_STORE_ABBREV: an abbreviated label
* @PIKA_INT_STORE_ICON_NAME: an icon name
* @PIKA_INT_STORE_PIXBUF: a #GdkPixbuf
* @PIKA_INT_STORE_USER_DATA: arbitrary user data
* @PIKA_INT_STORE_NUM_COLUMNS: the number of columns
*
* The column types of #PikaIntStore.
**/
typedef enum
{
PIKA_INT_STORE_VALUE,
PIKA_INT_STORE_LABEL,
PIKA_INT_STORE_ABBREV,
PIKA_INT_STORE_ICON_NAME,
PIKA_INT_STORE_PIXBUF,
PIKA_INT_STORE_USER_DATA,
PIKA_INT_STORE_NUM_COLUMNS
} PikaIntStoreColumns;
#define PIKA_TYPE_INT_STORE (pika_int_store_get_type ())
#define PIKA_INT_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_INT_STORE, PikaIntStore))
#define PIKA_INT_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_INT_STORE, PikaIntStoreClass))
#define PIKA_IS_INT_STORE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_INT_STORE))
#define PIKA_IS_INT_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_INT_STORE))
#define PIKA_INT_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_INT_STORE, PikaIntStoreClass))
typedef struct _PikaIntStorePrivate PikaIntStorePrivate;
typedef struct _PikaIntStoreClass PikaIntStoreClass;
struct _PikaIntStore
{
GtkListStore parent_instance;
PikaIntStorePrivate *priv;
};
struct _PikaIntStoreClass
{
GtkListStoreClass parent_class;
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_int_store_get_type (void) G_GNUC_CONST;
GtkListStore * pika_int_store_new (const gchar *first_label,
gint first_value,
...) G_GNUC_NULL_TERMINATED;
GtkListStore * pika_int_store_new_valist (const gchar *first_label,
gint first_value,
va_list values);
GtkListStore * pika_int_store_new_array (gint n_values,
const gchar *labels[]);
gboolean pika_int_store_lookup_by_value (GtkTreeModel *model,
gint value,
GtkTreeIter *iter);
gboolean pika_int_store_lookup_by_user_data (GtkTreeModel *model,
gpointer user_data,
GtkTreeIter *iter);
G_END_DECLS
#endif /* __PIKA_INT_STORE_H__ */

View File

@ -0,0 +1,436 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikalabelcolor.c
* Copyright (C) 2022 Jehan
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikacolor/pikacolor.h"
#include "libpikamath/pikamath.h"
#include "libpikabase/pikabase.h"
#include "pikawidgets.h"
#include "pikawidgets-private.h"
/**
* SECTION: pikalabelcolor
* @title: PikaLabelColor
* @short_description: Widget containing a color widget and a label.
*
* This widget is a subclass of #PikaLabeled with a #GtkColor.
**/
enum
{
VALUE_CHANGED,
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_VALUE,
PROP_EDITABLE,
N_PROPS
};
static GParamSpec *object_props[N_PROPS] = { NULL, };
typedef struct _PikaLabelColorPrivate
{
GtkWidget *area;
gboolean editable;
} PikaLabelColorPrivate;
static void pika_label_color_constructed (GObject *object);
static void pika_label_color_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_label_color_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static GtkWidget * pika_label_color_populate (PikaLabeled *color,
gint *x,
gint *y,
gint *width,
gint *height);
G_DEFINE_TYPE_WITH_PRIVATE (PikaLabelColor, pika_label_color, PIKA_TYPE_LABELED)
#define parent_class pika_label_color_parent_class
static guint pika_label_color_signals[LAST_SIGNAL] = { 0 };
static void
pika_label_color_class_init (PikaLabelColorClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaLabeledClass *labeled_class = PIKA_LABELED_CLASS (klass);
PikaRGB black;
pika_label_color_signals[VALUE_CHANGED] =
g_signal_new ("value-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaLabelColorClass, value_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
object_class->constructed = pika_label_color_constructed;
object_class->set_property = pika_label_color_set_property;
object_class->get_property = pika_label_color_get_property;
labeled_class->populate = pika_label_color_populate;
/**
* PikaLabelColor:value:
*
* The currently set value.
*
* Since: 3.0
**/
pika_rgba_set (&black, 0.0, 0.0, 0.0, 1.0);
object_props[PROP_VALUE] = pika_param_spec_rgb ("value",
"Color",
"The displayed color",
TRUE, &black,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT);
/**
* PikaLabelColor:editable:
*
* Whether the color can be edited.
*
* Since: 3.0
**/
object_props[PROP_EDITABLE] = g_param_spec_boolean ("editable",
"Whether the color can be edited",
"Whether the color can be edited",
FALSE,
PIKA_PARAM_READWRITE);
g_object_class_install_properties (object_class, N_PROPS, object_props);
}
static void
pika_label_color_init (PikaLabelColor *color)
{
PikaLabelColorPrivate *priv = pika_label_color_get_instance_private (color);
PikaRGB black;
pika_rgba_set (&black, 0.0, 0.0, 0.0, 1.0);
priv->editable = FALSE;
priv->area = pika_color_area_new (&black, PIKA_COLOR_AREA_SMALL_CHECKS,
GDK_BUTTON1_MASK | GDK_BUTTON2_MASK);
/* Typically for a labelled color area, a small square next to your
* label is probably what you want to display.
*/
gtk_widget_set_size_request (priv->area, 20, 20);
}
static void
pika_label_color_constructed (GObject *object)
{
PikaLabelColor *color = PIKA_LABEL_COLOR (object);
PikaLabelColorPrivate *priv = pika_label_color_get_instance_private (color);
G_OBJECT_CLASS (parent_class)->constructed (object);
/* This is important to make this object into a property widget. It
* will allow config object to bind the "value" property of this
* widget, and therefore be updated automatically.
*/
g_object_bind_property (G_OBJECT (priv->area), "color",
G_OBJECT (color), "value",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
}
static void
pika_label_color_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaLabelColor *lcolor = PIKA_LABEL_COLOR (object);
PikaLabelColorPrivate *priv = pika_label_color_get_instance_private (lcolor);
switch (property_id)
{
case PROP_VALUE:
{
PikaRGB *new_color;
PikaRGB *color;
new_color = g_value_get_boxed (value);
g_object_get (priv->area,
"color", &color,
NULL);
/* Avoid looping forever since we have bound this widget's
* "value" property with the color button "value" property.
*/
if (pika_rgba_distance (color, new_color) >= PIKA_RGBA_EPSILON)
{
g_object_set (priv->area, "color", new_color, NULL);
g_signal_emit (object, pika_label_color_signals[VALUE_CHANGED], 0);
}
g_boxed_free (PIKA_TYPE_RGB, color);
}
break;
case PROP_EDITABLE:
if (priv->editable != g_value_get_boolean (value))
{
const gchar *dialog_title;
PikaLabeled *labeled;
PikaRGB *color;
PikaColorAreaType type;
gboolean attached;
labeled = PIKA_LABELED (lcolor);
/* Reuse the label contents (without mnemonics) as dialog
* title for the color selection. This is why the "editable"
* property must not be a G_PARAM_CONSTRUCT.
*/
dialog_title = gtk_label_get_text (GTK_LABEL (pika_labeled_get_label (labeled)));
attached = (gtk_widget_get_parent (priv->area) != NULL);
g_object_get (priv->area,
"type", &type,
"color", &color,
NULL);
gtk_widget_destroy (priv->area);
priv->editable = g_value_get_boolean (value);
if (priv->editable)
priv->area = pika_color_button_new (dialog_title,
20, 20, color, type);
else
priv->area = pika_color_area_new (color, type,
GDK_BUTTON1_MASK | GDK_BUTTON2_MASK);
g_boxed_free (PIKA_TYPE_RGB, color);
gtk_widget_set_size_request (priv->area, 20, 20);
g_object_bind_property (G_OBJECT (priv->area), "color",
G_OBJECT (lcolor), "value",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
if (attached)
{
gtk_grid_attach (GTK_GRID (lcolor), priv->area, 1, 0, 1, 1);
gtk_widget_show (priv->area);
g_signal_emit_by_name (object, "mnemonic-widget-changed", priv->area);
}
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_label_color_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaLabelColor *color = PIKA_LABEL_COLOR (object);
PikaLabelColorPrivate *priv = pika_label_color_get_instance_private (color);
switch (property_id)
{
case PROP_VALUE:
g_object_get_property (G_OBJECT (priv->area), "color", value);
break;
case PROP_EDITABLE:
g_value_set_boolean (value, priv->editable);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static GtkWidget *
pika_label_color_populate (PikaLabeled *labeled,
gint *x,
gint *y,
gint *width,
gint *height)
{
PikaLabelColor *color = PIKA_LABEL_COLOR (labeled);
PikaLabelColorPrivate *priv = pika_label_color_get_instance_private (color);
gtk_grid_attach (GTK_GRID (color), priv->area, 1, 0, 1, 1);
/* Make sure the label and color won't be glued next to each other's. */
gtk_grid_set_column_spacing (GTK_GRID (color),
4 * gtk_widget_get_scale_factor (GTK_WIDGET (color)));
gtk_widget_show (priv->area);
return priv->area;
}
/* Public Functions */
/**
* pika_label_color_new:
* @label: The text for the #GtkLabel.
* @color: The color displayed.
*
* Creates a #PikaLabelColor which contains a widget and displays a
* color area. By default, the color area is of type
* %PIKA_COLOR_AREA_SMALL_CHECKS, which means transparency of @color
* will be shown.
*
* Moreover in the non-editable case, the color is draggable to other
* widgets accepting color drops with buttons 1 and 2.
* In the editable case, the @label is reused as the color chooser's
* dialog title.
*
* If you wish to customize any of these default behaviors, get the
* #PikaColorArea or #PikaColorButton with pika_label_color_get_color_widget().
*
* Returns: (transfer full): The new #PikaLabelColor widget.
**/
GtkWidget *
pika_label_color_new (const gchar *label,
const PikaRGB *color,
gboolean editable)
{
GtkWidget *labeled;
labeled = g_object_new (PIKA_TYPE_LABEL_COLOR,
"label", label,
"value", color,
"editable", editable,
NULL);
return labeled;
}
/**
* pika_label_color_set_value:
* @color: The #GtkLabelColor.
* @value: A new value.
*
* This function sets the value in the #GtkColor inside @color.
**/
void
pika_label_color_set_value (PikaLabelColor *color,
const PikaRGB *value)
{
g_return_if_fail (PIKA_IS_LABEL_COLOR (color));
g_object_set (color,
"value", value,
NULL);
}
/**
* pika_label_color_get_value:
* @color: The #GtkLabelColor.
* @value: (out callee-allocates): The color to assign to the color area.
*
* This function returns the value shown by @color.
**/
void
pika_label_color_get_value (PikaLabelColor *color,
PikaRGB *value)
{
PikaLabelColorPrivate *priv = pika_label_color_get_instance_private (color);
g_return_if_fail (PIKA_IS_LABEL_COLOR (color));
g_object_get (priv->area,
"color", &value,
NULL);
}
/**
* pika_label_color_set_editable:
* @color: The #GtkLabelColor.
* @editable: Whether the color should be editable.
*
* Changes the editability of the color.
**/
void
pika_label_color_set_editable (PikaLabelColor *color,
gboolean editable)
{
g_return_if_fail (PIKA_IS_LABEL_COLOR (color));
g_object_set (color, "editable", editable, NULL);
}
/**
* pika_label_color_is_editable:
* @color: The #GtkLabelColor.
*
* This function tells whether the color widget allows to edit the
* color.
* Returns: %TRUE if the color is editable.
**/
gboolean
pika_label_color_is_editable (PikaLabelColor *color)
{
PikaLabelColorPrivate *priv = pika_label_color_get_instance_private (color);
g_return_val_if_fail (PIKA_IS_LABEL_COLOR (color), FALSE);
priv = pika_label_color_get_instance_private (color);
return PIKA_IS_COLOR_SELECT (priv->area);
}
/**
* pika_label_color_get_color_widget:
* @color: The #PikaLabelColor
*
* This function returns the color widget packed in @color, which can be
* either a #PikaColorButton (if the @color is editable) or a
* #PikaColorArea otherwise.
*
* Returns: (transfer none): The color widget packed in @color.
**/
GtkWidget *
pika_label_color_get_color_widget (PikaLabelColor *color)
{
PikaLabelColorPrivate *priv = pika_label_color_get_instance_private (color);
g_return_val_if_fail (PIKA_IS_LABEL_COLOR (color), NULL);
return priv->area;
}

View File

@ -0,0 +1,76 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikalabelcolor.h
* Copyright (C) 2022 Jehan
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_LABEL_COLOR_H__
#define __PIKA_LABEL_COLOR_H__
#include <libpikawidgets/pikalabeled.h>
G_BEGIN_DECLS
#define PIKA_TYPE_LABEL_COLOR (pika_label_color_get_type ())
G_DECLARE_DERIVABLE_TYPE (PikaLabelColor, pika_label_color, PIKA, LABEL_COLOR, PikaLabeled)
struct _PikaLabelColorClass
{
PikaLabeledClass parent_class;
/* Signals */
void (* value_changed) (PikaLabelColor *color);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GtkWidget * pika_label_color_new (const gchar *label,
const PikaRGB *color,
gboolean editable);
/* TODO: it would be interesting for such a widget to have an API to
* customize the label being also above or below, left or right. I could
* imagine wanting to pretty-list several colors with specific layouts.
*/
void pika_label_color_set_value (PikaLabelColor *color,
const PikaRGB *value);
void pika_label_color_get_value (PikaLabelColor *color,
PikaRGB *value);
void pika_label_color_set_editable (PikaLabelColor *color,
gboolean editable);
gboolean pika_label_color_is_editable (PikaLabelColor *color);
GtkWidget * pika_label_color_get_color_widget (PikaLabelColor *color);
G_END_DECLS
#endif /* __PIKA_LABEL_COLOR_H__ */

View File

@ -0,0 +1,274 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikalabeled.c
* Copyright (C) 2020 Jehan
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikamath/pikamath.h"
#include "libpikabase/pikabase.h"
#include "pikawidgets.h"
/**
* SECTION: pikalabeled
* @title: PikaLabeled
* @short_description: Widget containing a label as mnemonic for another
* widget.
*
* This widget is a #GtkGrid showing a #GtkLabel used as mnemonic on
* another widget.
**/
enum
{
MNEMONIC_WIDGET_CHANGED,
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_LABEL,
};
typedef struct _PikaLabeledPrivate
{
GtkWidget *label;
} PikaLabeledPrivate;
static void pika_labeled_constructed (GObject *object);
static void pika_labeled_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_labeled_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static void pika_labeled_real_mnemonic_widget_changed (PikaLabeled *labeled,
GtkWidget *widget);
G_DEFINE_TYPE_WITH_PRIVATE (PikaLabeled, pika_labeled, GTK_TYPE_GRID)
#define parent_class pika_labeled_parent_class
static guint signals[LAST_SIGNAL] = { 0 };
static void
pika_labeled_class_init (PikaLabeledClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructed = pika_labeled_constructed;
object_class->set_property = pika_labeled_set_property;
object_class->get_property = pika_labeled_get_property;
signals[MNEMONIC_WIDGET_CHANGED] =
g_signal_new ("mnemonic-widget-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaLabeledClass, mnemonic_widget_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1,
GTK_TYPE_WIDGET);
klass->mnemonic_widget_changed = pika_labeled_real_mnemonic_widget_changed;
/**
* PikaLabeled:label:
*
* Label text with pango markup and mnemonic.
*
* Since: 3.0
**/
g_object_class_install_property (object_class, PROP_LABEL,
g_param_spec_string ("label",
"Label text",
"The text of the label part of this widget",
NULL,
PIKA_PARAM_READWRITE));
}
static void
pika_labeled_init (PikaLabeled *labeled)
{
}
static void
pika_labeled_constructed (GObject *object)
{
PikaLabeledClass *klass;
PikaLabeled *labeled = PIKA_LABELED (object);
PikaLabeledPrivate *priv = pika_labeled_get_instance_private (labeled);
GtkWidget *mnemonic_widget;
gint x = 0;
gint y = 0;
gint width = 1;
gint height = 1;
G_OBJECT_CLASS (parent_class)->constructed (object);
priv->label = gtk_label_new_with_mnemonic (NULL);
gtk_label_set_xalign (GTK_LABEL (priv->label), 0.0);
klass = PIKA_LABELED_GET_CLASS (labeled);
g_return_if_fail (klass->populate);
mnemonic_widget = klass->populate (labeled, &x, &y, &width, &height);
g_signal_emit (object, signals[MNEMONIC_WIDGET_CHANGED], 0,
mnemonic_widget);
gtk_grid_attach (GTK_GRID (labeled), priv->label, x, y, width, height);
gtk_widget_show (priv->label);
}
static void
pika_labeled_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaLabeled *entry = PIKA_LABELED (object);
PikaLabeledPrivate *priv = pika_labeled_get_instance_private (entry);
switch (property_id)
{
case PROP_LABEL:
{
/* This should not happen since the property is **not** set with
* G_PARAM_CONSTRUCT, hence the label should exist when the
* property is first set.
*/
g_return_if_fail (priv->label);
gtk_label_set_markup_with_mnemonic (GTK_LABEL (priv->label),
g_value_get_string (value));
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_labeled_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaLabeled *entry = PIKA_LABELED (object);
PikaLabeledPrivate *priv = pika_labeled_get_instance_private (entry);
switch (property_id)
{
case PROP_LABEL:
g_value_set_string (value, gtk_label_get_label (GTK_LABEL (priv->label)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_labeled_real_mnemonic_widget_changed (PikaLabeled *labeled,
GtkWidget *widget)
{
PikaLabeledPrivate *priv = pika_labeled_get_instance_private (labeled);
gtk_label_set_mnemonic_widget (GTK_LABEL (priv->label), widget);
}
/* Public functions */
/**
* pika_labeled_get_label:
* @labeled: The #PikaLabeled.
*
* This function returns the #GtkLabel packed in @labeled. This can be
* useful if you need to customize some aspects of the widget.
*
* Returns: (transfer none) (type GtkLabel): The #GtkLabel contained in @labeled.
**/
GtkWidget *
pika_labeled_get_label (PikaLabeled *labeled)
{
PikaLabeledPrivate *priv = pika_labeled_get_instance_private (labeled);
g_return_val_if_fail (PIKA_IS_LABELED (labeled), NULL);
return priv->label;
}
/**
* pika_labeled_get_text:
* @labeled: the #PikaLabeled.
*
* This function will return exactly what you entered with
* pika_labeled_set_text() or through the "label" property because this
* class expects labels to have mnemonics (and allows Pango formatting).
* To obtain instead the text as displayed with mnemonics and markup
* removed, call:
* |[<!-- language="C" -->
* gtk_label_get_text (GTK_LABEL (pika_labeled_get_label (@labeled)));
* ]|
*
* Returns: the label text as entered, which includes pango markup and
* mnemonics similarly to gtk_label_get_label().
*/
const gchar *
pika_labeled_get_text (PikaLabeled *labeled)
{
PikaLabeledPrivate *priv = pika_labeled_get_instance_private (labeled);
g_return_val_if_fail (PIKA_IS_LABELED (labeled), NULL);
return gtk_label_get_label (GTK_LABEL (priv->label));
}
/**
* pika_labeled_set_text:
* @labeled: the #PikaLabeled.
* @text: label text with Pango markup and mnemonic.
*
* This is the equivalent of running
* gtk_label_set_markup_with_mnemonic() on the #GtkLabel as a
* #PikaLabeled expects a mnemonic. Pango markup are also allowed.
*/
void
pika_labeled_set_text (PikaLabeled *labeled,
const gchar *text)
{
PikaLabeledPrivate *priv = pika_labeled_get_instance_private (labeled);
g_return_if_fail (PIKA_IS_LABELED (labeled));
gtk_label_set_markup_with_mnemonic (GTK_LABEL (priv->label), text);
}

View File

@ -0,0 +1,85 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikalabeled.h
* Copyright (C) 2020 Jehan
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_LABELED_H__
#define __PIKA_LABELED_H__
G_BEGIN_DECLS
#define PIKA_TYPE_LABELED (pika_labeled_get_type ())
G_DECLARE_DERIVABLE_TYPE (PikaLabeled, pika_labeled, PIKA, LABELED, GtkGrid)
struct _PikaLabeledClass
{
GtkGridClass parent_class;
/* Signals */
void (* mnemonic_widget_changed) (PikaLabeled *labeled,
GtkWidget *widget);
/* Class methods */
/**
* PikaLabelledClass::populate:
*
* Fill the #GtkGrid with any necessary widget and sets the
* coordinates and dimensions the #GtkLabel should be attached to.
* By default, @x, @y, @width and @height will be pre-filled with 0,
* 0, 1 and 1 respectively, i.e. the top-left of the grid. There is no
* need to edit these output variables unless your subclass wants the
* label to be placed elsewhere.
*
* Returns: (transfer none): the #GtkWidget which the label must be
* set as mnemonic to.
**/
GtkWidget * (* populate) (PikaLabeled *labeled,
gint *x,
gint *y,
gint *width,
gint *height);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GtkWidget * pika_labeled_get_label (PikaLabeled *labeled);
const gchar * pika_labeled_get_text (PikaLabeled *labeled);
void pika_labeled_set_text (PikaLabeled *labeled,
const gchar *text);
G_END_DECLS
#endif /* __PIKA_LABELED_H__ */

View File

@ -0,0 +1,296 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikalabelentry.c
* Copyright (C) 2022 Jehan
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikacolor/pikacolor.h"
#include "libpikamath/pikamath.h"
#include "libpikabase/pikabase.h"
#include "pikawidgets.h"
/**
* SECTION: pikalabelentry
* @title: PikaLabelEntry
* @short_description: Widget containing an entry and a label.
*
* This widget is a subclass of #PikaLabeled with a #GtkEntry.
**/
enum
{
VALUE_CHANGED,
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_VALUE,
};
typedef struct _PikaLabelEntryPrivate
{
GtkWidget *entry;
} PikaLabelEntryPrivate;
static void pika_label_entry_constructed (GObject *object);
static void pika_label_entry_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_label_entry_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static GtkWidget * pika_label_entry_populate (PikaLabeled *entry,
gint *x,
gint *y,
gint *width,
gint *height);
G_DEFINE_TYPE_WITH_PRIVATE (PikaLabelEntry, pika_label_entry, PIKA_TYPE_LABELED)
#define parent_class pika_label_entry_parent_class
static guint pika_label_entry_signals[LAST_SIGNAL] = { 0 };
static void
pika_label_entry_class_init (PikaLabelEntryClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaLabeledClass *labeled_class = PIKA_LABELED_CLASS (klass);
pika_label_entry_signals[VALUE_CHANGED] =
g_signal_new ("value-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaLabelEntryClass, value_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
object_class->constructed = pika_label_entry_constructed;
object_class->set_property = pika_label_entry_set_property;
object_class->get_property = pika_label_entry_get_property;
labeled_class->populate = pika_label_entry_populate;
/**
* PikaLabelEntry:value:
*
* The currently set value.
*
* Since: 3.0
**/
g_object_class_install_property (object_class, PROP_VALUE,
g_param_spec_string ("value",
"Entry text",
"The text in the entry",
NULL,
PIKA_PARAM_READWRITE));
}
static void
pika_label_entry_init (PikaLabelEntry *entry)
{
PikaLabelEntryPrivate *priv = pika_label_entry_get_instance_private (entry);
priv->entry = gtk_entry_new ();
}
static void
pika_label_entry_constructed (GObject *object)
{
PikaLabelEntry *entry = PIKA_LABEL_ENTRY (object);
PikaLabelEntryPrivate *priv = pika_label_entry_get_instance_private (entry);
GtkEntryBuffer *buffer = gtk_entry_get_buffer (GTK_ENTRY (priv->entry));
G_OBJECT_CLASS (parent_class)->constructed (object);
/* This is important to make this object into a property widget. It
* will allow config object to bind the "value" property of this
* widget, and therefore be updated automatically.
*/
g_object_bind_property (G_OBJECT (buffer), "text",
G_OBJECT (entry), "value",
G_BINDING_BIDIRECTIONAL | G_BINDING_SYNC_CREATE);
}
static void
pika_label_entry_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaLabelEntry *entry = PIKA_LABEL_ENTRY (object);
PikaLabelEntryPrivate *priv = pika_label_entry_get_instance_private (entry);
switch (property_id)
{
case PROP_VALUE:
{
GtkEntryBuffer *buffer = gtk_entry_get_buffer (GTK_ENTRY (priv->entry));
/* Avoid looping forever since we have bound this widget's
* "value" property with the entry button "value" property.
*/
if (g_strcmp0 (gtk_entry_buffer_get_text (buffer),
g_value_get_string (value)) != 0)
gtk_entry_buffer_set_text (buffer, g_value_get_string (value), -1);
g_signal_emit (object, pika_label_entry_signals[VALUE_CHANGED], 0);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_label_entry_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaLabelEntry *entry = PIKA_LABEL_ENTRY (object);
PikaLabelEntryPrivate *priv = pika_label_entry_get_instance_private (entry);
switch (property_id)
{
case PROP_VALUE:
{
GtkEntryBuffer *buffer = gtk_entry_get_buffer (GTK_ENTRY (priv->entry));
g_value_set_string (value, gtk_entry_buffer_get_text (buffer));
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static GtkWidget *
pika_label_entry_populate (PikaLabeled *labeled,
gint *x,
gint *y,
gint *width,
gint *height)
{
PikaLabelEntry *entry = PIKA_LABEL_ENTRY (labeled);
PikaLabelEntryPrivate *priv = pika_label_entry_get_instance_private (entry);
gtk_grid_attach (GTK_GRID (entry), priv->entry, 1, 0, 1, 1);
/* Make sure the label and entry won't be glued next to each other's. */
gtk_grid_set_column_spacing (GTK_GRID (entry),
4 * gtk_widget_get_scale_factor (GTK_WIDGET (entry)));
gtk_widget_show (priv->entry);
return priv->entry;
}
/* Public Functions */
/**
* pika_label_entry_new:
* @label: The text for the #GtkLabel.
*
*
* Returns: (transfer full): The new #PikaLabelEntry widget.
**/
GtkWidget *
pika_label_entry_new (const gchar *label)
{
GtkWidget *labeled;
labeled = g_object_new (PIKA_TYPE_LABEL_ENTRY,
"label", label,
NULL);
return labeled;
}
/**
* pika_label_entry_set_value:
* @entry: The #GtkLabelEntry.
* @value: A new value.
*
* This function sets the value in the #GtkEntry inside @entry.
**/
void
pika_label_entry_set_value (PikaLabelEntry *entry,
const gchar *value)
{
g_return_if_fail (PIKA_IS_LABEL_ENTRY (entry));
g_object_set (entry,
"value", value,
NULL);
}
/**
* pika_label_entry_get_value:
* @entry: The #GtkLabelEntry.
*
* This function returns the value shown by @entry.
*
* Returns: (transfer none): The value currently set.
**/
const gchar *
pika_label_entry_get_value (PikaLabelEntry *entry)
{
PikaLabelEntryPrivate *priv = pika_label_entry_get_instance_private (entry);
GtkEntryBuffer *buffer;
g_return_val_if_fail (PIKA_IS_LABEL_ENTRY (entry), NULL);
buffer = gtk_entry_get_buffer (GTK_ENTRY (priv->entry));
return gtk_entry_buffer_get_text (buffer);
}
/**
* pika_label_entry_get_entry:
* @entry: The #PikaLabelEntry
*
* This function returns the #GtkEntry packed in @entry.
*
* Returns: (transfer none): The #GtkEntry contained in @entry.
**/
GtkWidget *
pika_label_entry_get_entry (PikaLabelEntry *entry)
{
PikaLabelEntryPrivate *priv = pika_label_entry_get_instance_private (entry);
g_return_val_if_fail (PIKA_IS_LABEL_ENTRY (entry), NULL);
return priv->entry;
}

View File

@ -0,0 +1,64 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikalabelentry.h
* Copyright (C) 2022 Jehan
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_LABEL_ENTRY_H__
#define __PIKA_LABEL_ENTRY_H__
#include <libpikawidgets/pikalabeled.h>
G_BEGIN_DECLS
#define PIKA_TYPE_LABEL_ENTRY (pika_label_entry_get_type ())
G_DECLARE_DERIVABLE_TYPE (PikaLabelEntry, pika_label_entry, PIKA, LABEL_ENTRY, PikaLabeled)
struct _PikaLabelEntryClass
{
PikaLabeledClass parent_class;
/* Signals */
void (* value_changed) (PikaLabelEntry *entry);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GtkWidget * pika_label_entry_new (const gchar *label);
void pika_label_entry_set_value (PikaLabelEntry *entry,
const gchar *value);
const gchar * pika_label_entry_get_value (PikaLabelEntry *entry);
GtkWidget * pika_label_entry_get_entry (PikaLabelEntry *entry);
G_END_DECLS
#endif /* __PIKA_LABEL_ENTRY_H__ */

View File

@ -0,0 +1,273 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikalabelintwidget.c
* Copyright (C) 2020 Jehan
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikacolor/pikacolor.h"
#include "libpikamath/pikamath.h"
#include "libpikabase/pikabase.h"
#include "pikalabelintwidget.h"
/**
* SECTION: pikalabelintwidget
* @title: PikaLabelIntWidget
* @short_description: Widget containing a label and a widget with an
* integer "value" property.
*
* This widget is a subclass of #PikaLabeled.
**/
enum
{
VALUE_CHANGED,
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_VALUE,
PROP_WIDGET,
};
typedef struct _PikaLabelIntWidgetPrivate
{
PikaLabeled parent_instance;
GtkWidget *widget;
gint value;
} PikaLabelIntWidgetPrivate;
static void pika_label_int_widget_constructed (GObject *object);
static void pika_label_int_widget_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_label_int_widget_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static GtkWidget * pika_label_int_widget_populate (PikaLabeled *widget,
gint *x,
gint *y,
gint *width,
gint *height);
G_DEFINE_TYPE_WITH_PRIVATE (PikaLabelIntWidget, pika_label_int_widget, PIKA_TYPE_LABELED)
#define parent_class pika_label_int_widget_parent_class
static guint pika_label_int_widget_signals[LAST_SIGNAL] = { 0 };
static void
pika_label_int_widget_class_init (PikaLabelIntWidgetClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaLabeledClass *labeled_class = PIKA_LABELED_CLASS (klass);
pika_label_int_widget_signals[VALUE_CHANGED] =
g_signal_new ("value-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaLabelIntWidgetClass, value_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
object_class->constructed = pika_label_int_widget_constructed;
object_class->set_property = pika_label_int_widget_set_property;
object_class->get_property = pika_label_int_widget_get_property;
labeled_class->populate = pika_label_int_widget_populate;
/**
* PikaLabelIntWidget:value:
*
* The currently set value.
*
* Since: 3.0
**/
g_object_class_install_property (object_class, PROP_VALUE,
g_param_spec_int ("value", NULL,
"Current value",
G_MININT, G_MAXINT, 0,
PIKA_PARAM_READWRITE));
/**
* PikaLabelIntWidget:widget:
*
* The widget holding an integer value.
*
* Since: 3.0
**/
g_object_class_install_property (object_class, PROP_WIDGET,
g_param_spec_object ("widget", NULL,
"Integer widget",
GTK_TYPE_WIDGET,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
}
static void
pika_label_int_widget_init (PikaLabelIntWidget *widget)
{
}
static void
pika_label_int_widget_constructed (GObject *object)
{
PikaLabelIntWidget *widget = PIKA_LABEL_INT_WIDGET (object);
PikaLabelIntWidgetPrivate *priv = pika_label_int_widget_get_instance_private (widget);
G_OBJECT_CLASS (parent_class)->constructed (object);
gtk_grid_set_column_spacing (GTK_GRID (widget), 6);
gtk_grid_set_row_spacing (GTK_GRID (widget), 6);
/* This is important to make this object into a property widget. It
* will allow config object to bind the "value" property of this
* widget, and therefore be updated automatically.
*/
g_object_bind_property (G_OBJECT (priv->widget), "value",
object, "value",
G_BINDING_BIDIRECTIONAL |
G_BINDING_SYNC_CREATE);
}
static void
pika_label_int_widget_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaLabelIntWidget *widget = PIKA_LABEL_INT_WIDGET (object);
PikaLabelIntWidgetPrivate *priv = pika_label_int_widget_get_instance_private (widget);
switch (property_id)
{
case PROP_VALUE:
priv->value = g_value_get_int (value);
g_signal_emit (object, pika_label_int_widget_signals[VALUE_CHANGED], 0);
break;
case PROP_WIDGET:
priv->widget = g_value_get_object (value);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_label_int_widget_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaLabelIntWidget *widget = PIKA_LABEL_INT_WIDGET (object);
PikaLabelIntWidgetPrivate *priv = pika_label_int_widget_get_instance_private (widget);
switch (property_id)
{
case PROP_VALUE:
g_value_set_int (value, priv->value);
break;
case PROP_WIDGET:
g_value_set_object (value, priv->widget);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static GtkWidget *
pika_label_int_widget_populate (PikaLabeled *labeled,
gint *x,
gint *y,
gint *width,
gint *height)
{
PikaLabelIntWidget *widget = PIKA_LABEL_INT_WIDGET (labeled);
PikaLabelIntWidgetPrivate *priv = pika_label_int_widget_get_instance_private (widget);
gtk_grid_attach (GTK_GRID (widget), priv->widget, 1, 0, 1, 1);
gtk_widget_show (priv->widget);
return priv->widget;
}
/* Public Functions */
/**
* pika_label_int_widget_new:
* @text: The text for the #GtkLabel.
* @widget: (transfer full): The #GtkWidget to use.
*
* Creates a new #PikaLabelIntWidget whose "value" property is bound to
* that of @widget (which must therefore have such an integer property).
*
* Returns: (transfer full): The new #PikaLabelIntWidget widget.
**/
GtkWidget *
pika_label_int_widget_new (const gchar *text,
GtkWidget *widget)
{
GtkWidget *int_widget;
GParamSpec *pspec;
g_return_val_if_fail ((pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (widget),
"value")) &&
G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_INT,
NULL);
int_widget = g_object_new (PIKA_TYPE_LABEL_INT_WIDGET,
"label", text,
"widget", widget,
NULL);
return int_widget;
}
/**
* pika_label_int_widget_get_widget:
* @widget: the #PikaLabelIntWidget.
*
* Returns: (transfer none): The new #GtkWidget packed next to the label.
**/
GtkWidget *
pika_label_int_widget_get_widget (PikaLabelIntWidget *widget)
{
PikaLabelIntWidgetPrivate *priv;
g_return_val_if_fail (PIKA_IS_LABEL_INT_WIDGET (widget), NULL);
priv = pika_label_int_widget_get_instance_private (widget);
return priv->widget;
}

View File

@ -0,0 +1,62 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikalabelintwidget.h
* Copyright (C) 2020 Jehan
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_LABEL_INT_WIDGET_H__
#define __PIKA_LABEL_INT_WIDGET_H__
#include <libpikawidgets/pikalabeled.h>
G_BEGIN_DECLS
#define PIKA_TYPE_LABEL_INT_WIDGET (pika_label_int_widget_get_type ())
G_DECLARE_DERIVABLE_TYPE (PikaLabelIntWidget, pika_label_int_widget, PIKA, LABEL_INT_WIDGET, PikaLabeled)
struct _PikaLabelIntWidgetClass
{
PikaLabeledClass parent_class;
/* Signals */
void (* value_changed) (GtkWidget *int_widget);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GtkWidget * pika_label_int_widget_new (const gchar *text,
GtkWidget *widget);
GtkWidget * pika_label_int_widget_get_widget (PikaLabelIntWidget *widget);
G_END_DECLS
#endif /* __PIKA_LABEL_INT_WIDGET_H__ */

View File

@ -0,0 +1,519 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikalabelspin.c
* Copyright (C) 2020 Jehan
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "libpikacolor/pikacolor.h"
#include "libpikamath/pikamath.h"
#include "libpikabase/pikabase.h"
#include "pikawidgets.h"
/**
* SECTION: pikalabelspin
* @title: PikaLabelSpin
* @short_description: Widget containing a spin button and a label.
*
* This widget is a subclass of #PikaLabeled with a #PikaSpinButton.
**/
enum
{
VALUE_CHANGED,
LAST_SIGNAL
};
enum
{
PROP_0,
PROP_VALUE,
PROP_LOWER,
PROP_UPPER,
PROP_DIGITS,
};
typedef struct _PikaLabelSpinPrivate
{
PikaLabeled parent_instance;
GtkWidget *spinbutton;
GtkAdjustment *spin_adjustment;
gint digits;
} PikaLabelSpinPrivate;
static void pika_label_spin_constructed (GObject *object);
static void pika_label_spin_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec);
static void pika_label_spin_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec);
static GtkWidget * pika_label_spin_populate (PikaLabeled *spin,
gint *x,
gint *y,
gint *width,
gint *height);
static void pika_label_spin_update_spin_width (PikaLabelSpin *spin,
gdouble lower,
gdouble upper,
guint digits);
static void pika_label_spin_update_settings (PikaLabelSpin *spin);
G_DEFINE_TYPE_WITH_PRIVATE (PikaLabelSpin, pika_label_spin, PIKA_TYPE_LABELED)
#define parent_class pika_label_spin_parent_class
static guint pika_label_spin_signals[LAST_SIGNAL] = { 0 };
static void
pika_label_spin_class_init (PikaLabelSpinClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
PikaLabeledClass *labeled_class = PIKA_LABELED_CLASS (klass);
pika_label_spin_signals[VALUE_CHANGED] =
g_signal_new ("value-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaLabelSpinClass, value_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
object_class->constructed = pika_label_spin_constructed;
object_class->set_property = pika_label_spin_set_property;
object_class->get_property = pika_label_spin_get_property;
labeled_class->populate = pika_label_spin_populate;
/**
* PikaLabelSpin:value:
*
* The currently set value.
*
* Since: 3.0
**/
g_object_class_install_property (object_class, PROP_VALUE,
g_param_spec_double ("value", NULL,
"Current value",
-G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
PIKA_PARAM_READWRITE));
/**
* PikaLabelSpin:lower:
*
* The lower bound of the spin button.
*
* Since: 3.0
**/
g_object_class_install_property (object_class, PROP_LOWER,
g_param_spec_double ("lower", NULL,
"Minimum value",
-G_MAXDOUBLE, G_MAXDOUBLE, 1.0,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
/**
* PikaLabelSpin:upper:
*
* The upper bound of the spin button.
*
* Since: 3.0
**/
g_object_class_install_property (object_class, PROP_UPPER,
g_param_spec_double ("upper", NULL,
"Max value",
-G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
PIKA_PARAM_READWRITE |
G_PARAM_CONSTRUCT));
/**
* PikaLabelSpin:digits:
*
* The number of decimal places to display. If -1, then the number is
* estimated.
*
* Since: 3.0
**/
g_object_class_install_property (object_class, PROP_DIGITS,
g_param_spec_int ("digits", NULL,
"The number of decimal places to display",
-1, G_MAXINT, -1,
PIKA_PARAM_READWRITE));
}
static void
pika_label_spin_init (PikaLabelSpin *spin)
{
PikaLabelSpinPrivate *priv = pika_label_spin_get_instance_private (spin);
/* We want the adjustment to exist at init so that construction
* properties can apply (default values are bogus but should be
* properly overridden with expected values if the object was created
* with pika_label_spin_new().
*/
priv->spin_adjustment = gtk_adjustment_new (0.0, 0.0, 100.0, 1.0, 10.0, 0.0);
gtk_grid_set_row_spacing (GTK_GRID (spin), 6);
gtk_grid_set_column_spacing (GTK_GRID (spin), 6);
}
static void
pika_label_spin_constructed (GObject *object)
{
PikaLabelSpin *spin = PIKA_LABEL_SPIN (object);
PikaLabelSpinPrivate *priv = pika_label_spin_get_instance_private (spin);
G_OBJECT_CLASS (parent_class)->constructed (object);
/* This is important to make this object into a property widget. It
* will allow config object to bind the "value" property of this
* widget, and therefore be updated automatically.
*/
g_object_bind_property (G_OBJECT (priv->spin_adjustment), "value",
G_OBJECT (spin), "value",
G_BINDING_BIDIRECTIONAL |
G_BINDING_SYNC_CREATE);
pika_label_spin_update_settings (spin);
}
static void
pika_label_spin_set_property (GObject *object,
guint property_id,
const GValue *value,
GParamSpec *pspec)
{
PikaLabelSpin *spin = PIKA_LABEL_SPIN (object);
PikaLabelSpinPrivate *priv = pika_label_spin_get_instance_private (spin);
switch (property_id)
{
case PROP_VALUE:
/* Avoid looping forever since we have bound this widget's
* "value" property with the spin button "value" property.
*/
if (gtk_adjustment_get_value (priv->spin_adjustment) != g_value_get_double (value))
gtk_adjustment_set_value (priv->spin_adjustment, g_value_get_double (value));
g_signal_emit (object, pika_label_spin_signals[VALUE_CHANGED], 0);
break;
case PROP_LOWER:
gtk_adjustment_set_lower (priv->spin_adjustment,
g_value_get_double (value));
if (priv->spinbutton)
{
pika_label_spin_update_settings (spin);
}
break;
case PROP_UPPER:
gtk_adjustment_set_upper (priv->spin_adjustment,
g_value_get_double (value));
if (priv->spinbutton)
{
pika_label_spin_update_settings (spin);
}
break;
case PROP_DIGITS:
if (priv->spinbutton)
{
priv->digits = g_value_get_int (value);
pika_label_spin_update_settings (spin);
}
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static void
pika_label_spin_get_property (GObject *object,
guint property_id,
GValue *value,
GParamSpec *pspec)
{
PikaLabelSpin *spin = PIKA_LABEL_SPIN (object);
PikaLabelSpinPrivate *priv = pika_label_spin_get_instance_private (spin);
GtkSpinButton *spinbutton = GTK_SPIN_BUTTON (priv->spinbutton);
switch (property_id)
{
case PROP_VALUE:
g_value_set_double (value, gtk_adjustment_get_value (priv->spin_adjustment));
break;
case PROP_LOWER:
g_value_set_double (value, gtk_adjustment_get_lower (priv->spin_adjustment));
break;
case PROP_UPPER:
g_value_set_double (value, gtk_adjustment_get_upper (priv->spin_adjustment));
break;
case PROP_DIGITS:
g_value_set_uint (value, gtk_spin_button_get_digits (spinbutton));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
break;
}
}
static GtkWidget *
pika_label_spin_populate (PikaLabeled *labeled,
gint *x,
gint *y,
gint *width,
gint *height)
{
PikaLabelSpin *spin = PIKA_LABEL_SPIN (labeled);
PikaLabelSpinPrivate *priv = pika_label_spin_get_instance_private (spin);
priv->spinbutton = pika_spin_button_new (priv->spin_adjustment, 2.0, 2.0);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (priv->spinbutton), TRUE);
gtk_grid_attach (GTK_GRID (spin), priv->spinbutton, 1, 0, 1, 1);
gtk_widget_show (priv->spinbutton);
return priv->spinbutton;
}
static void
pika_label_spin_update_spin_width (PikaLabelSpin *spin,
gdouble lower,
gdouble upper,
guint digits)
{
PikaLabelSpinPrivate *priv = pika_label_spin_get_instance_private (spin);
gint width = 0;
g_return_if_fail (PIKA_IS_LABEL_SPIN (spin));
/* Necessary size to display the max/min integer values, with optional
* negative sign.
*/
width = (gint) floor (log10 (upper) + 1) + (upper < 0.0 ? 1 : 0);
width = MAX (width, (gint) floor (log10 (lower) + 1) + (lower < 0.0 ? 1 : 0));
/* Adding decimal digits and separator. */
width += (digits > 0 ? 1 + digits : 0);
/* Overlong spin button are useless. */
width = MIN (10, width);
gtk_entry_set_width_chars (GTK_ENTRY (priv->spinbutton), width);
}
static void
pika_label_spin_update_settings (PikaLabelSpin *spin)
{
PikaLabelSpinPrivate *priv = pika_label_spin_get_instance_private (spin);
gdouble lower;
gdouble upper;
gdouble step;
gdouble page;
gint digits = priv->digits;
g_return_if_fail (PIKA_IS_LABEL_SPIN (spin));
g_object_get (spin,
"lower", &lower,
"upper", &upper,
NULL);
g_return_if_fail (upper >= lower);
pika_range_estimate_settings (lower, upper, &step, &page,
digits < 0 ? &digits: NULL);
pika_label_spin_set_increments (spin, step, page);
gtk_spin_button_set_digits (GTK_SPIN_BUTTON (priv->spinbutton), (guint) digits);
pika_label_spin_update_spin_width (spin, lower, upper, (guint) digits);
}
/* Public Functions */
/**
* pika_label_spin_new:
* @text: The text for the #GtkLabel.
* @value: The initial value.
* @lower: The lower boundary.
* @upper: The upper boundary.
* @digits: The number of decimal digits.
*
* Suitable increment values are estimated based on the [@lower, @upper]
* range.
* If @digits is -1, then it will also be estimated based on the same
* range. Digits estimation will always be at least 1, so if you want to
* show integer values only, set 0 explicitly.
*
* Returns: (transfer full): The new #PikaLabelSpin widget.
**/
GtkWidget *
pika_label_spin_new (const gchar *text,
gdouble value,
gdouble lower,
gdouble upper,
gint digits)
{
GtkWidget *labeled;
g_return_val_if_fail (upper >= lower, NULL);
g_return_val_if_fail (digits >= -1, NULL);
labeled = g_object_new (PIKA_TYPE_LABEL_SPIN,
"label", text,
"value", value,
"lower", lower,
"upper", upper,
"digits", digits,
NULL);
return labeled;
}
/**
* pika_label_spin_set_value:
* @spin: The #GtkLabelSpin.
* @value: A new value.
*
* This function sets the value shown by @spin.
**/
void
pika_label_spin_set_value (PikaLabelSpin *spin,
gdouble value)
{
g_return_if_fail (PIKA_IS_LABEL_SPIN (spin));
g_object_set (spin,
"value", value,
NULL);
}
/**
* pika_label_spin_get_value:
* @spin: The #GtkLabelSpin.
*
* This function returns the value shown by @spin.
*
* Returns: The value currently set.
**/
gdouble
pika_label_spin_get_value (PikaLabelSpin *spin)
{
gdouble value;
g_return_val_if_fail (PIKA_IS_LABEL_SPIN (spin), 0.0);
g_object_get (spin,
"value", &value,
NULL);
return value;
}
/**
* pika_label_spin_set_increments:
* @spin: the #PikaLabelSpin.
* @step: the step increment.
* @page: the page increment.
*
* Set the step and page increments of the spin button.
* By default, these increment values are automatically computed
* depending on the range based on common usage. So you will likely not
* need to run this for most case. Yet if you want specific increments
* (which the widget cannot guess), you can call this function.
*/
void
pika_label_spin_set_increments (PikaLabelSpin *spin,
gdouble step,
gdouble page)
{
PikaLabelSpinPrivate *priv = pika_label_spin_get_instance_private (spin);
GtkSpinButton *spinbutton;
gdouble lower;
gdouble upper;
g_return_if_fail (PIKA_IS_LABEL_SPIN (spin));
g_return_if_fail (step < page);
spinbutton = GTK_SPIN_BUTTON (priv->spinbutton);
gtk_spin_button_get_range (spinbutton, &lower, &upper);
g_return_if_fail (upper >= lower);
g_return_if_fail (step < upper - lower && page < upper - lower);
g_object_freeze_notify (G_OBJECT (spinbutton));
gtk_adjustment_set_step_increment (gtk_spin_button_get_adjustment (spinbutton), step);
gtk_adjustment_set_page_increment (gtk_spin_button_get_adjustment (spinbutton), page);
g_object_thaw_notify (G_OBJECT (spinbutton));
g_object_set (priv->spinbutton,
"climb-rate", step,
NULL);
}
/**
* pika_label_spin_set_digits:
* @spin: the #PikaLabelSpin.
* @digits: the number of decimal places to display.
*
* Set the number of decimal place to display in the @spin's entry.
* If @digits is -1, then it will also be estimated based on @spin's
* range. Digits estimation will always be at least 1, so if you want to
* show integer values only, set 0 explicitly.
*/
void
pika_label_spin_set_digits (PikaLabelSpin *spin,
gint digits)
{
g_return_if_fail (PIKA_IS_LABEL_SPIN (spin));
g_object_set (spin,
"digits", digits,
NULL);
}
/**
* pika_label_spin_get_spin_button:
* @spin: The #PikaLabelSpin
*
* This function returns the #PikaSpinButton packed in @spin.
*
* Returns: (transfer none): The #PikaSpinButton contained in @spin.
**/
GtkWidget *
pika_label_spin_get_spin_button (PikaLabelSpin *spin)
{
PikaLabelSpinPrivate *priv = pika_label_spin_get_instance_private (spin);
g_return_val_if_fail (PIKA_IS_LABEL_SPIN (spin), NULL);
return priv->spinbutton;
}

View File

@ -0,0 +1,74 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikacolorscaleentry.h
* Copyright (C) 2020 Jehan
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_LABEL_SPIN_H__
#define __PIKA_LABEL_SPIN_H__
#include <libpikawidgets/pikalabeled.h>
G_BEGIN_DECLS
#define PIKA_TYPE_LABEL_SPIN (pika_label_spin_get_type ())
G_DECLARE_DERIVABLE_TYPE (PikaLabelSpin, pika_label_spin, PIKA, LABEL_SPIN, PikaLabeled)
struct _PikaLabelSpinClass
{
PikaLabeledClass parent_class;
/* Signals */
void (* value_changed) (PikaLabelSpin *spin);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GtkWidget * pika_label_spin_new (const gchar *text,
gdouble value,
gdouble lower,
gdouble upper,
gint digits);
void pika_label_spin_set_value (PikaLabelSpin *spin,
gdouble value);
gdouble pika_label_spin_get_value (PikaLabelSpin *spin);
void pika_label_spin_set_increments (PikaLabelSpin *spin,
gdouble step,
gdouble page);
void pika_label_spin_set_digits (PikaLabelSpin *spin,
gint digits);
GtkWidget * pika_label_spin_get_spin_button (PikaLabelSpin *spin);
G_END_DECLS
#endif /* __PIKA_LABEL_SPIN_H__ */

View File

@ -0,0 +1,336 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikamemsizeentry.c
* Copyright (C) 2000-2003 Sven Neumann <sven@gimp.org>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include "pikawidgetstypes.h"
#include "pikamemsizeentry.h"
#include "pikawidgets.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikamemsizeentry
* @title: PikaMemSizeEntry
* @short_description: A composite widget to enter a memory size.
*
* Similar to a #PikaSizeEntry but instead of lengths, this widget is
* used to let the user enter memory sizes. A combo box allows one to
* switch between Kilobytes, Megabytes and Gigabytes. Used in the PIKA
* preferences dialog.
**/
enum
{
VALUE_CHANGED,
LAST_SIGNAL
};
struct _PikaMemsizeEntryPrivate
{
guint64 value;
guint64 lower;
guint64 upper;
guint shift;
/* adjustment is owned by spinbutton. Do not unref() it. */
GtkAdjustment *adjustment;
GtkWidget *spinbutton;
GtkWidget *menu;
};
#define GET_PRIVATE(obj) (((PikaMemsizeEntry *) (obj))->priv)
static void pika_memsize_entry_adj_callback (GtkAdjustment *adj,
PikaMemsizeEntry *entry);
static void pika_memsize_entry_unit_callback (GtkWidget *widget,
PikaMemsizeEntry *entry);
static guint64 pika_memsize_entry_get_rounded_value (PikaMemsizeEntry *entry,
guint64 value);
G_DEFINE_TYPE_WITH_PRIVATE (PikaMemsizeEntry, pika_memsize_entry, GTK_TYPE_BOX)
#define parent_class pika_memsize_entry_parent_class
static guint pika_memsize_entry_signals[LAST_SIGNAL] = { 0 };
static void
pika_memsize_entry_class_init (PikaMemsizeEntryClass *klass)
{
klass->value_changed = NULL;
pika_memsize_entry_signals[VALUE_CHANGED] =
g_signal_new ("value-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaMemsizeEntryClass, value_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
}
static void
pika_memsize_entry_init (PikaMemsizeEntry *entry)
{
entry->priv = pika_memsize_entry_get_instance_private (entry);
gtk_orientable_set_orientation (GTK_ORIENTABLE (entry),
GTK_ORIENTATION_HORIZONTAL);
gtk_box_set_spacing (GTK_BOX (entry), 4);
}
static void
pika_memsize_entry_adj_callback (GtkAdjustment *adj,
PikaMemsizeEntry *entry)
{
PikaMemsizeEntryPrivate *private = GET_PRIVATE (entry);
guint64 size = gtk_adjustment_get_value (adj);
if (pika_memsize_entry_get_rounded_value (entry, private->value) != size)
/* Do not allow losing accuracy if the converted/displayed value
* stays the same.
*/
private->value = size << private->shift;
g_signal_emit (entry, pika_memsize_entry_signals[VALUE_CHANGED], 0);
}
static void
pika_memsize_entry_unit_callback (GtkWidget *widget,
PikaMemsizeEntry *entry)
{
PikaMemsizeEntryPrivate *private = GET_PRIVATE (entry);
guint shift;
pika_int_combo_box_get_active (PIKA_INT_COMBO_BOX (widget), (gint *) &shift);
#if _MSC_VER < 1300
# define CAST (gint64)
#else
# define CAST
#endif
if (shift != private->shift)
{
private->shift = shift;
gtk_adjustment_configure (private->adjustment,
pika_memsize_entry_get_rounded_value (entry, private->value),
CAST private->lower >> shift,
CAST private->upper >> shift,
gtk_adjustment_get_step_increment (private->adjustment),
gtk_adjustment_get_page_increment (private->adjustment),
gtk_adjustment_get_page_size (private->adjustment));
}
#undef CAST
}
/**
* pika_memsize_entry_get_rounded_value:
* @entry: #PikaMemsizeEntry whose set unit is used.
* @value: value to convert to @entry unit, and rounded.
*
* Returns: the proper integer value to be displayed for current unit.
* This value has been appropriately rounded to the nearest
* integer, away from zero.
*/
static guint64
pika_memsize_entry_get_rounded_value (PikaMemsizeEntry *entry,
guint64 value)
{
PikaMemsizeEntryPrivate *private = GET_PRIVATE (entry);
guint64 converted;
#if _MSC_VER < 1300
# define CAST (gint64)
#else
# define CAST
#endif
converted = (CAST value >> private->shift) +
((CAST private->value >> (private->shift - 1)) & 1);
#undef CAST
return converted;
}
/**
* pika_memsize_entry_new:
* @value: the initial value (in Bytes)
* @lower: the lower limit for the value (in Bytes)
* @upper: the upper limit for the value (in Bytes)
*
* Creates a new #PikaMemsizeEntry which is a #GtkHBox with a #GtkSpinButton
* and a #GtkOptionMenu all setup to allow the user to enter memory sizes.
*
* Returns: Pointer to the new #PikaMemsizeEntry.
**/
GtkWidget *
pika_memsize_entry_new (guint64 value,
guint64 lower,
guint64 upper)
{
PikaMemsizeEntry *entry;
PikaMemsizeEntryPrivate *private;
guint shift;
#if _MSC_VER < 1300
# define CAST (gint64)
#else
# define CAST
#endif
g_return_val_if_fail (value >= lower && value <= upper, NULL);
entry = g_object_new (PIKA_TYPE_MEMSIZE_ENTRY, NULL);
private = GET_PRIVATE (entry);
for (shift = 30; shift > 10; shift -= 10)
{
if (value > (G_GUINT64_CONSTANT (1) << shift) &&
value % (G_GUINT64_CONSTANT (1) << shift) == 0)
break;
}
private->value = value;
private->lower = lower;
private->upper = upper;
private->shift = shift;
private->adjustment = gtk_adjustment_new (pika_memsize_entry_get_rounded_value (entry,
private->value),
CAST (lower >> shift),
CAST (upper >> shift),
1, 8, 0);
private->spinbutton = pika_spin_button_new (private->adjustment, 1.0, 0);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (private->spinbutton), TRUE);
#undef CAST
gtk_entry_set_width_chars (GTK_ENTRY (private->spinbutton), 7);
gtk_box_pack_start (GTK_BOX (entry), private->spinbutton, FALSE, FALSE, 0);
gtk_widget_show (private->spinbutton);
g_signal_connect (private->adjustment, "value-changed",
G_CALLBACK (pika_memsize_entry_adj_callback),
entry);
private->menu = pika_int_combo_box_new (_("Kibibyte"), 10,
_("Mebibyte"), 20,
_("Gibibyte"), 30,
NULL);
pika_int_combo_box_set_active (PIKA_INT_COMBO_BOX (private->menu), shift);
g_signal_connect (private->menu, "changed",
G_CALLBACK (pika_memsize_entry_unit_callback),
entry);
gtk_box_pack_start (GTK_BOX (entry), private->menu, FALSE, FALSE, 0);
gtk_widget_show (private->menu);
return GTK_WIDGET (entry);
}
/**
* pika_memsize_entry_set_value:
* @entry: a #PikaMemsizeEntry
* @value: the new value (in Bytes)
*
* Sets the @entry's value. Please note that the #PikaMemsizeEntry rounds
* the value to full Kilobytes.
**/
void
pika_memsize_entry_set_value (PikaMemsizeEntry *entry,
guint64 value)
{
PikaMemsizeEntryPrivate *private;
guint shift;
g_return_if_fail (PIKA_IS_MEMSIZE_ENTRY (entry));
private = GET_PRIVATE (entry);
g_return_if_fail (value >= private->lower && value <= private->upper);
for (shift = 30; shift > 10; shift -= 10)
{
if (value > (G_GUINT64_CONSTANT (1) << shift) &&
value % (G_GUINT64_CONSTANT (1) << shift) == 0)
break;
}
if (shift != private->shift)
pika_int_combo_box_set_active (PIKA_INT_COMBO_BOX (private->menu), shift);
gtk_adjustment_set_value (private->adjustment,
(gdouble) pika_memsize_entry_get_rounded_value (entry, value));
#undef CASE
}
/**
* pika_memsize_entry_get_value:
* @entry: a #PikaMemsizeEntry
*
* Retrieves the current value from a #PikaMemsizeEntry.
*
* Returns: the current value of @entry (in Bytes).
**/
guint64
pika_memsize_entry_get_value (PikaMemsizeEntry *entry)
{
g_return_val_if_fail (PIKA_IS_MEMSIZE_ENTRY (entry), 0);
return GET_PRIVATE (entry)->value;
}
/**
* pika_memsize_entry_get_spinbutton:
* @entry: a #PikaMemsizeEntry
*
* Returns: (transfer none) (type GtkSpinButton): the entry's #GtkSpinbutton.
*
* Since: 3.0
**/
GtkWidget *
pika_memsize_entry_get_spinbutton (PikaMemsizeEntry *entry)
{
g_return_val_if_fail (PIKA_IS_MEMSIZE_ENTRY (entry), 0);
return GET_PRIVATE (entry)->spinbutton;
}

View File

@ -0,0 +1,82 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikamemsizeentry.h
* Copyright (C) 2000-2003 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_MEMSIZE_ENTRY_H__
#define __PIKA_MEMSIZE_ENTRY_H__
G_BEGIN_DECLS
#define PIKA_TYPE_MEMSIZE_ENTRY (pika_memsize_entry_get_type ())
#define PIKA_MEMSIZE_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_MEMSIZE_ENTRY, PikaMemsizeEntry))
#define PIKA_MEMSIZE_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_MEMSIZE_ENTRY, PikaMemsizeEntryClass))
#define PIKA_IS_MEMSIZE_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_MEMSIZE_ENTRY))
#define PIKA_IS_MEMSIZE_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_MEMSIZE_ENTRY))
#define PIKA_MEMSIZE_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_MEMSIZE_ENTRY, PikaMemsizeEntryClass))
typedef struct _PikaMemsizeEntryPrivate PikaMemsizeEntryPrivate;
typedef struct _PikaMemsizeEntryClass PikaMemsizeEntryClass;
struct _PikaMemsizeEntry
{
GtkBox parent_instance;
PikaMemsizeEntryPrivate *priv;
};
struct _PikaMemsizeEntryClass
{
GtkBoxClass parent_class;
void (* value_changed) (PikaMemsizeEntry *entry);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_memsize_entry_get_type (void) G_GNUC_CONST;
GtkWidget * pika_memsize_entry_new (guint64 value,
guint64 lower,
guint64 upper);
void pika_memsize_entry_set_value (PikaMemsizeEntry *entry,
guint64 value);
guint64 pika_memsize_entry_get_value (PikaMemsizeEntry *entry);
GtkWidget * pika_memsize_entry_get_spinbutton (PikaMemsizeEntry *entry);
G_END_DECLS
#endif /* __PIKA_MEMSIZE_ENTRY_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,109 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaratioentry.h
* Copyright (C) 2006 Simon Budig <simon@gimp.org>
* Copyright (C) 2007 Sven Neumann <sven@gimp.org>
* Copyright (C) 2007 Martin Nordholts <martin@svn.gnome.org>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_NUMBER_PAIR_ENTRY_H__
#define __PIKA_NUMBER_PAIR_ENTRY_H__
G_BEGIN_DECLS
#define PIKA_TYPE_NUMBER_PAIR_ENTRY (pika_number_pair_entry_get_type ())
#define PIKA_NUMBER_PAIR_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_NUMBER_PAIR_ENTRY, PikaNumberPairEntry))
#define PIKA_NUMBER_PAIR_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_NUMBER_PAIR_ENTRY, PikaNumberPairEntryClass))
#define PIKA_IS_NUMBER_PAIR_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_NUMBER_PAIR_ENTRY))
#define PIKA_IS_NUMBER_PAIR_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_NUMBER_PAIR_ENTRY))
#define PIKA_NUMBER_PAIR_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_NUMBER_PAIR_AREA, PikaNumberPairEntryClass))
typedef struct _PikaNumberPairEntryPrivate PikaNumberPairEntryPrivate;
typedef struct _PikaNumberPairEntryClass PikaNumberPairEntryClass;
struct _PikaNumberPairEntry
{
GtkEntry parent_instance;
PikaNumberPairEntryPrivate *priv;
};
struct _PikaNumberPairEntryClass
{
GtkEntryClass parent_class;
void (* numbers_changed) (PikaNumberPairEntry *entry);
void (* ratio_changed) (PikaNumberPairEntry *entry);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_number_pair_entry_get_type (void) G_GNUC_CONST;
GtkWidget * pika_number_pair_entry_new (const gchar *separators,
gboolean allow_simplification,
gdouble min_valid_value,
gdouble max_valid_value);
void pika_number_pair_entry_set_default_values (PikaNumberPairEntry *entry,
gdouble left,
gdouble right);
void pika_number_pair_entry_get_default_values (PikaNumberPairEntry *entry,
gdouble *left,
gdouble *right);
void pika_number_pair_entry_set_values (PikaNumberPairEntry *entry,
gdouble left,
gdouble right);
void pika_number_pair_entry_get_values (PikaNumberPairEntry *entry,
gdouble *left,
gdouble *right);
void pika_number_pair_entry_set_default_text (PikaNumberPairEntry *entry,
const gchar *string);
const gchar * pika_number_pair_entry_get_default_text (PikaNumberPairEntry *entry);
void pika_number_pair_entry_set_ratio (PikaNumberPairEntry *entry,
gdouble ratio);
gdouble pika_number_pair_entry_get_ratio (PikaNumberPairEntry *entry);
void pika_number_pair_entry_set_aspect (PikaNumberPairEntry *entry,
PikaAspectType aspect);
PikaAspectType pika_number_pair_entry_get_aspect (PikaNumberPairEntry *entry);
void pika_number_pair_entry_set_user_override (PikaNumberPairEntry *entry,
gboolean user_override);
gboolean pika_number_pair_entry_get_user_override (PikaNumberPairEntry *entry);
G_END_DECLS
#endif /* __PIKA_NUMBER_PAIR_ENTRY_H__ */

View File

@ -0,0 +1,535 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaoffsetarea.c
* Copyright (C) 2001 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gtk/gtk.h>
#include "pikawidgetstypes.h"
#include "pikawidgetsmarshal.h"
#include "pikaoffsetarea.h"
/**
* SECTION: pikaoffsetarea
* @title: PikaOffsetArea
* @short_description: Widget to control image offsets.
*
* Widget to control image offsets.
**/
#define DRAWING_AREA_SIZE 200
enum
{
OFFSETS_CHANGED,
LAST_SIGNAL
};
struct _PikaOffsetAreaPrivate
{
gint orig_width;
gint orig_height;
gint width;
gint height;
gint offset_x;
gint offset_y;
gdouble display_ratio_x;
gdouble display_ratio_y;
};
#define GET_PRIVATE(obj) (((PikaOffsetArea *) (obj))->priv)
static void pika_offset_area_resize (PikaOffsetArea *area);
static void pika_offset_area_realize (GtkWidget *widget);
static void pika_offset_area_size_allocate (GtkWidget *widget,
GtkAllocation *allocation);
static gboolean pika_offset_area_event (GtkWidget *widget,
GdkEvent *event);
static gboolean pika_offset_area_draw (GtkWidget *widget,
cairo_t *cr);
G_DEFINE_TYPE_WITH_PRIVATE (PikaOffsetArea, pika_offset_area,
GTK_TYPE_DRAWING_AREA)
#define parent_class pika_offset_area_parent_class
static guint pika_offset_area_signals[LAST_SIGNAL] = { 0 };
static void
pika_offset_area_class_init (PikaOffsetAreaClass *klass)
{
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
pika_offset_area_signals[OFFSETS_CHANGED] =
g_signal_new ("offsets-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaOffsetAreaClass, offsets_changed),
NULL, NULL,
_pika_widgets_marshal_VOID__INT_INT,
G_TYPE_NONE, 2,
G_TYPE_INT,
G_TYPE_INT);
widget_class->size_allocate = pika_offset_area_size_allocate;
widget_class->realize = pika_offset_area_realize;
widget_class->event = pika_offset_area_event;
widget_class->draw = pika_offset_area_draw;
}
static void
pika_offset_area_init (PikaOffsetArea *area)
{
PikaOffsetAreaPrivate *private;
area->priv = pika_offset_area_get_instance_private (area);
private = GET_PRIVATE (area);
private->display_ratio_x = 1.0;
private->display_ratio_y = 1.0;
gtk_widget_add_events (GTK_WIDGET (area),
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_BUTTON1_MOTION_MASK);
}
/**
* pika_offset_area_new:
* @orig_width: the original width
* @orig_height: the original height
*
* Creates a new #PikaOffsetArea widget. A #PikaOffsetArea can be used
* when resizing an image or a drawable to allow the user to interactively
* specify the new offsets.
*
* Returns: the new #PikaOffsetArea widget.
**/
GtkWidget *
pika_offset_area_new (gint orig_width,
gint orig_height)
{
PikaOffsetArea *area;
PikaOffsetAreaPrivate *private;
g_return_val_if_fail (orig_width > 0, NULL);
g_return_val_if_fail (orig_height > 0, NULL);
area = g_object_new (PIKA_TYPE_OFFSET_AREA, NULL);
private = GET_PRIVATE (area);
private->orig_width = private->width = orig_width;
private->orig_height = private->height = orig_height;
pika_offset_area_resize (area);
return GTK_WIDGET (area);
}
/**
* pika_offset_area_set_pixbuf:
* @offset_area: a #PikaOffsetArea.
* @pixbuf: a #GdkPixbuf.
*
* Sets the pixbuf which represents the original image/drawable which
* is being offset.
*
* Since: 2.2
**/
void
pika_offset_area_set_pixbuf (PikaOffsetArea *area,
GdkPixbuf *pixbuf)
{
g_return_if_fail (PIKA_IS_OFFSET_AREA (area));
g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
g_object_set_data_full (G_OBJECT (area), "pixbuf",
gdk_pixbuf_copy (pixbuf),
(GDestroyNotify) g_object_unref);
gtk_widget_queue_draw (GTK_WIDGET (area));
}
/**
* pika_offset_area_set_size:
* @offset_area: a #PikaOffsetArea.
* @width: the new width
* @height: the new height
*
* Sets the size of the image/drawable displayed by the #PikaOffsetArea.
* If the offsets change as a result of this change, the "offsets-changed"
* signal is emitted.
**/
void
pika_offset_area_set_size (PikaOffsetArea *area,
gint width,
gint height)
{
PikaOffsetAreaPrivate *private;
g_return_if_fail (PIKA_IS_OFFSET_AREA (area));
g_return_if_fail (width > 0 && height > 0);
private = GET_PRIVATE (area);
if (private->width != width || private->height != height)
{
gint offset_x;
gint offset_y;
private->width = width;
private->height = height;
if (private->orig_width <= private->width)
offset_x = CLAMP (private->offset_x,
0, private->width - private->orig_width);
else
offset_x = CLAMP (private->offset_x,
private->width - private->orig_width, 0);
if (private->orig_height <= private->height)
offset_y = CLAMP (private->offset_y,
0, private->height - private->orig_height);
else
offset_y = CLAMP (private->offset_y,
private->height - private->orig_height, 0);
if (offset_x != private->offset_x || offset_y != private->offset_y)
{
private->offset_x = offset_x;
private->offset_y = offset_y;
g_signal_emit (area,
pika_offset_area_signals[OFFSETS_CHANGED], 0,
offset_x, offset_y);
}
pika_offset_area_resize (area);
}
}
/**
* pika_offset_area_set_offsets:
* @offset_area: a #PikaOffsetArea.
* @offset_x: the X offset
* @offset_y: the Y offset
*
* Sets the offsets of the image/drawable displayed by the #PikaOffsetArea.
* It does not emit the "offsets-changed" signal.
**/
void
pika_offset_area_set_offsets (PikaOffsetArea *area,
gint offset_x,
gint offset_y)
{
PikaOffsetAreaPrivate *private;
g_return_if_fail (PIKA_IS_OFFSET_AREA (area));
private = GET_PRIVATE (area);
if (private->offset_x != offset_x || private->offset_y != offset_y)
{
if (private->orig_width <= private->width)
private->offset_x = CLAMP (offset_x,
0, private->width - private->orig_width);
else
private->offset_x = CLAMP (offset_x,
private->width - private->orig_width, 0);
if (private->orig_height <= private->height)
private->offset_y = CLAMP (offset_y,
0, private->height - private->orig_height);
else
private->offset_y = CLAMP (offset_y,
private->height - private->orig_height, 0);
gtk_widget_queue_draw (GTK_WIDGET (area));
}
}
static void
pika_offset_area_resize (PikaOffsetArea *area)
{
PikaOffsetAreaPrivate *private = GET_PRIVATE (area);
gint width;
gint height;
gdouble ratio;
if (private->orig_width == 0 || private->orig_height == 0)
return;
if (private->orig_width <= private->width)
width = private->width;
else
width = private->orig_width * 2 - private->width;
if (private->orig_height <= private->height)
height = private->height;
else
height = private->orig_height * 2 - private->height;
ratio = (gdouble) DRAWING_AREA_SIZE / (gdouble) MAX (width, height);
width = ratio * (gdouble) width;
height = ratio * (gdouble) height;
gtk_widget_set_size_request (GTK_WIDGET (area), width, height);
gtk_widget_queue_resize (GTK_WIDGET (area));
}
static void
pika_offset_area_size_allocate (GtkWidget *widget,
GtkAllocation *allocation)
{
PikaOffsetArea *area = PIKA_OFFSET_AREA (widget);
PikaOffsetAreaPrivate *private = GET_PRIVATE (area);
GdkPixbuf *pixbuf;
GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
private->display_ratio_x = ((gdouble) allocation->width /
((private->orig_width <= private->width) ?
private->width :
private->orig_width * 2 - private->width));
private->display_ratio_y = ((gdouble) allocation->height /
((private->orig_height <= private->height) ?
private->height :
private->orig_height * 2 - private->height));
pixbuf = g_object_get_data (G_OBJECT (area), "pixbuf");
if (pixbuf)
{
GdkPixbuf *copy;
gint pixbuf_width;
gint pixbuf_height;
pixbuf_width = private->display_ratio_x * private->orig_width;
pixbuf_width = MAX (pixbuf_width, 1);
pixbuf_height = private->display_ratio_y * private->orig_height;
pixbuf_height = MAX (pixbuf_height, 1);
copy = g_object_get_data (G_OBJECT (area), "pixbuf-copy");
if (copy &&
(pixbuf_width != gdk_pixbuf_get_width (copy) ||
pixbuf_height != gdk_pixbuf_get_height (copy)))
{
copy = NULL;
}
if (! copy)
{
copy = gdk_pixbuf_scale_simple (pixbuf, pixbuf_width, pixbuf_height,
GDK_INTERP_NEAREST);
g_object_set_data_full (G_OBJECT (area), "pixbuf-copy",
copy, (GDestroyNotify) g_object_unref);
}
}
}
static void
pika_offset_area_realize (GtkWidget *widget)
{
GdkCursor *cursor;
GTK_WIDGET_CLASS (parent_class)->realize (widget);
cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
GDK_FLEUR);
gdk_window_set_cursor (gtk_widget_get_window (widget), cursor);
g_object_unref (cursor);
}
static gboolean
pika_offset_area_event (GtkWidget *widget,
GdkEvent *event)
{
static gint orig_offset_x = 0;
static gint orig_offset_y = 0;
static gint start_x = 0;
static gint start_y = 0;
PikaOffsetArea *area = PIKA_OFFSET_AREA (widget);
PikaOffsetAreaPrivate *private = GET_PRIVATE (area);
gint offset_x;
gint offset_y;
if (private->orig_width == 0 || private->orig_height == 0)
return FALSE;
switch (event->type)
{
case GDK_BUTTON_PRESS:
if (event->button.button == 1)
{
gtk_grab_add (widget);
orig_offset_x = private->offset_x;
orig_offset_y = private->offset_y;
start_x = event->button.x;
start_y = event->button.y;
}
break;
case GDK_MOTION_NOTIFY:
offset_x = (orig_offset_x +
(event->motion.x - start_x) / private->display_ratio_x);
offset_y = (orig_offset_y +
(event->motion.y - start_y) / private->display_ratio_y);
if (private->offset_x != offset_x || private->offset_y != offset_y)
{
pika_offset_area_set_offsets (area, offset_x, offset_y);
g_signal_emit (area,
pika_offset_area_signals[OFFSETS_CHANGED], 0,
private->offset_x, private->offset_y);
}
break;
case GDK_BUTTON_RELEASE:
if (event->button.button == 1)
{
gtk_grab_remove (widget);
start_x = start_y = 0;
}
break;
default:
return FALSE;
}
return TRUE;
}
static gboolean
pika_offset_area_draw (GtkWidget *widget,
cairo_t *cr)
{
PikaOffsetArea *area = PIKA_OFFSET_AREA (widget);
PikaOffsetAreaPrivate *private = GET_PRIVATE (area);
GtkStyleContext *context = gtk_widget_get_style_context (widget);
GtkAllocation allocation;
GdkPixbuf *pixbuf;
gint w, h;
gint x, y;
gtk_widget_get_allocation (widget, &allocation);
x = (private->display_ratio_x *
((private->orig_width <= private->width) ?
private->offset_x :
private->offset_x + private->orig_width - private->width));
y = (private->display_ratio_y *
((private->orig_height <= private->height) ?
private->offset_y :
private->offset_y + private->orig_height - private->height));
w = private->display_ratio_x * private->orig_width;
w = MAX (w, 1);
h = private->display_ratio_y * private->orig_height;
h = MAX (h, 1);
pixbuf = g_object_get_data (G_OBJECT (widget), "pixbuf-copy");
if (pixbuf)
{
gdk_cairo_set_source_pixbuf (cr, pixbuf, x, y);
cairo_paint (cr);
cairo_rectangle (cr, x + 0.5, y + 0.5, w - 1, h - 1);
cairo_set_line_width (cr, 1.0);
cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
cairo_stroke (cr);
}
else
{
gtk_render_frame (context, cr, x, y, w, h);
}
if (private->orig_width > private->width ||
private->orig_height > private->height)
{
gint line_width;
if (private->orig_width > private->width)
{
x = private->display_ratio_x * (private->orig_width - private->width);
w = private->display_ratio_x * private->width;
}
else
{
x = -1;
w = allocation.width + 2;
}
if (private->orig_height > private->height)
{
y = private->display_ratio_y * (private->orig_height - private->height);
h = private->display_ratio_y * private->height;
}
else
{
y = -1;
h = allocation.height + 2;
}
w = MAX (w, 1);
h = MAX (h, 1);
line_width = MIN (3, MIN (w, h));
cairo_rectangle (cr,
x + line_width / 2.0,
y + line_width / 2.0,
MAX (w - line_width, 1),
MAX (h - line_width, 1));
cairo_set_line_width (cr, line_width);
cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.6);
cairo_stroke_preserve (cr);
cairo_set_line_width (cr, 1.0);
cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.8);
cairo_stroke (cr);
}
return FALSE;
}

View File

@ -0,0 +1,89 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikaoffsetarea.h
* Copyright (C) 2001 Sven Neumann <sven@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_OFFSET_AREA_H__
#define __PIKA_OFFSET_AREA_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
#define PIKA_TYPE_OFFSET_AREA (pika_offset_area_get_type ())
#define PIKA_OFFSET_AREA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_OFFSET_AREA, PikaOffsetArea))
#define PIKA_OFFSET_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_OFFSET_AREA, PikaOffsetAreaClass))
#define PIKA_IS_OFFSET_AREA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_OFFSET_AREA))
#define PIKA_IS_OFFSET_AREA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_OFFSET_AREA))
#define PIKA_OFFSET_AREA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_OFFSET_AREA, PikaOffsetAreaClass))
typedef struct _PikaOffsetAreaPrivate PikaOffsetAreaPrivate;
typedef struct _PikaOffsetAreaClass PikaOffsetAreaClass;
struct _PikaOffsetArea
{
GtkDrawingArea parent_instance;
PikaOffsetAreaPrivate *priv;
};
struct _PikaOffsetAreaClass
{
GtkDrawingAreaClass parent_class;
void (* offsets_changed) (PikaOffsetArea *offset_area,
gint offset_x,
gint offset_y);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_offset_area_get_type (void) G_GNUC_CONST;
GtkWidget * pika_offset_area_new (gint orig_width,
gint orig_height);
void pika_offset_area_set_pixbuf (PikaOffsetArea *offset_area,
GdkPixbuf *pixbuf);
void pika_offset_area_set_size (PikaOffsetArea *offset_area,
gint width,
gint height);
void pika_offset_area_set_offsets (PikaOffsetArea *offset_area,
gint offset_x,
gint offset_y);
G_END_DECLS
#endif /* __PIKA_OFFSET_AREA_H__ */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,110 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikapageselector.h
* Copyright (C) 2005 Michael Natterer <mitch@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_PAGE_SELECTOR_H__
#define __PIKA_PAGE_SELECTOR_H__
G_BEGIN_DECLS
#define PIKA_TYPE_PAGE_SELECTOR (pika_page_selector_get_type ())
#define PIKA_PAGE_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_PAGE_SELECTOR, PikaPageSelector))
#define PIKA_PAGE_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_PAGE_SELECTOR, PikaPageSelectorClass))
#define PIKA_IS_PAGE_SELECTOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), PIKA_TYPE_PAGE_SELECTOR))
#define PIKA_IS_PAGE_SELECTOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_PAGE_SELECTOR))
#define PIKA_PAGE_SELECTOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_PAGE_SELECTOR, PikaPageSelectorClass))
typedef struct _PikaPageSelectorPrivate PikaPageSelectorPrivate;
typedef struct _PikaPageSelectorClass PikaPageSelectorClass;
struct _PikaPageSelector
{
GtkBox parent_instance;
PikaPageSelectorPrivate *priv;
};
struct _PikaPageSelectorClass
{
GtkBoxClass parent_class;
void (* selection_changed) (PikaPageSelector *selector);
void (* activate) (PikaPageSelector *selector);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
GType pika_page_selector_get_type (void) G_GNUC_CONST;
GtkWidget * pika_page_selector_new (void);
void pika_page_selector_set_n_pages (PikaPageSelector *selector,
gint n_pages);
gint pika_page_selector_get_n_pages (PikaPageSelector *selector);
void pika_page_selector_set_target (PikaPageSelector *selector,
PikaPageSelectorTarget target);
PikaPageSelectorTarget
pika_page_selector_get_target (PikaPageSelector *selector);
void pika_page_selector_set_page_thumbnail (PikaPageSelector *selector,
gint page_no,
GdkPixbuf *thumbnail);
GdkPixbuf * pika_page_selector_get_page_thumbnail (PikaPageSelector *selector,
gint page_no);
void pika_page_selector_set_page_label (PikaPageSelector *selector,
gint page_no,
const gchar *label);
gchar * pika_page_selector_get_page_label (PikaPageSelector *selector,
gint page_no);
void pika_page_selector_select_all (PikaPageSelector *selector);
void pika_page_selector_unselect_all (PikaPageSelector *selector);
void pika_page_selector_select_page (PikaPageSelector *selector,
gint page_no);
void pika_page_selector_unselect_page (PikaPageSelector *selector,
gint page_no);
gboolean pika_page_selector_page_is_selected (PikaPageSelector *selector,
gint page_no);
gint * pika_page_selector_get_selected_pages (PikaPageSelector *selector,
gint *n_selected_pages);
void pika_page_selector_select_range (PikaPageSelector *selector,
const gchar *range);
gchar * pika_page_selector_get_selected_range (PikaPageSelector *selector);
G_END_DECLS
#endif /* __PIKA_PAGE_SELECTOR_H__ */

View File

@ -0,0 +1,873 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikapatheditor.c
* Copyright (C) 1999-2004 Michael Natterer <mitch@gimp.org>
*
* 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 3 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <string.h>
#include <gtk/gtk.h>
#include "libpikabase/pikabase.h"
#include "pikawidgetstypes.h"
#undef PIKA_DISABLE_DEPRECATED
#include "pikafileentry.h"
#include "pikahelpui.h"
#include "pikaicons.h"
#include "pikapatheditor.h"
#include "libpika/libpika-intl.h"
/**
* SECTION: pikapatheditor
* @title: PikaPathEditor
* @short_description: Widget for editing a file search path.
* @see_also: #PikaFileEntry, #G_SEARCHPATH_SEPARATOR
*
* This widget is used to edit file search paths.
*
* It shows a list of all directories which are in the search
* path. You can click a directory to select it. The widget provides a
* #PikaFileEntry to change the currently selected directory.
*
* There are buttons to add or delete directories as well as "up" and
* "down" buttons to change the order in which the directories will be
* searched.
*
* Whenever the user adds, deletes, changes or reorders a directory of
* the search path, the "path_changed" signal will be emitted.
**/
enum
{
PATH_CHANGED,
WRITABLE_CHANGED,
LAST_SIGNAL
};
enum
{
COLUMN_UTF8,
COLUMN_DIRECTORY,
COLUMN_WRITABLE,
NUM_COLUMNS
};
static void pika_path_editor_new_clicked (GtkWidget *widget,
PikaPathEditor *editor);
static void pika_path_editor_move_clicked (GtkWidget *widget,
PikaPathEditor *editor);
static void pika_path_editor_delete_clicked (GtkWidget *widget,
PikaPathEditor *editor);
static void pika_path_editor_file_entry_changed (GtkWidget *widget,
PikaPathEditor *editor);
static void pika_path_editor_selection_changed (GtkTreeSelection *sel,
PikaPathEditor *editor);
static void pika_path_editor_writable_toggled (GtkCellRendererToggle *toggle,
gchar *path_str,
PikaPathEditor *editor);
G_DEFINE_TYPE (PikaPathEditor, pika_path_editor, GTK_TYPE_BOX)
#define parent_class pika_path_editor_parent_class
static guint pika_path_editor_signals[LAST_SIGNAL] = { 0 };
static void
pika_path_editor_class_init (PikaPathEditorClass *klass)
{
/**
* PikaPathEditor::path-changed:
*
* This signal is emitted whenever the user adds, deletes, modifies
* or reorders an element of the search path.
**/
pika_path_editor_signals[PATH_CHANGED] =
g_signal_new ("path-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaPathEditorClass, path_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
/**
* PikaPathEditor::writable-changed:
*
* This signal is emitted whenever the "writable" column of a directory
* is changed, either by the user clicking on it or by calling
* pika_path_editor_set_dir_writable().
**/
pika_path_editor_signals[WRITABLE_CHANGED] =
g_signal_new ("writable-changed",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (PikaPathEditorClass, writable_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 0);
klass->path_changed = NULL;
klass->writable_changed = NULL;
}
static void
pika_path_editor_init (PikaPathEditor *editor)
{
GtkWidget *button_box;
GtkWidget *button;
GtkWidget *image;
GtkWidget *scrolled_window;
GtkWidget *tv;
GtkTreeViewColumn *col;
GtkCellRenderer *renderer;
editor->file_entry = NULL;
editor->sel_path = NULL;
editor->num_items = 0;
gtk_orientable_set_orientation (GTK_ORIENTABLE (editor),
GTK_ORIENTATION_VERTICAL);
editor->upper_hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
gtk_box_pack_start (GTK_BOX (editor), editor->upper_hbox, FALSE, TRUE, 0);
gtk_widget_show (editor->upper_hbox);
button_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_box_set_homogeneous (GTK_BOX (button_box), TRUE);
gtk_box_pack_start (GTK_BOX (editor->upper_hbox), button_box, FALSE, TRUE, 0);
gtk_widget_show (button_box);
editor->new_button = button = gtk_button_new ();
gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
gtk_widget_show (button);
image = gtk_image_new_from_icon_name (PIKA_ICON_DOCUMENT_NEW,
GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_widget_show (image);
g_signal_connect (button, "clicked",
G_CALLBACK (pika_path_editor_new_clicked),
editor);
pika_help_set_help_data (editor->new_button,
_("Add a new folder"),
NULL);
editor->up_button = button = gtk_button_new ();
gtk_widget_set_sensitive (button, FALSE);
gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
gtk_widget_show (button);
image = gtk_image_new_from_icon_name (PIKA_ICON_GO_UP,
GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_widget_show (image);
g_signal_connect (button, "clicked",
G_CALLBACK (pika_path_editor_move_clicked),
editor);
pika_help_set_help_data (editor->up_button,
_("Move the selected folder up"),
NULL);
editor->down_button = button = gtk_button_new ();
gtk_widget_set_sensitive (button, FALSE);
gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
gtk_widget_show (button);
image = gtk_image_new_from_icon_name (PIKA_ICON_GO_DOWN,
GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_widget_show (image);
g_signal_connect (button, "clicked",
G_CALLBACK (pika_path_editor_move_clicked),
editor);
pika_help_set_help_data (editor->down_button,
_("Move the selected folder down"),
NULL);
editor->delete_button = button = gtk_button_new ();
gtk_widget_set_sensitive (button, FALSE);
gtk_box_pack_start (GTK_BOX (button_box), button, TRUE, TRUE, 0);
gtk_widget_show (button);
image = gtk_image_new_from_icon_name (PIKA_ICON_EDIT_DELETE,
GTK_ICON_SIZE_BUTTON);
gtk_container_add (GTK_CONTAINER (button), image);
gtk_widget_show (image);
g_signal_connect (button, "clicked",
G_CALLBACK (pika_path_editor_delete_clicked),
editor);
pika_help_set_help_data (editor->delete_button,
_("Remove the selected folder from the list"),
NULL);
scrolled_window = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_SHADOW_IN);
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_ALWAYS);
gtk_box_pack_start (GTK_BOX (editor), scrolled_window, TRUE, TRUE, 2);
gtk_widget_show (scrolled_window);
editor->dir_list = gtk_list_store_new (NUM_COLUMNS,
G_TYPE_STRING,
G_TYPE_STRING,
G_TYPE_BOOLEAN);
tv = gtk_tree_view_new_with_model (GTK_TREE_MODEL (editor->dir_list));
g_object_unref (editor->dir_list);
renderer = gtk_cell_renderer_toggle_new ();
g_signal_connect (renderer, "toggled",
G_CALLBACK (pika_path_editor_writable_toggled),
editor);
editor->writable_column = col = gtk_tree_view_column_new ();
gtk_tree_view_column_set_title (col, _("Writable"));
gtk_tree_view_column_pack_start (col, renderer, FALSE);
gtk_tree_view_column_add_attribute (col, renderer, "active", COLUMN_WRITABLE);
gtk_tree_view_append_column (GTK_TREE_VIEW (tv), col);
gtk_tree_view_column_set_visible (col, FALSE);
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tv),
-1, _("Folder"),
gtk_cell_renderer_text_new (),
"text", COLUMN_UTF8,
NULL);
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tv), TRUE);
gtk_container_add (GTK_CONTAINER (scrolled_window), tv);
gtk_widget_show (tv);
editor->sel = gtk_tree_view_get_selection (GTK_TREE_VIEW (tv));
g_signal_connect (editor->sel, "changed",
G_CALLBACK (pika_path_editor_selection_changed),
editor);
}
/**
* pika_path_editor_new:
* @title: The title of the #GtkFileChooser dialog which can be popped up.
* @path: (nullable): The initial search path.
*
* Creates a new #PikaPathEditor widget.
*
* The elements of the initial search path must be separated with the
* #G_SEARCHPATH_SEPARATOR character.
*
* Returns: A pointer to the new #PikaPathEditor widget.
**/
GtkWidget *
pika_path_editor_new (const gchar *title,
const gchar *path)
{
PikaPathEditor *editor;
g_return_val_if_fail (title != NULL, NULL);
editor = g_object_new (PIKA_TYPE_PATH_EDITOR, NULL);
editor->file_entry = pika_file_entry_new (title, "", TRUE, TRUE);
gtk_widget_set_sensitive (editor->file_entry, FALSE);
gtk_box_pack_start (GTK_BOX (editor->upper_hbox), editor->file_entry,
TRUE, TRUE, 0);
gtk_widget_show (editor->file_entry);
g_signal_connect (editor->file_entry, "filename-changed",
G_CALLBACK (pika_path_editor_file_entry_changed),
editor);
if (path)
pika_path_editor_set_path (editor, path);
return GTK_WIDGET (editor);
}
/**
* pika_path_editor_get_path:
* @editor: The path editor you want to get the search path from.
*
* The elements of the returned search path string are separated with the
* #G_SEARCHPATH_SEPARATOR character.
*
* Note that you have to g_free() the returned string.
*
* Returns: The search path the user has selected in the path editor.
**/
gchar *
pika_path_editor_get_path (PikaPathEditor *editor)
{
GtkTreeModel *model;
GString *path;
GtkTreeIter iter;
gboolean iter_valid;
g_return_val_if_fail (PIKA_IS_PATH_EDITOR (editor), g_strdup (""));
model = GTK_TREE_MODEL (editor->dir_list);
path = g_string_new ("");
for (iter_valid = gtk_tree_model_get_iter_first (model, &iter);
iter_valid;
iter_valid = gtk_tree_model_iter_next (model, &iter))
{
gchar *dir;
gtk_tree_model_get (model, &iter,
COLUMN_DIRECTORY, &dir,
-1);
if (path->len > 0)
g_string_append_c (path, G_SEARCHPATH_SEPARATOR);
g_string_append (path, dir);
g_free (dir);
}
return g_string_free (path, FALSE);
}
/**
* pika_path_editor_set_path:
* @editor: The path editor you want to set the search path from.
* @path: The new path to set.
*
* The elements of the initial search path must be separated with the
* %G_SEARCHPATH_SEPARATOR character.
**/
void
pika_path_editor_set_path (PikaPathEditor *editor,
const gchar *path)
{
gchar *old_path;
GList *path_list;
GList *list;
g_return_if_fail (PIKA_IS_PATH_EDITOR (editor));
old_path = pika_path_editor_get_path (editor);
if (old_path && path && strcmp (old_path, path) == 0)
{
g_free (old_path);
return;
}
g_free (old_path);
path_list = pika_path_parse (path, 256, FALSE, NULL);
gtk_list_store_clear (editor->dir_list);
for (list = path_list; list; list = g_list_next (list))
{
gchar *directory = list->data;
gchar *utf8;
GtkTreeIter iter;
utf8 = g_filename_to_utf8 (directory, -1, NULL, NULL, NULL);
gtk_list_store_append (editor->dir_list, &iter);
gtk_list_store_set (editor->dir_list, &iter,
COLUMN_UTF8, utf8,
COLUMN_DIRECTORY, directory,
COLUMN_WRITABLE, FALSE,
-1);
g_free (utf8);
editor->num_items++;
}
pika_path_free (path_list);
g_signal_emit (editor, pika_path_editor_signals[PATH_CHANGED], 0);
}
gchar *
pika_path_editor_get_writable_path (PikaPathEditor *editor)
{
GtkTreeModel *model;
GString *path;
GtkTreeIter iter;
gboolean iter_valid;
g_return_val_if_fail (PIKA_IS_PATH_EDITOR (editor), g_strdup (""));
model = GTK_TREE_MODEL (editor->dir_list);
path = g_string_new ("");
for (iter_valid = gtk_tree_model_get_iter_first (model, &iter);
iter_valid;
iter_valid = gtk_tree_model_iter_next (model, &iter))
{
gchar *dir;
gboolean dir_writable;
gtk_tree_model_get (model, &iter,
COLUMN_DIRECTORY, &dir,
COLUMN_WRITABLE, &dir_writable,
-1);
if (dir_writable)
{
if (path->len > 0)
g_string_append_c (path, G_SEARCHPATH_SEPARATOR);
g_string_append (path, dir);
}
g_free (dir);
}
return g_string_free (path, FALSE);
}
void
pika_path_editor_set_writable_path (PikaPathEditor *editor,
const gchar *path)
{
GtkTreeModel *model;
GtkTreeIter iter;
gboolean iter_valid;
GList *path_list;
gboolean writable_changed = FALSE;
g_return_if_fail (PIKA_IS_PATH_EDITOR (editor));
gtk_tree_view_column_set_visible (editor->writable_column, TRUE);
path_list = pika_path_parse (path, 256, FALSE, NULL);
model = GTK_TREE_MODEL (editor->dir_list);
for (iter_valid = gtk_tree_model_get_iter_first (model, &iter);
iter_valid;
iter_valid = gtk_tree_model_iter_next (model, &iter))
{
gchar *dir;
gboolean dir_writable;
gboolean new_writable = FALSE;
gtk_tree_model_get (model, &iter,
COLUMN_DIRECTORY, &dir,
COLUMN_WRITABLE, &dir_writable,
-1);
if (g_list_find_custom (path_list, dir, (GCompareFunc) strcmp))
new_writable = TRUE;
g_free (dir);
if (dir_writable != new_writable)
{
gtk_list_store_set (editor->dir_list, &iter,
COLUMN_WRITABLE, new_writable,
-1);
writable_changed = TRUE;
}
}
pika_path_free (path_list);
if (writable_changed)
g_signal_emit (editor, pika_path_editor_signals[WRITABLE_CHANGED], 0);
}
gboolean
pika_path_editor_get_dir_writable (PikaPathEditor *editor,
const gchar *directory)
{
GtkTreeModel *model;
GtkTreeIter iter;
gboolean iter_valid;
g_return_val_if_fail (PIKA_IS_PATH_EDITOR (editor), FALSE);
g_return_val_if_fail (directory != NULL, FALSE);
model = GTK_TREE_MODEL (editor->dir_list);
for (iter_valid = gtk_tree_model_get_iter_first (model, &iter);
iter_valid;
iter_valid = gtk_tree_model_iter_next (model, &iter))
{
gchar *dir;
gboolean dir_writable;
gtk_tree_model_get (model, &iter,
COLUMN_DIRECTORY, &dir,
COLUMN_WRITABLE, &dir_writable,
-1);
if (! strcmp (dir, directory))
{
g_free (dir);
return dir_writable;
}
g_free (dir);
}
return FALSE;
}
void
pika_path_editor_set_dir_writable (PikaPathEditor *editor,
const gchar *directory,
gboolean writable)
{
GtkTreeModel *model;
GtkTreeIter iter;
gboolean iter_valid;
g_return_if_fail (PIKA_IS_PATH_EDITOR (editor));
g_return_if_fail (directory != NULL);
model = GTK_TREE_MODEL (editor->dir_list);
for (iter_valid = gtk_tree_model_get_iter_first (model, &iter);
iter_valid;
iter_valid = gtk_tree_model_iter_next (model, &iter))
{
gchar *dir;
gboolean dir_writable;
gtk_tree_model_get (model, &iter,
COLUMN_DIRECTORY, &dir,
COLUMN_WRITABLE, &dir_writable,
-1);
if (! strcmp (dir, directory) && dir_writable != writable)
{
gtk_list_store_set (editor->dir_list, &iter,
COLUMN_WRITABLE, writable ? TRUE : FALSE,
-1);
g_signal_emit (editor, pika_path_editor_signals[WRITABLE_CHANGED], 0);
g_free (dir);
break;
}
g_free (dir);
}
}
/* private functions */
static void
pika_path_editor_new_clicked (GtkWidget *widget,
PikaPathEditor *editor)
{
if (editor->sel_path)
{
g_signal_handlers_block_by_func (editor->sel,
pika_path_editor_selection_changed,
editor);
gtk_tree_selection_unselect_path (editor->sel, editor->sel_path);
g_signal_handlers_unblock_by_func (editor->sel,
pika_path_editor_selection_changed,
editor);
gtk_tree_path_free (editor->sel_path);
editor->sel_path = NULL;
}
gtk_widget_set_sensitive (editor->delete_button, FALSE);
gtk_widget_set_sensitive (editor->up_button, FALSE);
gtk_widget_set_sensitive (editor->down_button, FALSE);
gtk_widget_set_sensitive (editor->file_entry, TRUE);
gtk_editable_set_position
(GTK_EDITABLE (pika_file_entry_get_entry (PIKA_FILE_ENTRY (editor->file_entry))), -1);
gtk_widget_grab_focus
(pika_file_entry_get_entry (PIKA_FILE_ENTRY (editor->file_entry)));
}
static void
pika_path_editor_move_clicked (GtkWidget *widget,
PikaPathEditor *editor)
{
GtkTreePath *path;
GtkTreeModel *model;
GtkTreeIter iter1, iter2;
gchar *utf81, *utf82;
gchar *dir1, *dir2;
gboolean writable1, writable2;
if (editor->sel_path == NULL)
return;
path = gtk_tree_path_copy (editor->sel_path);
if (widget == editor->up_button)
gtk_tree_path_prev (path);
else
gtk_tree_path_next (path);
model = GTK_TREE_MODEL (editor->dir_list);
gtk_tree_model_get_iter (model, &iter1, editor->sel_path);
gtk_tree_model_get_iter (model, &iter2, path);
gtk_tree_model_get (model, &iter1,
COLUMN_UTF8, &utf81,
COLUMN_DIRECTORY, &dir1,
COLUMN_WRITABLE, &writable1,
-1);
gtk_tree_model_get (model, &iter2,
COLUMN_UTF8, &utf82,
COLUMN_DIRECTORY, &dir2,
COLUMN_WRITABLE, &writable2,
-1);
gtk_list_store_set (editor->dir_list, &iter1,
COLUMN_UTF8, utf82,
COLUMN_DIRECTORY, dir2,
COLUMN_WRITABLE, writable2,
-1);
gtk_list_store_set (editor->dir_list, &iter2,
COLUMN_UTF8, utf81,
COLUMN_DIRECTORY, dir1,
COLUMN_WRITABLE, writable1,
-1);
g_free (utf81);
g_free (utf82);
g_free (dir2);
g_free (dir1);
gtk_tree_selection_select_iter (editor->sel, &iter2);
g_signal_emit (editor, pika_path_editor_signals[PATH_CHANGED], 0);
}
static void
pika_path_editor_delete_clicked (GtkWidget *widget,
PikaPathEditor *editor)
{
GtkTreeIter iter;
gboolean dir_writable;
if (editor->sel_path == NULL)
return;
gtk_tree_model_get_iter (GTK_TREE_MODEL (editor->dir_list), &iter,
editor->sel_path);
gtk_tree_model_get (GTK_TREE_MODEL (editor->dir_list), &iter,
COLUMN_WRITABLE, &dir_writable,
-1);
gtk_list_store_remove (editor->dir_list, &iter);
editor->num_items--;
if (editor->num_items == 0)
{
gtk_tree_path_free (editor->sel_path);
editor->sel_path = NULL;
g_signal_handlers_block_by_func (editor->file_entry,
pika_path_editor_file_entry_changed,
editor);
pika_file_entry_set_filename (PIKA_FILE_ENTRY (editor->file_entry), "");
g_signal_handlers_unblock_by_func (editor->file_entry,
pika_path_editor_file_entry_changed,
editor);
gtk_widget_set_sensitive (editor->delete_button, FALSE);
gtk_widget_set_sensitive (editor->up_button, FALSE);
gtk_widget_set_sensitive (editor->down_button, FALSE);
gtk_widget_set_sensitive (editor->file_entry, FALSE);
}
else
{
gint *indices;
indices = gtk_tree_path_get_indices (editor->sel_path);
if ((indices[0] == editor->num_items) && (indices[0] > 0))
gtk_tree_path_prev (editor->sel_path);
gtk_tree_selection_select_path (editor->sel, editor->sel_path);
}
g_signal_emit (editor, pika_path_editor_signals[PATH_CHANGED], 0);
if (dir_writable)
g_signal_emit (editor, pika_path_editor_signals[WRITABLE_CHANGED], 0);
}
static void
pika_path_editor_file_entry_changed (GtkWidget *widget,
PikaPathEditor *editor)
{
gchar *dir;
gchar *utf8;
GtkTreeIter iter;
dir = pika_file_entry_get_filename (PIKA_FILE_ENTRY (widget));
if (strcmp (dir, "") == 0)
{
g_free (dir);
return;
}
utf8 = g_filename_display_name (dir);
if (editor->sel_path == NULL)
{
gtk_list_store_append (editor->dir_list, &iter);
gtk_list_store_set (editor->dir_list, &iter,
COLUMN_UTF8, utf8,
COLUMN_DIRECTORY, dir,
COLUMN_WRITABLE, FALSE,
-1);
editor->num_items++;
gtk_tree_selection_select_iter (editor->sel, &iter);
}
else
{
gtk_tree_model_get_iter (GTK_TREE_MODEL (editor->dir_list), &iter,
editor->sel_path);
gtk_list_store_set (editor->dir_list, &iter,
COLUMN_UTF8, utf8,
COLUMN_DIRECTORY, dir,
-1);
}
g_free (dir);
g_free (utf8);
g_signal_emit (editor, pika_path_editor_signals[PATH_CHANGED], 0);
}
static void
pika_path_editor_selection_changed (GtkTreeSelection *sel,
PikaPathEditor *editor)
{
GtkTreeIter iter;
gchar *directory;
gint *indices;
if (gtk_tree_selection_get_selected (sel, NULL, &iter))
{
gtk_tree_model_get (GTK_TREE_MODEL (editor->dir_list), &iter,
COLUMN_DIRECTORY, &directory,
-1);
g_signal_handlers_block_by_func (editor->file_entry,
pika_path_editor_file_entry_changed,
editor);
pika_file_entry_set_filename (PIKA_FILE_ENTRY (editor->file_entry),
directory);
g_signal_handlers_unblock_by_func (editor->file_entry,
pika_path_editor_file_entry_changed,
editor);
g_free (directory);
if (editor->sel_path)
gtk_tree_path_free (editor->sel_path);
editor->sel_path =
gtk_tree_model_get_path (GTK_TREE_MODEL (editor->dir_list), &iter);
indices = gtk_tree_path_get_indices (editor->sel_path);
gtk_widget_set_sensitive (editor->delete_button, TRUE);
gtk_widget_set_sensitive (editor->up_button, (indices[0] > 0));
gtk_widget_set_sensitive (editor->down_button,
(indices[0] < (editor->num_items - 1)));
gtk_widget_set_sensitive (editor->file_entry, TRUE);
}
else
{
g_signal_handlers_block_by_func (sel,
pika_path_editor_selection_changed,
editor);
gtk_tree_selection_select_path (editor->sel, editor->sel_path);
g_signal_handlers_unblock_by_func (sel,
pika_path_editor_selection_changed,
editor);
}
}
static void
pika_path_editor_writable_toggled (GtkCellRendererToggle *toggle,
gchar *path_str,
PikaPathEditor *editor)
{
GtkTreePath *path;
GtkTreeIter iter;
path = gtk_tree_path_new_from_string (path_str);
if (gtk_tree_model_get_iter (GTK_TREE_MODEL (editor->dir_list), &iter, path))
{
gboolean dir_writable;
gtk_tree_model_get (GTK_TREE_MODEL (editor->dir_list), &iter,
COLUMN_WRITABLE, &dir_writable,
-1);
gtk_list_store_set (editor->dir_list, &iter,
COLUMN_WRITABLE, ! dir_writable,
-1);
g_signal_emit (editor, pika_path_editor_signals[WRITABLE_CHANGED], 0);
}
gtk_tree_path_free (path);
}

View File

@ -0,0 +1,113 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikapatheditor.h
* Copyright (C) 1999-2004 Michael Natterer <mitch@gimp.org>
*
* 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 3 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 library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#if !defined (__PIKA_WIDGETS_H_INSIDE__) && !defined (PIKA_WIDGETS_COMPILATION)
#error "Only <libpikawidgets/pikawidgets.h> can be included directly."
#endif
#ifndef __PIKA_PATH_EDITOR_H__
#define __PIKA_PATH_EDITOR_H__
G_BEGIN_DECLS
/* For information look into the C source or the html documentation */
#define PIKA_TYPE_PATH_EDITOR (pika_path_editor_get_type ())
#define PIKA_PATH_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), PIKA_TYPE_PATH_EDITOR, PikaPathEditor))
#define PIKA_PATH_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PIKA_TYPE_PATH_EDITOR, PikaPathEditorClass))
#define PIKA_IS_PATH_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE (obj, PIKA_TYPE_PATH_EDITOR))
#define PIKA_IS_PATH_EDITOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PIKA_TYPE_PATH_EDITOR))
#define PIKA_PATH_EDITOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PIKA_TYPE_PATH_EDITOR, PikaPathEditorClass))
typedef struct _PikaPathEditorPrivate PikaPathEditorPrivate;
typedef struct _PikaPathEditorClass PikaPathEditorClass;
struct _PikaPathEditor
{
GtkBox parent_instance;
PikaPathEditorPrivate *priv;
/* FIXME MOVE TO PRIVATE */
GtkWidget *upper_hbox;
GtkWidget *new_button;
GtkWidget *up_button;
GtkWidget *down_button;
GtkWidget *delete_button;
GtkWidget *file_entry;
GtkListStore *dir_list;
GtkTreeSelection *sel;
GtkTreePath *sel_path;
GtkTreeViewColumn *writable_column;
gint num_items;
};
struct _PikaPathEditorClass
{
GtkBoxClass parent_class;
void (* path_changed) (PikaPathEditor *editor);
void (* writable_changed) (PikaPathEditor *editor);
/* Padding for future expansion */
void (* _pika_reserved1) (void);
void (* _pika_reserved2) (void);
void (* _pika_reserved3) (void);
void (* _pika_reserved4) (void);
void (* _pika_reserved5) (void);
void (* _pika_reserved6) (void);
void (* _pika_reserved7) (void);
void (* _pika_reserved8) (void);
};
/* For information look into the C source or the html documentation */
GType pika_path_editor_get_type (void) G_GNUC_CONST;
GtkWidget * pika_path_editor_new (const gchar *title,
const gchar *path);
gchar * pika_path_editor_get_path (PikaPathEditor *editor);
void pika_path_editor_set_path (PikaPathEditor *editor,
const gchar *path);
gchar * pika_path_editor_get_writable_path (PikaPathEditor *editor);
void pika_path_editor_set_writable_path (PikaPathEditor *editor,
const gchar *path);
gboolean pika_path_editor_get_dir_writable (PikaPathEditor *editor,
const gchar *directory);
void pika_path_editor_set_dir_writable (PikaPathEditor *editor,
const gchar *directory,
gboolean writable);
G_END_DECLS
#endif /* __PIKA_PATH_EDITOR_H__ */

View File

@ -0,0 +1,355 @@
/* LIBPIKA - The PIKA Library
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
*
* pikapickbutton.c
* Copyright (C) 2002 Michael Natterer <mitch@gimp.org>
*
* based on gtk+/gtk/gtkcolorsel.c
*
* 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gegl.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#ifdef G_OS_WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include "libpikacolor/pikacolor.h"
#include "pikawidgetstypes.h"
#include "pikacairo-utils.h"
#include "pikahelpui.h"
#include "pikaicons.h"
#include "pikapickbutton.h"
#include "pikapickbutton-default.h"
#include "pikapickbutton-private.h"
#include "pikawidgetsutils.h"
#include "libpika/libpika-intl.h"
static gboolean pika_pick_button_mouse_press (GtkWidget *invisible,
GdkEventButton *event,
PikaPickButton *button);
static gboolean pika_pick_button_key_press (GtkWidget *invisible,
GdkEventKey *event,
PikaPickButton *button);
static gboolean pika_pick_button_mouse_motion (GtkWidget *invisible,
GdkEventMotion *event,
PikaPickButton *button);
static gboolean pika_pick_button_mouse_release (GtkWidget *invisible,
GdkEventButton *event,
PikaPickButton *button);
static void pika_pick_button_shutdown (PikaPickButton *button);
static void pika_pick_button_pick (PikaPickButton *button,
GdkEvent *event);
static GdkCursor *
make_cursor (GdkDisplay *display)
{
GdkPixbuf *pixbuf;
GError *error = NULL;
pixbuf = gdk_pixbuf_new_from_resource ("/technology.heckin/color-picker-cursors/cursor-color-picker.png",
&error);
if (pixbuf)
{
GdkCursor *cursor = gdk_cursor_new_from_pixbuf (display, pixbuf, 1, 30);
g_object_unref (pixbuf);
return cursor;
}
else
{
g_critical ("Failed to create cursor image: %s", error->message);
g_clear_error (&error);
}
return NULL;
}
static gboolean
pika_pick_button_mouse_press (GtkWidget *invisible,
GdkEventButton *event,
PikaPickButton *button)
{
if (event->type == GDK_BUTTON_PRESS && event->button == 1)
{
g_signal_connect (invisible, "motion-notify-event",
G_CALLBACK (pika_pick_button_mouse_motion),
button);
g_signal_connect (invisible, "button-release-event",
G_CALLBACK (pika_pick_button_mouse_release),
button);
g_signal_handlers_disconnect_by_func (invisible,
pika_pick_button_mouse_press,
button);
g_signal_handlers_disconnect_by_func (invisible,
pika_pick_button_key_press,
button);
pika_pick_button_pick (button, (GdkEvent *) event);
return TRUE;
}
return FALSE;
}
static gboolean
pika_pick_button_key_press (GtkWidget *invisible,
GdkEventKey *event,
PikaPickButton *button)
{
if (event->keyval == GDK_KEY_Escape)
{
pika_pick_button_shutdown (button);
g_signal_handlers_disconnect_by_func (invisible,
pika_pick_button_mouse_press,
button);
g_signal_handlers_disconnect_by_func (invisible,
pika_pick_button_key_press,
button);
return TRUE;
}
return FALSE;
}
static gboolean
pika_pick_button_mouse_motion (GtkWidget *invisible,
GdkEventMotion *event,
PikaPickButton *button)
{
pika_pick_button_pick (button, (GdkEvent *) event);
return TRUE;
}
static gboolean
pika_pick_button_mouse_release (GtkWidget *invisible,
GdkEventButton *event,
PikaPickButton *button)
{
if (event->button != 1)
return FALSE;
pika_pick_button_pick (button, (GdkEvent *) event);
pika_pick_button_shutdown (button);
g_signal_handlers_disconnect_by_func (invisible,
pika_pick_button_mouse_motion,
button);
g_signal_handlers_disconnect_by_func (invisible,
pika_pick_button_mouse_release,
button);
return TRUE;
}
static void
pika_pick_button_shutdown (PikaPickButton *button)
{
GdkDisplay *display = gtk_widget_get_display (button->priv->grab_widget);
gtk_grab_remove (button->priv->grab_widget);
gdk_seat_ungrab (gdk_display_get_default_seat (display));
}
static void
pika_pick_button_pick (PikaPickButton *button,
GdkEvent *event)
{
GdkScreen *screen = gdk_event_get_screen (event);
PikaColorProfile *monitor_profile;
GdkMonitor *monitor;
PikaRGB rgb;
gint x_root;
gint y_root;
gdouble x_win;
gdouble y_win;
gdk_window_get_origin (gdk_event_get_window (event), &x_root, &y_root);
gdk_event_get_coords (event, &x_win, &y_win);
x_root += x_win;
y_root += y_win;
#ifdef G_OS_WIN32
{
HDC hdc;
RECT rect;
COLORREF win32_color;
/* For MS Windows, use native GDI functions to get the pixel, as
* cairo does not handle the case where you have multiple monitors
* with a monitor on the left or above the primary monitor. That
* scenario create a cairo primary surface with negative extent,
* which is not handled properly (bug 740634).
*/
hdc = GetDC (HWND_DESKTOP);
GetClipBox (hdc, &rect);
win32_color = GetPixel (hdc, x_root + rect.left, y_root + rect.top);
ReleaseDC (HWND_DESKTOP, hdc);
pika_rgba_set_uchar (&rgb,
GetRValue (win32_color),
GetGValue (win32_color),
GetBValue (win32_color),
255);
}
#else
{
GdkWindow *window;
gint x_window;
gint y_window;
cairo_surface_t *image;
cairo_t *cr;
guchar *data;
guchar color[3];
/* we try to pick from the local window under the cursor, and fall
* back to picking from the root window if this fails (i.e., if
* the cursor is not under a local window). on wayland, picking
* from the root window is not supported, so this at least allows
* us to pick from local windows. see bug #780375.
*/
window = gdk_device_get_window_at_position (gdk_event_get_device (event),
&x_window, &y_window);
if (! window)
{
window = gdk_screen_get_root_window (screen);
x_window = x_root;
y_window = y_root;
}
image = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 1, 1);
cr = cairo_create (image);
gdk_cairo_set_source_window (cr, window, -x_window, -y_window);
cairo_paint (cr);
cairo_destroy (cr);
data = cairo_image_surface_get_data (image);
PIKA_CAIRO_RGB24_GET_PIXEL (data, color[0], color[1], color[2]);
cairo_surface_destroy (image);
pika_rgba_set_uchar (&rgb, color[0], color[1], color[2], 255);
}
#endif
monitor = gdk_display_get_monitor_at_point (gdk_screen_get_display (screen),
x_root, y_root);
monitor_profile = pika_monitor_get_color_profile (monitor);
if (monitor_profile)
{
PikaColorProfile *srgb_profile;
PikaColorTransform *transform;
const Babl *format;
PikaColorTransformFlags flags = 0;
format = babl_format ("R'G'B'A double");
flags |= PIKA_COLOR_TRANSFORM_FLAGS_NOOPTIMIZE;
flags |= PIKA_COLOR_TRANSFORM_FLAGS_BLACK_POINT_COMPENSATION;
srgb_profile = pika_color_profile_new_rgb_srgb ();
transform = pika_color_transform_new (monitor_profile, format,
srgb_profile, format,
PIKA_COLOR_RENDERING_INTENT_PERCEPTUAL,
flags);
g_object_unref (srgb_profile);
if (transform)
{
pika_color_transform_process_pixels (transform,
format, &rgb,
format, &rgb,
1);
pika_rgb_clamp (&rgb);
g_object_unref (transform);
}
}
g_signal_emit_by_name (button, "color-picked", &rgb);
}
/* entry point to this file, called from pikapickbutton.c */
void
_pika_pick_button_default_pick (PikaPickButton *button)
{
GdkDisplay *display;
GtkWidget *widget;
if (! button->priv->cursor)
button->priv->cursor =
make_cursor (gtk_widget_get_display (GTK_WIDGET (button)));
if (! button->priv->grab_widget)
{
button->priv->grab_widget = gtk_invisible_new ();
gtk_widget_add_events (button->priv->grab_widget,
GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK |
GDK_BUTTON1_MOTION_MASK);
gtk_widget_show (button->priv->grab_widget);
}
widget = button->priv->grab_widget;
display = gtk_widget_get_display (widget);
if (gdk_seat_grab (gdk_display_get_default_seat (display),
gtk_widget_get_window (widget),
GDK_SEAT_CAPABILITY_ALL,
FALSE,
button->priv->cursor,
NULL,
NULL, NULL) != GDK_GRAB_SUCCESS)
{
g_warning ("Failed to grab seat to do eyedropper");
return;
}
gtk_grab_add (widget);
g_signal_connect (widget, "button-press-event",
G_CALLBACK (pika_pick_button_mouse_press),
button);
g_signal_connect (widget, "key-press-event",
G_CALLBACK (pika_pick_button_key_press),
button);
}

Some files were not shown because too many files have changed in this diff Show More