gnome-utils r7923 - in trunk/baobab: . data src



Author: acastro
Date: Thu May  8 11:35:22 2008
New Revision: 7923
URL: http://svn.gnome.org/viewvc/gnome-utils?rev=7923&view=rev

Log:

	Patch contributed by Felipe Erias <femorandeira igalia com>, Pablo
	Santamaria <psantamaria igalia com>, Jacobo Aragunde
	<jaragunde igalia com> and Eduardo Lima <elima igalia com>
	
	Enhancement to the ringschart widget, added multiple tooltips
	support (bug #421473)

	* src/baobab.c:
	(baobab_scan_location): We set the max depth after scanning in
	order to zoom the graphic as much as possible.
	(baobab_subfolderstips_toggled): This function is a callback that
	manages changes in the gconf key that controls the subfolders
	tips.
	(baobab_init): Monitor the gconf subfolders tooltips key
	connecting the callback.
	(create_context_menu): Create a context menu with three actions:
	go to the parent, zoom in and zoom out.
	(initialize_ringschart): Initialize max_depth so we get the
	biggest zoom for the initial ringschart. We also get the gconf
	value for the subfolders tips and create the context menu.

	* src/baobab.h: 
	Added a new struct to manage the context menu. Added also a new
	variable to the baobab_application struct, it is used to store the
	maximum depth of the tree we are representing.
	
	* src/baobab-ringschart.c:
	* src/baobab-ringschart.h: 	
	Added two functions to the API in order to control the new
	feature, adding subfolderstips. If we enable the subfoldertips we
	will see the tooltip for the sector (directory) under the cursor
	and tooltips for "some" of its children. 

	The way the tooltip for the sector under the cursor is painted has
	changed, now the tooltip is not painted all the time, if follows
	the cursor and the user has to stop over the sector.

	Added zoom support to the widget, it is connected to the
	scrolling.

	* src/callbacks.c:
	* src/callbacks.h:	
	(on_rchart_button_release): Callback that handles the context
	sensitive menu.
	(on_move_upwards_cb): Callback for an option in the menu, it tries
	to go to parent of the current directory.
	(on_zoom_in_cb): Callback for an option in the menu, it decreases
	the maximum depth of the ringschart, that way the graphic is
	bigger because we paint less levels.
	(on_zoom_out_cb): Callback for an option in the menu, it increases
	the maximum depth of the ringschart, that way the graphic is
	smaller because we paint more levels.

	* src/baobab-scan.c: 
	Added a new parameter to the allsizes struct in order to calculate
	the depth of the tree.
	(loopdir): Added a new parameter in order to calculate the depth
	of the tree.
	(baobab_scan_execute): Store the maximum depth of the tree we have
	scanned in the application structure. We will use it to calculate
	the proper zoom for the tree.



Modified:
   trunk/baobab/ChangeLog
   trunk/baobab/data/baobab.schemas.in
   trunk/baobab/src/baobab-ringschart.c
   trunk/baobab/src/baobab-ringschart.h
   trunk/baobab/src/baobab-scan.c
   trunk/baobab/src/baobab.c
   trunk/baobab/src/baobab.h
   trunk/baobab/src/callbacks.c
   trunk/baobab/src/callbacks.h

Modified: trunk/baobab/data/baobab.schemas.in
==============================================================================
--- trunk/baobab/data/baobab.schemas.in	(original)
+++ trunk/baobab/data/baobab.schemas.in	Thu May  8 11:35:22 2008
@@ -51,6 +51,19 @@
 	<long>A list of uri for partitions to be excluded from scanning.</long>
       </locale>
     </schema>
+
+    <schema>
+      <key>/schemas/apps/baobab/ui/baobab_subfoldertips_visible</key>
+      <applyto>/apps/baobab/ui/baobab_subfoldertips_visible</applyto>
+      <owner>baobab</owner>
+      <type>bool</type>
+      <default>TRUE</default>
+      <locale name="C">
+	<short>Subfolders tooltips visible</short>
+	<long>Whether the tooltips of the subfolders the folder we 
+        are selecting are drawn.</long>
+      </locale>
+    </schema>
     
   </schemalist>
 </gconfschemafile>

Modified: trunk/baobab/src/baobab-ringschart.c
==============================================================================
--- trunk/baobab/src/baobab-ringschart.c	(original)
+++ trunk/baobab/src/baobab-ringschart.c	Thu May  8 11:35:22 2008
@@ -1,7 +1,7 @@
 /*
  * baobab-ringschart.c
  *
- * Copyright (C) 2006 Igalia
+ * Copyright (C) 2006, 2007, 2008 Igalia
  *
  * 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
@@ -19,6 +19,10 @@
  * Boston, MA  02110-1301  USA
  *
  * Authors:
+ *   Felipe Erias <femorandeira igalia com>
+ *   Pablo Santamaria <psantamaria igalia com>
+ *   Jacobo Aragunde <jaragunde igalia com>
+ *   Eduardo Lima <elima igalia com>
  *   Mario Sanchez <msanchez igalia com>
  *   Miguel Gomez <magomez igalia com>
  *   Henrique Ferreiro <hferreiro igalia com>
@@ -35,12 +39,17 @@
 
 #include "baobab-ringschart.h"
 
-#define MAX_DRAWABLE_DEPTH 5
 #define MIN_DRAWABLE_ANGLE 0.03
 #define EDGE_ANGLE 0.01
 #define FILE_COLOR 0.6
 #define WINDOW_PADDING 5
-#define TOOLTIP_PADDING 5
+#define TOOLTIP_PADDING 3
+#define SUBFOLDERTIP_TRANSP 0.666
+#define TOOLTIP_TRANSP 0.666
+#define TOOLTIP_SPACING 1
+#define TOOLTIP_TIMEOUT 300 /* miliseconds before showing the tooltip
+                               window after mouse pointer rests over
+                               a sector */
 
 #define BAOBAB_RINGSCHART_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
                                             BAOBAB_RINGSCHART_TYPE, \
@@ -61,6 +70,8 @@
   gdouble max_radius;
   gdouble min_radius;
   gdouble thickness;
+  gdouble pointer_x;
+  gdouble pointer_y;
   guint max_depth;
   guint name_column;
   guint size_column;
@@ -75,6 +86,10 @@
   gboolean button_pressed;
   gboolean real_sector;
   gboolean is_frozen;
+  gboolean transparent_tips;
+  gboolean subfoldertips_enabled;
+  guint timeout_event_source;
+  gboolean draw_tooltip;
   guint init_depth;
   gboolean draw_center;
   cairo_surface_t *memento;
@@ -97,8 +112,18 @@
   gint depth;
   gchar *name;
   gchar *size;
+  GtkTreeRowReference *ref;
 };
 
+struct _Tooltip_rectangle {
+  gdouble x;
+  gdouble y;
+  gdouble width;
+  gdouble height;
+};
+
+typedef struct _Tooltip_rectangle Tooltip_rectangle;
+
 /* Signals */
 enum {
   SECTOR_ACTIVATED,
@@ -176,6 +201,9 @@
                          gdouble center_y,
                          gdouble radius,
                          gboolean highlighted);
+static void draw_tooltips (GtkWidget *rchart,
+                           cairo_t *cr,
+                           GSList *tooltips);
 static void draw_tip (cairo_t *cr,
                       GtkWidget *rchart,
                       gdouble init_angle,
@@ -183,6 +211,14 @@
                       gdouble depth,
                       gchar *name,
                       gchar *size);
