/* vi:set et ai sw=2 sts=2 ts=2: */ /*- * Copyright (c) 2022 Amrit Borah * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the Free * Software Foundation; either version 2 of the License, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "thunar/thunar-text-renderer.h" #include "thunar/thunar-util.h" #include #define USAGE_BAR_HEIGHT 4 #define USAGE_BAR_TOP_PAD 2 #define USAGE_BAR_RADIUS 2 enum { PROP_0, PROP_HIGHLIGHT_COLOR, PROP_ROUNDED_CORNERS, PROP_HIGHLIGHTING_ENABLED, PROP_USAGE_PERCENT, }; static void thunar_text_renderer_finalize (GObject *object); static void thunar_text_renderer_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec); static void thunar_text_renderer_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec); static void thunar_text_renderer_render (GtkCellRenderer *renderer, cairo_t *cr, GtkWidget *widget, const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState flags); static void thunar_text_renderer_get_preferred_height (GtkCellRenderer *cell, GtkWidget *widget, gint *minimum, gint *natural); struct _ThunarTextRendererClass { GtkCellRendererTextClass __parent__; void (*default_render_function) (GtkCellRenderer *cell, cairo_t *cr, GtkWidget *widget, const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState flags); }; struct _ThunarTextRenderer { GtkCellRendererText __parent__; gchar *highlight_color; gboolean rounded_corners; gboolean highlighting_enabled; gint usage_percent; /* -1 = no bar, 0..100 = percent used */ }; G_DEFINE_TYPE (ThunarTextRenderer, thunar_text_renderer, GTK_TYPE_CELL_RENDERER_TEXT); static void thunar_text_renderer_class_init (ThunarTextRendererClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass); object_class->finalize = thunar_text_renderer_finalize; object_class->get_property = thunar_text_renderer_get_property; object_class->set_property = thunar_text_renderer_set_property; klass->default_render_function = cell_class->render; cell_class->render = thunar_text_renderer_render; cell_class->get_preferred_height = thunar_text_renderer_get_preferred_height; /** * ThunarTextRenderer:highlight-color: * * The color with which the cell should be highlighted. **/ g_object_class_install_property (object_class, PROP_HIGHLIGHT_COLOR, g_param_spec_string ("highlight-color", "highlight-color", "highlight-color", NULL, EXO_PARAM_READWRITE)); /** * ThunarTextRenderer:rounded-corners: * * Determines if the cell should be clipped to rounded corners. * Useful when highlighting is enabled & a highlight color is set. **/ g_object_class_install_property (object_class, PROP_ROUNDED_CORNERS, g_param_spec_boolean ("rounded-corners", "rounded-corners", "rounded-corners", FALSE, EXO_PARAM_READWRITE)); /** * ThunarTextRenderer:highlighting-enabled: * * Determines if the cell background should be drawn with highlight color. **/ g_object_class_install_property (object_class, PROP_HIGHLIGHTING_ENABLED, g_param_spec_boolean ("highlighting-enabled", "highlighting-enabled", "highlighting-enabled", FALSE, EXO_PARAM_READWRITE)); g_object_class_install_property (object_class, PROP_USAGE_PERCENT, g_param_spec_int ("usage-percent", "usage-percent", "Disk usage percentage (0-100, -1 = hidden)", -1, 100, -1, G_PARAM_READWRITE)); } static void thunar_text_renderer_init (ThunarTextRenderer *text_renderer) { text_renderer->highlight_color = NULL; text_renderer->usage_percent = -1; } static void thunar_text_renderer_finalize (GObject *object) { ThunarTextRenderer *text_renderer = THUNAR_TEXT_RENDERER (object); g_free (text_renderer->highlight_color); G_OBJECT_CLASS (thunar_text_renderer_parent_class)->finalize (object); } static void thunar_text_renderer_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { ThunarTextRenderer *text_renderer = THUNAR_TEXT_RENDERER (object); switch (prop_id) { case PROP_HIGHLIGHT_COLOR: g_value_set_string (value, text_renderer->highlight_color); break; case PROP_ROUNDED_CORNERS: g_value_set_boolean (value, text_renderer->rounded_corners); break; case PROP_HIGHLIGHTING_ENABLED: g_value_set_boolean (value, text_renderer->highlighting_enabled); break; case PROP_USAGE_PERCENT: g_value_set_int (value, text_renderer->usage_percent); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } static void thunar_text_renderer_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { ThunarTextRenderer *text_renderer = THUNAR_TEXT_RENDERER (object); switch (prop_id) { case PROP_HIGHLIGHT_COLOR: g_free (text_renderer->highlight_color); text_renderer->highlight_color = g_value_dup_string (value); break; case PROP_ROUNDED_CORNERS: text_renderer->rounded_corners = g_value_get_boolean (value); break; case PROP_HIGHLIGHTING_ENABLED: text_renderer->highlighting_enabled = g_value_get_boolean (value); break; case PROP_USAGE_PERCENT: text_renderer->usage_percent = g_value_get_int (value); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } } /** * thunar_text_renderer_new: * * Creates a new #ThunarTextRenderer. Adjust rendering * parameters 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. * * Return value: (transfer full) The newly allocated #ThunarTextRenderer. **/ GtkCellRenderer * thunar_text_renderer_new (void) { return g_object_new (THUNAR_TYPE_TEXT_RENDERER, NULL); } static void thunar_text_renderer_get_preferred_height (GtkCellRenderer *cell, GtkWidget *widget, gint *minimum, gint *natural) { gint min_h = 0, nat_h = 0; GTK_CELL_RENDERER_CLASS (thunar_text_renderer_parent_class)->get_preferred_height (cell, widget, &min_h, &nat_h); if (minimum != NULL) *minimum = min_h; if (natural != NULL) *natural = nat_h; } static void thunar_text_renderer_draw_usage_bar (cairo_t *cr, GtkWidget *widget, const GdkRectangle *cell_area, gint usage_percent) { GtkStyleContext *context; GdkRGBA bar_bg = { 0.5, 0.5, 0.5, 0.3 }; GdkRGBA bar_fg; gint xpad = 2; gdouble x = cell_area->x + xpad; gdouble y = cell_area->y + cell_area->height - USAGE_BAR_HEIGHT; gdouble w = cell_area->width - 2 * xpad; gdouble h = USAGE_BAR_HEIGHT; gdouble r = USAGE_BAR_RADIUS; gdouble fw; if (w <= 0) return; context = gtk_widget_get_style_context (widget); if (usage_percent > 90) { bar_fg.red = 0.85; bar_fg.green = 0.2; bar_fg.blue = 0.2; bar_fg.alpha = 0.9; } else { if (!gtk_style_context_lookup_color (context, "theme_selected_bg_color", &bar_fg) || bar_fg.alpha < 0.01) { bar_fg.red = 0.3; bar_fg.green = 0.5; bar_fg.blue = 0.8; } bar_fg.alpha = 0.9; } cairo_save (cr); /* background track */ cairo_new_sub_path (cr); cairo_arc (cr, x + w - r, y + r, r, -G_PI_2, 0); cairo_arc (cr, x + w - r, y + h - r, r, 0, G_PI_2); cairo_arc (cr, x + r, y + h - r, r, G_PI_2, G_PI); cairo_arc (cr, x + r, y + r, r, G_PI, 3 * G_PI_2); cairo_close_path (cr); gdk_cairo_set_source_rgba (cr, &bar_bg); cairo_fill (cr); /* filled portion */ if (usage_percent > 0) { fw = w * usage_percent / 100.0; r = USAGE_BAR_RADIUS; if (fw < 2 * r) r = fw / 2.0; if (r < 0.5) r = 0; cairo_new_sub_path (cr); cairo_arc (cr, x + fw - r, y + r, r, -G_PI_2, 0); cairo_arc (cr, x + fw - r, y + h - r, r, 0, G_PI_2); cairo_arc (cr, x + r, y + h - r, r, G_PI_2, G_PI); cairo_arc (cr, x + r, y + r, r, G_PI, 3 * G_PI_2); cairo_close_path (cr); gdk_cairo_set_source_rgba (cr, &bar_fg); cairo_fill (cr); } cairo_restore (cr); } static void thunar_text_renderer_render (GtkCellRenderer *cell, cairo_t *cr, GtkWidget *widget, const GdkRectangle *background_area, const GdkRectangle *cell_area, GtkCellRendererState flags) { ThunarTextRenderer *text_renderer = THUNAR_TEXT_RENDERER (cell); if (text_renderer->highlighting_enabled) thunar_util_clip_view_background (cell, cr, background_area, widget, flags); /* draw text normally */ THUNAR_TEXT_RENDERER_GET_CLASS (text_renderer) ->default_render_function (cell, cr, widget, background_area, cell_area, flags); /* draw usage bar at the very bottom of the cell, overlapping if needed */ if (text_renderer->usage_percent >= 0) thunar_text_renderer_draw_usage_bar (cr, widget, cell_area, text_renderer->usage_percent); }