Using Pango Markup within a GTK+ TreeView in C - c

I have a completely hardcoded GtkTreeView and I am trying to use Pango Markup on one of the columns in the Treeview. This requires the use of a cell data function on the text renderer for that column. The cell data function has the form:
// This function uses pango markup on the Gtklabels shown in the TreeView
// A cell data function is a function that is called for a specific cell renderer for each single row before that row is rendered.
static void cell_data_func_label (__attribute__((unused)) GtkTreeViewColumn *column, GtkCellRenderer *renderer,
GtkTreeModel *model, GtkTreeIter *iter, __attribute__((unused)) gpointer user_data)
{
gchar *label;
gchar *markuptxt;
// Retrieve the current label
gtk_tree_model_get (model, iter, CURRENT, &label, -1);
markuptxt = g_strdup_printf("<i>%s</i>", label);
g_object_set(renderer, "markup", markuptxt, "text", NULL, NULL); // markup isn't showing and text field is blank due to "text" == NULL
g_free(markuptxt);
}
and within the function GtkWidget *create_view_and_model() I set the cell data function via:
// Sets the GtkTreeCellDataFunc to use for the column
gtk_tree_view_column_set_cell_data_func(column4, text, cell_data_func_label, NULL, NULL);
The problem is that the text cell renderer is now blank. I suspect it might have to do with passing NULL after "text" in g_object_set. The following link:
https://en.wikibooks.org/wiki/GTK%2B_By_Example/Tree_View/Columns_and_Renderers
states that:
When using the "markup" property, you need to take into account that the "markup" and "text" properties do not seem to be mutually exclusive (I suppose this could be called a bug). In other words: whenever you set "markup" (and have used the "text" property before), set the "text" property to NULL, and vice versa.
It may be that this is no longer the case (i.e. it is for GTK+ 2), but I am not sure what needs to be changed in order to render the column with markup, since anything other than NULL ends up being rendered without markup, and using NULL leaves the renderer empty. Any assitance would be appreciated.

What ended up working was simply not including any reference to "text" whatsoever in g_object_set:
g_object_set(renderer, "markup", markuptxt, NULL);

Related

Creating a list of widgets in Gtk using C

I want to create a window in Gtk that looks something like this.
widgets in glade
The left pane in the top window has a button labelled "Add to list". I have configured the callback for this button to add the widget "list_entry" into the GtkListBox in the right pane. It does so after changing the label of the widget from "label" to the text present in a text entry present just above it.
So, basically this button add a new entry into a list placed in the right pane(might be seen empty). This entry is a simple widget consisting of an icon and a label( at the bottom).
Now, I want the button "Add to list" to create new copies of this entry every time I click it and append that entry to the list in the right pane. But every time I add a new entry to the list, it simply overwrite the previous entry of the list and gives a warning ->
Attempting to add a widget with type GtkBox to a container of type GtkListBoxRow, but the widget is already inside a container of type GtkListBoxRow, please remove the widget from its existing container first.
I am using GtkListBox for the list in the right pane and the GtkBox for the new entry that I am supposed to add.
This is the code for the "click" callback of the button "Add to list"
static void
dw_left_add_btn_cb(CcPrintersPanel * self){
GtkLabel* row_list_label = (GtkLabel*) gtk_builder_get_object (self->builder, "list_entry_label");
GtkEntry* text_entry_to_add = (GtkEntry*) gtk_builder_get_object (self->builder, "dw_left_enter_text");
// debug
if ( self->list_serv == NULL || row_list_label == NULL) g_debug ("One of object for generating the list did'nt load up in the builder");
gtk_label_set_label (row_list_label, gtk_entry_get_text (text_entry_to_add));
gtk_entry_set_text(text_entry_to_add,"");
GtkWidget* row_list = (GtkWidget*) gtk_builder_get_object (self->builder, "list_entry");
gtk_list_box_insert (self->list_serv, row_list, -1);
}
I wanted to ask you how to create an entirely new widget( for every new entry ) from a widget that was loaded into Builder using a .ui file. Please also advise me if you have some other way of implementing this.
GtkBuilder is not a factory of widgets. It's more like a carton of widgets. Some pseudocode:
GtkWidget *widget1, *widget2;
builder = gtk_builder_new();
widget1 = gtk_builder_get_object(builder, "label");
widget2 = gtk_builder_get_object(builder, "label"); // this will not produce another label but return existing one
// (widget1 == widget2), they point to same object
// let's unpack another carton of widgets...
builder2 = gtk_builder_new();
widget2 = gtk_builder_get_object(builder2, "label");
// (widget1 != widget2), now that's really 2 distinct widgets
Hence the warning. You try to add widget to a ListBoxRow, but this exact widget is already in a ListBoxRow. When you want to dynamically create another widget, you must create another GtkBuilder.
static void
dw_left_add_btn_cb(CcPrintersPanel * self){
GtkBuilder *b = gtk_builder_new();
GtkLabel* w = (GtkLabel*) gtk_builder_get_object (b, "list_entry_label");
gtk_list_box_insert (self->list_serv, w, -1);
}

