Start implementing the Date and Time mockups

This commit is contained in:
David Zeuthen 2010-10-13 17:36:52 -04:00
parent 9bfda11f0d
commit 85ec4d86f3
8 changed files with 387 additions and 54 deletions

View File

@ -1,5 +1,5 @@
<?xml version="1.0"?> <?xml version="1.0"?>
<interface domain="gnome-shell"> <interface>
<requires lib="gtk+" version="2.16"/> <requires lib="gtk+" version="2.16"/>
<!-- interface-naming-policy project-wide --> <!-- interface-naming-policy project-wide -->
<object class="GtkDialog" id="prefs-dialog"> <object class="GtkDialog" id="prefs-dialog">
@ -145,6 +145,54 @@
<property name="position">1</property> <property name="position">1</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkFrame" id="frame3">
<property name="visible">True</property>
<property name="label_xalign">0</property>
<property name="shadow_type">none</property>
<child>
<object class="GtkAlignment" id="alignment3">
<property name="visible">True</property>
<property name="top_padding">6</property>
<property name="left_padding">12</property>
<child>
<object class="GtkVBox" id="vbox3">
<property name="visible">True</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkCheckButton" id="week_check">
<property name="label" translatable="yes">Show _week numbers</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
</object>
</child>
<child type="label">
<object class="GtkLabel" id="label_display1">
<property name="visible">True</property>
<property name="label" translatable="yes">Calendar</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">2</property>
</packing>
</child>
</object> </object>
<packing> <packing>
<property name="padding">6</property> <property name="padding">6</property>

View File

@ -795,6 +795,14 @@ StTooltip {
/* Calendar popup */ /* Calendar popup */
.calendar-vertical-separator {
-gradient-width: 2px;
-gradient-start: rgba(8,8,8,0);
-gradient-end: #333333;
-margin-vertical: 1.5em;
width: 1em;
}
#calendarPopup { #calendarPopup {
border-radius: 5px; border-radius: 5px;
background: rgba(0,0,0,0.9); background: rgba(0,0,0,0.9);
@ -807,37 +815,69 @@ StTooltip {
} }
.calendar { .calendar {
spacing-rows: 5px; spacing-rows: 0px;
spacing-columns: 3px; spacing-columns: 0px;
} }
.calendar-change-month { .calendar-change-month {
color: #666666;
font-size: 10px;
padding: 2px; padding: 2px;
} }
.calendar-change-month:hover { .calendar-change-month:hover {
background: #314a6c; background: #999999;
border-radius: 5px; border-radius: 5px;
} }
.calendar-change-month:active { .calendar-change-month:active {
background: #213050; background: #aaaaaa;
border-radius: 5px; border-radius: 5px;
} }
.datemenu-date-label {
font-size: 16px;
font-weight: bold;
color: #999999;
}
.calendar-day-base {
font-size: 10px;
padding: 5px 3px;
text-align: center;
}
.calendar-day-heading {
color: #666666;
}
.calendar-week-number {
color: #666666;
font-weight: bold;
}
.calendar-day { .calendar-day {
padding: 1px 2px; border: 1px solid #333333;
color: #cccccc;
}
.calendar-work-day {
}
.calendar-nonwork-day {
background: #181818;
} }
.calendar-today { .calendar-today {
color: #ffffff;
font-weight: bold; font-weight: bold;
background: #ffffff; background-gradient-direction: vertical;
color: black; background-gradient-start: #3c3c3c;
border-radius: 5px; background-gradient-end: #131313;
} }
.calendar-other-month-day { .calendar-other-month-day {
color: #cccccc; color: #333333;
} }
/* Message Tray */ /* Message Tray */
@ -988,10 +1028,6 @@ StTooltip {
padding-left: 4px; padding-left: 4px;
} }
.calendar-calendarweek {
color: #666666;
}
/* App Switcher */ /* App Switcher */
#altTabPopup { #altTabPopup {
padding: 8px; padding: 8px;

View File

