diff options
-rw-r--r-- | fastiv.c | 13 | ||||
-rw-r--r-- | fiv-view.c | 38 | ||||
-rw-r--r-- | fiv-view.h | 1 | ||||
-rw-r--r-- | resources/checkerboard-symbolic.svg | 115 | ||||
-rw-r--r-- | resources/resources.gresource.xml | 1 |
5 files changed, 160 insertions, 8 deletions
@@ -56,7 +56,6 @@ exit_fatal(const gchar *format, ...) // TODO(p): See if it's possible to give separators room to shrink // by some minor amount of pixels, margin-wise. -// TODO(p): Add a toggle for a checkerboard background. // TODO(p): Implement commented-out actions. #define B make_toolbar_button #define T make_toolbar_toggle @@ -84,6 +83,7 @@ exit_fatal(const gchar *format, ...) /* XX(PIN, B("view-pin-symbolic", "Keep view configuration")) */ \ /* Or perhaps "blur-symbolic", also in the extended set. */ \ XX(SMOOTH, T("blend-tool-symbolic", "Smooth scaling")) \ + XX(CHECKERBOARD, T("checkerboard-symbolic", "Highlight transparency")) \ /* XX(COLOR, B("preferences-color-symbolic", "Color management")) */ \ XX(SAVE, B("document-save-as-symbolic", "Save as...")) \ XX(PRINT, B("document-print-symbolic", "Print...")) \ @@ -759,6 +759,7 @@ on_view_actions_changed(void) gtk_widget_set_sensitive(g.toolbar[TOOLBAR_FIT], has_image); gtk_widget_set_sensitive(g.toolbar[TOOLBAR_SMOOTH], has_image); + gtk_widget_set_sensitive(g.toolbar[TOOLBAR_CHECKERBOARD], has_image); gtk_widget_set_sensitive(g.toolbar[TOOLBAR_SAVE], has_image); gtk_widget_set_sensitive(g.toolbar[TOOLBAR_PRINT], has_image); @@ -902,6 +903,7 @@ make_view_toolbar(void) toolbar_command(TOOLBAR_ONE, FIV_VIEW_COMMAND_ZOOM_1); toolbar_toggler(TOOLBAR_FIT, "scale-to-fit"); toolbar_toggler(TOOLBAR_SMOOTH, "filter"); + toolbar_toggler(TOOLBAR_CHECKERBOARD, "checkerboard"); toolbar_command(TOOLBAR_PRINT, FIV_VIEW_COMMAND_PRINT); toolbar_command(TOOLBAR_SAVE, FIV_VIEW_COMMAND_SAVE_PAGE); toolbar_command(TOOLBAR_LEFT, FIV_VIEW_COMMAND_ROTATE_LEFT); @@ -917,11 +919,14 @@ make_view_toolbar(void) G_CALLBACK(on_notify_view_boolean), g.toolbar[TOOLBAR_FIT]); g_signal_connect(g.view, "notify::filter", G_CALLBACK(on_notify_view_boolean), g.toolbar[TOOLBAR_SMOOTH]); + g_signal_connect(g.view, "notify::checkerboard", + G_CALLBACK(on_notify_view_boolean), g.toolbar[TOOLBAR_CHECKERBOARD]); g_object_notify(G_OBJECT(g.view), "scale"); g_object_notify(G_OBJECT(g.view), "playing"); g_object_notify(G_OBJECT(g.view), "scale-to-fit"); g_object_notify(G_OBJECT(g.view), "filter"); + g_object_notify(G_OBJECT(g.view), "checkerboard"); GCallback callback = G_CALLBACK(on_view_actions_changed); g_signal_connect(g.view, "notify::has-image", callback, NULL); @@ -995,8 +1000,10 @@ main(int argc, char *argv[]) fiv-browser { padding: 5px; } \ fiv-browser.item { \ color: mix(#000, @content_view_bg, 0.625); margin: 8px; \ - border: 2px solid #fff; background: @theme_bg_color; \ - background-image: \ + border: 2px solid #fff; \ + } \ + fiv-browser.item, fiv-view.checkerboard { \ + background: @theme_bg_color; background-image: \ linear-gradient(45deg, @fiv-tile 26%, transparent 26%), \ linear-gradient(-45deg, @fiv-tile 26%, transparent 26%), \ linear-gradient(45deg, transparent 74%, @fiv-tile 74%), \ @@ -38,6 +38,7 @@ struct _FivView { cairo_surface_t *frame; ///< Current frame within page, weak FivIoOrientation orientation; ///< Current page orientation bool filter; ///< Smooth scaling toggle + bool checkerboard; ///< Show checkerboard background bool scale_to_fit; ///< Image no larger than the allocation double scale; ///< Scaling factor @@ -88,6 +89,7 @@ enum { PROP_SCALE = 1, PROP_SCALE_TO_FIT, PROP_FILTER, + PROP_CHECKERBOARD, PROP_PLAYING, PROP_HAS_IMAGE, PROP_CAN_ANIMATE, @@ -122,6 +124,9 @@ fiv_view_get_property( case PROP_FILTER: g_value_set_boolean(value, self->filter); break; + case PROP_CHECKERBOARD: + g_value_set_boolean(value, self->checkerboard); + break; case PROP_PLAYING: g_value_set_boolean(value, !!self->frame_update_connection); break; @@ -158,6 +163,10 @@ fiv_view_set_property( if (self->filter != g_value_get_boolean(value)) fiv_view_command(self, FIV_VIEW_COMMAND_TOGGLE_FILTER); break; + case PROP_CHECKERBOARD: + if (self->checkerboard != g_value_get_boolean(value)) + fiv_view_command(self, FIV_VIEW_COMMAND_TOGGLE_CHECKERBOARD); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); } @@ -356,8 +365,8 @@ fiv_view_draw(GtkWidget *widget, cairo_t *cr) // which makes the widget have no double buffering or default background. GtkAllocation allocation; gtk_widget_get_allocation(widget, &allocation); - gtk_render_background(gtk_widget_get_style_context(widget), cr, 0, 0, - allocation.width, allocation.height); + GtkStyleContext *style = gtk_widget_get_style_context(widget); + gtk_render_background(style, cr, 0, 0, allocation.width, allocation.height); FivView *self = FIV_VIEW(widget); if (!self->image || @@ -376,10 +385,17 @@ fiv_view_draw(GtkWidget *widget, cairo_t *cr) if (h < allocation.height) y = round((allocation.height - h) / 2.); - // FIXME: Recording surfaces do not work well with CAIRO_SURFACE_TYPE_XLIB, - // we always get a shitty pixmap, where transparency contains junk. cairo_matrix_t matrix = get_orientation_matrix(self->orientation, sw, sh); cairo_translate(cr, x, y); + if (self->checkerboard) { + gtk_style_context_save(style); + gtk_style_context_add_class(style, "checkerboard"); + gtk_render_background(style, cr, 0, 0, w, h); + gtk_style_context_restore(style); + } + + // FIXME: Recording surfaces do not work well with CAIRO_SURFACE_TYPE_XLIB, + // we always get a shitty pixmap, where transparency contains junk. if (cairo_surface_get_type(self->frame) == CAIRO_SURFACE_TYPE_RECORDING) { cairo_surface_t *image = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); @@ -804,6 +820,8 @@ fiv_view_key_press_event(GtkWidget *widget, GdkEventKey *event) return command(self, FIV_VIEW_COMMAND_TOGGLE_SCALE_TO_FIT); case GDK_KEY_i: return command(self, FIV_VIEW_COMMAND_TOGGLE_FILTER); + case GDK_KEY_t: + return command(self, FIV_VIEW_COMMAND_TOGGLE_CHECKERBOARD); case GDK_KEY_less: return command(self, FIV_VIEW_COMMAND_ROTATE_LEFT); @@ -844,6 +862,9 @@ fiv_view_class_init(FivViewClass *klass) view_properties[PROP_FILTER] = g_param_spec_boolean( "filter", "Use filtering", "Scale images smoothly", TRUE, G_PARAM_READWRITE); + view_properties[PROP_CHECKERBOARD] = g_param_spec_boolean( + "checkerboard", "Show checkerboard", "Highlight transparent background", + TRUE, G_PARAM_READWRITE); view_properties[PROP_PLAYING] = g_param_spec_boolean( "playing", "Playing animation", "An animation is running", FALSE, G_PARAM_READABLE); @@ -885,6 +906,7 @@ fiv_view_init(FivView *self) gtk_widget_set_can_focus(GTK_WIDGET(self), TRUE); self->filter = true; + self->checkerboard = false; self->scale = 1.0; } @@ -975,7 +997,13 @@ fiv_view_command(FivView *self, FivViewCommand command) break; case FIV_VIEW_COMMAND_TOGGLE_FILTER: self->filter = !self->filter; - g_object_notify_by_pspec(G_OBJECT(self), view_properties[PROP_FILTER]); + g_object_notify_by_pspec( + G_OBJECT(self), view_properties[PROP_FILTER]); + gtk_widget_queue_draw(widget); + break; case FIV_VIEW_COMMAND_TOGGLE_CHECKERBOARD: + self->checkerboard = !self->checkerboard; + g_object_notify_by_pspec( + G_OBJECT(self), view_properties[PROP_CHECKERBOARD]); gtk_widget_queue_draw(widget); break; case FIV_VIEW_COMMAND_PRINT: print(self); @@ -42,6 +42,7 @@ typedef enum _FivViewCommand { FIV_VIEW_COMMAND_TOGGLE_PLAYBACK, FIV_VIEW_COMMAND_TOGGLE_FILTER, + FIV_VIEW_COMMAND_TOGGLE_CHECKERBOARD, FIV_VIEW_COMMAND_PRINT, FIV_VIEW_COMMAND_SAVE_PAGE, diff --git a/resources/checkerboard-symbolic.svg b/resources/checkerboard-symbolic.svg new file mode 100644 index 0000000..b22ee66 --- /dev/null +++ b/resources/checkerboard-symbolic.svg @@ -0,0 +1,115 @@ +<?xml version="1.0" encoding="UTF-8"?> +<svg height="16px" viewBox="0 0 16 16" width="16px" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> + <filter id="a" height="100%" width="100%" x="0%" y="0%"> + <feColorMatrix in="SourceGraphic" type="matrix" values="0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 1 0"/> + </filter> + <mask id="b"> + <g filter="url(#a)"> + <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.3"/> + </g> + </mask> + <clipPath id="c"> + <path d="m 0 0 h 1600 v 1200 h -1600 z"/> + </clipPath> + <mask id="d"> + <g filter="url(#a)"> + <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/> + </g> + </mask> + <clipPath id="e"> + <path d="m 0 0 h 1600 v 1200 h -1600 z"/> + </clipPath> + <mask id="f"> + <g filter="url(#a)"> + <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/> + </g> + </mask> + <clipPath id="g"> + <path d="m 0 0 h 1600 v 1200 h -1600 z"/> + </clipPath> + <mask id="h"> + <g filter="url(#a)"> + <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/> + </g> + </mask> + <clipPath id="i"> + <path d="m 0 0 h 1600 v 1200 h -1600 z"/> + </clipPath> + <mask id="j"> + <g filter="url(#a)"> + <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/> + </g> + </mask> + <clipPath id="k"> + <path d="m 0 0 h 1600 v 1200 h -1600 z"/> + </clipPath> + <mask id="l"> + <g filter="url(#a)"> + <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/> + </g> + </mask> + <clipPath id="m"> + <path d="m 0 0 h 1600 v 1200 h -1600 z"/> + </clipPath> + <mask id="n"> + <g filter="url(#a)"> + <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.05"/> + </g> + </mask> + <clipPath id="o"> + <path d="m 0 0 h 1600 v 1200 h -1600 z"/> + </clipPath> + <mask id="p"> + <g filter="url(#a)"> + <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.3"/> + </g> + </mask> + <clipPath id="q"> + <path d="m 0 0 h 1600 v 1200 h -1600 z"/> + </clipPath> + <mask id="r"> + <g filter="url(#a)"> + <path d="m 0 0 h 16 v 16 h -16 z" fill-opacity="0.5"/> + </g> + </mask> + <clipPath id="s"> + <path d="m 0 0 h 1600 v 1200 h -1600 z"/> + </clipPath> + <g clip-path="url(#c)" mask="url(#b)" transform="matrix(1 0 0 1 -256 -756)"> + <path d="m 562.460938 212.058594 h 10.449218 c -1.183594 0.492187 -1.296875 2.460937 0 3 h -10.449218 z m 0 0" fill="#2e3436"/> + </g> + <g clip-path="url(#e)" mask="url(#d)" transform="matrix(1 0 0 1 -256 -756)"> + <path d="m 16 748 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/> + </g> + <g clip-path="url(#g)" mask="url(#f)" transform="matrix(1 0 0 1 -256 -756)"> + <path d="m 17 747 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/> + </g> + <g clip-path="url(#i)" mask="url(#h)" transform="matrix(1 0 0 1 -256 -756)"> + <path d="m 18 750 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/> + </g> + <g clip-path="url(#k)" mask="url(#j)" transform="matrix(1 0 0 1 -256 -756)"> + <path d="m 16 750 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/> + </g> + <g clip-path="url(#m)" mask="url(#l)" transform="matrix(1 0 0 1 -256 -756)"> + <path d="m 17 751 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/> + </g> + <g clip-path="url(#o)" mask="url(#n)" transform="matrix(1 0 0 1 -256 -756)"> + <path d="m 19 751 h 1 v 1 h -1 z m 0 0" fill="#2e3436" fill-rule="evenodd"/> + </g> + <g clip-path="url(#q)" mask="url(#p)" transform="matrix(1 0 0 1 -256 -756)"> + <path d="m 136 776 v 7 h 7 v -7 z m 0 0" fill="#2e3436"/> + </g> + <g clip-path="url(#s)" mask="url(#r)" transform="matrix(1 0 0 1 -256 -756)"> + <path d="m 219 758 h 3 v 12 h -3 z m 0 0" fill="#2e3436"/> + </g> + <g fill="#2e3436"> + <path d="m 14 5 v -3 h -3 v 3 z m 0 0"/> + <path d="m 11 8 v -3 h -3 v 3 z m 0 0"/> + <path d="m 14 11 v -3 h -3 v 3 z m 0 0"/> + <path d="m 11 14 v -3 h -3 v 3 z m 0 0"/> + <path d="m 8 11 v -3 h -3 v 3 z m 0 0"/> + <path d="m 5 14 v -3 h -3 v 3 z m 0 0"/> + <path d="m 5 8 v -3 h -3 v 3 z m 0 0"/> + <path d="m 8 5 v -3 h -3 v 3 z m 0 0"/> + </g> +</svg> diff --git a/resources/resources.gresource.xml b/resources/resources.gresource.xml index ab85308..1a99827 100644 --- a/resources/resources.gresource.xml +++ b/resources/resources.gresource.xml @@ -4,5 +4,6 @@ <file preprocess="xml-stripblanks">circle-filled-symbolic.svg</file> <file preprocess="xml-stripblanks">funnel-symbolic.svg</file> <file preprocess="xml-stripblanks">blend-tool-symbolic.svg</file> + <file preprocess="xml-stripblanks">checkerboard-symbolic.svg</file> </gresource> </gresources> |