public RenderSlide TypesetSlide(RenderSlide slide, TextRenderer r) { LiturgyLine line = this; // update state if not in wrapmode if (!r.LLState.SpeakerWrap) { r.LLState.LastSpeaker = line.Speaker; } else { line.Speaker = r.LLState.LastSpeaker; } // try to fit to current slide int lineheight = (int)Math.Ceiling(slide.gfx.MeasureString("CPALTgy", r.SpeakerFonts.TryGetVal(line.Speaker, r.Font)).Height); // check if whole line will fit SizeF s = slide.gfx.MeasureString(line.Text, r.SpeakerFonts.TryGetVal(line.Speaker, r.Font), r.TextboxRect.Width); if (slide.YOffset + s.Height <= r.TextboxRect.Height) { // it fits, add this line at position and compute RenderLine rl = new RenderLine() { Height = (int)s.Height, Width = (int)s.Width, ShowSpeaker = line.SubSplit == 0 || slide.Lines == 0, Speaker = line.Speaker, Text = line.Text, RenderX = 0, RenderY = 0, RenderLayoutMode = LayoutMode.Auto, LineNum = slide.Lines++, Font = r.SpeakerFonts.TryGetVal(line.Speaker, r.Font) }; slide.RenderLines.Add(rl); slide.YOffset += (int)s.Height; // wrap only works for one line r.LLState.SpeakerWrap = false; return(slide); } // if slide isn't blank, then try it on a blank slide if (!slide.Blank) { r.Slides.Add(r.FinalizeSlide(slide)); // wrap only works for one line r.LLState.SpeakerWrap = false; return(line.TypesetSlide(new RenderSlide() { Order = slide.Order + 1 }, r)); } // if doesn't fit on a blank slide // try to split into sentences. put as many sentences as fit on one slide until done // If have already split into sentences... split into chunks of words? if (line.IsSubsplit) { RenderSlide errorslide; if (!slide.Blank) { r.Slides.Add(r.FinalizeSlide(slide)); errorslide = new RenderSlide() { Order = slide.Order + 1 }; } else { errorslide = slide; } // for now abandon string emsg = "ERROR"; Size esize = slide.gfx.MeasureString(emsg, r.Font).ToSize(); RenderLine errorline = new RenderLine() { Height = esize.Height, Width = esize.Width, ShowSpeaker = r.LLState.SpeakerWrap, Speaker = Speaker.None, Text = emsg, RenderX = 0, RenderY = 0, RenderLayoutMode = LayoutMode.Auto, LineNum = 0, Font = r.Font, TextBrush = Brushes.Red }; errorslide.RenderLines.Add(errorline); r.Slides.Add(r.FinalizeSlide(errorslide)); // wrap only works for one line r.LLState.SpeakerWrap = false; return(new RenderSlide() { Order = errorslide.Order + 1 }); } // split line text into sentences var sentences = line.Text.Split(new string[] { "." }, StringSplitOptions.RemoveEmptyEntries); var tmp = Regex.Matches(line.Text, @"((?<sentence>[^\.;!?]+)(?<delimiter>[\.;!?])+)"); // keep trying to stuff a sentence List <LiturgyLine> sublines = new List <LiturgyLine>(); int splitnum = 0; foreach (var sentence in tmp) { // create a bunch of sub-liturgy-lines and try to typeset them all string t = sentence.ToString(); sublines.Add(new LiturgyLine() { Speaker = line.Speaker, Text = t.Trim(), SubSplit = splitnum++, IsSubsplit = true }); } foreach (var sl in sublines) { slide = sl.TypesetSlide(slide, r); } // wrap only works for one line r.LLState.SpeakerWrap = false; return(slide); }