/// <summary> /// Build (generate) title content /// </summary> /// <param name="shape">Title shape</param> /// <param name="frametitle">Frame title record</param> /// <param name="passNumber">Number of current pass</param> /// <param name="pauseCounter">Number of processed pause commands</param> /// <param name="paused">output - processing of title was paused</param> /// <returns>true if title is complete; false if needs another pass</returns> public bool BuildTitle(PowerPoint.Shape shape, FrametitleRecord frametitle, int passNumber, int pauseCounter, out bool paused) { _passNumber = passNumber; _pauseCounter = pauseCounter; _localPauseCounter = 0; // prepare shape shape.TextFrame2.TextRange.ParagraphFormat.SpaceWithin = 0.8f; shape.TextFrame2.AutoSize = MsoAutoSize.msoAutoSizeShapeToFitText; shape.TextFrame2.MarginBottom = 15.0f; // following values are theme dependent (in earlier version themes wasn't used) //shape.TextFrame2.TextRange.ParagraphFormat.Alignment = MsoParagraphAlignment.msoAlignLeft; //shape.TextFrame2.VerticalAnchor = MsoVerticalAnchor.msoAnchorTop; //shape.ScaleWidth(1.085f, MsoTriState.msoFalse, MsoScaleFrom.msoScaleFromMiddle); // setup overlays for title _maxPass = Math.Max(Misc.MaxOverlay(frametitle.TitleOverlaySet), _maxPass); _maxPass = Math.Max(Misc.MaxOverlay(frametitle.SubtitleOverlaySet), _maxPass); // generate title TextFormat textformat = new TextFormat(_baseFontSize, true); textformat.ModifyFormat(new Node("Large")); // in beamer title font size is same as \Large paused = !BuildTitlePart(shape, frametitle.Title, textformat); if (!paused && frametitle.Subtitle != null) { shape.TextFrame2.TextRange.InsertAfter("\r"); // generate subtitle textformat = new TextFormat(_baseFontSize); textformat.ModifyFormat(new Node("footnotesize")); // in beamer subtitle font size is same as \footnotesize paused = !BuildTitlePart(shape, frametitle.Subtitle, textformat); } return _passNumber >= _maxPass; }
/// <summary> /// Build slide content /// </summary> /// <param name="slide">Slide in PowerPoint presentation</param> /// <param name="slideNode">Node containing content of slide</param> /// <param name="passNumber">Number of current pass (used for overlays)</param> /// <param name="pauseCounter">Number of used pauses</param> /// <param name="paused">output - processing of slide content was paused</param> /// <returns>true if slide is complete; false if needs another pass</returns> public bool BuildSlide(PowerPoint.Slide slide, Node slideNode, int passNumber, int pauseCounter, out bool paused) { _slide = slide; _passNumber = passNumber; _pauseCounter = pauseCounter; // copy title settings _titlesettings = new Dictionary<string,List<Node>>(_preambuleSettings.TitlepageSettings); _format = new TextFormat(_baseFontSize); _postProcessing = new Queue<Node>(); if (!_called) { // because title is processed before slide and can contain pause command, we need to setup internal counters according to title passed at first processing _localPauseCounter = pauseCounter; _localPauseCounterStart = pauseCounter; _maxPass = passNumber; _called = true; } else { _localPauseCounter = _localPauseCounterStart; } _bottomShapeBorder = 0.0f; UpdateBottomShapeBorder(); paused = !ProcessSlideContent(slideNode); if (!Settings.Instance.NestedAsText) // extract nested elements { _localPauseCounter = int.MinValue; // ignore pauses in post processed shapes PostProcessing(); } return _passNumber >= _maxPass; }
/// <summary> /// Build (generate) title part. /// </summary> /// <param name="shape">Prepared title shape</param> /// <param name="content">Title content</param> /// <param name="format">Text format</param> /// <returns>true if completed; false if paused</returns> private bool BuildTitlePart(PowerPoint.Shape shape, List<Node> content, TextFormat format) { if (content.Count == 0) // ignore empty node return true; Stack<Node> nodes = new Stack<Node>(); // copy content to stack foreach (Node item in content.Reverse<Node>()) { nodes.Push(item); } Node currentNode; Node rollbackNode = new Node("__format_pop"); // process nodes on stack while (nodes.Count != 0) { currentNode = nodes.Pop(); // process node depending on its type switch (currentNode.Type) { case "bold": case "italic": case "underline": case "smallcaps": case "typewriter": case "color": case "tiny": case "scriptsize": case "footnotesize": case "small": case "normalsize": case "large": case "Large": case "LARGE": case "huge": case "Huge": // check overlay settings int min = currentNode.OverlayList.Count != 0 ? currentNode.OverlayList.Min() : int.MaxValue; _maxPass = Math.Max(Misc.MaxOverlay(currentNode.OverlayList), _maxPass); // set maximal number of passes from overlay specification if (currentNode.OverlayList.Count == 0 || currentNode.OverlayList.Contains(_passNumber) || min < 0 && Math.Abs(min) < _passNumber) { format.ModifyFormat(currentNode); nodes.Push(rollbackNode); } break; case "__format_pop": // special node -> pop formatting from stack format.RollBackFormat(); break; case "string": format.AppendText(shape, currentNode.Content as string); break; case "paragraph": format.AppendText(shape, "\r"); break; case "today": shape.TextFrame.TextRange.InsertDateTime(PowerPoint.PpDateTimeFormat.ppDateTimeFigureOut, MsoTriState.msoTrue); break; case "pause": _localPauseCounter++; if (_localPauseCounter > _pauseCounter) { if (_passNumber == _maxPass) // increase number of passes _maxPass++; return false; } break; default: // unknown node -> ignore break; } if (currentNode.Children == null) continue; // push child nodes to stack foreach (Node item in currentNode.Children.Reverse<Node>()) { nodes.Push(item); } } return true; }