Example #1
0
            /// <summary>
            /// Re-renders all strokes which are currently being drawn.
            /// </summary>
            /// <remarks>
            /// This method should be invoked whenever the control onto which the
            /// <see cref="Core"/> is drawing is <see cref="Control.Invalidated">invalidated</see>.
            /// </remarks>
            /// <remarks>
            /// This method re-renders only the ink packets which have been received since the last <c>StylusDown</c> event
            /// but before a <c>StylusUp</c> event.  Once <c>StylusUp</c> is received, the packets are discarded and must
            /// be rendered elsewhere.
            /// </remarks>
            protected internal void Refresh(IntPtr hdc)
            {
                using (Synchronizer.Lock(this.m_SlideDisplay.SyncRoot)) {
                    foreach (int stylusId in this.m_CollectedPacketsTable.Keys)
                    {
                        // Get the DrawingAttributes which were in effect on StylusDown.
                        DrawingAttributes atts = ((DrawingAttributes)this.m_DrawingAttributesTable[stylusId]);

                        // Discard the stroke if we have no DrawingAttributes.
                        if (atts == null)
                        {
                            continue;
                        }

                        // Get the tablet description which the renderer will use to interpret the data.
                        TabletPropertyDescriptionCollection tabletProperties =
                            ((TabletPropertyDescriptionCollection)this.m_TabletPropertiesTable[stylusId]);
                        Debug.Assert(tabletProperties != null);

                        // Also add the packets to the collected packets list.
                        List <int> collected = this.m_CollectedPacketsTable[stylusId];
                        int[]      packets   = collected.ToArray();

                        // Create the temporary stroke which we will immediately render.
                        Stroke stroke = this.Ink.CreateStroke(packets, tabletProperties);
                        stroke.DrawingAttributes = atts;

                        // Now draw the stroke.
                        this.m_Renderer.Draw(hdc, stroke);

                        // Immediately delete the stroke, since there's no easy way to save it and modify it for the next data.
                        this.Ink.DeleteStroke(stroke);
                    }
                }
            }
Example #2
0
        /// <summary>
        /// Used by <see cref="Packets"/> and <see cref="StylusUp"/> to render ink.
        /// </summary>
        private void HandleStroke(int stylusId)
        {
            // Also add the packets to the collected packets list.
            List <int> collected = this.collectedPacketsTable[stylusId];
            TabletPropertyDescriptionCollection tabletProperties = this.tabletPropertiesTable[stylusId];

            // Construct the final stroke
            Stroke finalStroke = this.ink.CreateStroke(collected.ToArray(), tabletProperties);

            // Now interpret the stroke
            Point[]   pts        = finalStroke.GetPoints();
            Point     firstPoint = pts[0];
            Point     lastPoint  = pts[pts.Length - 1];
            Rectangle bounding   = finalStroke.GetBoundingBox();

            // Ensure we sort of draw a horizontal shape
            if (bounding.Width > HIMETRIC_WINDOW_WIDTH &&
                bounding.Height < HIMETRIC_WINDOW_HEIGHT)
            {
                // Ensure that the first and last points are far enough apart
                if (Math.Abs(firstPoint.X - lastPoint.X) > HIMETRIC_WINDOW_WIDTH)
                {
                    // Go forward or back depending on the direction
                    if (firstPoint.X < lastPoint.X)
                    {
                        this.NextSlide();
                    }
                    else
                    {
                        this.PrevSlide();
                    }
                }
            }
        }
