view src/bar_histogram.c @ 1743:d8e9d0cc640e

Allow to switch to fullscreen mode using LIRC. Imagine the following situation (which happened to me several times) : you want to see photos from your bed or your sofa so you launch geeqie and go to the right directory, then you take your remote control and sit comfortably far from your keyboard and mouse. And when you want to begin to watch photos, you realize you forgot to enable full screen! You have to stand up and to go until your computer and come back, whereas you could have done it with your remote control. Patch by Bernard Massot.
author zas_
date Tue, 05 Jan 2010 17:49:50 +0000
parents 7f91f906f9c2
children
line wrap: on
line source

/*
 * Geeqie
 * (C) 2004 John Ellis
 * Copyright (C) 2008 - 2009 The Geeqie Team
 *
 * Author: Vladimir Nadvornik
 *
 * 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 "main.h"
#include "bar_histogram.h"

#include "bar.h"
#include "metadata.h"
#include "filedata.h"
#include "menu.h"
#include "ui_menu.h"
#include "ui_misc.h"
#include "histogram.h"
#include "rcfile.h"

/*
 *-------------------------------------------------------------------
 * keyword / comment utils
 *-------------------------------------------------------------------
 */



typedef struct _PaneHistogramData PaneHistogramData;
struct _PaneHistogramData
{
	PaneData pane;
	GtkWidget *widget;
	GtkWidget *drawing_area;
	Histogram *histogram;
	gint histogram_width;
	gint histogram_height;
	GdkPixbuf *pixbuf;
	FileData *fd;
	gboolean need_update;
	guint idle_id; /* event source id */
};

static gboolean bar_pane_histogram_update_cb(gpointer data);


static void bar_pane_histogram_update(PaneHistogramData *phd)
{
	if (phd->pixbuf) g_object_unref(phd->pixbuf);
	phd->pixbuf = NULL;

	gtk_label_set_text(GTK_LABEL(phd->pane.title), histogram_label(phd->histogram));

	if (!phd->histogram_width || !phd->histogram_height || !phd->fd) return;

	/* histmap_get is relatively expensive, run it only when we really need it
	   and with lower priority than pixbuf_renderer 
	   FIXME: this does not work for fullscreen*/
	if (GTK_WIDGET_DRAWABLE(phd->drawing_area))
		{
		if (!phd->idle_id)
			{
			phd->idle_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, bar_pane_histogram_update_cb, phd, NULL);
			}
		}
	else
		{
		phd->need_update = TRUE;
		}
}

static gboolean bar_pane_histogram_update_cb(gpointer data)
{
	const HistMap *histmap;
	PaneHistogramData *phd = data;

	phd->idle_id = 0;
	phd->need_update = FALSE;
	
	gtk_widget_queue_draw_area(GTK_WIDGET(phd->drawing_area), 0, 0, phd->histogram_width, phd->histogram_height);
	
	if (phd->fd == NULL) return FALSE;
	histmap = histmap_get(phd->fd);
	
	if (!histmap) 
		{
		histmap_start_idle(phd->fd);
		return FALSE;
		}
	
	phd->pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, FALSE, 8, phd->histogram_width, phd->histogram_height);
	gdk_pixbuf_fill(phd->pixbuf, 0xffffffff);
	histogram_draw(phd->histogram, histmap, phd->pixbuf, 0, 0, phd->histogram_width, phd->histogram_height);

	return FALSE;
}


static void bar_pane_histogram_set_fd(GtkWidget *pane, FileData *fd)
{
	PaneHistogramData *phd;

	phd = g_object_get_data(G_OBJECT(pane), "pane_data");
	if (!phd) return;

	file_data_unref(phd->fd);
	phd->fd = file_data_ref(fd);

	bar_pane_histogram_update(phd);
}