@ -17,6 +17,7 @@ nobase_dist_js_DATA = \
ui/calendar.js \ ui/calendar.js \
ui/chrome.js \ ui/chrome.js \
ui/dash.js \ ui/dash.js \
ui/dateMenu.js \
ui/dnd.js \ ui/dnd.js \
ui/docDisplay.js \ ui/docDisplay.js \
ui/environment.js \ ui/environment.js \

View File

@ -13,6 +13,7 @@ const FORMAT_KEY = 'format';
const SHOW_DATE_KEY = 'show-date'; const SHOW_DATE_KEY = 'show-date';
const SHOW_SECONDS_KEY = 'show-seconds'; const SHOW_SECONDS_KEY = 'show-seconds';
const SHOW_WEEKDATE_KEY = 'show-weekdate';
function ClockPreferences(uiFile) { function ClockPreferences(uiFile) {
this._init(uiFile); this._init(uiFile);
@ -30,6 +31,7 @@ ClockPreferences.prototype = {
this._24hrRadio = builder.get_object('24hr_radio'); this._24hrRadio = builder.get_object('24hr_radio');
this._dateCheck = builder.get_object('date_check'); this._dateCheck = builder.get_object('date_check');
this._secondsCheck = builder.get_object('seconds_check'); this._secondsCheck = builder.get_object('seconds_check');
this._weekCheck = builder.get_object('week_check');
delete builder; delete builder;
@ -37,6 +39,10 @@ ClockPreferences.prototype = {
this._notifyId = this._settings.connect('changed', this._notifyId = this._settings.connect('changed',
Lang.bind(this, Lang.bind(this,
this._updateDialog)); this._updateDialog));
this._calendar_settings = new Gio.Settings({ schema: 'org.gnome.shell.calendar' });
this._calendar_notifyId = this._calendar_settings.connect('changed',
Lang.bind(this,
this._updateDialog));
this._12hrRadio.connect('toggled', Lang.bind(this, this._12hrRadio.connect('toggled', Lang.bind(this,
function() { function() {
@ -53,6 +59,11 @@ ClockPreferences.prototype = {
this._settings.set_boolean(SHOW_SECONDS_KEY, this._settings.set_boolean(SHOW_SECONDS_KEY,
this._secondsCheck.active); this._secondsCheck.active);
})); }));
this._weekCheck.connect('toggled', Lang.bind(this,
function() {
this._calendar_settings.set_boolean(SHOW_WEEKDATE_KEY,
this._weekCheck.active);
}));
this._updateDialog(); this._updateDialog();
}, },
@ -68,11 +79,13 @@ ClockPreferences.prototype = {
this._dateCheck.active = this._settings.get_boolean(SHOW_DATE_KEY); this._dateCheck.active = this._settings.get_boolean(SHOW_DATE_KEY);
this._secondsCheck.active = this._settings.get_boolean(SHOW_SECONDS_KEY); this._secondsCheck.active = this._settings.get_boolean(SHOW_SECONDS_KEY);
this._weekCheck.active = this._calendar_settings.get_boolean(SHOW_WEEKDATE_KEY);
}, },
_onResponse: function() { _onResponse: function() {
this._dialog.destroy(); this._dialog.destroy();
this._settings.disconnect(this._notifyId); this._settings.disconnect(this._notifyId);
this._calendar_settings.disconnect(this._calendar_notifyId);
this.emit('destroy'); this.emit('destroy');
} }
}; };

View File