+static void draw_folder_tip (cairo_t *cr,
+                             GtkWidget *rchart,
+                             gdouble init_angle,
+                             gdouble final_angle,
+                             gdouble depth,
+                             gchar *name,
+                             gchar *size,
+                             Tooltip_rectangle *previous_rectangle);
 static void interpolate_colors (Color *color,
                                 Color colora,
                                 Color colorb,
@@ -202,6 +238,8 @@
                            gboolean real_draw);
 static gint baobab_ringschart_button_release (GtkWidget *widget,
                                               GdkEventButton *event);
+static gint baobab_ringschart_scroll (GtkWidget *widget,
+                                      GdkEventScroll *event);
 static gint baobab_ringschart_motion_notify (GtkWidget *widget,
                                              GdkEventMotion *event);
 static inline void baobab_ringschart_disconnect_signals (GtkWidget *rchart, 
@@ -229,6 +267,7 @@
   widget_class->expose_event = baobab_ringschart_expose;
   widget_class->size_allocate = baobab_ringschart_size_allocate;
   widget_class->button_release_event = baobab_ringschart_button_release;
+  widget_class->scroll_event = baobab_ringschart_scroll;
   widget_class->motion_notify_event = baobab_ringschart_motion_notify;
 
   g_object_class_install_property (obj_class,
@@ -298,6 +337,8 @@
   priv->real_sector = FALSE;
   priv->button_pressed = FALSE;
   priv->is_frozen = FALSE;
+  priv->transparent_tips = FALSE;
+  priv->subfoldertips_enabled = FALSE;
   priv->init_depth = 0;
   priv->draw_center = FALSE;
   priv->memento = NULL;
@@ -607,8 +648,6 @@
 
   cairo_destroy (cr);
 
-  gdk_window_get_pointer (rchart->window, NULL, NULL, NULL);
-
   return FALSE;
 }
 
@@ -677,37 +716,12 @@
   /* no matter what happens in the draw now the button will be
      unpressed */
   priv->button_pressed = FALSE;
+  
+  if (priv->draw_tooltip)
+    {
+      draw_tooltips (rchart, cr, tooltips);
+    }
 
-  /* FIXME: we have to confirm there is not a way to control the depth
-     of the tooltips in the draw and we require this intermediate
-     structure. Actually there is painting from outside to inside, we
-     have to check if that is a good solution */
-  if (tooltips)    
-    do
-      {
-        GSList *tips_iter = NULL;
-        Tooltip *tooltip = NULL;
-
-        tips_iter = tooltips;
-
-        tooltip = tips_iter->data;
-
-        /* check if the root is highlihgted in order to redraw it*/
-        if ((priv->draw_center) && (tooltip->depth == -1))
-          draw_circle (cr, priv->center_x, priv->center_y, priv->min_radius, TRUE);
-
-        draw_tip (cr, rchart, tooltip->init_angle, tooltip->final_angle, 
-                  tooltip->depth , tooltip->name, tooltip->size);
-
-        g_free (tooltip->name);
-        g_free (tooltip->size);
-      
-        tooltips = g_slist_remove_link (tooltips, tips_iter);
-
-        g_free (tooltip);
-        g_slist_free_1 (tips_iter);
-      }
-    while (g_slist_next(tooltips));
 }
 
 static void 
@@ -769,6 +783,98 @@
   cairo_restore (cr);
 }
 
