[california/wip/725767-week] Fleshing out Week.Pane, moved drawing metrics to Palette object
- From: Jim Nelson <jnelson src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [california/wip/725767-week] Fleshing out Week.Pane, moved drawing metrics to Palette object
- Date: Wed, 7 May 2014 00:45:50 +0000 (UTC)
commit 9345a5a439a45a0fe0483ea670981723c1e6ff9e
Author: Jim Nelson <jim yorba org>
Date: Tue May 6 17:45:07 2014 -0700
Fleshing out Week.Pane, moved drawing metrics to Palette object
Having some trouble getting the Panes inside a ScrolledWindow to
work correctly, will work on that next.
src/Makefile.am | 2 +
src/host/host-main-window.vala | 8 ++
src/view/month/month-cell.vala | 85 +++++--------------
src/view/month/month.vala | 5 -
src/view/view-palette.vala | 167 ++++++++++++++++++++++++++++++++++++
src/view/view.vala | 8 ++-
src/view/week/week-controller.vala | 8 +-
src/view/week/week-grid.vala | 21 ++++-
src/view/week/week-pane.vala | 97 +++++++++++++++++++++
9 files changed, 323 insertions(+), 78 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 9a3aaa8..a5b5de4 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -127,6 +127,7 @@ california_VALASOURCES = \
view/view.vala \
view/view-container.vala \
view/view-controllable.vala \
+ view/view-palette.vala \
\
view/month/month.vala \
view/month/month-cell.vala \
@@ -136,6 +137,7 @@ california_VALASOURCES = \
view/week/week.vala \
view/week/week-controller.vala \
view/week/week-grid.vala \
+ view/week/week-pane.vala \
\
$(NULL)
diff --git a/src/host/host-main-window.vala b/src/host/host-main-window.vala
index dce6443..64c61b6 100644
--- a/src/host/host-main-window.vala
+++ b/src/host/host-main-window.vala
@@ -134,6 +134,14 @@ public class MainWindow : Gtk.ApplicationWindow {
add(layout);
}
+ public override void map() {
+ // give View.Palette a chance to gather display metrics for the various Views (week, months,
+ // etc.)
+ View.Palette.instance.main_window_mapped(this);
+
+ base.map();
+ }
+
private void add_controller(View.Controllable controller) {
view_stack.add_titled(controller.get_container(), controller.title, controller.title);
controller.get_container().show_all();
diff --git a/src/view/month/month-cell.vala b/src/view/month/month-cell.vala
index 0933d02..ae04260 100644
--- a/src/view/month/month-cell.vala
+++ b/src/view/month/month-cell.vala
@@ -11,12 +11,6 @@ namespace California.View.Month {
*/
private class Cell : Gtk.EventBox {
- private const int TOP_LINE_FONT_SIZE_PT = 11;
- private const int LINE_FONT_SIZE_PT = 8;
-
- 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;
@@ -74,18 +68,6 @@ private class Cell : Gtk.EventBox {
private Gee.TreeSet<Component.Event> sorted_events = new
Gee.TreeSet<Component.Event>(all_day_comparator);
private Gee.HashMap<int, Component.Event> line_to_event = new Gee.HashMap<int, Component.Event>();
- // TODO: We may need to get these colors from the theme
- private static Gdk.RGBA RGBA_BORDER = { red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0 };
- private static Gdk.RGBA RGBA_DAY_OF_MONTH = { red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0 };
- private static Gdk.RGBA RGBA_DAY_OUTSIDE_MONTH = { red: 0.6, green: 0.6, blue: 0.6, alpha: 1.0 };
- private static Gdk.RGBA RGBA_CURRENT_DAY = { red: 0.0, green: 0.25, blue: 0.50, alpha: 0.10 };
- private static Gdk.RGBA RGBA_SELECTED = { red: 0.0, green: 0.50, blue: 0.50, alpha: 0.10 };
-
- private static Pango.FontDescription top_line_font;
- private static Pango.FontDescription line_font;
- private static int top_line_height_px = -1;
- private static int line_height_px = -1;
-
private Gtk.DrawingArea canvas = new Gtk.DrawingArea();
public Cell(Grid owner, int row, int col) {
@@ -102,6 +84,7 @@ private class Cell : Gtk.EventBox {
notify["date"].connect(queue_draw);
notify["selected"].connect(queue_draw);
+ Palette.instance.palette_changed.connect(queue_draw);
Calendar.System.instance.is_24hr_changed.connect(on_24hr_changed);
Calendar.System.instance.today_changed.connect(on_today_changed);
@@ -109,26 +92,11 @@ private class Cell : Gtk.EventBox {
}
~Cell() {
+ Palette.instance.palette_changed.disconnect(queue_draw);
Calendar.System.instance.is_24hr_changed.disconnect(on_24hr_changed);
Calendar.System.instance.today_changed.disconnect(on_today_changed);
}
- internal static void init() {
- top_line_font = new Pango.FontDescription();
- top_line_font.set_size(TOP_LINE_FONT_SIZE_PT * Pango.SCALE);
-
- line_font = new Pango.FontDescription();
- line_font.set_size(LINE_FONT_SIZE_PT * Pango.SCALE);
-
- // top_line_height_px and line_height_px can't be calculated until one of the Cells is
- // rendered
- }
-
- internal static void terminate() {
- top_line_font = null;
- line_font = null;
- }
-
// this comparator uses the standard Event comparator with one exception: if both Events require
// solid span lines, it sorts the one(s) with the furthest out end dates to the top, to ensure
// they are at the top of the drawn lines and prevent gaps and skips in the connected bars
@@ -394,16 +362,12 @@ private class Cell : Gtk.EventBox {
}
private bool on_draw(Cairo.Context ctx) {
- // calculate extents if not already calculated;
- if (line_height_px < 0 || top_line_height_px < 0)
- calculate_extents(out top_line_height_px, out line_height_px);
-
// shade background of cell for selection or if today
if (selected) {
- Gdk.cairo_set_source_rgba(ctx, RGBA_SELECTED);
+ Gdk.cairo_set_source_rgba(ctx, Palette.instance.selection);
ctx.paint();
} else if (date != null && date.equal_to(Calendar.System.today)) {
- Gdk.cairo_set_source_rgba(ctx, RGBA_CURRENT_DAY);
+ Gdk.cairo_set_source_rgba(ctx, Palette.instance.current_day);
ctx.paint();
}
@@ -411,7 +375,7 @@ private class Cell : Gtk.EventBox {
int height = get_allocated_height();
// draw border lines (creates grid effect)
- Gdk.cairo_set_source_rgba(ctx, RGBA_BORDER);
+ Gdk.cairo_set_source_rgba(ctx, Palette.instance.border);
ctx.set_line_width(0.5);
// only draw top line if on the top row
@@ -436,7 +400,9 @@ private 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;
+ unowned Gdk.RGBA color = (date in owner.month_of_year)
+ ? Palette.instance.day_in_range
+ : Palette.instance.day_outside_range;
draw_line_of_text(ctx, -1, color, date.day_of_month.informal_number, CapEffect.NONE,
CapEffect.NONE);
}
@@ -497,31 +463,18 @@ private class Cell : Gtk.EventBox {
return true;
}
- private void calculate_extents(out int top_line_height_px, out int line_height_px) {
- Pango.Layout layout = create_pango_layout("Gg");
- layout.set_font_description(top_line_font);
-
- int width;
- layout.get_pixel_size(out width, out top_line_height_px);
-
- layout = create_pango_layout("Gg");
- layout.set_font_description(line_font);
-
- layout.get_pixel_size(out width, out line_height_px);
- }
-
// Returns top y position of line; negative line numbers are treated as top line
// The number is currently not clamped to the height of the widget.
private int get_line_top_y(int line_number) {
int y;
if (line_number < 0) {
- y = TEXT_MARGIN_PX;
+ y = Palette.TEXT_MARGIN_PX;
} else {
// starting y of "regular" lines
- y = TEXT_MARGIN_PX + top_line_height_px + LINE_SPACING_PX;
+ y = Palette.TEXT_MARGIN_PX + Palette.instance.normal_font_height_px + Palette.LINE_SPACING_PX;
// add additional lines
- y += line_number * (line_height_px + LINE_SPACING_PX);
+ y += line_number * (Palette.instance.small_font_height_px + Palette.LINE_SPACING_PX);
}
return y;
@@ -536,7 +489,7 @@ private class Cell : Gtk.EventBox {
int left = 0;
int right = get_allocated_width();
int top = get_line_top_y(line_number);
- int bottom = top + line_height_px;
+ int bottom = top + Palette.instance.small_font_height_px;
// use event color for text unless reversed, where it becomes the background color
Gdk.cairo_set_source_rgba(ctx, rgba);
@@ -554,7 +507,7 @@ private class Cell : Gtk.EventBox {
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, top + (Palette.instance.small_font_height_px / 2));
ctx.line_to(right - POINTED_CAP_WIDTH_PX, bottom);
break;
@@ -576,7 +529,7 @@ private class Cell : Gtk.EventBox {
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, top + (Palette.instance.small_font_height_px / 2));
ctx.line_to(left + POINTED_CAP_WIDTH_PX, top);
break;
@@ -599,11 +552,13 @@ private class Cell : Gtk.EventBox {
}
// 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);
+ int left_text_margin = Palette.TEXT_MARGIN_PX + (left_effect != CapEffect.NONE ? 3 : 0);
+ int right_text_margin = Palette.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_font_description((line_number < 0)
+ ? Palette.instance.normal_font
+ : Palette.instance.small_font);
layout.set_ellipsize(Pango.EllipsizeMode.END);
layout.set_width((right - left - left_text_margin - right_text_margin) * Pango.SCALE);
@@ -621,7 +576,7 @@ private class Cell : Gtk.EventBox {
public Component.Event? get_event_at(Gdk.Point point) {
for (int line_number = 0; line_number < line_to_event.size; line_number++) {
int y = get_line_top_y(line_number);
- if (point.y >= y && point.y < (y + line_height_px))
+ if (point.y >= y && point.y < (y + Palette.instance.small_font_height_px))
return line_to_event.get(line_number);
}
diff --git a/src/view/month/month.vala b/src/view/month/month.vala
index 8f07f50..6c4f016 100644
--- a/src/view/month/month.vala
+++ b/src/view/month/month.vala
@@ -20,17 +20,12 @@ public void init() throws Error {
Calendar.init();
Component.init();
Backing.init();
-
- // internal initialization
- Cell.init();
}
public void terminate() {
if (!Unit.do_terminate(ref init_count))
return;
- Cell.terminate();
-
Backing.terminate();
Component.terminate();
Calendar.terminate();
diff --git a/src/view/view-palette.vala b/src/view/view-palette.vala
new file mode 100644
index 0000000..ae9be91
--- /dev/null
+++ b/src/view/view-palette.vala
@@ -0,0 +1,167 @@
+/* Copyright 2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+namespace California.View {
+
+/**
+ * A singleton holding colors and theme information for drawing the various views.
+ *
+ * TODO: Currently colors are hard-coded. In the future we'll probably need to get these from the
+ * system or the theme.
+ */
+
+public class Palette : BaseObject {
+ /**
+ * Margins around text (in pixels).
+ */
+ public const int TEXT_MARGIN_PX = 2;
+
+ /**
+ * Line spacing when painting text (in pixels).
+ */
+ public const int LINE_SPACING_PX = 4;
+
+ private const int NORMAL_FONT_SIZE_PT = 11;
+ private const int SMALL_FONT_SIZE_PT = 8;
+
+ public static Palette instance { get; private set; }
+
+ /**
+ * Border color (when separating days, for example).
+ */
+ public Gdk.RGBA border { get; private set; }
+
+ /**
+ * Color to use when drawing details of a day inside the current { link View} range.
+ *
+ * @see day_outside_range
+ */
+ public Gdk.RGBA day_in_range { get; private set; }
+
+ /**
+ * Color to use when drawing details of a day outside the current { link View} range.
+ *
+ * @see day_in_range
+ */
+ public Gdk.RGBA day_outside_range { get; private set; }
+
+ /**
+ * Background color for day representing current date.
+ */
+ public Gdk.RGBA current_day { get; private set; }
+
+ /**
+ * Background color to use for selected days/time.
+ */
+ public Gdk.RGBA selection { get; private set; }
+
+ /**
+ * Normal-sized font.
+ *
+ * In general this should be used sparingly, as most calendar views need to conserve screen
+ * real estate and use { link Host.ShowEvent} to display a greater amount of detail.
+ *
+ * @see small_font
+ */
+ public Pango.FontDescription normal_font;
+
+ /**
+ * Font height extent for { link normal_font} (in pixels).
+ *
+ * This will be a negative value until the main window is mapped to the screen.
+ *
+ * @see main_window_mapped
+ */
+ public int normal_font_height_px { get; private set; default = -1; }
+
+ /**
+ * Small font.
+ *
+ * This is more appropriate than { link normal_font} when displaying calendar information,
+ * especially event detail.
+ */
+ public Pango.FontDescription small_font;
+
+ /**
+ * Font height extent for { link small_font} (in pixels).
+ *
+ * This will be a negative value until the main window is mapped to the screen.
+ *
+ * @see main_window_mapped
+ */
+ public int small_font_height_px { get; private set; default = -1; }
+
+ /**
+ * Fired when palette has changed.
+ *
+ * It's generally simpler to subscribe to this signal rather than the "notify" for every
+ * property.
+ */
+ public signal void palette_changed();
+
+ private Palette() {
+ border = { red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0 };
+ day_in_range = { red: 0.0, green: 0.0, blue: 0.0, alpha: 1.0 };
+ day_outside_range = { red: 0.6, green: 0.6, blue: 0.6, alpha: 1.0 };
+ current_day = { red: 0.0, green: 0.25, blue: 0.50, alpha: 0.10 };
+ selection = { red: 0.0, green: 0.50, blue: 0.50, alpha: 0.10 };
+
+ normal_font = new Pango.FontDescription();
+ normal_font.set_size(NORMAL_FONT_SIZE_PT * Pango.SCALE);
+
+ small_font = new Pango.FontDescription();
+ small_font.set_size(SMALL_FONT_SIZE_PT * Pango.SCALE);
+ }
+
+ internal static void init() {
+ instance = new Palette();
+ }
+
+ internal static void terminate() {
+ instance = null;
+ }
+
+ /**
+ * Called by { link Host.MainWindow} when it's mapped to the screen.
+ *
+ * This allows for { link Palette} to retrieve display metrics and other information.
+ */
+ public void main_window_mapped(Gtk.Window window) {
+ bool updated = false;
+
+ int height = get_height_extent(window, normal_font);
+ if (height != normal_font_height_px) {
+ normal_font_height_px = height;
+ updated = true;
+ }
+
+ height = get_height_extent(window, small_font);
+ if (height != small_font_height_px) {
+ small_font_height_px = height;
+ updated = true;
+ }
+
+ if (updated)
+ palette_changed();
+ }
+
+ private static int get_height_extent(Gtk.Widget widget, Pango.FontDescription font) {
+ Pango.Layout layout = widget.create_pango_layout("Gg");
+ layout.set_font_description(font);
+
+ int width, height;
+ layout.get_pixel_size(out width, out height);
+
+ return height;
+ }
+
+ public override string to_string() {
+ return "View.Palette";
+ }
+}
+
+}
+
diff --git a/src/view/view.vala b/src/view/view.vala
index e60f7ee..1af104e 100644
--- a/src/view/view.vala
+++ b/src/view/view.vala
@@ -7,7 +7,7 @@
/**
* User views of the calendar data.
*
- * The { link MainWindow} hosts all views and offers an interface to switch between them.
+ * The { link Host.MainWindow} hosts all views and offers an interface to switch between them.
*/
namespace California.View {
@@ -18,15 +18,21 @@ public void init() throws Error {
if (!Unit.do_init(ref init_count))
return;
+ Palette.init();
+
// subunit initialization
View.Month.init();
+ View.Week.init();
}
public void terminate() {
if (!Unit.do_terminate(ref init_count))
return;
+ View.Week.terminate();
View.Month.terminate();
+
+ Palette.terminate();
}
}
diff --git a/src/view/week/week-controller.vala b/src/view/week/week-controller.vala
index aed2748..0be5d54 100644
--- a/src/view/week/week-controller.vala
+++ b/src/view/week/week-controller.vala
@@ -15,11 +15,11 @@ public class Controller : BaseObject, View.Controllable {
private const int CACHE_NEIGHBORS_COUNT = 4;
- private class MasterStack : Gtk.Stack, View.Container {
+ private class ViewContainer : Gtk.Stack, View.Container {
private Controller _owner;
public unowned View.Controllable owner { get { return _owner; } }
- public MasterStack(Controller owner) {
+ public ViewContainer(Controller owner) {
_owner = owner;
}
}
@@ -49,12 +49,12 @@ public class Controller : BaseObject, View.Controllable {
*/
public Calendar.FirstOfWeek first_of_week { get; set; }
- private MasterStack stack;
+ private ViewContainer stack;
private Toolkit.StackModel<Calendar.Week> stack_model;
private Calendar.WeekSpan cache_span;
public Controller() {
- stack = new MasterStack(this);
+ stack = new ViewContainer(this);
stack.homogeneous = true;
stack.transition_duration = Toolkit.SLOW_STACK_TRANSITION_DURATION_MSEC;
diff --git a/src/view/week/week-grid.vala b/src/view/week/week-grid.vala
index dd82b8a..87a9afc 100644
--- a/src/view/week/week-grid.vala
+++ b/src/view/week/week-grid.vala
@@ -25,6 +25,9 @@ internal class Grid : Gtk.Grid {
*/
public string id { owned get { return week.to_string(); } }
+ private Gtk.Grid pane_grid = new Gtk.Grid();
+ private Gtk.ScrolledWindow scrolled_panes = new Gtk.ScrolledWindow(null, null);
+
public Grid(Calendar.Week week) {
this.week = week;
@@ -33,7 +36,17 @@ internal class Grid : Gtk.Grid {
row_homogeneous = false;
row_spacing = 0;
- // date labels across the top, week panes extending across the bottom
+ pane_grid.column_homogeneous = true;
+ pane_grid.column_spacing = 0;
+ pane_grid.row_homogeneous = true;
+ pane_grid.row_spacing = 0;
+
+ scrolled_panes.hscrollbar_policy = Gtk.PolicyType.NEVER;
+ scrolled_panes.vscrollbar_policy = Gtk.PolicyType.ALWAYS;
+ scrolled_panes.add_with_viewport(pane_grid);
+
+ // date labels across the top, week panes extending across the bottom, all stored inside
+ // a scrolled window
int col = 0;
foreach (Calendar.Date date in week) {
Gtk.Label date_label = new Gtk.Label("%s %d/%d".printf(date.day_of_week.abbrev_name,
@@ -42,12 +55,14 @@ internal class Grid : Gtk.Grid {
date_label.margin_bottom = 2;
attach(date_label, col, 0, 1, 1);
- Gtk.DrawingArea pane = new Gtk.DrawingArea();
+ Pane pane = new Pane(this, date);
pane.expand = true;
- attach(pane, col, 1, 1, 1);
+ pane_grid.attach(pane, col, 0, 1, 1);
col++;
}
+
+ attach(scrolled_panes, 0, 1, col, 1);
}
}
diff --git a/src/view/week/week-pane.vala b/src/view/week/week-pane.vala
new file mode 100644
index 0000000..87232b7
--- /dev/null
+++ b/src/view/week/week-pane.vala
@@ -0,0 +1,97 @@
+/* Copyright 2014 Yorba Foundation
+ *
+ * This software is licensed under the GNU Lesser General Public License
+ * (version 2.1 or later). See the COPYING file in this distribution.
+ */
+
+namespace California.View.Week {
+
+internal class Pane : Gtk.EventBox {
+ public const string PROP_OWNER = "owner";
+ public const string PROP_DATE = "date";
+ public const string PROP_SELECTED = "selected";
+
+ public weak Grid owner { get; private set; }
+
+ public Calendar.Date date { get; set; }
+
+ public bool selected { get; set; default = false; }
+
+ private Gtk.DrawingArea canvas = new Gtk.DrawingArea();
+
+ public Pane(Grid owner, Calendar.Date initial_date) {
+ this.owner = owner;
+ date = initial_date;
+
+ canvas.set_size_request(-1, get_line_y(Calendar.WallTime.latest) + get_line_height());
+ add(canvas);
+
+ notify[PROP_DATE].connect(queue_draw);
+ notify[PROP_SELECTED].connect(queue_draw);
+ Palette.instance.palette_changed.connect(queue_draw);
+ Calendar.System.instance.is_24hr_changed.connect(queue_draw);
+ Calendar.System.instance.today_changed.connect(on_today_changed);
+
+ canvas.draw.connect(on_draw);
+ }
+
+ ~Pane() {
+ Palette.instance.palette_changed.disconnect(queue_draw);
+ Calendar.System.instance.is_24hr_changed.disconnect(queue_draw);
+ Calendar.System.instance.today_changed.disconnect(on_today_changed);
+ }
+
+ private void on_today_changed(Calendar.Date old_today, Calendar.Date new_today) {
+ // need to know re: redrawing background color to indicate current day
+ if (date.equal_to(old_today) || date.equal_to(new_today))
+ queue_draw();
+ }
+
+ private bool on_draw(Cairo.Context ctx) {
+ // shade background color if this is current day or selected
+ if (selected) {
+ Gdk.cairo_set_source_rgba(ctx, Palette.instance.selection);
+ ctx.paint();
+ } else if (date.equal_to(Calendar.System.today)) {
+ Gdk.cairo_set_source_rgba(ctx, Palette.instance.current_day);
+ ctx.paint();
+ }
+
+ int width = get_allocated_width();
+ int height = get_allocated_height();
+
+ // draw border lines (one across top, one on right side)
+ Gdk.cairo_set_source_rgba(ctx, Palette.instance.border);
+ ctx.set_line_width(0.5);
+ ctx.move_to(0, 0);
+ ctx.line_to(width, 0);
+ ctx.line_to(width, height);
+ ctx.stroke();
+
+ // draw hour lines
+ Calendar.WallTime wall_time = Calendar.WallTime.earliest;
+ bool rollover = false;
+ do {
+ wall_time = wall_time.adjust(1, Calendar.TimeUnit.HOUR, out rollover);
+
+ int line_y = get_line_y(wall_time);
+
+ ctx.move_to(0, line_y);
+ ctx.line_to(width, line_y);
+ ctx.stroke();
+ } while (!rollover);
+
+ return true;
+ }
+
+ private int get_line_height() {
+ return (Palette.instance.normal_font_height_px + Palette.LINE_SPACING_PX) * 2;
+ }
+
+ private int get_line_y(Calendar.WallTime wall_time) {
+ return get_line_height() * wall_time.hour;
+ }
+}
+
+}
+
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]