aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGordon Norman Squash <gordsqsh@protonmail.com>2024-09-29 18:43:44 -0400
committerGordon Norman Squash <gordsqsh@protonmail.com>2024-09-29 18:43:44 -0400
commit59e1d8332530d70c0ed9fabd01b896b83efc72b5 (patch)
treebc9dcec3c5b0ed4295eeff378856779889dca1a9
parentLicense changed to LGPL-2 to match GTK license (diff)
downloadgtk3-classic-module-59e1d8332530d70c0ed9fabd01b896b83efc72b5.tar.gz
gtk3-classic-module-59e1d8332530d70c0ed9fabd01b896b83efc72b5.tar.bz2
gtk3-classic-module-59e1d8332530d70c0ed9fabd01b896b83efc72b5.zip
Draw tree view rows in alternating colours ('zebra stripes')
NOTE: Please see the README and the file `data/zebra-stripes.css` for information on how to actually activate the zebra stripes.
-rw-r--r--README.md17
-rw-r--r--data/zebra-stripes.css27
-rw-r--r--main.c2
-rw-r--r--meson.build3
-rw-r--r--patches/treeview-zebra-stripes.c170
-rw-r--r--screenshots/zebra-stripes.pngbin0 -> 53829 bytes
6 files changed, 206 insertions, 13 deletions
diff --git a/README.md b/README.md
index 6c12d58..c5fabb4 100644
--- a/README.md
+++ b/README.md
@@ -77,6 +77,16 @@ amount of documentation about each option.
**Requires disabling the GTK setting `gtk-auto-mnemonics`.**
+* Displays tree views with alternating row colours ('zebra stripes') if the
+ tree view contains more than one column.
+
+ <img src='screenshots/zebra-stripes.png'/>
+
+ **Requires copying the contents of the file `data/zebra-stripes.css` into
+ your `~/.config/gtk-3.0/gtk.css` file; please see the file
+ `data/zebra-stripes.css` for more information, as there is a comment at the
+ top of that file with more things you may need to know.**
+
* Forces GTK to display normal dialog buttons at the bottom of stock dialogs
(e.g. About dialog, color chooser, file chooser), instead of displaying the
buttons in a headerbar at the top of the dialog -- even on Wayland.
@@ -141,11 +151,6 @@ here.
* Convert menu-like popovers into traditional menus.
-* Restore 'zebra stripes' (alternating row colours in treeviews).
-
## License
-GNU LGPL-2. This is the same license under which GTK 3 is released. (This
-module used to be LGPL-3 until I was warned that GTK 3 is licensed under LGPL-2
-[*only*](https://gitlab.gnome.org/GNOME/gtk/-/blob/main/COPYING). I didn't
-know any project other than the Linux kernel was licensed that way.)
+GNU LGPL-2. This is the same license under which GTK 3 is released.
diff --git a/data/zebra-stripes.css b/data/zebra-stripes.css
index 5f13d79..e89c09d 100644
--- a/data/zebra-stripes.css
+++ b/data/zebra-stripes.css
@@ -1,16 +1,31 @@
-/* TODO: This is currently unused, but when alternating treeview row colours
- * are restored, this will be the default CSS code to activate them if the
- * current theme doesn't provide its own code for this.
+/* This file enables alternating light and dark row colours ('zebra stripes')
+ * in tree view widgets. These are general good default colours for light
+ * themes. You can enable zebra stripes by copying this file to your
+ * ~/.config/gtk-3.0/gtk.css file, or you can implement similar code in your
+ * theme CSS.
+ *
+ * Note the extra CSS selectors which theme only tree views with more than
+ * one column; generally speaking, zebra stripes are only necessary when the
+ * list or tree contains more than one column. If you really want zebra
+ * stripes on all tree views, regardless of column count, remove the extra
+ * selectors for ':not(.first):not(.last)', '.first:not(.last)', and
+ * ':not(.first).last'.
*/
-treeview:not(:selected).odd.sorted,
-treeview:not(:selected).even:not(.sorted)
+treeview.cell:not(.first):not(.last):not(:selected).odd.sorted,
+treeview.cell.first:not(.last):not(:selected).odd.sorted,
+treeview.cell:not(.first).last:not(:selected).odd.sorted,
+treeview.cell:not(.first):not(.last):not(:selected).even:not(.sorted),
+treeview.cell.first:not(.last):not(:selected).even:not(.sorted),
+treeview.cell:not(.first).last:not(:selected).even:not(.sorted)
{
background: alpha(black, 0.07);
}
-treeview:not(:selected).even.sorted
+treeview.cell:not(.first):not(.last):not(:selected).even.sorted,
+treeview.cell.first:not(.last):not(:selected).even.sorted,
+treeview.cell:not(.first).last:not(:selected).even.sorted
{
background: alpha(black, 0.13);
}
diff --git a/main.c b/main.c
index ddfc7ab..731b58e 100644
--- a/main.c
+++ b/main.c
@@ -14,9 +14,11 @@ void icon_sizes_init ();
void no_emojis_init ();
void persistent_mnemonics_init ();
void smaller_widgets_init ();
+void treeview_zebra_stripes_init ();
static const InitFunc init_funcs[] =
{
+ treeview_zebra_stripes_init,
smaller_widgets_init,
/* No Emojis must be loaded before Button/Menu Icons since the former
* overrides GtkMenuItem, the superclass of the GtkImageMenuItem class
diff --git a/meson.build b/meson.build
index b1417d0..4592d18 100644
--- a/meson.build
+++ b/meson.build
@@ -56,7 +56,8 @@ shared_module ('gtk3-classic-module',
'patches/icon-sizes.c',
'patches/no-emojis.c',
'patches/persistent-mnemonics.c',
- 'patches/smaller-widgets.c'
+ 'patches/smaller-widgets.c',
+ 'patches/treeview-zebra-stripes.c'
],
include_directories: [ include_dir ],
dependencies: [ gtk_dep, gtk_unix_print_dep ],
diff --git a/patches/treeview-zebra-stripes.c b/patches/treeview-zebra-stripes.c
new file mode 100644
index 0000000..8dafa16
--- /dev/null
+++ b/patches/treeview-zebra-stripes.c
@@ -0,0 +1,170 @@
+/* Treeview Zebra Stripes:
+ * (based on gtk3-classic patch 'treeview__alternating_row_colours.patch'):
+ *
+ * Adds appropriate style classes to each cell in a GtkTreeView, so that themes
+ * can draw the rows of a treeview in alternating colours, also known as
+ * 'zebra stripes'.
+ */
+
+
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <glib.h>
+#include <cairo/cairo.h>
+
+#include <gtk3-classic.h>
+
+
+#undef G_LOG_DOMAIN
+#define G_LOG_DOMAIN "Gtk3-Classic::Treeview-Zebra-Stripes"
+
+
+static gboolean find_row_index (GtkTreeView * treeview,
+ GtkTreeModel * model,
+ GtkTreeIter * start_iter,
+ GtkTreePath * target_path,
+ int * index);
+
+
+INTERCEPTED_CLASS_METHOD (gtk_cell_area, render,
+ (GtkCellArea * area,
+ GtkCellAreaContext * context,
+ GtkWidget * widget,
+ cairo_t * cr,
+ const GdkRectangle * background_area,
+ const GdkRectangle * cell_area,
+ GtkCellRendererState flags,
+ gboolean paint_focus),
+ void)
+
+
+void treeview_zebra_stripes_init ()
+{
+ GtkCellAreaClass * gtk_cell_area_class =
+ g_type_class_ref (GTK_TYPE_CELL_AREA);
+
+ INTERCEPT_CLASS_METHOD (gtk_cell_area, GTK_CELL_AREA_CLASS,
+ render)
+
+ g_type_class_unref (gtk_cell_area_class);
+}
+
+
+static void
+new_gtk_cell_area_render
+(GtkCellArea * area,
+ GtkCellAreaContext * context,
+ GtkWidget * widget,
+ cairo_t * cr,
+ const GdkRectangle * background_area,
+ const GdkRectangle * cell_area,
+ GtkCellRendererState flags,
+ gboolean paint_focus)
+{
+ GtkTreeView * treeview;
+ GtkTreeModel * model;
+ GtkStyleContext * style;
+ gint bin_x, bin_y;
+ GtkTreePath * path;
+ int index;
+ GtkTreeViewColumn * column;
+ GList * columns;
+
+
+ if (GTK_IS_TREE_VIEW (widget))
+ {
+ treeview = GTK_TREE_VIEW (widget);
+ model = gtk_tree_view_get_model (treeview);
+ style = gtk_widget_get_style_context (widget);
+ columns = gtk_tree_view_get_columns (treeview);
+
+ bin_x = cell_area->x + cell_area->width - 1;
+ bin_y = cell_area->y + cell_area->height - 1;
+
+ gtk_tree_view_get_path_at_pos (treeview, bin_x, bin_y,
+ &path, &column, NULL, NULL);
+ if (path != NULL)
+ {
+ index = 0;
+ find_row_index (treeview, model, NULL, path, &index);
+ gtk_tree_path_free (path);
+ gtk_style_context_add_class (style,
+ ((index % 2) ? "even" : "odd"));
+ }
+
+ if (column == columns->data)
+ gtk_style_context_add_class (style, "first");
+ if (column == g_list_last (columns)->data)
+ gtk_style_context_add_class (style, "last");
+ if ((flags & GTK_CELL_RENDERER_SORTED))
+ gtk_style_context_add_class (style, "sorted");
+
+ gtk_render_background (style, cr,
+ background_area->x, background_area->y,
+ background_area->width,
+ background_area->height);
+ }
+
+
+ CALL_ORIGINAL_CLASS_METHOD (gtk_cell_area, render,
+ (area, context, widget, cr,
+ background_area, cell_area,
+ flags, paint_focus));
+}
+
+
+/* Helper functions */
+
+static gboolean
+find_row_index
+(GtkTreeView * treeview,
+ GtkTreeModel * model,
+ GtkTreeIter * start_iter,
+ GtkTreePath * target_path,
+ int * index)
+{
+ GtkTreeIter iter;
+ GtkTreeIter child_iter;
+ GtkTreePath * path;
+
+
+ if (start_iter == NULL)
+ {
+ if (! gtk_tree_model_get_iter_first (model, &iter))
+ return TRUE;
+ }
+ else
+ iter = *start_iter;
+
+ while (1)
+ {
+ path = gtk_tree_model_get_path (model, &iter);
+
+ if (gtk_tree_path_compare (path, target_path) == 0)
+ {
+ gtk_tree_path_free (path);
+ return TRUE;
+ }
+
+ if (gtk_tree_view_row_expanded (treeview, path))
+ {
+ (*index)++;
+ gtk_tree_model_iter_children (model, &child_iter, &iter);
+ if (find_row_index (treeview, model, &child_iter,
+ target_path, index))
+ {
+ gtk_tree_path_free (path);
+ return TRUE;
+ }
+ }
+
+ gtk_tree_path_free (path);
+ if (! gtk_tree_model_iter_next (model, &iter))
+ break;
+ else
+ (*index)++;
+ }
+
+
+ return FALSE;
+}
diff --git a/screenshots/zebra-stripes.png b/screenshots/zebra-stripes.png
new file mode 100644
index 0000000..c6a9afb
--- /dev/null
+++ b/screenshots/zebra-stripes.png
Binary files differ
bgstack15