[baobab/wip/valacharts] Ringschart: add subfolder tips



commit 3fe7c1a00aaefceec299677a41aea599b266c60d
Author: Stefano Facchini <stefano facchini gmail com>
Date:   Tue Jun 11 15:37:31 2013 +0200

    Ringschart: add subfolder tips

 src/baobab-chart.vala      |   10 +--
 src/baobab-ringschart.vala |  165 +++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 168 insertions(+), 7 deletions(-)
---
diff --git a/src/baobab-chart.vala b/src/baobab-chart.vala
index 1aef8a3..d61d24a 100644
--- a/src/baobab-chart.vala
+++ b/src/baobab-chart.vala
@@ -152,10 +152,10 @@ namespace Baobab {
             root = model.get_path (iter);
         }
 
-        protected abstract void draw_item (Cairo.Context cr, ChartItem item, bool highlighted);
-        //abstract void pre_draw  (Cairo.Context cr);
-        //abstract void post_draw  (Cairo.Context cr);
+        protected virtual void post_draw  (Cairo.Context cr) {
+        }
         
+        protected abstract void draw_item (Cairo.Context cr, ChartItem item, bool highlighted);
         protected abstract void calculate_item_geometry (ChartItem item);
 
         protected abstract bool is_point_over_item (ChartItem item, double x, double y);