Gtk.Combobox displays two columns (instead of 1), Why?

I realize GTK-2 is now 'antique'. I have an old program I have to modify, and it's just too large to convert to GTK-3 for the time I have. This is the issue:
I added a ComboBox to which I assign a ListBox with 2 columns (G_TYPE_INT and G_TYPE_STRING).
For some reason, both columns are shown on the ComboBox, though I think the code shown below only assigns one.
void
fill_list(GtkComboBox *cbbox)
{
GtkListStore *store = gtk_list_store_new(2, G_TYPE_INT, G_TYPE_STRING);
GtkTreeIter iter;
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
gtk_combo_box_set_model(cbbox, GTK_TREE_MODEL(store));
gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(cbbox), renderer, TRUE);
gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(cbbox), renderer,
"text", 0, NULL);
gtk_combo_box_set_entry_text_column(cbbox, 0);
gtk_list_store_append(store, &iter);
// Col 0 Col 1
gtk_list_store_set(store, &iter, 0, 0, 1, "Kind 1", -1);
gtk_list_store_append(store, &iter);
gtk_list_store_set(store, &iter, 0, 1, 1, "Kind 2", -1);
gtk_list_store_append(store, &iter);
This is part of the function called on the 'realize' signal of the widget.
Changing ..."text", 0... to ..."text", 1... changes the second column of the
ComboBox to, as expected, the second column of the ListStore.
But, for unknown reason, I can't get rid of the first column. I've scanned the
entire project for signs of code that might influence - no luck. The interface was
generated using Glade-2.
For the last years, I've been working more from Python, so I'm suspecting there's something
I'm missing here. I even basically tested this code in Python, and had no problem there.
I'd appreciate suggestions!
The problem was solved!
I found out that Glade 2, when asked to add a GtkComboBox, actually inserted a GtkComboBoxText (even though in the Component editor it is shown as a GtkComboBox type). I've only detected this when browsing the automatically generated interface.c code.
This creates a widget with a 'model' in it, and (I suspect) the necessary code to render the single column in that model (for the 'text'). When adding a new column, by setting another model, the (original) renderer is rendering the first column.
To get rid of the original renderer, the solution seems to be to call gtk_cell_layout_clear, and only then add the new model + renderer:
gtk_cell_layout_clear(GTK_CELL_LAYOUT(cbbox));
Do this during a realize event handler for the ComboBox, don't modify interface.c, as it will be overwritten.
I'm not sure if this is enough to free any memory to the original renderer though.

How do I replace lookup_widget in Glade3/GTK3 code?