Example #3
0
            /// <summary>
            /// Notifies the <see cref="Core"/> of the start of a new stroke.
            /// </summary>
            /// <remarks>
            /// Note that some properties of the <see cref="Core"/> take effect only after a <see cref="StylusDown"/> event.
            /// </remarks>
            /// <param name="stylusId">The stylus which is being used to draw the stroke.</param>
            /// <param name="packets">The packet data describing the stroke.</param>
            /// <param name="tabletProperties">
            /// The <see cref="TabletPropertyDescriptionCollection"/>
            /// used to interpret the packet data, and also subsequent packet data from <see cref="Packets"/> and
            /// <see cref="StylusUp"/> events which have the same <paramref name="stylusId"/>.
            /// </param>
            public void StylusDown(int stylusId, int strokeId, int[] packets, TabletPropertyDescriptionCollection tabletProperties)
            {
                using (Synchronizer.Lock(this.m_SlideDisplay.SyncRoot)) {
                    if (!this.Enabled)
                    {
                        return;
                    }

                    // Insert the data into a hashtable using the stylus id as a key.
                    this.m_PacketsTable[stylusId] = packets;

                    // Also store the current DrawingAttributes.  This is necessary to emulate the default
                    // DynamicRenderer which only updates its DrawingAttributes on StylusDown.
                    this.m_DrawingAttributesTable[stylusId] = this.DrawingAttributes;

                    // Store the packets in the collected packets list so we can retrieve them on Refresh().
                    List <int> collected = new List <int>(packets);
                    this.m_CollectedPacketsTable[stylusId] = collected;

                    // Store the strokeId so RenderIncomingPackets will know when to cancel an incomplete
                    // stroke if a StylusUp event is missed.
                    this.m_CurrentStrokeIdTable[stylusId] = strokeId;

                    // Finally store the tablet properties, which will be used to interpret the packets when rendering a stroke.
                    this.m_TabletPropertiesTable[stylusId] = tabletProperties;
                }
            }
Example #4
0
        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;
                }
            }
        }
Example #5
0
            private void AddInk()
            {
                using (Synchronizer.Lock(this)) {
                    // Create an array of stroke Ids in order to fire the InkAdded event later.
                    int[] ids = new int[this.m_StrokesToAdd.Count];

                    using (Synchronizer.Lock(this.m_Watcher.m_InkSheet.Ink.Strokes.SyncRoot)) {
                        for (int i = 0; i < ids.Length; i++)
                        {
                            Stroke stroke = this.m_StrokesToAdd[i];

                            // The stroke probably 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 = this.m_Watcher.m_InkSheet.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);
                            }

                            // Get the new stroke's Id so we can fire the InkAdded event.
                            ids[i] = created.Id;
                        }

                        // If the added strokes don't yet have StrokeIdExtendedProperty properties,
                        // create new Guids for them.  Regardless, set this.m_StrokesToRemove
                        // to the list of stroke Guids.
                        this.UpdateAndSetStrokesToRemoveIds(this.m_StrokesToAdd);

                        // Then, unset this.m_StrokesToAdd since they're already added.
                        this.m_StrokesToAdd = null;
                    }

                    // Create the event arguments and add them to the ignore list so the
                    // InkSheetUndoService won't create an InkUndoer for this change.
                    StrokesEventArgs args = new StrokesEventArgs(ids);
                    using (Synchronizer.Lock(this.m_Watcher.m_Ignore.SyncRoot)) {
                        this.m_Watcher.m_Ignore.Add(args);
                    }

                    // Finally fire the appropriate InkAdded event from the InkSheetModel.
                    this.m_Watcher.m_InkSheet.OnInkAdded(args);
                }
            }
Example #6
0
 /// <summary>
 /// On stylus-down we record initial ink packets, stroke ID and Tablet properties.  Don't return any ink messages yet.
 /// </summary>
 /// <param name="rtissd"></param>
 /// <remarks>
 /// By definition CP3 real-time ink is ink that only exists during the act of inking, then is promptly deleted.  The static
 /// completed strokes are created and deleted by separate messages (InkSheetStrokesAddedMessage/...DeletedMessage).
 /// CP3 generates three types of real-time ink messages: stylus down, packets, and stylus up.  We translate the accumulated
 /// packets into ink strokes (using a constant ID, so that each RT ink message will replace the previous one on WebViewer),
 /// then on stylus up, we delete the last RT stroke, and a completed static ink stroke is added by InkSheetStrokesAddedMessage.
 /// By definition, real-time messages may be dropped by the CP3 sender, so we need to design with this expectation.
 /// The only serious impact of lost RT messages is that they may cause stray RT ink to remain after
 /// the static ink is deleted.  To work around this, we will keep a list of the RT ink strokes which have been
 /// added, but not yet deleted, then on InkSheetStrokesDeleted, we will examine the list, and generate deletes for any strays.
 /// </remarks>
 internal void AddRealTimeInkSheetStylusDown(UW.ClassroomPresenter.Network.Messages.Presentation.RealTimeInkSheetStylusDownMessage rtissd)
 {
     //Debug.WriteLine("***** Realtime Ink stylus down StrokeID=" + rtissd.StrokeId.ToString() + "; stylusId=" + rtissd.StylusId.ToString());
     // Store the packets array. In CP3 they use a hashtable keyed on the stylusId, but we can probably just assume one int[].
     // Also store the current stroke id so that we won't apply the wrong packets if a message is lost.
     this.previousRealTimePackets  = rtissd.Packets;
     this.previousRealTimeStroke   = rtissd.StrokeId;
     this.previousTabletProperties = rtissd.TabletProperties.CreateTabletPropertyDescriptionCollection();
     //For now we assume only one stylus.
 }