+static void
+draw_tooltips (GtkWidget *rchart,
+               cairo_t *cr,
+               GSList *tooltips)
+{
+  BaobabRingschartPrivate *priv;
+
+  priv = BAOBAB_RINGSCHART (rchart)->priv;
+
+  /* FIXME: replace this list of tips with just a variable, we are not
+     going to have more than one tooltip */
+  if (tooltips)
+    {
+      do
+        {
+          GSList *tips_iter = NULL;
+          Tooltip *tooltip = NULL;
+          GtkTreeIter child  = {0};
+          GtkTreeIter iter = {0};
+          Tooltip_rectangle *previous_rectangle = NULL;
+          GtkTreePath *path = NULL;
+
+          tips_iter = tooltips;
+          tooltip = tips_iter->data;
+
+          path = gtk_tree_row_reference_get_path (tooltip->ref);
+          gtk_tree_model_get_iter (priv->model, &iter, path);
+
+          /* draw the child tooltips */
+          if (gtk_tree_model_iter_has_child (priv->model, &iter) && 
+              (tooltip->depth == -1 || tooltip->depth < priv->max_depth-1))
+            {
+              gdouble _init_angle, _final_angle;
+
+              gtk_tree_model_iter_children (priv->model, &child, &iter);
+              _init_angle = tooltip->init_angle;
+
+              previous_rectangle = g_new (Tooltip_rectangle, 1);
+              previous_rectangle->x = 0.0;
+              previous_rectangle->y = 0.0;
+              previous_rectangle->width = 0.0;
+              previous_rectangle->height = 0.0;
+
+              do
+                {
+                  gchar *name;
+                  gchar *size_column;
+                  gdouble percentage;
+
+                  gtk_tree_model_get (priv->model, &child, 
+                                      priv->name_column, &name,
+                                      priv->size_column, &size_column,
+                                      priv->percentage_column, &percentage, -1);             
+                  
+                  _final_angle = _init_angle + 
+                    (tooltip->final_angle - tooltip->init_angle) * percentage/100;
+
+                  if (percentage > 0)
+                    draw_folder_tip (cr, rchart, _init_angle, 
+                                     _final_angle, tooltip->depth+1, name, 
+                                     size_column, previous_rectangle);                 
+
+                  g_free (name);
+                  g_free (size_column);
+                          
+                  _init_angle = _final_angle;
+
+                } while (gtk_tree_model_iter_next (priv->model, &child));
+            }
+
+          gtk_tree_path_free (path);
+
+          /* check if the root is highlihgted in order to redraw it*/
+          if ((priv->draw_center) && (tooltip->depth == -1))
+                  draw_circle (cr, priv->center_x, priv->center_y, priv->min_radius, TRUE);
+
+          draw_tip (cr, rchart, tooltip->init_angle, tooltip->final_angle, 
+                    tooltip->depth, tooltip->name, tooltip->size);
+
+          g_free (tooltip->name);
+          g_free (tooltip->size);
+          gtk_tree_row_reference_free (tooltip->ref);
+
+          tooltips = g_slist_remove_link (tooltips, tips_iter);
+
+          g_free (tooltip);
+          g_slist_free_1 (tips_iter);
+        }
+      while (g_slist_next(tooltips));
+    }
+}
+
 static void 
 draw_tip (cairo_t *cr,
           GtkWidget *rchart,
@@ -784,13 +890,10 @@
   gdouble max_radius;
   gdouble origin_x;
   gdouble origin_y;
-  gdouble max_radius_x;
-  gdouble max_radius_y;
   gdouble tooltip_x;
   gdouble tooltip_y;
   gdouble end_x;
   gdouble end_y;
-  gdouble width;
   gdouble tooltip_height;
   gdouble tooltip_width;  
   PangoRectangle rect;
@@ -800,10 +903,11 @@
   priv = BAOBAB_RINGSCHART_GET_PRIVATE (rchart);
 
   /* angle to start drawing from */
-  medium_angle = ((final_angle - init_angle)/2) + init_angle;
-  
+  /* medium_angle = ((final_angle - init_angle)/2) + init_angle; */
+  medium_angle = priv->point_angle;
+
   /* radius to start drawing from */
-  start_radius = (depth != -1) ? (depth + 0.5) * priv->thickness + priv->min_radius : 0;
+  start_radius = (depth != -1) ? (depth + 0.1) * priv->thickness + priv->min_radius : 0;
 
   /* coordinates of the starting point of the line */
   origin_x = priv->center_x + (cos(medium_angle) * start_radius);
@@ -817,65 +921,385 @@
   layout = gtk_widget_create_pango_layout (rchart, NULL);
   pango_layout_set_markup (layout, text, -1);
 
-  pango_layout_get_pixel_extents (layout, &rect, NULL);
-  width = rect.width;
+  pango_layout_get_pixel_extents (layout, NULL, &rect);
 
-  tooltip_width = floor(width+TOOLTIP_PADDING*2);  
+  tooltip_width = floor(rect.width+TOOLTIP_PADDING*2);  
   tooltip_height = floor(rect.height+TOOLTIP_PADDING*2);
-  
-  /* We must calculate the radius we are going to use to draw the
-     line from the sector. To do this, we calculate the distance from
-     the sector to the edge of the window, both horizontally and
-     vertically. Using this measures and the angle we calculate the
-     maximum radius allowed in each direction that guarantees that the
-     tip is in the window. We must use the minor one as the radius to
-     use. */
-
-  /* Horizontal radius */
-  max_radius_x = ABS ((priv->center_x - (tooltip_width/2 + WINDOW_PADDING)) / cos (medium_angle));
-
-  /* and vertical one */
-  max_radius_y = ABS ((priv->center_y - (tooltip_height/2 + WINDOW_PADDING)) / sin (medium_angle));
-
-  /* get the minor radius */
-  max_radius = MIN (max_radius_x,
-                    max_radius_y);
-                    
-  /* now we get the final coordinates of the line */
-  end_x = priv->center_x + (max_radius * cos (medium_angle));
-  end_y = priv->center_y + (max_radius * sin (medium_angle));
-      
-  /* and the position on the tip */
-  tooltip_x = ceil(end_x - (tooltip_width/2)) + 0.5;
-  tooltip_y = ceil(end_y - (tooltip_height/2)) + 0.5;
 
-  /* Time to the drawing stuff */
+  /* TODO */
+  tooltip_x = MAX (priv->pointer_x - tooltip_width, 0);
+  tooltip_x = ((tooltip_x + tooltip_width) > rchart->allocation.width) ?
+    rchart->allocation.width - tooltip_width : tooltip_x;
+  tooltip_y = MAX (priv->pointer_y - tooltip_height, 0);
+  tooltip_y = ((tooltip_y + tooltip_height) > rchart->allocation.height) ?
+    rchart->allocation.height - tooltip_height : tooltip_y;
+
+  /* avoid blurred lines */
+  tooltip_x = round (tooltip_x) + 0.5;
+  tooltip_y = round (tooltip_y) + 0.5;  
+
+  /* Time to do the drawing stuff */
   cairo_save (cr);
   cairo_set_source_rgb (cr, 0, 0, 0);
 
-  /* If the tip rectangle fully overlaps the line, we don't draw it */
+  cairo_set_line_width (cr, 1);
+  cairo_rectangle (cr, tooltip_x, tooltip_y, tooltip_width, tooltip_height);
+  cairo_set_source_rgb (cr, 0.99, 0.91, 0.31); /* tango: fce94f */
+  cairo_fill_preserve (cr);
+
+  cairo_set_source_rgb (cr, 0, 0, 0);
+  cairo_move_to (cr, tooltip_x+TOOLTIP_PADDING, tooltip_y+TOOLTIP_PADDING);
+  pango_cairo_show_layout (cr, layout);
+
+  cairo_stroke (cr);
+
+  cairo_restore (cr);
+
+  g_object_unref (layout);
+  g_free (text);
+}
+
+/* this function returns the area (rectangle) filled by this
+particular tooltip in previous_rectangle, so that the next tooltip to
+be drawn can decide wether it has enough space or not; in case that
+the tooltip can't be drawn, then the values of previous_rectangle
+remain unchanged */
+static void
+draw_folder_tip (cairo_t *cr,
+                 GtkWidget *rchart,
+                 gdouble init_angle,
+                 gdouble final_angle,
+                 gdouble depth,
+                 gchar *name,
+                 gchar *size,
+                 Tooltip_rectangle *previous_rectangle)
+{
+  BaobabRingschartPrivate *priv;
+  gdouble medium_angle;
+  gdouble start_radius;
+  gdouble max_radius;
+  gdouble origin_x;
+  gdouble origin_y;
+  gdouble max_radius_x;
+  gdouble max_radius_y;
+  gdouble tooltip_x;
+  gdouble tooltip_y;
+  gdouble end_x;
+  gdouble end_y;
+  gdouble tooltip_height;
+  gdouble tooltip_width;  
+  PangoRectangle rect;
+  PangoRectangle ink_rect;
+  PangoLayout *layout;
+  gchar *text = NULL;
+  gint i = 0;
+  gboolean valid = FALSE;
+  gdouble angle;
+  gdouble *test_angles;
+  gint n_test_angles;
+
+  priv = BAOBAB_RINGSCHART_GET_PRIVATE (rchart);
+
+  if (final_angle - init_angle < MIN_DRAWABLE_ANGLE)
+    return;
+
+  if (!priv->subfoldertips_enabled)
+    {
+      /* subfoldertips aren't enabled */ 
+      return;
+    }
+
+  /* prepare the angles to study */
+  angle = final_angle - init_angle;
+  test_angles = NULL;
+  n_test_angles = 0;
+
+  if (angle < G_PI/18) /* less than 10 degrees */
+    {
+      n_test_angles = 1;
+      test_angles = g_malloc (n_test_angles * sizeof (gdouble));
+      test_angles[0] = 0.5;    
+    }
+  else if (angle < G_PI/4)
+    {
+      n_test_angles = 3;
+      test_angles = g_malloc (n_test_angles * sizeof (gdouble));
+      test_angles[0] = 0.5;
+      test_angles[1] = 0.20;
+      test_angles[2] = 0.80;
+    }
+  else if (angle < G_PI/2)
+    {
+      n_test_angles = 5;
+      test_angles = g_malloc (n_test_angles * sizeof (gdouble));
+      test_angles[0] = 0.5;
+      test_angles[1] = 0.33;
+      test_angles[2] = 0.67; 
+      test_angles[3] = 0.17;
+      test_angles[4] = 0.83;
+    } 
+  else if (angle < 3*G_PI/4)
+    {
+      n_test_angles = 7;
+      test_angles = g_malloc (n_test_angles * sizeof (gdouble));
+      test_angles[0] = 0.5; 
+      test_angles[1] = 0.375;
+      test_angles[2] = 0.625; 
+      test_angles[3] = 0.25; 
+      test_angles[4] = 0.75;
+      test_angles[5] = 0.125;
+      test_angles[6] = 0.875;
+    }
+  else 
+    {
+      n_test_angles = 9;
+      test_angles = g_malloc (n_test_angles * sizeof (gdouble));
+      test_angles[0] = 0.5; 
+      test_angles[1] = 0.4;
+      test_angles[2] = 0.6; 
+      test_angles[3] = 0.3; 
+      test_angles[4] = 0.7;
+      test_angles[5] = 0.2;
+      test_angles[6] = 0.8;
+      test_angles[7] = 0.1; 
+      test_angles[8] = 0.9;
+    }
+
+  /* get the size of the text label */
+  /* text = (size != NULL) ? g_strconcat (name, "\n", size, NULL) : g_strdup (name); */
+  /* only the name is shown */
+  text = g_strdup(name);
+  text = g_strconcat("<span size=\"small\">", text, "</span>", NULL);
+  
+  layout = gtk_widget_create_pango_layout (rchart, NULL);
+  pango_layout_set_markup (layout, text, -1);
+  
+  pango_layout_set_indent (layout, 0);
+  pango_layout_set_spacing (layout, 0);
+  
+  pango_layout_get_pixel_extents (layout, &ink_rect, &rect);
+  
+  tooltip_width = rect.width + TOOLTIP_PADDING*2;
+  tooltip_height = rect.height + TOOLTIP_PADDING*2;
+  
+  /* radius to start drawing from */
+  start_radius = (depth != -1) ? (depth + 0.5) * priv->thickness + priv->min_radius : 0;
+
+  /* try a maximum of n_test_angles different angles */
+  while ( i < n_test_angles && !valid)
+    {
+      gint closest_x, closest_y;
+
+      /* angle to start drawing from */
+      medium_angle = angle*test_angles[i] + init_angle;
+
+      i++;
+
+      /* coordinates of the starting point of the line */
+      origin_x = priv->center_x + (cos (medium_angle) * start_radius);
+      origin_y = priv->center_y + (sin (medium_angle) * start_radius);
+
+      /* Horizontal radius */
+      max_radius_x = ABS ((priv->center_x - (tooltip_width/2 + WINDOW_PADDING)) / cos (medium_angle));
+
+      /* and vertical one */
+      max_radius_y = ABS ((priv->center_y - (tooltip_height/2 + WINDOW_PADDING)) / sin (medium_angle));
+
+      /* get the minor radius */
+      max_radius = MIN (max_radius_x, max_radius_y);
+
+      /* there is an alternative way */
+      /* max_radius = MIN( (priv->center_x - (tooltip_width/2 + WINDOW_PADDING)), (priv->center_y - (tooltip_height/2 + WINDOW_PADDING)) ); */
+
+      /* now we get the final coordinates of the line */
+      end_x = priv->center_x + (max_radius * cos (medium_angle));
+      end_y = priv->center_y + (max_radius * sin (medium_angle));
+
+      /* and the position on the tip */
+      tooltip_x = end_x - tooltip_width*0.5;
+      tooltip_y = end_y - tooltip_height*0.5;
+
+      /* coordinates of the closest point to the center */
+      closest_x = (ABS (priv->center_x - tooltip_x) < ABS (priv->center_x - tooltip_x - tooltip_width))? tooltip_x : tooltip_x + tooltip_width;
+      closest_y = (ABS (priv->center_y - tooltip_y) < ABS (priv->center_y - tooltip_y - tooltip_height))? tooltip_y : tooltip_y + tooltip_height;
+
+      /* check for overlaps: */
+      if ((((tooltip_x <= previous_rectangle->x) && (tooltip_x + tooltip_width >= previous_rectangle->x) ||
+          (tooltip_x >= previous_rectangle->x) && (tooltip_x <= previous_rectangle->x + previous_rectangle->width))
+          &&
+          ((tooltip_y <= previous_rectangle->y) && (tooltip_y + tooltip_height >= previous_rectangle->y) ||
+              (tooltip_y >= previous_rectangle->y) && (tooltip_y <= previous_rectangle->y + previous_rectangle->height)))
+              ||
+              /* intersection between the rectangle and the circle at current_depth (or better, current_depth+1) */
+              ( sqrt(pow(priv->center_x - closest_x, 2) + pow(priv->center_y - closest_y, 2)) < ((depth + 0.1) * priv->thickness + priv->min_radius))
+              ||
+              /* tooltip's width greater than half of the widget's */
+              ( tooltip_width > priv->center_x))
+        {
+          continue;
+        }
+      else 
+        {
+          previous_rectangle->x = tooltip_x;
+          previous_rectangle->y = tooltip_y;
+          previous_rectangle->width = tooltip_width+TOOLTIP_SPACING;
+          previous_rectangle->height = tooltip_height+TOOLTIP_SPACING;
+          valid = TRUE;
+        }
+    }
+
+  g_free (text);
+  g_free (test_angles);
+  
+  if (!valid)
+    {
+      g_object_unref (layout);
+      return;
+    }
+
+  /* Time to the drawing stuff */
+  cairo_save (cr);
+  
   if ((origin_x < tooltip_x) || (origin_x > tooltip_x + tooltip_width)
       || (origin_y < tooltip_y) || (origin_y > tooltip_y + tooltip_height))
     {
+      gdouble t_h;
+      gdouble t_w;
+      gdouble c_x;
+      gdouble c_y;
+      gdouble t_x;
+      gdouble t_y;
+      gdouble x_intersection;
+      gdouble y_intersection;
+
+      cairo_set_line_width (cr, 1);
       cairo_move_to(cr, origin_x, origin_y);
-      cairo_line_to(cr, end_x, end_y);
-      cairo_stroke(cr);
+      /* we have to calculate the intersection point */
+      /* the space is divided in four sectors, like an X or so, and on
+         each one of those the line intersects a different edge of the
+         rectangle */
+      /* it's quite likely that the following code can be greatly simplified */
+      t_h = (gdouble)tooltip_height;
+      t_w = (gdouble)tooltip_width;
+      /* center of the tooltip */
+      c_x = (gdouble)(end_x - priv->center_x);
+      c_y = (gdouble)(priv->center_y - end_y);
+      /* top left corner of the tooltip */
+      t_x = (gdouble)(tooltip_x - priv->center_x);
+      t_y = (gdouble)(priv->center_y - tooltip_y);
+      /* intersection point */
+      x_intersection = c_x;
+      y_intersection = c_y;
+
+      if (c_x > 0) {
+        if (c_y > 0) 
+          { /* top right */
+            /* does it intersect the bottom edge? y = 
+               t_y - tooltip_height  :  x_intersection = 
+               (c_x/c_y)*(t_y - tooltip_height) */
+            /* or the left one? x = t_x  :  y_intersection = (c_y/c_x)*(t_x) */
+            gdouble y_left_intersection = (c_y/c_x)*(t_x);
+
+            if ((y_left_intersection <= t_y) && (y_left_intersection > t_y - t_h)) 
+              {  /* left edge */
+                x_intersection = t_x;
+                y_intersection = y_left_intersection;
+              } 
+            else 
+              { /* bottom edge */
+                y_intersection = t_y - t_h;
+                x_intersection = (c_x/c_y)*(t_y - t_h);
+              }
+          } 
+        else 
+          { /* bottom right */
+            /* top : y = t_y  ;  x = (c_x/c_y)*t_y */
+            /* left :  x = t_x  ;  y_intersection = (c_y/c_x)*(t_x) */
+            gdouble y_left_intersection = (c_y/c_x)*(t_x);
+
+            if ((y_left_intersection <= t_y) && (y_left_intersection > t_y - t_h)) 
+              {  /* left edge */
+                x_intersection = t_x;
+                y_intersection = y_left_intersection;
+              } 
+            else 
+              { /* bottom edge */
+                y_intersection = t_y;
+                x_intersection = (c_x/c_y)*(t_y);
+              }
+          }
+      }
+      else  
+        { 
+          if (c_y > 0) 
+            {/* top left */
+              /* right edge : x = t_x + t_w ; y = (c_y/c_x)*(t_x + t_w) */
+              /* bottom :  y = t_y - t_h  :  x = (c_x/c_y)*(t_y + t_h) */
+              gdouble y_right_intersection = (c_y/c_x)*(t_x + t_w);
+
+              if ((y_right_intersection <= t_y) && (y_right_intersection > t_y - t_h)) 
+                {
+                  x_intersection = t_x + t_w;
+                  y_intersection = y_right_intersection;
+                } 
+              else 
+                {
+                  x_intersection =  (c_x/c_y)*(t_y - t_h);
+                  y_intersection = t_y - t_h;
+                }
+            } 
+          else 
+            { /* bottom left */
+              /* top : y = t_y  ;  x = (c_x/c_y)*t_y */
+              /* right :  x = t_x + t_w  ;  y_intersection = (c_y/c_x)*(t_x + t_w) */
+              gdouble y_left_intersection = (c_y/c_x)*(t_x + t_w);
+
+              if ((y_left_intersection <= t_y) && (y_left_intersection > t_y - t_h)) 
+                {  /* left edge */
+                  x_intersection = t_x + t_w;
+                  y_intersection = y_left_intersection;
+                } 
+              else 
+                { /* bottom edge */
+                  y_intersection = t_y;
+                  x_intersection = (c_x/c_y)*(t_y);
+                }
+            }
+        }
+
+      end_x = (gint)((gdouble)priv->center_x + x_intersection);
+      end_y = (gint)((gdouble)priv->center_y - y_intersection);
+
+      cairo_set_source_rgb (cr, 0.8275, 0.8431, 0.8118); /* tango: #d3d7cf */
+      cairo_line_to (cr, end_x, end_y);      
+      cairo_stroke (cr);
+
+      cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.6666 );
+      cairo_arc (cr, origin_x, origin_y, 1.0, 0, 2*G_PI );
+      cairo_stroke (cr);
     }
   
