namespace AIStudio.Tools.PowerPoint; /// /// One placeholder of a slide layout which the content of a slide goes into. /// /// What the slot is for. /// The number of the slot among the slots of the same role, starting at 1, in reading order. /// Where the slot sits, inherited from the slide master when the layout does not say. /// The placeholder type as the file spells it, e.g., "body" or "pic"; "obj" when the file states none. /// The placeholder index, which links a placeholder of a slide to the one of its layout. /// How much text fits; missing for pictures. internal sealed record TemplateSlot(PlaceholderRole Role, int Ordinal, SlotBounds Bounds, string PlaceholderType, uint? PlaceholderIndex, TextCapacity? Capacity) { /// /// The slot as the layout offers it, which a slot a slide moved or copied is measured against; /// null for a slot of the layout itself. /// public TemplateSlot? LayoutSlot { get; init; } /// /// The slot where a slide moved or resized its placeholder. /// /// /// The capacity grows and shrinks with the size, since the slide keeps the font. Insets stay as /// they are on a smaller slot, so the estimate runs a little high there; the check of the /// model's answer accepts a line more anyway. The capacity is always scaled from the slot of the /// layout, so that a slot moved twice, e.g., resized by its slide and then grown into room the /// slide frees, is not rounded down twice. /// /// Where the slide puts the placeholder. public TemplateSlot MovedTo(SlotBounds bounds) { var layoutSlot = this.LayoutSlot ?? this; return this with { Bounds = bounds, Capacity = layoutSlot.Capacity is { } capacity ? new TextCapacity( Math.Max(1, (int)(capacity.Lines * (double)bounds.Height / Math.Max(1, layoutSlot.Bounds.Height))), Math.Max(1, (int)(capacity.CharactersPerLine * (double)bounds.Width / Math.Max(1, layoutSlot.Bounds.Width)))) : null, LayoutSlot = layoutSlot, }; } }