static void bar_pane_histogram_write_config(GtkWidget *pane, GString *outstr, gint indent)
{
	PaneHistogramData *phd;

	phd = g_object_get_data(G_OBJECT(pane), "pane_data");
	if (!phd) return;

	WRITE_NL(); WRITE_STRING("<pane_histogram ");
	write_char_option(outstr, indent, "id", phd->pane.id);
	write_char_option(outstr, indent, "title", gtk_label_get_text(GTK_LABEL(phd->pane.title)));
	WRITE_BOOL(phd->pane, expanded);
	WRITE_INT(*phd->histogram, histogram_channel);
	WRITE_INT(*phd->histogram, histogram_mode);
	WRITE_STRING("/>");
}

static void bar_pane_histogram_notify_cb(FileData *fd, NotifyType type, gpointer data)
{
	PaneHistogramData *phd = data;
	if ((type & (NOTIFY_REREAD | NOTIFY_CHANGE | NOTIFY_HISTMAP | NOTIFY_PIXBUF)) && fd == phd->fd) 
		{
		DEBUG_1("Notify pane_histogram: %s %04x", fd->path, type);
		bar_pane_histogram_update(phd);
		}
}

static gboolean bar_pane_histogram_expose_event_cb(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
	PaneHistogramData *phd = data;
	if (!phd) return TRUE;
	
	if (phd->need_update)
		{
		bar_pane_histogram_update(phd);
		}
	
	if (!phd->pixbuf) return TRUE;
	
	gdk_draw_pixbuf(widget->window,
			widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
			phd->pixbuf,
			0, 0,
			0, 0,
			-1, -1,
			GDK_RGB_DITHER_NORMAL, 0, 0);
	return TRUE;
}

static void bar_pane_histogram_size_cb(GtkWidget *widget, GtkAllocation *allocation, gpointer data)
{
	PaneHistogramData *phd = data;

	phd->histogram_width = allocation->width;
	phd->histogram_height = allocation->height;
	bar_pane_histogram_update(phd);
}

#if 0
static void bar_pane_histogram_close(GtkWidget *pane)
{
	PaneHistogramData *phd;

	phd = g_object_get_data(G_OBJECT(pane), "pane_data");
	if (!phd) return;

	gtk_widget_destroy(phd->widget);
}
#endif

static void bar_pane_histogram_destroy(GtkWidget *widget, gpointer data)
{
	PaneHistogramData *phd = data;
	
	if (phd->idle_id) g_source_remove(phd->idle_id);
	file_data_unregister_notify_func(bar_pane_histogram_notify_cb, phd);

	file_data_unref(phd->fd);
	histogram_free(phd->histogram);
	if (phd->pixbuf) g_object_unref(phd->pixbuf);
	g_free(phd->pane.id);

	g_free(phd);
}

static void bar_pane_histogram_popup_channels_cb(GtkWidget *widget, gpointer data)
{
	PaneHistogramData *phd;
	gint channel;

	if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return;

	phd = submenu_item_get_data(widget);

	if (!phd) return;

	channel = GPOINTER_TO_INT(data);
	if (channel == histogram_get_channel(phd->histogram)) return;

	histogram_set_channel(phd->histogram, channel);
	bar_pane_histogram_update(phd);
}

static void bar_pane_histogram_popup_logmode_cb(GtkWidget *widget, gpointer data)
{
	PaneHistogramData *phd;
	gint logmode;
	
	if (!gtk_check_menu_item_get_active(GTK_CHECK_MENU_ITEM(widget))) return;

	phd = submenu_item_get_data(widget);

	if (!phd) return;

	logmode = GPOINTER_TO_INT(data);
	if (logmode == histogram_get_mode(phd->histogram)) return;

	histogram_set_mode(phd->histogram, logmode);
	bar_pane_histogram_update(phd);
}

static GtkWidget *bar_pane_histogram_add_radio(GtkWidget *menu, GtkWidget *parent,
					const gchar *label,
					GCallback func, gint value,
					gboolean show_current, gint current_value)
{
	GtkWidget *item;

	if (show_current)
		{
		item = menu_item_add_radio(menu, parent,
					   label, (value == current_value),
					   func, GINT_TO_POINTER((gint)value));
		}
	else
		{
		item = menu_item_add(menu, label,
				     func, GINT_TO_POINTER((gint)value));
		}

	return item;
}