-  cairo_set_line_width (cr, 1);
+  cairo_set_line_width (cr, 0.5);
+
+  /* avoid blurred lines */
+  tooltip_x = round (tooltip_x) + 0.5;
+  tooltip_y = round (tooltip_y) + 0.5;   
+
   cairo_rectangle (cr, tooltip_x, tooltip_y, tooltip_width, tooltip_height);
-  cairo_set_source_rgb (cr, 0.99, 0.91, 0.31); /* tango: fce94f */
-  cairo_fill_preserve (cr);
+  cairo_set_source_rgb (cr, 0.8275, 0.8431, 0.8118);  /* tango: #d3d7cf */
+  cairo_fill_preserve(cr);
+  cairo_set_source_rgb (cr, 0.5333, 0.5412, 0.5216);  /* tango: #888a85 */
+  cairo_stroke (cr);
+
+  cairo_move_to (cr, tooltip_x+TOOLTIP_PADDING-PANGO_LBEARING (ink_rect), tooltip_y+TOOLTIP_PADDING);
 
   cairo_set_source_rgb (cr, 0, 0, 0);
-  cairo_move_to(cr, tooltip_x+TOOLTIP_PADDING, tooltip_y+TOOLTIP_PADDING+PANGO_ASCENT (rect));
   pango_cairo_show_layout (cr, layout);
