diff --git a/src/apps/haiku-depot/Jamfile b/src/apps/haiku-depot/Jamfile index 36814395de..7788c34840 100644 --- a/src/apps/haiku-depot/Jamfile +++ b/src/apps/haiku-depot/Jamfile @@ -17,6 +17,7 @@ local textDocumentSources = BulletData.cpp CharacterStyle.cpp CharacterStyleData.cpp + MarkupParser.cpp Paragraph.cpp ParagraphLayout.cpp ParagraphStyle.cpp diff --git a/src/apps/haiku-depot/textview/MarkupParser.cpp b/src/apps/haiku-depot/textview/MarkupParser.cpp new file mode 100644 index 0000000000..fbbd333d07 --- /dev/null +++ b/src/apps/haiku-depot/textview/MarkupParser.cpp @@ -0,0 +1,233 @@ +/* + * Copyright 2013, Stephan Aßmus . + * All rights reserved. Distributed under the terms of the MIT License. + */ + +#include "MarkupParser.h" + +#include + +#include + +#include + + +MarkupParser::MarkupParser() + : + fNormalStyle(), + fBoldStyle(), + fItalicStyle(), + fBoldItalicStyle(), + fHeadingStyle(), + + fParagraphStyle(), + fHeadingParagraphStyle(), + fBulletStyle(), + + fCurrentCharacterStyle(&fNormalStyle), + fCurrentParagraphStyle(&fParagraphStyle) +{ + _InitStyles(); +} + + +MarkupParser::MarkupParser(const CharacterStyle& characterStyle, + const ParagraphStyle& paragraphStyle) + : + fNormalStyle(characterStyle), + fBoldStyle(), + fItalicStyle(), + fBoldItalicStyle(), + fHeadingStyle(), + + fParagraphStyle(paragraphStyle), + fHeadingParagraphStyle(), + fBulletStyle(), + + fCurrentCharacterStyle(&fNormalStyle), + fCurrentParagraphStyle(&fParagraphStyle) +{ + _InitStyles(); +} + + +TextDocumentRef +MarkupParser::CreateDocumentFromMarkup(const BString& text) +{ + fTextDocument.SetTo(new(std::nothrow) TextDocument(), true); + if (fTextDocument.Get() == NULL) + return fTextDocument; + + fCurrentCharacterStyle = &fNormalStyle; + fCurrentParagraphStyle = &fParagraphStyle; + + fCurrentParagraph = Paragraph(*fCurrentParagraphStyle); + fSpanStartOffset = 0; + + _ParseText(text); + + return fTextDocument; +} + + +// #pragma mark - private + + +void +MarkupParser::_InitStyles() +{ + fBoldStyle = fNormalStyle; + fBoldStyle.SetBold(true); + + fItalicStyle = fNormalStyle; + fItalicStyle.SetItalic(true); + + fBoldItalicStyle = fNormalStyle; + fBoldItalicStyle.SetBold(true); + fBoldItalicStyle.SetItalic(true); + + float fontSize = fNormalStyle.Font().Size(); + + fHeadingStyle = fNormalStyle; + fHeadingStyle.SetFontSize(ceilf(fontSize * 1.15f)); + fHeadingStyle.SetBold(true); + + fHeadingParagraphStyle = fParagraphStyle; + fHeadingParagraphStyle.SetSpacingTop(ceilf(fontSize * 0.8f)); + fHeadingParagraphStyle.SetSpacingBottom(ceilf(fontSize * 0.5f)); + fHeadingParagraphStyle.SetJustify(false); + + fBulletStyle = fParagraphStyle; + fBulletStyle.SetBullet(Bullet("•", fontSize)); + fBulletStyle.SetLineInset(ceilf(fontSize * 0.8f)); +} + + +void +MarkupParser::_ParseText(const BString& text) +{ + int32 start = 0; + int32 offset = 0; + + int32 charCount = text.CountChars(); + const char* c = text.String(); + + while (offset < charCount) { + uint32 nextChar = UTF8ToCharCode(&c); + + switch (nextChar) { + case '\n': + case '\0': + _CopySpan(text, start, offset - 1); + _FinishParagraph(); + start = offset + 1; + break; + + case '\'': + if (offset + 2 < charCount && c[0] == '\'') { + int32 tickCount = 2; + if (c[1] == '\'') + tickCount = 3; + + // Copy previous span using current style, excluding the + // ticks. + _CopySpan(text, start, offset); + + if (tickCount == 2) + _ToggleStyle(fItalicStyle); + else if (tickCount == 3) + _ToggleStyle(fBoldStyle); + + // Don't include the ticks in the next span. + offset += tickCount - 1; + start = offset + 1; + c += tickCount - 1; + } + break; + + case '=': + // Detect headings + if (offset == start + && fCurrentParagraph.IsEmpty() + && offset + 2 < charCount + && c[0] == '=' && c[1] == ' ') { + + fCurrentParagraph.SetStyle(fHeadingParagraphStyle); + fCurrentCharacterStyle = &fHeadingStyle; + + offset += 2; + c += 2; + + start = offset + 1; + } else if (offset > start + && offset + 2 < charCount + && c[0] == '=' && c[1] == '\n') { + + _CopySpan(text, start, offset - 1); + _FinishParagraph(); + + offset += 2; + c += 2; + + start = offset + 1; + } + break; + + case ' ': + // Detect bullets at line starts + if (offset == start + && fCurrentParagraph.IsEmpty() + && offset + 2 < charCount + && c[0] == '*' && c[1] == ' ') { + + fCurrentParagraph.SetStyle(fBulletStyle); + + offset += 2; + c += 2; + + start = offset + 1; + } + break; + + default: + break; + + } + offset++; + } +} + + +void +MarkupParser::_CopySpan(const BString& text, int32& start, int32 end) +{ + if (start >= end) + return; + + BString subString; + text.CopyCharsInto(subString, start, end - start); + fCurrentParagraph.Append(TextSpan(subString, + *fCurrentCharacterStyle)); + + start = end; +} + + +void +MarkupParser::_ToggleStyle(const CharacterStyle& style) +{ + if (fCurrentCharacterStyle == &style) + fCurrentCharacterStyle = &fNormalStyle; + else + fCurrentCharacterStyle = &style; +} + + +void +MarkupParser::_FinishParagraph() +{ + fTextDocument->Append(fCurrentParagraph); + fCurrentParagraph.Clear(); + fCurrentParagraph.SetStyle(fParagraphStyle); + fCurrentCharacterStyle = &fNormalStyle; +} diff --git a/src/apps/haiku-depot/textview/MarkupParser.h b/src/apps/haiku-depot/textview/MarkupParser.h new file mode 100644 index 0000000000..2462be50c4 --- /dev/null +++ b/src/apps/haiku-depot/textview/MarkupParser.h @@ -0,0 +1,50 @@ +/* + * Copyright 2013, Stephan Aßmus . + * All rights reserved. Distributed under the terms of the MIT License. + */ +#ifndef MARKUP_PARSER_H +#define MARKUP_PARSER_H + +#include "TextDocument.h" + + +class MarkupParser { +public: + MarkupParser(); + MarkupParser( + const CharacterStyle& characterStyle, + const ParagraphStyle& paragraphStyle); + + TextDocumentRef CreateDocumentFromMarkup(const BString& text); + +private: + void _InitStyles(); + + void _ParseText(const BString& text); + void _CopySpan(const BString& text, + int32& start, int32 end); + void _ToggleStyle(const CharacterStyle& style); + void _FinishParagraph(); + +private: + CharacterStyle fNormalStyle; + CharacterStyle fBoldStyle; + CharacterStyle fItalicStyle; + CharacterStyle fBoldItalicStyle; + CharacterStyle fHeadingStyle; + + ParagraphStyle fParagraphStyle; + ParagraphStyle fHeadingParagraphStyle; + ParagraphStyle fBulletStyle; + + const CharacterStyle* fCurrentCharacterStyle; + const ParagraphStyle* fCurrentParagraphStyle; + + // while parsing: + TextDocumentRef fTextDocument; + Paragraph fCurrentParagraph; + int32 fSpanStartOffset; +}; + + +#endif // MARKUP_PARSER_H diff --git a/src/apps/haiku-depot/textview/TextDocumentTest.cpp b/src/apps/haiku-depot/textview/TextDocumentTest.cpp index dcdd9b0e65..576a270047 100644 --- a/src/apps/haiku-depot/textview/TextDocumentTest.cpp +++ b/src/apps/haiku-depot/textview/TextDocumentTest.cpp @@ -5,11 +5,13 @@ #include "TextDocumentTest.h" +#include #include #include #include +#include "MarkupParser.h" #include "TextDocumentView.h" TextDocumentTest::TextDocumentTest() @@ -38,64 +40,80 @@ TextDocumentTest::ReadyToRun() .Add(documentView) ; - ParagraphStyle paragraphStyle; - paragraphStyle.SetJustify(true); - CharacterStyle regularStyle; - CharacterStyle boldStyle(regularStyle); - boldStyle.SetBold(true); - - CharacterStyle italicStyle(regularStyle); - italicStyle.SetItalic(true); - - CharacterStyle italicAndBoldStyle(boldStyle); - italicAndBoldStyle.SetItalic(true); + float fontSize = regularStyle.Font().Size(); - CharacterStyle bigStyle(regularStyle); - bigStyle.SetFontSize(24); - bigStyle.SetForegroundColor(255, 50, 50); - - TextDocumentRef document(new TextDocument(), true); - - Paragraph paragraph(paragraphStyle); - paragraph.Append(TextSpan("This is a", regularStyle)); - paragraph.Append(TextSpan(" test ", bigStyle)); - paragraph.Append(TextSpan("to see if ", regularStyle)); - paragraph.Append(TextSpan("different", boldStyle)); - paragraph.Append(TextSpan(" character styles already work.", regularStyle)); - document->Append(paragraph); - - paragraphStyle.SetSpacingTop(8.0f); - paragraphStyle.SetAlignment(ALIGN_CENTER); - paragraphStyle.SetJustify(false); - - paragraph = Paragraph(paragraphStyle); - paragraph.Append(TextSpan("Different alignment styles ", regularStyle)); - paragraph.Append(TextSpan("are", boldStyle)); - paragraph.Append(TextSpan(" supported as of now!", regularStyle)); - document->Append(paragraph); - - // Test a bullet list - paragraphStyle.SetSpacingTop(8.0f); - paragraphStyle.SetAlignment(ALIGN_LEFT); + ParagraphStyle paragraphStyle; paragraphStyle.SetJustify(true); - paragraphStyle.SetBullet(Bullet("•", 12.0f)); - paragraphStyle.SetLineInset(10.0f); - - paragraph = Paragraph(paragraphStyle); - paragraph.Append(TextSpan("Even bullet lists are supported.", regularStyle)); - document->Append(paragraph); - - paragraph = Paragraph(paragraphStyle); - paragraph.Append(TextSpan("The wrapping in ", regularStyle)); - paragraph.Append(TextSpan("this", italicStyle)); + paragraphStyle.SetSpacingTop(ceilf(fontSize * 0.6f)); + paragraphStyle.SetLineSpacing(ceilf(fontSize * 0.2f)); - paragraph.Append(TextSpan(" bullet item should look visually " - "pleasing. And ", regularStyle)); - paragraph.Append(TextSpan("why", italicAndBoldStyle)); - paragraph.Append(TextSpan(" should it not?", regularStyle)); - document->Append(paragraph); +// CharacterStyle boldStyle(regularStyle); +// boldStyle.SetBold(true); +// +// CharacterStyle italicStyle(regularStyle); +// italicStyle.SetItalic(true); +// +// CharacterStyle italicAndBoldStyle(boldStyle); +// italicAndBoldStyle.SetItalic(true); +// +// CharacterStyle bigStyle(regularStyle); +// bigStyle.SetFontSize(24); +// bigStyle.SetForegroundColor(255, 50, 50); +// +// TextDocumentRef document(new TextDocument(), true); +// +// Paragraph paragraph(paragraphStyle); +// paragraph.Append(TextSpan("This is a", regularStyle)); +// paragraph.Append(TextSpan(" test ", bigStyle)); +// paragraph.Append(TextSpan("to see if ", regularStyle)); +// paragraph.Append(TextSpan("different", boldStyle)); +// paragraph.Append(TextSpan(" character styles already work.", regularStyle)); +// document->Append(paragraph); +// +// paragraphStyle.SetSpacingTop(8.0f); +// paragraphStyle.SetAlignment(ALIGN_CENTER); +// paragraphStyle.SetJustify(false); +// +// paragraph = Paragraph(paragraphStyle); +// paragraph.Append(TextSpan("Different alignment styles ", regularStyle)); +// paragraph.Append(TextSpan("are", boldStyle)); +// paragraph.Append(TextSpan(" supported as of now!", regularStyle)); +// document->Append(paragraph); +// +// // Test a bullet list +// paragraphStyle.SetSpacingTop(8.0f); +// paragraphStyle.SetAlignment(ALIGN_LEFT); +// paragraphStyle.SetJustify(true); +// paragraphStyle.SetBullet(Bullet("•", 12.0f)); +// paragraphStyle.SetLineInset(10.0f); +// +// paragraph = Paragraph(paragraphStyle); +// paragraph.Append(TextSpan("Even bullet lists are supported.", regularStyle)); +// document->Append(paragraph); +// +// paragraph = Paragraph(paragraphStyle); +// paragraph.Append(TextSpan("The wrapping in ", regularStyle)); +// paragraph.Append(TextSpan("this", italicStyle)); +// +// paragraph.Append(TextSpan(" bullet item should look visually " +// "pleasing. And ", regularStyle)); +// paragraph.Append(TextSpan("why", italicAndBoldStyle)); +// paragraph.Append(TextSpan(" should it not?", regularStyle)); +// document->Append(paragraph); + + MarkupParser parser(regularStyle, paragraphStyle); + + TextDocumentRef document = parser.CreateDocumentFromMarkup( + "== Text document test ==\n" + "This is a test to see if '''different''' " + "character styles already work.\n" + "Different alignment styles '''are''' supported as of now!\n" + " * Even bullet lists are supported.\n" + " * The wrapping in ''this'' bullet item should look visually " + "pleasing. And ''why'' should it not?\n" + ); documentView->SetTextDocument(document);