Logo Search packages:      
Sourcecode: tasque version File versions  Download package

CellRendererDate.cs

using System;
using Mono.Unix;
using Gtk;
using Tasque;

namespace Gtk.Extras
{
      public delegate void DateEditedHandler (CellRendererDate renderer, string path);

      public class CellRendererDate : Gtk.CellRenderer
      {
            DateTime date;
            bool editable;
            bool show_time;

            Window popup;
            Calendar cal;
            string path;

            // The following variable is set during StartEditing ()
            // and this is kind of a hack, but it "works".  The widget
            // that is passed-in to StartEditing() is the TreeView.
            // This is used to position the calendar popup.
            Gtk.TreeView tree;

            private const uint CURRENT_TIME = 0;

            #region Constructors
            /// <summary>
            /// <param name="parent">The parent window where this CellRendererDate
            /// will be used from.  This is needed to access the Gdk.Screen so the
            /// Calendar will popup in the proper location.</param>
            /// </summary>
            public CellRendererDate()
            {
                  date = DateTime.MinValue;
                  editable = false;
                  popup = null;
                  show_time = true;
            }

protected CellRendererDate (System.IntPtr ptr) : base (ptr)
            {
            }
            #endregion // Constructors

            #region Public Properties
            public DateTime Date
            {
                  get {
                        return date;
                  }
                  set {
                        date = value;
                  }
            }

            /// <summary>
            /// If the renderer is editable, a date picker widget will appear when
            /// the user attempts to edit the cell.
            /// </summary>
            public bool Editable
            {
                  get {
                        return editable;
                  }
                  set {
                        editable = value;

                        if (editable)
                              Mode = CellRendererMode.Editable;
                        else
                              Mode = CellRendererMode.Inert;
                  }
            }

            /// <summary>
            /// If true, both the date and time will be shown.  If false, the time
            /// will be omitted.  The default is true.
            /// </summary>
            public bool ShowTime
            {
                  get {
                        return show_time;
                  }
                  set {
                        show_time = value;
                  }
            }
            #endregion // Public Properties

            #region Public Methods
            public override void GetSize (Widget widget, ref Gdk.Rectangle cell_area,
                                          out int x_offset, out int y_offset, out int width, out int height)
            {
                  Pango.Layout layout = GetLayout (widget);

                  // FIXME: If this code is ever built into its own library,
                  // the call to Tomboy will definitely have to change
                  layout.SetText (Utilities.GetPrettyPrintDate (date, show_time));

                  CalculateSize (layout, out x_offset, out y_offset, out width, out height);
            }

            public override CellEditable StartEditing (Gdk.Event evnt,
                            Widget widget, string path, Gdk.Rectangle background_area,
                            Gdk.Rectangle cell_area, CellRendererState flags)
            {
                  this.path = path;
                  this.tree = widget as Gtk.TreeView;
                  ShowCalendar();

                  return null;
            }

            #endregion

            #region Public Events

            public event DateEditedHandler Edited;

            #endregion // Public Events

            #region Private Methods
            protected override void Render (Gdk.Drawable drawable, Widget widget,
                                            Gdk.Rectangle background_area, Gdk.Rectangle cell_area,
                                            Gdk.Rectangle expose_area, CellRendererState flags)
            {
                  Pango.Layout layout = GetLayout (widget);

                  // FIXME: If this code is ever built into its own library,
                  // the call to Tomboy will definitely have to change
                  layout.SetText (Utilities.GetPrettyPrintDate (date, show_time));

                  int x, y, w, h;
                  CalculateSize (layout, out x, out y, out w, out h);

                  StateType state = RendererStateToWidgetState(flags);

                  Gdk.GC gc;
                  if (state.Equals(StateType.Selected)) {
                        // Use the proper Gtk.StateType so text appears properly when selected
                        gc = new Gdk.GC(drawable);
                        gc.Copy(widget.Style.TextGC(state));
                        gc.RgbFgColor = widget.Style.Foreground(state);
                  } else
                        gc = widget.Style.TextGC(Gtk.StateType.Normal);

                  drawable.DrawLayout (
                          gc,
                          cell_area.X + (int)Xalign + (int)Xpad,
                          cell_area.Y + ((cell_area.Height - h) / 2),
                          layout);
            }

            Pango.Layout GetLayout (Gtk.Widget widget)
            {
                  return widget.CreatePangoLayout (string.Empty);
            }

            void CalculateSize (Pango.Layout layout, out int x, out int y,
                                out int width, out int height)
            {
                  int w, h;

                  layout.GetPixelSize (out w, out h);

                  x = 0;
                  y = 0;
                  width = w + ((int) Xpad) * 2;
                  height = h + ((int) Ypad) * 2;
            }

