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 #ifndef BOXES_H
9 #define BOXES_H
10 
11 #include "glyphcluster.h"
12 #include "sctextstruct.h"
13 #include "itextcontext.h"
14 
15 class StoryText;
16 class TextLayoutPainter;
17 class ScreenPainter;
18 
19 /**
20  Class Box has a similar role as TeX's boxes.
21  Scribus packs glyph runs into GlyphBoxes, GlyphBoxes and ObjectBoxes into LineBoxes
22  and LineBoxes into GroupBox(T_Block).
23  (and in the future: math atoms, tables & table cells, ...)
24  */
25 class Box
26 {
27 public:
28 	enum BoxType
29 	{
30 		T_Invalid,
31 		T_Block,
32 		T_Line,
33 		T_PathLine,
34 		T_Glyph,
35 		T_Object
36 	};
37 
38 	enum BoxDirection
39 	{
40 		D_Horizontal,
41 		D_Vertical
42 	};
43 
Box()44 	Box()
45 	{
46 		m_type = T_Invalid;
47 		m_direction = D_Horizontal;
48 		m_x = m_y = m_width = m_ascent = m_descent = 0;
49 		m_firstChar = 0;
50 		m_lastChar = 0;
51 		m_naturalAscent = 0;
52 		m_naturalDescent = 0;
53 	}
54 
~Box()55 	virtual ~Box()
56 	{
57 		while (!m_boxes.isEmpty())
58 			delete m_boxes.takeFirst();
59 	}
60 
61 	/// The x position of the box relative to its parent.
x()62 	double x() const { return m_x; }
63 	/// The y position of the box relative to its parent.
y()64 	double y() const { return m_y; }
65 	/// Sets x and y positions of the box.
moveTo(double x,double y)66 	void moveTo (double x, double y) { m_x = x, m_y = y; }
67 	/// Increments x and y positions of the box.
moveBy(double x,double y)68 	void moveBy (double x, double y) { m_x += x, m_y += y; }
69 
70 	/// The box width, can be different from its natural width.
width()71 	double width() const { return m_width; }
72 	/// Set the box width.
setWidth(double w)73 	void setWidth(double w) { m_width = w; }
74 
75 	/// The box ascender above baseline.
ascent()76 	double ascent() const { return m_ascent; }
77 	/// The box descender below baseline.
descent()78 	double descent() const { return m_descent; }
79 	/// The box height, can be different from its natural height.
height()80 	double height() const { return m_ascent - m_descent; }
81 	/// Set the box ascender.
setAscent(double a)82 	void setAscent(double a) { m_ascent = a; }
83 	/// Set the box descender.
setDescent(double d)84 	void setDescent(double d) { m_descent = d; }
85 
86 	/// The actual width of the box contents, can be different from the requested width.
naturalWidth()87 	virtual double naturalWidth() const { return width(); }
88 	/// The actual height of the box contents, can be different from the requested height.
naturalHeight()89 	virtual double naturalHeight() const { return height(); }
90 
91 	/// The bounding box and position of the box relative to its parent.
bbox()92 	QRectF bbox() const { return QRectF(m_x, m_y, m_width, height()); }
93 
94 	/// Whether the coordinate is inside the box or not.
containsPoint(QPointF coord)95 	virtual bool containsPoint(QPointF coord) const { return bbox().contains(coord); }
96 	/// Whether the character at index pos is inside the box or not.
containsPos(int pos)97 	bool containsPos(int pos) const { return firstChar() <= pos && pos <= lastChar(); }
98 
99 	/// Returns the character index at coorddinate.
100 	virtual int pointToPosition(QPointF coord, const StoryText &story) const = 0;
101 	/// Returns the position of cursor before the character at index pos.
positionToPoint(int,const StoryText &)102 	virtual QLineF positionToPoint(int, const StoryText&) const { return QLineF(); }
103 
104 	/// The first character within the box.
firstChar()105 	int firstChar() const { return m_firstChar == INT_MAX ? 0 : m_firstChar; }
106 	/// The last character within the box.
lastChar()107 	int lastChar() const { return m_lastChar == INT_MIN ? 0 : m_lastChar; }
108 
109 	/// Sets the transformation matrix to applied to the box.
setMatrix(QTransform x)110 	void setMatrix(QTransform x) { m_matrix = x; }
111 
112 	/// The transformation matrix applied to the box.
matrix()113 	const QTransform& matrix() const { return m_matrix; }
114 
115 //	virtual void justify(const ParagraphStyle& style) {}
116 
117 	/// Returns the children of the box.
boxes()118 	QList<Box*>& boxes() { return m_boxes; }
boxes()119 	const QList<const Box*>& boxes() const {
120 		return reinterpret_cast<const QList<const Box*> & > (m_boxes);
121 	}
122 
123 	/// Returns the number of child boxes
boxCount()124 	int boxCount() const { return m_boxes.count(); }
125 
126 	/// Returns if current box contains any child boxes
isEmpty()127 	bool isEmpty() const { return m_boxes.isEmpty(); }
128 
129 	/// Renders the box and any boxes it contains, recursively.
130 	virtual void render(TextLayoutPainter *p) const = 0;
131 
132 	/// Same as render() but handles text selection, for rendering on screen.
133 	virtual void render(ScreenPainter *p, ITextContext *ctx) const = 0;
134 
135 	/// Draw selection if the the box selected
drawSelection(ScreenPainter * p,ITextContext * ctx)136 	virtual void drawSelection(ScreenPainter *p, ITextContext *ctx) const {}
137 
138 	/// Get natural ascent and descent.
naturalAsc()139 	virtual double naturalAsc() const { return m_naturalAscent; }
naturalDescent()140 	virtual double naturalDescent() const { return m_naturalDescent; }
141 
142 	/// return box type
type()143 	BoxType type() const { return m_type; }
144 
145 protected:
146 	BoxType m_type;
147 	BoxDirection m_direction;
148 	double m_x;
149 	double m_y;
150 	double m_width;
151 	double m_descent;
152 	double m_ascent;
153 	QList<Box*> m_boxes;
154 	int m_firstChar;
155 	int m_lastChar;
156 	QTransform m_matrix;
157 	double m_naturalAscent;
158 	double m_naturalDescent;
159 };
160 
161 
162 class GroupBox: public Box
163 {
164 public:
GroupBox(BoxDirection direction)165 	GroupBox(BoxDirection direction)
166 	{
167 		m_type = T_Block;
168 		m_direction = direction;
169 		m_firstChar = INT_MAX;
170 		m_lastChar = INT_MIN;
171 		m_naturalWidth = m_naturalHeight = 0;
172 	}
173 
174 	int pointToPosition(QPointF coord, const StoryText &story) const override;
175 	QLineF positionToPoint(int pos, const StoryText& story) const override;
176 
177 	void render(TextLayoutPainter *p) const override;
178 	void render(ScreenPainter *p, ITextContext *ctx) const override;
179 	void drawSelection(ScreenPainter *p, ITextContext *ctx) const override;
180 
naturalWidth()181 	double naturalWidth() const override { return m_naturalWidth; }
182 	double naturalHeight() const override;
183 
184 //	void justify(const ParagraphStyle& style);
185 
186 	/// Adds a new child to the box.
187 	virtual void addBox(const Box* box);
188 	/// Remove the child at i.
189 	virtual void removeBox(int i);
190 
191 protected:
192 	double m_naturalWidth;
193 	double m_naturalHeight;
194 
195 private:
196 	void update();
197 };
198 
199 
200 class LineBox: public GroupBox
201 {
202 public:
LineBox()203 	LineBox()
204 		: GroupBox(D_Horizontal)
205 	{
206 		m_type = T_Line;
207 	}
208 
209 	int pointToPosition(QPointF coord, const StoryText &story) const override;
210 	QLineF positionToPoint(int pos, const StoryText& story) const override;
211 
212 	bool containsPoint(QPointF coord) const override;
213 
214 	void render(TextLayoutPainter *p) const override;
215 	void render(ScreenPainter *p, ITextContext *ctx) const override;
216 	void drawSelection(ScreenPainter *p, ITextContext *ctx) const override;
217 
naturalWidth()218 	double naturalWidth() const override{ return m_naturalWidth; }
naturalHeight()219 	double naturalHeight() const override{ return height(); }
220 
221 //	void justify(const ParagraphStyle& style);
222 
223 	void addBox(const Box* box) override;
224 	void removeBox(int i) override;
225 
226 protected:
227 	virtual void drawBackGround(TextLayoutPainter *p) const;
228 	virtual void update();
229 };
230 
231 class PathLineBox: public LineBox
232 {
233 public:
PathLineBox()234 	PathLineBox()
235 	{
236 		m_type = T_PathLine;
237 	}
238 
239 protected:
240 	void update() override;
241 	void drawBackGround(TextLayoutPainter *p) const override;
242 };
243 
244 class GlyphBox: public Box
245 {
246 public:
GlyphBox(const GlyphCluster & run)247 	GlyphBox(const GlyphCluster& run)
248 		: m_glyphRun(run)
249 		, m_effects(run.style().effects())
250 	{
251 		m_type = T_Glyph;
252 		m_firstChar = run.firstChar();
253 		m_lastChar = run.lastChar();
254 		m_width = run.width();
255 		m_naturalAscent = run.ascent();
256 		m_naturalDescent = run.descent();
257 	}
258 
259 	int pointToPosition(QPointF coord, const StoryText &story) const override;
260 	QLineF positionToPoint(int pos, const StoryText& story) const override;
261 
262 	void render(TextLayoutPainter *p) const override;
263 	void render(ScreenPainter *p, ITextContext *ctx) const override;
264 	void drawSelection(ScreenPainter *p, ITextContext *ctx) const override;
265 
glyphRun()266 	GlyphCluster glyphRun() const { return m_glyphRun; }
267 
style()268 	const CharStyle& style() const { return m_glyphRun.style(); }
269 
270 protected:
271 	GlyphCluster m_glyphRun;
272 	const StyleFlag m_effects;
273 };
274 
275 class ObjectBox: public GlyphBox
276 {
277 public:
ObjectBox(const GlyphCluster & run,ITextContext * ctx)278 	ObjectBox(const GlyphCluster& run, ITextContext* ctx)
279 		: GlyphBox(run)
280 		, m_object(ctx->object(run.object()))
281 	{
282 		m_type = T_Object;
283 	}
284 
285 	void render(TextLayoutPainter *p) const override;
286 	void render(ScreenPainter*, ITextContext *ctx) const override;
287 
288 private:
289 	/* const */ PageItem* m_object;
290 };
291 
292 #endif // BOXES_H
293