GtkWidget *bar_pane_histogram_add_channels(GtkWidget *menu, GCallback func, gpointer data,
			    		   gboolean show_current, gint current_value)
{
	GtkWidget *submenu;
	GtkWidget *parent;

	submenu = gtk_menu_new();
	g_object_set_data(G_OBJECT(submenu), "submenu_data", data);

	parent = bar_pane_histogram_add_radio(submenu, NULL, _("_Red"), func, HCHAN_R, show_current, current_value);
	bar_pane_histogram_add_radio(submenu, parent, _("_Green"), func, HCHAN_G, show_current, current_value);
	bar_pane_histogram_add_radio(submenu, parent, _("_Blue"),func, HCHAN_B, show_current, current_value);
	bar_pane_histogram_add_radio(submenu, parent, _("_RGB"),func, HCHAN_RGB, show_current, current_value);
	bar_pane_histogram_add_radio(submenu, parent, _("_Value"),func, HCHAN_MAX, show_current, current_value);

	if (menu)
		{
		GtkWidget *item;

		item = menu_item_add(menu, _("Channels"), NULL, NULL);
		gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
		return item;
		}

	return submenu;
}
GtkWidget *bar_pane_histogram_add_logmode(GtkWidget *menu, GCallback func, gpointer data,
			    		   gboolean show_current, gint current_value)
{
	GtkWidget *submenu;
	GtkWidget *parent;

	submenu = gtk_menu_new();
	g_object_set_data(G_OBJECT(submenu), "submenu_data", data);

	parent = bar_pane_histogram_add_radio(submenu, NULL, _("_Linear"), func, 0, show_current, current_value);
	bar_pane_histogram_add_radio(submenu, parent, _("Lo_garithmical"), func, 1, show_current, current_value);

	if (menu)
		{
		GtkWidget *item;

		item = menu_item_add(menu, _("Mode"), NULL, NULL);
		gtk_menu_item_set_submenu(GTK_MENU_ITEM(item), submenu);
		return item;
		}

	return submenu;
}


static GtkWidget *bar_pane_histogram_menu(PaneHistogramData *phd)
{
	GtkWidget *menu;
	static gboolean show_current = TRUE;

	menu = popup_menu_short_lived();
	bar_pane_histogram_add_channels(menu, G_CALLBACK(bar_pane_histogram_popup_channels_cb), phd,
					show_current, histogram_get_channel(phd->histogram));
	bar_pane_histogram_add_logmode(menu, G_CALLBACK(bar_pane_histogram_popup_logmode_cb), phd,
				       show_current, histogram_get_mode(phd->histogram));

	return menu;
}

static gboolean bar_pane_histogram_press_cb(GtkWidget *widget, GdkEventButton *bevent, gpointer data)
{
	PaneHistogramData *phd = data;

	if (bevent->button == MOUSE_BUTTON_RIGHT)
		{
		GtkWidget *menu;

		menu = bar_pane_histogram_menu(phd);
		gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, bevent->button, bevent->time);
		return TRUE;
	}

	return FALSE;
}