            private void ShowCalendar()
            {
                  popup = new Window(WindowType.Popup);
                  popup.Screen = tree.Screen;

                  Frame frame = new Frame();
                  frame.Shadow = ShadowType.Out;
                  frame.Show();

                  popup.Add(frame);

                  VBox box = new VBox(false, 0);
                  box.Show();
                  frame.Add(box);

                  cal = new Calendar();
                  cal.DisplayOptions = CalendarDisplayOptions.ShowHeading
                                       | CalendarDisplayOptions.ShowDayNames
                                       | CalendarDisplayOptions.ShowWeekNumbers;

                  cal.KeyPressEvent += OnCalendarKeyPressed;
                  popup.ButtonPressEvent += OnButtonPressed;

                  cal.Show();

                  Alignment calAlignment = new Alignment(0.0f, 0.0f, 1.0f, 1.0f);
                  calAlignment.Show();
                  calAlignment.SetPadding(4, 4, 4, 4);
                  calAlignment.Add(cal);

                  box.PackStart(calAlignment, false, false, 0);

                  // FIXME: Make the popup appear directly below the date
                  Gdk.Rectangle allocation = tree.Allocation;
//   Gtk.Requisition req = tree.SizeRequest ();
                  int x = 0, y = 0;
                  tree.GdkWindow.GetOrigin(out x, out y);
//   popup.Move(x + allocation.X, y + allocation.Y + req.Height + 3);
                  popup.Move(x + allocation.X, y + allocation.Y);
                  popup.Show();
                  popup.GrabFocus();

                  Grab.Add(popup);

                  Gdk.GrabStatus grabbed = Gdk.Pointer.Grab(popup.GdkWindow, true,
                                           Gdk.EventMask.ButtonPressMask
                                           | Gdk.EventMask.ButtonReleaseMask
                                           | Gdk.EventMask.PointerMotionMask, null, null, CURRENT_TIME);

                  if (grabbed == Gdk.GrabStatus.Success) {
                        grabbed = Gdk.Keyboard.Grab(popup.GdkWindow,
                                                    true, CURRENT_TIME);

                        if (grabbed != Gdk.GrabStatus.Success) {
                              Grab.Remove(popup);
                              popup.Destroy();
                              popup = null;
                        }
                  } else {
                        Grab.Remove(popup);
                        popup.Destroy();
                        popup = null;
                  }

                  cal.DaySelectedDoubleClick += OnCalendarDaySelected;
                  cal.ButtonPressEvent += OnCalendarButtonPressed;

                  cal.Date = date == DateTime.MinValue ? DateTime.Now : date;
            }

            public void HideCalendar(bool update)
            {
                  if (popup != null) {
                        Grab.Remove(popup);
                        Gdk.Pointer.Ungrab(CURRENT_TIME);
                        Gdk.Keyboard.Ungrab(CURRENT_TIME);

                        popup.Destroy();
                        popup = null;
                  }

                  if (update) {
                        date = cal.GetDate();

                        if (Edited != null)
                              Edited (this, path);
                  }
            }

            private StateType RendererStateToWidgetState(CellRendererState flags)
            {
                  StateType state = StateType.Normal;
                  if ((CellRendererState.Selected & flags).Equals(
                                          CellRendererState.Selected))
                        state = StateType.Selected;
                  return state;
            }
            #endregion

            #region Event Handlers
            private void OnButtonPressed(object o, ButtonPressEventArgs args)
            {
                  if (popup != null)
                        HideCalendar(false);
            }

            private void OnCalendarDaySelected(object o, EventArgs args)
            {
                  HideCalendar(true);
            }

            private void OnCalendarButtonPressed(object o,
                                                 ButtonPressEventArgs args)
            {
                  args.RetVal = true;
            }

            private void OnCalendarKeyPressed(object o, KeyPressEventArgs args)
            {
                  switch (args.Event.Key) {
                  case Gdk.Key.Escape:
                        HideCalendar(false);
                        break;
                  case Gdk.Key.KP_Enter:
                  case Gdk.Key.ISO_Enter:
                  case Gdk.Key.Key_3270_Enter:
                  case Gdk.Key.Return:
                  case Gdk.Key.space:
                  case Gdk.Key.KP_Space:
                        HideCalendar(true);
                        break;
                  default:
                        break;
                  }
            }

            #endregion // Event Handlers
      }
}

Generated by  Doxygen 1.6.0   Back to index