-    
-  cairo_stroke (cr);  
+  cairo_set_line_width (cr, 1);
+  cairo_stroke (cr);
   cairo_restore (cr);
 
   g_object_unref (layout);
-  g_free (text);
 }
 
 static void
@@ -906,7 +1330,7 @@
   gint color_number;
   gint next_color_number;
 
-  intensity = 1-((circle_number*0.3)/MAX_DRAWABLE_DEPTH);
+  intensity = 1-(((circle_number-1)*0.3)/MAX_DRAWABLE_DEPTH);
 
   if (circle_number == 0)
     {
@@ -954,7 +1378,6 @@
 {
   BaobabRingschartPrivate *priv;
   Color fill_color;
-  GtkTreeIter child;
   gboolean highlighted = FALSE;
 
   priv = BAOBAB_RINGSCHART (rchart)->priv;
@@ -968,27 +1391,28 @@
         {
           if (priv->point_angle >= init_angle)
             {
+              GtkTreePath *path;
+              GtkTreeRowReference *ref;
+              
+              path = gtk_tree_model_get_path (priv->model, iter);
+              ref = gtk_tree_row_reference_new (priv->model, path);
+
               if (priv->button_pressed)
                 {
-                  GtkTreePath *path;
-
                   if (priv->root) 
                     gtk_tree_row_reference_free (priv->root);
 
-                  path = gtk_tree_model_get_path (priv->model, iter);
-                  priv->root = gtk_tree_row_reference_new (priv->model, path);
+                  priv->root = ref;
                   priv->button_pressed = FALSE;
                   real_draw = TRUE;
                   depth = priv->init_depth;
                   radius = priv->min_radius;
                   init_angle = 0;
                   final_angle = 2*G_PI;
-
+                  
                   g_signal_emit (BAOBAB_RINGSCHART (rchart),
                                  ringschart_signals[SECTOR_ACTIVATED],
                                  0, iter);
-                  
-                  gtk_tree_path_free (path);
                 }
               else 
                 {
@@ -1009,10 +1433,13 @@
                   tip->depth = depth-1;
                   tip->name = name;
                   tip->size = size_column;
+                  tip->ref = ref;
                   
                   *tooltips = g_slist_prepend (*tooltips , tip);
                   highlighted = TRUE;
                 }
+
+              gtk_tree_path_free (path);
             }
           else 
             priv->current_final_angle = init_angle;            
@@ -1045,6 +1472,7 @@
 
   if (gtk_tree_model_iter_has_child (priv->model, iter) && (depth < priv->max_depth))
     {
+      GtkTreeIter child  = {0};
       gdouble _init_angle, _final_angle;
 
       gtk_tree_model_iter_children (priv->model, &child, iter);
@@ -1063,14 +1491,16 @@
 
           if (size >= 0)
             {
-               _final_angle = _init_angle + (final_angle - init_angle) * size/100;
-
-               tree_traverse (cr, rchart, &child, depth+1, next_radius, 
-                              _init_angle, _final_angle, 
-                              tooltips, real_draw);
+              _final_angle = _init_angle + (final_angle - init_angle) * size/100;
+              
+              tree_traverse (cr, rchart, &child, depth+1, next_radius, 
+                             _init_angle, _final_angle, 
+                             tooltips, real_draw);
 
-               _init_angle = _final_angle;
+              highlighted = TRUE;
             }
+
+          _init_angle = _final_angle;
         }
       while (gtk_tree_model_iter_next (priv->model, &child));
     }
@@ -1092,11 +1522,13 @@
       if (priv->real_sector)
 	{
 	  priv->button_pressed = TRUE;		  
-	  gtk_widget_queue_resize (widget);
+
+	  gtk_widget_queue_draw (widget);
 	}   	  
       break;
     case MIDDLE_BUTTON:
       /* Go back to the parent dir */
+
       if (priv->root != NULL) 
 	{
           GtkTreePath *path = gtk_tree_row_reference_get_path (priv->root);
@@ -1126,8 +1558,8 @@
 	      g_signal_emit (BAOBAB_RINGSCHART (widget),
 			     ringschart_signals[SECTOR_ACTIVATED],
 			     0, &parent_iter);
-
-              gtk_widget_queue_resize (widget);
+            
+              gtk_widget_queue_draw (widget);
 	    }
 
           gtk_tree_path_free (path);
@@ -1141,6 +1573,49 @@
 }
 
 static gint 
+baobab_ringschart_scroll (GtkWidget *widget,
+                          GdkEventScroll *event)
+{
+  guint current_depth = baobab_ringschart_get_max_depth (widget);
+
+  switch (event->direction)
+    {
+    case GDK_SCROLL_LEFT :
+    case GDK_SCROLL_UP :
+      baobab_ringschart_set_max_depth (widget, current_depth + 1);
+      break;
+    case GDK_SCROLL_RIGHT :
+    case GDK_SCROLL_DOWN :
+      baobab_ringschart_set_max_depth (widget, current_depth - 1);
+      break;
+    }
+
+  /* change the selected sector when zooming */
+  baobab_ringschart_motion_notify (widget, (GdkEventMotion *)event);
+
+  return FALSE;
+}
+
+gboolean
+baobab_ringschart_no_pointer_motion (GtkWidget *widget)
+{
+  BaobabRingschartPrivate *priv;
+  
+  priv = BAOBAB_RINGSCHART (widget)->priv;
+  
+  /* At this function we are sure the mouse pointer didn't move during
+     TOOLTIP_TIMEOUT miliseconds, so we redraw the chart, asking to
+     draw the tooltip also. */
+  priv->draw_tooltip = TRUE;
+
+  gtk_widget_queue_draw (widget);
+
+  /* It's important to return FALSE to prevent the timeout from
+     executing again */
+  return FALSE;
+}
+
+static gint 
 baobab_ringschart_motion_notify (GtkWidget        *widget,
                                  GdkEventMotion   *event)
 {
@@ -1148,31 +1623,85 @@
   gdouble angle;
   gdouble x, y;
   guint depth;
+  guint old_depth;
+  gboolean redraw = FALSE;
 
   priv = BAOBAB_RINGSCHART (widget)->priv;
+  
+  /* First remove a previous timeout that never fired, if any */
+  if (priv->timeout_event_source > 0)
+    {
+      g_source_remove (priv->timeout_event_source);
+    }
+      
+  /* We will redraw the chart here only in one of these situations:
 
-  x = event->x - priv->center_x;
-  y = event->y - priv->center_y;
+     1) If the tooltip window is being shown, to hide it (our
+     behavior is "hide tooltip while moving pointer")
 
-  /* FIXME: could we use cairo_in_stroke or cairo_in_fill? would it be
-     a better solution */
-  angle = atan2 (y, x);
-  angle = (angle > 0) ? angle : angle + 2*G_PI;
-
-  depth = sqrt (x*x + y*y) / (priv->thickness);
-
-  if (priv->current_depth != depth     ||
-      angle < priv->current_init_angle ||
-      angle > priv->current_final_angle)
+     2) If the mouse pointer is inside the maximun depth
+     (priv->max_depth) of the chart and if it hasn't move out
+     from the current sector */
+  
+  /* Situation 1 */
+  if (priv->draw_tooltip)
+    {
+      priv->draw_tooltip = FALSE; /* To avoid drawing the tooltip in the
+                                     chart redraw */
+      redraw = TRUE;
+      
+      /* Add a new timeout for the tooltip */
+      priv->timeout_event_source = 
+        g_timeout_add (TOOLTIP_TIMEOUT,
+                       (GSourceFunc) baobab_ringschart_no_pointer_motion,
+                       widget);
+    }
+  else
     {
+      /* Situation 2  */
+
+      /* We need to calculate depth and angle first */
+      priv->pointer_x = event->x;
+      priv->pointer_y = event->y;
+
+      x = priv->pointer_x - priv->center_x;
+      y = priv->pointer_y - priv->center_y;
+
+      /* FIXME: could we use cairo_in_stroke or cairo_in_fill? would it be
+         a better solution */
+      angle = atan2 (y, x);
+      angle = (angle > 0) ? angle : angle + 2*G_PI;
+
+      depth = sqrt (x*x + y*y) / (priv->thickness);
+
+      old_depth = priv->current_depth; 
       priv->current_depth = depth;
       priv->point_angle = angle;
 
-      gtk_widget_queue_draw (widget);
+      if (depth <= priv->max_depth) {
+
+        /* At this point we know the mouse pointer is potentially over a
+           sector, so let's start the timeout to show the tooltip */
+
+        /* Add a new timeout for the tooltip */
+        priv->timeout_event_source = 
+          g_timeout_add (TOOLTIP_TIMEOUT,
+                         (GSourceFunc) baobab_ringschart_no_pointer_motion,
+                         widget);
+
+        /* Now we check we moved out from current sector */
+        if ((depth != old_depth) || (angle < priv->current_init_angle) || 
+            (angle > priv->current_final_angle))
+          {
+            redraw = TRUE;
+          }
+      }
     }
-  else
+
+  /* Ask redrawing if so stated */
+  if (redraw)
     {
-      gdk_window_get_pointer (widget->window, NULL, NULL, NULL);
+      gtk_widget_queue_draw (widget);
     }
 
   return FALSE;
@@ -1388,7 +1917,7 @@
  *
  * Sets the maximum number of rings that are going to be show in the
  * wigdet, and causes a redraw of the widget to show the new maximum
- * depth.
+ * depth. If max_depth is < 1 MAX_DRAWABLE_DEPTH is used.
  *
  * Fails if @rchart is not a #BaobabRingschart.
  **/
@@ -1403,12 +1932,16 @@
   priv = BAOBAB_RINGSCHART (rchart)->priv;
 
   if (max_depth != priv->max_depth)
-    {    
-      priv->max_depth = MIN (max_depth,
-                             MAX_DRAWABLE_DEPTH);
-
+    {
+      priv->max_depth = MAX (1, MIN (max_depth, MAX_DRAWABLE_DEPTH));
+      priv->max_radius = MIN (rchart->allocation.width / 2,
+                              rchart->allocation.height / 2) - WINDOW_PADDING*2;
+      priv->min_radius = priv->max_radius / (priv->max_depth + 1);
+      priv->thickness = priv->min_radius;
       g_object_notify (G_OBJECT (rchart), "max-depth");
 
+      priv->draw_tooltip = FALSE;
+
       gtk_widget_queue_draw (rchart);
     }
 }
@@ -1468,9 +2001,10 @@
  * baobab_ringschart_get_root:
  * @rchart: a #BaobabRingschart.
  *
- * Returns a #GtkTreePath pointing to the root of the
- * widget. The programmer has the responsability to free the used
- * memory once finished with the returned value.
+ * Returns a #GtkTreePath pointing to the root of the widget. The
+ * programmer has the responsability to free the used memory once
+ * finished with the returned value. It returns NULL if there is no
+ * root node defined
  *
  * Fails if @rchart is not a #BaobabRingschart.
  **/
@@ -1479,7 +2013,10 @@
 {
   g_return_val_if_fail (BAOBAB_IS_RINGSCHART (rchart), NULL);
 
-  return gtk_tree_row_reference_get_path (BAOBAB_RINGSCHART (rchart)->priv->root);  
+  if (BAOBAB_RINGSCHART (rchart)->priv->root) 
+    return gtk_tree_row_reference_get_path (BAOBAB_RINGSCHART (rchart)->priv->root);
+  else
+    return NULL;
 }
 
 /**
@@ -1645,3 +2182,30 @@
   priv->draw_center = draw_center;
   gtk_widget_queue_draw (rchart);   
 }
+
+void baobab_ringschart_set_subfoldertips_enabled (GtkWidget *rchart, 
+                                                  gboolean enabled)
+{
+  BaobabRingschartPrivate *priv;
+
+  g_return_if_fail (BAOBAB_IS_RINGSCHART (rchart));
+
+  priv = BAOBAB_RINGSCHART (rchart)->priv;
+
+  if (enabled != priv->subfoldertips_enabled)
+    {
+      priv->subfoldertips_enabled = enabled;
+      gtk_widget_queue_draw (rchart);
+    }
+}
+
+gboolean baobab_ringschart_get_subfoldertips_enabled (GtkWidget *rchart)
+{
+  BaobabRingschartPrivate *priv;
+
+  g_return_if_fail (BAOBAB_IS_RINGSCHART (rchart));
+
+  priv = BAOBAB_RINGSCHART (rchart)->priv;
+
+  return priv->subfoldertips_enabled;  
+}

Modified: trunk/baobab/src/baobab-ringschart.h
==============================================================================
--- trunk/baobab/src/baobab-ringschart.h	(original)
+++ trunk/baobab/src/baobab-ringschart.h	Thu May  8 11:35:22 2008
@@ -1,7 +1,7 @@
 /*
  * baobab-ringschart.h
  *
- * Copyright (C) 2006 igalia
+ * Copyright (C) 2006, 2007, 2008 Igalia
  *
  * 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
@@ -19,10 +19,15 @@
  * Boston, MA  02110-1301  USA
  *
  * Authors:
+ *   Felipe Erias <femorandeira igalia com>
+ *   Pablo Santamaria <psantamaria igalia com>
+ *   Jacobo Aragunde <jaragunde igalia com>
+ *   Eduardo Lima <elima igalia com>
  *   Mario Sanchez <msanchez igalia com>
- *   Miguel Gomez <mgomez igalia com>
+ *   Miguel Gomez <magomez igalia com>
  *   Henrique Ferreiro <hferreiro igalia com>
  *   Alejandro Pinheiro <apinheiro igalia com>
+ *   Carlos Sanmartin <csanmartin igalia com>
  *   Alejandro Garcia <alex igalia com>
  */
 
@@ -34,6 +39,8 @@
 
 G_BEGIN_DECLS
 
+#define MAX_DRAWABLE_DEPTH 8
+
 #define BAOBAB_RINGSCHART_TYPE		(baobab_ringschart_get_type ())
 #define BAOBAB_RINGSCHART(obj)		(G_TYPE_CHECK_INSTANCE_CAST ((obj), BAOBAB_RINGSCHART_TYPE, BaobabRingschart))
 #define BAOBAB_RINGSCHART_CLASS(obj)	(G_TYPE_CHECK_CLASS_CAST ((obj), BAOBAB_RINGSCHART, BaobabRingschartClass))
@@ -89,6 +96,9 @@
                                        guint depth);
 void baobab_ringschart_draw_center (GtkWidget *rchart, 
                                     gboolean draw_center);