Example #7
0
            public TabletPropertyDescriptionCollection CreateTabletPropertyDescriptionCollection()
            {
                TabletPropertyDescriptionCollection tp = new TabletPropertyDescriptionCollection(this.InkToDeviceScaleX, this.InkToDeviceScaleY);

                foreach (TabletPropertyDescriptionInformation info in this.TabletPropertyDescriptions)
                {
                    tp.Add(info.CreateTabletPropertyDescription());
                }
                return(tp);
            }
Example #8
0
        /// <summary>
        /// Occurs when the stylus leaves the digitizer surface.
        /// Retrieve the packet array for this stylus and use it to create
        /// a new stoke.
        /// </summary>
        /// <param name="sender">The real time stylus associated with the notification</param>
        /// <param name="data">The notification data</param>
        void IStylusAsyncPlugin.StylusUp(RealTimeStylus sender, StylusUpData data)
        {
            // Retrieve the packet array from the hashtable using the cursor id as a key.
            int        stylusId = data.Stylus.Id;
            List <int> collected;

            if (!this.m_PacketsTable.TryGetValue(stylusId, out collected))
            {
                // If ink collection was disabled on StylusDown or if the user is erasing,
                // then ignore these packets.
                return;
            }

            int strokeId = this.m_StrokeIdTable[stylusId];

            // Also get the DrawingAttributes which were in effect on StylusDown.
            DrawingAttributes atts = this.m_DrawingAttributesTable[stylusId];

            // Remove this entry from the hash tables since it is no longer needed.
            this.m_PacketsTable.Remove(stylusId);
            this.m_DrawingAttributesTable.Remove(stylusId);

            // Add the newly collected packet data from StylusUp to the array.
            collected.AddRange(data.GetData());

            // Assemble the completed information we'll need to create the stroke.
            int[] packets = collected.ToArray();
            TabletPropertyDescriptionCollection tabletProperties =
                sender.GetTabletPropertyDescriptionCollection(data.Stylus.TabletContextId);

            // Now that we have the data, we're ready to create the stroke and add it to our Ink object.
            using (Synchronizer.Lock(this)) { // Ensure that this.(RealTime)InkSheetModel aren't changed unexpectedly.
                // If there is no Ink object, then probably the SlideViewer is not looking at a slide,
                // so discard the stroke.  Otherwise, create the stroke from the collected packets.
                // Also discard the stroke if we have no DrawingAttributes.

                if (this.InkSheetModel != null && atts != null)
                {
                    int inkStrokeId;
                    using (Synchronizer.Lock(this.InkSheetModel.Ink.Strokes.SyncRoot)) {
                        Stroke stroke = this.InkSheetModel.Ink.CreateStroke(packets, tabletProperties);
                        stroke.DrawingAttributes = atts.Clone();
                        inkStrokeId = stroke.Id;
                    }
                    // Note that this ink stroke's Id is different from the strokeId used by the RealTimeInkSheetModel.
                    this.InkSheetModel.OnInkAdded(new StrokesEventArgs(new int[] { inkStrokeId }));
                }

                if (this.RealTimeInkSheetModel != null)
                {
                    this.RealTimeInkSheetModel.OnStylusUp(stylusId, strokeId, data.GetData());
                }
            }
        }
Example #9
0
            public TabletPropertyDescriptionCollectionInformation(TabletPropertyDescriptionCollection tp)
            {
                this.InkToDeviceScaleX = tp.InkToDeviceScaleX;
                this.InkToDeviceScaleY = tp.InkToDeviceScaleY;

                this.TabletPropertyDescriptions = new ArrayList(tp.Count);
                foreach (TabletPropertyDescription d in tp)
                {
                    this.TabletPropertyDescriptions.Add(new TabletPropertyDescriptionInformation(d));
                }
            }
