// // Copyright (C) 2008-2009 Jordi Mas i Hernandez, jmas@softcatala.org // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections; using System.IO; using System.Text; using Gtk; using Gdk; using Mono.Unix; using Mistelix.DataModel; using Mistelix.Core; using Mistelix.Widgets; using Mistelix.Dialogs; namespace Mistelix.Widgets { // // Contains all the logic for the project authoring view // public class AuthoringPaneView : DrawingArea { static readonly TargetEntry [] tag_dest_target_table = new TargetEntry [] { new TargetEntry ("application/x-mistelix-item", 0, (uint) 2)}; Project project; DvdMenu menu; bool safearea; Core.Button moving_button; int x_delta, y_delta, button, active_item; public AuthoringPaneView (Gtk.VBox parent, Project project) { Project = project; active_item = -1; DragDataReceived += new DragDataReceivedHandler (HandleTargetDragDataReceived); EventBox eb = new EventBox (); // Provides a window for this windowless widget parent.Add (eb); eb.Add (this); Gtk.Drag.DestSet (this, DestDefaults.All, tag_dest_target_table, DragAction.Copy | DragAction.Move); eb.ButtonPressEvent += HandleButtonPress; eb.ButtonReleaseEvent += HandleButtonRelease; eb.MotionNotifyEvent += HandleMotionNotify; UpdateTheme (); } public Project Project { set { project = value; if (menu != null) menu.Dispose (); menu = new DvdMenu (project); menu.CompletedThumbnails += delegate { Application.Invoke (delegate { QueueDraw (); }); }; menu.Asynchronous = true; if (project != null) { project.Buttons.CollectionChanged += delegate { Logger.Debug ("AuthoringPaneView.Project. CollectionChanged"); Application.Invoke (delegate { QueueDraw (); }); }; } } } public bool ViewSafeArea { set { safearea = value; QueueDraw (); } } public void UpdateTheme () { menu.UpdateTheme (); QueueDraw (); } // Processing of dropped files from the Project Element View is done here void HandleTargetDragDataReceived (object sender, DragDataReceivedArgs args) { Logger.Debug ("AuthoringPaneView.HandleTargetDragDataReceived. {0} {1}", args.X, args.Y); IntList list = new IntList (); list.FromString (System.Text.Encoding.UTF8.GetString (args.SelectionData.Data)); foreach (int item_id in list) { Logger.Debug ("AuthoringPaneView.HandleTargetDragDataReceived.Item {0}", item_id); project.AddButton (new Core.Button (args.X, args.Y, item_id)); } args.RetVal = true; Gtk.Drag.Finish (args.Context, true, false, args.Time); // QueueDraw fired by CollectionChanged } void DrawText (Gdk.Window window, Cairo.Context cr, string text) { bool theme; Gdk.GC light; const int marginx = 10; int winWidth, winHeight, w, h; window.GetSize (out winWidth, out winHeight); if (project != null && project.Details.Theme != null) { theme = true; } else theme = false; if (theme == true) { if (winWidth > project.Details.Width) winWidth = project.Details.Width; if (winHeight > project.Details.Height) winHeight = project.Details.Height; } Pango.Layout layout = new Pango.Layout (this.PangoContext); layout.Width = winWidth * (int) Pango.Scale.PangoScale; layout.SetMarkup (text); layout.GetPixelSize (out w, out h); if (theme) { // TODO: We should force the ink colour too cr.Color = new Cairo.Color (0, 0, 0, 0.7); cr.Rectangle (((winWidth - w) /2) - marginx, (winHeight / 2), w + marginx * 2, h * 2); cr.Fill (); cr.Stroke (); light = Style.LightGC (StateType.Normal); } light = Style.DarkGC (StateType.Normal); window.DrawLayout (light, (winWidth - w) /2, (winHeight / 2) + 4, layout); layout.Dispose (); } protected override bool OnExposeEvent (Gdk.EventExpose args) { if (!IsRealized) return false; int width, height; Cairo.Context cr = Gdk.CairoHelper.Create (args.Window); args.Window.GetSize (out width, out height); cr.Color = new Cairo.Color (1, 1, 1, 1); cr.Paint (); cr.Stroke (); menu.Draw (cr, moving_button); if (project != null) { if (project.Elements.Count == 0) { DrawText (args.Window, cr, Catalog.GetString ("Use the 'Add Videos' or 'Add Slideshow' buttons to add new elements")); } else { if (project.Buttons.Count == 0) DrawText (args.Window, cr, Catalog.GetString ("Drag elements here to add them to the main DVD menu")); } } else { DrawText (args.Window, cr, Catalog.GetString ("Start a new project or open an existing one")); } if (project != null && safearea) { // 95% of the area is safe double w_area = project.Details.Width * 0.05; double h_area = project.Details.Height * 0.05; Utils.DrawSelectionBox (cr, w_area / 2, h_area /2 , project.Details.Width - w_area, project.Details.Height - h_area); } ((IDisposable)cr).Dispose (); return base.OnExposeEvent (args); } void HandleButtonPress (object o, ButtonPressEventArgs args) { Logger.Debug ("AuthoringPaneView.HandleButtonPress"); if (project == null) return; if (args.Event.Type == EventType.TwoButtonPress) { DoubleClick (o, args); return; } int x = (int) args.Event.X; int y = (int) args.Event.Y; int b = ButtonIDFromCoordinates (x, y); if (b == -1) return; if (args.Event.Button == 3) { active_item = b; ExtendedMenu menu = new ExtendedMenu (); menu.AddItem (Catalog.GetString ("Element properties"), OnShowElementProperties); menu.AddItem (Catalog.GetString ("Delete element from project"), OnDeleteElement); menu.Popup (args); } button = b; x_delta = x >= project.Buttons[b].X ? project.Buttons[b].X - x: x - project.Buttons[b].X; y_delta = y >= project.Buttons[b].Y ? project.Buttons[b].Y - y: y - project.Buttons[b].Y; moving_button = new Core.Button (x + x_delta, y + y_delta, project.Buttons[b].LinkedId); GdkWindow.Cursor = new Gdk.Cursor (Gdk.CursorType.Hand1); QueueDraw (); Logger.Debug ("AuthoringPaneView.HandleButtonPress. Button {0}", project.Buttons[b].LinkedId); } int ButtonIDFromCoordinates (int x, int y) { for (int b = 0; b < project.Buttons.Count; b++) { if ((x >= project.Buttons[b].X && x <= project.Buttons[b].X + project.Buttons[b].Width) && (y >= project.Buttons[b].Y && y <= project.Buttons[b].Y + project.Buttons[b].Height)) return b; } return -1; } void HandleMotionNotify (object o, MotionNotifyEventArgs args) { int x = (int) args.Event.X; int y = (int) args.Event.Y; if (moving_button == null || project == null || project.Buttons.Count <= 0) return; if (x + x_delta < 0 || y + y_delta < 0) return; if (x + x_delta + project.Buttons[button].Width > project.details.Width || y + y_delta + project.Buttons[button].Height > project.details.Height) return; moving_button.X = x + x_delta; moving_button.Y = y + y_delta; QueueDraw (); } void HandleButtonRelease (object o, ButtonReleaseEventArgs args) { int x = (int) args.Event.X; int y = (int) args.Event.Y; if (moving_button == null || project == null || project.Buttons.Count <= 0) return; Logger.Debug ("AuthoringPaneView.HandleButtonRelease"); if (x + x_delta < 0 || y + y_delta < 0) return; if (x + x_delta + project.Buttons[button].Width > project.Details.Width || y + y_delta + project.Buttons[button].Height > project.Details.Height) return; Logger.Debug ("AuthoringPaneView.HandleButtonRelease. True"); GdkWindow.Cursor = null; project.Buttons[button].X = (int) args.Event.X + x_delta; project.Buttons[button].Y = (int) args.Event.Y + y_delta; moving_button = null; QueueDraw (); } void DoubleClick (object o, ButtonPressEventArgs args) { Logger.Debug ("AuthoringPaneView.DoubleClick"); if (project == null) return; int x = (int) args.Event.X; int y = (int) args.Event.Y; int b = ButtonIDFromCoordinates (x, y); if (b == -1) return; ShowButtonProperties (b); } void ShowButtonProperties (int button) { ButtonPropertiesDialog dialog = new ButtonPropertiesDialog (project, button); if (dialog.RunModal () == ResponseType.Ok) { // Can change the button ShowAs QueueDraw (); } } void OnShowElementProperties (object obj, EventArgs args) { Logger.Debug ("AuthoringPaneView.OnShowElementProperties"); ShowButtonProperties (active_item); } void OnDeleteElement (object obj, EventArgs args) { Logger.Debug ("AuthoringPaneView.OnDeleteElement"); project.Buttons.Remove (project.Buttons [active_item]); } } }