changeset 18:53aa5ef798c9

##### Note: GQview CVS on sourceforge is not always up to date, please use ##### ##### an offical release when making enhancements and translation updates. ##### Fri Mar 4 21:53:03 2005 John Ellis <johne@verizon.net> * pan-view.c: Add calendar view. Make mouse wheel scroll. * po/POTFILES.in: Add pan-view.c for translation.
author John Ellis <johne@verizon.net>
date Sat, 05 Mar 2005 03:00:57 +0000
parents 5fbd6210ddf7
children 076c69f6adec
files ChangeLog TODO po/POTFILES.in src/pan-view.c
diffstat 4 files changed, 431 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Thu Mar 03 23:03:06 2005 +0000
+++ b/ChangeLog	Sat Mar 05 03:00:57 2005 +0000
@@ -1,3 +1,8 @@
+Fri Mar  4 21:53:03 2005  John Ellis  <johne@verizon.net>
+
+	* pan-view.c: Add calendar view. Make mouse wheel scroll.
+	* po/POTFILES.in: Add pan-view.c for translation.
+
 Thu Mar  3 17:57:46 2005  John Ellis  <johne@verizon.net>
 
 	* pan-view.c: Make subsequent searches for same string step through all
--- a/TODO	Thu Mar 03 23:03:06 2005 +0000
+++ b/TODO	Sat Mar 05 03:00:57 2005 +0000
@@ -25,6 +25,9 @@
    > time line view:
     d> searching by date should scroll to proper alignment with year/month/day boundaries.
 
+   > calendar view:
+     > fix search.
+
    > grid view:
      > allow sorting by name, date, size, dimensions, etc.
 
--- a/po/POTFILES.in	Thu Mar 03 23:03:06 2005 +0000
+++ b/po/POTFILES.in	Sat Mar 05 03:00:57 2005 +0000
@@ -20,6 +20,7 @@
 ./src/layout_util.c
 ./src/main.c
 ./src/menu.c
+./src/pan-view.c
 ./src/preferences.c
 ./src/print.c
 ./src/rcfile.c
--- a/src/pan-view.c	Thu Mar 03 23:03:06 2005 +0000
+++ b/src/pan-view.c	Sat Mar 05 03:00:57 2005 +0000
@@ -100,6 +100,7 @@
 
 typedef enum {
 	LAYOUT_TIMELINE = 0,
+	LAYOUT_CALENDAR,
 	LAYOUT_FOLDERS_LINEAR,
 	LAYOUT_FOLDERS_FLOWER,
 	LAYOUT_GRID,
@@ -236,6 +237,8 @@
 
 static GList *pan_window_layout_list(const gchar *path, SortType sort, gint ascend);
 
+static GList *pan_layout_intersect(PanWindow *pw, gint x, gint y, gint width, gint height);
+
 static GtkWidget *pan_popup_menu(PanWindow *pw);
 static void pan_fullscreen_toggle(PanWindow *pw, gint force_off);
 static void pan_overlay_toggle(PanWindow *pw);
@@ -309,6 +312,34 @@
 	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;
@@ -1075,6 +1106,8 @@
 	if (!pi) return;
 
 	if (pw->click_pi == pi) pw->click_pi = NULL;
+	if (pw->queue_pi == pi)	pw->queue_pi = NULL;
+	pw->queue = g_list_remove(pw->queue, pi);
 
 	pw->list = g_list_remove(pw->list, pi);
 	image_area_changed(pw->imd, pi->x, pi->y, pi->width, pi->height);
@@ -1233,7 +1266,7 @@
 	return g_list_reverse(list);
 }
 
-static PanItem *pan_item_find_by_coord(PanWindow *pw, ItemType type, gint x, gint y)
+static PanItem *pan_item_find_by_coord(PanWindow *pw, ItemType type, gint x, gint y, const gchar *key)
 {
 	GList *work;
 
@@ -1248,7 +1281,8 @@
 		pi = work->data;
 		if ((pi->type == type || type == ITEM_NONE) &&
 		     x >= pi->x && x < pi->x + pi->width &&
-		     y >= pi->y && y < pi->y + pi->height)
+		     y >= pi->y && y < pi->y + pi->height &&
+		    (!key || (pi->key && strcmp(pi->key, key) == 0)))
 			{
 			return pi;
 			}
@@ -1798,6 +1832,343 @@
 	if (height) *height = h;
 }
 