Example #10
0
        public void OnStylusDown(int stylusId, int strokeId, int[] packets, TabletPropertyDescriptionCollection tabletProperties)
        {
            StylusDownEventHandler handler;

            using (Synchronizer.Lock(this)) {
                handler = (this.m_DrawingAttributes != null) ? this.m_StylusDownDelegate : null;
            }

            if (handler != null)
            {
                handler(this, stylusId, strokeId, packets, tabletProperties);
            }
        }
Example #11
0
        private Dictionary <Guid, SizeF> customSlideBounds;                   //XPS decks use non-standard slide bounds.  Map deckID to bounds.

        public CP3StateCache()
        {
            currentPresentationId          = Guid.Empty;
            currentDeckId                  = Guid.Empty;
            previousTabletProperties       = null;
            currentSlideId                 = Guid.Empty;
            realTimeStrokesPending         = new Dictionary <int, RTStrokeData>();
            sheetToSlideLookup             = new Hashtable();
            sheetToDrawingAttributesLookup = new Hashtable();
            strokeCountsBySlideId          = new Dictionary <Guid, int>();
            toc                   = new TableOfContents();
            pendingInk            = new Dictionary <Guid, List <Ink> >();
            m_QuickPollAggregator = new QuickPollAggregator();
            customSlideBounds     = new Dictionary <Guid, SizeF>();
        }
        /// <summary>
        /// Occurs when the stylus leaves the digitizer surface.
        /// Retrieve the packet array for this stylus and use it to create
        /// a new stoke.
        /// </summary>
        /// <param name="sender">The real time stylus associated with the notification</param>
        /// <param name="data">The notification data</param>
        public void StylusUp(RealTimeStylus sender, StylusUpData data)
        {
            // Retrieve the packet array from the hashtable using the cursor id
            // as a key.  Then, clean this entry from the hash since it is no
            // longer needed.
            ArrayList collectedPackets = (ArrayList)myPackets[data.Stylus.Id];

            myPackets.Remove(data.Stylus.Id);

            // Add the packet data from StylusUp to the array
            collectedPackets.AddRange(data.GetData());

            // Create the stroke using the specified drawing attributes.
            int[] packets = (int[])(collectedPackets.ToArray(typeof(int)));
            TabletPropertyDescriptionCollection tabletProperties = myRealTimeStylus.GetTabletPropertyDescriptionCollection(data.Stylus.TabletContextId);

            Stroke stroke = myInk.CreateStroke(packets, tabletProperties);

            if (stroke != null)
            {
                stroke.DrawingAttributes.Color = myDynamicRenderer.DrawingAttributes.Color;
                stroke.DrawingAttributes.Width = myDynamicRenderer.DrawingAttributes.Width;
            }
        }
        private void HandleStylusDownHelper(object sender, int stylusId, int strokeId, int[] packets, TabletPropertyDescriptionCollection tabletProperties)
        {
            this.FlushPackets(stylusId, strokeId);

            if (ViewerStateModel.NonStandardDpi)
            {
                RealTimeInkSheetModel.ScalePackets(packets, ViewerStateModel.DpiNormalizationSendMatrix);
            }

            Message message = new RealTimeInkSheetStylusDownMessage(this.m_Sheet, stylusId, strokeId, packets, tabletProperties);

            message.Tags                = new MessageTags();
            message.Tags.SlideID        = m_SlideID;
            message.Tags.Priority       = MessagePriority.RealTime;
            message.Tags.BridgePriority = MessagePriority.RealTime;
            this.Sender.Send(message, MessagePriority.RealTime);
        }
 private void HandleStylusDown(object sender, int stylusId, int strokeId, int[] packets, TabletPropertyDescriptionCollection tabletProperties)
 {
     this.StylusDown(stylusId, strokeId, packets, tabletProperties);
 }
        private void LoadInkIntoTarget(InkSheetModel sheet, byte[] saved, out int[] ids)
        {
            Ink restored = new Ink();
            restored.Load(saved);

            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(StrokeIdExtendedProperty)) {
                        object id = stroke.ExtendedProperties[StrokeIdExtendedProperty].Data;
                        foreach(Stroke existing in sheet.Ink.Strokes) {
                            if(existing.ExtendedProperties.DoesPropertyExist(StrokeIdExtendedProperty)) {
                                if(id.Equals(existing.ExtendedProperties[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;

                    if (ViewerStateModel.NonStandardDpi)
                        created.Transform(ViewerStateModel.DpiNormalizationReceiveMatrix);

                }
            }
        }
        public void OnStylusDown(int stylusId, int strokeId, int[] packets, TabletPropertyDescriptionCollection tabletProperties)
        {
            StylusDownEventHandler handler;
            using(Synchronizer.Lock(this)) {
                handler = (this.m_DrawingAttributes != null) ? this.m_StylusDownDelegate : null;
            }

            if(handler != null)
                handler(this, stylusId, strokeId, packets, tabletProperties);
        }
        private void HandleStylusDownHelper(object sender, int stylusId, int strokeId, int[] packets, TabletPropertyDescriptionCollection tabletProperties)
        {
            this.FlushPackets(stylusId, strokeId);

            Message message = new RealTimeInkSheetStylusDownMessage(this.m_Sheet, stylusId, strokeId, packets, tabletProperties);

            message.Tags                = new MessageTags();
            message.Tags.SlideID        = this.m_SlideID;
            message.Tags.Priority       = MessagePriority.RealTime;
            message.Tags.BridgePriority = MessagePriority.RealTime;
            this.Sender.Send(message, MessagePriority.RealTime);
        }
Example #18
0
 private void HandleStylusDown(object sender, int stylusId, int strokeId, int[] packets, TabletPropertyDescriptionCollection tabletProperties)
 {
     this.StylusDown(stylusId, strokeId, packets, tabletProperties);
 }
        private void HandleStylusDownHelper(object sender, int stylusId, int strokeId, int[] packets, TabletPropertyDescriptionCollection tabletProperties)
        {
            this.FlushPackets(stylusId, strokeId);

            if (ViewerStateModel.NonStandardDpi) {
                RealTimeInkSheetModel.ScalePackets(packets, ViewerStateModel.DpiNormalizationSendMatrix);
            }

            Message message = new RealTimeInkSheetStylusDownMessage(this.m_Sheet, stylusId, strokeId, packets, tabletProperties);
            message.Tags = new MessageTags();
            message.Tags.SlideID = m_SlideID;
            message.Tags.Priority = MessagePriority.RealTime;
            message.Tags.BridgePriority = MessagePriority.RealTime;
            this.Sender.Send(message, MessagePriority.RealTime);
        }
 public RealTimeInkSheetStylusDownMessage(RealTimeInkSheetModel sheet, int stylusId, int strokeId, int[] packets, TabletPropertyDescriptionCollection tabletProperties)
     : base(sheet, stylusId, strokeId, packets)
 {
     this.TabletProperties = new TabletPropertyDescriptionCollectionInformation(tabletProperties);
 }
Example #21
0
 /// <summary>
 /// Helper function to marshal stylus down events
 /// </summary>
 /// <param name="sender">The object that sent the message</param>
 /// <param name="stylusId">The id of the stylus that was pressed down</param>
 /// <param name="packets">The packets sent by the stylus</param>
 /// <param name="tabletProperties">The properties of the tablet</param>
 private void HandleStylusDownHelper(object sender, int stylusId, int strokeId, int[] packets, TabletPropertyDescriptionCollection tabletProperties)
 {
     if (this.m_DestSheet != null)
     {
         this.m_DestSheet.OnStylusDown(stylusId, strokeId, packets, tabletProperties);
     }
 }
            public TabletPropertyDescriptionCollectionInformation(TabletPropertyDescriptionCollection tp)
            {
                this.InkToDeviceScaleX = tp.InkToDeviceScaleX;
                this.InkToDeviceScaleY = tp.InkToDeviceScaleY;

                this.TabletPropertyDescriptions = new ArrayList(tp.Count);
                foreach(TabletPropertyDescription d in tp)
                    this.TabletPropertyDescriptions.Add(new TabletPropertyDescriptionInformation(d));
            }
            private void AddInk()
            {
                using(Synchronizer.Lock(this)) {
                    // Create an array of stroke Ids in order to fire the InkAdded event later.
                    int[] ids = new int[this.m_StrokesToAdd.Count];

                    using (Synchronizer.Lock(this.m_Watcher.m_InkSheet.Ink.Strokes.SyncRoot)) {
                        for (int i = 0; i < ids.Length; i++) {
                            Stroke stroke = this.m_StrokesToAdd[i];

                            // The stroke probably 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 = this.m_Watcher.m_InkSheet.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);

                            // Get the new stroke's Id so we can fire the InkAdded event.
                            ids[i] = created.Id;
                        }

                        // If the added strokes don't yet have StrokeIdExtendedProperty properties,
                        // create new Guids for them.  Regardless, set this.m_StrokesToRemove
                        // to the list of stroke Guids.
                        this.UpdateAndSetStrokesToRemoveIds(this.m_StrokesToAdd);

                        // Then, unset this.m_StrokesToAdd since they're already added.
                        this.m_StrokesToAdd = null;
                    }

                    // Create the event arguments and add them to the ignore list so the
                    // InkSheetUndoService won't create an InkUndoer for this change.
                    StrokesEventArgs args = new StrokesEventArgs(ids);
                    using(Synchronizer.Lock(this.m_Watcher.m_Ignore.SyncRoot)) {
                        this.m_Watcher.m_Ignore.Add(args);
                    }

                    // Finally fire the appropriate InkAdded event from the InkSheetModel.
                    this.m_Watcher.m_InkSheet.OnInkAdded(args);
                }
            }
 /// <summary>
 /// Helper function to marshal stylus down events
 /// </summary>
 /// <param name="sender">The object that sent the message</param>
 /// <param name="stylusId">The id of the stylus that was pressed down</param>
 /// <param name="packets">The packets sent by the stylus</param>
 /// <param name="tabletProperties">The properties of the tablet</param>
 private void HandleStylusDownHelper(object sender, int stylusId, int strokeId, int[] packets, TabletPropertyDescriptionCollection tabletProperties)
 {
     if (this.m_DestSheet != null)
         this.m_DestSheet.OnStylusDown(stylusId, strokeId, packets, tabletProperties);
 }
 private void HandleStylusDown(object sender, int stylusId, int strokeId, int[] packets, TabletPropertyDescriptionCollection tabletProperties)
 {
     this.Sender.Post(delegate() {
         this.HandleStylusDownHelper(sender, stylusId, strokeId, packets, tabletProperties);
     });
 }
Example #26
0
        // Copied from the RealTimeStylus InkCollection example from
        // the Microsoft Tablet PC API Sample Applications collection.

        /// <summary>
        /// Occurs when the stylus touches the digitizer surface.
        /// Allocate a new array to store the packet data for this stylus.
        /// </summary>
        /// <param name="sender">The real time stylus associated with the notification</param>
        /// <param name="data">The notification data</param>
        void IStylusAsyncPlugin.StylusDown(RealTimeStylus sender, StylusDownData data)
        {
            // An inverted stylus is reserved for the eraser.
            if (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;
                }
            }

            int stylusId = data.Stylus.Id;


            // Allocate an empty array to store the packet data that will be
            // collected for this stylus.
            List <int> collectedPackets = new List <int>();

            // Add the packet data from StylusDown to the array
            collectedPackets.AddRange(data.GetData());

            // Insert the array into a hashtable using the stylus id as a key.
            this.m_PacketsTable[stylusId] = collectedPackets;

            // Also store the current DrawingAttributes.  This is necessary because the default
            // DynamicRenderer (which will be used in conjunction with the ink stored by this collector)
            // only updates its DrawingAttributes on StylusDown.
            this.m_DrawingAttributesTable[stylusId] = this.m_DrawingAttributes;

            // Increment the current stroke id.
            int strokeId;

            if (!this.m_StrokeIdTable.TryGetValue(stylusId, out strokeId))
            {
                this.m_StrokeIdTable[stylusId] = (strokeId = 0);
            }
            else
            {
                this.m_StrokeIdTable[stylusId] = ++strokeId;
            }

            // And send the packets to anybody who's listening to the RealTimeInk.
            using (Synchronizer.Lock(this)) {
                if (this.RealTimeInkSheetModel != null)
                {
                    TabletPropertyDescriptionCollection tabletProperties =
                        sender.GetTabletPropertyDescriptionCollection(data.Stylus.TabletContextId);
                    this.RealTimeInkSheetModel.OnStylusDown(stylusId, strokeId, data.GetData(), tabletProperties);
                }
            }
        }
 private void HandleStylusDown(object sender, int stylusId, int strokeId, int[] packets, TabletPropertyDescriptionCollection tabletProperties)
 {
     this.Sender.Post(delegate() {
         this.HandleStylusDownHelper(sender, stylusId, strokeId, packets, tabletProperties);
     });
 }
Example #28
0
            /// <summary>
            /// Used by <see cref="Packets"/> and <see cref="StylusUp"/> to render ink.
            /// </summary>
            private void RenderIncomingPackets(int stylusId, int strokeId, int[] packets)
            {
                using (Synchronizer.Lock(this.m_SlideDisplay.SyncRoot)) {
                    if (!this.Enabled)
                    {
                        return;
                    }

                    //Allow rendering packets on disposed TransformableDynamicRenderer.
                    //if (this.m_Disposed) {
                    //    Debug.WriteLine("Warning: Ignoring request to RenderIncomingPackets on disposed TransformableDynamicRenderer.");
                    //    return;
                    //}
                    // Verify that the stroke we're about to render matches the StrokeId
                    // from the most recent StylusDown event.  (If not, then something
                    // probably got lost over the network.)
                    int currentStrokeId;
                    if (!this.m_CurrentStrokeIdTable.TryGetValue(stylusId, out currentStrokeId) || currentStrokeId != strokeId)
                    {
                        // First cancel the previous stroke to avoid
                        // drawing a bogus connecting line between the endpoints.
                        this.CancelStroke(stylusId);
                        // Then attempt to start a new stroke.  Since we didn't get the
                        // StylusDown event, we'll have to re-use the old TabletPropertyDescriptionCollection.
                        // (Theoretically this might have changed between strokes, but that's unlikely.)
                        // But if there was no previous stroke, and therefore no TabletPropertyDescriptionCollection
                        // we can use to render the packets, we'll have to give up.
                        TabletPropertyDescriptionCollection props;
                        if (!this.m_TabletPropertiesTable.TryGetValue(stylusId, out props))
                        {
                            return; // Give up!
                        }
                        this.StylusDown(stylusId, strokeId, new int[] { }, props);
                    }

                    // At this point we're guaranteed to have executed a (real or simulated)
                    // StylusDown event, so the entries in all the other dictionaries must exist.

                    // Get the DrawingAttributes which were in effect on StylusDown.
                    DrawingAttributes atts = this.m_DrawingAttributesTable[stylusId];

                    // Discard the stroke if we have no DrawingAttributes.
                    if (atts == null)
                    {
                        return;
                    }

                    // Get the tablet description which the renderer will use to interpret the data.
                    TabletPropertyDescriptionCollection tabletProperties = this.m_TabletPropertiesTable[stylusId];
                    Debug.Assert(tabletProperties != null);

                    // Retrieve the packet array from the hashtable using the cursor id as a key.
                    int[] previousData = this.m_PacketsTable[stylusId];
                    Debug.Assert(previousData != null);

                    // Store the new data so that the next rendering job will only have to "connect the dots".
                    this.m_PacketsTable[stylusId] = packets;

                    // Also add the packets to the collected packets list.
                    List <int> collected = this.m_CollectedPacketsTable[stylusId];
                    collected.AddRange(packets);

                    //Calculate the distance between the last point of previous stroke, and first point of current stroke.
                    //If the distance is smaller than distanceThreshold, then draw both previous and current strokes.
                    bool   combinedMode        = true;
                    double distanceThreshold   = 2500;
                    Stroke previousStroke      = this.Ink.CreateStroke(previousData, tabletProperties);
                    Stroke currentStroke       = this.Ink.CreateStroke(packets, tabletProperties);
                    Point  lastPointInPrevious = previousStroke.GetPoint(previousStroke.GetPoints().Length - 1);
                    Point  firstPointInCurrent = currentStroke.GetPoint(0);
                    int    x = lastPointInPrevious.X - firstPointInCurrent.X;
                    int    y = lastPointInPrevious.Y - firstPointInCurrent.Y;
                    if (Math.Sqrt(x * x + y * y) > distanceThreshold)
                    {
                        combinedMode = false;
                    }

                    // Assemble the completed information we'll need to create the mini-stroke.
                    int[] combinedPackets = new int[previousData.Length + packets.Length];
                    previousData.CopyTo(combinedPackets, 0);
                    packets.CopyTo(combinedPackets, previousData.Length);

                    // Now that we have the data, we're ready to create the temporary stroke
                    // which we will immediately render.
                    Stroke stroke = null;
                    if (combinedMode)
                    {
                        stroke = this.Ink.CreateStroke(combinedPackets, tabletProperties);
                    }
                    else
                    {
                        stroke = this.Ink.CreateStroke(packets, tabletProperties);
                    }
                    stroke.DrawingAttributes = atts;

                    // Render the stroke onto the canvas.
                    using (Graphics graphics = this.m_SlideDisplay.CreateGraphics()) {
                        IntPtr hdc = graphics.GetHdc();
                        try {
                            int saved = SaveDC(hdc);
                            try {
                                // Copy the clip region from the slide viewer to the DC.
                                Rectangle bounds = this.m_SlideDisplay.Bounds;
                                IntersectClipRect(hdc, bounds.Left, bounds.Top, bounds.Right, bounds.Bottom);
                                // Draw the ink!
                                this.m_Renderer.Draw(hdc, stroke);
                            } catch (COMException) {
                                //0x80004005.  Observed this happening when the public node was in a minimized window
                                //of a remote desktop connection.  Ignoring the exception fixes the issue.
                            } finally {
                                RestoreDC(hdc, saved);
                            }
                        } finally {
                            graphics.ReleaseHdc();
                        }
                    }

                    // Immediately delete the stroke, since there's no easy way to save it and modify it for the next data.
                    this.Ink.DeleteStroke(stroke);
                }
            }
Example #29
0
 public RealTimeInkSheetStylusDownMessage(RealTimeInkSheetModel sheet, int stylusId, int strokeId, int[] packets, TabletPropertyDescriptionCollection tabletProperties) : base(sheet, stylusId, strokeId, packets)
 {
     this.TabletProperties = new TabletPropertyDescriptionCollectionInformation(tabletProperties);
 }
            /// <summary>
            /// Notifies the <see cref="Core"/> of the start of a new stroke.
            /// </summary>
            /// <remarks>
            /// Note that some properties of the <see cref="Core"/> take effect only after a <see cref="StylusDown"/> event.
            /// </remarks>
            /// <param name="stylusId">The stylus which is being used to draw the stroke.</param>
            /// <param name="packets">The packet data describing the stroke.</param>
            /// <param name="tabletProperties">
            /// The <see cref="TabletPropertyDescriptionCollection"/>
            /// used to interpret the packet data, and also subsequent packet data from <see cref="Packets"/> and
            /// <see cref="StylusUp"/> events which have the same <paramref name="stylusId"/>.
            /// </param>
            public void StylusDown(int stylusId, int strokeId, int[] packets, TabletPropertyDescriptionCollection tabletProperties)
            {
                using(Synchronizer.Lock(this.m_SlideDisplay.SyncRoot)) {
                    if(!this.Enabled) return;

                    // Insert the data into a hashtable using the stylus id as a key.
                    this.m_PacketsTable[stylusId] = packets;

                    // Also store the current DrawingAttributes.  This is necessary to emulate the default
                    // DynamicRenderer which only updates its DrawingAttributes on StylusDown.
                    this.m_DrawingAttributesTable[stylusId] = this.DrawingAttributes;

                    // Store the packets in the collected packets list so we can retrieve them on Refresh().
                    List<int> collected = new List<int>(packets);
                    this.m_CollectedPacketsTable[stylusId] = collected;

                    // Store the strokeId so RenderIncomingPackets will know when to cancel an incomplete
                    // stroke if a StylusUp event is missed.
                    this.m_CurrentStrokeIdTable[stylusId] = strokeId;

                    // Finally store the tablet properties, which will be used to interpret the packets when rendering a stroke.
                    this.m_TabletPropertiesTable[stylusId] = tabletProperties;
                }
            }
        private void HandleStylusDownHelper(object sender, int stylusId, int strokeId, int[] packets, TabletPropertyDescriptionCollection tabletProperties)
        {
            this.FlushPackets(stylusId, strokeId);

            Message message = new RealTimeInkSheetStylusDownMessage(this.m_Sheet, stylusId, strokeId, packets, tabletProperties);
            message.Tags = new MessageTags();
            message.Tags.SlideID = this.m_SlideID;
            message.Tags.Priority = MessagePriority.RealTime;
            message.Tags.BridgePriority = MessagePriority.RealTime;
            this.Sender.Send(message, MessagePriority.RealTime);
        }
 public TabletPropertyDescriptionCollection CreateTabletPropertyDescriptionCollection()
 {
     TabletPropertyDescriptionCollection tp = new TabletPropertyDescriptionCollection(this.InkToDeviceScaleX, this.InkToDeviceScaleY);
     foreach(TabletPropertyDescriptionInformation info in this.TabletPropertyDescriptions)
         tp.Add(info.CreateTabletPropertyDescription());
     return tp;
 }