private void HandleDeckStripChanged(object sender, EventArgs e) { Debug.Assert(!this.InvokeRequired); if (this.m_DeckStrip != null) this.m_DeckStrip.DockChanged -= new EventHandler(this.HandleDeckStripDockChanged); this.m_DeckStrip = (this.m_DeckTabPage != null) ? this.m_DeckTabPage.Parent as DeckStrip : null; if (this.m_DeckStrip != null) this.m_DeckStrip.DockChanged += new EventHandler(this.HandleDeckStripDockChanged); this.HandleDeckStripDockChanged(this, EventArgs.Empty); }
/// <summary> /// Creates a new <see cref="ViewerPresentationLayout"/> instance and instantiates all of the child controls. /// </summary> /// <param name="model">The model whose <see cref="WorkspaceModel.CurrentDeckTraversal"/> property will /// be used to display the current slide and deck.</param> public ViewerPresentationLayout(PresenterModel model) { this.Name = "ViewerPresentationLayout"; this.m_Model = model; this.m_EventQueue = new ControlEventQueue(this); m_Model.Workspace.CurrentDeckTraversal.ListenAndInitialize(m_EventQueue, new Property<DeckTraversalModel>.EventHandler(this.HandleTraversalChanged)); // Create the film strip, docked to the right side of the container. this.m_DeckStrip = new DeckStrip(this.m_Model); /// Filmstrip docking this.m_DeckStrip.Dock = DockStyle.Right; // Make the deck strip resizable with a LinkedSplitter. // The splitter automatically sets its dock to be the same as the FilmStrip. this.m_DeckStripSplitter = new LinkedSplitter(this.m_DeckStrip); // Create the MainSlideViewer, which occupies the remaining space in the container. this.m_MainSlideViewer = new MainSlideViewer(this.m_Model, true); this.m_MainSlideViewer.Dock = DockStyle.Fill; #region RealTimeStylus Initialization // Create a new RealTimeStylus, which will process ink drawn on the MainSlideViewer. this.m_RealTimeStylus = new RealTimeStylus(this.m_MainSlideViewer, true); // Make sure the TransformableDynamicRenderer and InkAnnotationCollector // find out whenever the current StylusModel changes. this.m_StylusInputSelector = new StylusInputSelector(this.m_Model, this.m_RealTimeStylus); this.m_RealTimeStylus.SyncPluginCollection.Add(this.m_StylusInputSelector); // Scale the ink to the inverse of the MainSlideViewer's transform. // This keeps the ink's coordinates correct when the MainSlideViewer's transform // is applied again later by the TransformableDynamicRenderer and InkAnnotationCollector. this.m_InkTransformFilter = new InkTransformFilter(this.m_MainSlideViewer.SlideDisplay); this.m_RealTimeStylus.SyncPluginCollection.Add(this.m_InkTransformFilter); // Create a *synchronous* TransformableDynamicRenderer, which will render ink received directly // from the RealTimeStylus on a high-priority thread. this.m_TransformableDynamicRenderer = new TransformableDynamicRendererLinkedToDisplay(this.m_MainSlideViewer, this.m_MainSlideViewer.SlideDisplay); this.m_TransformableDynamicRenderer.Enabled = true; this.m_RealTimeStylus.SyncPluginCollection.Add(this.m_TransformableDynamicRenderer); // Don't dynamically render ink on the main slide viewer twice. The MainSlideViewer's RealTimeInkSheetRenderer's // own TransformableDynamicRenderer would render the ink on a low-priority asynchronous thread, which is // fine for secondary slide viewers and the FilmStrip, but not fine for the MainSlideViewer. using (Synchronizer.Lock(this.m_MainSlideViewer.SlideDisplay.SyncRoot)) { this.m_MainSlideViewer.SlideDisplay.RenderLocalRealTimeInk = false; } // Create an InkAnnotationCollector and wrap it in an InkSheetAdapter, // which sends ink from the RealTimeStylus to the RealTimeInkSheetModel // of the MainSlideViewer's current slide. this.m_InkAnnotationCollector = new InkAnnotationCollector(); this.m_InkAnnotationCollector_InkSheetAdapter = new InkSheetAdapter(this.m_MainSlideViewer.SlideDisplay, this.m_InkAnnotationCollector); this.m_RealTimeStylus.AsyncPluginCollection.Add(this.m_InkAnnotationCollector); this.m_LassoPlugin = new LassoPlugin(this.m_MainSlideViewer, this.m_MainSlideViewer.SlideDisplay); this.m_LassoPlugin_InkSheetAdapter = new InkSheetAdapter(this.m_MainSlideViewer.SlideDisplay, this.m_LassoPlugin); this.m_RealTimeStylus.SyncPluginCollection.Add(this.m_LassoPlugin); this.m_EraserPlugin = new EraserPlugin(this.m_MainSlideViewer.SlideDisplay); this.m_EraserPlugin_InkSheetAdapter = new InkSheetAdapter(this.m_MainSlideViewer.SlideDisplay, this.m_EraserPlugin); this.m_RealTimeStylus.SyncPluginCollection.Add(this.m_EraserPlugin); // Now that all the plugins have been added, enable the RealTimeStylus. this.m_RealTimeStylus.Enabled = true; #endregion RealTimeStylus Initialization // Create a DeckTraversalModelAdapter, which causes the MainSlideViewer to always display the // current slide of the current deck of the PresenterModel's current DeckTraversalModel. this.m_WorkspaceModelAdapter = new WorkspaceModelAdapter(this.m_MainSlideViewer.SlideDisplay.EventQueue, this.m_MainSlideViewer, this.m_Model); // Create the Slide Preview control this.m_SlidePreview = new SlidePreview(this.m_Model, this.m_DeckStripSplitter); this.m_PreviewTraversalModelAdapter = new PreviewTraversalModelAdapter(this.m_SlidePreview.m_EventQueue, this.m_SlidePreview.m_PreviewSlideViewer, this.m_Model); // Create the Second Monitor Form, this displays the slide on the secondary display this.m_SecondMonitorForm = new SecondMonitorForm(this.m_Model); this.ParentChanged += new EventHandler(OnParentChanged); // Create the Role Synchronizer for the MainSlideViewer this.m_RoleSync = new RoleSynchronizer(this.m_MainSlideViewer, this.m_Model.Participant); #region Add Controls // Add the SlidePreview Control this.Controls.Add(this.m_SlidePreview); // Now, add the controls in reverse order of their docking priority. // The MainSlideViewer gets added first so its Fill dock-style will be effective. this.Controls.Add(this.m_MainSlideViewer); // Next, dock the FilmStripSplitter and the FilmStrip in reverse order, // so that the FilmStripSplitter will be farther away from the edge of the container. this.Controls.Add(this.m_DeckStripSplitter); this.Controls.Add(this.m_DeckStrip); #endregion Add Controls }
/// <summary> /// Creates a new <see cref="ViewerPresentationLayout"/> instance and instantiates all of the child controls. /// </summary> /// <param name="model">The model whose <see cref="WorkspaceModel.CurrentDeckTraversal"/> property will /// be used to display the current slide and deck.</param> public ViewerPresentationLayout(PresenterModel model) { this.Name = "ViewerPresentationLayout"; this.m_Model = model; this.m_EventQueue = new ControlEventQueue(this); m_Model.Workspace.CurrentDeckTraversal.ListenAndInitialize(m_EventQueue, new Property <DeckTraversalModel> .EventHandler(this.HandleTraversalChanged)); // Create the film strip, docked to the right side of the container. this.m_DeckStrip = new DeckStrip(this.m_Model); /// Filmstrip docking this.m_DeckStrip.Dock = DockStyle.Right; this.m_MainSlideViewer = new MainSlideViewer(this.m_Model, true); // Make the deck strip resizable with a LinkedSplitter. // The splitter automatically sets its dock to be the same as the FilmStrip and // keeps z-order correct with respect to the FilmStrip and the MainSlideViewer. this.m_DeckStripSplitter = new LinkedSplitter(this.m_DeckStrip, this.m_MainSlideViewer); // Create the MainSlideViewer, which occupies the remaining space in the container. this.m_MainSlideViewer.Dock = DockStyle.Fill; #region RealTimeStylus Initialization // Create a new RealTimeStylus, which will process ink drawn on the MainSlideViewer. this.m_RealTimeStylus = new RealTimeStylus(this.m_MainSlideViewer, true); try { // Enable touch input for the real time stylus this.m_RealTimeStylus.MultiTouchEnabled = true; this.m_TouchGestureHandler = new TouchGestureHandler(this.m_Model, this.m_EventQueue); this.m_RealTimeStylus.SyncPluginCollection.Add(this.m_TouchGestureHandler); } catch { } // Make sure the TransformableDynamicRenderer and InkAnnotationCollector // find out whenever the current StylusModel changes. this.m_StylusInputSelector = new StylusInputSelector(this.m_Model, this.m_RealTimeStylus); this.m_RealTimeStylus.SyncPluginCollection.Add(this.m_StylusInputSelector); // Scale the ink to the inverse of the MainSlideViewer's transform. // This keeps the ink's coordinates correct when the MainSlideViewer's transform // is applied again later by the TransformableDynamicRenderer and InkAnnotationCollector. this.m_InkTransformFilter = new InkTransformFilter(this.m_MainSlideViewer.SlideDisplay); this.m_RealTimeStylus.SyncPluginCollection.Add(this.m_InkTransformFilter); // Create a *synchronous* TransformableDynamicRenderer, which will render ink received directly // from the RealTimeStylus on a high-priority thread. this.m_TransformableDynamicRenderer = new TransformableDynamicRendererLinkedToDisplay(this.m_MainSlideViewer, this.m_MainSlideViewer.SlideDisplay); this.m_TransformableDynamicRenderer.Enabled = true; this.m_RealTimeStylus.SyncPluginCollection.Add(this.m_TransformableDynamicRenderer); // Don't dynamically render ink on the main slide viewer twice. The MainSlideViewer's RealTimeInkSheetRenderer's // own TransformableDynamicRenderer would render the ink on a low-priority asynchronous thread, which is // fine for secondary slide viewers and the FilmStrip, but not fine for the MainSlideViewer. using (Synchronizer.Lock(this.m_MainSlideViewer.SlideDisplay.SyncRoot)) { this.m_MainSlideViewer.SlideDisplay.RenderLocalRealTimeInk = false; } // Create an InkAnnotationCollector and wrap it in an InkSheetAdapter, // which sends ink from the RealTimeStylus to the RealTimeInkSheetModel // of the MainSlideViewer's current slide. this.m_InkAnnotationCollector = new InkAnnotationCollector(); this.m_InkAnnotationCollector_InkSheetAdapter = new InkSheetAdapter(this.m_MainSlideViewer.SlideDisplay, this.m_InkAnnotationCollector); this.m_RealTimeStylus.AsyncPluginCollection.Add(this.m_InkAnnotationCollector); this.m_LassoPlugin = new LassoPlugin(this.m_MainSlideViewer, this.m_MainSlideViewer.SlideDisplay); this.m_LassoPlugin_InkSheetAdapter = new InkSheetAdapter(this.m_MainSlideViewer.SlideDisplay, this.m_LassoPlugin); this.m_RealTimeStylus.SyncPluginCollection.Add(this.m_LassoPlugin); this.m_EraserPlugin = new EraserPlugin(this.m_MainSlideViewer.SlideDisplay); this.m_EraserPlugin_InkSheetAdapter = new InkSheetAdapter(this.m_MainSlideViewer.SlideDisplay, this.m_EraserPlugin); this.m_RealTimeStylus.SyncPluginCollection.Add(this.m_EraserPlugin); // Now that all the plugins have been added, enable the RealTimeStylus. this.m_RealTimeStylus.Enabled = true; #endregion RealTimeStylus Initialization // Create a DeckTraversalModelAdapter, which causes the MainSlideViewer to always display the // current slide of the current deck of the PresenterModel's current DeckTraversalModel. this.m_WorkspaceModelAdapter = new WorkspaceModelAdapter(this.m_MainSlideViewer.SlideDisplay.EventQueue, this.m_MainSlideViewer, this.m_Model); // Create the Slide Preview control this.m_SlidePreview = new SlidePreview(this.m_Model, this.m_DeckStripSplitter); this.m_PreviewTraversalModelAdapter = new PreviewTraversalModelAdapter(this.m_SlidePreview.m_EventQueue, this.m_SlidePreview.m_PreviewSlideViewer, this.m_Model); // Create the Second Monitor Form, this displays the slide on the secondary display this.m_SecondMonitorForm = new SecondMonitorForm(this.m_Model); this.ParentChanged += new EventHandler(OnParentChanged); // Create the Role Synchronizer for the MainSlideViewer this.m_RoleSync = new RoleSynchronizer(this.m_MainSlideViewer, this.m_Model.Participant); #region Add Controls // Add the SlidePreview Control this.Controls.Add(this.m_SlidePreview); // Now, add the controls in reverse order of their docking priority. // The MainSlideViewer gets added first so its Fill dock-style will be effective. this.Controls.Add(this.m_MainSlideViewer); // Next, dock the FilmStripSplitter and the FilmStrip in reverse order, // so that the FilmStripSplitter will be farther away from the edge of the container. this.Controls.Add(this.m_DeckStripSplitter); this.Controls.Add(this.m_DeckStrip); #endregion Add Controls }