r21584 by jghali - #14440, second part: fix text layout offset issue when attaching text to path <Fahad>
scribus-commit
scribus-commit at lists.scribus.net
Mon Dec 5 07:56:48 UTC 2016
Author: jghali
Date: Mon Dec 5 07:56:48 2016
New Revision: 21584
URL: http://scribus.net/websvn/listing.php?repname=Scribus&sc=1&rev=21584
Log:
#14440, second part: fix text layout offset issue when attaching text to path <Fahad>
Modified:
trunk/Scribus/scribus/text/boxes.h
trunk/Scribus/scribus/text/textlayout.cpp
Modified: trunk/Scribus/scribus/text/boxes.h
URL: http://scribus.net/websvn/diff.php?repname=Scribus&rev=21584&path=/trunk/Scribus/scribus/text/boxes.h
==============================================================================
--- trunk/Scribus/scribus/text/boxes.h (original)
+++ trunk/Scribus/scribus/text/boxes.h Mon Dec 5 07:56:48 2016
@@ -134,6 +134,9 @@
/// Get natural ascent and decent.
virtual double naturalAsc() const { return m_naturalAscent; }
virtual double naturalDecent() const { return m_naturalDecent; }
+
+ /// return box type
+ BoxType type() const { return m_type; }
//public slots:
// virtual void childChanged() { }
Modified: trunk/Scribus/scribus/text/textlayout.cpp
URL: http://scribus.net/websvn/diff.php?repname=Scribus&rev=21584&path=/trunk/Scribus/scribus/text/textlayout.cpp
==============================================================================
--- trunk/Scribus/scribus/text/textlayout.cpp (original)
+++ trunk/Scribus/scribus/text/textlayout.cpp Mon Dec 5 07:56:48 2016
@@ -1,332 +1,334 @@
-/*
- For general Scribus (>=1.3.2) copyright and licensing information please refer
- to the COPYING file provided with the program. Following this notice may exist
- a copyright and/or license notice that predates the release of Scribus 1.3.2
- for which a new license (GPL+exception) is in place.
- */
-/***************************************************************************
-* *
-* This program is free software; you can redistribute it and/or modify *
-* it under the terms of the GNU General Public License as published by *
-* the Free Software Foundation; either version 2 of the License, or *
-* (at your option) any later version. *
-* *
-***************************************************************************/
-
-#undef NDEBUG
-
-#include <cassert>
-#include "../styles/charstyle.h"
-#include "prefsstructs.h"
-#include "../styles/paragraphstyle.h"
-#include "specialchars.h"
-#include "storytext.h"
-#include "textlayout.h"
-#include "textlayoutpainter.h"
-#include "screenpainter.h"
-#include "boxes.h"
-#include "itextcontext.h"
-
-
-
-TextLayout::TextLayout(StoryText* text, ITextContext* frame)
-{
- m_story = text;
- m_frame = frame;
-
- m_validLayout = false;
- m_magicX = 0.0;
- m_lastMagicPos = -1;
-
- m_box = new GroupBox(Box::D_Horizontal);
-}
-
-TextLayout::~TextLayout()
-{
- delete m_box;
-}
-
-uint TextLayout::lines() const
-{
- uint count = 0;
- foreach (const Box *box, m_box->boxes())
- {
- count += box->boxes().count();
- }
- return count;
-}
-
-const LineBox* TextLayout::line(uint i) const
-{
- uint count = 0;
- foreach (const Box *box, m_box->boxes())
- {
- if (i < count + box->boxes().count())
- return dynamic_cast<const LineBox*>(box->boxes()[i - count]);
- count += box->boxes().count();
- }
- assert(false);
- return NULL;
-}
-
-const Box* TextLayout::box() const
-{
- return m_box;
-}
-
-Box* TextLayout::box()
-{
- return m_box;
-}
-
-void TextLayout::appendLine(LineBox* ls)
-{
- assert(ls);
- assert(ls->firstChar() >= 0);
- assert(ls->firstChar() < story()->length());
- assert(ls->lastChar() < story()->length());
- assert(!m_box->boxes().empty());
-
- GroupBox* column = dynamic_cast<GroupBox*>(m_box->boxes().last());
- assert(column);
-
- ls->setWidth(column->width());
- column->addBox(ls);
-}
-
-// Remove the last line from the list. Used when we need to backtrack on the layouting.
-void TextLayout::removeLastLine ()
-{
- QList<Box*>& boxes = m_box->boxes();
- if (boxes.isEmpty())
- return;
-
- GroupBox* column = dynamic_cast<GroupBox*>(boxes.last());
- assert(column);
-
- int lineCount = column->boxes().count();
- if (lineCount > 0)
- column->removeBox(lineCount - 1);
-}
-
-void TextLayout::render(ScreenPainter *p, ITextContext *ctx)
-{
- p->save();
- m_box->render(p, ctx);
- p->restore();
-}
-
-void TextLayout::renderBackground(TextLayoutPainter *p)
-{
- foreach (const Box* column, m_box->boxes())
- {
- const ParagraphStyle& style = m_story->paragraphStyle(column->firstChar());
- if (style.backgroundColor() != CommonStrings::None)
- {
- p->save();
- TextLayoutColor backColor(style.backgroundColor(), style.backgroundShade());
- p->setFillColor(backColor);
- p->setStrokeColor(backColor);
- p->drawRect(column->bbox());
- p->restore();
- }
- }
-}
-
-void TextLayout::render(TextLayoutPainter *p)
-{
- p->save();
- m_box->render(p);
- p->restore();
-}
-
-void TextLayout::addColumn(double colLeft, double colWidth)
-{
- GroupBox *newBox = new GroupBox(Box::D_Vertical);
- newBox->moveTo(colLeft, 0.0);
- newBox->setWidth(colWidth);
- newBox->setAscent(m_frame->height());
- m_box->addBox(newBox);
-
- // Update the box width and height, any better place to do this?
- m_box->setAscent(m_frame->height());
- m_box->setWidth(m_frame->width());
-}
-
-void TextLayout::clear()
-{
- delete m_box;
- m_box = new GroupBox(Box::D_Horizontal);
-}
-
-void TextLayout::setStory(StoryText *story)
-{
- m_story = story;
- clear();
-}
-
-int TextLayout::startOfLine(int pos) const
-{
- for (uint i=0; i < lines(); ++i) {
- const LineBox* ls = line(i);
- if (ls->firstChar() <= pos && pos <= ls->lastChar())
- return ls->firstChar();
- }
- return 0;
-}
-
-int TextLayout::endOfLine(int pos) const
-{
- for (uint i=0; i < lines(); ++i) {
- const LineBox* ls = line(i);
- if (ls->containsPos(pos))
- return story()->text(ls->lastChar()) == SpecialChars::PARSEP ? ls->lastChar() :
- story()->text(ls->lastChar()) == ' ' ? ls->lastChar() : ls->lastChar() + 1;
- }
- return story()->length();
-}
-
-int TextLayout::prevLine(int pos) const
-{
- bool isRTL = (m_story->paragraphStyle().direction() == ParagraphStyle::RTL);
- for (uint i=0; i < lines(); ++i)
- {
- // find line for pos
- const LineBox* ls = line(i);
- if (ls->containsPos(pos))
- {
- if (i == 0)
- return startOfLine(pos);
- // find current xpos
- qreal xpos = ls->positionToPoint(pos, *m_story).x1();
- if (pos != m_lastMagicPos || xpos > m_magicX)
- m_magicX = xpos;
-
- const LineBox* ls2 = line(i-1);
- // find new cpos
- for (int j = ls2->firstChar(); j <= ls2->lastChar(); ++j)
- {
- xpos = ls2->positionToPoint(j, *m_story).x1();
- if ((isRTL && xpos <= m_magicX) || (!isRTL && xpos >= m_magicX))
- {
- m_lastMagicPos = j;
- return j;
- }
- }
- m_lastMagicPos = ls2->lastChar();
- return ls2->lastChar();
- }
- }
- return m_box->firstChar();
-}
-
-int TextLayout::nextLine(int pos) const
-{
- bool isRTL = (m_story->paragraphStyle().direction() == ParagraphStyle::RTL);
- for (uint i=0; i < lines(); ++i)
- {
- // find line for pos
- const LineBox* ls = line(i);
- if (ls->containsPos(pos))
- {
- if (i+1 == lines())
- return endOfLine(pos);
- // find current xpos
- qreal xpos = ls->positionToPoint(pos, *m_story).x1();
-
- if (pos != m_lastMagicPos || xpos > m_magicX)
- m_magicX = xpos;
-
- const LineBox* ls2 = line(i+1);
- // find new cpos
- for (int j = ls2->firstChar(); j <= ls2->lastChar(); ++j)
- {
- xpos = ls2->positionToPoint(j, *m_story).x1();
- if ((isRTL && xpos <= m_magicX) || (!isRTL && xpos >= m_magicX))
- {
- m_lastMagicPos = j;
- return j;
- }
- }
- m_lastMagicPos = ls2->lastChar() + 1;
- return ls2->lastChar() + 1;
- }
- }
- return m_box->lastChar();
-}
-
-int TextLayout::startOfFrame() const
-{
- return m_box->firstChar();
-}
-
-int TextLayout::endOfFrame() const
-{
- return m_box->lastChar() + 1;
-}
-
-
-int TextLayout::pointToPosition(QPointF coord) const
-{
- int position = m_box->pointToPosition(coord, *m_story);
- return position;
-}
-
-
-QLineF TextLayout::positionToPoint(int pos) const
-{
- QLineF result;
- bool isRTL = (m_story->paragraphStyle().direction() == ParagraphStyle::RTL);
-
- result = m_box->positionToPoint(pos, *m_story);
- if (result.isNull())
- {
- qreal x, y1, y2;
- if (lines() > 0)
- {
- // TODO: move this branch to GroupBox::positionToPoint()
- // last glyph box in last line
- Box* column = m_box->boxes().last();
- Box* line = column->boxes().last();
- Box* glyph = line->boxes().empty()? NULL : line->boxes().last();
- QChar ch = story()->text(line->lastChar());
- if (ch == SpecialChars::PARSEP || ch == SpecialChars::LINEBREAK)
- {
- // last character is a newline, draw the cursor on the next line.
- if (isRTL)
- x = line->width();
- else
- x = 1;
- y1 = line->y() + line->height();
- y2 = y1 + line->height();
- }
- else
- {
- // draw the cursor at the end of last line.
- if (isRTL || glyph == NULL)
- x = line->x();
- else
- x = line->x() + glyph->x() + glyph->width();
- y1 = line->y();
- y2 = y1 + line->height();
- }
- result.setLine(x, y1, x, y2);
- result.translate(column->x(), column->y());
- }
- else
- {
- // rather the trailing style than a segfault.
- const ParagraphStyle& pstyle(story()->paragraphStyle(qMin(pos, story()->length())));
- if (isRTL)
- x = m_box->width();
- else
- x = 1;
- y1 = 0;
- y2 = pstyle.lineSpacing();
- result.setLine(x, y1, x, y2);
- }
- result.translate(m_box->x(), m_box->y());
- }
-
- return result;
-}
+/*
+ For general Scribus (>=1.3.2) copyright and licensing information please refer
+ to the COPYING file provided with the program. Following this notice may exist
+ a copyright and/or license notice that predates the release of Scribus 1.3.2
+ for which a new license (GPL+exception) is in place.
+ */
+/***************************************************************************
+* *
+* This program is free software; you can redistribute it and/or modify *
+* it under the terms of the GNU General Public License as published by *
+* the Free Software Foundation; either version 2 of the License, or *
+* (at your option) any later version. *
+* *
+***************************************************************************/
+
+#undef NDEBUG
+
+#include <cassert>
+#include "../styles/charstyle.h"
+#include "prefsstructs.h"
+#include "../styles/paragraphstyle.h"
+#include "specialchars.h"
+#include "storytext.h"
+#include "textlayout.h"
+#include "textlayoutpainter.h"
+#include "screenpainter.h"
+#include "boxes.h"
+#include "itextcontext.h"
+
+
+
+TextLayout::TextLayout(StoryText* text, ITextContext* frame)
+{
+ m_story = text;
+ m_frame = frame;
+
+ m_validLayout = false;
+ m_magicX = 0.0;
+ m_lastMagicPos = -1;
+
+ m_box = new GroupBox(Box::D_Horizontal);
+}
+
+TextLayout::~TextLayout()
+{
+ delete m_box;
+}
+
+uint TextLayout::lines() const
+{
+ uint count = 0;
+ foreach (const Box *box, m_box->boxes())
+ {
+ count += box->boxes().count();
+ }
+ return count;
+}
+
+const LineBox* TextLayout::line(uint i) const
+{
+ uint count = 0;
+ foreach (const Box *box, m_box->boxes())
+ {
+ if (i < count + box->boxes().count())
+ return dynamic_cast<const LineBox*>(box->boxes()[i - count]);
+ count += box->boxes().count();
+ }
+ assert(false);
+ return NULL;
+}
+
+const Box* TextLayout::box() const
+{
+ return m_box;
+}
+
+Box* TextLayout::box()
+{
+ return m_box;
+}
+
+void TextLayout::appendLine(LineBox* ls)
+{
+ assert(ls);
+ assert(ls->firstChar() >= 0);
+ assert(ls->firstChar() < story()->length());
+ assert(ls->lastChar() < story()->length());
+ assert(!m_box->boxes().empty());
+
+ GroupBox* column = dynamic_cast<GroupBox*>(m_box->boxes().last());
+ assert(column);
+ if (ls->type() == Box::T_PathLine)
+ ls->setAscent(ls->y() - column->naturalHeight());
+
+ ls->setWidth(column->width());
+ column->addBox(ls);
+}
+
+// Remove the last line from the list. Used when we need to backtrack on the layouting.
+void TextLayout::removeLastLine ()
+{
+ QList<Box*>& boxes = m_box->boxes();
+ if (boxes.isEmpty())
+ return;
+
+ GroupBox* column = dynamic_cast<GroupBox*>(boxes.last());
+ assert(column);
+
+ int lineCount = column->boxes().count();
+ if (lineCount > 0)
+ column->removeBox(lineCount - 1);
+}
+
+void TextLayout::render(ScreenPainter *p, ITextContext *ctx)
+{
+ p->save();
+ m_box->render(p, ctx);
+ p->restore();
+}
+
+void TextLayout::renderBackground(TextLayoutPainter *p)
+{
+ foreach (const Box* column, m_box->boxes())
+ {
+ const ParagraphStyle& style = m_story->paragraphStyle(column->firstChar());
+ if (style.backgroundColor() != CommonStrings::None)
+ {
+ p->save();
+ TextLayoutColor backColor(style.backgroundColor(), style.backgroundShade());
+ p->setFillColor(backColor);
+ p->setStrokeColor(backColor);
+ p->drawRect(column->bbox());
+ p->restore();
+ }
+ }
+}
+
+void TextLayout::render(TextLayoutPainter *p)
+{
+ p->save();
+ m_box->render(p);
+ p->restore();
+}
+
+void TextLayout::addColumn(double colLeft, double colWidth)
+{
+ GroupBox *newBox = new GroupBox(Box::D_Vertical);
+ newBox->moveTo(colLeft, 0.0);
+ newBox->setWidth(colWidth);
+ newBox->setAscent(m_frame->height());
+ m_box->addBox(newBox);
+
+ // Update the box width and height, any better place to do this?
+ m_box->setAscent(m_frame->height());
+ m_box->setWidth(m_frame->width());
+}
+
+void TextLayout::clear()
+{
+ delete m_box;
+ m_box = new GroupBox(Box::D_Horizontal);
+}
+
+void TextLayout::setStory(StoryText *story)
+{
+ m_story = story;
+ clear();
+}
+
+int TextLayout::startOfLine(int pos) const
+{
+ for (uint i=0; i < lines(); ++i) {
+ const LineBox* ls = line(i);
+ if (ls->firstChar() <= pos && pos <= ls->lastChar())
+ return ls->firstChar();
+ }
+ return 0;
+}
+
+int TextLayout::endOfLine(int pos) const
+{
+ for (uint i=0; i < lines(); ++i) {
+ const LineBox* ls = line(i);
+ if (ls->containsPos(pos))
+ return story()->text(ls->lastChar()) == SpecialChars::PARSEP ? ls->lastChar() :
+ story()->text(ls->lastChar()) == ' ' ? ls->lastChar() : ls->lastChar() + 1;
+ }
+ return story()->length();
+}
+
+int TextLayout::prevLine(int pos) const
+{
+ bool isRTL = (m_story->paragraphStyle().direction() == ParagraphStyle::RTL);
+ for (uint i=0; i < lines(); ++i)
+ {
+ // find line for pos
+ const LineBox* ls = line(i);
+ if (ls->containsPos(pos))
+ {
+ if (i == 0)
+ return startOfLine(pos);
+ // find current xpos
+ qreal xpos = ls->positionToPoint(pos, *m_story).x1();
+ if (pos != m_lastMagicPos || xpos > m_magicX)
+ m_magicX = xpos;
+
+ const LineBox* ls2 = line(i-1);
+ // find new cpos
+ for (int j = ls2->firstChar(); j <= ls2->lastChar(); ++j)
+ {
+ xpos = ls2->positionToPoint(j, *m_story).x1();
+ if ((isRTL && xpos <= m_magicX) || (!isRTL && xpos >= m_magicX))
+ {
+ m_lastMagicPos = j;
+ return j;
+ }
+ }
+ m_lastMagicPos = ls2->lastChar();
+ return ls2->lastChar();
+ }
+ }
+ return m_box->firstChar();
+}
+
+int TextLayout::nextLine(int pos) const
+{
+ bool isRTL = (m_story->paragraphStyle().direction() == ParagraphStyle::RTL);
+ for (uint i=0; i < lines(); ++i)
+ {
+ // find line for pos
+ const LineBox* ls = line(i);
+ if (ls->containsPos(pos))
+ {
+ if (i+1 == lines())
+ return endOfLine(pos);
+ // find current xpos
+ qreal xpos = ls->positionToPoint(pos, *m_story).x1();
+
+ if (pos != m_lastMagicPos || xpos > m_magicX)
+ m_magicX = xpos;
+
+ const LineBox* ls2 = line(i+1);
+ // find new cpos
+ for (int j = ls2->firstChar(); j <= ls2->lastChar(); ++j)
+ {
+ xpos = ls2->positionToPoint(j, *m_story).x1();
+ if ((isRTL && xpos <= m_magicX) || (!isRTL && xpos >= m_magicX))
+ {
+ m_lastMagicPos = j;
+ return j;
+ }
+ }
+ m_lastMagicPos = ls2->lastChar() + 1;
+ return ls2->lastChar() + 1;
+ }
+ }
+ return m_box->lastChar();
+}
+
+int TextLayout::startOfFrame() const
+{
+ return m_box->firstChar();
+}
+
+int TextLayout::endOfFrame() const
+{
+ return m_box->lastChar() + 1;
+}
+
+
+int TextLayout::pointToPosition(QPointF coord) const
+{
+ int position = m_box->pointToPosition(coord, *m_story);
+ return position;
+}
+
+
+QLineF TextLayout::positionToPoint(int pos) const
+{
+ QLineF result;
+ bool isRTL = (m_story->paragraphStyle().direction() == ParagraphStyle::RTL);
+
+ result = m_box->positionToPoint(pos, *m_story);
+ if (result.isNull())
+ {
+ qreal x, y1, y2;
+ if (lines() > 0)
+ {
+ // TODO: move this branch to GroupBox::positionToPoint()
+ // last glyph box in last line
+ Box* column = m_box->boxes().last();
+ Box* line = column->boxes().last();
+ Box* glyph = line->boxes().empty()? NULL : line->boxes().last();
+ QChar ch = story()->text(line->lastChar());
+ if (ch == SpecialChars::PARSEP || ch == SpecialChars::LINEBREAK)
+ {
+ // last character is a newline, draw the cursor on the next line.
+ if (isRTL)
+ x = line->width();
+ else
+ x = 1;
+ y1 = line->y() + line->height();
+ y2 = y1 + line->height();
+ }
+ else
+ {
+ // draw the cursor at the end of last line.
+ if (isRTL || glyph == NULL)
+ x = line->x();
+ else
+ x = line->x() + glyph->x() + glyph->width();
+ y1 = line->y();
+ y2 = y1 + line->height();
+ }
+ result.setLine(x, y1, x, y2);
+ result.translate(column->x(), column->y());
+ }
+ else
+ {
+ // rather the trailing style than a segfault.
+ const ParagraphStyle& pstyle(story()->paragraphStyle(qMin(pos, story()->length())));
+ if (isRTL)
+ x = m_box->width();
+ else
+ x = 1;
+ y1 = 0;
+ y2 = pstyle.lineSpacing();
+ result.setLine(x, y1, x, y2);
+ }
+ result.translate(m_box->x(), m_box->y());
+ }
+
+ return result;
+}
More information about the scribus-commit
mailing list