From 69d60676dd59891de96513c9803562bde4c75ac0 Mon Sep 17 00:00:00 2001 From: John Stebbins Date: Tue, 30 Jul 2019 12:51:13 -0700 Subject: [PATCH] LinGui: change chapter list to GtkListBox GtkListBox is more flexible than GtkTreeView. It is possible now to process key press events without creating a custom text cell renderer. Also due to the way event handling changes in GTK4, it was no longer even possible to create a custom cell renderer that can process key events. So this GtkListBox implementation is compatible with GTK4. --- gtk/src/Makefile.am | 6 +- gtk/src/callbacks.c | 178 +-- gtk/src/callbacks.h | 1 - gtk/src/chapters.c | 308 +++++ gtk/src/chapters.h | 32 + gtk/src/ghb3.ui | 77 +- gtk/src/ghb4.ui | 57 +- gtk/src/ghbcellrenderertext.c | 2022 --------------------------------- gtk/src/ghbcellrenderertext.h | 78 -- gtk/src/main.c | 53 +- gtk/src/marshalers.c | 60 +- gtk/src/marshalers.h | 64 +- libhb/hb_json.c | 15 +- 13 files changed, 517 insertions(+), 2434 deletions(-) create mode 100644 gtk/src/chapters.c create mode 100644 gtk/src/chapters.h delete mode 100644 gtk/src/ghbcellrenderertext.c delete mode 100644 gtk/src/ghbcellrenderertext.h diff --git a/gtk/src/Makefile.am b/gtk/src/Makefile.am index d5cc6055d..617e71012 100644 --- a/gtk/src/Makefile.am +++ b/gtk/src/Makefile.am @@ -69,6 +69,8 @@ ghb_SOURCES = \ ghbcompat.h \ callbacks.c \ callbacks.h \ + chapters.c \ + chapters.h \ queuehandler.c \ queuehandler.h \ videohandler.c \ @@ -107,8 +109,6 @@ ghb_SOURCES = \ hb-backend.h \ renderer_button.h \ renderer_button.c \ - ghbcellrenderertext.c \ - ghbcellrenderertext.h \ ghb-dvd.c \ ghb-dvd.h \ marshalers.c \ @@ -186,8 +186,6 @@ widget.deps: makedeps.py fr.handbrake.ghb.appdata.xml.in: fr.handbrake.ghb.appdata.xml.template sed -e 's^RELEASE_TAG^^' $< > $@ -ghbcellrenderertext.$(OBJEXT): marshalers.h - $(srcdir)/marshalers.h: marshalers.list glib-genmarshal --prefix=ghb_marshal $(srcdir)/marshalers.list --header > $(srcdir)/marshalers.h diff --git a/gtk/src/callbacks.c b/gtk/src/callbacks.c index dcb4fc758..2f82ba094 100644 --- a/gtk/src/callbacks.c +++ b/gtk/src/callbacks.c @@ -76,6 +76,7 @@ #include "hb.h" #include "callbacks.h" +#include "chapters.h" #include "queuehandler.h" #include "audiohandler.h" #include "subtitlehandler.h" @@ -89,7 +90,6 @@ #include "appcast.h" #include "hb-backend.h" #include "ghb-dvd.h" -#include "ghbcellrenderertext.h" #include "libavutil/parseutils.h" static void update_queue_labels(signal_user_data_t *ud); @@ -4613,182 +4613,6 @@ show_presets_action_cb(GSimpleAction *action, GVariant *value, presets_window_set_visible(ud, state); } -static void -chapter_refresh_list_row_ui( - GtkTreeModel *tm, - GtkTreeIter *ti, - GhbValue *chapter_list, - const hb_title_t *title, - int index) -{ - const gchar *chapter; - gchar *s_duration, *s_start; - gint hh, mm, ss; - gint64 duration, start; - - // Update row with settings data - g_debug("Updating chapter row ui"); - chapter = ghb_dict_get_string(ghb_array_get(chapter_list, index), "Name"); - duration = ghb_get_chapter_duration(title, index) / 90000; - ghb_break_duration(duration, &hh, &mm, &ss); - s_duration = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss); - start = ghb_get_chapter_start(title, index) / 90000; - ghb_break_duration(start, &hh, &mm, &ss); - s_start = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss); - gtk_list_store_set(GTK_LIST_STORE(tm), ti, - 0, index+1, - 1, s_start, - 2, s_duration, - 3, chapter, - 4, TRUE, - -1); - g_free(s_duration); - g_free(s_start); -} - -static void -ghb_clear_chapter_list_ui(GtkBuilder *builder) -{ - GtkTreeView *tv; - GtkListStore *ts; - - tv = GTK_TREE_VIEW(GHB_WIDGET(builder, "chapters_list")); - ts = GTK_LIST_STORE(gtk_tree_view_get_model(tv)); - gtk_list_store_clear(ts); -} - -static void -chapter_refresh_list_ui(signal_user_data_t *ud) -{ - GhbValue *chapter_list; - gint ii, count, tm_count; - GtkTreeView *tv; - GtkTreeModel *tm; - GtkTreeIter ti; - int title_id, titleindex; - const hb_title_t *title; - - tv = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list")); - tm = gtk_tree_view_get_model(tv); - - tm_count = gtk_tree_model_iter_n_children(tm, NULL); - - title_id = ghb_dict_get_int(ud->settings, "title"); - title = ghb_lookup_title(title_id, &titleindex); - chapter_list = ghb_get_job_chapter_list(ud->settings); - count = ghb_array_len(chapter_list); - if (count != tm_count) - { - ghb_clear_chapter_list_ui(ud->builder); - for (ii = 0; ii < count; ii++) - { - gtk_list_store_append(GTK_LIST_STORE(tm), &ti); - } - } - for (ii = 0; ii < count; ii++) - { - gtk_tree_model_iter_nth_child(tm, &ti, NULL, ii); - chapter_refresh_list_row_ui(tm, &ti, chapter_list, title, ii); - } -} - -void -ghb_chapter_list_refresh_all(signal_user_data_t *ud) -{ - chapter_refresh_list_ui(ud); -} - -static guint chapter_edit_key = 0; - -G_MODULE_EXPORT gboolean -chapter_keypress_cb( - GtkCellRendererText *cell, - GdkEvent *event, - signal_user_data_t *ud) -{ - ghb_event_get_keyval(event, &chapter_edit_key); - return FALSE; -} - -G_MODULE_EXPORT void -chapter_edited_cb( - GtkCellRendererText *cell, - gchar *path, - gchar *text, - signal_user_data_t *ud) -{ - GtkTreePath *treepath; - GtkListStore *store; - GtkTreeView *treeview; - GtkTreeIter iter; - gint index; - gint *pi; - gint row; - - g_debug("chapter_edited_cb ()"); - g_debug("path (%s)", path); - g_debug("text (%s)", text); - treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list")); - store = GTK_LIST_STORE(gtk_tree_view_get_model(treeview)); - treepath = gtk_tree_path_new_from_string (path); - pi = gtk_tree_path_get_indices(treepath); - row = pi[0]; - gtk_tree_model_get_iter(GTK_TREE_MODEL(store), &iter, treepath); - gtk_list_store_set(store, &iter, - 3, text, - 4, TRUE, - -1); - gtk_tree_model_get(GTK_TREE_MODEL(store), &iter, 0, &index, -1); - - const GhbValue *chapters; - GhbValue *chapter; - - chapters = ghb_get_job_chapter_list(ud->settings); - chapter = ghb_array_get(chapters, index-1); - ghb_dict_set_string(chapter, "Name", text); - if ((chapter_edit_key == GDK_KEY_Return || chapter_edit_key == GDK_KEY_Down) && - gtk_tree_model_iter_next(GTK_TREE_MODEL(store), &iter)) - { - GtkTreeViewColumn *column; - - gtk_tree_path_next(treepath); - // When a cell has been edited, I want to advance to the - // next cell and start editing it automatically. - // Unfortunately, we may not be in a state here where - // editing is allowed. This happens when the user selects - // a new cell with the mouse instead of just hitting enter. - // Some kind of Gtk quirk. widget_editable==NULL assertion. - // Editing is enabled again once the selection event has been - // processed. So I'm queueing up a callback to be called - // when things go idle. There, I will advance to the next - // cell and initiate editing. - // - // Now, you might be asking why I don't catch the keypress - // event and determine what action to take based on that. - // The Gtk developers in their infinite wisdom have made the - // actual GtkEdit widget being used a private member of - // GtkCellRendererText, so it can not be accessed to hang a - // signal handler off of. And they also do not propagate the - // keypress signals in any other way. So that information is lost. - //g_idle_add((GSourceFunc)next_cell, ud); - // - // Keeping the above comment for posterity. - // I got industrious and made my own CellTextRendererText that - // passes on the key-press-event. So now I have much better - // control of this. - column = gtk_tree_view_get_column(treeview, 3); - gtk_tree_view_set_cursor(treeview, treepath, column, TRUE); - } - else if (chapter_edit_key == GDK_KEY_Up && row > 0) - { - GtkTreeViewColumn *column; - gtk_tree_path_prev(treepath); - column = gtk_tree_view_get_column(treeview, 3); - gtk_tree_view_set_cursor(treeview, treepath, column, TRUE); - } - gtk_tree_path_free (treepath); -} - void debug_log_handler(const gchar *domain, GLogLevelFlags flags, const gchar *msg, gpointer data) { diff --git a/gtk/src/callbacks.h b/gtk/src/callbacks.h index 6e025f0a6..39e570eac 100644 --- a/gtk/src/callbacks.h +++ b/gtk/src/callbacks.h @@ -78,7 +78,6 @@ void ghb_update_pending(signal_user_data_t *ud); gboolean ghb_idle_scan(signal_user_data_t *ud); void ghb_add_all_titles(signal_user_data_t *ud); void ghb_update_title_info(signal_user_data_t *ud); -void ghb_chapter_list_refresh_all(signal_user_data_t *ud); void ghb_load_settings(signal_user_data_t * ud); void ghb_load_post_settings(signal_user_data_t * ud); void ghb_set_current_title_settings(signal_user_data_t *ud); diff --git a/gtk/src/chapters.c b/gtk/src/chapters.c new file mode 100644 index 000000000..336c0b9bd --- /dev/null +++ b/gtk/src/chapters.c @@ -0,0 +1,308 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * chapters.c + * Copyright (C) John Stebbins 2008-2019 + * + * chapters.c is free software. + * + * You may redistribute it and/or modify it under the terms of the + * GNU General Public License, as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * chapters.c 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 main.c. If not, write to: + * The Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301, USA. + */ + +#include "ghbcompat.h" +#include "hb-backend.h" +#include "callbacks.h" +#include "jobdict.h" + +static void +chapter_changed_cb(GtkEditable * edit, signal_user_data_t *ud); + +#if GTK_CHECK_VERSION(3, 90, 0) +static gboolean +chapter_keypress_cb( + GtkEventController * keycon, + guint keyval, + guint keycode, + GdkModifierType state, + signal_user_data_t * ud); +#else +static gboolean +chapter_keypress_cb( + GtkWidget * widget, + GdkEvent * event, + signal_user_data_t * ud); +#endif + +static GtkWidget *find_widget(GtkWidget *widget, gchar *name) +{ + const char *wname; + GtkWidget *result = NULL; + + if (widget == NULL || name == NULL) + return NULL; + + wname = gtk_widget_get_name(widget); + if (wname != NULL && !strncmp(wname, name, 80)) + { + return widget; + } + if (GTK_IS_CONTAINER(widget)) + { + GList *list, *link; + link = list = gtk_container_get_children(GTK_CONTAINER(widget)); + while (link) + { + result = find_widget(GTK_WIDGET(link->data), name); + if (result != NULL) + break; + link = link->next; + } + g_list_free(list); + } + return result; +} + +static GtkListBoxRow * +list_box_get_row(GtkWidget *widget) +{ + while (widget != NULL && G_OBJECT_TYPE(widget) != GTK_TYPE_LIST_BOX_ROW) + { + widget = gtk_widget_get_parent(widget); + } + return GTK_LIST_BOX_ROW(widget); +} + +static GtkWidget * +create_chapter_row(int index, int64_t start, int64_t duration, + const char * name, signal_user_data_t * ud) +{ + GtkWidget * entry; + GtkWidget * row; + GtkBox * hbox; + GtkWidget * label; + gchar * str; + gint hh, mm, ss; + + row = gtk_list_box_row_new(); + hbox = GTK_BOX(gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6)); + + str = g_strdup_printf("%d", index); + label = gtk_label_new(str); + gtk_label_set_width_chars(GTK_LABEL(label), 5); + gtk_label_set_xalign(GTK_LABEL(label), 0); + ghb_box_append_child(hbox, label); + + ghb_break_duration(start, &hh, &mm, &ss); + str = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss); + label = gtk_label_new(str); + gtk_label_set_width_chars(GTK_LABEL(label), 10); + gtk_label_set_xalign(GTK_LABEL(label), 1); + ghb_box_append_child(hbox, label); + + ghb_break_duration(duration, &hh, &mm, &ss); + str = g_strdup_printf("%02d:%02d:%02d", hh, mm, ss); + label = gtk_label_new(str); + gtk_label_set_width_chars(GTK_LABEL(label), 10); + gtk_label_set_xalign(GTK_LABEL(label), 1); + ghb_box_append_child(hbox, label); + +#if GTK_CHECK_VERSION(3, 90, 0) + entry = gtk_text_new(); +#else + entry = gtk_entry_new(); +#endif + gtk_widget_set_name(entry, "chapter_entry"); + gtk_widget_set_margin_start(entry, 12); + gtk_widget_set_hexpand(entry, TRUE); + ghb_editable_set_text(entry, name); + ghb_box_append_child(hbox, entry); + +#if GTK_CHECK_VERSION(3, 90, 0) + GtkEventController * econ; + + econ = gtk_event_controller_key_new(); + gtk_widget_add_controller(entry, econ); + + g_signal_connect(econ, "key-pressed", G_CALLBACK(chapter_keypress_cb), ud); +#else + g_signal_connect(entry, "key-press-event", G_CALLBACK(chapter_keypress_cb), ud); +#endif + g_signal_connect(entry, "changed", G_CALLBACK(chapter_changed_cb), ud); + + gtk_container_add(GTK_CONTAINER(row), GTK_WIDGET(hbox)); +#if !GTK_CHECK_VERSION(3, 90, 0) + gtk_widget_show_all(row); +#endif + + return row; +} + +static void +ghb_clear_chapter_list_ui(signal_user_data_t * ud) +{ + GtkListBox * lb; + GtkListBoxRow * row; + + lb = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "chapters_list")); + while ((row = gtk_list_box_get_row_at_index(lb, 0)) != NULL) + { + gtk_container_remove(GTK_CONTAINER(lb), GTK_WIDGET(row)); + } +} + +static void +chapter_refresh_list_ui(signal_user_data_t *ud) +{ + GhbValue * chapter_list; + GtkListBox * lb; + GtkWidget * row; + gint ii, count; + + lb = GTK_LIST_BOX(GHB_WIDGET(ud->builder, "chapters_list")); + + chapter_list = ghb_get_job_chapter_list(ud->settings); + count = ghb_array_len(chapter_list); + for (ii = 0; ii < count; ii++) + { + GhbValue * chapter_dict; + GhbValue * duration_dict; + const char * name; + int64_t start = 0, duration; + + chapter_dict = ghb_array_get(chapter_list, ii); + name = ghb_dict_get_string(chapter_dict, "Name"); + duration_dict = ghb_dict_get(chapter_dict, "Duration"); + duration = ghb_dict_get_int(duration_dict, "Ticks") / 90000; + row = create_chapter_row(ii + 1, start, duration, name, ud); + start += duration; + + gtk_list_box_insert(lb, row, -1); + } +} + +void +ghb_chapter_list_refresh_all(signal_user_data_t *ud) +{ + ghb_clear_chapter_list_ui(ud); + chapter_refresh_list_ui(ud); +} + +static gboolean +chapter_keypress( + GtkWidget * widget, + guint keyval, + signal_user_data_t * ud) +{ + GtkWidget * entry; + GtkListBoxRow * row; + GtkListBox * lb; + int index; + + if (keyval != GDK_KEY_Return && + keyval != GDK_KEY_Down && + keyval != GDK_KEY_Up) + { + return FALSE; + } + + row = list_box_get_row(widget); + lb = GTK_LIST_BOX(gtk_widget_get_parent(GTK_WIDGET(row))); + index = gtk_list_box_row_get_index(row); + if (keyval == GDK_KEY_Return || keyval == GDK_KEY_Down) + { + index++; + } + else if (keyval == GDK_KEY_Up && index > 0) + { + index--; + } + if (index >= 0) + { + row = gtk_list_box_get_row_at_index(lb, index); + if (row != NULL) + { + entry = find_widget(GTK_WIDGET(row), "chapter_entry"); + if (entry != NULL) + { + gtk_widget_grab_focus(entry); + return TRUE; + } + } + } + return FALSE; +} + +#if GTK_CHECK_VERSION(3, 90, 0) +static gboolean +chapter_keypress_cb( + GtkEventController * keycon, + guint keyval, + guint keycode, + GdkModifierType state, + signal_user_data_t * ud) +{ + GtkWidget * widget; + + widget = gtk_event_controller_get_widget(keycon); + return chapter_keypress(widget, keyval, ud); +} +#else +static gboolean +chapter_keypress_cb( + GtkWidget * widget, + GdkEvent * event, + signal_user_data_t * ud) +{ + guint keyval; + + ghb_event_get_keyval(event, &keyval); + return chapter_keypress(widget, keyval, ud); +} +#endif + +static void +chapter_changed_cb( + GtkEditable * edit, + signal_user_data_t *ud) +{ + GtkListBoxRow * row; + const char * text; + int index; + + row = list_box_get_row(GTK_WIDGET(edit)); + if (row == NULL) + { + return; + } + index = gtk_list_box_row_get_index(row); + text = ghb_editable_get_text(edit); + if (text == NULL) + { + return; + } + + const GhbValue * chapter_list; + GhbValue * chapter_dict; + + chapter_list = ghb_get_job_chapter_list(ud->settings); + chapter_dict = ghb_array_get(chapter_list, index); + if (chapter_dict == NULL) + { + return; + } + ghb_dict_set_string(chapter_dict, "Name", text); +} + diff --git a/gtk/src/chapters.h b/gtk/src/chapters.h new file mode 100644 index 000000000..7286f8623 --- /dev/null +++ b/gtk/src/chapters.h @@ -0,0 +1,32 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * callbacks.h + * Copyright (C) John Stebbins 2008-2019 + * + * callbacks.h is free software. + * + * You may redistribute it and/or modify it under the terms of the + * GNU General Public License, as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * callbacks.h 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 callbacks.h. If not, write to: + * The Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301, USA. + */ + +#if !defined(_CHAPTERS_H_) +#define _CHAPTERS_H_ + +#include "settings.h" + +void ghb_chapter_list_refresh_all(signal_user_data_t *ud); + +#endif // _CHAPTERS_H_ diff --git a/gtk/src/ghb3.ui b/gtk/src/ghb3.ui index e7d1b8d95..23436e4a2 100644 --- a/gtk/src/ghb3.ui +++ b/gtk/src/ghb3.ui @@ -6357,6 +6357,75 @@ Only one subtitle track can be burned! Since conflicts can occur, the first chos 0 + + + True + False + + + 1 + + + + + horizontal + True + False + 6 + + + True + False + 5 + Index + 0 + + + 0 + + + + + True + False + 10 + Start + 1 + + + 1 + + + + + True + False + 10 + Duration + 1 + + + 2 + + + + + True + False + Title + 12 + True + 0 + + + 3 + + + + + 2 + + True @@ -6364,19 +6433,15 @@ Only one subtitle track can be burned! Since conflicts can occur, the first chos GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK True - + True True GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK - False - - - - 1 + 3 diff --git a/gtk/src/ghb4.ui b/gtk/src/ghb4.ui index abb3dc5e2..b8975f351 100644 --- a/gtk/src/ghb4.ui +++ b/gtk/src/ghb4.ui @@ -5414,19 +5414,66 @@ Only one subtitle track can be burned! Since conflicts can occur, the first chos + + + True + False + + + + + horizontal + True + False + 6 + + + True + False + 5 + Index + 0 + + + + + True + False + 10 + Start + 1 + + + + + True + False + 10 + Duration + 1 + + + + + True + False + Title + 12 + True + 0 + + + + True False True - + True True - False - - - diff --git a/gtk/src/ghbcellrenderertext.c b/gtk/src/ghbcellrenderertext.c deleted file mode 100644 index 79fd93410..000000000 --- a/gtk/src/ghbcellrenderertext.c +++ /dev/null @@ -1,2022 +0,0 @@ -/* - * ghbcellrenderertext.c - * Copyright (C) John Stebbins 2008-2019 - * - * ghbcellrenderertext.c is free software. - * - * You may redistribute it and/or modify it under the terms of the - * GNU General Public License, as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * ghbcellrenderertext.c 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 main.c. If not, write to: - * The Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301, USA. - */ - -#include -#include -#include "ghbcompat.h" -#include - -#include "marshalers.h" -#include "ghbcellrenderertext.h" - -#ifdef ENABLE_NLS -#define P_(String) dgettext(GETTEXT_PACKAGE "-properties",String) -#else -#define P_(String) (String) -#endif - -#define I_(string) g_intern_static_string (string) - -#define GTK_PARAM_READABLE G_PARAM_READABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB -#define GTK_PARAM_WRITABLE G_PARAM_WRITABLE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB -#define GTK_PARAM_READWRITE G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB - - -#define MyGdkRectangle const GdkRectangle - -static void ghb_cell_renderer_text_finalize (GObject *object); - -static void ghb_cell_renderer_text_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec); -static void ghb_cell_renderer_text_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec); -static void ghb_cell_renderer_text_get_size (GtkCellRenderer *cell, - GtkWidget *widget, - MyGdkRectangle *cell_area, - gint *x_offset, - gint *y_offset, - gint *width, - gint *height); -#if GTK_CHECK_VERSION(3, 90, 0) -static void ghb_cell_renderer_text_snapshot (GtkCellRenderer *cell, - GtkSnapshot *snapshot, - GtkWidget *widget, - MyGdkRectangle *background_area, - MyGdkRectangle *cell_area, - GtkCellRendererState flags); -#else -static void ghb_cell_renderer_text_render (GtkCellRenderer *cell, - cairo_t *cr, - GtkWidget *widget, - MyGdkRectangle *background_area, - MyGdkRectangle *cell_area, - GtkCellRendererState flags); -#endif -static GtkCellEditable *ghb_cell_renderer_text_start_editing (GtkCellRenderer *cell, - GdkEvent *event, - GtkWidget *widget, - const gchar *path, - MyGdkRectangle *background_area, - MyGdkRectangle *cell_area, - GtkCellRendererState flags); - -enum { - EDITED, - KEYPRESS, - LAST_SIGNAL -}; - -enum { - PROP_0, - - PROP_TEXT, - PROP_MARKUP, - PROP_ATTRIBUTES, - PROP_SINGLE_PARAGRAPH_MODE, - PROP_WIDTH_CHARS, - PROP_WRAP_WIDTH, - PROP_ALIGN, - - /* Style args */ - PROP_BACKGROUND, - PROP_FOREGROUND, - PROP_BACKGROUND_RGBA, - PROP_FOREGROUND_RGBA, - PROP_FONT, - PROP_FONT_DESC, - PROP_FAMILY, - PROP_STYLE, - PROP_VARIANT, - PROP_WEIGHT, - PROP_STRETCH, - PROP_SIZE, - PROP_SIZE_POINTS, - PROP_SCALE, - PROP_EDITABLE, - PROP_STRIKETHROUGH, - PROP_UNDERLINE, - PROP_RISE, - PROP_LANGUAGE, - PROP_ELLIPSIZE, - PROP_WRAP_MODE, - - /* Whether-a-style-arg-is-set args */ - PROP_BACKGROUND_SET, - PROP_FOREGROUND_SET, - PROP_FAMILY_SET, - PROP_STYLE_SET, - PROP_VARIANT_SET, - PROP_WEIGHT_SET, - PROP_STRETCH_SET, - PROP_SIZE_SET, - PROP_SCALE_SET, - PROP_EDITABLE_SET, - PROP_STRIKETHROUGH_SET, - PROP_UNDERLINE_SET, - PROP_RISE_SET, - PROP_LANGUAGE_SET, - PROP_ELLIPSIZE_SET, - PROP_ALIGN_SET -}; - -static guint text_cell_renderer_signals [LAST_SIGNAL]; - -#define GHB_CELL_RENDERER_TEXT_PATH "gtk-cell-renderer-text-path" - -typedef struct _GhbCellRendererTextPrivate GhbCellRendererTextPrivate; -struct _GhbCellRendererTextPrivate -{ - - gchar *text; - PangoFontDescription *font; - gdouble font_scale; - GdkRGBA foreground; - GdkRGBA background; - - PangoAttrList *extra_attrs; - - PangoUnderline underline_style; - - gint rise; - gint fixed_height_rows; - - guint strikethrough : 1; - - guint editable : 1; - - guint scale_set : 1; - - guint foreground_set : 1; - guint background_set : 1; - - guint underline_set : 1; - - guint rise_set : 1; - - guint strikethrough_set : 1; - - guint editable_set : 1; - guint calc_fixed_height : 1; - guint single_paragraph : 1; - guint language_set : 1; - guint markup_set : 1; - guint ellipsize_set : 1; - guint align_set : 1; - - gulong focus_out_id; - PangoLanguage *language; - PangoEllipsizeMode ellipsize; - PangoWrapMode wrap_mode; - PangoAlignment align; - - gulong populate_popup_id; - gulong entry_menu_popdown_timeout; - gboolean in_entry_menu; - - gint width_chars; - gint wrap_width; - - GtkWidget *entry; -}; - -G_DEFINE_TYPE_WITH_CODE (GhbCellRendererText, ghb_cell_renderer_text, - GTK_TYPE_CELL_RENDERER, - G_ADD_PRIVATE(GhbCellRendererText)) - -static void -ghb_cell_renderer_text_init (GhbCellRendererText *celltext) -{ - GhbCellRendererTextPrivate *priv; - - priv = ghb_cell_renderer_text_get_instance_private (celltext); - - g_object_set(celltext, "xalign", 0.0, NULL); - g_object_set(celltext, "yalign", 0.5, NULL); - g_object_set(celltext, "xpad", 2, NULL); - g_object_set(celltext, "ypad", 2, NULL); - priv->font_scale = 1.0; - priv->fixed_height_rows = -1; - priv->font = pango_font_description_new (); - - priv->width_chars = -1; - priv->wrap_width = -1; - priv->wrap_mode = PANGO_WRAP_CHAR; - priv->align = PANGO_ALIGN_LEFT; - priv->align_set = FALSE; -} - -static void -ghb_cell_renderer_text_class_init (GhbCellRendererTextClass *class) -{ - GObjectClass *object_class = G_OBJECT_CLASS (class); - GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (class); - - object_class->finalize = ghb_cell_renderer_text_finalize; - - object_class->get_property = ghb_cell_renderer_text_get_property; - object_class->set_property = ghb_cell_renderer_text_set_property; - - cell_class->get_size = ghb_cell_renderer_text_get_size; -#if GTK_CHECK_VERSION(3, 90, 0) - cell_class->snapshot = ghb_cell_renderer_text_snapshot; -#else - cell_class->render = ghb_cell_renderer_text_render; -#endif - cell_class->start_editing = ghb_cell_renderer_text_start_editing; - - g_object_class_install_property (object_class, - PROP_TEXT, - g_param_spec_string ("text", - P_("Text"), - P_("Text to render"), - NULL, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_MARKUP, - g_param_spec_string ("markup", - P_("Markup"), - P_("Marked up text to render"), - NULL, - GTK_PARAM_WRITABLE)); - - g_object_class_install_property (object_class, - PROP_ATTRIBUTES, - g_param_spec_boxed ("attributes", - P_("Attributes"), - P_("A list of style attributes to apply to the text of the renderer"), - PANGO_TYPE_ATTR_LIST, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_SINGLE_PARAGRAPH_MODE, - g_param_spec_boolean ("single-paragraph-mode", - P_("Single Paragraph Mode"), - P_("Whether or not to keep all text in a single paragraph"), - FALSE, - GTK_PARAM_READWRITE)); - - - g_object_class_install_property (object_class, - PROP_BACKGROUND, - g_param_spec_string ("background", - P_("Background color name"), - P_("Background color as a string"), - NULL, - GTK_PARAM_WRITABLE)); - - g_object_class_install_property (object_class, - PROP_BACKGROUND_RGBA, - g_param_spec_boxed ("background-rgba", - P_("Background color"), - P_("Background color as a GdkColor"), - GDK_TYPE_RGBA, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_FOREGROUND, - g_param_spec_string ("foreground", - P_("Foreground color name"), - P_("Foreground color as a string"), - NULL, - GTK_PARAM_WRITABLE)); - - g_object_class_install_property (object_class, - PROP_FOREGROUND_RGBA, - g_param_spec_boxed ("foreground-rgba", - P_("Foreground color"), - P_("Foreground color as a GdkColor"), - GDK_TYPE_RGBA, - GTK_PARAM_READWRITE)); - - - g_object_class_install_property (object_class, - PROP_EDITABLE, - g_param_spec_boolean ("editable", - P_("Editable"), - P_("Whether the text can be modified by the user"), - FALSE, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_FONT, - g_param_spec_string ("font", - P_("Font"), - P_("Font description as a string, e.g. \"Sans Italic 12\""), - NULL, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_FONT_DESC, - g_param_spec_boxed ("font-desc", - P_("Font"), - P_("Font description as a PangoFontDescription struct"), - PANGO_TYPE_FONT_DESCRIPTION, - GTK_PARAM_READWRITE)); - - - g_object_class_install_property (object_class, - PROP_FAMILY, - g_param_spec_string ("family", - P_("Font family"), - P_("Name of the font family, e.g. Sans, Helvetica, Times, Monospace"), - NULL, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_STYLE, - g_param_spec_enum ("style", - P_("Font style"), - P_("Font style"), - PANGO_TYPE_STYLE, - PANGO_STYLE_NORMAL, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_VARIANT, - g_param_spec_enum ("variant", - P_("Font variant"), - P_("Font variant"), - PANGO_TYPE_VARIANT, - PANGO_VARIANT_NORMAL, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_WEIGHT, - g_param_spec_int ("weight", - P_("Font weight"), - P_("Font weight"), - 0, - G_MAXINT, - PANGO_WEIGHT_NORMAL, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_STRETCH, - g_param_spec_enum ("stretch", - P_("Font stretch"), - P_("Font stretch"), - PANGO_TYPE_STRETCH, - PANGO_STRETCH_NORMAL, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_SIZE, - g_param_spec_int ("size", - P_("Font size"), - P_("Font size"), - 0, - G_MAXINT, - 0, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_SIZE_POINTS, - g_param_spec_double ("size-points", - P_("Font points"), - P_("Font size in points"), - 0.0, - G_MAXDOUBLE, - 0.0, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_SCALE, - g_param_spec_double ("scale", - P_("Font scale"), - P_("Font scaling factor"), - 0.0, - G_MAXDOUBLE, - 1.0, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_RISE, - g_param_spec_int ("rise", - P_("Rise"), - P_("Offset of text above the baseline " - "(below the baseline if rise is negative)"), - -G_MAXINT, - G_MAXINT, - 0, - GTK_PARAM_READWRITE)); - - - g_object_class_install_property (object_class, - PROP_STRIKETHROUGH, - g_param_spec_boolean ("strikethrough", - P_("Strikethrough"), - P_("Whether to strike through the text"), - FALSE, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_UNDERLINE, - g_param_spec_enum ("underline", - P_("Underline"), - P_("Style of underline for this text"), - PANGO_TYPE_UNDERLINE, - PANGO_UNDERLINE_NONE, - GTK_PARAM_READWRITE)); - - g_object_class_install_property (object_class, - PROP_LANGUAGE, - g_param_spec_string ("language", - P_("Language"), - P_("The language this text is in, as an ISO code. " - "Pango can use this as a hint when rendering the text. " - "If you don't understand this parameter, you probably don't need it"), - NULL, - GTK_PARAM_READWRITE)); - - - /** - * GhbCellRendererText:ellipsize: - * - * Specifies the preferred place to ellipsize the string, if the cell renderer - * does not have enough room to display the entire string. Setting it to - * %PANGO_ELLIPSIZE_NONE turns off ellipsizing. See the wrap-width property - * for another way of making the text fit into a given width. - * - * Since: 2.6 - */ - g_object_class_install_property (object_class, - PROP_ELLIPSIZE, - g_param_spec_enum ("ellipsize", - P_("Ellipsize"), - P_("The preferred place to ellipsize the string, " - "if the cell renderer does not have enough room " - "to display the entire string"), - PANGO_TYPE_ELLIPSIZE_MODE, - PANGO_ELLIPSIZE_NONE, - GTK_PARAM_READWRITE)); - - /** - * GhbCellRendererText:width-chars: - * - * The desired width of the cell, in characters. If this property is set to - * -1, the width will be calculated automatically, otherwise the cell will - * request either 3 characters or the property value, whichever is greater. - * - * Since: 2.6 - **/ - g_object_class_install_property (object_class, - PROP_WIDTH_CHARS, - g_param_spec_int ("width-chars", - P_("Width In Characters"), - P_("The desired width of the label, in characters"), - -1, - G_MAXINT, - -1, - GTK_PARAM_READWRITE)); - - /** - * GhbCellRendererText:wrap-mode: - * - * Specifies how to break the string into multiple lines, if the cell - * renderer does not have enough room to display the entire string. - * This property has no effect unless the wrap-width property is set. - * - * Since: 2.8 - */ - g_object_class_install_property (object_class, - PROP_WRAP_MODE, - g_param_spec_enum ("wrap-mode", - P_("Wrap mode"), - P_("How to break the string into multiple lines, " - "if the cell renderer does not have enough room " - "to display the entire string"), - PANGO_TYPE_WRAP_MODE, - PANGO_WRAP_CHAR, - GTK_PARAM_READWRITE)); - - /** - * GhbCellRendererText:wrap-width: - * - * Specifies the width at which the text is wrapped. The wrap-mode property can - * be used to influence at what character positions the line breaks can be placed. - * Setting wrap-width to -1 turns wrapping off. - * - * Since: 2.8 - */ - g_object_class_install_property (object_class, - PROP_WRAP_WIDTH, - g_param_spec_int ("wrap-width", - P_("Wrap width"), - P_("The width at which the text is wrapped"), - -1, - G_MAXINT, - -1, - GTK_PARAM_READWRITE)); - - /** - * GhbCellRendererText:alignment: - * - * Specifies how to align the lines of text with respect to each other. - * - * Note that this property describes how to align the lines of text in - * case there are several of them. The "xalign" property of #GtkCellRenderer, - * on the other hand, sets the horizontal alignment of the whole text. - * - * Since: 2.10 - */ - g_object_class_install_property (object_class, - PROP_ALIGN, - g_param_spec_enum ("alignment", - P_("Alignment"), - P_("How to align the lines"), - PANGO_TYPE_ALIGNMENT, - PANGO_ALIGN_LEFT, - GTK_PARAM_READWRITE)); - - /* Style props are set or not */ - -#define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (object_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, GTK_PARAM_READWRITE)) - - ADD_SET_PROP ("background-set", PROP_BACKGROUND_SET, - P_("Background set"), - P_("Whether this tag affects the background color")); - - ADD_SET_PROP ("foreground-set", PROP_FOREGROUND_SET, - P_("Foreground set"), - P_("Whether this tag affects the foreground color")); - - ADD_SET_PROP ("editable-set", PROP_EDITABLE_SET, - P_("Editability set"), - P_("Whether this tag affects text editability")); - - ADD_SET_PROP ("family-set", PROP_FAMILY_SET, - P_("Font family set"), - P_("Whether this tag affects the font family")); - - ADD_SET_PROP ("style-set", PROP_STYLE_SET, - P_("Font style set"), - P_("Whether this tag affects the font style")); - - ADD_SET_PROP ("variant-set", PROP_VARIANT_SET, - P_("Font variant set"), - P_("Whether this tag affects the font variant")); - - ADD_SET_PROP ("weight-set", PROP_WEIGHT_SET, - P_("Font weight set"), - P_("Whether this tag affects the font weight")); - - ADD_SET_PROP ("stretch-set", PROP_STRETCH_SET, - P_("Font stretch set"), - P_("Whether this tag affects the font stretch")); - - ADD_SET_PROP ("size-set", PROP_SIZE_SET, - P_("Font size set"), - P_("Whether this tag affects the font size")); - - ADD_SET_PROP ("scale-set", PROP_SCALE_SET, - P_("Font scale set"), - P_("Whether this tag scales the font size by a factor")); - - ADD_SET_PROP ("rise-set", PROP_RISE_SET, - P_("Rise set"), - P_("Whether this tag affects the rise")); - - ADD_SET_PROP ("strikethrough-set", PROP_STRIKETHROUGH_SET, - P_("Strikethrough set"), - P_("Whether this tag affects strikethrough")); - - ADD_SET_PROP ("underline-set", PROP_UNDERLINE_SET, - P_("Underline set"), - P_("Whether this tag affects underlining")); - - ADD_SET_PROP ("language-set", PROP_LANGUAGE_SET, - P_("Language set"), - P_("Whether this tag affects the language the text is rendered as")); - - ADD_SET_PROP ("ellipsize-set", PROP_ELLIPSIZE_SET, - P_("Ellipsize set"), - P_("Whether this tag affects the ellipsize mode")); - - ADD_SET_PROP ("align-set", PROP_ALIGN_SET, - P_("Align set"), - P_("Whether this tag affects the alignment mode")); - - /** - * GhbCellRendererText::edited - * @renderer: the object which received the signal - * @path: the path identifying the edited cell - * @new_text: the new text - * - * This signal is emitted after @renderer has been edited. - * - * It is the responsibility of the application to update the model - * and store @new_text at the position indicated by @path. - */ - text_cell_renderer_signals [EDITED] = - g_signal_new (I_("edited"), - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GhbCellRendererTextClass, edited), - NULL, NULL, - ghb_marshal_VOID__STRING_STRING, - G_TYPE_NONE, 2, - G_TYPE_STRING, - G_TYPE_STRING); - - text_cell_renderer_signals [KEYPRESS] = - g_signal_new (I_("key-press-event"), - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GhbCellRendererTextClass, keypress), - NULL, NULL, - ghb_marshal_BOOLEAN__BOXED, - G_TYPE_BOOLEAN, 1, - GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE); -} - -static void -ghb_cell_renderer_text_finalize (GObject *object) -{ - GhbCellRendererText *celltext = GHB_CELL_RENDERER_TEXT (object); - GhbCellRendererTextPrivate *priv; - - priv = ghb_cell_renderer_text_get_instance_private (celltext); - - pango_font_description_free (priv->font); - - g_free (priv->text); - - if (priv->extra_attrs) - pango_attr_list_unref (priv->extra_attrs); - - if (priv->language) - g_object_unref (priv->language); - - (* G_OBJECT_CLASS (ghb_cell_renderer_text_parent_class)->finalize) (object); -} - -static PangoFontMask -get_property_font_set_mask (guint prop_id) -{ - switch (prop_id) - { - case PROP_FAMILY_SET: - return PANGO_FONT_MASK_FAMILY; - case PROP_STYLE_SET: - return PANGO_FONT_MASK_STYLE; - case PROP_VARIANT_SET: - return PANGO_FONT_MASK_VARIANT; - case PROP_WEIGHT_SET: - return PANGO_FONT_MASK_WEIGHT; - case PROP_STRETCH_SET: - return PANGO_FONT_MASK_STRETCH; - case PROP_SIZE_SET: - return PANGO_FONT_MASK_SIZE; - } - - return 0; -} - -static void -ghb_cell_renderer_text_get_property (GObject *object, - guint param_id, - GValue *value, - GParamSpec *pspec) -{ - GhbCellRendererText *celltext = GHB_CELL_RENDERER_TEXT (object); - GhbCellRendererTextPrivate *priv; - - priv = ghb_cell_renderer_text_get_instance_private (celltext); - - switch (param_id) - { - case PROP_TEXT: - g_value_set_string (value, priv->text); - break; - - case PROP_ATTRIBUTES: - g_value_set_boxed (value, priv->extra_attrs); - break; - - case PROP_SINGLE_PARAGRAPH_MODE: - g_value_set_boolean (value, priv->single_paragraph); - break; - - case PROP_BACKGROUND_RGBA: - { - g_value_set_boxed(value, &priv->background); - } - break; - - case PROP_FOREGROUND_RGBA: - { - g_value_set_boxed(value, &priv->foreground); - } - break; - - case PROP_FONT: - g_value_take_string (value, pango_font_description_to_string (priv->font)); - break; - - case PROP_FONT_DESC: - g_value_set_boxed (value, priv->font); - break; - - case PROP_FAMILY: - g_value_set_string (value, pango_font_description_get_family (priv->font)); - break; - - case PROP_STYLE: - g_value_set_enum (value, pango_font_description_get_style (priv->font)); - break; - - case PROP_VARIANT: - g_value_set_enum (value, pango_font_description_get_variant (priv->font)); - break; - - case PROP_WEIGHT: - g_value_set_int (value, pango_font_description_get_weight (priv->font)); - break; - - case PROP_STRETCH: - g_value_set_enum (value, pango_font_description_get_stretch (priv->font)); - break; - - case PROP_SIZE: - g_value_set_int (value, pango_font_description_get_size (priv->font)); - break; - - case PROP_SIZE_POINTS: - g_value_set_double (value, ((double)pango_font_description_get_size (priv->font)) / (double)PANGO_SCALE); - break; - - case PROP_SCALE: - g_value_set_double (value, priv->font_scale); - break; - - case PROP_EDITABLE: - g_value_set_boolean (value, priv->editable); - break; - - case PROP_STRIKETHROUGH: - g_value_set_boolean (value, priv->strikethrough); - break; - - case PROP_UNDERLINE: - g_value_set_enum (value, priv->underline_style); - break; - - case PROP_RISE: - g_value_set_int (value, priv->rise); - break; - - case PROP_LANGUAGE: - g_value_set_static_string (value, pango_language_to_string (priv->language)); - break; - - case PROP_ELLIPSIZE: - g_value_set_enum (value, priv->ellipsize); - break; - - case PROP_WRAP_MODE: - g_value_set_enum (value, priv->wrap_mode); - break; - - case PROP_WRAP_WIDTH: - g_value_set_int (value, priv->wrap_width); - break; - - case PROP_ALIGN: - g_value_set_enum (value, priv->align); - break; - - case PROP_BACKGROUND_SET: - g_value_set_boolean (value, priv->background_set); - break; - - case PROP_FOREGROUND_SET: - g_value_set_boolean (value, priv->foreground_set); - break; - - case PROP_FAMILY_SET: - case PROP_STYLE_SET: - case PROP_VARIANT_SET: - case PROP_WEIGHT_SET: - case PROP_STRETCH_SET: - case PROP_SIZE_SET: - { - PangoFontMask mask = get_property_font_set_mask (param_id); - g_value_set_boolean (value, (pango_font_description_get_set_fields (priv->font) & mask) != 0); - - break; - } - - case PROP_SCALE_SET: - g_value_set_boolean (value, priv->scale_set); - break; - - case PROP_EDITABLE_SET: - g_value_set_boolean (value, priv->editable_set); - break; - - case PROP_STRIKETHROUGH_SET: - g_value_set_boolean (value, priv->strikethrough_set); - break; - - case PROP_UNDERLINE_SET: - g_value_set_boolean (value, priv->underline_set); - break; - - case PROP_RISE_SET: - g_value_set_boolean (value, priv->rise_set); - break; - - case PROP_LANGUAGE_SET: - g_value_set_boolean (value, priv->language_set); - break; - - case PROP_ELLIPSIZE_SET: - g_value_set_boolean (value, priv->ellipsize_set); - break; - - case PROP_ALIGN_SET: - g_value_set_boolean (value, priv->align_set); - break; - - case PROP_WIDTH_CHARS: - g_value_set_int (value, priv->width_chars); - break; - - case PROP_BACKGROUND: - case PROP_FOREGROUND: - case PROP_MARKUP: - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - } -} - - -static void -set_bg_color (GhbCellRendererText *celltext, - GdkRGBA *rgba) -{ - GhbCellRendererTextPrivate *priv; - - priv = ghb_cell_renderer_text_get_instance_private (celltext); - if (rgba) - { - if (!priv->background_set) - { - priv->background_set = TRUE; - g_object_notify (G_OBJECT (celltext), "background-set"); - } - - priv->background = *rgba; - } - else - { - if (priv->background_set) - { - priv->background_set = FALSE; - g_object_notify (G_OBJECT (celltext), "background-set"); - } - } -} - - -static void -set_fg_color (GhbCellRendererText *celltext, - GdkRGBA *rgba) -{ - GhbCellRendererTextPrivate *priv; - - priv = ghb_cell_renderer_text_get_instance_private (celltext); - if (rgba) - { - if (!priv->foreground_set) - { - priv->foreground_set = TRUE; - g_object_notify (G_OBJECT (celltext), "foreground-set"); - } - - priv->foreground = *rgba; - } - else - { - if (priv->foreground_set) - { - priv->foreground_set = FALSE; - g_object_notify (G_OBJECT (celltext), "foreground-set"); - } - } -} - -static PangoFontMask -set_font_desc_fields (PangoFontDescription *desc, - PangoFontMask to_set) -{ - PangoFontMask changed_mask = 0; - - if (to_set & PANGO_FONT_MASK_FAMILY) - { - const char *family = pango_font_description_get_family (desc); - if (!family) - { - family = "sans"; - changed_mask |= PANGO_FONT_MASK_FAMILY; - } - - pango_font_description_set_family (desc, family); - } - if (to_set & PANGO_FONT_MASK_STYLE) - pango_font_description_set_style (desc, pango_font_description_get_style (desc)); - if (to_set & PANGO_FONT_MASK_VARIANT) - pango_font_description_set_variant (desc, pango_font_description_get_variant (desc)); - if (to_set & PANGO_FONT_MASK_WEIGHT) - pango_font_description_set_weight (desc, pango_font_description_get_weight (desc)); - if (to_set & PANGO_FONT_MASK_STRETCH) - pango_font_description_set_stretch (desc, pango_font_description_get_stretch (desc)); - if (to_set & PANGO_FONT_MASK_SIZE) - { - gint size = pango_font_description_get_size (desc); - if (size <= 0) - { - size = 10 * PANGO_SCALE; - changed_mask |= PANGO_FONT_MASK_SIZE; - } - - pango_font_description_set_size (desc, size); - } - - return changed_mask; -} - -static void -notify_set_changed (GObject *object, - PangoFontMask changed_mask) -{ - if (changed_mask & PANGO_FONT_MASK_FAMILY) - g_object_notify (object, "family-set"); - if (changed_mask & PANGO_FONT_MASK_STYLE) - g_object_notify (object, "style-set"); - if (changed_mask & PANGO_FONT_MASK_VARIANT) - g_object_notify (object, "variant-set"); - if (changed_mask & PANGO_FONT_MASK_WEIGHT) - g_object_notify (object, "weight-set"); - if (changed_mask & PANGO_FONT_MASK_STRETCH) - g_object_notify (object, "stretch-set"); - if (changed_mask & PANGO_FONT_MASK_SIZE) - g_object_notify (object, "size-set"); -} - -static void -notify_fields_changed (GObject *object, - PangoFontMask changed_mask) -{ - if (changed_mask & PANGO_FONT_MASK_FAMILY) - g_object_notify (object, "family"); - if (changed_mask & PANGO_FONT_MASK_STYLE) - g_object_notify (object, "style"); - if (changed_mask & PANGO_FONT_MASK_VARIANT) - g_object_notify (object, "variant"); - if (changed_mask & PANGO_FONT_MASK_WEIGHT) - g_object_notify (object, "weight"); - if (changed_mask & PANGO_FONT_MASK_STRETCH) - g_object_notify (object, "stretch"); - if (changed_mask & PANGO_FONT_MASK_SIZE) - g_object_notify (object, "size"); -} - -static void -set_font_description (GhbCellRendererText *celltext, - PangoFontDescription *font_desc) -{ - GObject *object = G_OBJECT (celltext); - PangoFontDescription *new_font_desc; - PangoFontMask old_mask, new_mask, changed_mask, set_changed_mask; - GhbCellRendererTextPrivate *priv; - - priv = ghb_cell_renderer_text_get_instance_private (celltext); - - if (font_desc) - new_font_desc = pango_font_description_copy (font_desc); - else - new_font_desc = pango_font_description_new (); - - old_mask = pango_font_description_get_set_fields (priv->font); - new_mask = pango_font_description_get_set_fields (new_font_desc); - - changed_mask = old_mask | new_mask; - set_changed_mask = old_mask ^ new_mask; - - pango_font_description_free (priv->font); - priv->font = new_font_desc; - - g_object_freeze_notify (object); - - g_object_notify (object, "font-desc"); - g_object_notify (object, "font"); - - if (changed_mask & PANGO_FONT_MASK_FAMILY) - g_object_notify (object, "family"); - if (changed_mask & PANGO_FONT_MASK_STYLE) - g_object_notify (object, "style"); - if (changed_mask & PANGO_FONT_MASK_VARIANT) - g_object_notify (object, "variant"); - if (changed_mask & PANGO_FONT_MASK_WEIGHT) - g_object_notify (object, "weight"); - if (changed_mask & PANGO_FONT_MASK_STRETCH) - g_object_notify (object, "stretch"); - if (changed_mask & PANGO_FONT_MASK_SIZE) - { - g_object_notify (object, "size"); - g_object_notify (object, "size-points"); - } - - notify_set_changed (object, set_changed_mask); - - g_object_thaw_notify (object); -} - -static void -ghb_cell_renderer_text_set_property (GObject *object, - guint param_id, - const GValue *value, - GParamSpec *pspec) -{ - GhbCellRendererText *celltext = GHB_CELL_RENDERER_TEXT (object); - GhbCellRendererTextPrivate *priv; - - priv = ghb_cell_renderer_text_get_instance_private (celltext); - - switch (param_id) - { - case PROP_TEXT: - g_free (priv->text); - - if (priv->markup_set) - { - if (priv->extra_attrs) - pango_attr_list_unref (priv->extra_attrs); - priv->extra_attrs = NULL; - priv->markup_set = FALSE; - } - - priv->text = g_strdup (g_value_get_string (value)); - g_object_notify (object, "text"); - break; - - case PROP_ATTRIBUTES: - if (priv->extra_attrs) - pango_attr_list_unref (priv->extra_attrs); - - priv->extra_attrs = g_value_get_boxed (value); - if (priv->extra_attrs) - pango_attr_list_ref (priv->extra_attrs); - break; - case PROP_MARKUP: - { - const gchar *str; - gchar *text = NULL; - GError *error = NULL; - PangoAttrList *attrs = NULL; - - str = g_value_get_string (value); - if (str && !pango_parse_markup (str, - -1, - 0, - &attrs, - &text, - NULL, - &error)) - { - g_warning ("Failed to set text from markup due to error parsing markup: %s", - error->message); - g_error_free (error); - return; - } - - g_free (priv->text); - - if (priv->extra_attrs) - pango_attr_list_unref (priv->extra_attrs); - - priv->text = text; - priv->extra_attrs = attrs; - priv->markup_set = TRUE; - } - break; - - case PROP_SINGLE_PARAGRAPH_MODE: - priv->single_paragraph = g_value_get_boolean (value); - break; - - case PROP_BACKGROUND: - { - GdkRGBA rgba; - - if (!g_value_get_string (value)) - set_bg_color (celltext, NULL); /* reset to background_set to FALSE */ - else if (gdk_rgba_parse(&rgba, g_value_get_string(value))) - set_bg_color (celltext, &rgba); - else - g_warning ("Don't know color `%s'", g_value_get_string(value)); - - g_object_notify (object, "background-rgba"); - } - break; - - case PROP_FOREGROUND: - { - GdkRGBA rgba; - - if (!g_value_get_string (value)) - set_fg_color (celltext, NULL); /* reset to foreground_set to FALSE */ - else if (gdk_rgba_parse(&rgba, g_value_get_string(value))) - set_fg_color (celltext, &rgba); - else - g_warning ("Don't know color `%s'", g_value_get_string (value)); - - g_object_notify (object, "foreground-rgba"); - } - break; - - case PROP_BACKGROUND_RGBA: - /* This notifies the GObject itself. */ - set_bg_color (celltext, g_value_get_boxed (value)); - break; - - case PROP_FOREGROUND_RGBA: - /* This notifies the GObject itself. */ - set_fg_color (celltext, g_value_get_boxed (value)); - break; - - case PROP_FONT: - { - PangoFontDescription *font_desc = NULL; - const gchar *name; - - name = g_value_get_string (value); - - if (name) - font_desc = pango_font_description_from_string (name); - - set_font_description (celltext, font_desc); - - pango_font_description_free (font_desc); - - if (priv->fixed_height_rows != -1) - priv->calc_fixed_height = TRUE; - } - break; - - case PROP_FONT_DESC: - set_font_description (celltext, g_value_get_boxed (value)); - - if (priv->fixed_height_rows != -1) - priv->calc_fixed_height = TRUE; - break; - - case PROP_FAMILY: - case PROP_STYLE: - case PROP_VARIANT: - case PROP_WEIGHT: - case PROP_STRETCH: - case PROP_SIZE: - case PROP_SIZE_POINTS: - { - PangoFontMask old_set_mask = pango_font_description_get_set_fields (priv->font); - - switch (param_id) - { - case PROP_FAMILY: - pango_font_description_set_family (priv->font, - g_value_get_string (value)); - break; - case PROP_STYLE: - pango_font_description_set_style (priv->font, - g_value_get_enum (value)); - break; - case PROP_VARIANT: - pango_font_description_set_variant (priv->font, - g_value_get_enum (value)); - break; - case PROP_WEIGHT: - pango_font_description_set_weight (priv->font, - g_value_get_int (value)); - break; - case PROP_STRETCH: - pango_font_description_set_stretch (priv->font, - g_value_get_enum (value)); - break; - case PROP_SIZE: - pango_font_description_set_size (priv->font, - g_value_get_int (value)); - g_object_notify (object, "size-points"); - break; - case PROP_SIZE_POINTS: - pango_font_description_set_size (priv->font, - g_value_get_double (value) * PANGO_SCALE); - g_object_notify (object, "size"); - break; - } - - if (priv->fixed_height_rows != -1) - priv->calc_fixed_height = TRUE; - - notify_set_changed (object, old_set_mask & pango_font_description_get_set_fields (priv->font)); - g_object_notify (object, "font-desc"); - g_object_notify (object, "font"); - - break; - } - - case PROP_SCALE: - priv->font_scale = g_value_get_double (value); - priv->scale_set = TRUE; - if (priv->fixed_height_rows != -1) - priv->calc_fixed_height = TRUE; - g_object_notify (object, "scale-set"); - break; - - case PROP_EDITABLE: - priv->editable = g_value_get_boolean (value); - priv->editable_set = TRUE; - if (priv->editable) - g_object_set(celltext, "mode", GTK_CELL_RENDERER_MODE_EDITABLE, NULL); - else - g_object_set(celltext, "mode", GTK_CELL_RENDERER_MODE_INERT, NULL); - g_object_notify (object, "editable-set"); - break; - - case PROP_STRIKETHROUGH: - priv->strikethrough = g_value_get_boolean (value); - priv->strikethrough_set = TRUE; - g_object_notify (object, "strikethrough-set"); - break; - - case PROP_UNDERLINE: - priv->underline_style = g_value_get_enum (value); - priv->underline_set = TRUE; - g_object_notify (object, "underline-set"); - - break; - - case PROP_RISE: - priv->rise = g_value_get_int (value); - priv->rise_set = TRUE; - g_object_notify (object, "rise-set"); - if (priv->fixed_height_rows != -1) - priv->calc_fixed_height = TRUE; - break; - - case PROP_LANGUAGE: - priv->language_set = TRUE; - if (priv->language) - g_object_unref (priv->language); - priv->language = pango_language_from_string (g_value_get_string (value)); - g_object_notify (object, "language-set"); - break; - - case PROP_ELLIPSIZE: - priv->ellipsize = g_value_get_enum (value); - priv->ellipsize_set = TRUE; - g_object_notify (object, "ellipsize-set"); - break; - - case PROP_WRAP_MODE: - priv->wrap_mode = g_value_get_enum (value); - break; - - case PROP_WRAP_WIDTH: - priv->wrap_width = g_value_get_int (value); - break; - - case PROP_WIDTH_CHARS: - priv->width_chars = g_value_get_int (value); - break; - - case PROP_ALIGN: - priv->align = g_value_get_enum (value); - priv->align_set = TRUE; - g_object_notify (object, "align-set"); - break; - - case PROP_BACKGROUND_SET: - priv->background_set = g_value_get_boolean (value); - break; - - case PROP_FOREGROUND_SET: - priv->foreground_set = g_value_get_boolean (value); - break; - - case PROP_FAMILY_SET: - case PROP_STYLE_SET: - case PROP_VARIANT_SET: - case PROP_WEIGHT_SET: - case PROP_STRETCH_SET: - case PROP_SIZE_SET: - if (!g_value_get_boolean (value)) - { - pango_font_description_unset_fields (priv->font, - get_property_font_set_mask (param_id)); - } - else - { - PangoFontMask changed_mask; - - changed_mask = set_font_desc_fields (priv->font, - get_property_font_set_mask (param_id)); - notify_fields_changed (G_OBJECT (celltext), changed_mask); - } - break; - - case PROP_SCALE_SET: - priv->scale_set = g_value_get_boolean (value); - break; - - case PROP_EDITABLE_SET: - priv->editable_set = g_value_get_boolean (value); - break; - - case PROP_STRIKETHROUGH_SET: - priv->strikethrough_set = g_value_get_boolean (value); - break; - - case PROP_UNDERLINE_SET: - priv->underline_set = g_value_get_boolean (value); - break; - - case PROP_RISE_SET: - priv->rise_set = g_value_get_boolean (value); - break; - - case PROP_LANGUAGE_SET: - priv->language_set = g_value_get_boolean (value); - break; - - case PROP_ELLIPSIZE_SET: - priv->ellipsize_set = g_value_get_boolean (value); - break; - - case PROP_ALIGN_SET: - priv->align_set = g_value_get_boolean (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec); - break; - } -} - -/** - * ghb_cell_renderer_text_new: - * - * Creates a new #GhbCellRendererText. Adjust how text is drawn using - * object properties. Object properties can be - * set globally (with g_object_set()). Also, with #GtkTreeViewColumn, - * you can bind a property to a value in a #GtkTreeModel. For example, - * you can bind the "text" property on the cell renderer to a string - * value in the model, thus rendering a different string in each row - * of the #GtkTreeView - * - * Return value: the new cell renderer - **/ -GtkCellRenderer * -ghb_cell_renderer_text_new (void) -{ - return g_object_new (GHB_TYPE_CELL_RENDERER_TEXT, NULL); -} - -static void -add_attr (PangoAttrList *attr_list, - PangoAttribute *attr) -{ - attr->start_index = 0; - attr->end_index = G_MAXINT; - - pango_attr_list_insert (attr_list, attr); -} - -static PangoLayout* -get_layout (GhbCellRendererText *celltext, - GtkWidget *widget, - gboolean will_render, - GtkCellRendererState flags) -{ - PangoAttrList *attr_list; - PangoLayout *layout; - PangoUnderline uline; - GhbCellRendererTextPrivate *priv; - - priv = ghb_cell_renderer_text_get_instance_private (celltext); - - layout = gtk_widget_create_pango_layout (widget, priv->text); - - if (priv->extra_attrs) - attr_list = pango_attr_list_copy (priv->extra_attrs); - else - attr_list = pango_attr_list_new (); - - pango_layout_set_single_paragraph_mode (layout, priv->single_paragraph); - - if (will_render) - { - /* Add options that affect appearance but not size */ - - /* note that background doesn't go here, since it affects - * background_area not the PangoLayout area - */ - - if (priv->foreground_set - && (flags & GTK_CELL_RENDERER_SELECTED) == 0) - { - add_attr(attr_list, - pango_attr_foreground_new(priv->foreground.red, - priv->foreground.green, - priv->foreground.blue)); - } - - if (priv->strikethrough_set) - add_attr (attr_list, - pango_attr_strikethrough_new (priv->strikethrough)); - } - - add_attr (attr_list, pango_attr_font_desc_new (priv->font)); - - if (priv->scale_set && - priv->font_scale != 1.0) - add_attr (attr_list, pango_attr_scale_new (priv->font_scale)); - - if (priv->underline_set) - uline = priv->underline_style; - else - uline = PANGO_UNDERLINE_NONE; - - if (priv->language_set) - add_attr (attr_list, pango_attr_language_new (priv->language)); - - if ((flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT) - { - switch (uline) - { - case PANGO_UNDERLINE_NONE: - uline = PANGO_UNDERLINE_SINGLE; - break; - - case PANGO_UNDERLINE_SINGLE: - uline = PANGO_UNDERLINE_DOUBLE; - break; - - default: - break; - } - } - - if (uline != PANGO_UNDERLINE_NONE) - add_attr (attr_list, pango_attr_underline_new (priv->underline_style)); - - if (priv->rise_set) - add_attr (attr_list, pango_attr_rise_new (priv->rise)); - - if (priv->ellipsize_set) - pango_layout_set_ellipsize (layout, priv->ellipsize); - else - pango_layout_set_ellipsize (layout, PANGO_ELLIPSIZE_NONE); - - if (priv->wrap_width != -1) - { - pango_layout_set_width (layout, priv->wrap_width * PANGO_SCALE); - pango_layout_set_wrap (layout, priv->wrap_mode); - } - else - { - pango_layout_set_width (layout, -1); - pango_layout_set_wrap (layout, PANGO_WRAP_CHAR); - } - - if (priv->align_set) - pango_layout_set_alignment (layout, priv->align); - else - { - PangoAlignment align; - - if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) - align = PANGO_ALIGN_RIGHT; - else - align = PANGO_ALIGN_LEFT; - - pango_layout_set_alignment (layout, align); - } - - pango_layout_set_attributes (layout, attr_list); - - pango_attr_list_unref (attr_list); - - return layout; -} - -static void -get_size (GtkCellRenderer *cell, - GtkWidget *widget, - MyGdkRectangle *cell_area, - PangoLayout *layout, - gint *x_offset, - gint *y_offset, - gint *width, - gint *height) -{ - GhbCellRendererText *celltext = (GhbCellRendererText *) cell; - PangoRectangle rect; - GhbCellRendererTextPrivate *priv; - - priv = ghb_cell_renderer_text_get_instance_private (celltext); - - gint cell_width, cell_height, cell_xpad, cell_ypad; - gfloat cell_xalign, cell_yalign; - - gtk_cell_renderer_get_fixed_size(cell, &cell_width, &cell_height); - gtk_cell_renderer_get_alignment(cell, &cell_xalign, &cell_yalign); - gtk_cell_renderer_get_padding(cell, &cell_xpad, &cell_ypad); - - if (priv->calc_fixed_height) - { - PangoContext *context; - PangoFontMetrics *metrics; - PangoFontDescription *font_desc; - gint row_height; - - font_desc = pango_font_description_copy_static(ghb_widget_get_font(widget)); - pango_font_description_merge_static(font_desc, priv->font, TRUE); - - if (priv->scale_set) - pango_font_description_set_size (font_desc, - priv->font_scale * pango_font_description_get_size (font_desc)); - - context = gtk_widget_get_pango_context (widget); - - metrics = pango_context_get_metrics (context, - font_desc, - pango_context_get_language (context)); - row_height = (pango_font_metrics_get_ascent (metrics) + - pango_font_metrics_get_descent (metrics)); - pango_font_metrics_unref (metrics); - - pango_font_description_free (font_desc); - - gtk_cell_renderer_set_fixed_size (cell, - cell_width, 2*cell_ypad + - priv->fixed_height_rows * PANGO_PIXELS (row_height)); - - if (height) - { - *height = cell_height; - height = NULL; - } - priv->calc_fixed_height = FALSE; - if (width == NULL) - return; - } - - if (layout) - g_object_ref (layout); - else - layout = get_layout (celltext, widget, FALSE, 0); - - pango_layout_get_pixel_extents(layout, NULL, &rect); - - if (cell_area) - { - rect.height = MIN(rect.height, cell_area->height - 2 * cell_ypad); - rect.width = MIN(rect.width, cell_area->width - 2 * cell_xpad); - - if (x_offset) - { - if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL) - *x_offset = (1.0 - cell_xalign) * (cell_area->width - (2 * cell_xpad)); - else - *x_offset = cell_xalign * (cell_area->width - (2 * cell_xpad)); - - if ((priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE) || priv->wrap_width != -1) - *x_offset = MAX(*x_offset, 0); - } - if (y_offset) - { - *y_offset = cell_yalign * (cell_area->height - (rect.height + (2 * cell_ypad))); - *y_offset = MAX (*y_offset, 0); - } - } - else - { - if (x_offset) *x_offset = 0; - if (y_offset) *y_offset = 0; - } - - if (height) - *height = cell_ypad * 2 + rect.height; - - if (width) - *width = cell_xpad * 2 + rect.width; - - g_object_unref (layout); -} - - -static void -ghb_cell_renderer_text_get_size (GtkCellRenderer *cell, - GtkWidget *widget, - MyGdkRectangle *cell_area, - gint *x_offset, - gint *y_offset, - gint *width, - gint *height) -{ - get_size (cell, widget, cell_area, NULL, - x_offset, y_offset, width, height); -} - -#if GTK_CHECK_VERSION(3, 90, 0) -static void ghb_cell_renderer_text_snapshot( - GtkCellRenderer *cell, - GtkSnapshot *snapshot, - GtkWidget *widget, - MyGdkRectangle *background_area, - MyGdkRectangle *cell_area, - GtkCellRendererState flags) -{ - GhbCellRendererText * celltext = (GhbCellRendererText *) cell; - GhbCellRendererTextPrivate * priv; - GtkStyleContext * context; - PangoLayout * layout; - gint x_offset = 0; - gint y_offset = 0; - gint xpad, ypad; - PangoRectangle rect; - - priv = ghb_cell_renderer_text_get_instance_private (celltext); - - layout = get_layout (celltext, widget, TRUE, flags); - get_size(cell, widget, cell_area, layout, &x_offset, &y_offset, NULL, NULL); - context = gtk_widget_get_style_context(widget); - - if (priv->background_set && (flags & GTK_CELL_RENDERER_SELECTED) == 0) - { - gtk_snapshot_append_color(snapshot, - &priv->background, - &GRAPHENE_RECT_INIT( - background_area->x, background_area->y, - background_area->width, - background_area->height)); - } - - - gtk_cell_renderer_get_padding(cell, &xpad, &ypad); - - if (priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE) - pango_layout_set_width(layout, - (cell_area->width - x_offset - 2 * xpad) * PANGO_SCALE); - else if (priv->wrap_width == -1) - pango_layout_set_width(layout, -1); - - pango_layout_get_pixel_extents (layout, NULL, &rect); - x_offset = x_offset - rect.x; - - gtk_snapshot_push_clip(snapshot, - &GRAPHENE_RECT_INIT( - cell_area->x, cell_area->y, - cell_area->width, cell_area->height)); - - gtk_snapshot_render_layout(snapshot, context, - cell_area->x + x_offset + xpad, - cell_area->y + y_offset + ypad, layout); - - gtk_snapshot_pop(snapshot); - - g_object_unref(layout); -} -#else -static void ghb_cell_renderer_text_render( - GtkCellRenderer *cell, - cairo_t *cr, - GtkWidget *widget, - MyGdkRectangle *background_area, - MyGdkRectangle *cell_area, - GtkCellRendererState flags) -{ - GhbCellRendererText *celltext = (GhbCellRendererText *) cell; - PangoLayout *layout; - gint x_offset = 0; - gint y_offset = 0; - GhbCellRendererTextPrivate *priv; - - priv = ghb_cell_renderer_text_get_instance_private (celltext); - - layout = get_layout (celltext, widget, TRUE, flags); - get_size(cell, widget, cell_area, layout, &x_offset, &y_offset, NULL, NULL); - - gint xpad, ypad; -#if 0 - GtkStateType state; - gboolean sensitive; - - sensitive = gtk_cell_renderer_get_sensitive(cell); - if (!sensitive) - { - state = GTK_STATE_INSENSITIVE; - } - else if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED) - { - if (gtk_widget_has_focus (widget)) - state = GTK_STATE_SELECTED; - else - state = GTK_STATE_ACTIVE; - } - else if ((flags & GTK_CELL_RENDERER_PRELIT) == GTK_CELL_RENDERER_PRELIT && - gtk_widget_get_state(widget) == GTK_STATE_PRELIGHT) - { - state = GTK_STATE_PRELIGHT; - } - else - { - if (gtk_widget_get_state(widget) == GTK_STATE_INSENSITIVE) - state = GTK_STATE_INSENSITIVE; - else - state = GTK_STATE_NORMAL; - } -#endif - - gtk_cell_renderer_get_padding(cell, &xpad, &ypad); - - if (priv->background_set && - (flags & GTK_CELL_RENDERER_SELECTED) == 0) - { - gdk_cairo_rectangle (cr, background_area); - cairo_set_source_rgb (cr, - priv->background.red / 65535., - priv->background.green / 65535., - priv->background.blue / 65535.); - cairo_fill (cr); - } - - if (priv->ellipsize_set && priv->ellipsize != PANGO_ELLIPSIZE_NONE) - pango_layout_set_width (layout, - (cell_area->width - x_offset - 2 * xpad) * PANGO_SCALE); - else if (priv->wrap_width == -1) - pango_layout_set_width (layout, -1); - - gtk_render_layout(gtk_widget_get_style_context(widget), - cr, - cell_area->x + x_offset + xpad, - cell_area->y + y_offset + ypad, - layout); - - g_object_unref (layout); -} -#endif - -static gboolean -ghb_cell_renderer_text_keypress( - GtkCellEditable *entry, - GdkEventKey *event, - gpointer data) -{ - gboolean result; - g_signal_emit( - data, text_cell_renderer_signals[KEYPRESS], 0, event, &result); - return result; -} - -static void -ghb_cell_renderer_text_editing_done (GtkCellEditable *entry, - gpointer data) -{ - const gchar *path; - const gchar *new_text; - GhbCellRendererTextPrivate *priv; - - priv = ghb_cell_renderer_text_get_instance_private(GHB_CELL_RENDERER_TEXT(data)); - - priv->entry = NULL; - - if (priv->focus_out_id > 0) - { - g_signal_handler_disconnect (entry, priv->focus_out_id); - priv->focus_out_id = 0; - } - - if (priv->populate_popup_id > 0) - { - g_signal_handler_disconnect (entry, priv->populate_popup_id); - priv->populate_popup_id = 0; - } - - if (priv->entry_menu_popdown_timeout) - { - g_source_remove (priv->entry_menu_popdown_timeout); - priv->entry_menu_popdown_timeout = 0; - } - - gboolean editing_canceled; - g_object_get(entry, "editing-canceled", &editing_canceled, NULL); - gtk_cell_renderer_stop_editing (GTK_CELL_RENDERER (data), - editing_canceled); - if (editing_canceled) - return; - - path = g_object_get_data (G_OBJECT (entry), GHB_CELL_RENDERER_TEXT_PATH); - new_text = ghb_editable_get_text(entry); - - g_signal_emit (data, text_cell_renderer_signals[EDITED], 0, path, new_text); -} - -static gboolean -popdown_timeout (gpointer data) -{ - GhbCellRendererTextPrivate *priv; - - priv = ghb_cell_renderer_text_get_instance_private(GHB_CELL_RENDERER_TEXT(data)); - - priv->entry_menu_popdown_timeout = 0; - - if (!gtk_widget_has_focus (priv->entry)) - ghb_cell_renderer_text_editing_done (GTK_CELL_EDITABLE (priv->entry), data); - - return FALSE; -} - -static void -ghb_cell_renderer_text_popup_unmap (GtkMenu *menu, - gpointer data) -{ - GhbCellRendererTextPrivate *priv; - - priv = ghb_cell_renderer_text_get_instance_private(GHB_CELL_RENDERER_TEXT(data)); - - priv->in_entry_menu = FALSE; - - if (priv->entry_menu_popdown_timeout) - return; - - priv->entry_menu_popdown_timeout = g_timeout_add(500, popdown_timeout, data); -} - -static void -ghb_cell_renderer_text_populate_popup (GtkEntry *entry, - GtkMenu *menu, - gpointer data) -{ - GhbCellRendererTextPrivate *priv; - - priv = ghb_cell_renderer_text_get_instance_private(GHB_CELL_RENDERER_TEXT(data)); - - if (priv->entry_menu_popdown_timeout) - { - g_source_remove (priv->entry_menu_popdown_timeout); - priv->entry_menu_popdown_timeout = 0; - } - - priv->in_entry_menu = TRUE; - - g_signal_connect (menu, "unmap", - G_CALLBACK (ghb_cell_renderer_text_popup_unmap), data); -} - -static gboolean -ghb_cell_renderer_text_focus_out_event (GtkWidget *entry, - GdkEvent *event, - gpointer data) -{ - GhbCellRendererTextPrivate *priv; - - priv = ghb_cell_renderer_text_get_instance_private(GHB_CELL_RENDERER_TEXT(data)); - - if (priv->in_entry_menu) - return FALSE; - - g_object_set(entry, "editing-canceled", TRUE, NULL); - gtk_cell_editable_remove_widget (GTK_CELL_EDITABLE (entry)); - gtk_cell_editable_editing_done (GTK_CELL_EDITABLE (entry)); - - /* entry needs focus-out-event */ - return FALSE; -} - -static GtkCellEditable * -ghb_cell_renderer_text_start_editing (GtkCellRenderer *cell, - GdkEvent *event, - GtkWidget *widget, - const gchar *path, - MyGdkRectangle *background_area, - MyGdkRectangle *cell_area, - GtkCellRendererState flags) -{ - GhbCellRendererText *celltext; - GhbCellRendererTextPrivate *priv; - - celltext = GHB_CELL_RENDERER_TEXT (cell); - priv = ghb_cell_renderer_text_get_instance_private (celltext); - - /* If the cell isn't editable we return NULL. */ - if (priv->editable == FALSE) - return NULL; - - gint xalign; - g_object_get(cell, "xalign", &xalign, NULL); - priv->entry = g_object_new (GTK_TYPE_ENTRY, - "has-frame", FALSE, - "xalign", xalign, - NULL); - - if (priv->text) - ghb_editable_set_text (priv->entry, priv->text); - - g_object_set_data_full (G_OBJECT (priv->entry), - I_(GHB_CELL_RENDERER_TEXT_PATH), g_strdup (path), g_free); - - gtk_editable_select_region (GTK_EDITABLE (priv->entry), 0, -1); - - priv->in_entry_menu = FALSE; - if (priv->entry_menu_popdown_timeout) - { - g_source_remove (priv->entry_menu_popdown_timeout); - priv->entry_menu_popdown_timeout = 0; - } - - g_signal_connect (priv->entry, - "key-press-event", - G_CALLBACK (ghb_cell_renderer_text_keypress), - celltext); - g_signal_connect (priv->entry, - "editing_done", - G_CALLBACK (ghb_cell_renderer_text_editing_done), - celltext); - priv->focus_out_id = g_signal_connect_after (priv->entry, "focus_out_event", - G_CALLBACK (ghb_cell_renderer_text_focus_out_event), - celltext); - priv->populate_popup_id = g_signal_connect (priv->entry, "populate_popup", - G_CALLBACK (ghb_cell_renderer_text_populate_popup), - celltext); - - gtk_widget_show (priv->entry); - - return GTK_CELL_EDITABLE (priv->entry); -} - -/** - * ghb_cell_renderer_text_set_fixed_height_from_font: - * @renderer: A #GhbCellRendererText - * @number_of_rows: Number of rows of text each cell renderer is allocated, or -1 - * - * Sets the height of a renderer to explicitly be determined by the "font" and - * "y_pad" property set on it. Further changes in these properties do not - * affect the height, so they must be accompanied by a subsequent call to this - * function. Using this function is unflexible, and should really only be used - * if calculating the size of a cell is too slow (ie, a massive number of cells - * displayed). If @number_of_rows is -1, then the fixed height is unset, and - * the height is determined by the properties again. - **/ -void -ghb_cell_renderer_text_set_fixed_height_from_font (GhbCellRendererText *celltext, - gint number_of_rows) -{ - g_return_if_fail (GHB_IS_CELL_RENDERER_TEXT (celltext)); - g_return_if_fail (number_of_rows == -1 || number_of_rows > 0); - GhbCellRendererTextPrivate *priv; - - priv = ghb_cell_renderer_text_get_instance_private (celltext); - if (number_of_rows == -1) - { - gint width; - g_object_get(celltext, "width", &width, NULL); - gtk_cell_renderer_set_fixed_size (GTK_CELL_RENDERER (celltext), - width, - -1); - } - else - { - priv->fixed_height_rows = number_of_rows; - priv->calc_fixed_height = TRUE; - } -} - diff --git a/gtk/src/ghbcellrenderertext.h b/gtk/src/ghbcellrenderertext.h deleted file mode 100644 index 6c24030d2..000000000 --- a/gtk/src/ghbcellrenderertext.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * ghbcellrenderertext.h - * Copyright (C) John Stebbins 2008-2019 - * - * ghbcellrenderertext.h is free software. - * - * You may redistribute it and/or modify it under the terms of the - * GNU General Public License, as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * ghbcellrenderertext.h 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 callbacks.h. If not, write to: - * The Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301, USA. - */ - -#ifndef __GHB_CELL_RENDERER_TEXT_H__ -#define __GHB_CELL_RENDERER_TEXT_H__ - -#include -#include - - -G_BEGIN_DECLS - - -#define GHB_TYPE_CELL_RENDERER_TEXT (ghb_cell_renderer_text_get_type ()) -#define GHB_CELL_RENDERER_TEXT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GHB_TYPE_CELL_RENDERER_TEXT, GhbCellRendererText)) -#define GHB_CELL_RENDERER_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GHB_TYPE_CELL_RENDERER_TEXT, GhbCellRendererTextClass)) -#define GHB_IS_CELL_RENDERER_TEXT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GHB_TYPE_CELL_RENDERER_TEXT)) -#define GHB_IS_CELL_RENDERER_TEXT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GHB_TYPE_CELL_RENDERER_TEXT)) -#define GHB_CELL_RENDERER_TEXT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GHB_TYPE_CELL_RENDERER_TEXT, GhbCellRendererTextClass)) - -typedef struct _GhbCellRendererText GhbCellRendererText; -typedef struct _GhbCellRendererTextPrivate GhbCellRendererTextPrivate; -typedef struct _GhbCellRendererTextClass GhbCellRendererTextClass; - -struct _GhbCellRendererText -{ - GtkCellRenderer parent; -}; - -struct _GhbCellRendererTextClass -{ - GtkCellRendererClass parent_class; - - void (* edited) (GhbCellRendererText *cell_renderer_text, - const gchar *path, - const gchar *new_text); - - gboolean (* keypress) (GhbCellRendererText *cell_renderer_text, - GdkEventKey *event); - - /* Padding for future expansion */ - void (*_gtk_reserved1) (void); - void (*_gtk_reserved2) (void); - void (*_gtk_reserved3) (void); - void (*_gtk_reserved4) (void); -}; - -GType ghb_cell_renderer_text_get_type (void) G_GNUC_CONST; -GtkCellRenderer *ghb_cell_renderer_text_new (void); - -void ghb_cell_renderer_text_set_fixed_height_from_font (GhbCellRendererText *renderer, - gint number_of_rows); - - -G_END_DECLS - - -#endif /* __GHB_CELL_RENDERER_TEXT_H__ */ diff --git a/gtk/src/main.c b/gtk/src/main.c index 1acdc4da1..f0ca67a3b 100644 --- a/gtk/src/main.c +++ b/gtk/src/main.c @@ -51,7 +51,6 @@ #include "renderer_button.h" #include "hb-backend.h" #include "ghb-dvd.h" -#include "ghbcellrenderertext.h" #include "values.h" #include "icons.h" #include "callbacks.h" @@ -199,56 +198,6 @@ change_font(GtkWidget *widget, gpointer data) //gtk_container_foreach((GtkContainer*)window, change_font, "sans 20"); #endif -extern G_MODULE_EXPORT void chapter_edited_cb(void); -extern G_MODULE_EXPORT void chapter_keypress_cb(void); - -// Create and bind the tree model to the tree view for the chapter list -// Also, connect up the signal that lets us know the selection has changed -static void -bind_chapter_tree_model(signal_user_data_t *ud) -{ - GtkCellRenderer *cell; - GtkTreeViewColumn *column; - GtkListStore *treestore; - GtkTreeView *treeview; - - g_debug("bind_chapter_tree_model()\n"); - treeview = GTK_TREE_VIEW(GHB_WIDGET(ud->builder, "chapters_list")); - treestore = gtk_list_store_new(5, G_TYPE_INT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_BOOLEAN); - gtk_tree_view_set_model(treeview, GTK_TREE_MODEL(treestore)); - -#if GTK_CHECK_VERSION(3, 90, 0) - cell = gtk_cell_renderer_text_new(); -#else - cell = ghb_cell_renderer_text_new(); -#endif - column = gtk_tree_view_column_new_with_attributes( - _("Index"), cell, "text", 0, NULL); - gtk_tree_view_append_column(treeview, GTK_TREE_VIEW_COLUMN(column)); - - cell = ghb_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes( - _("Start"), cell, "text", 1, NULL); - gtk_tree_view_append_column(treeview, GTK_TREE_VIEW_COLUMN(column)); - - cell = ghb_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes( - _("Duration"), cell, "text", 2, NULL); - gtk_tree_view_append_column(treeview, GTK_TREE_VIEW_COLUMN(column)); - - cell = ghb_cell_renderer_text_new(); - column = gtk_tree_view_column_new_with_attributes( - _("Title"), cell, "text", 3, "editable", 4, NULL); - gtk_tree_view_append_column(treeview, GTK_TREE_VIEW_COLUMN(column)); - -#if GTK_CHECK_VERSION(3, 90, 0) -#else - g_signal_connect(cell, "key-press-event", chapter_keypress_cb, ud); -#endif - g_signal_connect(cell, "edited", chapter_edited_cb, ud); - g_debug("Done\n"); -} - extern G_MODULE_EXPORT void audio_list_selection_changed_cb(void); extern G_MODULE_EXPORT void audio_edit_clicked_cb(void); extern G_MODULE_EXPORT void audio_remove_clicked_cb(void); @@ -1121,7 +1070,7 @@ ghb_activate_cb(GApplication * app, signal_user_data_t * ud) bind_audio_tree_model(ud); bind_subtitle_tree_model(ud); bind_presets_tree_model(ud); - bind_chapter_tree_model(ud); + // Connect up the signals to their callbacks // I wrote my own connector so that I could pass user data // to the callbacks. Builder's standard autoconnect doesn't all this. diff --git a/gtk/src/marshalers.c b/gtk/src/marshalers.c index 9c4b7f1b9..8f118cb4d 100644 --- a/gtk/src/marshalers.c +++ b/gtk/src/marshalers.c @@ -1,32 +1,9 @@ -/* - * marshalers.c - * Copyright (C) John Stebbins 2008-2019 - * - * marshalers.c is free software. - * - * You may redistribute it and/or modify it under the terms of the - * GNU General Public License, as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * marshalers.c 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 main.c. If not, write to: - * The Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301, USA. - */ - -#include - +/* This file is generated by glib-genmarshal, do not modify it. This code is licensed under the same license as the containing project. Note that it links to GLib, so must comply with the LGPL linking clauses. */ +#include #ifdef G_ENABLE_DEBUG #define g_marshal_value_peek_boolean(v) g_value_get_boolean (v) -#define g_marshal_value_peek_char(v) g_value_get_char (v) +#define g_marshal_value_peek_char(v) g_value_get_schar (v) #define g_marshal_value_peek_uchar(v) g_value_get_uchar (v) #define g_marshal_value_peek_int(v) g_value_get_int (v) #define g_marshal_value_peek_uint(v) g_value_get_uint (v) @@ -70,9 +47,6 @@ #define g_marshal_value_peek_variant(v) (v)->data[0].v_pointer #endif /* !G_ENABLE_DEBUG */ - -/* VOID:STRING (/home/jstebbins/Source/hb/HandBrake/build.dbg/../gtk/src/marshalers.list:1) */ - /* VOID:STRING,STRING (/home/jstebbins/Source/hb/HandBrake/build.dbg/../gtk/src/marshalers.list:2) */ void ghb_marshal_VOID__STRING_STRING (GClosure *closure, @@ -82,13 +56,13 @@ ghb_marshal_VOID__STRING_STRING (GClosure *closure, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { - typedef void (*GMarshalFunc_VOID__STRING_STRING) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer data2); - register GMarshalFunc_VOID__STRING_STRING callback; - register GCClosure *cc = (GCClosure*) closure; - register gpointer data1, data2; + typedef void (*GMarshalFunc_VOID__STRING_STRING) (gpointer data1, + gpointer arg1, + gpointer arg2, + gpointer data2); + GCClosure *cc = (GCClosure *) closure; + gpointer data1, data2; + GMarshalFunc_VOID__STRING_STRING callback; g_return_if_fail (n_param_values == 3); @@ -113,18 +87,18 @@ ghb_marshal_VOID__STRING_STRING (GClosure *closure, /* BOOLEAN:BOXED (/home/jstebbins/Source/hb/HandBrake/build.dbg/../gtk/src/marshalers.list:3) */ void ghb_marshal_BOOLEAN__BOXED (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, + GValue *return_value, guint n_param_values, const GValue *param_values, gpointer invocation_hint G_GNUC_UNUSED, gpointer marshal_data) { - typedef gboolean (*GMarshalFunc_BOOLEAN__BOXED) (gpointer data1, - gpointer arg_1, - gpointer data2); - register GMarshalFunc_BOOLEAN__BOXED callback; - register GCClosure *cc = (GCClosure*) closure; - register gpointer data1, data2; + typedef gboolean (*GMarshalFunc_BOOLEAN__BOXED) (gpointer data1, + gpointer arg1, + gpointer data2); + GCClosure *cc = (GCClosure *) closure; + gpointer data1, data2; + GMarshalFunc_BOOLEAN__BOXED callback; gboolean v_return; g_return_if_fail (return_value != NULL); diff --git a/gtk/src/marshalers.h b/gtk/src/marshalers.h index f5e0d1bfe..fd05e7b82 100644 --- a/gtk/src/marshalers.h +++ b/gtk/src/marshalers.h @@ -1,53 +1,33 @@ -/* - * marshalers.h - * Copyright (C) John Stebbins 2008-2019 - * - * marshalers.h is free software. - * - * You may redistribute it and/or modify it under the terms of the - * GNU General Public License, as published by the Free Software - * Foundation; either version 2 of the License, or (at your option) - * any later version. - * - * marshalers.h 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 callbacks.h. If not, write to: - * The Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301, USA. - */ - -#ifndef __ghb_marshal_MARSHAL_H__ -#define __ghb_marshal_MARSHAL_H__ - -#include +/* This file is generated by glib-genmarshal, do not modify it. This code is licensed under the same license as the containing project. Note that it links to GLib, so must comply with the LGPL linking clauses. */ +#ifndef __GHB_MARSHAL_MARSHAL_H__ +#define __GHB_MARSHAL_MARSHAL_H__ + +#include G_BEGIN_DECLS /* VOID:STRING (/home/jstebbins/Source/hb/HandBrake/build.dbg/../gtk/src/marshalers.list:1) */ -#define ghb_marshal_VOID__STRING g_cclosure_marshal_VOID__STRING +#define ghb_marshal_VOID__STRING g_cclosure_marshal_VOID__STRING /* VOID:STRING,STRING (/home/jstebbins/Source/hb/HandBrake/build.dbg/../gtk/src/marshalers.list:2) */ -extern void ghb_marshal_VOID__STRING_STRING (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); +extern +void ghb_marshal_VOID__STRING_STRING (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); /* BOOLEAN:BOXED (/home/jstebbins/Source/hb/HandBrake/build.dbg/../gtk/src/marshalers.list:3) */ -extern void ghb_marshal_BOOLEAN__BOXED (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); +extern +void ghb_marshal_BOOLEAN__BOXED (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); -G_END_DECLS -#endif /* __ghb_marshal_MARSHAL_H__ */ +G_END_DECLS +#endif /* __GHB_MARSHAL_MARSHAL_H__ */ diff --git a/libhb/hb_json.c b/libhb/hb_json.c index 8413d3cd6..3b1602954 100644 --- a/libhb/hb_json.c +++ b/libhb/hb_json.c @@ -765,13 +765,20 @@ hb_dict_t* hb_job_to_dict( const hb_job_t * job ) for (ii = 0; ii < hb_list_count(job->list_chapter); ii++) { hb_dict_t *chapter_dict; - char *title = ""; + char *name = ""; hb_chapter_t *chapter = hb_list_item(job->list_chapter, ii); if (chapter->title != NULL) - title = chapter->title; + name = chapter->title; - chapter_dict = json_pack_ex(&error, 0, "{s:o}", - "Name", hb_value_string(title)); + chapter_dict = json_pack_ex(&error, 0, + "{s:o, s:{s:o, s:o, s:o, s:o}}", + "Name", hb_value_string(name), + "Duration", + "Ticks", hb_value_int(chapter->duration), + "Hours", hb_value_int(chapter->hours), + "Minutes", hb_value_int(chapter->minutes), + "Seconds", hb_value_int(chapter->seconds) + ); hb_value_array_append(chapter_list, chapter_dict); } -- 2.40.0