+/*
+ *-----------------------------------------------------------------------------
+ * calendar
+ *-----------------------------------------------------------------------------
+ */
+
+#define PAN_CAL_DAY_WIDTH 100
+#define PAN_CAL_DAY_HEIGHT 80
+#define PAN_CAL_DOT_SIZE 3
+#define PAN_CAL_DOT_GAP 2
+#define PAN_CAL_DOT_COLOR 0, 0, 0
+#define PAN_CAL_DOT_ALPHA 32
+
+static void pan_calendar_update(PanWindow *pw, PanItem *pi_day)
+{
+	PanItem *pbox;
+	PanItem *pi;
+	GList *list;
+	GList *work;
+	gint x1, y1, x2, y2, x3, y3;
+	gint x, y, w, h;
+	gint grid;
+	gint column;
+	
+	while ((pi = pan_item_find_by_key(pw, ITEM_NONE, "day_bubble"))) pan_item_remove(pw, pi);
+
+	if (!pi_day || pi_day->type != ITEM_BOX ||
+	    !pi_day->key || strcmp(pi_day->key, "day") != 0) return;
+
+	list = pan_layout_intersect(pw, pi_day->x, pi_day->y, pi_day->width, pi_day->height);
+
+	work = list;
+	while (work)
+		{
+		PanItem *dot;
+		GList *node;
+
+		dot = work->data;
+		node = work;
+		work = work->next;
+
+		if (dot->type != ITEM_BOX || !dot->fd ||
+		    !dot->key || strcmp(dot->key, "dot") != 0)
+			{
+			list = g_list_delete_link(list, node);
+			}
+		}
+
+	if (!list) return;
+
+	grid = (gint)(sqrt(g_list_length(list)) + 0.5);
+
+	x = pi_day->x + pi_day->width + 4;
+	y = pi_day->y;
+
+#if 0
+	if (y + grid * (PAN_THUMB_SIZE + PAN_THUMB_GAP) + PAN_FOLDER_BOX_BORDER * 4 > pw->imd->image_height)
+		{
+		y = pw->imd->image_height - (grid * (PAN_THUMB_SIZE + PAN_THUMB_GAP) + PAN_FOLDER_BOX_BORDER * 4);
+		}
+#endif
+
+	pbox = pan_item_new_box(pw, NULL, x, y, PAN_FOLDER_BOX_BORDER, PAN_FOLDER_BOX_BORDER,
+				PAN_POPUP_BORDER,
+				PAN_POPUP_COLOR, PAN_POPUP_ALPHA,
+				PAN_POPUP_BORDER_COLOR, PAN_POPUP_ALPHA);
+	pan_item_set_key(pbox, "day_bubble");
+
+	pi = list->data;
+	if (pi->fd)
+		{
+		PanItem *plabel;
+		gchar *buf;
+
+		buf = date_value_string(pi->fd->date, DATE_LENGTH_WEEK);
+		plabel = pan_item_new_text(pw, x, y, buf, TEXT_ATTR_BOLD | TEXT_ATTR_HEADING,
+					   PAN_POPUP_TEXT_COLOR, 255);
+		pan_item_set_key(plabel, "day_bubble");
+		g_free(buf);
+
+		pan_item_size_by_item(pbox, plabel, 0);
+
+		y += plabel->height;
+		}
+
+	column = 0;
+
+	x += PAN_FOLDER_BOX_BORDER;
+	y += PAN_FOLDER_BOX_BORDER;
+
+	work = list;
+	while (work)
+		{
+		PanItem *dot;
+
+		dot = work->data;
+		work = work->next;
+
+		if (dot->fd)
+			{
+			PanItem *pimg;
+
+			pimg = pan_item_new_thumb(pw, file_data_new_simple(dot->fd->path), x, y);
+			pan_item_set_key(pimg, "day_bubble");
+
+			pan_item_size_by_item(pbox, pimg, PAN_FOLDER_BOX_BORDER);
+
+			column++;
+			if (column < grid)
+				{
+				x += pimg->width + PAN_THUMB_GAP;
+				}
+			else
+				{
+				column = 0;
+				x = pbox->x + PAN_FOLDER_BOX_BORDER;
+				y += pimg->height + PAN_THUMB_GAP;
+				}
+			}
+		}
+
+	x1 = pi_day->x + pi_day->width - 8;
+	y1 = pi_day->y + 8;
+	x2 = pbox->x + 1;
+	y2 = pbox->y + 36;
+	x3 = pbox->x + 1;
+	y3 = pbox->y + 12;
+	triangle_rect_region(x1, y1, x2, y2, x3, y3,
+			     &x, &y, &w, &h);
+
+	pi = pan_item_new_tri(pw, NULL, x, y, w, h,
+			      x1, y1, x2, y2, x3, y3,
+			      PAN_POPUP_COLOR, PAN_POPUP_ALPHA);
+	pan_item_tri_border(pi, BORDER_1 | BORDER_3, PAN_POPUP_BORDER_COLOR, PAN_POPUP_ALPHA);
+	pan_item_set_key(pi, "day_bubble");
+	pan_item_added(pw, pi);
+
+	pan_item_box_shadow(pbox, PAN_SHADOW_OFFSET * 2, PAN_SHADOW_FADE * 2);
+	pan_item_added(pw, pbox);
+}
+
+static void pan_window_layout_compute_calendar(PanWindow *pw, const gchar *path, gint *width, gint *height)
+{
+	GList *list;
+	GList *work;
+	gint x, y;
+	time_t tc;
+	gint count;
+	gint day_max;
+	gint day_width;
+	gint day_height;
+	gint grid;
+	gint year = 0;
+	gint month = 0;
+	gint end_year = 0;
+	gint end_month = 0;
+
+	pw->cache_list = filelist_sort(pw->cache_list, SORT_TIME, TRUE);
+
+	list = pan_window_layout_list(path, SORT_NONE, TRUE);
+	list = filelist_sort(list, SORT_TIME, TRUE);
+
+	day_max = 0;
+	count = 0;
+	tc = 0;
+	work = list;
+	while (work)
+		{
+		FileData *fd;
+
+		fd = work->data;
+		work = work->next;
+
+		if (!date_compare(fd->date, tc, DATE_LENGTH_DAY))
+			{
+			count = 0;
+			tc = fd->date;
+			}
+		else
+			{
+			count++;
+			if (day_max < count) day_max = count;
+			}
+		}
+
+	printf("biggest day contains %d images\n", day_max);
+
+	grid = (gint)(sqrt((double)day_max) + 0.5) * (PAN_THUMB_SIZE + PAN_SHADOW_OFFSET * 2 + PAN_THUMB_GAP);
+	day_width = MAX(PAN_CAL_DAY_WIDTH, grid);
+	day_height = MAX(PAN_CAL_DAY_HEIGHT, grid);
+
+	if (list)
+		{
+		FileData *fd = list->data;
+
+		year = date_value(fd->date, DATE_LENGTH_YEAR);
+		month = date_value(fd->date, DATE_LENGTH_MONTH);
+		}
+
+	work = g_list_last(list);
+	if (work)
+		{
+		FileData *fd = work->data;
+		end_year = date_value(fd->date, DATE_LENGTH_YEAR);
+		end_month = date_value(fd->date, DATE_LENGTH_MONTH);
+		}
+
+	*width = PAN_FOLDER_BOX_BORDER * 2;
+	*height = PAN_FOLDER_BOX_BORDER * 2;
+
+	x = PAN_FOLDER_BOX_BORDER;
+	y = PAN_FOLDER_BOX_BORDER;
+
+	work = list;
+	while (work && (year < end_year || (year == end_year && month <= end_month)))
+		{
+		PanItem *pi_month;
+		PanItem *pi_text;
+		gint day;
+		gint days;
+		gint col;
+		gint row;
+		time_t dt;
+		gchar *buf;
+
+		dt = date_to_time((month == 12) ? year + 1 : year, (month == 12) ? 1 : month + 1, 1);
+		dt -= 60 * 60 * 24;
+		days = date_value(dt, DATE_LENGTH_DAY);
+		dt = date_to_time(year, month, 1);
+		col = date_value(dt, DATE_LENGTH_WEEK);
+		row = 1;
+
+		x = PAN_FOLDER_BOX_BORDER;
+
+		pi_month = pan_item_new_box(pw, NULL, x, y, PAN_CAL_DAY_WIDTH * 7, PAN_CAL_DAY_HEIGHT / 4,
+					    PAN_FOLDER_BOX_OUTLINE_THICKNESS,
+					    PAN_FOLDER_BOX_COLOR, PAN_FOLDER_BOX_ALPHA,
+					    PAN_FOLDER_BOX_OUTLINE_COLOR, PAN_FOLDER_BOX_OUTLINE_ALPHA);
+		buf = date_value_string(dt, DATE_LENGTH_MONTH);
+		pi_text = pan_item_new_text(pw, x, y, buf,
+					     TEXT_ATTR_BOLD | TEXT_ATTR_HEADING,
+					     PAN_TEXT_COLOR, 255);
+		g_free(buf);
+		pi_text->x = pi_month->x + (pi_month->width - pi_text->width) / 2;
+
+		pi_month->height = pi_text->y + pi_text->height - pi_month->y;
+
+		x = PAN_FOLDER_BOX_BORDER + col * PAN_CAL_DAY_WIDTH;
+		y = pi_month->y + pi_month->height + PAN_FOLDER_BOX_BORDER;
+
+		for (day = 1; day <= days; day++)
+			{
+			FileData *fd;
+			PanItem *pi_day;
+			gint dx, dy;
+			gint n = 0;
+
+			dt = date_to_time(year, month, day);
+
+			pi_day = pan_item_new_box(pw, NULL, x, y, PAN_CAL_DAY_WIDTH, PAN_CAL_DAY_HEIGHT,
+						  PAN_FOLDER_BOX_OUTLINE_THICKNESS,
+						  PAN_FOLDER_BOX_COLOR, PAN_FOLDER_BOX_ALPHA,
+						  PAN_FOLDER_BOX_OUTLINE_COLOR, PAN_FOLDER_BOX_OUTLINE_ALPHA);
+			pan_item_set_key(pi_day, "day");
+
+			dx = x + PAN_CAL_DOT_GAP * 2;
+			dy = y + PAN_CAL_DOT_GAP * 2;
+
+			fd = (work) ? work->data : NULL;
+			while (fd && date_compare(fd->date, dt, DATE_LENGTH_DAY))
+				{
+				PanItem *pi;
+
+				pi = pan_item_new_box(pw, fd, dx, dy, PAN_CAL_DOT_SIZE, PAN_CAL_DOT_SIZE,
+						      0,
+						      PAN_CAL_DOT_COLOR, PAN_CAL_DOT_ALPHA,
+						      0, 0, 0, 0);
+				pan_item_set_key(pi, "dot");
+
+				dx += PAN_CAL_DOT_SIZE + PAN_CAL_DOT_GAP;
+				if (dx + PAN_CAL_DOT_SIZE > pi_day->x + pi_day->width - PAN_CAL_DOT_GAP * 2)
+					{
+					dx = x + PAN_CAL_DOT_GAP * 2;
+					dy += PAN_CAL_DOT_SIZE + PAN_CAL_DOT_GAP;
+					}
+				if (dy + PAN_CAL_DOT_SIZE > pi_day->y + pi_day->height - PAN_CAL_DOT_GAP * 2)
+					{
+					/* must keep all dots within respective day even if it gets ugly */
+					dy = y + PAN_CAL_DOT_GAP * 2;
+					}
+
+				pi_day->color_a = MIN(PAN_FOLDER_BOX_ALPHA + 64 + n, 255);
+				n++;
+
+				work = work->next;
+				fd = (work) ? work->data : NULL;
+				}
+
+			buf = g_strdup_printf("%d", day);
+			pan_item_new_text(pw, x + 4, y + 4, buf, TEXT_ATTR_BOLD | TEXT_ATTR_HEADING,
+					  PAN_TEXT_COLOR, 255);
+			g_free(buf);
+
+
+			pan_item_size_coordinates(pi_day, PAN_FOLDER_BOX_BORDER, width, height);
+
+			col++;
+			if (col > 6)
+				{
+				col = 0;
+				row++;
+				x = PAN_FOLDER_BOX_BORDER;
+				y += PAN_CAL_DAY_HEIGHT;
+				}
+			else
+				{
+				x += PAN_CAL_DAY_WIDTH;
+				}
+			}
+
+		if (col > 0) y += PAN_CAL_DAY_HEIGHT;
+		y += PAN_FOLDER_BOX_BORDER * 2;
+
+		month ++;
+		if (month > 12)
+			{
+			year++;
+			month = 1;
+			}
+		}
+
+	*width += grid;
+	*height = MAX(*height, grid + PAN_FOLDER_BOX_BORDER * 2 * 2);
+
+	g_list_free(list);
+}
+
 static void pan_window_layout_compute_timeline(PanWindow *pw, const gchar *path, gint *width, gint *height)
 {
 	GList *list;
@@ -2025,6 +2396,9 @@
 		case LAYOUT_FOLDERS_FLOWER:
 			pan_window_layout_compute_folders_flower(pw, path, width, height, scroll_x, scroll_y);
 			break;
+		case LAYOUT_CALENDAR:
+			pan_window_layout_compute_calendar(pw, path, width, height);
+			break;
 		case LAYOUT_TIMELINE:
 			pan_window_layout_compute_timeline(pw, path, width, height);
 			break;
@@ -2174,6 +2548,13 @@
 	pw->queue = g_list_remove(pw->queue, pi);
 	pw->queue_pi = pi;
 
+	if (!pw->queue_pi->fd)
+		{
+		pw->queue_pi->queued = FALSE;
+		pw->queue_pi = NULL;
+		return TRUE;
+		}
+
 	image_loader_free(pw->il);
 	pw->il = NULL;
 	thumb_loader_free(pw->tl);
@@ -3442,7 +3823,12 @@
 
 	if (pan_search_by_path(pw, text)) return;
 
-	if (pw->layout == LAYOUT_TIMELINE && pan_search_by_date(pw, text)) return;
+	if ((pw->layout == LAYOUT_TIMELINE ||
+	     pw->layout == LAYOUT_CALENDAR) &&
+	    pan_search_by_date(pw, text))
+		{
+		return;
+		}
 
 	if (pan_search_by_partial(pw, text)) return;
 
@@ -3483,18 +3869,28 @@
 	PanWindow *pw = data;
 	PanItem *pi = NULL;
 	GtkWidget *menu;
-
+	gint rx, ry;
+
+	rx = ry = 0;
 	if (pw->imd->scale)
 		{
-		pi = pan_item_find_by_coord(pw, (pw->size > LAYOUT_SIZE_THUMB_LARGE) ? ITEM_IMAGE : ITEM_THUMB,
-			    (gint)((double)(pw->imd->x_scroll + x - pw->imd->x_offset) / pw->imd->scale),
-			    (gint)((double)(pw->imd->y_scroll + y - pw->imd->y_offset) / pw->imd->scale));
+		rx = (double)(pw->imd->x_scroll + x - pw->imd->x_offset) / pw->imd->scale;
+		ry = (double)(pw->imd->y_scroll + y - pw->imd->y_offset) / pw->imd->scale;
 		}
 
+	pi = pan_item_find_by_coord(pw, (pw->size > LAYOUT_SIZE_THUMB_LARGE) ? ITEM_IMAGE : ITEM_THUMB,
+				    rx, ry, NULL);
+
 	switch (button)
 		{
 		case 1:
 			pan_info_update(pw, pi);
+
+			if (!pi && pw->layout == LAYOUT_CALENDAR)
+				{
+				pi = pan_item_find_by_coord(pw, ITEM_BOX, rx, ry, "day");
+				pan_calendar_update(pw, pi);
+				}
 			break;
 		case 2:
 			break;
@@ -3514,6 +3910,16 @@
 #if 0
 	PanWindow *pw = data;
 #endif
+	gint w, h;
+
+	w = imd->vis_width;
+	h = imd->vis_height;
+
+	if (!(state & GDK_SHIFT_MASK))
+		{
+		w /= 3;
+		h /= 3;
+		}
 
 	if (state & GDK_CONTROL_MASK)
 		{
@@ -3529,33 +3935,21 @@
 				break;
 			}
 		}
-	else if ( (state & GDK_SHIFT_MASK) != (mousewheel_scrolls))
-		{
-		switch (direction)
-			{
-			case GDK_SCROLL_UP:
-				image_scroll(imd, 0, -MOUSEWHEEL_SCROLL_SIZE);
-				break;
-			case GDK_SCROLL_DOWN:
-				image_scroll(imd, 0, MOUSEWHEEL_SCROLL_SIZE);
-				break;
-			case GDK_SCROLL_LEFT:
-				image_scroll(imd, -MOUSEWHEEL_SCROLL_SIZE, 0);
-				break;
-			case GDK_SCROLL_RIGHT:
-				image_scroll(imd, MOUSEWHEEL_SCROLL_SIZE, 0);
-				break;
-			default:
-				break;
-			}
-		}
 	else
 		{
 		switch (direction)
 			{
 			case GDK_SCROLL_UP:
+				image_scroll(imd, 0, -h);
 				break;
 			case GDK_SCROLL_DOWN:
+				image_scroll(imd, 0, h);
+				break;
+			case GDK_SCROLL_LEFT:
+				image_scroll(imd, -w, 0);
+				break;
+			case GDK_SCROLL_RIGHT:
+				image_scroll(imd, w, 0);
 				break;
 			default:
 				break;
@@ -3815,6 +4209,7 @@
 
 	combo = gtk_combo_box_new_text();
 	gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Timeline"));
+	gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Calendar"));
 	gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Folders"));
 	gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Folders (flower)"));
 	gtk_combo_box_append_text(GTK_COMBO_BOX(combo), _("Grid"));