static GtkWidget *bar_pane_histogram_new(const gchar *id, const gchar *title, gint height, gboolean expanded, gint histogram_channel, gint histogram_mode)
{
	PaneHistogramData *phd;

	phd = g_new0(PaneHistogramData, 1);
	
	phd->pane.pane_set_fd = bar_pane_histogram_set_fd;
	phd->pane.pane_write_config = bar_pane_histogram_write_config;
	phd->pane.title = bar_pane_expander_title(title);
	phd->pane.id = g_strdup(id);
	phd->pane.type = PANE_HISTOGRAM;

	phd->pane.expanded = expanded;
	
	phd->histogram = histogram_new();

	histogram_set_channel(phd->histogram, histogram_channel);
	histogram_set_mode(phd->histogram, histogram_mode);

	phd->widget = gtk_vbox_new(FALSE, PREF_PAD_GAP);

	g_object_set_data(G_OBJECT(phd->widget), "pane_data", phd);
	g_signal_connect(G_OBJECT(phd->widget), "destroy",
			 G_CALLBACK(bar_pane_histogram_destroy), phd);
	

	gtk_widget_set_size_request(GTK_WIDGET(phd->widget), -1, height);

	phd->drawing_area = gtk_drawing_area_new();
	g_signal_connect_after(G_OBJECT(phd->drawing_area), "size_allocate",
                               G_CALLBACK(bar_pane_histogram_size_cb), phd);

	g_signal_connect(G_OBJECT(phd->drawing_area), "expose_event",  
			 G_CALLBACK(bar_pane_histogram_expose_event_cb), phd);
			 
	gtk_box_pack_start(GTK_BOX(phd->widget), phd->drawing_area, TRUE, TRUE, 0);
	gtk_widget_show(phd->drawing_area);
	gtk_widget_add_events(phd->drawing_area, GDK_BUTTON_PRESS_MASK);

	g_signal_connect(G_OBJECT(phd->drawing_area), "button_press_event", G_CALLBACK(bar_pane_histogram_press_cb), phd);

	gtk_widget_show(phd->widget);

	file_data_register_notify_func(bar_pane_histogram_notify_cb, phd, NOTIFY_PRIORITY_LOW);

	return phd->widget;
}

GtkWidget *bar_pane_histogram_new_from_config(const gchar **attribute_names, const gchar **attribute_values)
{
	gchar *title = NULL;
	gchar *id = g_strdup("histogram");
	gboolean expanded = TRUE;
	gint height = 80;
	gint histogram_channel = HCHAN_RGB;
	gint histogram_mode = 0;
	GtkWidget *ret;

	while (*attribute_names)
		{
		const gchar *option = *attribute_names++;
		const gchar *value = *attribute_values++;

		if (READ_CHAR_FULL("id", id)) continue;
		if (READ_CHAR_FULL("title", title)) continue;
		if (READ_BOOL_FULL("expanded", expanded)) continue;
		if (READ_INT_FULL("histogram_channel", histogram_channel)) continue;
		if (READ_INT_FULL("histogram_mode", histogram_mode)) continue;

		log_printf("unknown attribute %s = %s\n", option, value);
		}
	
	bar_pane_translate_title(PANE_HISTOGRAM, id, &title);
	ret = bar_pane_histogram_new(id, title, height, expanded, histogram_channel, histogram_mode);
	g_free(title);
	g_free(id);
	return ret;
}

void bar_pane_histogram_update_from_config(GtkWidget *pane, const gchar **attribute_names, const gchar **attribute_values)
{
	PaneHistogramData *phd;

	phd = g_object_get_data(G_OBJECT(pane), "pane_data");
	if (!phd) return;

	gint histogram_channel = phd->histogram->histogram_channel;
	gint histogram_mode = phd->histogram->histogram_mode;

	while (*attribute_names)
		{
		const gchar *option = *attribute_names++;
		const gchar *value = *attribute_values++;

		if (READ_CHAR_FULL("id", phd->pane.id)) continue;
//		if (READ_CHAR_FULL("pane.title", title)) continue;
		if (READ_BOOL_FULL("expanded", phd->pane.expanded)) continue;
		if (READ_INT_FULL("histogram_channel", histogram_channel)) continue;
		if (READ_INT_FULL("histogram_mode", histogram_mode)) continue;
		

		log_printf("unknown attribute %s = %s\n", option, value);
		}
	
	histogram_set_channel(phd->histogram, histogram_channel);
	histogram_set_mode(phd->histogram, histogram_mode);

	bar_update_expander(pane);
	bar_pane_histogram_update(phd);
}


/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */