📄 pan-view.c
字号:
/* * GQview * (C) 2005 John Ellis * * Author: John Ellis * * This software is released under the GNU General Public License (GNU GPL). * Please read the included file COPYING for more information. * This software comes with no warranty of any kind, use at your own risk! */#include "gqview.h"#include "pan-view.h"#include "cache.h"#include "cache-loader.h"#include "dnd.h"#include "editors.h"#include "filelist.h"#include "fullscreen.h"#include "image.h"#include "image-load.h"#include "img-view.h"#include "info.h"#include "menu.h"#include "pixbuf-renderer.h"#include "pixbuf_util.h"#include "thumb.h"#include "utilops.h"#include "ui_bookmark.h"#include "ui_fileops.h"#include "ui_menu.h"#include "ui_misc.h"#include "ui_tabcomp.h"#include <gdk/gdkkeysyms.h> /* for keyboard values */#include <math.h>#define PAN_WINDOW_DEFAULT_WIDTH 720#define PAN_WINDOW_DEFAULT_HEIGHT 500#define PAN_TILE_SIZE 512#define PAN_THUMB_SIZE_DOTS 4#define PAN_THUMB_SIZE_NONE 24#define PAN_THUMB_SIZE_SMALL 64#define PAN_THUMB_SIZE_NORMAL 128#define PAN_THUMB_SIZE_LARGE 256#define PAN_THUMB_SIZE pw->thumb_size#define PAN_THUMB_GAP_DOTS 2#define PAN_THUMB_GAP_SMALL 14#define PAN_THUMB_GAP_NORMAL 30#define PAN_THUMB_GAP_LARGE 40#define PAN_THUMB_GAP_HUGE 50#define PAN_THUMB_GAP pw->thumb_gap#define PAN_SHADOW_OFFSET 6#define PAN_SHADOW_FADE 5#define PAN_SHADOW_COLOR 0, 0, 0#define PAN_SHADOW_ALPHA 64#define PAN_OUTLINE_THICKNESS 1#define PAN_OUTLINE_COLOR_1 255, 255, 255#define PAN_OUTLINE_COLOR_2 64, 64, 64#define PAN_OUTLINE_ALPHA 180#define PAN_BACKGROUND_COLOR 150, 150, 150#define PAN_GRID_SIZE 60#define PAN_GRID_COLOR 0, 0, 0#define PAN_GRID_ALPHA 20#define PAN_FOLDER_BOX_COLOR 255, 255, 255#define PAN_FOLDER_BOX_ALPHA 100#define PAN_FOLDER_BOX_BORDER 20#define PAN_FOLDER_BOX_OUTLINE_THICKNESS 4#define PAN_FOLDER_BOX_OUTLINE_COLOR 0, 0, 0#define PAN_FOLDER_BOX_OUTLINE_ALPHA 128#define PAN_TEXT_BORDER_SIZE 4#define PAN_TEXT_COLOR 0, 0, 0#define PAN_POPUP_COLOR 255, 255, 225#define PAN_POPUP_ALPHA 255#define PAN_POPUP_BORDER 1#define PAN_POPUP_BORDER_COLOR 0, 0, 0#define PAN_POPUP_TEXT_COLOR 0, 0, 0#define PAN_CAL_POPUP_COLOR 220, 220, 220#define PAN_CAL_POPUP_ALPHA 255#define PAN_CAL_POPUP_BORDER 1#define PAN_CAL_POPUP_BORDER_COLOR 0, 0, 0#define PAN_CAL_POPUP_TEXT_COLOR 0, 0, 0#define PAN_CAL_DAY_WIDTH 100#define PAN_CAL_DAY_HEIGHT 80#define PAN_CAL_DAY_COLOR 255, 255, 255#define PAN_CAL_DAY_ALPHA 220#define PAN_CAL_DAY_BORDER 2#define PAN_CAL_DAY_BORDER_COLOR 0, 0, 0#define PAN_CAL_DAY_TEXT_COLOR 0, 0, 0#define PAN_CAL_MONTH_COLOR 255, 255, 255#define PAN_CAL_MONTH_ALPHA 200#define PAN_CAL_MONTH_BORDER 4#define PAN_CAL_MONTH_BORDER_COLOR 0, 0, 0#define PAN_CAL_MONTH_TEXT_COLOR 0, 0, 0#define PAN_CAL_DOT_SIZE 3#define PAN_CAL_DOT_GAP 2#define PAN_CAL_DOT_COLOR 128, 128, 128#define PAN_CAL_DOT_ALPHA 128#define PAN_GROUP_MAX 16#define ZOOM_INCREMENT 1.0#define ZOOM_LABEL_WIDTH 64#define PAN_PREF_GROUP "pan_view_options"#define PAN_PREF_HIDE_WARNING "hide_performance_warning"#define PAN_PREF_EXIF_DATE "use_exif_date"typedef enum { LAYOUT_TIMELINE = 0, LAYOUT_CALENDAR, LAYOUT_FOLDERS_LINEAR, LAYOUT_FOLDERS_FLOWER, LAYOUT_GRID,} LayoutType;typedef enum { LAYOUT_SIZE_THUMB_DOTS = 0, LAYOUT_SIZE_THUMB_NONE, LAYOUT_SIZE_THUMB_SMALL, LAYOUT_SIZE_THUMB_NORMAL, LAYOUT_SIZE_THUMB_LARGE, LAYOUT_SIZE_10, LAYOUT_SIZE_25, LAYOUT_SIZE_33, LAYOUT_SIZE_50, LAYOUT_SIZE_100} LayoutSize;typedef enum { ITEM_NONE, ITEM_THUMB, ITEM_BOX, ITEM_TRIANGLE, ITEM_TEXT, ITEM_IMAGE} ItemType;typedef enum { TEXT_ATTR_NONE = 0, TEXT_ATTR_BOLD = 1 << 0, TEXT_ATTR_HEADING = 1 << 1, TEXT_ATTR_MARKUP = 1 << 2} TextAttrType;enum { BORDER_NONE = 0, BORDER_1 = 1 << 0, BORDER_2 = 1 << 1, BORDER_3 = 1 << 2, BORDER_4 = 1 << 3};typedef struct _PanItem PanItem;struct _PanItem { ItemType type; gint x; gint y; gint width; gint height; gchar *key; FileData *fd; GdkPixbuf *pixbuf; gint refcount; gchar *text; TextAttrType text_attr; guint8 color_r; guint8 color_g; guint8 color_b; guint8 color_a; guint8 color2_r; guint8 color2_g; guint8 color2_b; guint8 color2_a; gint border; gpointer data; gint queued;};typedef struct _PanWindow PanWindow;struct _PanWindow{ GtkWidget *window; ImageWindow *imd; ImageWindow *imd_normal; FullScreenData *fs; GtkWidget *path_entry; GtkWidget *label_message; GtkWidget *label_zoom; GtkWidget *search_box; GtkWidget *search_entry; GtkWidget *search_label; GtkWidget *search_button; GtkWidget *search_button_arrow; GtkWidget *date_button; GtkWidget *scrollbar_h; GtkWidget *scrollbar_v; gint overlay_id; gchar *path; LayoutType layout; LayoutSize size; gint thumb_size; gint thumb_gap; gint image_size; gint exif_date_enable; gint ignore_symlinks; GList *list; GList *list_static; GList *list_grid; GList *cache_list; GList *cache_todo; gint cache_count; gint cache_total; gint cache_tick; CacheLoader *cache_cl; ImageLoader *il; ThumbLoader *tl; PanItem *queue_pi; GList *queue; PanItem *click_pi; PanItem *search_pi; gint idle_id;};typedef struct _PanGrid PanGrid;struct _PanGrid { gint x; gint y; gint w; gint h; GList *list;};typedef struct _PanCacheData PanCacheData;struct _PanCacheData { FileData fd; CacheData *cd;};static GList *pan_window_list = NULL;static GList *pan_window_layout_list(const gchar *path, SortType sort, gint ascend, gint ignore_symlinks);static GList *pan_layout_intersect(PanWindow *pw, gint x, gint y, gint width, gint height);static void pan_window_layout_update_idle(PanWindow *pw);static GtkWidget *pan_popup_menu(PanWindow *pw);static void pan_fullscreen_toggle(PanWindow *pw, gint force_off);static void pan_window_close(PanWindow *pw);static void pan_window_dnd_init(PanWindow *pw);typedef enum { DATE_LENGTH_EXACT, DATE_LENGTH_HOUR, DATE_LENGTH_DAY, DATE_LENGTH_WEEK, DATE_LENGTH_MONTH, DATE_LENGTH_YEAR} DateLengthType;static gint date_compare(time_t a, time_t b, DateLengthType length){ struct tm ta; struct tm tb; if (length == DATE_LENGTH_EXACT) return (a == b); if (!localtime_r(&a, &ta) || !localtime_r(&b, &tb)) return FALSE; if (ta.tm_year != tb.tm_year) return FALSE; if (length == DATE_LENGTH_YEAR) return TRUE; if (ta.tm_mon != tb.tm_mon) return FALSE; if (length == DATE_LENGTH_MONTH) return TRUE; if (length == DATE_LENGTH_WEEK) return (ta.tm_yday / 7 == tb.tm_yday / 7); if (ta.tm_mday != tb.tm_mday) return FALSE; if (length == DATE_LENGTH_DAY) return TRUE; return (ta.tm_hour == tb.tm_hour);}static gint date_value(time_t d, DateLengthType length){ struct tm td; if (!localtime_r(&d, &td)) return -1; switch (length) { case DATE_LENGTH_DAY: return td.tm_mday; break; case DATE_LENGTH_WEEK: return td.tm_wday; break; case DATE_LENGTH_MONTH: return td.tm_mon + 1; break; case DATE_LENGTH_YEAR: return td.tm_year + 1900; break; case DATE_LENGTH_EXACT: default: break; } return -1;}static gchar *date_value_string(time_t d, DateLengthType length){ struct tm td; gchar buf[128]; gchar *format = NULL; if (!localtime_r(&d, &td)) return g_strdup(""); switch (length) { case DATE_LENGTH_DAY: return g_strdup_printf("%d", td.tm_mday); break; case DATE_LENGTH_WEEK: format = "%A %e"; break; case DATE_LENGTH_MONTH: format = "%B %Y"; break; case DATE_LENGTH_YEAR: return g_strdup_printf("%d", td.tm_year + 1900); break; case DATE_LENGTH_EXACT: default: return g_strdup(text_from_time(d)); break; } if (format && strftime(buf, sizeof(buf), format, &td) > 0) { gchar *ret = g_locale_to_utf8(buf, -1, NULL, NULL, NULL); if (ret) return ret; } return g_strdup("");}static time_t date_to_time(gint year, gint month, gint day){ struct tm lt; lt.tm_sec = 0; lt.tm_min = 0; lt.tm_hour = 0; lt.tm_mday = (day >= 1 && day <= 31) ? day : 1; lt.tm_mon = (month >= 1 && month <= 12) ? month - 1 : 0; lt.tm_year = year - 1900; lt.tm_isdst = 0; return mktime(<);}/* *----------------------------------------------------------------------------- * cache *----------------------------------------------------------------------------- */static void pan_cache_free(PanWindow *pw){ GList *work; work = pw->cache_list; while (work) { PanCacheData *pc; pc = work->data; work = work->next; cache_sim_data_free(pc->cd); file_data_free((FileData *)pc); } g_list_free(pw->cache_list); pw->cache_list = NULL; filelist_free(pw->cache_todo); pw->cache_todo = NULL; pw->cache_count = 0; pw->cache_total = 0; pw->cache_tick = 0; cache_loader_free(pw->cache_cl); pw->cache_cl = NULL;}static void pan_cache_fill(PanWindow *pw, const gchar *path){ GList *list; pan_cache_free(pw); list = pan_window_layout_list(path, SORT_NAME, TRUE, pw->ignore_symlinks); pw->cache_todo = g_list_reverse(list); pw->cache_total = g_list_length(pw->cache_todo);}static void pan_cache_step_done_cb(CacheLoader *cl, gint error, gpointer data){ PanWindow *pw = data; if (pw->cache_list) { PanCacheData *pc; pc = pw->cache_list->data; if (!pc->cd) { pc->cd = cl->cd; cl->cd = NULL; } } cache_loader_free(cl); pw->cache_cl = NULL; pan_window_layout_update_idle(pw);}static gint pan_cache_step(PanWindow *pw){ FileData *fd; PanCacheData *pc; CacheDataType load_mask; if (!pw->cache_todo) return TRUE; fd = pw->cache_todo->data; pw->cache_todo = g_list_remove(pw->cache_todo, fd);#if 0 if (enable_thumb_caching) { gchar *found; found = cache_find_location(CACHE_TYPE_SIM, fd->path); if (found && filetime(found) == fd->date) { cd = cache_sim_data_load(found); } g_free(found); } if (!cd) cd = cache_sim_data_new(); if (!cd->dimensions) { cd->dimensions = image_load_dimensions(fd->path, &cd->width, &cd->height); if (enable_thumb_caching && cd->dimensions) { gchar *base; mode_t mode = 0755; base = cache_get_location(CACHE_TYPE_SIM, fd->path, FALSE, &mode); if (cache_ensure_dir_exists(base, mode)) { g_free(cd->path); cd->path = cache_get_location(CACHE_TYPE_SIM, fd->path, TRUE, NULL); if (cache_sim_data_save(cd)) { filetime_set(cd->path, filetime(fd->path)); } } g_free(base); } pw->cache_tick = 9; }#endif pc = g_new0(PanCacheData, 1); memcpy(pc, fd, sizeof(FileData)); g_free(fd); pc->cd = NULL; pw->cache_list = g_list_prepend(pw->cache_list, pc); cache_loader_free(pw->cache_cl); load_mask = CACHE_LOADER_NONE; if (pw->size > LAYOUT_SIZE_THUMB_LARGE) load_mask |= CACHE_LOADER_DIMENSIONS; if (pw->exif_date_enable) load_mask |= CACHE_LOADER_DATE; pw->cache_cl = cache_loader_new(((FileData *)pc)->path, load_mask, pan_cache_step_done_cb, pw); return (pw->cache_cl == NULL);}/* This sync date function is optimized for lists with a common sort */static void pan_cache_sync_date(PanWindow *pw, GList *list){ GList *haystack; GList *work; haystack = g_list_copy(pw->cache_list); work = list; while (work) { FileData *fd; GList *needle; fd = work->data; work = work->next; needle = haystack; while (needle) { PanCacheData *pc; gchar *path; pc = needle->data; path = ((FileData *)pc)->path; if (path && strcmp(path, fd->path) == 0) { if (pc->cd && pc->cd->have_date && pc->cd->date >= 0) { fd->date = pc->cd->date; } haystack = g_list_delete_link(haystack, needle); needle = NULL; } else { needle = needle->next; } } } g_list_free(haystack);}/* *----------------------------------------------------------------------------- * item grid *----------------------------------------------------------------------------- */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -