Subversion Repositories Scribus

Rev

Rev 20882 | Rev 21110 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
18988 avox 1
/*
2
 For general Scribus (>=1.3.2) copyright and licensing information please refer
3
 to the COPYING file provided with the program. Following this notice may exist
4
 a copyright and/or license notice that predates the release of Scribus 1.3.2
5
 for which a new license (GPL+exception) is in place.
6
 */
7
/***************************************************************************
8
*                                                                         *
9
*   This program is free software; you can redistribute it and/or modify  *
10
*   it under the terms of the GNU General Public License as published by  *
11
*   the Free Software Foundation; either version 2 of the License, or     *
12
*   (at your option) any later version.                                   *
13
*                                                                         *
14
***************************************************************************/
15
 
16
#undef NDEBUG
17
 
18
#include <cassert>
19
#include "../styles/charstyle.h"
20
#include "pageitem.h"
21
#include "prefsstructs.h"
22
#include "../styles/paragraphstyle.h"
23
#include "specialchars.h"
24
#include "storytext.h"
25
#include "textlayout.h"
21107 craig 26
#include "textlayoutpainter.h"
27
#include "boxes.h"
18988 avox 28
 
29
 
30
 
31
 
32
TextLayout::TextLayout(StoryText* text, PageItem* frame)
33
{
34
        m_story = text;
35
        m_frame = frame;
36
 
20882 jghali 37
        m_validLayout = false;
18988 avox 38
        m_magicX = 0.0;
39
        m_lastMagicPos = -1;
21107 craig 40
 
41
        m_box = new GroupBox(Box::D_Horizontal);
18988 avox 42
}
43
 
21107 craig 44
TextLayout::~TextLayout()
45
{
46
        delete m_box;
47
}
18988 avox 48
 
49
uint TextLayout::lines() const
50
{
21107 craig 51
        uint count = 0;
52
        foreach (const Box *box, m_box->boxes())
53
        {
54
                count += box->boxes().count();
55
        }
56
        return count;
18988 avox 57
}
58
 
21107 craig 59
const LineBox* TextLayout::line(uint i) const
18988 avox 60
{
21107 craig 61
        uint count = 0;
62
        foreach (const Box *box, m_box->boxes())
63
        {
64
                if (i < count + box->boxes().count())
65
                        return dynamic_cast<const LineBox*>(box->boxes()[i - count]);
66
                count += box->boxes().count();
67
        }
68
        assert(false);
69
        return NULL;
18988 avox 70
}
71
 
21107 craig 72
const Box* TextLayout::box() const
73
{
74
        return m_box;
75
}
76
 
77
Box* TextLayout::box()
78
{
79
        return m_box;
80
}
81
 
18988 avox 82
const PathData& TextLayout::point(int pos) const
83
{
84
        return m_path[pos];
85
}
86
 
87
PathData& TextLayout::point(int pos)
88
{
89
        if (pos >= story()->length())
90
                m_path.resize(story()->length());
91
        return m_path[pos];
92
}
93
 
94
 
21107 craig 95
void TextLayout::appendLine(LineBox* ls)
96
{
97
        assert( ls->firstChar() >= 0 );
98
        assert( ls->firstChar() < story()->length() );
99
        assert( ls->lastChar() < story()->length() );
18988 avox 100
 
21107 craig 101
        // HACK: the ascent set by PageItem_TextFrame::layout()
102
        // is useless, we reset it again based on the y position
103
        ls->setAscent(ls->y() - m_box->boxes().last()->naturalHeight());
104
        dynamic_cast<GroupBox*>(m_box->boxes().last())->addBox(ls);
105
}
106
 
18988 avox 107
// Remove the last line from the list. Used when we need to backtrack on the layouting.
108
void TextLayout::removeLastLine ()
109
{
21107 craig 110
        m_box->removeBox(m_box->boxes().count() - 1);
111
}
112
 
113
void TextLayout::render(TextLayoutPainter *p, PageItem *item)
114
{
115
        p->save();
116
        m_box->render(p, item);
117
        p->restore();
118
}
119
 
