/*
* Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
* Parts of this file:
- * Copyright (C) 1999-2006 Hiroyuki Yamamoto and the Sylpheed-Claws team
+ * Copyright (C) 1999-2007 Hiroyuki Yamamoto and the Claws Mail team
*
* Parts of this file from gtk/gtkctree.c and gtk/gtkclist.c:
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball, Josh MacDonald,
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
#include <stdlib.h>
#include "gtksctree.h"
-#include "sylpheed-marshal.h"
+#include "claws-marshal.h"
#include "stock_pixmap.h"
#include "prefs_common.h"
#include "utils.h"
guint info, guint time);
static void gtk_sctree_clear (GtkCList *clist);
+static void gtk_sctree_real_unselect_all (GtkCList *clist);
static void gtk_sctree_collapse (GtkCTree *ctree, GtkCTreeNode *node);
static void stree_sort (GtkCTree *ctree, GtkCTreeNode *node, gpointer data);
justification_factor = -1;
else
justification_factor = 1;
- y = (clip_rectangle->y + (clip_rectangle->height - PM_SIZE) / 2 -
- (clip_rectangle->height + 1) % 2);
+ if (!GTK_CLIST_ROW_HEIGHT_SET(GTK_CLIST(clist)))
+ y = (clip_rectangle->y + (clip_rectangle->height - PM_SIZE) / 2 -
+ (clip_rectangle->height + 1) % 2);
+ else
+ y = (clip_rectangle->y + (clip_rectangle->height/2 - PM_SIZE) / 2 -
+ (clip_rectangle->height/2 + 1) % 2);
if (!ctree_row->children)
{
return offset;
}
+static gboolean filter_fg (PangoAttribute *attribute, gpointer data)
+{
+ const PangoAttrClass *klass = attribute->klass;
+ if (klass->type == PANGO_ATTR_FOREGROUND)
+ return TRUE;
+
+ return FALSE;
+}
+
static PangoLayout *
sc_gtk_clist_create_cell_layout (GtkCList *clist,
GtkCListRow *clist_row,
if (!text)
return NULL;
- layout = gtk_widget_create_pango_layout (GTK_WIDGET (clist),
- ((cell->type == GTK_CELL_PIXTEXT) ?
- GTK_CELL_PIXTEXT (*cell)->text :
- GTK_CELL_TEXT (*cell)->text));
- pango_layout_set_font_description (layout, style->font_desc);
+ if (!GTK_SCTREE(clist)->use_markup[column]) {
+ layout = gtk_widget_create_pango_layout (GTK_WIDGET (clist),
+ ((cell->type == GTK_CELL_PIXTEXT) ?
+ GTK_CELL_PIXTEXT (*cell)->text :
+ GTK_CELL_TEXT (*cell)->text));
+ pango_layout_set_font_description (layout, style->font_desc);
+ } else {
+ PangoContext *context = gtk_widget_get_pango_context (GTK_WIDGET(clist));
+ layout = pango_layout_new (context);
+ pango_layout_set_markup (layout, text, -1);
+ pango_layout_set_font_description (layout, style->font_desc);
+ if (clist_row->state == GTK_STATE_SELECTED) {
+ /* for selected row, we should remove any forced foreground color
+ * or it looks like shit */
+ PangoAttrList *list = pango_layout_get_attributes(layout);
+ PangoAttrList *rem = pango_attr_list_filter(list, filter_fg, NULL);
+ if (rem)
+ pango_attr_list_unref(rem);
+ }
+ }
return layout;
}
if (normalbg.red > 0x8888 && normalbg.green > 0x8888 && normalbg.blue > 0x8888) {
greybg.pixel = normalbg.pixel;
- greybg.red = normalbg.red - 0x1111;
- greybg.green = normalbg.green - 0x1111;
- greybg.blue = normalbg.blue - 0x1111;
+ greybg.red = normalbg.red - prefs_common.stripes_color_offset;
+ greybg.green = normalbg.green - prefs_common.stripes_color_offset;
+ greybg.blue = normalbg.blue - prefs_common.stripes_color_offset;
} else if (normalbg.red < 0x8888 && normalbg.green < 0x8888 && normalbg.blue < 0x8888) {
greybg.pixel = normalbg.pixel;
- greybg.red = normalbg.red + 0x1111;
- greybg.green = normalbg.green + 0x1111;
- greybg.blue = normalbg.blue + 0x1111;
+ greybg.red = normalbg.red + prefs_common.stripes_color_offset;
+ greybg.green = normalbg.green + prefs_common.stripes_color_offset;
+ greybg.blue = normalbg.blue + prefs_common.stripes_color_offset;
} else {
color_change = FALSE;
}
if (i != ctree->tree_column)
{
+ int start_y = (clip_rectangle.height - height) / 2;
+ if (GTK_CLIST_ROW_HEIGHT_SET(GTK_CLIST(clist)))
+ start_y = (clip_rectangle.height/2 - height) / 2;
+
offset += clist_row->cell[i].horizontal;
switch (clist_row->cell[i].type)
{
GTK_CELL_PIXMAP (clist_row->cell[i])->mask,
offset,
clip_rectangle.y + clist_row->cell[i].vertical +
- (clip_rectangle.height - height) / 2,
+ start_y,
pixmap_width, height);
break;
case GTK_CELL_PIXTEXT:
GTK_CELL_PIXTEXT (clist_row->cell[i])->mask,
offset,
clip_rectangle.y + clist_row->cell[i].vertical +
- (clip_rectangle.height - height) / 2,
+ start_y,
pixmap_width, height);
offset += GTK_CELL_PIXTEXT (clist_row->cell[i])->spacing;
switch (action)
{
case GTK_CTREE_EXPANSION_EXPAND:
- gtk_ctree_expand_recursive (ctree, node);
+ if (GTK_SCTREE(ctree)->always_expand_recursively)
+ gtk_ctree_expand_recursive (ctree, node);
+ else
+ gtk_ctree_expand (ctree, node);
+
break;
case GTK_CTREE_EXPANSION_EXPAND_RECURSIVE:
gtk_ctree_expand_recursive (ctree, node);
gtk_ctree_collapse_recursive (ctree, node);
break;
case GTK_CTREE_EXPANSION_TOGGLE:
- gtk_ctree_toggle_expansion_recursive (ctree, node);
+ if (GTK_SCTREE(ctree)->always_expand_recursively)
+ gtk_ctree_toggle_expansion_recursive (ctree, node);
+ else
+ gtk_ctree_toggle_expansion (ctree, node);
break;
case GTK_CTREE_EXPANSION_TOGGLE_RECURSIVE:
gtk_ctree_toggle_expansion_recursive (ctree, node);
}
}
+static void gtk_sctree_finalize(GObject *object)
+{
+ GtkSCTree *sctree = GTK_SCTREE(object);
+ g_free(sctree->use_markup);
+ sctree->use_markup = NULL;
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
/* Standard class initialization function */
static void
gtk_sctree_class_init (GtkSCTreeClass *klass)
{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
GtkObjectClass *object_class;
GtkWidgetClass *widget_class;
GtkCListClass *clist_class;
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GtkSCTreeClass, row_popup_menu),
NULL, NULL,
- sylpheed_marshal_VOID__POINTER,
+ claws_marshal_VOID__POINTER,
G_TYPE_NONE, 1,
GDK_TYPE_EVENT);
sctree_signals[EMPTY_POPUP_MENU] =
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GtkSCTreeClass, empty_popup_menu),
NULL, NULL,
- sylpheed_marshal_VOID__POINTER,
+ claws_marshal_VOID__POINTER,
G_TYPE_NONE, 1,
GDK_TYPE_EVENT);
sctree_signals[OPEN_ROW] =
G_SIGNAL_RUN_FIRST,
G_STRUCT_OFFSET (GtkSCTreeClass, start_drag),
NULL, NULL,
- sylpheed_marshal_VOID__INT_POINTER,
+ claws_marshal_VOID__INT_POINTER,
G_TYPE_NONE, 2,
G_TYPE_INT,
GDK_TYPE_EVENT);
clist_class->clear = gtk_sctree_clear;
clist_class->draw_row = gtk_sctree_draw_row;
+ clist_class->unselect_all = gtk_sctree_real_unselect_all;
ctree_class->tree_collapse = gtk_sctree_collapse;
ctree_class->tree_expand = gtk_sctree_real_tree_expand;
ctree_class->tree_move = sreal_tree_move;
ctree_class->change_focus_row_expansion = gtk_sctree_change_focus_row_expansion;
-
+
widget_class->button_press_event = gtk_sctree_button_press;
widget_class->button_release_event = gtk_sctree_button_release;
widget_class->motion_notify_event = gtk_sctree_motion;
widget_class->drag_motion = gtk_sctree_drag_motion;
widget_class->drag_drop = gtk_sctree_drag_drop;
widget_class->drag_data_received = gtk_sctree_drag_data_received;
+
+ gobject_class->finalize = gtk_sctree_finalize;
}
/* Standard object initialization function */
min = prev_row;
max = row;
}
- sctree->selecting_range = TRUE;
+ sctree->selecting_range++;
if (max < min) {
int t = min;
gtk_clist_thaw(GTK_CLIST(sctree));
- sctree->selecting_range = FALSE;
+ sctree->selecting_range--;
gtk_clist_select_row (GTK_CLIST (sctree), max, -1);
}
(GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_SINGLE) &&
(GTK_CLIST(sctree)->selection_mode != GTK_SELECTION_BROWSE);
+ if (!range && !additive && sctree->force_additive_sel)
+ additive = TRUE;
+
GTK_CLIST(sctree)->focus_row = row;
if (!additive) {
- /* if this selection isn't additive, we have to unselect what
- * is selected. Here, heavy GUI updates can occur if we have
- * a big selection. See if more than one line is selected, in
- * which case, freeze, else don't. */
-
- gboolean should_freeze = FALSE;
- if (sc_g_list_bigger(GTK_CLIST(sctree)->selection, 10)) {
- should_freeze = TRUE;
- sctree->selecting_range = TRUE;
- gtk_clist_freeze (GTK_CLIST (sctree));
- }
-
gtk_clist_unselect_all (GTK_CLIST (sctree));
-
- if (should_freeze) {
- gtk_clist_thaw (GTK_CLIST (sctree));
- sctree->selecting_range = FALSE;
- }
}
if (!range) {
select_range (sctree, row);
}
+static gboolean
+sctree_is_hot_spot (GtkSCTree *sctree,
+ GtkCTreeNode *node,
+ gint row,
+ gint x,
+ gint y)
+{
+ GtkCTreeRow *tree_row;
+ GtkCList *clist;
+ GtkCTree *ctree;
+ GtkCellPixText *cell;
+ gint xl, xmax;
+ gint yu;
+
+ g_return_val_if_fail (GTK_IS_SCTREE (sctree), FALSE);
+ g_return_val_if_fail (node != NULL, FALSE);
+
+ clist = GTK_CLIST (sctree);
+ ctree = GTK_CTREE (sctree);
+
+ if (!clist->column[ctree->tree_column].visible ||
+ ctree->expander_style == GTK_CTREE_EXPANDER_NONE)
+ return FALSE;
+
+ tree_row = GTK_CTREE_ROW (node);
+
+ cell = GTK_CELL_PIXTEXT (tree_row->row.cell[ctree->tree_column]);
+
+ if (!GTK_CLIST_ROW_HEIGHT_SET(GTK_CLIST(clist)))
+ yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height - PM_SIZE) / 2 -
+ (clist->row_height - 1) % 2);
+ else
+ yu = (ROW_TOP_YPIXEL (clist, row) + (clist->row_height/2 - PM_SIZE) / 2 -
+ (clist->row_height/2 - 1) % 2);
+
+#ifndef GENERIC_UMPC
+ if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT)
+ xl = (clist->column[ctree->tree_column].area.x +
+ clist->column[ctree->tree_column].area.width - 1 + clist->hoffset -
+ (tree_row->level - 1) * ctree->tree_indent - PM_SIZE -
+ (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3);
+ else
+ xl = (clist->column[ctree->tree_column].area.x + clist->hoffset +
+ (tree_row->level - 1) * ctree->tree_indent +
+ (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3);
+
+ xmax = xl + PM_SIZE;
+#else
+ if (clist->column[ctree->tree_column].justification == GTK_JUSTIFY_RIGHT) {
+ xl = (clist->column[ctree->tree_column].area.x +
+ clist->column[ctree->tree_column].area.width - 1 + clist->hoffset -
+ (tree_row->level - 1) * ctree->tree_indent - PM_SIZE -
+ (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3);
+ xmax = xl + PM_SIZE;
+ } else if (ctree->tree_column == 0) {
+ xl = (clist->column[ctree->tree_column].area.x + clist->hoffset +
+ (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3);
+ xmax = (clist->column[ctree->tree_column].area.x + clist->hoffset +
+ (tree_row->level - 1) * ctree->tree_indent +
+ (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3) +
+ PM_SIZE;
+ } else {
+ xl = (clist->column[ctree->tree_column].area.x + clist->hoffset +
+ (tree_row->level - 1) * ctree->tree_indent +
+ (ctree->line_style == GTK_CTREE_LINES_TABBED) * 3);
+ xmax = xl + PM_SIZE;
+ }
+#endif
+ return (x >= xl && x <= xmax && y >= yu && y <= yu + PM_SIZE);
+}
+
+gboolean
+gtk_sctree_is_hot_spot (GtkSCTree *ctree,
+ gint x,
+ gint y)
+{
+ GtkCTreeNode *node;
+ gint column;
+ gint row;
+
+ g_return_val_if_fail (GTK_IS_SCTREE (ctree), FALSE);
+
+ if (gtk_clist_get_selection_info (GTK_CLIST (ctree), x, y, &row, &column))
+ if ((node = GTK_CTREE_NODE(g_list_nth (GTK_CLIST (ctree)->row_list, row))))
+ return sctree_is_hot_spot (ctree, node, row, x, y);
+
+ return FALSE;
+}
+
/* Our handler for button_press events. We override all of GtkCList's broken
* behavior.
*/
if (on_row && !GTK_WIDGET_HAS_FOCUS(widget))
gtk_widget_grab_focus (widget);
- if (gtk_ctree_is_hot_spot (GTK_CTREE(sctree), event->x, event->y)) {
- gtk_ctree_toggle_expansion_recursive
- (GTK_CTREE(sctree),
- gtk_ctree_node_nth(GTK_CTREE(sctree), row));
+ if (gtk_sctree_is_hot_spot (GTK_SCTREE(sctree), event->x, event->y)) {
+ GtkCTreeNode *node = gtk_ctree_node_nth(GTK_CTREE(sctree), row);
+ if (GTK_CTREE_ROW (node)->expanded)
+ gtk_ctree_collapse(GTK_CTREE(sctree), node);
+ else if (GTK_SCTREE(sctree)->always_expand_recursively)
+ gtk_ctree_expand_recursive (GTK_CTREE(sctree), node);
+ else
+ gtk_ctree_expand(GTK_CTREE(sctree), node);
return TRUE;
}
select_row (sctree, row, col, event->state, NULL);
}
} else {
- sctree->selecting_range = TRUE;
gtk_clist_unselect_all (clist);
- sctree->selecting_range = FALSE;
}
retval = TRUE;
sctree_signals[ROW_POPUP_MENU],
0, event);
} else {
- sctree->selecting_range = TRUE;
gtk_clist_unselect_all(clist);
- sctree->selecting_range = FALSE;
g_signal_emit (G_OBJECT (sctree),
sctree_signals[EMPTY_POPUP_MENU],
0, event);
/* This is the same threshold value that is used in gtkdnd.c */
+#ifndef GENERIC_UMPC
+#define THRESHOLD 3
+#else
+#define THRESHOLD 8
+#endif
if (MAX (ABS (sctree->dnd_press_x - event->x),
- ABS (sctree->dnd_press_y - event->y)) <= 3)
+ ABS (sctree->dnd_press_y - event->y)) <= THRESHOLD)
return FALSE;
/* Handle any pending selections */
(* ((GtkCListClass *)parent_class)->clear) (clist);
}
+static void
+gtk_sctree_real_unselect_all (GtkCList *clist)
+{
+ GtkSCTree *sctree;
+ gboolean should_freeze = FALSE;
+
+ g_return_if_fail (clist != NULL);
+ g_return_if_fail (GTK_IS_SCTREE (clist));
+
+ sctree = GTK_SCTREE (clist);
+
+ if (sc_g_list_bigger(GTK_CLIST(sctree)->selection, 10)) {
+ should_freeze = TRUE;
+ sctree->selecting_range++;
+ gtk_clist_freeze (GTK_CLIST (sctree));
+ }
+
+ if (((GtkCListClass *)parent_class)->unselect_all)
+ (* ((GtkCListClass *)parent_class)->unselect_all) (clist);
+
+ if (should_freeze) {
+ gtk_clist_thaw (GTK_CLIST (sctree));
+ sctree->selecting_range--;
+ }
+}
+
/* Our handler for the change_focus_row_expansion signal of the ctree.
We have to set the anchor to parent visible node.
*/
}
GTK_SCTREE(widget)->show_stripes = TRUE;
+ GTK_SCTREE(widget)->always_expand_recursively = TRUE;
+ GTK_SCTREE(widget)->force_additive_sel = FALSE;
+
+ GTK_SCTREE(widget)->use_markup = g_new0(gboolean, columns);
return widget;
}
+void gtk_sctree_set_use_markup (GtkSCTree *sctree,
+ int column,
+ gboolean markup)
+{
+ gint columns = 0;
+ GValue value = { 0 };
+
+ g_return_if_fail(GTK_IS_SCTREE(sctree));
+
+ g_value_init (&value, G_TYPE_INT);
+ g_object_get_property (G_OBJECT (sctree), "n-columns", &value);
+ columns = g_value_get_int (&value);
+ g_value_unset (&value);
+
+ g_return_if_fail(column < columns);
+
+ sctree->use_markup[column] = markup;
+}
+
void gtk_sctree_select (GtkSCTree *sctree, GtkCTreeNode *node)
{
select_row(sctree,
void gtk_sctree_unselect_all (GtkSCTree *sctree)
{
- gboolean froze = FALSE;
- sctree->selecting_range = TRUE;
- if (sc_g_list_bigger(GTK_CLIST(sctree)->selection, 1)) {
- gtk_clist_freeze(GTK_CLIST(sctree));
- froze = TRUE;
- }
gtk_clist_unselect_all(GTK_CLIST(sctree));
- if (froze)
- gtk_clist_thaw(GTK_CLIST(sctree));
- sctree->selecting_range = FALSE;
sctree->anchor_row = NULL;
}
sctree->show_stripes = show_stripes;
}
+void gtk_sctree_set_recursive_expand(GtkSCTree *sctree, gboolean rec_exp)
+{
+ sctree->always_expand_recursively = rec_exp;
+}
+
/***********************************************************
* Tree sorting functions *
***********************************************************/
{
GList *tmp_list;
+ if (clist->row_list_end == list)
+ clist->row_list_end = g_list_last(list);
+
tmp_list = (GList *)GTK_CTREE_NODE_NEXT (node);
tmp_list->prev = list;
}
gtk_clist_thaw (clist);
}
+void gtk_sctree_set_column_tooltip (GtkSCTree *sctree,
+ int column,
+ const gchar *tip)
+{
+ if (!sctree->tips)
+ sctree->tips = gtk_tooltips_new();
+
+ gtk_tooltips_set_tip(GTK_TOOLTIPS(sctree->tips),
+ GTK_CLIST(sctree)->column[column].button,
+ tip, NULL);
+
+}
+