* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#include "pixbuf-renderer.h"
+
#include <cmath>
#include <cstdlib>
#include <cstring>
-#include "main.h"
-#include "pixbuf-renderer.h"
-
+#include "debug.h"
+#include "main-defines.h"
+#include "options.h"
#include "renderer-tiles.h"
/* comment this out if not using this from within Geeqie
#define GQ_BUILD 1
#ifdef GQ_BUILD
-#include "main.h"
-#include "pixbuf-util.h"
#include "exif.h"
+#include "pixbuf-util.h"
#else
enum ExifOrientationType {
EXIF_ORIENTATION_UNKNOWN = 0,
};
#endif
-
-/* default min and max zoom */
-#define PR_ZOOM_MIN (-32.0)
-#define PR_ZOOM_MAX 32.0
+namespace
+{
/* distance to drag mouse to disable image flip */
-#define PR_DRAG_SCROLL_THRESHHOLD 4
+constexpr gint PR_DRAG_SCROLL_THRESHHOLD = 4;
/* increase pan rate when holding down shift */
-#define PR_PAN_SHIFT_MULTIPLIER 6
+constexpr gint PR_PAN_SHIFT_MULTIPLIER = 6;
-/* scroller config */
-#define PR_SCROLLER_UPDATES_PER_SEC 30
-#define PR_SCROLLER_DEAD_ZONE 6
+} // namespace
-/* when scaling image to below this size, use nearest pixel for scaling
- * (below about 4, the other scale types become slow generating their conversion tables)
- */
-#define PR_MIN_SCALE_SIZE 8
+/* default min and max zoom */
+#define PR_ZOOM_MIN (-32.0)
+#define PR_ZOOM_MAX 32.0
+
+/* scroller config */
+enum {
+ PR_SCROLLER_UPDATES_PER_SEC = 30,
+ PR_SCROLLER_DEAD_ZONE = 6
+};
enum {
SIGNAL_ZOOM = 0,
FALSE,
static_cast<GParamFlags>(G_PARAM_READABLE | G_PARAM_WRITABLE)));
g_object_class_install_property(gobject_class,
- PROP_SCROLL_RESET,
- g_param_spec_uint("scroll_reset",
- "New image scroll reset",
- nullptr,
- PR_SCROLL_RESET_TOPLEFT,
- PR_SCROLL_RESET_NOCHANGE,
- PR_SCROLL_RESET_TOPLEFT,
- static_cast<GParamFlags>(G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ PROP_SCROLL_RESET,
+ g_param_spec_uint("scroll_reset",
+ "New image scroll reset",
+ nullptr,
+ ScrollReset::TOPLEFT,
+ ScrollReset::NOCHANGE,
+ ScrollReset::TOPLEFT,
+ static_cast<GParamFlags>(G_PARAM_READABLE | G_PARAM_WRITABLE)));
g_object_class_install_property(gobject_class,
PROP_DELAY_FLIP,
pr->scale = 1.0;
pr->aspect_ratio = 1.0;
- pr->scroll_reset = PR_SCROLL_RESET_TOPLEFT;
+ pr->scroll_reset = ScrollReset::TOPLEFT;
pr->scroller_id = 0;
pr->scroller_overlay = -1;
pr->zoom_expand = g_value_get_boolean(value);
break;
case PROP_SCROLL_RESET:
- pr->scroll_reset = static_cast<PixbufRendererScrollResetType>(g_value_get_uint(value));
+ pr->scroll_reset = static_cast<ScrollReset>(g_value_get_uint(value));
break;
case PROP_DELAY_FLIP:
pr->delay_flip = g_value_get_boolean(value);
if (cursor) g_object_unref(G_OBJECT(cursor));
}
-gboolean pr_clip_region(gint x, gint y, gint w, gint h,
- gint clip_x, gint clip_y, gint clip_w, gint clip_h,
- gint *rx, gint *ry, gint *rw, gint *rh)
-{
- if (clip_x + clip_w <= x ||
- clip_x >= x + w ||
- clip_y + clip_h <= y ||
- clip_y >= y + h)
- {
- return FALSE;
- }
-
- *rx = MAX(x, clip_x);
- *rw = MIN((x + w), (clip_x + clip_w)) - *rx;
-
- *ry = MAX(y, clip_y);
- *rh = MIN((y + h), (clip_y + clip_h)) - *ry;
-
- return TRUE;
-}
-
static gboolean pr_parent_window_sizable(PixbufRenderer *pr)
{
GdkWindowState state;
{
GtkWidget *widget;
GtkWidget *parent;
- gint ww, wh;
+ gint ww;
+ gint wh;
GtkAllocation widget_allocation;
GtkAllocation parent_allocation;
static gboolean pr_scroller_update_cb(gpointer data)
{
auto pr = static_cast<PixbufRenderer *>(data);
- gint x, y;
- gint xinc, yinc;
+ gint x;
+ gint y;
+ gint xinc;
+ gint yinc;
/* this was a simple scroll by difference between scroller and mouse position,
* but all this math results in a smoother result and accounts for a dead zone.
if (pr->scroller_overlay == -1)
{
GdkPixbuf *pixbuf;
- gint w, h;
+ gint w;
+ gint h;
#ifdef GQ_BUILD
pixbuf = gdk_pixbuf_new_from_resource(GQ_RESOURCE_PATH_ICONS "/" PIXBUF_INLINE_SCROLLER ".png", nullptr);
static gboolean pr_source_tile_visible(PixbufRenderer *pr, SourceTile *st)
{
- gint x1, y1, x2, y2;
+ gint x1;
+ gint y1;
+ gint x2;
+ gint y2;
if (!st) return FALSE;
GList *pr_source_tile_compute_region(PixbufRenderer *pr, gint x, gint y, gint w, gint h, gboolean request)
{
- gint x1, y1;
+ gint x1;
+ gint y1;
GList *list = nullptr;
- gint sx, sy;
+ gint sx;
+ gint sy;
if (x < 0) x = 0;
if (y < 0) y = 0;
static void pr_source_tile_changed(PixbufRenderer *pr, gint x, gint y, gint width, gint height)
{
- GList *work;
-
if (width < 1 || height < 1) return;
- work = pr->source_tiles;
- while (work)
+ const GdkRectangle request_rect{x, y, width, height};
+ GdkRectangle st_rect{0, 0, pr->source_tile_width, pr->source_tile_height};
+ GdkRectangle r;
+
+ for (GList *work = pr->source_tiles; work; work = work->next)
{
- SourceTile *st;
- gint rx, ry, rw, rh;
+ auto *st = static_cast<SourceTile *>(work->data);
- st = static_cast<SourceTile *>(work->data);
- work = work->next;
+ st_rect.x = st->x;
+ st_rect.y = st->y;
- if (pr_clip_region(st->x, st->y, pr->source_tile_width, pr->source_tile_height,
- x, y, width, height,
- &rx, &ry, &rw, &rh))
+ if (gdk_rectangle_intersect(&st_rect, &request_rect, &r))
{
GdkPixbuf *pixbuf;
- pixbuf = gdk_pixbuf_new_subpixbuf(st->pixbuf, rx - st->x, ry - st->y, rw, rh);
+ pixbuf = gdk_pixbuf_new_subpixbuf(st->pixbuf, r.x - st->x, r.y - st->y, r.width, r.height);
if (pr->func_tile_request &&
- pr->func_tile_request(pr, rx, ry, rw, rh, pixbuf, pr->func_tile_data))
+ pr->func_tile_request(pr, r.x, r.y, r.width, r.height, pixbuf, pr->func_tile_data))
{
- pr->renderer->invalidate_region(pr->renderer, rx * pr->scale, ry * pr->scale,
- rw * pr->scale, rh * pr->scale);
- if (pr->renderer2) pr->renderer2->invalidate_region(pr->renderer2, rx * pr->scale, ry * pr->scale,
- rw * pr->scale, rh * pr->scale);
+ r.x *= pr->scale;
+ r.y *= pr->scale;
+ r.width *= pr->scale;
+ r.height *= pr->scale;
+
+ pr->renderer->invalidate_region(pr->renderer, r.x, r.y, r.width, r.height);
+ if (pr->renderer2) pr->renderer2->invalidate_region(pr->renderer2, r.x, r.y, r.width, r.height);
}
g_object_unref(pixbuf);
}
static void pixbuf_renderer_sync_scroll_center(PixbufRenderer *pr)
{
- gint src_x, src_y;
+ gint src_x;
+ gint src_y;
if (!pr->width || !pr->height) return;
/*
static gboolean pr_size_clamp(PixbufRenderer *pr)
{
- gint old_vw, old_vh;
+ gint old_vw;
+ gint old_vh;
old_vw = pr->vis_width;
old_vh = pr->vis_height;
static gboolean pr_zoom_clamp(PixbufRenderer *pr, gdouble zoom,
PrZoomFlags flags)
{
- gint w, h;
+ gint w;
+ gint h;
gdouble scale;
gboolean force = !!(flags & PR_ZOOM_FORCE);
gboolean new_z = !!(flags & PR_ZOOM_NEW);
PrZoomFlags flags, gint px, gint py)
{
gdouble old_scale;
- gint old_cx, old_cy;
+ gint old_cx;
+ gint old_cy;
gboolean center_point = !!(flags & PR_ZOOM_CENTER);
gboolean force = !!(flags & PR_ZOOM_FORCE);
gboolean new_z = !!(flags & PR_ZOOM_NEW);
{
switch (pr->scroll_reset)
{
- case PR_SCROLL_RESET_NOCHANGE:
+ case ScrollReset::NOCHANGE:
/* maintain old scroll position */
- pr->x_scroll = (static_cast<gdouble>(pr->image_width) * old_center_x * pr->scale) - pr->vis_width / 2;
- pr->y_scroll = (static_cast<gdouble>(pr->image_height) * old_center_y * pr->scale * pr->aspect_ratio) - pr->vis_height / 2;
+ pr->x_scroll = (static_cast<gdouble>(pr->image_width) * old_center_x * pr->scale) - pr->vis_width / 2.0;
+ pr->y_scroll = (static_cast<gdouble>(pr->image_height) * old_center_y * pr->scale * pr->aspect_ratio) - pr->vis_height / 2.0;
break;
- case PR_SCROLL_RESET_CENTER:
+ case ScrollReset::CENTER:
/* center new image */
- pr->x_scroll = (static_cast<gdouble>(pr->image_width) / 2.0 * pr->scale) - pr->vis_width / 2;
- pr->y_scroll = (static_cast<gdouble>(pr->image_height) / 2.0 * pr->scale * pr->aspect_ratio) - pr->vis_height / 2;
+ pr->x_scroll = (static_cast<gdouble>(pr->image_width) / 2.0 * pr->scale) - pr->vis_width / 2.0;
+ pr->y_scroll = (static_cast<gdouble>(pr->image_height) / 2.0 * pr->scale * pr->aspect_ratio) - pr->vis_height / 2.0;
break;
- case PR_SCROLL_RESET_TOPLEFT:
+ case ScrollReset::TOPLEFT:
default:
/* reset to upper left */
pr->x_scroll = 0;
}
else
{
- pr->x_scroll = old_cx / old_scale * pr->scale - (pr->vis_width / 2);
- pr->y_scroll = old_cy / old_scale * pr->scale * pr->aspect_ratio - (pr->vis_height / 2);
+ pr->x_scroll = old_cx / old_scale * pr->scale - (pr->vis_width / 2.0);
+ pr->y_scroll = old_cy / old_scale * pr->scale * pr->aspect_ratio - (pr->vis_height / 2.0);
}
}
if (pixbuf_renderer_overlay_get(pr, pr->scroller_overlay, &pixbuf, nullptr, nullptr))
{
- gint w, h;
+ gint w;
+ gint h;
w = gdk_pixbuf_get_width(pixbuf);
h = gdk_pixbuf_get_height(pixbuf);
void pixbuf_renderer_scroll(PixbufRenderer *pr, gint x, gint y)
{
- gint old_x, old_y;
- gint x_off, y_off;
+ gint old_x;
+ gint old_y;
+ gint x_off;
+ gint y_off;
g_return_if_fail(IS_PIXBUF_RENDERER(pr));
void pixbuf_renderer_scroll_to_point(PixbufRenderer *pr, gint x, gint y,
gdouble x_align, gdouble y_align)
{
- gint px, py;
- gint ax, ay;
+ gint px;
+ gint py;
+ gint ax;
+ gint ay;
x_align = CLAMP(x_align, 0.0, 1.0);
y_align = CLAMP(y_align, 0.0, 1.0);
void pixbuf_renderer_set_scroll_center(PixbufRenderer *pr, gdouble x, gdouble y)
{
- gdouble dst_x, dst_y;
+ gdouble dst_x;
+ gdouble dst_y;
- dst_x = x * pr->width - pr->vis_width / 2 - pr->x_scroll + CLAMP(pr->subpixel_x_scroll, -1.0, 1.0);
- dst_y = y * pr->height - pr->vis_height / 2 - pr->y_scroll + CLAMP(pr->subpixel_y_scroll, -1.0, 1.0);
+ dst_x = x * pr->width - pr->vis_width / 2.0 - pr->x_scroll + CLAMP(pr->subpixel_x_scroll, -1.0, 1.0);
+ dst_y = y * pr->height - pr->vis_height / 2.0 - pr->y_scroll + CLAMP(pr->subpixel_y_scroll, -1.0, 1.0);
pr->subpixel_x_scroll = dst_x - static_cast<gint>(dst_x);
pr->subpixel_y_scroll = dst_y - static_cast<gint>(dst_y);
/* This is a hack, but work far the best, at least for single pointer systems.
* See https://bugzilla.gnome.org/show_bug.cgi?id=587714 for more. */
- gint x, y;
+ gint x;
+ gint y;
seat = gdk_display_get_default_seat(gdk_window_get_display(event->window));
device = gdk_seat_get_pointer(seat);
*-------------------------------------------------------------------
*/
-#define COLOR_BYTES 3 /* rgb */
-#define RC 0 /* Red-Cyan */
-#define GM 1 /* Green-Magenta */
-#define YB 2 /* Yellow-Blue */
+enum {
+ COLOR_BYTES = 3, /* rgb */
+ RC = 0, /* Red-Cyan */
+ GM = 1, /* Green-Magenta */
+ YB = 2 /* Yellow-Blue */
+};
static void pr_create_anaglyph_color(GdkPixbuf *pixbuf, GdkPixbuf *right, gint x, gint y, gint w, gint h, guint mode)
{
- gint srs, drs;
- guchar *s_pix, *d_pix;
- guchar *sp, *dp;
- guchar *spi, *dpi;
- gint i, j;
+ gint srs;
+ gint drs;
+ guchar *s_pix;
+ guchar *d_pix;
+ guchar *sp;
+ guchar *dp;
+ guchar *spi;
+ guchar *dpi;
+ gint i;
+ gint j;
srs = gdk_pixbuf_get_rowstride(right);
s_pix = gdk_pixbuf_get_pixels(right);
dp[0] = sp[0];
dp[1] = sp[1];
break;
+ default:
+ break;
}
sp += COLOR_BYTES;
dp += COLOR_BYTES;
static void pr_create_anaglyph_gray(GdkPixbuf *pixbuf, GdkPixbuf *right, gint x, gint y, gint w, gint h, guint mode)
{
- gint srs, drs;
- guchar *s_pix, *d_pix;
- guchar *sp, *dp;
- guchar *spi, *dpi;
- gint i, j;
+ gint srs;
+ gint drs;
+ guchar *s_pix;
+ guchar *d_pix;
+ guchar *sp;
+ guchar *dp;
+ guchar *spi;
+ guchar *dpi;
+ gint i;
+ gint j;
const double gc[3] = {0.299, 0.587, 0.114};
srs = gdk_pixbuf_get_rowstride(right);
dp[1] = g2;
dp[2] = g1;
break;
+ default:
+ break;
}
sp += COLOR_BYTES;
dp += COLOR_BYTES;
static void pr_create_anaglyph_dubois(GdkPixbuf *pixbuf, GdkPixbuf *right, gint x, gint y, gint w, gint h, guint mode)
{
- gint srs, drs;
- guchar *s_pix, *d_pix;
- guchar *sp, *dp;
- guchar *spi, *dpi;
- gint i, j, k;
+ gint srs;
+ gint drs;
+ guchar *s_pix;
+ guchar *d_pix;
+ guchar *sp;
+ guchar *dp;
+ guchar *spi;
+ guchar *dpi;
+ gint i;
+ gint j;
+ gint k;
double pr_dubois_matrix[3][6];
static const double pr_dubois_matrix_RC[3][6] = {
{ 0.456, 0.500, 0.176, -0.043, -0.088, -0.002},
case YB:
memcpy(pr_dubois_matrix, pr_dubois_matrix_YB, sizeof pr_dubois_matrix);
break;
+ default:
+ break;
}
srs = gdk_pixbuf_get_rowstride(right);
void pixbuf_renderer_move(PixbufRenderer *pr, PixbufRenderer *source)
{
GObject *object;
- PixbufRendererScrollResetType scroll_reset;
+ ScrollReset scroll_reset;
g_return_if_fail(IS_PIXBUF_RENDERER(pr));
g_return_if_fail(IS_PIXBUF_RENDERER(source));
pr->y_mouse = source->y_mouse;
scroll_reset = pr->scroll_reset;
- pr->scroll_reset = PR_SCROLL_RESET_NOCHANGE;
+ pr->scroll_reset = ScrollReset::NOCHANGE;
pr->func_post_process = source->func_post_process;
pr->post_process_user_data = source->post_process_user_data;
void pixbuf_renderer_copy(PixbufRenderer *pr, PixbufRenderer *source)
{
GObject *object;
- PixbufRendererScrollResetType scroll_reset;
+ ScrollReset scroll_reset;
g_return_if_fail(IS_PIXBUF_RENDERER(pr));
g_return_if_fail(IS_PIXBUF_RENDERER(source));
pr->y_mouse = source->y_mouse;
scroll_reset = pr->scroll_reset;
- pr->scroll_reset = PR_SCROLL_RESET_NOCHANGE;
+ pr->scroll_reset = ScrollReset::NOCHANGE;
pr->orientation = source->orientation;
pr->stereo_data = source->stereo_data;
gint *r_mouse, gint *g_mouse, gint *b_mouse)
{
GdkPixbuf *pb = pr->pixbuf;
- gint p_alpha, prs;
- guchar *p_pix, *pp;
- gint map_x, map_y, map_w, map_h;
- size_t xoff, yoff;
+ gint p_alpha;
+ gint prs;
+ guchar *p_pix;
+ guchar *pp;
+ gint map_x;
+ gint map_y;
+ gint map_w;
+ gint map_h;
+ size_t xoff;
+ size_t yoff;
g_return_val_if_fail(IS_PIXBUF_RENDERER(pr), FALSE);
g_return_val_if_fail(r_mouse != nullptr && g_mouse != nullptr && b_mouse != nullptr, FALSE);
gboolean pixbuf_renderer_get_mouse_position(PixbufRenderer *pr, gint *x_pixel_return, gint *y_pixel_return)
{
- gint x_pixel, y_pixel, x_pixel_clamped, y_pixel_clamped;
+ gint x_pixel;
+ gint y_pixel;
+ gint x_pixel_clamped;
+ gint y_pixel_clamped;
g_return_val_if_fail(IS_PIXBUF_RENDERER(pr), FALSE);
g_return_val_if_fail(x_pixel_return != nullptr && y_pixel_return != nullptr, FALSE);