[california/wip/725778-allday] Cap ends of all-day events with rounded and pointed corners



commit 9fb1d91b8169f62b36a77fb128ccd9c126d482d1
Author: Jim Nelson <jim yorba org>
Date:   Thu Apr 24 17:23:18 2014 -0700

    Cap ends of all-day events with rounded and pointed corners

 src/view/month/month-cell.vala |  116 +++++++++++++++++++++++++++++++++++-----
 1 files changed, 103 insertions(+), 13 deletions(-)
---
diff --git a/src/view/month/month-cell.vala b/src/view/month/month-cell.vala
index 1e3b68b..5ac7f3e 100644
--- a/src/view/month/month-cell.vala
+++ b/src/view/month/month-cell.vala
@@ -17,12 +17,24 @@ public class Cell : Gtk.EventBox {
     private const int TEXT_MARGIN_PX = 2;
     private const int LINE_SPACING_PX = 4;
     
+    private const double ROUNDED_CAP_RADIUS = 5.0;
+    private const int POINTED_CAP_WIDTH_PX = 6;
+    
+    private const double DEGREES = Math.PI / 180.0;
+    
     private const string KEY_TOOLTIP = "california-view-month-cell-tooltip";
     
     private const Calendar.WallTime.PrettyFlag PRETTY_TIME_FLAGS =
         Calendar.WallTime.PrettyFlag.OPTIONAL_MINUTES
         | Calendar.WallTime.PrettyFlag.BRIEF_MERIDIEM;
     
+    private enum CapEffect {
+        NONE,
+        BLOCKED,
+        ROUNDED,
+        POINTED
+    }
+    
     public weak Controllable owner { get; private set; }
     public int row { get; private set; }
     public int col { get; private set; }
@@ -333,7 +345,8 @@ public class Cell : Gtk.EventBox {
         // draw day of month as the top line
         if (date != null) {
             Gdk.RGBA color = (date in owner.month_of_year) ? RGBA_DAY_OF_MONTH : RGBA_DAY_OUTSIDE_MONTH;
-            draw_line_of_text(ctx, -1, color, date.day_of_month.informal_number, false);
+            draw_line_of_text(ctx, -1, color, date.day_of_month.informal_number, CapEffect.NONE,
+                CapEffect.NONE);
         }
         
         // walk the assigned line numbers for each event and draw
@@ -357,8 +370,28 @@ public class Cell : Gtk.EventBox {
                 tooltip_text = text;
             }
             
+            // use caps on both ends of all-day events depending whether this is the start, end,
+            // or start/end of week of continuing event
+            CapEffect left_effect = CapEffect.NONE;
+            CapEffect right_effect = CapEffect.NONE;
+            if (event.is_all_day) {
+                if (event.date_span.start_date.equal_to(date))
+                    left_effect = CapEffect.ROUNDED;
+                else if (date.day_of_week == owner.first_of_week.as_day_of_week())
+                    left_effect = CapEffect.POINTED;
+                else
+                    left_effect = CapEffect.BLOCKED;
+                
+                if (event.date_span.end_date.equal_to(date))
+                    right_effect = CapEffect.ROUNDED;
+                else if (date.day_of_week == owner.first_of_week.as_day_of_week().previous())
+                    right_effect = CapEffect.POINTED;
+                else
+                    right_effect = CapEffect.BLOCKED;
+            }
+            
             Pango.Layout layout = draw_line_of_text(ctx, iter.get_key(), 
event.calendar_source.color_as_rgba(),
-                text, event.is_all_day);
+                text, left_effect, right_effect);
             event.set_data<string?>(KEY_TOOLTIP, layout.is_ellipsized() ? tooltip_text : null);
         }
         