@@ -319,8 +319,6 @@ namespace Baobab {
         }
 
         void draw_chart (Cairo.Context cr) {
-            // call pre_draw
-
             cr.save ();
 
             foreach (ChartItem item in items) {
@@ -336,7 +334,7 @@ namespace Baobab {
 
             cr.restore ();
 
-            // call post_draw
+            post_draw (cr);
         }
 
         void update_draw (Gtk.TreePath path) {
diff --git a/src/baobab-ringschart.vala b/src/baobab-ringschart.vala
index 2b60709..a899eb4 100644
--- a/src/baobab-ringschart.vala
+++ b/src/baobab-ringschart.vala
@@ -16,10 +16,165 @@ namespace Baobab {
         const double ITEM_MIN_ANGLE = 0.03;
         const double EDGE_ANGLE = 0.004;
 
+        const int SUBFOLDER_TIP_PADDING = 3;
+
+        int subtip_timeout;
+        uint tips_timeout_id = 0;
+        bool drawing_subtips = false;
+        List<ChartItem> subtip_items;
+
+        construct {
+            subtip_timeout = Gtk.Settings.get_default ().gtk_tooltip_timeout * 2;
+
+            notify["highlighted-item"].connect (() => {
+                    if (drawing_subtips) {
+                        queue_draw ();
+                    }
+                    drawing_subtips = false;
+
+                    if (tips_timeout_id != 0) {
+                        Source.remove (tips_timeout_id);
+                        tips_timeout_id = 0;
+                    }
+
+                    subtip_items = null;
+
+                    if (highlighted_item != null) {
+                        tips_timeout_id = Timeout.add (subtip_timeout, () => {
+                            drawing_subtips = true;
+                            queue_draw ();
+                            return false;
+                        });
+                    }
+                });
+        }
+
         protected override ChartItem create_new_chartitem () {
             return (new RingschartItem () as ChartItem);
         }
 
+        protected override void post_draw (Cairo.Context cr) {
+            if (drawing_subtips) {
+                Gtk.Allocation allocation;
+                get_allocation (out allocation);
+
+                var q_width = allocation.width / 2;
+                var q_height = allocation.height / 2;
+                var q_angle = Math.atan2 (q_height, q_width);
+
+                Gdk.Rectangle last_rect = {0};
+
+                foreach (ChartItem item in subtip_items) {
+                    RingschartItem ringsitem = item as RingschartItem;
+
+                    // get the middle angle
+                    var middle_angle = ringsitem.start_angle + ringsitem.angle / 2;
+                    // normalize the middle angle (take it to the first quadrant
+                    var middle_angle_n = middle_angle;
+                    while (middle_angle_n > Math.PI / 2) {
+                        middle_angle_n -= Math.PI;
+                    }
+                    middle_angle_n = Math.fabs (middle_angle_n);
+
+                    // get the pango layout and its enclosing rectangle
+                    var layout = create_pango_layout (null);
+                    var markup = "<span size=\"small\">" + Markup.escape_text (item.name) + "</span>";
+                    layout.set_markup (markup, -1);
+                    layout.set_indent (0);
+                    layout.set_spacing (0);
+                    Pango.Rectangle layout_rect;
+                    layout.get_pixel_extents (null, out layout_rect);
+
+                    // get the center point of the tooltip rectangle
+                    double tip_x, tip_y;
+                    if (middle_angle_n < q_angle) {
+                        tip_x = q_width - layout_rect.width / 2 - SUBFOLDER_TIP_PADDING * 2;
+                        tip_y = Math.tan (middle_angle_n) * tip_x;
+                    } else {
+                        tip_y = q_height - layout_rect.height / 2 - SUBFOLDER_TIP_PADDING * 2;
+                        tip_x = tip_y / Math.tan (middle_angle_n);
+                    }
+
+                    // get the tooltip rectangle
+                    Cairo.Rectangle tooltip_rect = Cairo.Rectangle ();
+                    tooltip_rect.x = q_width + tip_x - layout_rect.width/2 - SUBFOLDER_TIP_PADDING;
+                    tooltip_rect.y = q_height + tip_y - layout_rect.height/2 - SUBFOLDER_TIP_PADDING;
+                    tooltip_rect.width = layout_rect.width + SUBFOLDER_TIP_PADDING * 2;
+                    tooltip_rect.height = layout_rect.height + SUBFOLDER_TIP_PADDING * 2;
+
+                    // check tooltip's width is not greater than half of the widget
+                    if (tooltip_rect.width > q_width) {
+                        continue;
+                    }
+
+                    // translate tooltip rectangle and edge angles to the original quadrant
+                    var a = middle_angle;
+                    int i = 0;
+                    while (a > Math.PI/2) {
+                        if (i % 2 == 0) {
+                            tooltip_rect.x = allocation.width - tooltip_rect.x - tooltip_rect.width;
+                        } else {
+                            tooltip_rect.y = allocation.height - tooltip_rect.y - tooltip_rect.height;
+                        }
+                        i++;
+                        a -= Math.PI/2;
+                    }
+
+                    // get the Gdk.Rectangle of the tooltip (with a little padding)
+                    Gdk.Rectangle _rect = Gdk.Rectangle ();
+                    _rect.x = (int) (tooltip_rect.x - 1);
+                    _rect.y = (int) (tooltip_rect.y - 1);
+                    _rect.width = (int) (tooltip_rect.width + 2);
+                    _rect.height = (int) (tooltip_rect.height + 2);
+
+                    // check if tooltip overlaps
+                    if (!_rect.intersect (last_rect, null)) {
+                        last_rect = _rect;
+
+                        // finally draw the tooltip!
+
+                        // TODO: do not hardcode colors
+
+                        // avoid blurred lines
+                        tooltip_rect.x = (int) Math.floor (tooltip_rect.x) + 0.5;
+                        tooltip_rect.y = (int) Math.floor (tooltip_rect.y) + 0.5;
+
+                        var middle_radius = ringsitem.min_radius + (ringsitem.max_radius - 
ringsitem.min_radius) / 2;
+                        var sector_center_x = q_width + middle_radius * Math.cos (middle_angle);
+                        var sector_center_y = q_height + middle_radius * Math.sin (middle_angle);
+
+                        // draw line from sector center to tooltip center
+                        cr.set_line_width (1);
+                        cr.move_to (sector_center_x, sector_center_y);
+                        cr.set_source_rgb (0.8275, 0.8431, 0.8118); // tango: #d3d7cf
+                        cr.line_to (tooltip_rect.x + tooltip_rect.width / 2,
+                                    tooltip_rect.y + tooltip_rect.height / 2);
+                        cr.stroke ();
+
+                        // draw a tiny circle in sector center
+                        cr.set_source_rgba (1.0, 1.0, 1.0, 0.6666);
+                        cr.arc (sector_center_x, sector_center_y, 1.0, 0, 2 * Math.PI);
+                        cr.stroke ();
+
+                        // draw tooltip box
+                        cr.set_line_width (0.5);
+                        cr.rectangle (tooltip_rect.x, tooltip_rect.y, tooltip_rect.width, 
tooltip_rect.height);
+                        cr.set_source_rgb (0.8275, 0.8431, 0.8118);  // tango: #d3d7cf
+                        cr.fill_preserve ();
+                        cr.set_source_rgb (0.5333, 0.5412, 0.5216);  // tango: #888a85
+                        cr.stroke ();
+
+                        // draw the text inside the box
+                        cr.set_source_rgb (0, 0, 0);
+                        cr.move_to (tooltip_rect.x + SUBFOLDER_TIP_PADDING, tooltip_rect.y + 
SUBFOLDER_TIP_PADDING);
+                        Pango.cairo_show_layout (cr, layout);
+                        cr.set_line_width (1);
+                        cr.stroke ();
+                    }
+                }
+            }
+        }
+
         void draw_sector (Cairo.Context cr,
                           double center_x,
                           double center_y,
@@ -52,7 +207,15 @@ namespace Baobab {
 
         protected override void draw_item (Cairo.Context cr, ChartItem item, bool highlighted) {
             RingschartItem ringsitem = item as RingschartItem;
-            // subtips...
+
+            if (drawing_subtips) {
+                if (highlighted_item != null &&
+                    item.parent != null &&
+                    item.parent.data == highlighted_item) {
+                    subtip_items.prepend (item);
+                }
+            }
+
             var fill_color = get_item_color (ringsitem.start_angle / Math.PI * 99,
                                              item.depth,
                                              highlighted);


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