120
void TextLayout::renderBackground(TextLayoutPainter *p)
121
{
122
        foreach (const Box* column, m_box->boxes())
123
        {
124
                const ParagraphStyle& style = m_story->paragraphStyle(column->firstChar());
125
                if (style.backgroundColor() != CommonStrings::None)
126
                {
127
                        p->save();
128
                        TextLayoutColor backColor(style.backgroundColor(), style.backgroundShade());
129
                        p->setFillColor(backColor);
130
                        p->setStrokeColor(backColor);
131
                        p->drawRect(column->bbox());
132
                        p->restore();
133
                }
18988 avox 134
        }
135
}
136
 
21107 craig 137
void TextLayout::render(TextLayoutPainter *p)
138
{
139
        p->save();
140
        m_box->render(p);
141
        p->restore();
142
}
18988 avox 143
 
21107 craig 144
void TextLayout::addColumn(double colLeft, double colWidth)
145
{
146
        GroupBox *newBox = new GroupBox(Box::D_Vertical);
147
        newBox->moveTo(colLeft, 0.0);
148
        newBox->setWidth(colWidth);
149
        newBox->setAscent(m_frame->height());
150
        m_box->addBox(newBox);
18988 avox 151
 
21107 craig 152
        // Update the box width and height, any better place to do this?
153
        m_box->setAscent(m_frame->height());
154
        m_box->setWidth(m_frame->width());
155
}
156
 
18988 avox 157
void TextLayout::clear()
158
{
21107 craig 159
        delete m_box;
160
        m_box = new GroupBox(Box::D_Horizontal);
18988 avox 161
        m_path.clear();
162
        if (m_frame->asPathText() != NULL)
163
                m_path.resize(story()->length());
164
}
165
 
166
void TextLayout::setStory(StoryText *story)
167
{
168
        m_story = story;
169
        clear();
170
}
171
 
172
int TextLayout::startOfLine(int pos) const
173
{
21107 craig 174
        for (uint i=0; i < lines(); ++i) {
175
                const LineBox* ls = line(i);
176
                if (ls->firstChar() <= pos && pos <= ls->lastChar())
177
                        return ls->firstChar();
18988 avox 178
        }
179
        return 0;
180
}
181
 
182
int TextLayout::endOfLine(int pos) const
183
{
21107 craig 184
        for (uint i=0; i < lines(); ++i) {
185
                const LineBox* ls = line(i);
186
                if (ls->containsPos(pos))
187
                        return story()->text(ls->lastChar()) == SpecialChars::PARSEP ? ls->lastChar() :
188
                                story()->text(ls->lastChar()) == ' ' ? ls->lastChar() : ls->lastChar() + 1;
18988 avox 189
        }
190
        return story()->length();
191
}
192
 
193
int TextLayout::prevLine(int pos) const
194
{
21107 craig 195
        for (uint i=0; i < lines(); ++i)
18988 avox 196
        {
197
                // find line for pos
21107 craig 198
                const LineBox* ls = line(i);
199
                if (ls->containsPos(pos))
18988 avox 200
                {
201
                        if (i == 0)
202
                                return startOfLine(pos);
203
                        // find current xpos
21107 craig 204
                        qreal xpos = ls->positionToPoint(pos).x1();
18988 avox 205
                        if (pos != m_lastMagicPos || xpos > m_magicX)
206
                                m_magicX = xpos;
21107 craig 207
 
208
                        const LineBox* ls2 = line(i-1);
18988 avox 209
                        // find new cpos
21107 craig 210
                        for (int j = ls2->firstChar(); j <= ls2->lastChar(); ++j)
18988 avox 211
                        {
21107 craig 212
                                xpos = ls2->positionToPoint(j).x1();
18988 avox 213
                                if (xpos > m_magicX) {
214
                                        m_lastMagicPos = j;
215
                                        return j;
216
                                }
217
                        }
21107 craig 218
                        m_lastMagicPos = ls2->lastChar();
219
                        return ls2->lastChar();
18988 avox 220
                }
221
        }
21107 craig 222
        return m_box->firstChar();
18988 avox 223
}
224
 
