protected override bool UpdateTarget(ReceiveContext context) { bool update = base.UpdateTarget(context); InkSheetModel sheet = this.Target as InkSheetModel; if (sheet == null) { return(update); } ArrayList deleting = new ArrayList(this.StrokeIds.Length); foreach (Stroke existing in sheet.Ink.Strokes) { if (existing.ExtendedProperties.DoesPropertyExist(StrokeIdExtendedProperty)) { if (Array.IndexOf(this.StrokeIds, existing.ExtendedProperties[StrokeIdExtendedProperty].Data) >= 0) { deleting.Add(existing.Id); } } } int[] ids = ((int[])deleting.ToArray(typeof(int))); using (Strokes strokes = sheet.Ink.CreateStrokes(ids)) { StrokesEventArgs args = new StrokesEventArgs(ids); sheet.OnInkDeleting(args); sheet.Ink.DeleteStrokes(strokes); sheet.OnInkDeleted(args); } return(update); }
protected override bool UpdateTarget(ReceiveContext context) { bool update = base.UpdateTarget(context); InkSheetModel sheet = this.Target as InkSheetModel; if (sheet == null) { return(update); } using (Synchronizer.Lock(sheet.Ink.Strokes.SyncRoot)) { int[] newIds; if (this.SavedInks.Length == 1) { this.LoadInkIntoTarget(sheet, this.SavedInks[0], out newIds); } else { ArrayList ids = new ArrayList(); foreach (byte[] saved in this.SavedInks) { this.LoadInkIntoTarget(sheet, saved, out newIds); ids.AddRange(newIds); } newIds = ((int[])ids.ToArray(typeof(int))); } // Notify the renderers that a new set of strokes have been created. sheet.OnInkAdded(new StrokesEventArgs(newIds)); } return(update); }
/// <summary> /// Performs a deep copy of the given SheetModel. /// If the given sheetmodel is not an InkSheet, then returns itself. /// </summary> /// <param name="s">The SheetModel to copy</param> /// <returns>The given sheetmodel if not an InkSheetModel, otherwise a deep copy of the InkSheetModel</returns> protected SheetModel InkSheetDeepCopyHelper(SheetModel s) { using (Synchronizer.Lock(s.SyncRoot)) { InkSheetModel t; // Only copy InkSheetModels if (s is InkSheetModel) { if (s is RealTimeInkSheetModel) { // Make a deep copy of the SheetModel t = new RealTimeInkSheetModel(Guid.NewGuid(), s.Disposition | SheetDisposition.Remote, s.Bounds, ((RealTimeInkSheetModel)s).Ink.Clone()); using (Synchronizer.Lock(t.SyncRoot)) { ((RealTimeInkSheetModel)t).CurrentDrawingAttributes = ((RealTimeInkSheetModel)s).CurrentDrawingAttributes; } } else { // Make a deep copy of the SheetModel t = new InkSheetModel(Guid.NewGuid(), s.Disposition, s.Bounds, ((InkSheetModel)s).Ink.Clone()); } // This is a new object so add it to the local references Message.AddLocalRef(t.Id, t); return(t); } } return(s); }
protected override object SetUpMember(int index, object member) { SheetModel sheet = ((SheetModel)member); // Add the SheetMatch to the collection of matches using (Synchronizer.Lock(sheet.SyncRoot)) { using (Synchronizer.Lock(this.m_Owner.m_DestSlide.SyncRoot)) { if (sheet is RealTimeInkSheetModel) { // Add the sheet RealTimeInkSheetModel m = new RealTimeInkSheetModel(Guid.NewGuid(), sheet.Disposition, sheet.Bounds); this.m_Owner.m_DestSlide.AnnotationSheets.Add(m); // Add the sheet match SheetMatch toAdd = SheetMatch.ForSheet(this.m_Owner.m_Sender, sheet, m); this.m_Owner.m_SheetMatches.Add(toAdd); } else if (sheet is InkSheetModel) { // Add the sheet InkSheetModel m = new InkSheetModel(Guid.NewGuid(), sheet.Disposition, sheet.Bounds); this.m_Owner.m_DestSlide.AnnotationSheets.Add(m); // Add the sheet match SheetMatch toAdd = SheetMatch.ForSheet(this.m_Owner.m_Sender, sheet, m); this.m_Owner.m_SheetMatches.Add(toAdd); } } } return(null); }
private void LoadInkIntoTarget(InkSheetModel sheet, Ink extracted, out int[] ids) { Ink restored = extracted; using (Synchronizer.Lock(sheet.Ink.Strokes.SyncRoot)) { ids = new int[restored.Strokes.Count]; for (int i = 0; i < ids.Length; i++) { Stroke stroke = restored.Strokes[i]; // Remove any strokes that have the same remote Id as the new one. // Unfortunately, because the InkSheetUndoService cannot preserve stroke referential identity, // we must do a full search each time and cannot simply keep a table. if (stroke.ExtendedProperties.DoesPropertyExist(InkSheetMessage.StrokeIdExtendedProperty)) { object id = stroke.ExtendedProperties[InkSheetMessage.StrokeIdExtendedProperty].Data; foreach (Stroke existing in sheet.Ink.Strokes) { if (existing.ExtendedProperties.DoesPropertyExist(InkSheetMessage.StrokeIdExtendedProperty)) { if (id.Equals(existing.ExtendedProperties[InkSheetMessage.StrokeIdExtendedProperty].Data)) { StrokesEventArgs args = new StrokesEventArgs(new int[] { existing.Id }); sheet.OnInkDeleting(args); sheet.Ink.DeleteStroke(existing); sheet.OnInkDeleted(args); } } } } // The stroke has no association with the current Ink object. // Therefore, we have to recreate it by copying the raw packet data. // This first requires recreating the TabletPropertyDescriptionCollection, // which, for some stupid reason, must be done manually for lack of a better API. TabletPropertyDescriptionCollection properties = new TabletPropertyDescriptionCollection(); foreach (Guid property in stroke.PacketDescription) { properties.Add(new TabletPropertyDescription(property, stroke.GetPacketDescriptionPropertyMetrics(property))); } // Create a new stroke from the raw packet data. Stroke created = sheet.Ink.CreateStroke(stroke.GetPacketData(), properties); // Copy the DrawingAttributes and all application data // (especially the StrokesIdExtendedProperty) to the new stroke. created.DrawingAttributes = stroke.DrawingAttributes; foreach (ExtendedProperty prop in stroke.ExtendedProperties) { created.ExtendedProperties.Add(prop.Id, prop.Data); } ids[i] = created.Id; } } }
/// <summary> /// Handle the button being clicked /// </summary> /// <param name="args">The event args</param> protected override void OnClick(EventArgs args) { if (this.m_Slide == null) { return; } using (Synchronizer.Lock(this.m_Slide.SyncRoot)) { InkSheetModel inks = null; // TODO: This code is duplicated in InkSheetAdapter. Extract to a "ActiveInkAnnotationSheet" property of the SlideModel. // Find the *top-most* *local* InkSheetModel in the annotation layer. for (int i = m_Slide.AnnotationSheets.Count - 1; i >= 0; i--) { SheetModel sheet = m_Slide.AnnotationSheets[i]; if ((sheet.Disposition & SheetDisposition.Remote) != 0) { continue; } if (sheet is InkSheetModel) { inks = ((InkSheetModel)sheet); } //else if (sheet is EditableSheetModel ) { // ///only erase the sheet model if the user made it // ///(i.e. it is editable. If this is sent from another // ///person, don't erase it). // EditableSheetModel edit_sheet = (EditableSheetModel)sheet; // if (edit_sheet.IsEditable) { // m_Slide.AnnotationSheets.Remove(sheet); // } //} } if (inks != null) { using (Synchronizer.Lock(inks.SyncRoot)) { Strokes strokes = inks.Ink.Strokes; using (Synchronizer.Lock(strokes.SyncRoot)) { int[] ids = new int[inks.Ink.Strokes.Count]; for (int j = 0; j < strokes.Count; j++) { ids[j] = strokes[j].Id; } StrokesEventArgs sea = new StrokesEventArgs(ids); inks.OnInkDeleting(sea); inks.Ink.DeleteStrokes(); inks.OnInkDeleted(sea); } } } } base.OnClick(args); }
public SSInkSheetNetworkService(SendingQueue sender, PresentationModel presentation, DeckModel deck, SlideModel slide, InkSheetModel sheet, SheetMessage.SheetCollection selector) : base(sender, presentation, deck, slide, sheet, selector) { this.m_Sheet = sheet; this.m_Sheet.InkAdded += new StrokesEventHandler(this.HandleInkAdded); this.m_Sheet.InkDeleting += new StrokesEventHandler(this.HandleInkDeleting); this.SendExistingInk(); }
public InkSheetMatch(EventQueue sender, InkSheetModel srcSheet, InkSheetModel dstSheet) : base(sender, srcSheet, dstSheet) { this.m_SourceSheet = srcSheet; this.m_DestSheet = dstSheet; this.m_SourceSheet.InkAdded += new StrokesEventHandler(this.HandleInkAdded); this.m_SourceSheet.InkDeleting += new StrokesEventHandler(this.HandleInkDeleting); this.SendExistingInk(); }
public InkSheetRenderer(SlideDisplayModel display, InkSheetModel sheet) : base(display, sheet) { this.m_Sheet = sheet; this.m_Renderer = new Renderer(); this.m_Sheet.Changed["Selection"].Add(new PropertyEventHandler(this.HandleSelectionChanged)); this.m_Sheet.InkAdded += new StrokesEventHandler(this.HandleInkAdded); this.m_Sheet.InkDeleted += new StrokesEventHandler(this.HandleInkDeleted); this.SlideDisplay.Changed["InkTransform"].Add(new PropertyEventHandler(this.HandleInkTransformChanged)); this.HandleInkTransformChanged(this.SlideDisplay, null); }
public InkSheetUndoService(EventQueue dispatcher, UndoModel undo, DeckModel deck, SlideModel slide, InkSheetModel sheet) : base(undo, deck, slide, sheet) { this.m_EventQueue = dispatcher; this.m_InkSheet = sheet; this.m_Ignore = new ArrayList(); //Ignore any sheets with the Remote flag if ((this.m_InkSheet.Disposition & SheetDisposition.Remote) == 0) { this.m_HandleInkChangedDelegate = new HandleInkChangedDelegate(this.HandleInkChanged); this.m_InkSheet.InkAdded += new StrokesEventHandler(this.HandleInkAdded); this.m_InkSheet.InkDeleting += new StrokesEventHandler(this.HandleInkDeleting); } }
/// <summary> /// Construct the InkSheetWebService, this class listens for strokes to finish /// and sends them across the network /// </summary> /// <param name="sender">The queue to use</param> /// <param name="presentation">The presentation model</param> /// <param name="deck">The deck model</param> /// <param name="slide">The slide model</param> /// <param name="sheet">The sheet model</param> /// <param name="selector">The sheet collection we are part of</param> public InkSheetWebService(SendingQueue sender, PresentationModel presentation, DeckModel deck, SlideModel slide, SheetModel sheet, SheetMessage.SheetCollection selector) : base(sender, presentation, deck, slide, sheet, selector) { // Keep track of our sheet this.m_Sheet = (InkSheetModel)sheet; // Get the slide ID using (Synchronizer.Lock(slide.SyncRoot)) { m_SlideID = slide.Id; } // Set Events this.m_Sheet.InkAdded += new StrokesEventHandler(this.HandleInkAdded); // this.m_Sheet.InkDeleting += new StrokesEventHandler(this.HandleInkDeleting); }
public InkSheetNetworkService(SendingQueue sender, PresentationModel presentation, DeckModel deck, SlideModel slide, InkSheetModel sheet, SheetMessage.SheetCollection selector) : base(sender, presentation, deck, slide, sheet, selector) { this.m_Sheet = sheet; using (Synchronizer.Lock(slide.SyncRoot)) { m_SlideID = slide.Id; } this.m_Sheet.InkAdded += new StrokesEventHandler(this.HandleInkAdded); this.m_Sheet.InkDeleting += new StrokesEventHandler(this.HandleInkDeleting); Group receivers = Group.AllParticipant; if ((deck.Disposition & (DeckDisposition.StudentSubmission | DeckDisposition.QuickPoll)) != 0) { receivers = Group.Submissions; } this.SendExistingInk(receivers); }
public InkSheetStrokesAddedMessage(InkSheetModel sheet, Guid slideId, SheetCollection selector, Ink ink) : base(sheet, selector) { this.SavedInks = new byte[][] { ink.Save() }; SlideId = slideId; }
public InkSheetInformationMessage(InkSheetModel sheet, SheetCollection selector) : base(sheet, selector) { }
/// <summary> /// Erases strokes that overlap the cursor. /// </summary> /// <param name="sender">The real time stylus associated with the notification</param> /// <param name="data">The notification data</param> /// <seealso cref="EraserPlugin.StylusDown"/> /// <seealso cref="EraserPlugin.Packets"/> /// <seealso cref="EraserPlugin.StylusUp"/> private void HandlePackets(RealTimeStylus sender, StylusDataBase data) { using (Synchronizer.Lock(this)) { // Ignore the strokes if the eraser stylus is not selected, // and if the stylus is not inverted. if (this.Eraser == null && !data.Stylus.Inverted) { return; } // Ignore if a touch input if (m_TouchSupported) { try { if (sender.GetTabletFromTabletContextId(data.Stylus.TabletContextId).DeviceKind == TabletDeviceKind.Touch) { return; } } catch { m_TouchSupported = false; } } // Ignore the strokes if no ink sheet is selected. InkSheetModel sheet = this.InkSheetModel; if (sheet == null) { return; } // Convert the X and Y coordinates of the data, // which are defined to be at offsets [i] and [i+1], // to an array of Points. Debug.Assert(data.Count % data.PacketPropertyCount == 0); Point[] points = new Point[data.Count / data.PacketPropertyCount]; for (int i = 0, j = 0, il = data.Count, inc = data.PacketPropertyCount; i < il; i += inc, j++) { points[j] = new Point(data[i], data[i + 1]); } // Convert the ink points to pixels so we can // ignore the ones that are outside the slide view area. // This is done all at once to conserve resources used by the Graphics object. Point[] pixels = points; using (Synchronizer.Lock(this.m_Display.SyncRoot)) using (Graphics g = this.m_Display.CreateGraphics()) this.m_Renderer.InkSpaceToPixel(g, ref pixels); // Prevent anyone else from accessing the ink concurrently. using (Synchronizer.Lock(this.InkSheetModel.Ink.Strokes.SyncRoot)) { // Iterate through each point through which the cursor has passed. for (int i = 0, il = points.Length; i < il; i++) { // Don't erase anything when the cursor is outside of the // slide viewing area. This prevents users from accidentally // erasing strokes they can't see, especially when using the // slide zoom feature. if (!this.m_DisplayBounds.Contains(pixels[i])) { continue; } // Find all strokes within some radius from the cursor. Strokes erased = sheet.Ink.HitTest(points[i], ERASER_RADIUS); // If any strokes were found, erase them. if (erased.Count > 0) { // Get the list of stroke IDs in order to send an event int[] ids = new int[erased.Count]; for (int j = 0; j < ids.Length; j++) { ids[j] = erased[j].Id; } // We must first warn listeners that the strokes are about to // be deleted, because after they're deleted, no information // about them can be recovered. This is used to send // network events and to store undo information. sheet.OnInkDeleting(new StrokesEventArgs(ids)); // Delete the erased strokes. sheet.Ink.DeleteStrokes(erased); // Inform listeners that the strokes have actually been deleted. // This causes slide displays to refresh. sheet.OnInkDeleted(new StrokesEventArgs(ids)); } } } } }
public InkSheetStrokesDeletingMessage(InkSheetModel sheet, SheetCollection selector, string[] strokeIds) : base(sheet, selector) { this.StrokeIds = ((string[])strokeIds.Clone()); }
private void HandleSlideChanged(object sender, PropertyEventArgs args) { using (Synchronizer.Lock(this)) { SlideModel slide; using (Synchronizer.Lock(this.m_SlideDisplay.SyncRoot)) { slide = this.m_SlideDisplay.Slide; // Release the reader lock immediately, because it is not possible (or at least easy) // to guarantee consistent locking order between the SlideDisplayModel and the SlideModel. // Most of the SheetRenderer classes will obtain a lock on the SlideModel *first* // and the SlideDisplayModel *second* because they react to changes in the slide; // but that order is not possible here. } if (slide == null) { this.m_Adaptee.InkSheetModel = null; this.m_Adaptee.RealTimeInkSheetModel = null; } else { using (Synchronizer.Lock(slide.SyncRoot)) { try { InkSheetModel inks = null; RealTimeInkSheetModel rti = null; // TODO: This code is duplicated in SlideToolBarButtons.ClearInkSheetToolBarButton. Extract to a "ActiveInkAnnotationSheet" property of the SlideModel. // Find the *top-most* InkSheetModel and RealTimeInkSheetModel in the annotation layer. foreach (SheetModel sheet in slide.AnnotationSheets) { // Only consider local sheets. if ((sheet.Disposition & SheetDisposition.Remote) != 0) { continue; // RealTimeInkSheetModels get priority. } else if (sheet is RealTimeInkSheetModel) { inks = rti = ((RealTimeInkSheetModel)sheet); // Regular InkSheetModels are our second choice. } else if (sheet is InkSheetModel) { inks = ((InkSheetModel)sheet); rti = null; // Only consider the *top-most* non-remote sheet (the last one in the collection). } else { continue; } } if (inks == null && rti == null) { // If the slide does not have an ink annotation sheet, create one. inks = rti = new RealTimeInkSheetModel(Guid.NewGuid(), SheetDisposition.All, Rectangle.Empty); // Add it to the slide. slide.AnnotationSheets.Add(rti); } // Start collecting ink into the InkSheetModel's Ink object // (after the sheet is added to the slide, so renderers don't get out of sync). // Also start sending events to InkSheetModel.RealTimeInk. this.m_Adaptee.InkSheetModel = rti == null ? inks : rti; this.m_Adaptee.RealTimeInkSheetModel = rti; } catch { // We were unable to get an Ink annotation sheet, so disable inking. this.m_Adaptee.InkSheetModel = null; this.m_Adaptee.RealTimeInkSheetModel = null; throw; } } } } }