@ -6,6 +6,8 @@ const Lang = imports.lang;
const St = imports.gi.St; const St = imports.gi.St;
const Pango = imports.gi.Pango; const Pango = imports.gi.Pango;
const Gettext_gtk20 = imports.gettext.domain('gtk20'); const Gettext_gtk20 = imports.gettext.domain('gtk20');
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const MSECS_IN_DAY = 24 * 60 * 60 * 1000; const MSECS_IN_DAY = 24 * 60 * 60 * 1000;
const WEEKDATE_HEADER_WIDTH_DIGITS = 3; const WEEKDATE_HEADER_WIDTH_DIGITS = 3;
@ -17,6 +19,14 @@ function _sameDay(dateA, dateB) {
dateA.getYear() == dateB.getYear()); dateA.getYear() == dateB.getYear());
} }
/* TODO: maybe needs config - right now we assume that Saturday and
* Sunday are work days (not true in e.g. Israel, it's Sunday and
* Monday there)
*/
function _isWorkDay(date) {
return date.getDay() != 0 && date.getDay() != 6;
}
function _getCalendarWeekForDate(date) { function _getCalendarWeekForDate(date) {
// Based on the algorithms found here: // Based on the algorithms found here:
// http://en.wikipedia.org/wiki/Talk:ISO_week_date // http://en.wikipedia.org/wiki/Talk:ISO_week_date
@ -43,6 +53,50 @@ function _getDigitWidth(actor){
return width; return width;
} }
function _getCustomDayAbrreviation(day_number) {
let ret;
switch (day_number) {
case 0:
/* Translators: One-letter abbreaviation for Sunday - note:
* all one-letter abbreviations are always shown together and
* in order, e.g. "S M T W T F S"
*/
ret = _("S");
break;
case 1:
/* Translators: One-letter abbreaviation for Monday */
ret = _("M");
break;
case 2:
/* Translators: One-letter abbreaviation for Tuesday */
ret = _("T");
break;
case 3:
/* Translators: One-letter abbreaviation for Wednesday */
ret = _("W");
break;
case 4:
/* Translators: One-letter abbreaviation for Thursday */
ret = _("T");
break;
case 5:
/* Translators: One-letter abbreaviation for Friday */
ret = _("F");
break;
case 6:
/* Translators: One-letter abbreaviation for Saturday */
ret = _("S");
break;
}
return ret;
}
function Calendar() { function Calendar() {
this._init(); this._init();
} }
@ -125,36 +179,32 @@ Calendar.prototype = {
this._topBox.add(back); this._topBox.add(back);
back.connect('clicked', Lang.bind(this, this._prevMonth)); back.connect('clicked', Lang.bind(this, this._prevMonth));
this._dateLabel = new St.Label(); this._dateLabel = new St.Label({style_class: 'calendar-change-month'});
this._topBox.add(this._dateLabel, { expand: true, x_fill: false, x_align: St.Align.MIDDLE }); this._topBox.add(this._dateLabel, { expand: true, x_fill: false, x_align: St.Align.MIDDLE });
let forward = new St.Button({ label: forwardlabel, style_class: 'calendar-change-month' }); let forward = new St.Button({ label: forwardlabel, style_class: 'calendar-change-month' });
this._topBox.add(forward); this._topBox.add(forward);
forward.connect('clicked', Lang.bind(this, this._nextMonth)); forward.connect('clicked', Lang.bind(this, this._nextMonth));
// Add weekday labels...
//
// We need to figure out the abbreviated localized names for the days of the week; // We need to figure out the abbreviated localized names for the days of the week;
// we do this by just getting the next 7 days starting from right now and then putting // we do this by just getting the next 7 days starting from right now and then putting
// them in the right cell in the table. It doesn't matter if we add them in order // them in the right cell in the table. It doesn't matter if we add them in order
//
let iter = new Date(this.date); let iter = new Date(this.date);
iter.setSeconds(0); // Leap second protection. Hah! iter.setSeconds(0); // Leap second protection. Hah!
iter.setHours(12); iter.setHours(12);
if (this._useWeekdate) {
this._weekdateHeader = new St.Label();
this.actor.add(this._weekdateHeader,
{ row: 1,
col: 0,
x_fill: false, x_align: St.Align.MIDDLE });
this._setWeekdateHeaderWidth();
} else {
this._weekdateHeader = null;
}
for (let i = 0; i < 7; i++) { for (let i = 0; i < 7; i++) {
this.actor.add(new St.Label({ text: iter.toLocaleFormat('%a') }), // Could use iter.toLocaleFormat('%a') but that normally gives three characters
// and we want, ideally, a single character for e.g. S M T W T F S
let custom_day_abbrev = _getCustomDayAbrreviation(iter.getDay());
let label = new St.Label({ text: custom_day_abbrev });
label.style_class = 'calendar-day-base calendar-day-heading';
this.actor.add(label,
{ row: 1, { row: 1,
col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7,
x_fill: false, x_align: St.Align.END }); x_fill: false, x_align: St.Align.MIDDLE });
iter.setTime(iter.getTime() + MSECS_IN_DAY); iter.setTime(iter.getTime() + MSECS_IN_DAY);
} }
@ -234,24 +284,30 @@ Calendar.prototype = {
let row = 2; let row = 2;
while (true) { while (true) {
let label = new St.Label({ text: iter.getDate().toString() }); let label = new St.Label({ text: iter.getDate().toString() });
if (_sameDay(now, iter)) let style_class;
label.style_class = 'calendar-day calendar-today';
else if (iter.getMonth() != this.date.getMonth()) style_class = 'calendar-day-base calendar-day';
label.style_class = 'calendar-day calendar-other-month-day'; if (_isWorkDay(iter))
style_class += ' calendar-work-day'
else else
label.style_class = 'calendar-day'; style_class += ' calendar-nonwork-day'
if (_sameDay(now, iter))
style_class += ' calendar-today';
else if (iter.getMonth() != this.date.getMonth())
style_class += ' calendar-other-month-day';
label.style_class = style_class;
let offsetCols = this._useWeekdate ? 1 : 0; let offsetCols = this._useWeekdate ? 1 : 0;
this.actor.add(label, this.actor.add(label,
{ row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7, { row: row, col: offsetCols + (7 + iter.getDay() - this._weekStart) % 7 });
x_fill: false, x_align: St.Align.END });
if (this._useWeekdate && iter.getDay() == 4) { if (this._useWeekdate && iter.getDay() == 4) {
let label = new St.Label({ text: _getCalendarWeekForDate(iter).toString(), let label = new St.Label({ text: _getCalendarWeekForDate(iter).toString(),
style_class: 'calendar-day calendar-calendarweek'}); style_class: 'calendar-day-base calendar-week-number'});
this.actor.add(label, this.actor.add(label,
{ row: row, col: 0, { row: row, col: 0, y_align: St.Align.MIDDLE });
x_fill: false, x_align: St.Align.MIDDLE });
} }
iter.setTime(iter.getTime() + MSECS_IN_DAY); iter.setTime(iter.getTime() + MSECS_IN_DAY);

189
js/ui/dateMenu.js Normal file
View File

@ -0,0 +1,189 @@
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
const GLib = imports.gi.GLib;
const Gio = imports.gi.Gio;
const Lang = imports.lang;
const Mainloop = imports.mainloop;
const Cairo = imports.cairo;
const Clutter = imports.gi.Clutter;
const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Gettext = imports.gettext.domain('gnome-shell');
const _ = Gettext.gettext;
const Main = imports.ui.main;
const PanelMenu = imports.ui.panelMenu;
const PopupMenu = imports.ui.popupMenu;
const Calendar = imports.ui.calendar;
const CLOCK_FORMAT_KEY = 'format';
const CLOCK_CUSTOM_FORMAT_KEY = 'custom-format';
const CLOCK_SHOW_DATE_KEY = 'show-date';
const CLOCK_SHOW_SECONDS_KEY = 'show-seconds';
function DateMenuButton() {
this._init();
}
function on_vert_sep_repaint (area)
{
let cr = area.get_context();
let themeNode = area.get_theme_node();
let [width, height] = area.get_surface_size();
let found, margin, gradientHeight;
[found, margin] = themeNode.get_length('-margin-vertical', false);
[found, gradientWidth] = themeNode.get_length('-gradient-width', false);
let startColor = new Clutter.Color();
themeNode.get_color('-gradient-start', false, startColor);
let endColor = new Clutter.Color();
themeNode.get_color('-gradient-end', false, endColor);
let gradientHeight = (height - margin * 2);
let gradientOffset = (width - gradientWidth) / 2;
let pattern = new Cairo.LinearGradient(gradientOffset, margin, gradientOffset + gradientWidth, height - margin);
pattern.addColorStopRGBA(0, startColor.red / 255, startColor.green / 255, startColor.blue / 255, startColor.alpha / 255);
pattern.addColorStopRGBA(0.5, endColor.red / 255, endColor.green / 255, endColor.blue / 255, endColor.alpha / 255);
pattern.addColorStopRGBA(1, startColor.red / 255, startColor.green / 255, startColor.blue / 255, startColor.alpha / 255);
cr.setSource(pattern);
cr.rectangle(gradientOffset, margin, gradientWidth, gradientHeight);
cr.fill();
};
DateMenuButton.prototype = {
__proto__: PanelMenu.Button.prototype,
_init: function() {
let item;
PanelMenu.Button.prototype._init.call(this, St.Align.START);
this._clock = new St.Label();
this.actor.set_child(this._clock);
this._date = new St.Label();
this._date.style_class = 'datemenu-date-label';
this.menu._box.add(this._date);
this._calendar = new Calendar.Calendar();
this.menu._box.add(this._calendar.actor);
item = new PopupMenu.PopupSeparatorMenuItem();
this.menu.addMenuItem(item);
item = new PopupMenu.PopupImageMenuItem(_("Date and Time Settings"), 'gnome-shell-clock-preferences');
item.connect('activate', Lang.bind(this, this._onPreferencesActivate));
this.menu.addMenuItem(item);
this._clockSettings = new Gio.Settings({ schema: 'org.gnome.shell.clock' });
this._clockSettings.connect('changed', Lang.bind(this, this._clockSettingsChanged));
this._vertSep = new St.DrawingArea({ style_class: 'calendar-vertical-separator',
pseudo_class: 'highlighted' });
//this._vertSep.set_width (25);
this._vertSep.connect('repaint', Lang.bind(this, on_vert_sep_repaint));
let hbox;
let orig_menu_box;
orig_menu_box = this.menu._box;
this.menu._boxPointer.bin.remove_actor(orig_menu_box);
hbox = new St.BoxLayout();
hbox.add(orig_menu_box);
hbox.add(this._vertSep);
hbox.add(new St.Label({text: "foo0"}));
this.menu._boxPointer.bin.set_child(hbox);
this.menu._box = hbox;
// Start the clock
this._updateClockAndDate();
},
_clockSettingsChanged: function() {
this._updateClockAndDate();
},
_updateClockAndDate: function() {
let format = this._clockSettings.get_string(CLOCK_FORMAT_KEY);
let showDate = this._clockSettings.get_boolean(CLOCK_SHOW_DATE_KEY);
let showSeconds = this._clockSettings.get_boolean(CLOCK_SHOW_SECONDS_KEY);
let clockFormat;
let dateFormat;
switch (format) {
case 'unix':
// force updates every second
showSeconds = true;
clockFormat = '%s';
break;
case 'custom':
// force updates every second
showSeconds = true;
clockFormat = this._clockSettings.get_string(CLOCK_CUSTOM_FORMAT_KEY);
break;
case '24-hour':
if (showDate)
/* Translators: This is the time format with date used
in 24-hour mode. */
clockFormat = showSeconds ? _("%a %b %e, %R:%S")
: _("%a %b %e, %R");
else
/* Translators: This is the time format without date used
in 24-hour mode. */
clockFormat = showSeconds ? _("%a %R:%S")
: _("%a %R");
break;
case '12-hour':
default:
if (showDate)
/* Translators: This is a time format with date used
for AM/PM. */
clockFormat = showSeconds ? _("%a %b %e, %l:%M:%S %p")
: _("%a %b %e, %l:%M %p");
else
/* Translators: This is a time format without date used
for AM/PM. */
clockFormat = showSeconds ? _("%a %l:%M:%S %p")
: _("%a %l:%M %p");
break;
}
let displayDate = new Date();
let msecRemaining;
if (showSeconds) {
msecRemaining = 1000 - displayDate.getMilliseconds();
if (msecRemaining < 50) {
displayDate.setSeconds(displayDate.getSeconds() + 1);
msecRemaining += 1000;
}
} else {
msecRemaining = 60000 - (1000 * displayDate.getSeconds() +
displayDate.getMilliseconds());
if (msecRemaining < 500) {
displayDate.setMinutes(displayDate.getMinutes() + 1);
msecRemaining += 60000;
}
}
this._clock.set_text(displayDate.toLocaleFormat(clockFormat));
/* Translators: This is the date format to use */
dateFormat = _("%B %e, %Y");
this._date.set_text(displayDate.toLocaleFormat(dateFormat));
Mainloop.timeout_add(msecRemaining, Lang.bind(this, this._updateClockAndDate));
return false;
},
_onPreferencesActivate: function() {
Main.overview.hide();
this._spawn(['gnome-shell-clock-preferences']);
},
_spawn: function(args) {
// FIXME: once Shell.Process gets support for signalling
// errors we should pop up an error dialog or something here
// on failure
let p = new Shell.Process({'args' : args});
p.run();
}
};

View File

@ -247,7 +247,7 @@ function _relayout() {
// will be updated when it is next shown. We do the same for // will be updated when it is next shown. We do the same for
// the calendar popdown. // the calendar popdown.
overview.hide(); overview.hide();
panel.hideCalendar(); //panel.hideCalendar();
} }
// metacity-clutter currently uses the same prefs as plain metacity, // metacity-clutter currently uses the same prefs as plain metacity,

View File

@ -16,6 +16,7 @@ const Overview = imports.ui.overview;
const PopupMenu = imports.ui.popupMenu; const PopupMenu = imports.ui.popupMenu;
const PanelMenu = imports.ui.panelMenu; const PanelMenu = imports.ui.panelMenu;
const StatusMenu = imports.ui.statusMenu; const StatusMenu = imports.ui.statusMenu;
const DateMenu = imports.ui.dateMenu;
const Main = imports.ui.main; const Main = imports.ui.main;
const Tweener = imports.ui.tweener; const Tweener = imports.ui.tweener;
@ -34,11 +35,6 @@ const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
'a11y': imports.ui.status.accessibility.ATIndicator 'a11y': imports.ui.status.accessibility.ATIndicator
}; };
const CLOCK_FORMAT_KEY = 'format';
const CLOCK_CUSTOM_FORMAT_KEY = 'custom-format';
const CLOCK_SHOW_DATE_KEY = 'show-date';
const CLOCK_SHOW_SECONDS_KEY = 'show-seconds';
function AnimatedIcon(name, size) { function AnimatedIcon(name, size) {
this._init(name, size); this._init(name, size);
} }
@ -792,11 +788,9 @@ Panel.prototype = {
this._menus.addMenu(appMenuButton.menu); this._menus.addMenu(appMenuButton.menu);
/* center */ /* center */
this._dateMenu = new DateMenu.DateMenuButton();
this._clockButton = new ClockButton(); this._centerBox.add(this._dateMenu.actor, { y_fill: true });
this._centerBox.add(this._clockButton.actor, { y_fill: true }); this._menus.addMenu(this._dateMenu.menu);
this._menus.addMenu(this._clockButton.menu);
/* right */ /* right */
@ -856,10 +850,6 @@ Panel.prototype = {
Main.chrome.addActor(this.actor, { visibleInOverview: true }); Main.chrome.addActor(this.actor, { visibleInOverview: true });
}, },
hideCalendar: function() {
this._clockButton.closeCalendar();
},
startupAnimation: function() { startupAnimation: function() {
this.actor.y = -this.actor.height; this.actor.y = -this.actor.height;
Tweener.addTween(this.actor, Tweener.addTween(this.actor,