225
int TextLayout::nextLine(int pos) const
226
{
21107 craig 227
        for (uint i=0; i < lines(); ++i)
18988 avox 228
        {
229
                // find line for pos
21107 craig 230
                const LineBox* ls = line(i);
231
                if (ls->containsPos(pos))
18988 avox 232
                {
21107 craig 233
                        if (i+1 == lines())
18988 avox 234
                                return endOfLine(pos);
235
                        // find current xpos
21107 craig 236
                        qreal xpos = ls->positionToPoint(pos).x1();
237
 
18988 avox 238
                        if (pos != m_lastMagicPos || xpos > m_magicX)
239
                                m_magicX = xpos;
21107 craig 240
 
241
                        const LineBox* ls2 = line(i+1);
18988 avox 242
                        // find new cpos
21107 craig 243
                        for (int j = ls2->firstChar(); j <= ls2->lastChar(); ++j)
18988 avox 244
                        {
21107 craig 245
                                xpos = ls2->positionToPoint(j).x1();
18988 avox 246
                                if (xpos > m_magicX) {
247
                                        m_lastMagicPos = j;
248
                                        return j;
249
                                }
250
                        }
21107 craig 251
                        m_lastMagicPos = ls2->lastChar() + 1;
252
                        return ls2->lastChar() + 1;
18988 avox 253
                }
254
        }
21107 craig 255
        return m_box->lastChar();
18988 avox 256
}
257
 
258
int TextLayout::startOfFrame() const
259
{
21107 craig 260
        return m_box->firstChar();
18988 avox 261
}
262
 
263
int TextLayout::endOfFrame() const
264
{
21107 craig 265
        return m_box->lastChar() + 1;
18988 avox 266
}
267
 
268
 
21107 craig 269
int TextLayout::pointToPosition(QPointF coord) const
18988 avox 270
{
21107 craig 271
        int position = m_box->pointToPosition(coord);
272
        if (position == m_box->lastChar())
273
                position += 1;
274
        return position;
18988 avox 275
}
276
 
277
 
21107 craig 278
QLineF TextLayout::positionToPoint(int pos) const
18988 avox 279
{
21107 craig 280
        QLineF result;
281
 
282
        result = m_box->positionToPoint(pos);
283
        if (result.isNull())
18988 avox 284
        {
21107 craig 285
                qreal x, y1, y2;
286
                if (lines() > 0)
287
                {
288
                        // TODO: move this branch to GroupBox::positionToPoint()
289
                        // last glyph box in last line
290
                        Box* column = m_box->boxes().last();
291
                        Box* line = column->boxes().last();
292
                        Box* glyph = line->boxes().last();
293
                        QChar ch = story()->text(glyph->lastChar());
294
                        if (ch == SpecialChars::PARSEP || ch == SpecialChars::LINEBREAK)
18988 avox 295
                        {
21107 craig 296
                                // last character is a newline, draw the cursor on the next line.
297
                                x = 1;
298
                                y1 = line->y() + line->height();
299
                                y2 = y1 + line->height();
18988 avox 300
                        }
21107 craig 301
                        else
18988 avox 302
                        {
21107 craig 303
                                // draw the cursor at the end of last line.
304
                                x = line->x() + glyph->x() + glyph->width();
305
                                y1 = line->y();
306
                                y2 = y1 + line->height();
18988 avox 307
                        }
21107 craig 308
                        result.setLine(x, y1, x, y2);
309
                        result.translate(column->x(), column->y());
18988 avox 310
                }
21107 craig 311
                else
312
                {
313
                        // rather the trailing style than a segfault.
314
                        const ParagraphStyle& pstyle(story()->paragraphStyle(qMin(pos, story()->length())));
315
                        x = 1;
316
                        y1 = 0;
317
                        y2 = pstyle.lineSpacing();
318
                        result.setLine(x, y1, x, y2);
319
                }
320
                result.translate(m_box->x(), m_box->y());
18988 avox 321
        }
21107 craig 322
 
18988 avox 323
        return result;
324
}