+void baobab_ringschart_set_subfoldertips_enabled (GtkWidget *rchart, 
+                                                  gboolean enabled);
+gboolean baobab_ringschart_get_subfoldertips_enabled (GtkWidget *rchart);
 
 G_END_DECLS
 

Modified: trunk/baobab/src/baobab-scan.c
==============================================================================
--- trunk/baobab/src/baobab-scan.c	(original)
+++ trunk/baobab/src/baobab-scan.c	Thu May  8 11:35:22 2008
@@ -121,6 +121,7 @@
 struct allsizes {
 	goffset size;
 	goffset alloc_size;
+	gint depth;
 };
 
 static const char *dir_attributes = \
@@ -156,7 +157,8 @@
 loopdir (GFile *file,
 	 GFileInfo *info,
 	 guint count,
-	 BaobabHardLinkArray *hla)
+	 BaobabHardLinkArray *hla,
+	 gint current_depth)
 {
 	GList *file_list;
 	guint64 tempHLsize = 0;
@@ -173,7 +175,7 @@
 	count++;
 	retloop.size = 0;
 	retloop.alloc_size = 0;
-	dir_uri = g_file_get_uri (file);
+	retloop.depth = 0;
 
 	/* Skip the user excluded folders */
 	if (baobab_is_excluded_location (file))
@@ -242,9 +244,10 @@
 		if (temp_type == G_FILE_TYPE_DIRECTORY) {
 			GFile *child_dir = g_file_get_child (file, 
 						g_file_info_get_name (temp_info));
-			temp = loopdir (child_dir, temp_info, count, hla);
+			temp = loopdir (child_dir, temp_info, count, hla, current_depth+1);
 			retloop.size += temp.size;
 			retloop.alloc_size += temp.alloc_size;
+			retloop.depth = ((temp.depth + 1) > retloop.depth) ? temp.depth + 1 : retloop.depth;
 			elements++;
 			g_object_unref (child_dir);
 		}
@@ -314,6 +317,7 @@
 	GFileInfo *info;
 	GError *err = NULL;
 	GFileType ftype;
+	struct allsizes sizes;
 
 	g_return_if_fail (location != NULL);
 
@@ -339,7 +343,8 @@
 	if (ftype == G_FILE_TYPE_DIRECTORY) {
 		hla = baobab_hardlinks_array_create ();
 
-		loopdir (location, info, 0, hla);
+		sizes = loopdir (location, info, 0, hla, 0);
+		baobab.model_max_depth = sizes.depth;
 
 		baobab_hardlinks_array_free (hla);
 	}

Modified: trunk/baobab/src/baobab.c
==============================================================================
--- trunk/baobab/src/baobab.c	(original)
+++ trunk/baobab/src/baobab.c	Thu May  8 11:35:22 2008
@@ -172,6 +172,8 @@
 	gtk_tree_model_foreach (GTK_TREE_MODEL (baobab.model),
 				show_bars,
 				NULL);
+
+	baobab_ringschart_set_max_depth (baobab.ringschart, baobab.model_max_depth);
 	baobab_set_busy (FALSE);
 	check_menu_sens (FALSE);
 	set_statusbar (_("Ready"));
@@ -602,6 +604,18 @@
 }
 
 static void
