1 /* AbiWord
2  * Copyright (C) 2003 Tomas Frydrych <tomas@frydrych.uklinux.net>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301 USA.
18  */
19 
20 #include "fp_DirectionMarkerRun.h"
21 #include "fl_BlockLayout.h"
22 #include "fp_TextRun.h"
23 #include "fp_Line.h"
24 #include "fv_View.h"
25 
26 #include "gr_DrawArgs.h"
27 #include "gr_Graphics.h"
28 
29 #include "ut_debugmsg.h"
30 #include "ut_assert.h"
31 #include "gr_Painter.h"
32 
fp_DirectionMarkerRun(fl_BlockLayout * pBL,UT_uint32 iOffsetFirst,UT_UCS4Char cMarker)33 fp_DirectionMarkerRun::fp_DirectionMarkerRun(fl_BlockLayout* pBL,
34 					  UT_uint32 iOffsetFirst,
35 					  UT_UCS4Char cMarker):
36 		fp_Run(pBL, iOffsetFirst, 1, FPRUN_DIRECTIONMARKER)
37 {
38 	m_iMarker = cMarker;
39 
40 	_setDirty(true);
41 	_setDirection(UT_bidiGetCharType(m_iMarker));
42 	lookupProperties();
43 }
44 
45 
_recalcWidth(void)46 bool fp_DirectionMarkerRun::_recalcWidth(void)
47 {
48 	UT_sint32 iOldWidth = getWidth();
49 	FV_View* pView = _getView();
50 
51 	if (pView && pView->getShowPara())
52 	{
53 		if(static_cast<UT_sint32>(m_iDrawWidth) != iOldWidth)
54 		{
55 			_setWidth(m_iDrawWidth);
56 			return true;
57 		}
58 
59 		xxx_UT_DEBUGMSG(("fp_DirectionMarkerRun::lookupProperties: width %d\n", getWidth()));
60 	}
61 	else
62 	{
63 		if(iOldWidth != 0)
64 		{
65 			_setWidth(0);
66 			return true;
67 		}
68 	}
69 
70 	return false;
71 }
72 
_lookupProperties(const PP_AttrProp * pSpanAP,const PP_AttrProp * pBlockAP,const PP_AttrProp * pSectionAP,GR_Graphics * pG)73 void fp_DirectionMarkerRun::_lookupProperties(const PP_AttrProp * pSpanAP,
74 											  const PP_AttrProp * pBlockAP,
75 											  const PP_AttrProp * pSectionAP,
76 											  GR_Graphics * pG)
77 {
78 	//UT_DEBUGMSG(("fp_DirectionMarkerRun::lookupProperties\n"));
79 	_inheritProperties();
80 	if(pG == NULL)
81 	{
82 		pG = getGraphics();
83 	}
84 	const gchar* pRevision = NULL;
85 
86 	if(pBlockAP && pBlockAP->getAttribute("revision", pRevision))
87 	{
88 		// we will not in fact be doing anything with the actual
89 		// properties and attributes contained in the revision
90 		// we just need its representation so the base class can
91 		// handle us properly
92 		PP_RevisionAttr * pRev = getRevisions();
93 		DELETEP(pRev);
94 
95 		_setRevisions(new PP_RevisionAttr(pRevision));
96 	}
97 
98 	// Find drawing width
99 	fp_Run* pPropRun = _findPrevPropertyRun();
100 	if (pPropRun && (FPRUN_TEXT == pPropRun->getType()))
101 	{
102 		fp_TextRun* pTextRun = static_cast<fp_TextRun*>(pPropRun);
103 		pG->setFont(pTextRun->getFont());
104 	}
105 	else
106 	{
107 		// look for fonts in this DocLayout's font cache
108 		FL_DocLayout * pLayout = getBlock()->getDocLayout();
109 
110 		const GR_Font * pFont = pLayout->findFont(pSpanAP,pBlockAP,pSectionAP);
111 		pG->setFont(pFont);
112 	}
113 
114 	UT_UCS4Char cM = m_iMarker == UCS_LRM ? (UT_UCS4Char)'>' : (UT_UCS4Char)'<';
115 	m_iDrawWidth  = pG->measureString(&cM, 0, 1, NULL);
116 	xxx_UT_DEBUGMSG(("fp_DirectionMarkerRun::lookupProperties: width %d\n", getWidth()));
117 }
118 
canBreakAfter(void) const119 bool fp_DirectionMarkerRun::canBreakAfter(void) const
120 {
121 	return true;
122 }
123 
canBreakBefore(void) const124 bool fp_DirectionMarkerRun::canBreakBefore(void) const
125 {
126 	return true;
127 }
128 
_letPointPass(void) const129 bool fp_DirectionMarkerRun::_letPointPass(void) const
130 {
131 	return false;
132 }
133 
_deleteFollowingIfAtInsPoint() const134 bool fp_DirectionMarkerRun::_deleteFollowingIfAtInsPoint() const
135 {
136 	// we will only allow deletion if visible on screen
137 	FV_View* pView = _getView();
138     if(!pView || !pView->getShowPara())
139     {
140     	return true;
141     }
142 
143 	return false;
144 }
145 
mapXYToPosition(UT_sint32 x,UT_sint32,PT_DocPosition & pos,bool & bBOL,bool & bEOL,bool &)146 void fp_DirectionMarkerRun::mapXYToPosition(UT_sint32 x,
147 											UT_sint32 /*y*/,
148 											PT_DocPosition& pos,
149 											bool& bBOL,
150 											bool& bEOL,
151 											bool & /*isTOC*/)
152 {
153 	if (x > getWidth())
154 		pos = getBlock()->getPosition() + getBlockOffset() + getLength();
155 	else
156 		pos = getBlock()->getPosition() + getBlockOffset();
157 
158 	bBOL = false;
159 	bEOL = false;
160 }
161 
findPointCoords(UT_uint32 iOffset,UT_sint32 & x,UT_sint32 & y,UT_sint32 & x2,UT_sint32 & y2,UT_sint32 & height,bool & bDirection)162 void fp_DirectionMarkerRun::findPointCoords(UT_uint32 iOffset,
163 										   UT_sint32& x, UT_sint32& y,
164 										   UT_sint32& x2, UT_sint32& y2,
165 										   UT_sint32& height,
166 										   bool& bDirection)
167 {
168 	fp_Run* pPropRun = _findPrevPropertyRun();
169 
170 	height = getHeight();
171 
172 	if (pPropRun)
173 	{
174 		height = pPropRun->getHeight();
175 		// If property Run is on the same line, get y location from
176 		// it (to reflect proper ascent).
177 		if (pPropRun->getLine() == getLine())
178 		{
179 			if(FPRUN_TEXT == pPropRun->getType())
180 			{
181 				pPropRun->findPointCoords(iOffset, x, y, x2, y2, height, bDirection);
182 				return;
183 			}
184 		}
185 	}
186 
187 	getLine()->getOffsets(this, x, y);
188 	x2 = x;
189 	y2 = y;
190 	bDirection = (getVisDirection() != UT_BIDI_LTR);
191 }
192 
_clearScreen(bool)193 void fp_DirectionMarkerRun::_clearScreen(bool /* bFullLineHeightRect */)
194 {
195 	UT_return_if_fail(getGraphics()->queryProperties(GR_Graphics::DGP_SCREEN));
196 
197 	GR_Painter painter(getGraphics());
198 
199 	if(getWidth())
200 	{
201 		UT_sint32 xoff = 0, yoff = 0;
202 		getLine()->getScreenOffsets(this, xoff, yoff);
203 
204 		if(getVisDirection() == UT_BIDI_RTL)
205 		{
206 			xoff -= m_iDrawWidth;
207 		}
208 		painter.fillRect(_getColorPG(), xoff, yoff+1, m_iDrawWidth, getLine()->getHeight()+1);
209 	}
210 }
211 
212 /*!
213   Draw Direction marker graphical representation
214   \param pDA Draw arguments
215   Draws the < or > character in show paragraphs mode.
216 */
_draw(dg_DrawArgs * pDA)217 void fp_DirectionMarkerRun::_draw(dg_DrawArgs* pDA)
218 {
219 	// if showPara is turned off we will not draw anything at all; however,
220 	// we will ensure that the width is set to 0, and if it is currently not
221 	// we will get our line to redo its layout and redraw.
222 	FV_View* pView = _getView();
223     if(!pView || !pView->getShowPara())
224     {
225     	return;
226     }
227 
228 	GR_Painter painter(getGraphics());
229 
230 	UT_ASSERT_HARMLESS(pDA->pG == getGraphics());
231 
232 	UT_uint32 iRunBase = getBlock()->getPosition() + getBlockOffset();
233 
234 	UT_uint32 iSelAnchor = pView->getSelectionAnchor();
235 	UT_uint32 iPoint = pView->getPoint();
236 
237 	UT_uint32 iSel1 = UT_MIN(iSelAnchor, iPoint);
238 	UT_uint32 iSel2 = UT_MAX(iSelAnchor, iPoint);
239 
240 	UT_ASSERT_HARMLESS(iSel1 <= iSel2);
241 
242 	bool bIsSelected = false;
243 	if (/* pView->getFocus()!=AV_FOCUS_NONE && */	(iSel1 <= iRunBase) && (iSel2 > iRunBase))
244 		bIsSelected = true;
245 
246 	UT_sint32 iAscent;
247 
248 	fp_Run* pPropRun = _findPrevPropertyRun();
249 	if (pPropRun && (FPRUN_TEXT == pPropRun->getType()))
250 	{
251 		fp_TextRun* pTextRun = static_cast<fp_TextRun*>(pPropRun);
252 		getGraphics()->setFont(pTextRun->getFont());
253 		iAscent = pTextRun->getAscent();
254 	}
255 	else
256 	{
257 		const PP_AttrProp * pSpanAP = NULL;
258 		const PP_AttrProp * pBlockAP = NULL;
259 		const PP_AttrProp * pSectionAP = NULL;
260 		getSpanAP(pSpanAP);
261 		getBlockAP(pBlockAP);
262 		// look for fonts in this DocLayout's font cache
263 		FL_DocLayout * pLayout = getBlock()->getDocLayout();
264 
265 		const GR_Font * pFont = pLayout->findFont(pSpanAP,pBlockAP,pSectionAP);
266 		getGraphics()->setFont(pFont);
267 		iAscent = getGraphics()->getFontAscent();
268 	}
269 
270 	// if we currently have a 0 width, i.e., we draw in response to the
271 	// showPara being turned on, then we obtain the new width, and then
272 	// tell the line to redo its layout and redraw instead of drawing ourselves
273 	UT_UCS4Char cM = m_iMarker == UCS_LRM ? (UT_UCS4Char)'>' : (UT_UCS4Char)'<';
274 	m_iDrawWidth  = getGraphics()->measureString(&cM, 0, 1, NULL);
275 
276 	_setHeight(getGraphics()->getFontHeight());
277 	m_iXoffText = pDA->xoff;
278 
279 	m_iYoffText = pDA->yoff - iAscent;
280 	xxx_UT_DEBUGMSG(("fp_DirectionMarkerRun::draw: width %d\n", m_iDrawWidth));
281 
282 	if (bIsSelected)
283 	{
284 		painter.fillRect(_getView()->getColorSelBackground(),
285 						  m_iXoffText,
286 						  m_iYoffText,
287 						  m_iDrawWidth,
288 						  getLine()->getHeight());
289 	}
290 	else
291 	{
292 		painter.fillRect(_getColorPG(),
293 						  m_iXoffText,
294 						  m_iYoffText,
295 						  m_iDrawWidth,
296 						  getLine()->getHeight());
297 	}
298 	if (pView->getShowPara())
299 	{
300 		// Draw symbol
301 		// use the hard-coded colour only if not revised
302 		if(!getRevisions())
303 			getGraphics()->setColor(pView->getColorShowPara());
304         painter.drawChars(&cM, 0, 1, m_iXoffText, m_iYoffText);
305 	}
306 }
307