I have recently resurrected a project from a decade ago (https://github.com/clancyj4/z80sim) and I'm running into problems that are related to the transition from glade 2 to 3.
One problem is that I use a function lookup_widget which is defined in support.c by glade 2, but is not defined in glade 3. And I don't know how to replace it.
An example of how I use it is:
void init_Code(GtkWidget *Main)
{
GtkWidget *widget;
PangoFontDescription *codefont;
codetext = lookup_widget(Main, "Code_Text");
code_textbuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(codetext));
I have looked the problem up, of course, but I don't understand the answer which was:
The preferred solution is to pass a pointer to your ENTRY as the user data pointer when you connect the signal, or, if you're using gtk_builder_connect_signals(), store a pointer to ENTRY in your class and pass the class as the user data pointer.
which was referring to:
on_BT_OK_clicked(GtkButton *button, gpointer user_data)
{
//The line directly below is the one I get an error on
GtkWidget *entry = lookup_widget( GTK_WIDGET(button), "ENTRY" );
Any clarification would be most helpful.
EDIT:
I'm pretty sure that the signals are all connected because I use this:
builder = gtk_builder_new();
gtk_builder_add_from_file(builder, "z80em2.glade", NULL);
window = GTK_WIDGET(gtk_builder_get_object(builder, "Main"));
gtk_builder_connect_signals(builder, NULL);
As I understand it codetext = lookup_widget(Main, "Code_Text") returns a pointer to the GtkWidget referred to as Code_Text under the Main widget and I don't see how to do that in GTK3.
I haven't used Glade, but if you have "manual" code that connects the signal handler, you should pass a pointer to that other widget in that call. That will then be stored inside GTK+, and passed as the user_pointer argument to the event handler.
So it would become just:
on_BT_OK_clicked(GtkButton *button, gpointer user_data)
{
// This assumes the entry was passed to g_signal_connect() as 'data'
GtkWidget *entry = GTK_WIDGET(user_data);
See g_signal_connect().
If you are planning to rewrite this codebase heavily anyway, you may find it helpful to reorganize the widgets into composite widget templates, which Glade 3 supports, and use gtk_widget_class_bind_template_child() to make all the widgets that you would have otherwise looked up with lookup_widget() into members of your widget class. But it's not a good short-term fix, because it would involve a lot of refactoring.

Difficulty in editable GtkTreeView

I am writing a piece of software where my user should be able to add data to a table-like editing widget, which I managed to render by using a GtkTreeView. I was able to render my cell editable by setting its editable property via this call
g_object_set(content_renderer,
"editable", TRUE,
NULL);
However, my GtkTreeView not only doesn't retain values entered as it's not even showing the data I've added before rendering. I saw a few examples in the web where the developer manually set the user input data to the model but all of these were either written in Python or C++ using offered bindings for these languages and therefore don't address my issue directly.
I've written this (not so) small example where the problem is successfully shown.
How can I make user input data persistent in a GtkTreeView?
P.S.: my problem is somehow related to this one, however this solution doesn't apply to me.
EDIT:
I followed #PhillipWood hint and connected my GtkCellRendererText to the edited signal, and also set by hand the new data into the model.
HOWEVER, neither the data I've entered prior to the edition nor the data I've entered during the edition appear in the grid.
I am under Fedora 19, with GTK+ 3.8.8.
You need to connect to the 'edited' signal of the cell renderer. This is emitted when the user finishes editing, it is up to the application (i.e. your code) to store the new value in the correct column of the model.
Update:
Looking at your updated code there are a few things that stand out.
Firstly when you use a GtkListStore or a GtkTreeStore it is a good idea to create an enum for indexing the columns.
enum {COLUMN_LABEL, COLUMN_CONTENT, COLUMN_LAST};
Then when you create the list store do
list_store = gtk_list_store_new(COLUMN_LAST, G_TYPE_STRING, G_TYPE_INT);
When you create a tree column you need to tell it which column(s) of the model to display with the cellrenderer. You do this by binding properties of the cellrenderer to columns in the model
label_col = gtk_tree_view_column_new_with_attributes ("Layer",
gtk_cell_renderer_text_new(),
"text", COLUMN_LABEL,
NULL);
Now the content column the model stores an int so we cannot just bind the text property of the renderer as it expects a string. We need to map the column contents onto the text property using
content_column = gtk_tree_view_column_new ();
gtk_tree_view_column_set_cell_data_func (content_column,
gtk_cell_renderer_text_new (),
content_column_data_func,
NULL, NULL);
with
static void
content_column_data_func (GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
GtkTreeModel *tree_model,
GtkTreeIter *iter,
gpointer data)
{
int value;
gchar text;
gtk_tree_model_get (tree_model, iter, COLUMN_CONTENT, &value, -1);
text = g_strdup_printf ("%d", value);
g_object_set (cell, "text", text);
g_free (text);
}
Finally in the edited callback you need to convert the string to an integer before you store it
int value = atoi (new_text);
gtk_list_store_set (list_store, &iter, COLUMN_CONTENT, value, -1);

GtkAboutDialog icon not loading?

I'm attempting to add an about dialog to my next bit of tutorial code, but I can't get the icon to load for some reason. Below is the entire function for creating and displaying the dialog.
static void help_clicked(GtkButton *button, GtkWindow *window)
{
const gchar *authors[] = { "me", NULL };
const gchar *license = "somestuff";
GdkPixbuf *logo = gdk_pixbuf_new_from_file("logo.png", NULL);
gtk_show_about_dialog(window,
"authors", authors, "license", license, "license-type", GTK_LICENSE_CUSTOM,
"logo", logo, "logo-icon-name", "Logo Icon",
"program-name", "Chapter 6, Exercise 1",
"version", "1.0",
"comments", "This is just an exercise from Chapter 6 of the book I'm reading.",
"website", "http://www.google.com", "website-label", "Application Homepage",
"copyright", "(C) 2014 Patrick Meyer",
"wrap-license", TRUE, NULL);
}
This results in an about dialog with every attribute successfully set except the icon.
The weird thing is, the exact same call to gdk_pixbuf_new_from_file() works in main() when I supply it to gtk_window_set_icon(). This is a single-file program with logo.png present in the directory of execution. What's missing?
as the API reference clearly states, the GtkAboutDialog:logo-icon-name property overrides the GtkAboutDialog:logo property:
https://developer.gnome.org/gtk3/stable/GtkAboutDialog.html#GtkAboutDialog--logo-icon-name
also, you're passing a value for the logo-icon-name property that does not mean anything; the logo-icon-name property requires a named icon according to the Icon Naming Specification.
just remove the logo-icon-name property and you'll see the correct icon.
as a side note from your example: you should release the reference on the GdkPixbuf object you create after gtk_show_about_dialog() returns, otherwise you will leak it. ideally, though, since you don't want to load the image file from disk every time you click the help button, you should use something like this:
static GdkPixbuf *logo_icon = NULL;
if (logo_icon == NULL)
logo_icon = gdk_pixbuf_new_from_file ("logo.png", NULL);
gtk_show_about_dialog (...);
which will keep the pixbuf around for the duration of your application.
another option is to use GResource and inject the image data into the application's binary.
The problem is you are setting logo-icon-name too which is supposed to be a symbolic name for an icon, not a human description.
So the internal image is being set correctly and then replaced internally a second time. This also explains why calling gtk_window_set_icon() afterwards works correctly.
The problem is with the logo-icon-name property. As it is stated inside the documentation, this overwrites the logo property. If you leave out the logo-icon-name property, the logo will show correctly.

Resources