+baobab_subfolderstips_toggled (GConfClient *client,
+			       guint cnxn_id,
+			       GConfEntry *entry,
+			       gpointer user_data)
+{
+        baobab_ringschart_set_subfoldertips_enabled (baobab.ringschart,
+						     gconf_client_get_bool (baobab.gconf_client,
+									    BAOBAB_SUBFLSTIPS_VISIBLE_KEY,
+									    NULL));
+}
+
+static void
 sanity_check_excluded_locations (void)
 {
 	GFile *root;
@@ -660,6 +674,9 @@
 				 NULL, NULL, NULL);
 	gconf_client_notify_add (baobab.gconf_client, SYSTEM_TOOLBAR_STYLE, baobab_toolbar_style,
 				 NULL, NULL, NULL);				 
+	gconf_client_notify_add (baobab.gconf_client, BAOBAB_SUBFLSTIPS_VISIBLE_KEY, baobab_subfolderstips_toggled,
+				 NULL, NULL, NULL);
+
 	uri_list = gconf_client_get_list (baobab.gconf_client,
 						      PROPS_SCAN_KEY,
 						      GCONF_VALUE_STRING,
@@ -727,10 +744,51 @@
 }
 
 static void
+create_context_menu (void)
+{
+	ContextMenu *menu = NULL;
+
+	baobab.rchart_menu = g_new0 (ContextMenu, 1);
+	menu = baobab.rchart_menu;
+
+	menu->widget = gtk_menu_new ();
+		
+	menu->up_item = gtk_image_menu_item_new_with_label (_("Move to parent folder")); 
+	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu->up_item), 
+				       gtk_image_new_from_stock(GTK_STOCK_GO_UP, GTK_ICON_SIZE_MENU));
+		
+	menu->zoom_in_item = gtk_image_menu_item_new_with_label (_("Zoom in")) ;
+	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu->zoom_in_item), 
+				       gtk_image_new_from_stock(GTK_STOCK_ADD, GTK_ICON_SIZE_MENU));
+        
+	menu->zoom_out_item = gtk_image_menu_item_new_with_label (_("Zoom out"));
+	gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu->zoom_out_item), 
+				       gtk_image_new_from_stock(GTK_STOCK_REMOVE, GTK_ICON_SIZE_MENU));       
+		
+	gtk_menu_shell_append (GTK_MENU_SHELL (menu->widget),
+			       menu->up_item);
+	gtk_menu_shell_append (GTK_MENU_SHELL (menu->widget),
+			       menu->zoom_in_item);
+	gtk_menu_shell_append (GTK_MENU_SHELL (menu->widget),
+			       menu->zoom_out_item);
+
+	/* connect signals */
+	g_signal_connect (menu->up_item, "activate",
+			  G_CALLBACK (on_move_upwards_cb), NULL);
+	g_signal_connect (menu->zoom_in_item, "activate",
+			  G_CALLBACK (on_zoom_in_cb), NULL);
+	g_signal_connect (menu->zoom_out_item, "activate",
+			  G_CALLBACK (on_zoom_out_cb), NULL);
+	
+	gtk_widget_show_all (menu->widget);
+}
+
+static void
 initialize_ringschart (void)
 {
         GtkWidget *hpaned_main;
         GtkWidget *ringschart_frame;
+        ContextMenu *menu = NULL;
 
         baobab.ringschart = GTK_WIDGET (baobab_ringschart_new ());
         baobab_ringschart_set_model_with_columns (baobab.ringschart,
@@ -743,6 +801,13 @@
                                                   NULL);
         baobab_ringschart_set_init_depth (baobab.ringschart, 1);
 
+	baobab_ringschart_set_max_depth (baobab.ringschart, 1);
+
+	baobab_ringschart_set_subfoldertips_enabled(baobab.ringschart, 
+						    gconf_client_get_bool (baobab.gconf_client,
+									   BAOBAB_SUBFLSTIPS_VISIBLE_KEY,
+									   NULL));
+
         g_signal_connect (baobab.ringschart, "sector_activated",
                           G_CALLBACK (on_rchart_sector_activated), NULL);
 
@@ -760,6 +825,11 @@
 
         baobab_ringschart_draw_center (baobab.ringschart, TRUE);
 
+	create_context_menu ();
+
+	g_signal_connect (baobab.ringschart, "button-release-event", 
+			  G_CALLBACK (on_rchart_button_release), NULL);
+
         gtk_widget_show_all (ringschart_frame);
 }
 

