Initial checkin of Pika from heckimp
This commit is contained in:
134
libpikawidgets/Makefile.gi
Normal file
134
libpikawidgets/Makefile.gi
Normal 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
250
libpikawidgets/meson.build
Normal 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,
|
||||
)
|
||||
496
libpikawidgets/pikabrowser.c
Normal file
496
libpikawidgets/pikabrowser.c
Normal 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;
|
||||
}
|
||||
94
libpikawidgets/pikabrowser.h
Normal file
94
libpikawidgets/pikabrowser.h
Normal 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__ */
|
||||
232
libpikawidgets/pikabusybox.c
Normal file
232
libpikawidgets/pikabusybox.c
Normal 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);
|
||||
}
|
||||
76
libpikawidgets/pikabusybox.h
Normal file
76
libpikawidgets/pikabusybox.h
Normal 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
173
libpikawidgets/pikabutton.c
Normal 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);
|
||||
}
|
||||
}
|
||||
81
libpikawidgets/pikabutton.h
Normal file
81
libpikawidgets/pikabutton.h
Normal 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__ */
|
||||
202
libpikawidgets/pikacairo-utils.c
Normal file
202
libpikawidgets/pikacairo-utils.c
Normal 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;
|
||||
}
|
||||
36
libpikawidgets/pikacairo-utils.h
Normal file
36
libpikawidgets/pikacairo-utils.h
Normal 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__ */
|
||||
332
libpikawidgets/pikacellrenderercolor.c
Normal file
332
libpikawidgets/pikacellrenderercolor.c
Normal 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);
|
||||
}
|
||||
73
libpikawidgets/pikacellrenderercolor.h
Normal file
73
libpikawidgets/pikacellrenderercolor.h
Normal 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__ */
|
||||
577
libpikawidgets/pikacellrenderertoggle.c
Normal file
577
libpikawidgets/pikacellrenderertoggle.c
Normal 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);
|
||||
}
|
||||
81
libpikawidgets/pikacellrenderertoggle.h
Normal file
81
libpikawidgets/pikacellrenderertoggle.h
Normal 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__ */
|
||||
621
libpikawidgets/pikachainbutton.c
Normal file
621
libpikawidgets/pikachainbutton.c
Normal 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;
|
||||
}
|
||||
93
libpikawidgets/pikachainbutton.h
Normal file
93
libpikawidgets/pikachainbutton.h
Normal 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__ */
|
||||
1042
libpikawidgets/pikacolorarea.c
Normal file
1042
libpikawidgets/pikacolorarea.c
Normal file
File diff suppressed because it is too large
Load Diff
100
libpikawidgets/pikacolorarea.h
Normal file
100
libpikawidgets/pikacolorarea.h
Normal 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__ */
|
||||
1063
libpikawidgets/pikacolorbutton.c
Normal file
1063
libpikawidgets/pikacolorbutton.c
Normal file
File diff suppressed because it is too large
Load Diff
113
libpikawidgets/pikacolorbutton.h
Normal file
113
libpikawidgets/pikacolorbutton.h
Normal 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__ */
|
||||
479
libpikawidgets/pikacolordisplay.c
Normal file
479
libpikawidgets/pikacolordisplay.c
Normal 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;
|
||||
}
|
||||
106
libpikawidgets/pikacolordisplay.h
Normal file
106
libpikawidgets/pikacolordisplay.h
Normal 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__ */
|
||||
460
libpikawidgets/pikacolordisplaystack.c
Normal file
460
libpikawidgets/pikacolordisplaystack.c
Normal 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);
|
||||
}
|
||||
102
libpikawidgets/pikacolordisplaystack.h
Normal file
102
libpikawidgets/pikacolordisplaystack.h
Normal 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__ */
|
||||
349
libpikawidgets/pikacolorhexentry.c
Normal file
349
libpikawidgets/pikacolorhexentry.c
Normal 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;
|
||||
}
|
||||
80
libpikawidgets/pikacolorhexentry.h
Normal file
80
libpikawidgets/pikacolorhexentry.h
Normal 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__ */
|
||||
628
libpikawidgets/pikacolornotebook.c
Normal file
628
libpikawidgets/pikacolornotebook.c
Normal 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);
|
||||
}
|
||||
}
|
||||
88
libpikawidgets/pikacolornotebook.h
Normal file
88
libpikawidgets/pikacolornotebook.h
Normal 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__ */
|
||||
360
libpikawidgets/pikacolorprofilechooserdialog.c
Normal file
360
libpikawidgets/pikacolorprofilechooserdialog.c
Normal 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);
|
||||
}
|
||||
75
libpikawidgets/pikacolorprofilechooserdialog.h
Normal file
75
libpikawidgets/pikacolorprofilechooserdialog.h
Normal 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__ */
|
||||
557
libpikawidgets/pikacolorprofilecombobox.c
Normal file
557
libpikawidgets/pikacolorprofilecombobox.c
Normal 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));
|
||||
}
|
||||
87
libpikawidgets/pikacolorprofilecombobox.h
Normal file
87
libpikawidgets/pikacolorprofilecombobox.h
Normal 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__ */
|
||||
57
libpikawidgets/pikacolorprofilestore-private.h
Normal file
57
libpikawidgets/pikacolorprofilestore-private.h
Normal 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__ */
|
||||
845
libpikawidgets/pikacolorprofilestore.c
Normal file
845
libpikawidgets/pikacolorprofilestore.c
Normal 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);
|
||||
}
|
||||
76
libpikawidgets/pikacolorprofilestore.h
Normal file
76
libpikawidgets/pikacolorprofilestore.h
Normal 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__ */
|
||||
213
libpikawidgets/pikacolorprofileview.c
Normal file
213
libpikawidgets/pikacolorprofileview.c
Normal 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);
|
||||
}
|
||||
76
libpikawidgets/pikacolorprofileview.h
Normal file
76
libpikawidgets/pikacolorprofileview.h
Normal 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__ */
|
||||
982
libpikawidgets/pikacolorscale.c
Normal file
982
libpikawidgets/pikacolorscale.c
Normal 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;
|
||||
}
|
||||
83
libpikawidgets/pikacolorscale.h
Normal file
83
libpikawidgets/pikacolorscale.h
Normal 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__ */
|
||||
112
libpikawidgets/pikacolorscaleentry.c
Normal file
112
libpikawidgets/pikacolorscaleentry.c
Normal 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;
|
||||
}
|
||||
45
libpikawidgets/pikacolorscaleentry.h
Normal file
45
libpikawidgets/pikacolorscaleentry.h
Normal 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__ */
|
||||
926
libpikawidgets/pikacolorscales.c
Normal file
926
libpikawidgets/pikacolorscales.c
Normal 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);
|
||||
}
|
||||
49
libpikawidgets/pikacolorscales.h
Normal file
49
libpikawidgets/pikacolorscales.h
Normal 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__ */
|
||||
1995
libpikawidgets/pikacolorselect.c
Normal file
1995
libpikawidgets/pikacolorselect.c
Normal file
File diff suppressed because it is too large
Load Diff
41
libpikawidgets/pikacolorselect.h
Normal file
41
libpikawidgets/pikacolorselect.h
Normal 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__ */
|
||||
823
libpikawidgets/pikacolorselection.c
Normal file
823
libpikawidgets/pikacolorselection.c
Normal 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);
|
||||
}
|
||||
}
|
||||
106
libpikawidgets/pikacolorselection.h
Normal file
106
libpikawidgets/pikacolorselection.h
Normal 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__ */
|
||||
668
libpikawidgets/pikacolorselector.c
Normal file
668
libpikawidgets/pikacolorselector.c
Normal 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);
|
||||
}
|
||||
187
libpikawidgets/pikacolorselector.h
Normal file
187
libpikawidgets/pikacolorselector.h
Normal 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__ */
|
||||
264
libpikawidgets/pikacontroller.c
Normal file
264
libpikawidgets/pikacontroller.c
Normal 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;
|
||||
}
|
||||
191
libpikawidgets/pikacontroller.h
Normal file
191
libpikawidgets/pikacontroller.h
Normal 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
726
libpikawidgets/pikadialog.c
Normal 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
117
libpikawidgets/pikadialog.h
Normal 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
666
libpikawidgets/pikaeevl.c
Normal 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
99
libpikawidgets/pikaeevl.h
Normal 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__ */
|
||||
211
libpikawidgets/pikaenumcombobox.c
Normal file
211
libpikawidgets/pikaenumcombobox.c
Normal 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);
|
||||
}
|
||||
77
libpikawidgets/pikaenumcombobox.h
Normal file
77
libpikawidgets/pikaenumcombobox.h
Normal 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__ */
|
||||
231
libpikawidgets/pikaenumlabel.c
Normal file
231
libpikawidgets/pikaenumlabel.c
Normal 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);
|
||||
}
|
||||
76
libpikawidgets/pikaenumlabel.h
Normal file
76
libpikawidgets/pikaenumlabel.h
Normal 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__ */
|
||||
395
libpikawidgets/pikaenumstore.c
Normal file
395
libpikawidgets/pikaenumstore.c
Normal 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);
|
||||
}
|
||||
}
|
||||
86
libpikawidgets/pikaenumstore.h
Normal file
86
libpikawidgets/pikaenumstore.h
Normal 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__ */
|
||||
476
libpikawidgets/pikaenumwidgets.c
Normal file
476
libpikawidgets/pikaenumwidgets.c
Normal 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);
|
||||
}
|
||||
82
libpikawidgets/pikaenumwidgets.h
Normal file
82
libpikawidgets/pikaenumwidgets.h
Normal 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__ */
|
||||
530
libpikawidgets/pikafileentry.c
Normal file
530
libpikawidgets/pikafileentry.c
Normal 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);
|
||||
}
|
||||
90
libpikawidgets/pikafileentry.h
Normal file
90
libpikawidgets/pikafileentry.h
Normal 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
264
libpikawidgets/pikaframe.c
Normal 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;
|
||||
}
|
||||
74
libpikawidgets/pikaframe.h
Normal file
74
libpikawidgets/pikaframe.h
Normal 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
651
libpikawidgets/pikahelpui.c
Normal 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;
|
||||
}
|
||||
74
libpikawidgets/pikahelpui.h
Normal file
74
libpikawidgets/pikahelpui.h
Normal 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__ */
|
||||
224
libpikawidgets/pikahintbox.c
Normal file
224
libpikawidgets/pikahintbox.c
Normal 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);
|
||||
}
|
||||
75
libpikawidgets/pikahintbox.h
Normal file
75
libpikawidgets/pikahintbox.h
Normal 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
314
libpikawidgets/pikaicons.c
Normal 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
435
libpikawidgets/pikaicons.h
Normal 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__ */
|
||||
1002
libpikawidgets/pikaintcombobox.c
Normal file
1002
libpikawidgets/pikaintcombobox.c
Normal file
File diff suppressed because it is too large
Load Diff
128
libpikawidgets/pikaintcombobox.h
Normal file
128
libpikawidgets/pikaintcombobox.h
Normal 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__ */
|
||||
789
libpikawidgets/pikaintradioframe.c
Normal file
789
libpikawidgets/pikaintradioframe.c
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
128
libpikawidgets/pikaintradioframe.h
Normal file
128
libpikawidgets/pikaintradioframe.h
Normal 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__ */
|
||||
452
libpikawidgets/pikaintstore.c
Normal file
452
libpikawidgets/pikaintstore.c
Normal 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;
|
||||
}
|
||||
111
libpikawidgets/pikaintstore.h
Normal file
111
libpikawidgets/pikaintstore.h
Normal 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__ */
|
||||
436
libpikawidgets/pikalabelcolor.c
Normal file
436
libpikawidgets/pikalabelcolor.c
Normal 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;
|
||||
}
|
||||
76
libpikawidgets/pikalabelcolor.h
Normal file
76
libpikawidgets/pikalabelcolor.h
Normal 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__ */
|
||||
274
libpikawidgets/pikalabeled.c
Normal file
274
libpikawidgets/pikalabeled.c
Normal 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);
|
||||
}
|
||||
85
libpikawidgets/pikalabeled.h
Normal file
85
libpikawidgets/pikalabeled.h
Normal 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__ */
|
||||
296
libpikawidgets/pikalabelentry.c
Normal file
296
libpikawidgets/pikalabelentry.c
Normal 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;
|
||||
}
|
||||
64
libpikawidgets/pikalabelentry.h
Normal file
64
libpikawidgets/pikalabelentry.h
Normal 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__ */
|
||||
273
libpikawidgets/pikalabelintwidget.c
Normal file
273
libpikawidgets/pikalabelintwidget.c
Normal 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;
|
||||
}
|
||||
62
libpikawidgets/pikalabelintwidget.h
Normal file
62
libpikawidgets/pikalabelintwidget.h
Normal 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__ */
|
||||
519
libpikawidgets/pikalabelspin.c
Normal file
519
libpikawidgets/pikalabelspin.c
Normal 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;
|
||||
}
|
||||
74
libpikawidgets/pikalabelspin.h
Normal file
74
libpikawidgets/pikalabelspin.h
Normal 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__ */
|
||||
336
libpikawidgets/pikamemsizeentry.c
Normal file
336
libpikawidgets/pikamemsizeentry.c
Normal 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;
|
||||
}
|
||||
82
libpikawidgets/pikamemsizeentry.h
Normal file
82
libpikawidgets/pikamemsizeentry.h
Normal 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__ */
|
||||
1280
libpikawidgets/pikanumberpairentry.c
Normal file
1280
libpikawidgets/pikanumberpairentry.c
Normal file
File diff suppressed because it is too large
Load Diff
109
libpikawidgets/pikanumberpairentry.h
Normal file
109
libpikawidgets/pikanumberpairentry.h
Normal 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__ */
|
||||
535
libpikawidgets/pikaoffsetarea.c
Normal file
535
libpikawidgets/pikaoffsetarea.c
Normal 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;
|
||||
}
|
||||
89
libpikawidgets/pikaoffsetarea.h
Normal file
89
libpikawidgets/pikaoffsetarea.h
Normal 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__ */
|
||||
1340
libpikawidgets/pikapageselector.c
Normal file
1340
libpikawidgets/pikapageselector.c
Normal file
File diff suppressed because it is too large
Load Diff
110
libpikawidgets/pikapageselector.h
Normal file
110
libpikawidgets/pikapageselector.h
Normal 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__ */
|
||||
873
libpikawidgets/pikapatheditor.c
Normal file
873
libpikawidgets/pikapatheditor.c
Normal 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);
|
||||
}
|
||||
113
libpikawidgets/pikapatheditor.h
Normal file
113
libpikawidgets/pikapatheditor.h
Normal 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__ */
|
||||
355
libpikawidgets/pikapickbutton-default.c
Normal file
355
libpikawidgets/pikapickbutton-default.c
Normal 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
Reference in New Issue
Block a user