@@ -398,27 +431,84 @@ public class Cell : Gtk.EventBox {
     // If line number is negative, the top line is drawn; otherwise, zero-based line numbers get
     // "regular" treatment
     private Pango.Layout draw_line_of_text(Cairo.Context ctx, int line_number, Gdk.RGBA rgba,
-        string text, bool reversed) {
-        int allocated_width = get_allocated_width();
-        int top_y = get_line_top_y(line_number);
+        string text, CapEffect left_effect, CapEffect right_effect) {
+        bool is_reversed = (left_effect != CapEffect.NONE || right_effect != CapEffect.NONE);
         
-        Pango.Layout layout = create_pango_layout(text);
-        layout.set_font_description((line_number < 0) ? top_line_font : line_font);
-        layout.set_ellipsize(Pango.EllipsizeMode.END);
-        layout.set_width((allocated_width - (TEXT_MARGIN_PX * 2)) * Pango.SCALE);
+        int left = 0;
+        int right = get_allocated_width();
+        int top = get_line_top_y(line_number);
+        int bottom = top + line_height_px;
         
+        // use event color for text unless reversed, where it becomes the background color
         Gdk.cairo_set_source_rgba(ctx, rgba);
-        if (reversed) {
-            // draw background rectangle in spec'd color
-            ctx.rectangle(0, top_y, allocated_width, line_height_px);
+        if (is_reversed) {
+            // draw background rectangle in spec'd color with text in white
+            switch (right_effect) {
+                case CapEffect.ROUNDED:
+                    ctx.new_sub_path();
+                    // sub 2 to avoid touching right calendar line
+                    ctx.arc(right - 2 - ROUNDED_CAP_RADIUS, top + ROUNDED_CAP_RADIUS, ROUNDED_CAP_RADIUS,
+                        -90.0 * DEGREES, 0 * DEGREES);
+                    ctx.arc(right - 2 - ROUNDED_CAP_RADIUS, bottom - ROUNDED_CAP_RADIUS, ROUNDED_CAP_RADIUS,
+                        0 * DEGREES, 90.0 * DEGREES);
+                break;
+                
+                case CapEffect.POINTED:
+                    ctx.move_to(right - POINTED_CAP_WIDTH_PX, top);
+                    ctx.line_to(right, top + (line_height_px / 2));
+                    ctx.line_to(right - POINTED_CAP_WIDTH_PX, bottom);
+                break;
+                
+                case CapEffect.BLOCKED:
+                default:
+                    ctx.move_to(right, top);
+                    ctx.line_to(right, bottom);
+                break;
+            }
+            
+            switch (left_effect) {
+                case CapEffect.ROUNDED:
+                    // add one to avoid touching cell to the left's right calendar line
+                    ctx.arc(left + 1 + ROUNDED_CAP_RADIUS, bottom - ROUNDED_CAP_RADIUS, ROUNDED_CAP_RADIUS,
+                        90.0 * DEGREES, 180.0 * DEGREES);
+                    ctx.arc(left + 1 + ROUNDED_CAP_RADIUS, top + ROUNDED_CAP_RADIUS, ROUNDED_CAP_RADIUS,
+                        180.0 * DEGREES, 270.0 * DEGREES);
+                break;
+                
+                case CapEffect.POINTED:
+                    ctx.line_to(left + POINTED_CAP_WIDTH_PX, bottom);
+                    ctx.line_to(left, top + (line_height_px / 2));
+                    ctx.line_to(left + POINTED_CAP_WIDTH_PX, top);
+                break;
+                
+                case CapEffect.BLOCKED:
+                default:
+                    ctx.line_to(left, bottom);
+                    ctx.line_to(left, top);
+                break;
+            }
+            
+            // fill with event color
             ctx.fill_preserve();
+            
+            // close path from last point (deals with capped and uncapped ends) and paint
+            ctx.close_path();
             ctx.stroke ();
             
             // set to white for text
             Gdk.cairo_set_source_rgba(ctx, Gdk.RGBA() { red = 1.0, green = 1.0, blue = 1.0, alpha = 1.0 });
         }
         
-        ctx.move_to(TEXT_MARGIN_PX, top_y);
+        // add a couple of pixels to the text margins if capped
+        int left_text_margin = TEXT_MARGIN_PX + (left_effect != CapEffect.NONE ? 3 : 0);
+        int right_text_margin = TEXT_MARGIN_PX + (right_effect != CapEffect.NONE ? 3 : 0);
+        
+        Pango.Layout layout = create_pango_layout(text);
+        layout.set_font_description((line_number < 0) ? top_line_font : line_font);
+        layout.set_ellipsize(Pango.EllipsizeMode.END);
+        layout.set_width((right - left - left_text_margin - right_text_margin) * Pango.SCALE);
+        
+        ctx.move_to(left_text_margin, top);
         Pango.cairo_show_layout(ctx, layout);
         
         return layout;


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