r21349 by jghali -
scribus-commit
scribus-commit at lists.scribus.net
Sun May 22 20:49:41 UTC 2016
Author: jghali
Date: Sun May 22 20:49:41 2016
New Revision: 21349
URL: http://scribus.net/websvn/listing.php?repname=Scribus&sc=1&rev=21349
Log:
Better sizing of text cursor in paragraph with drop caps or different font size
Modified:
trunk/Scribus/scribus/pageitem_textframe.cpp
trunk/Scribus/scribus/text/boxes.cpp
trunk/Scribus/scribus/text/boxes.h
trunk/Scribus/scribus/text/textlayout.cpp
Modified: trunk/Scribus/scribus/pageitem_textframe.cpp
URL: http://scribus.net/websvn/diff.php?repname=Scribus&rev=21349&path=/trunk/Scribus/scribus/pageitem_textframe.cpp
==============================================================================
--- trunk/Scribus/scribus/pageitem_textframe.cpp (original)
+++ trunk/Scribus/scribus/pageitem_textframe.cpp Sun May 22 20:49:41 2016
@@ -808,7 +808,7 @@
result->moveTo(line.x - colLeft, line.y);
result->setWidth(line.width);
result->setAscent(line.ascent);
- result->setDescent(line.descent);
+ result->setDescent(-line.descent);
for (int i = line.firstRun; i <= line.lastRun; ++i)
{
Modified: trunk/Scribus/scribus/text/boxes.cpp
URL: http://scribus.net/websvn/diff.php?repname=Scribus&rev=21349&path=/trunk/Scribus/scribus/text/boxes.cpp
==============================================================================
--- trunk/Scribus/scribus/text/boxes.cpp (original)
+++ trunk/Scribus/scribus/text/boxes.cpp Sun May 22 20:49:41 2016
@@ -154,8 +154,24 @@
{
if (box->containsPos(pos))
{
+ const GlyphBox* glypBox = dynamic_cast<const GlyphBox*>(box);
+ if (!glypBox)
+ {
+ double xPos = x() + box->x();
+ result = QLineF(xPos, y(), xPos, y() + height());
+ break;
+ }
+
+ const CharStyle& cStyle(glypBox->style());
+ double fontSize = cStyle.fontSize() / 10.0;
+ double scaleV = cStyle.scaleV() / 1000.0;
+ double offset = fontSize * (cStyle.baselineOffset() / 1000.0);
+ double asce = cStyle.font().ascent(fontSize) * scaleV + offset;
+ double desc = cStyle.font().descent(fontSize) * scaleV - offset;
+
double xPos = x() + box->x();
- result = QLineF(xPos, y(), xPos, y() + height());
+ double yPos = y() + box->y() + ascent();
+ result = QLineF(xPos, yPos - asce, xPos, yPos - desc);
break;
}
}
Modified: trunk/Scribus/scribus/text/boxes.h
URL: http://scribus.net/websvn/diff.php?repname=Scribus&rev=21349&path=/trunk/Scribus/scribus/text/boxes.h
==============================================================================
--- trunk/Scribus/scribus/text/boxes.h (original)
+++ trunk/Scribus/scribus/text/boxes.h Sun May 22 20:49:41 2016
@@ -121,6 +121,9 @@
/// Same as render() but handles text selection, for rendering on screen.
virtual void render(TextLayoutPainter *p, PageItem *item) const = 0;
+
+ /// Return the 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=21349&path=/trunk/Scribus/scribus/text/textlayout.cpp
==============================================================================
--- trunk/Scribus/scribus/text/textlayout.cpp (original)
+++ trunk/Scribus/scribus/text/textlayout.cpp Sun May 22 20:49:41 2016
@@ -1,338 +1,352 @@
-/*
- 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 "pageitem.h"
-#include "prefsstructs.h"
-#include "../styles/paragraphstyle.h"
-#include "specialchars.h"
-#include "storytext.h"
-#include "textlayout.h"
-#include "textlayoutpainter.h"
-#include "boxes.h"
-
-
-
-
-TextLayout::TextLayout(StoryText* text, PageItem* 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;
-}
-
-const PathData& TextLayout::point(int pos) const
-{
- return m_path[pos];
-}
-
-PathData& TextLayout::point(int pos)
-{
- if (pos >= story()->length())
- m_path.resize(story()->length());
- return m_path[pos];
-}
-
-
-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);
-
- // HACK: the ascent set by PageItem_TextFrame::layout()
- // is useless, we reset it again based on the y position
- ls->setAscent(ls->y() - column->naturalHeight());
- 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(TextLayoutPainter *p, PageItem *item)
-{
- p->save();
- m_box->render(p, item);
- 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);
- m_path.clear();
- if (m_frame->asPathText() != NULL)
- m_path.resize(story()->length());
-}
-
-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
-{
- 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).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).x1();
- if (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
-{
- 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).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).x1();
- if (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);
- if (position == m_box->lastChar())
- position += 1;
- return position;
-}
-
-
-QLineF TextLayout::positionToPoint(int pos) const
-{
- QLineF result;
-
- result = m_box->positionToPoint(pos);
- 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().last();
- QChar ch = story()->text(glyph->lastChar());
- if (ch == SpecialChars::PARSEP || ch == SpecialChars::LINEBREAK)
- {
- // last character is a newline, draw the cursor on the next line.
- x = 1;
- y1 = line->y() + line->height();
- y2 = y1 + line->height();
- }
- else
- {
- // draw the cursor at the end of last line.
- 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())));
- 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 "pageitem.h"
+#include "prefsstructs.h"
+#include "../styles/paragraphstyle.h"
+#include "specialchars.h"
+#include "storytext.h"
+#include "textlayout.h"
+#include "textlayoutpainter.h"
+#include "boxes.h"
+
+
+
+
+TextLayout::TextLayout(StoryText* text, PageItem* 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;
+}
+
+const PathData& TextLayout::point(int pos) const
+{
+ return m_path[pos];
+}
+
+PathData& TextLayout::point(int pos)
+{
+ if (pos >= story()->length())
+ m_path.resize(story()->length());
+ return m_path[pos];
+}
+
+
+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);
+
+ // HACK: the ascent set by PageItem_TextFrame::layout()
+ // is useless, we reset it again based on the y position
+ ls->setAscent(ls->y() - column->naturalHeight());
+ 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(TextLayoutPainter *p, PageItem *item)
+{
+ p->save();
+ m_box->render(p, item);
+ 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);
+ m_path.clear();
+ if (m_frame->asPathText() != NULL)
+ m_path.resize(story()->length());
+}
+
+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
+{
+ 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).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).x1();
+ if (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
+{
+ 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).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).x1();
+ if (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);
+ if (position == m_box->lastChar())
+ position += 1;
+ return position;
+}
+
+
+QLineF TextLayout::positionToPoint(int pos) const
+{
+ QLineF result;
+
+ result = m_box->positionToPoint(pos);
+ 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().last();
+ QChar ch = story()->text(glyph->lastChar());
+ if (ch == SpecialChars::PARSEP || ch == SpecialChars::LINEBREAK)
+ {
+ // last character is a newline, draw the cursor on the next line.
+ x = 1;
+ y1 = line->y() + line->height();
+ y2 = y1 + line->height();
+ }
+ else if (glyph->type() == Box::T_Glyph)
+ {
+ // draw the cursor at the end of last line.
+ const CharStyle& cStyle(story()->charStyle(glyph->lastChar()));
+ double fontSize = cStyle.fontSize() / 10.0;
+ double scaleV = cStyle.scaleV() / 1000.0;
+ double offset = fontSize * (cStyle.baselineOffset() / 1000.0);
+ double asce = cStyle.font().ascent(fontSize) * scaleV + offset;
+ double desc = cStyle.font().descent(fontSize) * scaleV - offset;
+
+ x = line->x() + glyph->x() + glyph->width();
+ y1 = line->y() + line->ascent() - asce;
+ y2 = line->y() + line->ascent() - desc;
+ }
+ else
+ {
+ // draw the cursor at the end of last line.
+ 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())));
+ 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