1 /* AbiWord
2 * Copyright (C) 1998 AbiSource, Inc.
3 * Copyright (C) 2002 Patrick Lam <plam@mit.edu>
4 * Copyright (C) 2003 Martin Sevior <msevior@physics.unimelb.edu.au>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 * 02110-1301 USA.
20 */
21
22 #include <stdlib.h>
23 #include <math.h>
24 #include <string.h>
25
26 #include "fp_FrameContainer.h"
27 #include "fp_Column.h"
28 #include "fp_Page.h"
29 #include "fp_Line.h"
30 #include "fl_DocLayout.h"
31 #include "pd_Document.h"
32 #include "fl_SectionLayout.h"
33 #include "gr_DrawArgs.h"
34 #include "ut_vector.h"
35 #include "ut_types.h"
36 #include "ut_debugmsg.h"
37 #include "ut_assert.h"
38 #include "fl_FrameLayout.h"
39 #include "fp_TableContainer.h"
40 #include "fv_View.h"
41 #include "gr_Painter.h"
42 #include "fl_BlockLayout.h"
43
44 /*!
45 Create Frame container
46 \param iType Container type
47 \param pSectionLayout Section layout type used for this container
48 */
fp_FrameContainer(fl_SectionLayout * pSectionLayout)49 fp_FrameContainer::fp_FrameContainer(fl_SectionLayout* pSectionLayout)
50 : fp_VerticalContainer(FP_CONTAINER_FRAME, pSectionLayout),
51 m_pPage(NULL),
52 m_iXpad(0),
53 m_iYpad(0),
54 m_bNeverDrawn(true),
55 m_bOverWrote(false),
56 m_bIsWrapped(false),
57 m_bIsTightWrapped(false),
58 m_bIsAbove(true),
59 m_bIsTopBot(false),
60 m_bIsLeftWrapped(false),
61 m_bIsRightWrapped(false),
62 m_iPreferedPageNo(-1),
63 m_iPreferedColumnNo(0)
64 {
65 }
66
67 /*!
68 Destruct container
69 \note The Containers in vector of the container are not
70 destructed. They are owned by the logical hierarchy (i.e.,
71 the fl_Container classes like fl_BlockLayout), not the physical
72 hierarchy.
73 */
~fp_FrameContainer()74 fp_FrameContainer::~fp_FrameContainer()
75 {
76 UT_DEBUGMSG(("Delete FrameContainer %p \n",this));
77 m_pPage = NULL;
78 }
79
setPage(fp_Page * pPage)80 void fp_FrameContainer::setPage(fp_Page * pPage)
81 {
82 if(pPage && (m_pPage != NULL) && m_pPage != pPage)
83 {
84 clearScreen();
85 m_pPage->removeFrameContainer(this);
86 getSectionLayout()->markAllRunsDirty();
87
88 UT_GenericVector<fl_ContainerLayout *> AllLayouts;
89 AllLayouts.clear();
90 m_pPage->getAllLayouts(AllLayouts);
91 UT_sint32 i = 0;
92 for(i=0; i<AllLayouts.getItemCount(); i++)
93 {
94 fl_ContainerLayout * pCL = AllLayouts.getNthItem(i);
95 pCL->collapse();
96 pCL->format();
97 }
98 m_pPage->getOwningSection()->setNeedsSectionBreak(true,m_pPage);
99
100 }
101 m_pPage = pPage;
102 if(pPage)
103 {
104 getFillType().setParent(&pPage->getFillType());
105 }
106 else
107 {
108 getFillType().setParent(NULL);
109 }
110 }
111
112
isAbove(void)113 bool fp_FrameContainer::isAbove(void)
114 {
115 return m_bIsAbove;
116 }
117 /*!
118 * Returns true if the supplied screen rectangle overlaps with frame
119 * container. This method takes account of transparening and tight wrapping.
120 */
overlapsRect(UT_Rect & rec)121 bool fp_FrameContainer::overlapsRect(UT_Rect & rec)
122 {
123 UT_Rect * pMyFrameRec = getScreenRect();
124 fl_FrameLayout * pFL = static_cast<fl_FrameLayout *>(getSectionLayout());
125 UT_sint32 iextra = pFL->getBoundingSpace() -2;
126 pMyFrameRec->left -= iextra;
127 pMyFrameRec->top -= iextra;
128 pMyFrameRec->width += 2*iextra;
129 pMyFrameRec->height += 2*iextra;
130 xxx_UT_DEBUGMSG(("look at rec.left %d top %d width %d \n",rec.left,rec.top,rec.width));
131 if(rec.intersectsRect(pMyFrameRec))
132 {
133 if(!isTightWrapped())
134 {
135 delete pMyFrameRec;
136 return true;
137 }
138 UT_sint32 iTweak = getGraphics()->tlu(2);
139 pMyFrameRec->left += iextra + iTweak;
140 pMyFrameRec->top += iextra + iTweak;
141 pMyFrameRec->width -= (2*iextra + 2*iTweak);
142 pMyFrameRec->height -= (2*iextra + 2*iTweak);
143
144 UT_sint32 y = rec.top - pMyFrameRec->top;
145 UT_sint32 h = rec.height;
146 if(pFL->getBackgroundImage() == NULL)
147 {
148 delete pMyFrameRec;
149 return true;
150 }
151 UT_sint32 pad = pFL->getBoundingSpace();
152 UT_sint32 iLeft = pFL->getBackgroundImage()->GetOffsetFromLeft(getGraphics(),pad,y,h);
153 xxx_UT_DEBUGMSG(("iLeft projection %d \n",iLeft));
154 if(iLeft < -getWidth())
155 {
156 //
157 // Pure transparent.
158 //
159 xxx_UT_DEBUGMSG(("Overlaps pure transparent line top %d line height %d image top %d \n",rec.top,rec.height,y));
160 delete pMyFrameRec;
161 return false;
162 }
163 xxx_UT_DEBUGMSG(("iLeft in overlapRect %d Y %d \n",iLeft,y));
164 if(rec.left < pMyFrameRec->left)
165 {
166 pMyFrameRec->left -= iLeft;
167 xxx_UT_DEBUGMSG(("Moves Image left border by %d to %d \n",-iLeft,pMyFrameRec->left));
168 }
169 else
170 {
171 UT_sint32 iRight = pFL->getBackgroundImage()->GetOffsetFromRight(getGraphics(),pad,y,h);
172 pMyFrameRec->width += iRight;
173 xxx_UT_DEBUGMSG(("Reduce Image width by %d to %d \n",iRight,pMyFrameRec->width));
174 }
175 if(rec.intersectsRect(pMyFrameRec))
176 {
177 xxx_UT_DEBUGMSG(("Frame Still overlaps \n"));
178 delete pMyFrameRec;
179 return true;
180 }
181 xxx_UT_DEBUGMSG(("Tight Frame no longer overlaps \n"));
182 xxx_UT_DEBUGMSG(("Line Top %d Height %d left %d width %d \n",rec.top,rec.height,rec.left,rec.width));
183 xxx_UT_DEBUGMSG(("Image Top %d Height %d left %d width %d \n",pMyFrameRec->top,pMyFrameRec->height,pMyFrameRec->left,pMyFrameRec->width));
184 xxx_UT_DEBUGMSG(("Relative Top of line %d \n",y));
185 }
186 delete pMyFrameRec;
187 return false;
188 }
189
setPreferedPageNo(UT_sint32 i)190 void fp_FrameContainer::setPreferedPageNo(UT_sint32 i)
191 {
192 if(m_iPreferedPageNo == i)
193 return;
194 m_iPreferedPageNo = i;
195 fl_FrameLayout * pFL = static_cast<fl_FrameLayout *>(getSectionLayout());
196 FL_DocLayout * pDL = pFL->getDocLayout();
197 if(pDL->isLayoutFilling())
198 return;
199 PD_Document * pDoc = pDL->getDocument();
200 UT_UTF8String sVal;
201 UT_UTF8String_sprintf(sVal,"%d",i);
202 const char * attr = PT_PROPS_ATTRIBUTE_NAME;
203 UT_UTF8String sAttVal = "frame-pref-page:";
204 sAttVal += sVal.utf8_str();
205
206 pDoc->changeStruxAttsNoUpdate(pFL->getStruxDocHandle(),attr,sAttVal.utf8_str());
207 }
208
setPreferedColumnNo(UT_sint32 i)209 void fp_FrameContainer::setPreferedColumnNo(UT_sint32 i)
210 {
211 if(m_iPreferedColumnNo == i)
212 return;
213 m_iPreferedColumnNo = i;
214 fl_FrameLayout * pFL = static_cast<fl_FrameLayout *>(getSectionLayout());
215 FL_DocLayout * pDL = pFL->getDocLayout();
216 if(pDL->isLayoutFilling())
217 return;
218 PD_Document * pDoc = pDL->getDocument();
219 UT_UTF8String sVal;
220 UT_UTF8String_sprintf(sVal,"%d",i);
221 const char * attr = PT_PROPS_ATTRIBUTE_NAME;
222 UT_UTF8String sAttVal = "frame-pref-column:";
223 sAttVal += sVal.utf8_str();
224
225 pDoc->changeStruxAttsNoUpdate(pFL->getStruxDocHandle(),attr,sAttVal.utf8_str());
226 }
227
228 /*!
229 * This method returns the padding to be applied between a line approaching
230 * wrapped frame or image from the left.
231 * y Is the top of the line in logical units as defined relative to the
232 * y position on the screen.
233 * height is the height of the line.
234 * If tight wrapping is set on a positioned object this number can be negative
235 * which means the line can encroach into the rectangular region of the
236 * image provided the region is transparent.
237 */
getLeftPad(UT_sint32 y,UT_sint32 height)238 UT_sint32 fp_FrameContainer::getLeftPad(UT_sint32 y, UT_sint32 height)
239 {
240 fl_FrameLayout *pFL = static_cast<fl_FrameLayout *>(getSectionLayout());
241 UT_sint32 pad = pFL->getBoundingSpace();
242 UT_Rect * pRect = getScreenRect();
243 UT_sint32 yC = pRect->top;
244 delete pRect;
245 if(!isTightWrapped() || !isWrappingSet())
246 {
247 return pad;
248 }
249 if(FL_FRAME_TEXTBOX_TYPE == pFL->getFrameType())
250 {
251 return pad;
252 }
253 if(pFL->getBackgroundImage() == NULL)
254 {
255 return pad;
256 }
257 UT_sint32 iLeft = pFL->getBackgroundImage()->GetOffsetFromLeft(getGraphics(),pad,y - yC,height);
258 xxx_UT_DEBUGMSG(("Local Y %d iLeft %d width %d \n",y-yC,iLeft,getFullWidth())); return iLeft;
259 }
260
261
262 /*!
263 * This method returns the padding to be applied between a line approaching
264 * wrapped frame or image from the right.
265 * y Is the top of the line in logical units as defined relative to the
266 * y position on the screen.
267 * height is the height of the line.
268 * If tight wrapping is set on a positioned object this number can be negative
269 * which means the line can encroach into the rectangular region of the
270 * image provided the region is transparent.
271 */
getRightPad(UT_sint32 y,UT_sint32 height)272 UT_sint32 fp_FrameContainer::getRightPad(UT_sint32 y, UT_sint32 height)
273 {
274 fl_FrameLayout *pFL = static_cast<fl_FrameLayout *>(getSectionLayout());
275 UT_sint32 pad = pFL->getBoundingSpace();
276 UT_Rect * pRect = getScreenRect();
277 UT_sint32 yC = pRect->top;
278 if(!isTightWrapped() || !isWrappingSet())
279 {
280 return pad;
281 }
282 if(FL_FRAME_TEXTBOX_TYPE == pFL->getFrameType())
283 {
284 return pad;
285 }
286 if(pFL->getBackgroundImage() == NULL)
287 {
288 return pad;
289 }
290 UT_sint32 iRight = pFL->getBackgroundImage()->GetOffsetFromRight(getGraphics(),pad,y - yC,height);
291 xxx_UT_DEBUGMSG(("Local Y %d iRight %d width %d \n",y-yC,iRight,getFullWidth()));
292 return iRight;
293 }
294
clearScreen(void)295 void fp_FrameContainer::clearScreen(void)
296 {
297 fp_Page * pPage = getPage();
298 if(pPage == NULL)
299 {
300 return;
301 }
302 if(getView() == NULL)
303 {
304 return;
305 }
306
307 UT_sint32 srcX,srcY;
308 UT_sint32 xoff,yoff;
309 getView()->getPageScreenOffsets(pPage,xoff,yoff);
310 xxx_UT_DEBUGMSG(("pagescreenoffsets xoff %d yoff %d \n",xoff,yoff));
311 UT_sint32 leftThick = m_lineLeft.m_thickness;
312 UT_sint32 rightThick = m_lineRight.m_thickness;
313 UT_sint32 topThick = m_lineTop.m_thickness;
314 UT_sint32 botThick = m_lineBottom.m_thickness;
315
316 srcX = getFullX() - leftThick;
317 srcY = getFullY() - topThick;
318
319 xoff += getFullX() - leftThick;
320 yoff += getFullY() - topThick;
321 getFillType().getParent()->Fill(getGraphics(),srcX,srcY,xoff,yoff,getFullWidth()+leftThick+rightThick,getFullHeight()+topThick+botThick+getGraphics()->tlu(1) +1);
322 fp_Container * pCon = NULL;
323 UT_sint32 i = 0;
324 for(i=0; i< countCons(); i++)
325 {
326 pCon = static_cast<fp_Container *>(getNthCon(i));
327 pCon->clearScreen();
328 }
329 m_bNeverDrawn = true;
330 }
331
332 /*!
333 * All these methods are used to implement an X and Y padding around the
334 * Frame
335 */
getFullWidth(void) const336 UT_sint32 fp_FrameContainer::getFullWidth(void) const
337 {
338 return fp_VerticalContainer::getWidth();
339 }
340
getFullHeight(void) const341 UT_sint32 fp_FrameContainer::getFullHeight(void) const
342 {
343 return fp_VerticalContainer::getHeight();
344 }
345
getFullX(void) const346 UT_sint32 fp_FrameContainer::getFullX(void) const
347 {
348 return fp_VerticalContainer::getX();
349 }
350
getFullY(void) const351 UT_sint32 fp_FrameContainer::getFullY(void) const
352 {
353 return fp_VerticalContainer::getY();
354 }
355
356
getWidth(void) const357 UT_sint32 fp_FrameContainer::getWidth(void) const
358 {
359 UT_sint32 iWidth = fp_VerticalContainer::getWidth() - m_iXpad*2;
360 return iWidth;
361 }
362
getX(void) const363 UT_sint32 fp_FrameContainer::getX(void) const
364 {
365 UT_sint32 iX = fp_VerticalContainer::getX() + m_iXpad;
366 return iX;
367 }
368
369
getY(void) const370 UT_sint32 fp_FrameContainer::getY(void) const
371 {
372 UT_sint32 iY = fp_VerticalContainer::getY() + m_iYpad;
373 return iY;
374 }
375
getHeight(void) const376 UT_sint32 fp_FrameContainer::getHeight(void) const
377 {
378 UT_sint32 iHeight = fp_VerticalContainer::getHeight() - m_iYpad*2;
379 return iHeight;
380 }
381
382
setContainer(fp_Container *)383 void fp_FrameContainer::setContainer(fp_Container * /*pContainer*/)
384 {
385 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
386 }
387
getDocSectionLayout(void)388 fl_DocSectionLayout * fp_FrameContainer::getDocSectionLayout(void)
389 {
390 fl_FrameLayout * pFL = static_cast<fl_FrameLayout *>(getSectionLayout());
391 fl_DocSectionLayout * pDSL = static_cast<fl_DocSectionLayout *>(pFL->getSectionLayout());
392 UT_ASSERT(pDSL && (pDSL->getContainerType() == FL_CONTAINER_DOCSECTION));
393 return pDSL;
394 }
395
396 /*!
397 * Fill the supplied vector with a list of the blocks whose lines are affected
398 * by the Frame.
399 */
getBlocksAroundFrame(UT_GenericVector<fl_BlockLayout * > & vecBlocks)400 void fp_FrameContainer::getBlocksAroundFrame(UT_GenericVector<fl_BlockLayout *> & vecBlocks)
401 {
402 fp_Page * pPage = getPage();
403 if(pPage == NULL)
404 {
405 return;
406 }
407 UT_sint32 iColLeader = 0;
408 fp_Column * pCol = NULL;
409 fl_BlockLayout * pCurBlock = NULL;
410 fp_Line * pCurLine = NULL;
411 fp_Container * pCurCon = NULL;
412 if(pPage->countColumnLeaders() == 0)
413 {
414 UT_sint32 iPage = getPreferedPageNo();
415 if(iPage >0)
416 setPreferedPageNo(iPage-1);
417 return;
418 }
419 for(iColLeader = 0; iColLeader < pPage->countColumnLeaders(); iColLeader++)
420 {
421 pCol = pPage->getNthColumnLeader(iColLeader);
422 while(pCol)
423 {
424 UT_sint32 i = 0;
425 UT_sint32 iYCol = pCol->getY(); // Vertical position relative to page.
426 for(i=0; i< pCol->countCons(); i++)
427 {
428 pCurCon = static_cast<fp_Container *>(pCol->getNthCon(i));
429 if(pCurCon->getContainerType() == FP_CONTAINER_LINE)
430 {
431 pCurLine = static_cast<fp_Line *>(pCurCon);
432 UT_sint32 iYLine = iYCol + pCurLine->getY();
433 xxx_UT_DEBUGMSG(("iYLine %d FullY %d FullHeight %d \n",iYLine,getFullY(),getFullHeight()));
434 if((iYLine + pCurLine->getHeight() > getFullY()) && (iYLine < (getFullY() + getFullHeight())))
435 {
436 //
437 // Line overlaps frame in Height. Add it's block to the vector.
438 //
439 if(pCurLine->getBlock() != pCurBlock)
440 {
441 pCurBlock = pCurLine->getBlock();
442 vecBlocks.addItem(pCurBlock);
443 xxx_UT_DEBUGMSG(("Add Block %x to vector \n",pCurBlock));
444 }
445 }
446 }
447 }
448 pCol = pCol->getFollower();
449 }
450 }
451 if(vecBlocks.getItemCount() == 0)
452 {
453 pCol = pPage->getNthColumnLeader(0);
454 fp_Container * pCon = pCol->getFirstContainer();
455 fl_BlockLayout * pB = NULL;
456 if(pCon && pCon->getContainerType() == FP_CONTAINER_LINE)
457 {
458 pB = static_cast<fp_Line *>(pCon)->getBlock();
459 }
460 else if(pCon)
461 {
462 fl_ContainerLayout * pCL = static_cast<fl_ContainerLayout *>(pCon->getSectionLayout());
463 pB = pCL->getNextBlockInDocument();
464 }
465 if(pB != NULL)
466 vecBlocks.addItem(pB);
467 }
468
469 }
470
471 /* just a little helper function
472 */
_drawLine(const PP_PropertyMap::Line & style,UT_sint32 left,UT_sint32 top,UT_sint32 right,UT_sint32 bot,GR_Graphics * pGr)473 void fp_FrameContainer::_drawLine (const PP_PropertyMap::Line & style,
474 UT_sint32 left, UT_sint32 top, UT_sint32 right, UT_sint32 bot,GR_Graphics * pGr)
475 {
476 GR_Painter painter(pGr);
477
478 if (style.m_t_linestyle == PP_PropertyMap::linestyle_none)
479 return; // do not draw
480
481 GR_Graphics::JoinStyle js = GR_Graphics::JOIN_MITER;
482 GR_Graphics::CapStyle cs = GR_Graphics::CAP_PROJECTING;
483
484 UT_sint32 iLineWidth = static_cast<UT_sint32>(style.m_thickness);
485 pGr->setLineWidth (iLineWidth);
486 pGr->setColor (style.m_color);
487
488 switch (style.m_t_linestyle)
489 {
490 case PP_PropertyMap::linestyle_dotted:
491 pGr->setLineProperties (iLineWidth, js, cs, GR_Graphics::LINE_DOTTED);
492 break;
493 case PP_PropertyMap::linestyle_dashed:
494 pGr->setLineProperties (iLineWidth, js, cs, GR_Graphics::LINE_ON_OFF_DASH);
495 break;
496 case PP_PropertyMap::linestyle_solid:
497 pGr->setLineProperties (iLineWidth, js, cs, GR_Graphics::LINE_SOLID);
498 break;
499 default: // do nothing; shouldn't happen
500 break;
501 }
502
503 xxx_UT_DEBUGMSG(("_drawLine: top %d bot %d \n",top,bot));
504
505 painter.drawLine (left, top, right, bot);
506
507 pGr->setLineProperties (pGr->tlu(1), js, cs, GR_Graphics::LINE_SOLID);
508 }
509
510 /*!
511 * Draw the frame boundaries
512 */
drawBoundaries(dg_DrawArgs * pDA)513 void fp_FrameContainer::drawBoundaries(dg_DrawArgs * pDA)
514 {
515 UT_sint32 iXlow = pDA->xoff - m_iXpad;
516 UT_sint32 iXhigh = iXlow + getFullWidth() ;
517 UT_sint32 iYlow = pDA->yoff - m_iYpad;
518 UT_sint32 iYhigh = iYlow + getFullHeight();
519 GR_Graphics * pG = pDA->pG;
520 if(getPage())
521 {
522 getPage()->expandDamageRect(iXlow,iYlow,getFullWidth(),getFullHeight());
523
524 //
525 // Only fill to the bottom of the viewed page.
526 //
527 UT_sint32 iFullHeight = getFullHeight();
528 fl_DocSectionLayout * pDSL = getDocSectionLayout();
529 UT_sint32 iMaxHeight = 0;
530 if(!pG->queryProperties(GR_Graphics::DGP_PAPER) && (getView()->getViewMode() != VIEW_PRINT))
531 {
532 iMaxHeight = pDSL->getActualColumnHeight();
533 }
534 else
535 {
536 iMaxHeight = getPage()->getHeight();
537 }
538 UT_sint32 iBot = getFullY()+iFullHeight;
539 if(iBot > iMaxHeight)
540 {
541 iFullHeight = iFullHeight - (iBot-iMaxHeight);
542 iYhigh = iFullHeight;
543 }
544 }
545 _drawLine(m_lineTop,iXlow,iYlow,iXhigh,iYlow,pDA->pG); // top
546 _drawLine(m_lineRight,iXhigh,iYlow,iXhigh,iYhigh,pDA->pG); // right
547 _drawLine(m_lineBottom,iXlow,iYhigh,iXhigh,iYhigh,pDA->pG); // bottom
548 _drawLine(m_lineLeft,iXlow,iYlow,iXlow,iYhigh,pDA->pG); // left
549 }
550
551
552 /*!
553 * Draw the frame handles
554 */
drawHandles(dg_DrawArgs * pDA)555 void fp_FrameContainer::drawHandles(dg_DrawArgs * pDA)
556 {
557 if(getView() == NULL)
558 {
559 getSectionLayout()->format();
560 getSectionLayout()->setNeedsReformat(getSectionLayout());
561 }
562 if(getView() == NULL)
563 {
564 return;
565 }
566 if(!getPage())
567 {
568 return;
569 }
570 //
571 // Only fill to the bottom of the viewed page.
572 //
573 GR_Graphics * pG = pDA->pG;
574 UT_sint32 iFullHeight = getFullHeight();
575 fl_DocSectionLayout * pDSL = getDocSectionLayout();
576 UT_sint32 iMaxHeight = 0;
577 if(!pG->queryProperties(GR_Graphics::DGP_PAPER) && (getView()->getViewMode() != VIEW_PRINT))
578 {
579 iMaxHeight = pDSL->getActualColumnHeight();
580 }
581 else
582 {
583 iMaxHeight = getPage()->getHeight();
584 }
585 UT_sint32 iBot = getFullY()+iFullHeight;
586 if(iBot > iMaxHeight)
587 {
588 iFullHeight = iFullHeight - (iBot-iMaxHeight);
589 }
590 UT_sint32 iXlow = pDA->xoff - m_iXpad;
591 UT_sint32 iYlow = pDA->yoff - m_iYpad;
592
593 UT_Rect box(iXlow + pDA->pG->tlu(2), iYlow + pDA->pG->tlu(2), getFullWidth() - pDA->pG->tlu(4), iFullHeight - pDA->pG->tlu(4));
594 getPage()->expandDamageRect(box.left,box.top,box.width,box.height);
595 getView()->drawSelectionBox(box, true);
596 }
597
598 /*!
599 Draw container content
600 \param pDA Draw arguments
601 */
draw(dg_DrawArgs * pDA)602 void fp_FrameContainer::draw(dg_DrawArgs* pDA)
603 {
604 FV_View * pView = getView();
605 UT_return_if_fail( pView);
606
607 xxx_UT_DEBUGMSG(("FrameContainer %x called, page %x \n",this,getPage()));
608 if(getPage() == NULL)
609 {
610 getSectionLayout()->format();
611 getSectionLayout()->setNeedsReformat(getSectionLayout());
612 if(getPage() == NULL)
613 {
614 return;
615 }
616 }
617 if(pView)
618 {
619 if(pView->getFrameEdit()->getFrameEditMode() == FV_FrameEdit_DRAG_EXISTING)
620 {
621 if((pView->getFrameEdit()->getFrameContainer() == this))
622 {
623 return;
624 }
625 }
626 }
627 //
628 // Only draw the lines in the clipping region.
629 //
630 /*
631 [Somewhere down here is where the logic to only draw the region of the frame which
632 is within the complement of the union of all higher frames needs to be. We need to
633 draw the applicable region of the rectangle we're on, then unify it with (if
634 applicable) the higher union.] <-- Possibly obsolete comment, not sure.
635 I think I might have landed on an alternative solution involving more rearranging
636 of the storage of the FrameContainers, based on their z-index. Not sure how far
637 I got with that or if it worked either. See also abi bug 7664 and the original
638 discussions about defining the undefinedness of layered frame behaviour.
639 */
640
641 if(m_bOverWrote)
642 {
643 pDA->bDirtyRunsOnly = false;
644 }
645 dg_DrawArgs da = *pDA;
646 GR_Graphics * pG = da.pG;
647 UT_return_if_fail( pG);
648
649 UT_sint32 x = pDA->xoff - m_iXpad;
650 UT_sint32 y = pDA->yoff - m_iYpad;
651 getPage()->expandDamageRect(x,y,getFullWidth(),getFullHeight());
652 if(!pDA->bDirtyRunsOnly || m_bNeverDrawn)
653 {
654 if(m_bNeverDrawn)
655 {
656 pDA->bDirtyRunsOnly= false;
657 }
658 UT_sint32 srcX,srcY;
659 getSectionLayout()->checkGraphicTick(pG);
660 srcX = -m_iXpad;
661 srcY = -m_iYpad;
662 //
663 // Only fill to the bottom of the viewed page.
664 //
665 UT_sint32 iFullHeight = getFullHeight();
666 fl_DocSectionLayout * pDSL = getDocSectionLayout();
667 UT_sint32 iMaxHeight = 0;
668 if(!pG->queryProperties(GR_Graphics::DGP_PAPER) && (pView->getViewMode() != VIEW_PRINT))
669 {
670 iMaxHeight = pDSL->getActualColumnHeight();
671 }
672 else
673 {
674 iMaxHeight = getPage()->getHeight();
675 }
676 UT_sint32 iBot = getFullY()+iFullHeight;
677 if(iBot > iMaxHeight)
678 {
679 iFullHeight = iFullHeight - (iBot-iMaxHeight);
680 }
681 getFillType().Fill(pG,srcX,srcY,x,y,getFullWidth(),iFullHeight);
682 m_bNeverDrawn = false;
683 }
684 UT_uint32 count = countCons();
685 xxx_UT_DEBUGMSG(("Number of containers in frame %d \n",count));
686 auto p = pDA->pG->getClipRect();
687 std::unique_ptr<UT_Rect> pPrevRect(p ? new UT_Rect(*p) : nullptr);
688 UT_Rect * pRect = getScreenRect();
689 UT_Rect newRect;
690 bool bRemoveRectAfter = false;
691 bool bSetOrigClip = false;
692 bool bSkip = false;
693 if((pPrevRect == NULL) && pG->queryProperties(GR_Graphics::DGP_SCREEN))
694 {
695 pDA->pG->setClipRect(pRect);
696 UT_DEBUGMSG(("Clip bottom is %d \n",pRect->top + pRect->height));
697 bRemoveRectAfter = true;
698 }
699 else if(pPrevRect && !pRect->intersectsRect(pPrevRect.get()))
700 {
701 bSkip = true;
702 xxx_UT_DEBUGMSG(("External Clip bottom is %d \n",pRect->top + pRect->height));
703 }
704 else if(pPrevRect)
705 {
706 newRect.top = UT_MAX(pPrevRect->top,pRect->top);
707 UT_sint32 iBotPrev = pPrevRect->height + pPrevRect->top;
708 UT_sint32 iBot = pRect->height + pRect->top;
709 newRect.height = UT_MIN(iBotPrev,iBot) - newRect.top;
710 newRect.width = pPrevRect->width;
711 newRect.left = pPrevRect->left;
712 if((newRect.height > 0) && pDA->pG->queryProperties(GR_Graphics::DGP_SCREEN))
713 {
714 pDA->pG->setClipRect(&newRect);
715 bSetOrigClip = true;
716 }
717 else
718 {
719 bSkip = true;
720 }
721 }
722 if(!bSkip)
723 {
724 for (UT_uint32 i = 0; i<count; i++)
725 {
726 fp_ContainerObject* pContainer = static_cast<fp_ContainerObject*>(getNthCon(i));
727 da.xoff = pDA->xoff + pContainer->getX();
728 da.yoff = pDA->yoff + pContainer->getY();
729 pContainer->draw(&da);
730 }
731 }
732 m_bNeverDrawn = false;
733 m_bOverWrote = false;
734 if(bRemoveRectAfter)
735 {
736 pDA->pG->setClipRect(NULL);
737 }
738 if(bSetOrigClip)
739 {
740 pDA->pG->setClipRect(pPrevRect.get());
741 }
742 delete pRect;
743 drawBoundaries(pDA);
744 }
745
setBackground(const PP_PropertyMap::Background & style)746 void fp_FrameContainer::setBackground (const PP_PropertyMap::Background & style)
747 {
748 m_background = style;
749 PP_PropertyMap::Background background = m_background;
750 if(background.m_t_background == PP_PropertyMap::background_solid)
751 {
752 getFillType().setColor(background.m_color);
753 }
754 }
755
756
757 /*!
758 * FrameContainers are not in the linked list of physical containers
759 */
getNextContainerInSection() const760 fp_Container * fp_FrameContainer::getNextContainerInSection() const
761 {
762 return NULL;
763 }
764
765 /*!
766 * FrameContainers are not in the linked list of physical containers
767 */
getPrevContainerInSection() const768 fp_Container * fp_FrameContainer::getPrevContainerInSection() const
769 {
770 return NULL;
771 }
772
layout(void)773 void fp_FrameContainer::layout(void)
774 {
775 _setMaxContainerHeight(0);
776 UT_sint32 iY = 0, iPrevY = 0;
777 iY= 0;
778 UT_uint32 iCountContainers = countCons();
779 fp_Container *pContainer, *pPrevContainer = NULL;
780 for (UT_uint32 i=0; i < iCountContainers; i++)
781 {
782 pContainer = static_cast<fp_Container*>(getNthCon(i));
783 //
784 // This is to speedup redraws.
785 //
786 if(pContainer->getHeight() > _getMaxContainerHeight())
787 _setMaxContainerHeight(pContainer->getHeight());
788
789 if(pContainer->getY() != iY)
790 {
791 pContainer->clearScreen();
792 }
793 if(iY > getHeight())
794 {
795 pContainer->setY(-1000000);
796 }
797 else
798 {
799 pContainer->setY(iY);
800 }
801 UT_sint32 iContainerHeight = pContainer->getHeight();
802 UT_sint32 iContainerMarginAfter = pContainer->getMarginAfter();
803 if(pContainer->getContainerType() == FP_CONTAINER_TABLE)
804 {
805 fp_TableContainer * pTab = static_cast<fp_TableContainer *>(pContainer);
806 iContainerHeight = pTab->getHeight();
807 if(!pTab->isThisBroken() && (pTab->getFirstBrokenTable() == NULL))
808 {
809 /*fp_Container * pBroke = static_cast<fp_Container *> */(pTab->VBreakAt(0));
810 }
811 }
812
813 iY += iContainerHeight;
814 iY += iContainerMarginAfter;
815 //iY += 0.5;
816
817 if (pPrevContainer)
818 {
819 pPrevContainer->setAssignedScreenHeight(iY - iPrevY);
820 }
821 pPrevContainer = pContainer;
822 iPrevY = iY;
823 }
824
825 // Correct height position of the last line
826 if (pPrevContainer)
827 {
828 if(iY > getHeight())
829 {
830 pPrevContainer->setAssignedScreenHeight(-1000000);
831 }
832 else
833 {
834 pPrevContainer->setAssignedScreenHeight(iY - iPrevY + 1);
835 }
836 }
837 fl_FrameLayout * pFL = static_cast<fl_FrameLayout *>(getSectionLayout());
838 if(pFL->expandHeight() && (iY > pFL->minHeight()))
839 {
840 setHeight(iY+m_iYpad*2);
841 }
842 }
843
setHeight(UT_sint32 iY)844 void fp_FrameContainer::setHeight(UT_sint32 iY)
845 {
846 if(iY != getFullHeight())
847 {
848 xxx_UT_DEBUGMSG((" SetHeight Frame iY %d Fullheight %d Height %d \n",iY,getFullHeight(),getHeight()));
849 clearScreen();
850 fp_VerticalContainer::setHeight(iY);
851 fp_Page * pPage = getPage();
852 getDocSectionLayout()->setNeedsSectionBreak(true,pPage);
853 }
854 }
855