Modified: trunk/baobab/src/baobab.h
==============================================================================
--- trunk/baobab/src/baobab.h	(original)
+++ trunk/baobab/src/baobab.h	Thu May  8 11:35:22 2008
@@ -42,16 +42,27 @@
 #define BAOBAB_KEY_DIR "/apps/baobab"
 #define BAOBAB_TOOLBAR_VISIBLE_KEY	BAOBAB_KEY_DIR "/ui/toolbar_visible"
 #define BAOBAB_STATUSBAR_VISIBLE_KEY	BAOBAB_KEY_DIR "/ui/statusbar_visible"
+#define BAOBAB_SUBFLSTIPS_VISIBLE_KEY   BAOBAB_KEY_DIR "/ui/baobab_subfoldertips_visible"
 #define PROPS_SCAN_KEY			BAOBAB_KEY_DIR "/properties/skip_scan_uri_list"
 #define PROPS_ENABLE_HOME_MONITOR	BAOBAB_KEY_DIR "/properties/enable_home_monitor"
 #define SYSTEM_TOOLBAR_STYLE		"/desktop/gnome/interface/toolbar_style"
 
+typedef struct _ContextMenu ContextMenu;
+
+struct _ContextMenu {
+	GtkWidget* widget;
+	GtkWidget* up_item;
+	GtkWidget* zoom_in_item;
+	GtkWidget* zoom_out_item;
+	GtkWidget* subfolders_item;
+};
 
 struct _baobab_application {
 	GladeXML *main_xml;
   	GtkWidget *window;
   	GtkWidget *tree_view;
   	GtkWidget *ringschart;
+	ContextMenu *rchart_menu;
 	GtkWidget *toolbar;
 	GtkWidget *spinner;
 	GtkWidget *statusbar;
@@ -67,6 +78,7 @@
 	char *selected_path;
 
 	GConfClient *gconf_client;
+	gint model_max_depth;
 };
 
 struct _baobab_fs {

Modified: trunk/baobab/src/callbacks.c
==============================================================================
--- trunk/baobab/src/callbacks.c	(original)
+++ trunk/baobab/src/callbacks.c	Thu May  8 11:35:22 2008
@@ -424,3 +424,85 @@
 				  path, NULL, FALSE);
 	gtk_tree_path_free (path);
 }
+
+
+gboolean
+on_rchart_button_release (BaobabRingschart *rchart, GdkEventButton *event,
+                          gpointer data)
+{
+  ContextMenu *menu = baobab.rchart_menu;
+  
+  if (event->button== 3) /* right button */
+    {
+      GtkTreePath *root_path = NULL;
+
+      root_path = baobab_ringschart_get_root (baobab.ringschart);
+
+      gtk_widget_set_sensitive (menu->up_item,
+                                ((root_path != NULL) &&
+                                 (gtk_tree_path_get_depth (root_path) > 1)));
+      gtk_widget_set_sensitive (menu->zoom_in_item,
+                                (baobab_ringschart_get_max_depth (baobab.ringschart) > 1));
+      gtk_widget_set_sensitive (menu->zoom_out_item,
+                                (baobab_ringschart_get_max_depth (baobab.ringschart) < MAX_DRAWABLE_DEPTH));
+
+      /* show the menu */
+      gtk_menu_popup (GTK_MENU (menu->widget), NULL, NULL, NULL, NULL,
+                      event->button, event->time);
+      
+      gtk_tree_path_free (root_path);
+    }
+ 
+  return FALSE;
+}
+
+void
+on_move_upwards_cb (GtkCheckMenuItem *checkmenuitem, gpointer user_data)
+{
+  GtkTreePath *path = baobab_ringschart_get_root (baobab.ringschart);
+
+  /* Go back to the parent dir */
+  if (path != NULL)
+    {
+      GtkTreeIter parent_iter;
+      GtkTreeIter root_iter;
+
+      if (path != NULL)
+        {
+          gtk_tree_model_get_iter (GTK_TREE_MODEL (baobab.model), &root_iter, path);
+
+          if (gtk_tree_model_iter_parent (GTK_TREE_MODEL (baobab.model), &parent_iter, &root_iter))
+            {
+              gint valid;
+              GtkTreePath *parent_path;
+
+              gtk_tree_model_get (GTK_TREE_MODEL (baobab.model), &parent_iter, COL_H_ELEMENTS,
+                                  &valid, -1);
+
+              if (valid != -1)
+                {
+                  parent_path = gtk_tree_model_get_path (GTK_TREE_MODEL (baobab.model), &parent_iter);
+
+                  baobab_ringschart_set_root (baobab.ringschart, parent_path);
+
+                  gtk_tree_path_free (parent_path);
+                }
+            }
+        }
+      gtk_tree_path_free (path);
+    }
+}
+
+void
+on_zoom_in_cb (GtkCheckMenuItem *checkmenuitem, gpointer user_data)
+{
+  baobab_ringschart_set_max_depth (baobab.ringschart,
+                                   baobab_ringschart_get_max_depth (baobab.ringschart) - 1);
+}
+
+void
+on_zoom_out_cb (GtkCheckMenuItem *checkmenuitem, gpointer user_data)
+{
+  baobab_ringschart_set_max_depth (baobab.ringschart,
+                                   baobab_ringschart_get_max_depth (baobab.ringschart) + 1);
+}

Modified: trunk/baobab/src/callbacks.h
==============================================================================
--- trunk/baobab/src/callbacks.h	(original)
+++ trunk/baobab/src/callbacks.h	Thu May  8 11:35:22 2008
@@ -68,5 +68,9 @@
 void on_helpcontents_activate (GtkMenuItem *menuitem, gpointer user_data);
 void on_tv_selection_changed (GtkTreeSelection *selection, gpointer user_data);
 void on_rchart_sector_activated (BaobabRingschart *rchart, GtkTreeIter *iter);
+gboolean on_rchart_button_release (BaobabRingschart *rchart, GdkEventButton *event, gpointer data);
+void on_move_upwards_cb (GtkCheckMenuItem *checkmenuitem, gpointer user_data);
+void on_zoom_in_cb (GtkCheckMenuItem *checkmenuitem, gpointer user_data);
+void on_zoom_out_cb (GtkCheckMenuItem *checkmenuitem, gpointer user_data);
 
 #endif /* __BAOBAB_CALLBACKS_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]