1 /* -*- mode: C++; tab-width: 4; c-basic-offset: 4; -*- */
2 /* AbiWord
3 * Copyright (C) 1998 AbiSource, Inc.
4 *
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * as published by the Free Software Foundation; either version 2
8 * of the License, or (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 * 02110-1301 USA.
19 */
20
21 #include <stdlib.h>
22 #include <math.h>
23 #include <string.h>
24
25 #include "fp_Column.h"
26 #include "fp_Page.h"
27 #include "fp_Line.h"
28 #include "fp_TOCContainer.h"
29 #include "fl_SectionLayout.h"
30 #include "gr_DrawArgs.h"
31 #include "fp_TableContainer.h"
32 #include "fp_FootnoteContainer.h"
33 #include "fp_FrameContainer.h"
34 #include "fl_FootnoteLayout.h"
35 #include "fp_Run.h"
36 #include "fl_TOCLayout.h"
37 #include "ut_debugmsg.h"
38 #include "ut_assert.h"
39 #include "fv_View.h"
40 #include "gr_Painter.h"
41
42
43 /*!
44 Create container
45 \param iType Container type
46 \param pSectionLayout Section layout type used for this container
47 */
fp_VerticalContainer(FP_ContainerType iType,fl_SectionLayout * pSectionLayout)48 fp_VerticalContainer::fp_VerticalContainer(FP_ContainerType iType, fl_SectionLayout* pSectionLayout) :
49 fp_Container(iType, pSectionLayout),
50 m_iRedrawHeight(-1),
51 m_iWidth(0),
52 m_iHeight(0),
53 m_iMaxHeight(0),
54 m_iX(0),
55 m_iY(INITIAL_OFFSET),
56 m_bIntentionallyEmpty(0),
57 m_imaxContainerHeight(0)
58 {
59 clearWrappedLines();
60 UT_ASSERT(getDocSectionLayout());
61 }
62
63 /*!
64 Destruct container
65 \note The Containers in vector of the container are not
66 destructed. They are owned by the logical hierarchy (i.e.,
67 the fl_Container classes like fl_BlockLayout), not the physical
68 hierarchy.
69 */
~fp_VerticalContainer()70 fp_VerticalContainer::~fp_VerticalContainer()
71 {
72 }
73
74 /*!
75 Set width
76 \param iWidth Width of container
77 \todo Should force re-line-break operations on all blocks in the
78 container
79 */
setWidth(UT_sint32 iWidth)80 void fp_VerticalContainer::setWidth(UT_sint32 iWidth)
81 {
82 if (iWidth == m_iWidth)
83 {
84 return;
85 }
86 m_iWidth = iWidth;
87 if(getContainerType() != FP_CONTAINER_COLUMN)
88 {
89 getSectionLayout()->setImageWidth(iWidth);
90 getFillType().setWidth(getGraphics(),iWidth);
91 }
92
93 // TODO we really need to force a re-line-break operation on every block herein
94
95 // UT_ASSERT(UT_NOT_IMPLEMENTED);
96 }
97
98 /*!
99 * return a pointer to the current view.
100 */
getView(void) const101 FV_View * fp_VerticalContainer::getView(void) const
102 {
103 fp_Page * pPage = getPage();
104 if(pPage == NULL)
105 {
106 return NULL;
107 }
108 FL_DocLayout * pDL = pPage->getDocLayout();
109 if(pDL == NULL)
110 {
111 return NULL;
112 }
113 return pDL->getView();
114 }
115 /*!
116 Set height
117 \param iHeight Height of container
118 */
setHeight(UT_sint32 iHeight)119 void fp_VerticalContainer::setHeight(UT_sint32 iHeight)
120 {
121 if (iHeight == m_iHeight)
122 {
123 return;
124 }
125 if(getContainerType() == FP_CONTAINER_TABLE)
126 {
127 fp_TableContainer * pTab = static_cast<fp_TableContainer *>(this);
128 if(!pTab->isThisBroken())
129 {
130 UT_DEBUGMSG(("Unbroken Table container set to %d from %d \n",iHeight,pTab->getHeight()));
131 }
132 }
133 if(getContainerType() == FP_CONTAINER_TOC)
134 {
135 fp_TOCContainer * pTOC = static_cast<fp_TOCContainer *>(this);
136 if(!pTOC->isThisBroken())
137 {
138 UT_DEBUGMSG(("Unbroken TOC container set to %d from %d \n",iHeight,pTOC->getHeight()));
139 }
140 }
141 m_iHeight = iHeight;
142 if(getContainerType() != FP_CONTAINER_COLUMN)
143 {
144 if(getContainerType() == FP_CONTAINER_CELL)
145 {
146 getSectionLayout()->setImageHeight(getMaxHeight()); // was iHeight
147 }
148 getFillType().setHeight(getGraphics(),iHeight);
149 }
150 }
151
152 /*!
153 Set maximum height
154 \param iMaxHeight Maximum height of container
155 */
setMaxHeight(UT_sint32 iMaxHeight)156 void fp_VerticalContainer::setMaxHeight(UT_sint32 iMaxHeight)
157 {
158 //UT_ASSERT(iMaxHeight > 0);
159
160 if (iMaxHeight == m_iMaxHeight)
161 {
162 return;
163 }
164
165 m_iMaxHeight = iMaxHeight;
166 }
167
168 /*!
169 Get container's X position
170 \return X position
171 */
getX(void) const172 UT_sint32 fp_VerticalContainer::getX(void) const
173 {
174 return m_iX;
175 }
176
177 /*!
178 Get container's Y position.
179 \return Y position
180 */
getY(void) const181 UT_sint32 fp_VerticalContainer::getY(void) const
182 {
183 if(getSectionLayout()->getDocLayout()->getView() && (getSectionLayout()->getDocLayout()->getView()->getViewMode() != VIEW_PRINT))
184 {
185 fl_SectionLayout * pSL = getSectionLayout();
186 fl_DocSectionLayout * pDSL = NULL;
187 if(static_cast<fl_ContainerLayout *>(pSL)->getContainerType() == FL_CONTAINER_DOCSECTION)
188 {
189 pDSL = static_cast<fl_DocSectionLayout *>(pSL);
190 }
191 else
192 {
193 pDSL = static_cast<fl_DocSectionLayout *>(pSL->getDocSectionLayout());
194 }
195 if(pSL->getContainerType() == FL_CONTAINER_DOCSECTION)
196 {
197 return m_iY - pDSL->getTopMargin();
198 }
199 return m_iY;
200 }
201 return m_iY;
202 }
203 /*!
204 Get container's Y position. This version checks for a mismatch between view
205 mode and if we're printing.
206 \return Y position
207 */
getY(GR_Graphics * pG) const208 UT_sint32 fp_VerticalContainer::getY(GR_Graphics * pG) const
209 {
210 if(getSectionLayout()->getDocLayout()->getView() && (getSectionLayout()->getDocLayout()->getView()->getViewMode() != VIEW_PRINT) && pG->queryProperties(GR_Graphics::DGP_SCREEN))
211 {
212 return m_iY - static_cast<fl_DocSectionLayout *>(getSectionLayout())->getTopMargin();
213 }
214 return m_iY;
215 }
216
217 /*!
218 * This method returns the vertical offset due to a table broken
219 * across more than 1 page.
220 */
getYoffsetFromTable(fp_Container * pT,fp_Container * pCell,fp_ContainerObject * pCon)221 UT_sint32 fp_VerticalContainer::getYoffsetFromTable(fp_Container * pT,
222 fp_Container* pCell,
223 fp_ContainerObject * pCon)
224 {
225 fp_TableContainer * pFirstTable = static_cast<fp_TableContainer *>(pT)->getFirstBrokenTable();
226 fp_TableContainer * pTable = pFirstTable;
227 // UT_ASSERT(pTable);
228 UT_sint32 offset = 0;
229 bool bFound = false;
230 while(pTable != NULL && !bFound)
231 {
232 bFound = pTable->isInBrokenTable(static_cast<fp_CellContainer *>(pCell),static_cast<fp_Container *>(pCon));
233 if(bFound)
234 {
235 offset = -pTable->getYBreak();
236 }
237 pTable = static_cast<fp_TableContainer *>(pTable->getNext());
238 }
239 return offset;
240 }
241
242
243 /*!
244 * This method returns the correct broken table for this line.
245 */
getCorrectBrokenTable(fp_Container * pCon)246 fp_TableContainer * fp_VerticalContainer::getCorrectBrokenTable(fp_Container * pCon)
247 {
248 xxx_UT_DEBUGMSG(("VerticalContainer: In get Correct proken table \n"));
249 bool bFound = false;
250 fp_CellContainer * pCell = NULL;
251 if(pCon->getContainerType() == FP_CONTAINER_CELL)
252 {
253 pCell = static_cast<fp_CellContainer *>(pCon);
254 pCon = pCell->getFirstContainer();
255 }
256 else
257 {
258 pCell = static_cast<fp_CellContainer *>(pCon->getContainer());
259 if(!pCell)
260 {
261 return NULL;
262 }
263 }
264 UT_return_val_if_fail(pCell->getContainerType() == FP_CONTAINER_CELL,NULL);
265 //
266 // OK scan through the broken tables and look for the table that contains this
267 //
268 fp_Container * pCur = static_cast<fp_Container *>(pCell->getContainer());
269 UT_return_val_if_fail(pCur->getContainerType() == FP_CONTAINER_TABLE,NULL);
270 fp_TableContainer * pMasterTab = static_cast<fp_TableContainer *>(pCur);
271 UT_return_val_if_fail(pMasterTab && pMasterTab->getContainerType() == FP_CONTAINER_TABLE,NULL);
272 fp_TableContainer * pTab = pMasterTab->getFirstBrokenTable();
273 bFound = false;
274 UT_sint32 iCount =0;
275 while(pTab && !bFound)
276 {
277 xxx_UT_DEBUGMSG(("getCorrectBrokenTable YBreak %d height %d \n",pTab->getYBreak(),pTab->getHeight()));
278 if(pTab->isInBrokenTable(pCell,pCon))
279 {
280 bFound = true;
281 }
282 else
283 {
284 pTab = static_cast<fp_TableContainer *>(pTab->getNext());
285 }
286 if(!bFound)
287 {
288 iCount++;
289 }
290 }
291 if(bFound)
292 {
293 xxx_UT_DEBUGMSG(("getCorrect: Found table after %d tries \n",iCount));
294 xxx_UT_DEBUGMSG(("Container y %d height %d was found in table %d ybreak %d ybottom y %d \n",pCon->getY(),pCon->getHeight(),iCount,pTab->getYBreak(),pTab->getYBottom()));
295 return pTab;
296 }
297
298 xxx_UT_DEBUGMSG(("getCorrectBroken: No table found after %d tries, Y of Con \n",iCount,pCon->getY()));
299 if(pMasterTab)
300 {
301 // UT_ASSERT(pMasterTab->getFirstBrokenTable() == NULL);
302 }
303 return pMasterTab;
304 }
305
306
307
308 /*!
309 * This method returns the correct broken TOC for this line.
310 */
getCorrectBrokenTOC(fp_Container * pCon)311 fp_TOCContainer * fp_VerticalContainer::getCorrectBrokenTOC(fp_Container * pCon)
312 {
313 xxx_UT_DEBUGMSG(("VerticalContainer: In get Correct proken TOC \n"));
314 bool bFound = false;
315 //
316 // OK scan through the broken TOC's and look for the TOC that contains this
317 //
318 fp_Container * pCur = static_cast<fp_Container *>(pCon->getContainer());
319 UT_return_val_if_fail(pCur->getContainerType() == FP_CONTAINER_TOC,NULL);
320 fp_TOCContainer * pMasterTOC = static_cast<fp_TOCContainer *>(pCur);
321 UT_return_val_if_fail(pMasterTOC && pMasterTOC->getContainerType() == FP_CONTAINER_TOC,NULL);
322 fp_TOCContainer * pTOC = pMasterTOC->getFirstBrokenTOC();
323 bFound = false;
324 UT_sint32 iCount =0;
325 while(pTOC && !bFound)
326 {
327 if(pTOC->isInBrokenTOC(pCon))
328 {
329 bFound = true;
330 }
331 else
332 {
333 pTOC = static_cast<fp_TOCContainer *>(pTOC->getNext());
334 }
335 if(!bFound)
336 {
337 iCount++;
338 }
339 }
340 if(bFound)
341 {
342 xxx_UT_DEBUGMSG(("getCorrect: Found table after %d tries \n",iCount));
343 xxx_UT_DEBUGMSG(("Container y %d height %d was found in table %d ybreak %d ybottom y %d \n",pCon->getY(),pCon->getHeight(),iCount,pTab->getYBreak(),pTab->getYBottom()));
344 return pTOC;
345 }
346 xxx_UT_DEBUGMSG(("getCorrectBrokenTOC: NoTOC found after %d tries, Y of Con \n",iCount,pCon->getY()));
347 if(pMasterTOC)
348 {
349 // UT_ASSERT(pMasterTOC->getFirstBrokenTOC() == NULL);
350 }
351 return pMasterTOC;
352 }
353
354 /*!
355 Get line's offsets relative to this container
356 \param pContainer Container
357 \retval xoff Container's X offset relative to container
358 \retval yoff Container's Y offset relative to container
359 */
getOffsets(fp_ContainerObject * pContainer,UT_sint32 & xoff,UT_sint32 & yoff)360 void fp_VerticalContainer::getOffsets(fp_ContainerObject* pContainer, UT_sint32& xoff, UT_sint32& yoff)
361 {
362 fp_ContainerObject * pOrig = pContainer;
363 UT_sint32 my_xoff = 0;
364 UT_sint32 my_yoff = 0;
365 fp_Container * pCon = static_cast<fp_Container *>(this);
366 fp_Container * pPrev = NULL;
367 fp_TableContainer * pTab = NULL;
368 while(pCon && !pCon->isColumnType())
369 {
370 my_xoff += pCon->getX();
371 xxx_UT_DEBUGMSG(("my_xoff = %d pCon %x Type is %s \n",my_xoff,pCon,pCon->getContainerString()));
372 UT_sint32 iycon = pCon->getY();
373 my_yoff += iycon;
374 //
375 // Handle offsets from tables broken across pages.
376 //
377 // We detect
378 // line->cell->table->cell->table->cell->table->column
379 //
380 if(pCon->getContainerType() == FP_CONTAINER_TABLE)
381 {
382 fp_VerticalContainer * pVCon= static_cast<fp_VerticalContainer *>(pCon);
383 //
384 // Lines and Cells are actually always in the Master table. To make
385 // Them print on the right pages broken tables are created which
386 // sit in different columns. Here we hijack the recursive search and
387 // move it up the correct broken table line when we come across a cell
388 //
389 pVCon = getCorrectBrokenTable(static_cast<fp_Container *>(pContainer));
390 if(pPrev && pPrev->getContainerType() == FP_CONTAINER_CELL)
391 {
392 UT_sint32 iTable = getYoffsetFromTable(pCon,pPrev,pContainer);
393 my_yoff += iTable;
394 pTab = static_cast<fp_TableContainer *>(pVCon);
395 if(pTab->isThisBroken() && (pTab != pTab->getMasterTable()->getFirstBrokenTable()))
396 {
397 my_yoff = my_yoff + pVCon->getY() -iycon;
398 }
399 }
400 if(pVCon && pVCon->getContainer() && (pVCon->getContainer()->getContainerType() == FP_CONTAINER_CELL))
401 {
402 pContainer = static_cast<fp_Container *>(pVCon);
403 xxx_UT_DEBUGMSG(("pContainer set to %p height %d \n",pContainer,pContainer->getHeight()));
404 }
405 else if(pVCon && (pVCon->getContainer() == NULL))
406 {
407 //
408 // Just bail out for now
409 //
410 return;
411 }
412 if(pVCon == NULL)
413 {
414 pCon = NULL;
415 break;
416 }
417 pCon = static_cast<fp_Container *>(pVCon);
418 }
419 if(pCon->getContainerType() == FP_CONTAINER_TOC)
420 {
421 fp_VerticalContainer * pVCon= static_cast<fp_VerticalContainer *>(pCon);
422 //
423 // Lines and Cells are actually always in the Master table. To make
424 // Them print on the right pages broken tables are created which
425 // sit in different columns. Here we hijack the recursive search and
426 // move it up the correct broken table line when we come across a cell
427 //
428 pVCon = getCorrectBrokenTOC(static_cast<fp_Container *>(pContainer));
429 pCon = static_cast<fp_Container *>(pVCon);
430 }
431 pPrev = pCon;
432 pCon = pCon->getContainer();
433 }
434 if(pCon && pCon->getContainerType() == FP_CONTAINER_HDRFTR)
435 {
436 fl_HdrFtrSectionLayout* pHFSL = static_cast<fp_HdrFtrContainer *>(pCon)->getHdrFtrSectionLayout();
437 fp_Page * pPage = getPage();
438 fl_HdrFtrShadow * pShadowL = NULL;
439 if(pPage == NULL)
440 {
441 pShadowL = pHFSL->getFirstShadow();
442 }
443 else
444 {
445 pShadowL = pHFSL->findShadow(pPage);
446 }
447 if(pShadowL == NULL)
448 {
449 return;
450 }
451 // UT_ASSERT(pShadowL);
452 if(pShadowL)
453 {
454 pCon = static_cast<fp_Container *>(pShadowL->getFirstContainer());
455 }
456 else
457 {
458 return;
459 }
460 }
461
462 UT_sint32 col_x =0;
463 UT_sint32 col_y =0;
464 if(pPrev && ((pPrev->getContainerType() == FP_CONTAINER_TABLE) ||
465 (pPrev->getContainerType() == FP_CONTAINER_TOC)))
466 {
467 if(pCon->getContainerType() == FP_CONTAINER_COLUMN)
468 {
469 UT_sint32 col_xV =0;
470 UT_sint32 col_yV =0;
471 fp_Column * pCol = static_cast<fp_Column *>(pCon);
472 pCol->getPage()->getScreenOffsets(pCol, col_xV, col_yV);
473 pCol =static_cast<fp_Column *>(pCon->getColumn());
474 pCol->getPage()->getScreenOffsets(pCol, col_x, col_y);
475 UT_sint32 ydiff = col_yV - col_y;
476 my_yoff += ydiff;
477 }
478 xoff = pCon->getX() + my_xoff + pOrig->getX();
479 yoff = pCon->getY() + my_yoff + pOrig->getY();
480 if ((pPrev->getContainerType() == FP_CONTAINER_TOC) &&
481 (pCon->getContainerType() != FP_CONTAINER_COLUMN_SHADOW))
482 {
483 xxx_UT_DEBUGMSG(("Not in shadow final xoff %d \n",xoff));
484 return;
485 }
486 }
487
488 if(pCon && pCon->getContainerType() == FP_CONTAINER_COLUMN_SHADOW)
489 {
490 xoff = pCon->getX() + my_xoff + pOrig->getX();
491 yoff = pCon->getY() + my_yoff + pOrig->getY();
492 xxx_UT_DEBUGMSG(("Offsets in FP_CONTAINER_COLUMN_SHADOW x= %d \n",xoff));
493 return;
494 }
495 if(pCon)
496 {
497 xoff = pCon->getX() + my_xoff + pOrig->getX();
498 yoff = pCon->getY() + my_yoff + pOrig->getY();
499 }
500 else
501 {
502 xoff = 0;
503 yoff = 0;
504 }
505 if(pCon && pCon->getContainerType() == FP_CONTAINER_FOOTNOTE)
506 {
507 if(getPage() && getView() && (getView()->getViewMode() != VIEW_PRINT))
508 {
509 fl_DocSectionLayout * pDSL = getPage()->getOwningSection();
510 yoff -= pDSL->getTopMargin();
511 }
512 }
513 if(pCon && getPage() && (pCon->getContainerType() == FP_CONTAINER_ANNOTATION) &&
514 getPage()->getDocLayout()->displayAnnotations())
515 {
516 if(getPage() && getView() && (getView()->getViewMode() != VIEW_PRINT))
517 {
518 fl_DocSectionLayout * pDSL = getPage()->getOwningSection();
519 yoff -= pDSL->getTopMargin();
520 }
521 }
522 }
523
524
525
526 /*!
527 * return an rectangle that covers this object on the screen
528 * The calling routine is resposible for deleting the returned struct
529 */
getScreenRect(void)530 UT_Rect * fp_VerticalContainer::getScreenRect(void)
531 {
532 UT_sint32 xoff = 0;
533 UT_sint32 yoff = 0;
534 UT_Rect * pRec = NULL;
535 if(getContainerType() == FP_CONTAINER_FRAME)
536 {
537 fp_Page * pPage = getPage();
538 if(pPage == NULL)
539 {
540 return NULL;
541 }
542 fp_FrameContainer * pFrameC = static_cast<fp_FrameContainer *>(this);
543 getView()->getPageScreenOffsets(pPage,xoff,yoff);
544 xoff += pFrameC->getFullX();
545 yoff += pFrameC->getFullY();
546 pRec= new UT_Rect(xoff,yoff,pFrameC->getFullWidth(),pFrameC->getFullHeight());
547 return pRec;
548 }
549 fp_Container * pCon = static_cast<fp_Container *>(fp_Container::getNthCon(0));
550 if(pCon == NULL)
551 {
552 return NULL;
553 }
554 getScreenOffsets(pCon,xoff,yoff);
555 xoff -= pCon->getX();
556 yoff -= pCon->getY();
557 pRec= new UT_Rect(xoff,yoff,getWidth(),getHeight());
558 return pRec;
559 }
560
561 /*!
562 * Marks Dirty any runs that overlap the supplied rectangle. This rectangle
563 * is relative to the screen.
564 */
markDirtyOverlappingRuns(UT_Rect & recScreen)565 void fp_VerticalContainer::markDirtyOverlappingRuns(UT_Rect & recScreen)
566 {
567 UT_Rect * pRec = NULL;
568 pRec = getScreenRect();
569 if(pRec && recScreen.intersectsRect(pRec))
570 {
571 DELETEP(pRec);
572 UT_sint32 count = countCons();
573 UT_sint32 i = 0;
574 for(i = 0; i < count;i++)
575 {
576 fp_Container * pCon = static_cast<fp_Container * >(getNthCon(i));
577 pCon->markDirtyOverlappingRuns(recScreen);
578 }
579 return;
580 }
581 DELETEP(pRec);
582 }
583
584
585 /*!
586 Get Containers' offsets relative to the screen
587 \param pContainer Container which we want to find the absolute
588 position of.
589 \retval xoff Container's X offset relative the screen
590 \retval yoff Container's Y offset relative the screen
591 */
getScreenOffsets(fp_ContainerObject * pContainer,UT_sint32 & xoff,UT_sint32 & yoff)592 void fp_VerticalContainer::getScreenOffsets(fp_ContainerObject* pContainer,
593 UT_sint32& xoff, UT_sint32& yoff)
594 {
595 fp_ContainerObject * pOrig = pContainer;
596 UT_sint32 my_xoff =0;
597 UT_sint32 my_yoff =0;
598
599 if((getPage() == NULL) || (pContainer == NULL))
600 {
601 xoff = 0;
602 yoff = 0;
603 return;
604 }
605
606 fp_Container * pCon = static_cast<fp_Container *>(this);
607 bool bCell = false;
608 bool bTable = false;
609 UT_sint32 xcell = 0;
610 UT_sint32 ycell = 0;
611 if((getContainerType() == FP_CONTAINER_TABLE) && (pContainer->getContainerType() == FP_CONTAINER_CELL))
612 {
613 pCon = static_cast<fp_Container *>(pContainer);
614 pContainer = static_cast<fp_CellContainer *>(pContainer)->getNthCon(0);
615 if(pContainer != NULL)
616 {
617 bCell = true;
618 xcell = pContainer->getX();
619 ycell = pContainer->getY();
620 }
621 else
622 {
623 bTable = true;
624 pContainer = pCon;
625 pCon = static_cast<fp_Container *>(this);
626 my_yoff = getY();
627 my_xoff = getX();
628 }
629 }
630 fp_Container * pPrev = NULL;
631 fp_TableContainer * pTab = NULL;
632 while(pCon && !pCon->isColumnType() && !bTable)
633 {
634 my_xoff += pCon->getX();
635 xxx_UT_DEBUGMSG(("Screen offsets my_xoff %d pCon %x type %s \n",my_xoff,pCon,pCon->getContainerString()));
636 UT_sint32 iycon = pCon->getY();
637 my_yoff += iycon;
638 //
639 // Handle offsets from tables broken across pages.
640 //
641 // We detect
642 // line->cell->table->cell->table->cell->table->column
643 //
644 if(pCon->getContainerType() == FP_CONTAINER_TABLE)
645 {
646 fp_VerticalContainer * pVCon= static_cast<fp_VerticalContainer *>(pCon);
647 //
648 // Lines and Cells are actually always in the Master table. To make
649 // Them print on the right pages broken tables are created which
650 // sit in different columns. Here we put in a recursive search find
651 // the correct broken table line when we come across a cell
652 //
653 // Then we have to get all the offsets right for the broken table.
654 //
655
656 pVCon = getCorrectBrokenTable(static_cast<fp_Container *>(pContainer));
657 //
658 // Can happen during loading.
659 //
660 if(pVCon == NULL)
661 {
662 xoff = 0;
663 yoff = 0;
664 return;
665 }
666 if(pPrev && pPrev->getContainerType() == FP_CONTAINER_CELL)
667 {
668 my_yoff += getYoffsetFromTable(pCon,pPrev,pContainer);
669 pTab = static_cast<fp_TableContainer *>(pVCon);
670 if(pTab->isThisBroken() && pTab != pTab->getMasterTable()->getFirstBrokenTable())
671 {
672 my_yoff = my_yoff + pVCon->getY() -iycon;
673 }
674 pCon = static_cast<fp_Container *>(pVCon);
675 }
676 else if(pPrev == NULL)
677 {
678 my_yoff = 0;
679 }
680 else
681 {
682 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
683 }
684 if(pVCon->getContainer()->getContainerType() == FP_CONTAINER_CELL)
685 {
686 pContainer = static_cast<fp_ContainerObject *>(pVCon);
687 }
688 pCon = static_cast<fp_Container *>(pVCon);
689 }
690 if(pCon->getContainerType() == FP_CONTAINER_TOC)
691 {
692 fp_VerticalContainer * pVCon= static_cast<fp_VerticalContainer *>(pCon);
693 //
694 // Lines are actually always in the Master table. To make
695 // Them print on the right pages broken tables are created which
696 // sit in different columns. Here we put in a recursive search find
697 // the correct broken table line when we come across a cell
698 //
699 // Then we have to get all the offsets right for the broken table.
700 //
701
702 pVCon = getCorrectBrokenTOC(static_cast<fp_Container *>(pContainer));
703 pCon = static_cast<fp_Container *>(pVCon);
704 }
705 pPrev = pCon;
706 pCon = pCon->getContainer();
707 if (!pCon)
708 {
709 // Can happen during loading
710 xoff = 0;
711 yoff = 0;
712 return;
713 }
714 }
715 UT_return_if_fail(pCon);
716 UT_sint32 col_x =0;
717 UT_sint32 col_y =0;
718 xoff = my_xoff + pOrig->getX();
719 yoff = my_yoff + pOrig->getY();
720 if(bCell)
721 {
722 xoff -= xcell;
723 yoff -= ycell;
724 }
725 if (pCon->getContainerType() == FP_CONTAINER_COLUMN)
726 {
727 fp_Column * pCol = static_cast<fp_Column *>(pCon);
728 pCol->getPage()->getScreenOffsets(pCol, col_x, col_y);
729
730 xoff += col_x;
731 yoff += col_y;
732 }
733 else if (pCon->getContainerType() == FP_CONTAINER_COLUMN_SHADOW)
734 {
735 fp_ShadowContainer * pCol = static_cast<fp_ShadowContainer *>(pCon);
736 pCol->getPage()->getScreenOffsets(pCol, col_x, col_y);
737
738 xoff += col_x;
739 yoff += col_y;
740 }
741 else if(pCon->getContainerType() == FP_CONTAINER_FOOTNOTE)
742 {
743 fp_FootnoteContainer * pFC = static_cast<fp_FootnoteContainer *>(pCon);
744 pFC->getPage()->getScreenOffsets(pFC, col_x, col_y);
745
746 xoff += col_x;
747 yoff += col_y;
748 if(pFC->getPage() && getView() && (getView()->getViewMode() != VIEW_PRINT))
749 {
750 fl_DocSectionLayout * pDSL = getPage()->getOwningSection();
751 yoff -= pDSL->getTopMargin();
752 }
753 }
754 else if(pCon->getContainerType() == FP_CONTAINER_ANNOTATION)
755 {
756 fp_AnnotationContainer * pAC = static_cast<fp_AnnotationContainer *>(pCon);
757 pAC->getPage()->getScreenOffsets(pAC, col_x, col_y);
758
759 xoff += col_x;
760 yoff += col_y;
761 if(pAC->getPage() && getView() && (getView()->getViewMode() != VIEW_PRINT))
762 {
763 fl_DocSectionLayout * pDSL = getPage()->getOwningSection();
764 yoff -= pDSL->getTopMargin();
765 }
766 }
767 else if(pCon->getContainerType() == FP_CONTAINER_FRAME)
768 {
769 fp_FrameContainer * pFC = static_cast<fp_FrameContainer *>(pCon);
770 pFC->getPage()->getScreenOffsets(pFC, col_x, col_y);
771
772 xoff += col_x;
773 yoff += col_y;
774 }
775 else
776 {
777 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
778 }
779 }
780
781
782 /*!
783 * remove all contains from this.
784 */
removeAll(void)785 void fp_VerticalContainer::removeAll(void)
786 {
787 UT_sint32 iCount = countCons();
788 UT_sint32 i = 0;
789 for(i=0; i< iCount; i++)
790 {
791 deleteNthCon(0);
792 }
793 }
794 /*!
795 Remove line from container
796 \param pContainer Container
797 \param bClear if true clear screen.
798 \note The line is not destructed, as it is owned by the logical
799 hierarchy.
800 */
removeContainer(fp_Container * pContainer,bool bClear)801 void fp_VerticalContainer::removeContainer(fp_Container* pContainer,bool bClear)
802 {
803 UT_sint32 iCount = countCons();
804 if(iCount == 0)
805 return;
806 UT_sint32 ndx = findCon(pContainer);
807 UT_ASSERT(ndx >= 0);
808 if(ndx < 0)
809 {
810 return;
811 }
812 if(bClear && (pContainer->getContainerType() == FP_CONTAINER_LINE))
813 {
814 pContainer->clearScreen();
815 }
816 xxx_UT_DEBUGMSG(("Removing Container %x from column %x \n",pContainer,this));
817 pContainer->setContainer(NULL);
818 deleteNthCon(ndx);
819
820 // don't delete the line here, it's deleted elsewhere.
821 }
822
823 /*!
824 Insert line at the front/top of the container
825 \param pNewContainer Container
826 */
insertContainer(fp_Container * pNewContainer)827 bool fp_VerticalContainer::insertContainer(fp_Container* pNewContainer)
828 {
829 UT_return_val_if_fail(pNewContainer,false);
830 UT_return_val_if_fail((pNewContainer->getContainerType() == FP_CONTAINER_ENDNOTE) || (pNewContainer->getDocSectionLayout() == getDocSectionLayout()),false);
831 UT_ASSERT(pNewContainer->getContainerType() != FP_CONTAINER_ANNOTATION);
832 pNewContainer->clearScreen();
833 xxx_UT_DEBUGMSG(("Insert Container after CS %x in column %x \n",pNewContainer,this));
834 insertConAt(pNewContainer, 0);
835 pNewContainer->setContainer(static_cast<fp_Container *>(this));
836 pNewContainer->recalcMaxWidth(true);
837
838 return true;
839 }
840
841 /*!
842 Get column gap from page the container is located on
843 \return Column gap
844 */
getColumnGap(void) const845 UT_sint32 fp_VerticalContainer::getColumnGap(void) const
846 {
847 return getColumn()->getPage()->getColumnGap();
848 }
849
850 /*!
851 Append line at the end/bottom of the container
852 \param pNewContainer Container
853 */
addContainer(fp_Container * pNewContainer)854 bool fp_VerticalContainer::addContainer(fp_Container* pNewContainer)
855 {
856 UT_return_val_if_fail(pNewContainer,false);
857 UT_return_val_if_fail((pNewContainer->getContainerType() == FP_CONTAINER_ENDNOTE) || (pNewContainer->getDocSectionLayout() == getDocSectionLayout()),false);
858 UT_ASSERT(pNewContainer->getContainerType() != FP_CONTAINER_ANNOTATION);
859 if(pNewContainer->getContainer() != NULL)
860 {
861 pNewContainer->clearScreen();
862 }
863 xxx_UT_DEBUGMSG(("Add Container after CS %x in column %x \n",pNewContainer,this));
864 addCon(pNewContainer);
865 pNewContainer->setContainer(this);
866 pNewContainer->recalcMaxWidth(true);
867 return true;
868 }
869
870 /*!
871 Insert line in container after specified line
872 \param pNewContainer Container to be inserted
873 \param pAfterContainer After this line
874 \todo This function has been hacked to handle the case where
875 pAfterContainer is NULL. That case should not happen. Bad callers
876 should be identified and fixed, and this function should be
877 cleaned up.
878 */
insertContainerAfter(fp_Container * pNewContainer,fp_Container * pAfterContainer)879 bool fp_VerticalContainer::insertContainerAfter(fp_Container* pNewContainer, fp_Container* pAfterContainer)
880 {
881 UT_ASSERT(pAfterContainer);
882 UT_return_val_if_fail(pNewContainer, false);
883 UT_return_val_if_fail((pNewContainer->getContainerType() == FP_CONTAINER_ENDNOTE) || (pNewContainer->getDocSectionLayout() == getDocSectionLayout()),false);
884 UT_ASSERT(pNewContainer->getContainerType() != FP_CONTAINER_ANNOTATION);
885
886 UT_sint32 count = countCons();
887 UT_sint32 ndx = findCon(pAfterContainer);
888 UT_ASSERT( (count > 0) || (ndx == -1) );
889
890 /*
891 TODO this routine should not be allowing pAfterContainer to be NULL.
892 Right now, we've fixed the symptom, but we really should fix
893 the problem. */
894 UT_ASSERT(ndx >= 0);
895 pNewContainer->clearScreen();
896 if ( (ndx+1) == count ) // append after last line in vector
897 addCon(pNewContainer);
898 else if (ndx >= 0) // append after this item within the vector
899 insertConAt(pNewContainer, ndx+1);
900 else
901 {
902 // TODO remove this....
903 insertConAt(pNewContainer, 0);
904 }
905
906 pNewContainer->setContainer(this);
907 if(pNewContainer->getContainerType() == FP_CONTAINER_LINE)
908 {
909 if(static_cast<fp_Line *>(pNewContainer)->isWrapped())
910 {
911 return true;
912 }
913 }
914 pNewContainer->recalcMaxWidth(true);
915
916 return true;
917 }
918
919 /*!
920 Clear container content from screen.
921
922 \fixme Needs to clear outline as well
923 */
clearScreen(void)924 void fp_VerticalContainer::clearScreen(void)
925 {
926 if(getPage() == NULL)
927 {
928 return;
929 }
930 if(!getPage()->isOnScreen())
931 {
932 return;
933 }
934 int count = countCons();
935 for (int i = 0; i<count; i++)
936 {
937 fp_ContainerObject* pContainer = static_cast<fp_ContainerObject*>(getNthCon(i));
938
939 pContainer->clearScreen();
940 }
941 }
942
943 /*!
944 Draw container outline
945 \param pDA Draw arguments
946 */
_drawBoundaries(dg_DrawArgs * pDA)947 void fp_VerticalContainer::_drawBoundaries(dg_DrawArgs* pDA)
948 {
949 if(pDA->pG->queryProperties(GR_Graphics::DGP_SCREEN))
950 {
951 return;
952 }
953 UT_return_if_fail(getPage());
954 UT_return_if_fail(getPage()->getDocLayout()->getView());
955
956 if(getPage()->getDocLayout()->getView()->getShowPara() && getGraphics()->queryProperties(GR_Graphics::DGP_SCREEN)){
957 UT_sint32 xoffBegin = pDA->xoff - getGraphics()->tlu(1);
958 UT_sint32 yoffBegin = pDA->yoff - getGraphics()->tlu(1);
959 UT_sint32 xoffEnd = pDA->xoff + m_iWidth + getGraphics()->tlu(2);
960 UT_sint32 yoffEnd = pDA->yoff + m_iMaxHeight + getGraphics()->tlu(2);
961
962 UT_RGBColor clrShowPara(127,127,127);
963
964 GR_Painter painter(getGraphics());
965
966 getGraphics()->setColor(clrShowPara);
967
968 painter.drawLine(xoffBegin, yoffBegin, xoffEnd, yoffBegin);
969 painter.drawLine(xoffBegin, yoffEnd, xoffEnd, yoffEnd);
970 painter.drawLine(xoffBegin, yoffBegin, xoffBegin, yoffEnd);
971 painter.drawLine(xoffEnd, yoffBegin, xoffEnd, yoffEnd);
972 }
973 }
974
975 /*!
976 * Returns the maximum line height as determined from the layout method
977 * This used by the draw method to determine if a line should be drawn in
978 * a clipping rectangle
979 */
_getMaxContainerHeight(void) const980 UT_sint32 fp_VerticalContainer::_getMaxContainerHeight(void) const
981 {
982 return m_imaxContainerHeight;
983 }
984
985 /*!
986 * Set the maximum line Height
987 \param UT_sint32 iLineHeight the largest line height yet found.
988 */
_setMaxContainerHeight(UT_sint32 iLineHeight)989 void fp_VerticalContainer::_setMaxContainerHeight( UT_sint32 iLineHeight)
990 {
991 m_imaxContainerHeight = iLineHeight;
992 }
993
994
validate(void)995 bool fp_VerticalContainer::validate(void)
996 {
997 #if DEBUG
998 UT_sint32 curTop =0;
999 UT_sint32 curBot = 0;
1000 UT_sint32 oldTop = -1;
1001 UT_sint32 oldBot = -1;
1002 UT_sint32 i =0;
1003 bool bValid = true;
1004 for(i=0; i<countCons();i++)
1005 {
1006 fp_ContainerObject* pContainer = static_cast<fp_ContainerObject*>(getNthCon(i));
1007 curTop = pContainer->getY();
1008 UT_sint32 iH = pContainer->getHeight();
1009 if(pContainer->getContainerType() == FP_CONTAINER_TABLE)
1010 {
1011 fp_TableContainer * pTab = static_cast<fp_TableContainer *>(pContainer);
1012 iH = pTab->getHeight();
1013 }
1014 if(pContainer->getContainerType() == FP_CONTAINER_TOC)
1015 {
1016 fp_TOCContainer * pTOC = static_cast<fp_TOCContainer *>(pContainer);
1017 iH = pTOC->getHeight();
1018 }
1019 if(pContainer->getContainerType() == FP_CONTAINER_LINE)
1020 {
1021 fp_Line * pLine = static_cast<fp_Line *>(pContainer);
1022 if(pLine->isSameYAsPrevious())
1023 {
1024 continue;
1025 }
1026 }
1027 curBot = curTop + iH;
1028 UT_ASSERT(oldBot <= curTop);
1029 if(oldBot > curTop)
1030 {
1031 bValid =false;
1032 }
1033 UT_ASSERT(curBot >= curTop);
1034 UT_ASSERT(curTop >=oldTop);
1035 oldBot = curBot;
1036 oldTop = curTop;
1037 }
1038 return bValid;
1039 #else
1040 return true;
1041 #endif
1042 }
1043
1044
1045 /*!
1046 Draw container content
1047 \param pDA Draw arguments
1048 */
draw(dg_DrawArgs * pDA)1049 void fp_VerticalContainer::draw(dg_DrawArgs* pDA)
1050 {
1051 #if DEBUG
1052 // validate();
1053 #endif
1054 const UT_Rect * pClipRect = pDA->pG->getClipRect();
1055 UT_sint32 ytop = 0, ybot = (UT_sint32)(((UT_uint32)(1<<31)) - 1);
1056
1057 if(pClipRect)
1058 {
1059 ytop = pClipRect->top;
1060 ybot = UT_MAX(pClipRect->height,_getMaxContainerHeight())
1061 + ytop + pDA->pG->tlu(1);
1062 xxx_UT_DEBUGMSG(("clipRect height %d \n",pClipRect->height));
1063 }
1064
1065 //
1066 // Only draw the lines in the clipping region.
1067 //
1068 bool bStartedDrawing = false;
1069 dg_DrawArgs da = *pDA;
1070 UT_uint32 count = countCons();
1071 UT_sint32 iCurrHeight = 0;
1072 xxx_UT_DEBUGMSG(("number of container %d \n",count));
1073 for (UT_uint32 i = 0; i < count; i++)
1074 {
1075 fp_ContainerObject* pContainer = static_cast<fp_ContainerObject*>(getNthCon(i));
1076 if(pContainer->getY() == INITIAL_OFFSET)
1077 continue ; // container is not yet placed
1078 bool bInTable = false;
1079 bool bInTOC = false;
1080
1081 da.xoff = pDA->xoff + pContainer->getX();
1082 da.yoff = pDA->yoff + pContainer->getY();
1083 iCurrHeight = pContainer->getY() + pContainer->getHeight();
1084 xxx_UT_DEBUGMSG(("iCurrHeight %d | m_iRedrawHeight %d\n", iCurrHeight, m_iRedrawHeight));
1085 if((m_iRedrawHeight > 0) && (iCurrHeight > m_iRedrawHeight))
1086 {
1087 da.bDirtyRunsOnly = false;
1088 }
1089 xxx_UT_DEBUGMSG(("Draw container %x yoff %d\n",pContainer,da.yoff));
1090 xxx_UT_DEBUGMSG(("Draw container %x xoff %d\n",pContainer,da.xoff));
1091 #if 0
1092 if(pContainer->getContainerType() == FP_CONTAINER_LINE)
1093 {
1094 fp_Line * pLine = static_cast<fp_Line *>(pContainer);
1095 if(pLine->isSameYAsPrevious())
1096 {
1097 UT_DEBUGMSG((" !!!!!! Same previous!!!!!!!!\n"));
1098 }
1099 }
1100 #endif
1101 if(pContainer->getContainerType() == FP_CONTAINER_TABLE)
1102 {
1103 fp_TableContainer * pTab = static_cast<fp_TableContainer *>(pContainer);
1104 if(pTab->isThisBroken())
1105 da.xoff = pDA->xoff + pTab->getMasterTable()->getX();
1106
1107 UT_sint32 iTableBot = da.yoff + pTab->getHeight();
1108 /* we're in the table if iTableBot < ytop, or table top > ybot */
1109 bInTable = !(iTableBot < ytop || da.yoff > ybot);
1110 }
1111
1112 if(pContainer->getContainerType() == FP_CONTAINER_TOC)
1113 {
1114 fp_TOCContainer * pTOC = static_cast<fp_TOCContainer *>(pContainer);
1115 xxx_UT_DEBUGMSG(("Draw a TOC getY is %d \n",pContainer->getY()));
1116 if(pTOC->isThisBroken())
1117 da.xoff = pDA->xoff + pTOC->getMasterTOC()->getX();
1118
1119 UT_sint32 iTOCBot = da.yoff + pTOC->getHeight();
1120 /* we're in the table if iTableBot < ytop, or table top > ybot */
1121 bInTOC = !(iTOCBot < ytop || da.yoff > ybot);
1122 }
1123
1124 UT_sint32 sumHeight = pContainer->getHeight() + (ybot-ytop);
1125 UT_sint32 totDiff;
1126 if(da.yoff < ytop)
1127 totDiff = ybot - da.yoff;
1128 else
1129 totDiff = da.yoff + pContainer->getHeight() - ytop;
1130
1131 // if(bTable || (da.yoff >= ytop && da.yoff <= ybot) || (ydiff >= ytop && ydiff <= ybot))
1132 if((bInTable || bInTOC) || (totDiff < sumHeight) || (pClipRect == NULL))
1133 {
1134 bStartedDrawing = true;
1135 pContainer->draw(&da);
1136 }
1137 else if(bStartedDrawing)
1138 {
1139 // we've started drawing and now we're not, so we're done.
1140 break;
1141 }
1142 }
1143 m_iRedrawHeight = -1;
1144 _drawBoundaries(pDA);
1145 }
1146
1147 /*!
1148 Find document position from X and Y coordinates
1149 \param x X coordinate
1150 \param y Y coordinate
1151 \retval pos Document position
1152 \retval bBOL True if position is at begining of line, otherwise false
1153 \retval bEOL True if position is at end of line, otherwise false
1154 */
mapXYToPosition(UT_sint32 x,UT_sint32 y,PT_DocPosition & pos,bool & bBOL,bool & bEOL,bool & isTOC)1155 void fp_VerticalContainer::mapXYToPosition(UT_sint32 x, UT_sint32 y, PT_DocPosition& pos,
1156 bool& bBOL, bool& bEOL, bool &isTOC)
1157 {
1158 int count = countCons();
1159 if(getContainerType() == FP_CONTAINER_TOC)
1160 {
1161 fl_TOCLayout * pTOCL = static_cast<fl_TOCLayout *>(getSectionLayout());
1162 getPage()-> setLastMappedTOC(pTOCL);
1163 isTOC = true;
1164 }
1165 else if(getContainerType() == FP_CONTAINER_COLUMN)
1166 {
1167 isTOC = false;
1168 }
1169 xxx_UT_DEBUGMSG(("SEVIOR: count cons %d x %d y %d \n",count,x,y));
1170 if(count == 0)
1171 {
1172 xxx_UT_DEBUGMSG(("SEVIOR: In container type %d return with bBOL set \n",getContainerType()));
1173 if(getContainerType() == FP_CONTAINER_TABLE)
1174 {
1175 xxx_UT_DEBUGMSG(("SEVIOR: Table container with no containers \n"));
1176 return;
1177 }
1178 if(getContainerType() == FP_CONTAINER_TOC)
1179 {
1180 xxx_UT_DEBUGMSG(("SEVIOR: TOC container with no containers \n"));
1181 return;
1182 }
1183 pos = 2;
1184 bBOL = true;
1185 bEOL = true;
1186 return;
1187 }
1188
1189
1190 fp_ContainerObject* pContainer = NULL;
1191 int i = 0;
1192 // Find first container that contains the point. First has its lower level below the desired Y
1193 // position. Note that X-positions are completely ignored here.
1194 UT_sint32 iHeight = 0;
1195 do
1196 {
1197 pContainer = static_cast<fp_ContainerObject*>(getNthCon(i++));
1198 iHeight = pContainer->getHeight();
1199 xxx_UT_DEBUGMSG(("SEVIOR: IN column looking at x %d y %d height %d \n",pContainer->getX(),pContainer->getY(),iHeight));
1200 } while ((i < count)
1201 && (y > (pContainer->getY() + iHeight)));
1202 // Undo the postincrement.
1203 i--;
1204 // Now check if the position is actually between the found container
1205 // and the line before it (ignore check on the top-most line).
1206 UT_sint32 iUHeight =0;
1207 if (i > 0 && y < pContainer->getY())
1208 {
1209 fp_ContainerObject* pContainerUpper = static_cast<fp_ContainerObject*>(getNthCon(i-1));
1210 iUHeight = pContainer->getHeight();
1211
1212 // Be careful with the signedness here - bug 172 leared us a
1213 // lesson!
1214
1215 // Now pick the line that is closest to the point - or the
1216 // upper if it's a stalemate.
1217 if ((pContainer->getY() - y) >= (y - (pContainerUpper->getY() + static_cast<UT_sint32>(iUHeight))))
1218 {
1219 pContainer = pContainerUpper;
1220 }
1221 }
1222 if(getContainerType() == FP_CONTAINER_CELL && (i == 0))
1223 {
1224 fp_CellContainer *pCellCon = static_cast<fp_CellContainer *>(this);
1225 if((x < getX()) && (pCellCon->getLeftAttach() == 0) )
1226 {
1227 fl_CellLayout * pCL = static_cast<fl_CellLayout *>(getSectionLayout());
1228 pos = pCL->getPosition(true)+2;
1229 bBOL = true;
1230 bEOL = false;
1231 // if((pCellCon->getTopAttach() == 0))
1232 // pos--;
1233 return;
1234 }
1235 }
1236 if(pContainer->getContainerType() == FP_CONTAINER_TABLE)
1237 {
1238 xxx_UT_DEBUGMSG(("SEVIOR: Looking in a table \n"));
1239 fp_TableContainer * pTab = static_cast<fp_TableContainer *>(pContainer);
1240 xxx_UT_DEBUGMSG(("SEVIOR: do map to position for %x \n",pContainer));
1241 pTab->mapXYToPosition(x - pContainer->getX(),
1242 y - pContainer->getY() ,
1243 pos, bBOL, bEOL,isTOC);
1244 }
1245 else if(pContainer->getContainerType() == FP_CONTAINER_FRAME)
1246 {
1247 fp_FrameContainer * pFrame = static_cast<fp_FrameContainer *>(pContainer);
1248 fl_FrameLayout * pFL = static_cast<fl_FrameLayout *>(pFrame->getSectionLayout());
1249 if(pFL->getFrameType() == FL_FRAME_WRAPPER_IMAGE)
1250 {
1251 pos = pFL->getPosition(true);
1252 return;
1253 }
1254 else
1255 {
1256 pContainer->mapXYToPosition(x - pContainer->getX(),
1257 y - pContainer->getY() ,
1258 pos, bBOL, bEOL,isTOC);
1259 }
1260
1261 }
1262 else if(pContainer->getContainerType() == FP_CONTAINER_LINE)
1263 {
1264 //
1265 // Deal with wrapped lines where more than one line can have the same Y
1266 //
1267 fp_Line * pLine2 = static_cast<fp_Line *>(pContainer);
1268 if(pLine2->isWrapped())
1269 {
1270 fp_Line * pNext = static_cast<fp_Line *>(pLine2->getNext());
1271 if(pNext && pNext->isSameYAsPrevious())
1272 {
1273 fp_ContainerObject *pBest = pContainer;
1274 UT_sint32 xmin = UT_MIN(abs(pNext->getX() - x),abs(pNext->getX()+pNext->getMaxWidth() -x));
1275 while(pNext && pNext->isSameYAsPrevious())
1276 {
1277 if((pNext->getX() < x) && (x < pNext->getX() + pNext->getMaxWidth()))
1278 {
1279 pNext->mapXYToPosition(x - pNext->getX(),
1280 y - pNext->getY() ,
1281 pos, bBOL, bEOL,isTOC);
1282 return;
1283 }
1284 UT_sint32 xmin1 = UT_MIN(abs(pNext->getX() - x),abs(pNext->getX()+pNext->getMaxWidth() -x));
1285 if(xmin1 < xmin)
1286 {
1287 xmin = xmin1;
1288 pBest = static_cast<fp_ContainerObject *>(pNext);
1289 }
1290 pNext = static_cast<fp_Line *>(pNext->getNext());
1291 }
1292 pBest->mapXYToPosition(x - pContainer->getX(),
1293 y - pContainer->getY() ,
1294 pos, bBOL, bEOL,isTOC);
1295 return;
1296 }
1297 else
1298 {
1299 pContainer->mapXYToPosition(x - pContainer->getX(),
1300 y - pContainer->getY() ,
1301 pos, bBOL, bEOL,isTOC);
1302 }
1303 }
1304 else if(!pLine2->canContainPoint())
1305 {
1306 // lines that cannot contain point are those that are located in blocks that
1307 // cannot contain point (hidden, collapsed, etc. So we need to find the block
1308 // that can contain point
1309 fl_BlockLayout * pBlock = pLine2->getBlock();
1310 UT_return_if_fail( pBlock );
1311
1312 pBlock = pBlock->getNextBlockInDocument();
1313
1314 while(pBlock && !pBlock->canContainPoint())
1315 {
1316 pBlock = pBlock->getNextBlockInDocument();
1317 }
1318
1319 if(!pBlock)
1320 {
1321 // look the other way (reusing pNext, even though it will be previous)
1322 pBlock = pLine2->getBlock();
1323
1324 pBlock = pBlock->getPrevBlockInDocument();
1325
1326 while(pBlock && !pBlock->canContainPoint())
1327 {
1328 pBlock = pBlock->getPrevBlockInDocument();
1329 }
1330
1331 }
1332
1333 if(!pBlock)
1334 {
1335 // we are in trouble
1336 // no blocks that can take point in this document !!!
1337 // one of the scenarios in which this happens is when the user did ctrl+a -> del
1338 // in revisions mode or marked everything hidden while fmt marks are not showing
1339 // If there is a block and it is not visible, we return that block
1340 // Note that it is difficult to prevent this from happening on the PT level, since
1341 // just because text is marked as hidden or deleted does not mean it is not
1342 // visible in a given view.
1343 fp_Page * pPage = getPage();
1344 if(pPage && pPage->getDocLayout() && pPage->getDocLayout()->getFirstSection())
1345 {
1346 pBlock = pPage->getDocLayout()->getFirstSection()->getFirstBlock();
1347 }
1348
1349 if(!pBlock)
1350 {
1351 UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
1352 }
1353 else
1354 {
1355 fp_Run * pFirstRun = pBlock->getFirstRun();
1356
1357 if(pFirstRun)
1358 {
1359 fp_Line * pLine = pFirstRun->getLine();
1360 if(pLine)
1361 {
1362 pLine->mapXYToPosition(x - pLine->getX(),
1363 y - pLine->getY() ,
1364 pos, bBOL, bEOL,isTOC);
1365 }
1366
1367 }
1368 }
1369 }
1370 else
1371 {
1372 fp_Run * pFirstRun = pBlock->getFirstRun();
1373
1374 if(pFirstRun)
1375 {
1376 fp_Line * pVisibleLine = pFirstRun->getLine();
1377
1378 if(pVisibleLine)
1379 {
1380 #if 0
1381 // !!! This results in an endless loop (bug 7420)
1382 // get the container that holds this line, so we deal with wrapped
1383 // lines, etc.
1384 fp_Container * pVisibleContainer = pVisibleLine->getContainer();
1385
1386 pVisibleContainer->mapXYToPosition(x - pContainer->getX(),
1387 y - pContainer->getY() ,
1388 pos, bBOL, bEOL,isTOC);
1389
1390 #else
1391 pVisibleLine->mapXYToPosition(x - pVisibleLine->getX(),
1392 y - pVisibleLine->getY() ,
1393 pos, bBOL, bEOL,isTOC);
1394 #endif
1395 return;
1396 }
1397
1398 UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
1399 }
1400 else
1401 {
1402 UT_ASSERT_HARMLESS( UT_SHOULD_NOT_HAPPEN );
1403 }
1404 }
1405 }
1406
1407 pContainer->mapXYToPosition(x - pContainer->getX(),
1408 y - pContainer->getY() ,
1409 pos, bBOL, bEOL,isTOC);
1410 }
1411 else
1412 {
1413 xxx_UT_DEBUGMSG(("SEVIOR: do map to position for %x \n",pContainer));
1414 pContainer->mapXYToPosition(x - pContainer->getX(),
1415 y - pContainer->getY() ,
1416 pos, bBOL, bEOL,isTOC);
1417 xxx_UT_DEBUGMSG(("SEVIOR: Found pos %d in column \n",pos));
1418 }
1419 }
1420
1421 /*!
1422 Compute the distance from point to the container's circumference
1423 \param x X coordinate of point
1424 \param y Y coordinate of point
1425 \return Distance between container's circumference and point
1426 */
distanceFromPoint(UT_sint32 x,UT_sint32 y)1427 UT_uint32 fp_VerticalContainer::distanceFromPoint(UT_sint32 x, UT_sint32 y)
1428 {
1429 UT_sint32 dx;
1430 UT_sint32 dy;
1431
1432 if (x < m_iX)
1433 {
1434 dx = m_iX - x;
1435 }
1436 else if (x > (m_iX + m_iWidth - getGraphics()->tlu(1)))
1437 {
1438 dx = x - (m_iX + m_iWidth - getGraphics()->tlu(1));
1439 }
1440 else
1441 {
1442 dx = 0;
1443 }
1444
1445 if (y < m_iY)
1446 {
1447 dy = m_iY - y;
1448 }
1449 else if (y > (m_iY + m_iHeight - getGraphics()->tlu(1)))
1450 {
1451 dy = y - (m_iY + m_iHeight - getGraphics()->tlu(1));
1452 }
1453 else
1454 {
1455 dy = 0;
1456 }
1457
1458 if (dx == 0)
1459 {
1460 return dy;
1461 }
1462
1463 if (dy == 0)
1464 {
1465 return dx;
1466 }
1467
1468 UT_uint32 dist = (UT_uint32) (sqrt((float)(dx * dx) + (dy * dy)));
1469
1470 // UT_ASSERT(dist > 0);
1471
1472 return dist;
1473 }
1474
1475 /*!
1476 Set X position of container
1477 \param iX New X position
1478
1479 Before the postition of the container is changed, its content is
1480 first cleared from the screen.
1481 */
setX(UT_sint32 iX,bool)1482 void fp_VerticalContainer::setX(UT_sint32 iX, bool /*bDontClearIfNeeded*/)
1483 {
1484 if (iX == m_iX)
1485 {
1486 return;
1487 }
1488
1489 clearScreen();
1490
1491 m_iX = iX;
1492 }
1493
1494 /*!
1495 Set Y position of container
1496 \param iY New Y position
1497
1498 Before the postition of the container is changed, its content is
1499 first cleared from the screen.
1500 */
setY(UT_sint32 iY)1501 void fp_VerticalContainer::setY(UT_sint32 iY)
1502 {
1503 if (iY == m_iY)
1504 {
1505 return;
1506 }
1507 if(m_iY != -99999999)
1508 {
1509 clearScreen();
1510 }
1511 m_iY = iY;
1512 }
1513
1514 /*!
1515 Return first line in the container
1516 \return The first line, or NULL if the container is empty
1517 */
getFirstContainer(void) const1518 fp_Container* fp_VerticalContainer::getFirstContainer(void) const
1519 {
1520 if (countCons() > 0)
1521 {
1522 return static_cast<fp_Container*>(getNthCon(0));
1523 }
1524 else
1525 {
1526 return NULL;
1527 }
1528 }
1529
countWrapped(void)1530 UT_sint32 fp_VerticalContainer::countWrapped(void)
1531 {
1532 UT_sint32 nWrapped = 0;
1533 UT_sint32 i = 0;
1534 for(i=0; i<countCons();i++)
1535 {
1536 fp_Container * pCon = static_cast<fp_Container*>(getNthCon(i));
1537 if(pCon->getContainerType() == FP_CONTAINER_LINE)
1538 {
1539 fp_Line * pLine = static_cast<fp_Line *>(pCon);
1540 xxx_UT_DEBUGMSG(("Line %d MaxWidth %d \n",i,pLine->getMaxWidth()));
1541 if(pLine->isWrapped())
1542 {
1543 nWrapped++;
1544 }
1545 else if(pLine->isSameYAsPrevious())
1546 {
1547 nWrapped++;
1548 }
1549 else if((pLine->getMaxWidth() > 0) && (pLine->getMaxWidth() < getWidth()))
1550 {
1551 nWrapped++;
1552
1553 }
1554 }
1555 }
1556 return nWrapped;
1557 }
1558
1559
1560 /*!
1561 Return last line in the container
1562 \return The last line, or NULL if the container is empty
1563 */
getLastContainer(void) const1564 fp_Container* fp_VerticalContainer::getLastContainer(void) const
1565 {
1566 UT_uint32 iCount = countCons();
1567
1568 if (iCount > 0)
1569 {
1570 return static_cast<fp_Container*>(getNthCon(iCount - 1));
1571 }
1572 else
1573 {
1574 return NULL;
1575 }
1576 }
1577
1578
1579 /*!
1580 Bump Containers from this Container to the next
1581 \param pLastContainerToKeep Last line to keep in this column or NULL for none
1582 */
bumpContainers(fp_ContainerObject * pLastContainerToKeep)1583 void fp_VerticalContainer::bumpContainers(fp_ContainerObject* pLastContainerToKeep)
1584 {
1585 UT_sint32 ndx = (NULL == pLastContainerToKeep) ? 0 : (findCon(pLastContainerToKeep)+1);
1586 xxx_UT_DEBUGMSG(("!!!---Bump Containers LastToKeep %x Index %d \n",pLastContainerToKeep,ndx));
1587 UT_ASSERT(ndx >= 0);
1588 UT_sint32 i;
1589 fp_TOCContainer *pTOC2 = NULL;
1590 fp_VerticalContainer* pNextContainer = static_cast<fp_VerticalContainer*>(getNext());
1591 UT_return_if_fail(pNextContainer);
1592 UT_return_if_fail((pNextContainer->getContainerType() == FP_CONTAINER_ENDNOTE) || (pNextContainer->getDocSectionLayout() == getDocSectionLayout()));
1593 if (pNextContainer->isEmpty())
1594 {
1595 for (i=ndx; i< countCons(); i++)
1596 {
1597 if(i >= countCons())
1598 continue;
1599 fp_Container* pContainer = static_cast<fp_Container*>(getNthCon(i));
1600 if(pContainer == NULL)
1601 continue;
1602 pContainer->clearScreen();
1603 //
1604 // Experimental code: FIXME: Might remove after a while - check
1605 // that large tables broken over many pages work fine.
1606 //
1607 #if 1
1608 if(pContainer->getContainerType() == FP_CONTAINER_TABLE)
1609 {
1610 fp_TableContainer *pTab = static_cast<fp_TableContainer *>(pContainer);
1611 if(!pTab->isThisBroken())
1612 {
1613 pTab->deleteBrokenTables(true);
1614 }
1615 }
1616 if(pContainer->getContainerType() == FP_CONTAINER_TOC)
1617 {
1618 fp_TOCContainer *pTOC = static_cast<fp_TOCContainer *>(pContainer);
1619 xxx_UT_DEBUGMSG(("Found TOC %x index %d prev %x to bump to Empty Col \n",pTOC,i,pTOC->getPrevContainerInSection()));
1620 if(!pTOC->isThisBroken())
1621 {
1622 pTOC->deleteBrokenTOCs(true);
1623 }
1624 }
1625 #endif
1626 pNextContainer->addContainer(pContainer);
1627 }
1628 }
1629 else
1630 {
1631 bool bTOC = false;
1632 for (i=countCons() - 1; i >= ndx; i--)
1633 {
1634 bTOC = false;
1635 if(i >= countCons())
1636 continue;
1637 fp_Container* pContainer = static_cast<fp_Container*>(getNthCon(i));
1638 if(pContainer == NULL)
1639 continue;
1640 xxx_UT_DEBUGMSG(("clearScreen on %x in bumpContainers \n",pContainer));
1641 pContainer->clearScreen();
1642 //
1643 // Experimental code: FIXME: Might remove after a while - check
1644 // that large tables broken over many pages work fine.
1645 //
1646 #if 1
1647 if(pContainer->getContainerType() == FP_CONTAINER_TABLE)
1648 {
1649 fp_TableContainer *pTab = static_cast<fp_TableContainer *>(pContainer);
1650 if(!pTab->isThisBroken())
1651 {
1652 pTab->deleteBrokenTables(true);
1653 }
1654 }
1655 if(pContainer->getContainerType() == FP_CONTAINER_TOC)
1656 {
1657 pTOC2 = static_cast<fp_TOCContainer *>(pContainer);
1658 xxx_UT_DEBUGMSG(("Found TOC %x index %d prev %x to bump to filled Col \n",pTOC2,i,pTOC2->getPrevContainerInSection()));
1659 if(!pTOC2->isThisBroken())
1660 {
1661 pTOC2->deleteBrokenTOCs(true);
1662 }
1663 bTOC = true;
1664 }
1665 #endif
1666 fp_Line * pLine = NULL;
1667 UT_sint32 iOldMaxWidth = 0;
1668 if(pContainer->getContainerType() == FP_CONTAINER_LINE)
1669 {
1670 pLine = static_cast<fp_Line *>(pContainer);
1671 iOldMaxWidth = pLine->getMaxWidth();
1672 }
1673 pNextContainer->insertContainer(pContainer);
1674 //
1675 // Max Line widths can change after a bump. If so
1676 // we must reformat from the start of the line
1677 //
1678 if(pLine && (pLine->getMaxWidth() != iOldMaxWidth))
1679 {
1680 UT_DEBUGMSG(("MaxWidthChanged from container bump \n"));
1681 pLine->setReformat();
1682 }
1683 if(bTOC)
1684 {
1685 //UT_sint32 iTOC = pNextContainer->findCon(pContainer);
1686 xxx_UT_DEBUGMSG(("TOC insert at location %d in next Container \n",iTOC));
1687 }
1688 }
1689 }
1690 if(pTOC2)
1691 {
1692 //UT_sint32 iTOC = pNextContainer->findCon(pTOC);
1693 xxx_UT_DEBUGMSG(("TOC Final location %d in next Container \n",iTOC));
1694 }
1695 for (i=countCons() - 1; i >= ndx; i--)
1696 {
1697 deleteNthCon(i);
1698 }
1699 }
1700
1701
1702 /*!
1703 Create column
1704 \param pSectionLayout Section layout type used for this container
1705
1706 The section the column is created in specifies the number of column
1707 rows. There is always created columns for all rows at the same
1708 time. The first (left-most) column is the leader.
1709
1710 \fixme I suspect BIDI does not work with multiple columns since the
1711 leader would then have to be the right-most column.
1712 */
fp_Column(fl_SectionLayout * pSectionLayout)1713 fp_Column::fp_Column(fl_SectionLayout* pSectionLayout) : fp_VerticalContainer(FP_CONTAINER_COLUMN, pSectionLayout),
1714 m_pLeader(NULL),
1715 m_pFollower(NULL),
1716 m_pPage(NULL)
1717 {
1718 }
1719
~fp_Column()1720 fp_Column::~fp_Column()
1721 {
1722 xxx_UT_DEBUGMSG(("Deleting Column %x Number containers left %d \n",this,countCons()));
1723 // UT_ASSERT(countCons() == 0);
1724 }
1725
1726 /*!
1727 * This method should be called before a docsection collapse since we can't
1728 * be sure that the docsection that owns this column also contains the endnote
1729 * in this column
1730 */
collapseEndnotes(void)1731 void fp_Column::collapseEndnotes(void)
1732 {
1733 UT_sint32 i = 0;
1734 for(i=countCons()-1; i>= 0; i--)
1735 {
1736 fp_Container * pCon = static_cast<fp_Container *>(getNthCon(i));
1737 if(pCon->getContainerType() == FP_CONTAINER_ENDNOTE)
1738 {
1739 fl_EndnoteLayout * pEL = static_cast<fl_EndnoteLayout *>(pCon->getSectionLayout());
1740 pEL->collapse();
1741 UT_sint32 ndx = findCon(pCon);
1742 if(ndx >= 0)
1743 {
1744 justRemoveNthCon(ndx);
1745 }
1746 }
1747 }
1748 }
1749
1750
1751 /*!
1752 * Returns true of the column contains a page break.
1753 */
containsPageBreak(void) const1754 bool fp_Column::containsPageBreak(void) const
1755 {
1756 fp_Container * pCon = getLastContainer();
1757 if(pCon && (pCon->getContainerType() ==FP_CONTAINER_LINE))
1758 {
1759 fp_Line * pLine = static_cast<fp_Line *>(pCon);
1760 return pLine->containsForcedPageBreak();
1761 }
1762 return false;
1763 }
1764
setPage(fp_Page * pPage)1765 void fp_Column::setPage(fp_Page * pPage)
1766 {
1767 if(pPage == NULL)
1768 {
1769 getFillType().setParent(NULL);
1770 }
1771 else
1772 {
1773 getFillType().setParent(&pPage->getFillType());
1774 }
1775 m_pPage = pPage;
1776 }
1777
1778 /* Return the index of the column on its page*/
getColumnIndex(void)1779 UT_sint32 fp_Column::getColumnIndex(void)
1780 {
1781 fp_Page * pPage = getPage();
1782 fl_DocSectionLayout * pSection = getDocSectionLayout();
1783 fp_Column * pCol = NULL;
1784 if (!pPage || !pSection)
1785 {return 0;}
1786 UT_sint32 kmax = static_cast<UT_sint32>(pSection->getNumColumns());
1787 UT_sint32 j;
1788 for(j=0;j<pPage->countColumnLeaders();j++)
1789 {
1790 pCol = pPage->getNthColumnLeader(j);
1791 if (pCol && (pCol->getDocSectionLayout() == pSection))
1792 {
1793 UT_sint32 k = 0;
1794 while(pCol && k<kmax)
1795 {
1796 if (pCol == this)
1797 {return k;}
1798 pCol = static_cast<fp_Column *> (pCol->getNext());
1799 k++;
1800 }
1801 }
1802 }
1803 return 0;
1804 }
1805 /*!
1806 Draw column outline
1807 \param pDA Draw arguments
1808
1809 This differs from the container function in that it will use draw the
1810 outline based on the tallest column in the row.
1811 */
_drawBoundaries(dg_DrawArgs * pDA)1812 void fp_Column::_drawBoundaries(dg_DrawArgs* pDA)
1813 {
1814 if(!pDA->pG->queryProperties(GR_Graphics::DGP_SCREEN))
1815 {
1816 return;
1817 }
1818 if(getPage()->getDocLayout()->getView()->getShowPara() && getGraphics()->queryProperties(GR_Graphics::DGP_SCREEN))
1819 {
1820 getGraphics()->setColor(getPage()->getDocLayout()->getView()->getColorShowPara());
1821 UT_sint32 xoffBegin = pDA->xoff - getGraphics()->tlu(1);
1822 UT_sint32 yoffBegin = pDA->yoff - getGraphics()->tlu(1);
1823 UT_sint32 xoffEnd = pDA->xoff + getWidth() + getGraphics()->tlu(2);
1824
1825 UT_sint32 iHeight = 0;
1826 fp_Column* pCol = getLeader();
1827 if (getPage()->getNthColumnLeader(getPage()->countColumnLeaders()-1) == pCol)
1828 {
1829 // If there's no column rows after this one on the page, use max height
1830 iHeight = getMaxHeight();
1831 }
1832 else
1833 {
1834 // Find max column height in row
1835 while (pCol)
1836 {
1837 if (pCol->getHeight() > iHeight)
1838 iHeight = pCol->getHeight();
1839 pCol = pCol->getFollower();
1840 }
1841 }
1842 UT_sint32 yoffEnd = pDA->yoff + iHeight + getGraphics()->tlu(2);
1843
1844 GR_Painter painter(getGraphics());
1845
1846 getGraphics()->setLineProperties(getGraphics()->tlu(1),
1847 GR_Graphics::JOIN_MITER,
1848 GR_Graphics::CAP_PROJECTING,
1849 GR_Graphics::LINE_SOLID);
1850
1851 painter.drawLine(xoffBegin, yoffBegin, xoffEnd, yoffBegin);
1852 painter.drawLine(xoffBegin, yoffEnd, xoffEnd, yoffEnd);
1853 painter.drawLine(xoffBegin, yoffBegin, xoffBegin, yoffEnd);
1854 painter.drawLine(xoffEnd, yoffBegin, xoffEnd, yoffEnd);
1855 }
1856 }
1857
1858 /*!
1859 Layout lines in the column
1860
1861 This function iterates over the lines in the column and computes
1862 their screen position from their accumulative heights in layout
1863 units.
1864
1865 Since this code accumulates fractions of the conversion process, the
1866 difference between Y positions of two lines may differ from the
1867 pre-computed height of the upper line. This is due to simple
1868 rounding errors and general lack of precision (screen coordinates
1869 are integer while the computation yields fractions).
1870
1871 To make XY/position conversion precise, remove the gaps by updating
1872 the line heights. Note that the line heights get updated next time
1873 there's a line lookup - so this does not in any way affect layout,
1874 only the precision of the XY/position conversion code.
1875
1876 Sevior: I put in the 0.5 to deal with truncation errors and the +1 to deal
1877 with the last line.
1878
1879 \see fp_Line::setAssignedScreenHeight, fp_Container::recalcHeight
1880 */
layout(void)1881 void fp_Column::layout(void)
1882 {
1883 clearWrappedLines();
1884 _setMaxContainerHeight(0);
1885 UT_sint32 iY = 0, iPrevY2 = 0;
1886 UT_sint32 iContainerMarginAfter = 0;
1887 UT_GenericVector<fl_BlockLayout *> vecBlocks;
1888 fp_Line * pLastLine = NULL;
1889 fp_Container *pContainer = NULL;
1890 fp_Container *pPrevContainer = NULL;
1891 UT_sint32 i = 0;
1892 //
1893 // RedrawHeight makes sure we redraw from whereever a line
1894 // changes position.
1895 //
1896 m_iRedrawHeight = -1;
1897 for (i=0; i < countCons(); i++)
1898 {
1899 pContainer = static_cast<fp_Container*>(getNthCon(i));
1900
1901 // ignore footnotes
1902 if (pContainer->getContainerType() == FP_CONTAINER_FOOTNOTE)
1903 continue;
1904 // ignore annotations
1905 if (pContainer->getContainerType() == FP_CONTAINER_ANNOTATION)
1906 continue;
1907
1908 xxx_UT_DEBUGMSG(("Column Layout: Container %d Container %x Type %d \n",i,pContainer,pContainer->getContainerType()));
1909 //
1910 // Set the location first so the height of a table can be calculated
1911 // and adjusted.
1912 //
1913 if(pContainer->getContainerType() == FP_CONTAINER_LINE)
1914 {
1915 //
1916 // Handle case of lines broken around a positioned object with text wrap on
1917 //
1918 fp_Line * pLine = static_cast<fp_Line *>(pContainer);
1919 xxx_UT_DEBUGMSG(("Line %x X %d Y %d MaxWidth %d Width %d Height %d \n",pLine,pLine->getX(),pLine->getY(),pLine->getMaxWidth(),pLine->getWidth(),pLine->getHeight()));
1920 if(pLine->isWrapped())
1921 {
1922 addWrappedLine(pLine);
1923 }
1924 #if 0
1925 else if((pLine->getMaxWidth() > 0) && (pLine->getMaxWidth() < getWidth()))
1926 {
1927 addWrappedLine(pLine);
1928 }
1929 #endif
1930 if(pLine->isSameYAsPrevious() && pLine->getPrev())
1931 {
1932 UT_sint32 iPrevY = static_cast<fp_Line *>(pLine->getPrev())->getY();
1933 if(pLine->getY() != iPrevY)
1934 {
1935 pLine->clearScreen();
1936 pLine->setY(iPrevY);
1937 }
1938 pPrevContainer = pLine;
1939 xxx_UT_DEBUGMSG(("Layout: %x SameY container %d getY %d getX %d width %d \n",pLine,i,pLine->getY(),pLine->getX(),pLine->getMaxWidth()));
1940 continue;
1941 }
1942 }
1943 if(pContainer->getY() != iY)
1944 {
1945 pContainer->clearScreen();
1946 if((m_iRedrawHeight == -1) && (pContainer->getY() > 0))
1947 m_iRedrawHeight = pContainer->getY();
1948
1949 }
1950 xxx_UT_DEBUGMSG(("Layout: container %d Height %d setY %d \n",i,iY));
1951 //
1952 // fxime comeback and re-evaluate this
1953 // UT_ASSERT(iY>=0);
1954 pContainer->setY(iY);
1955 // UT_ASSERT(iY == pContainer->getY());
1956 //UT_ASSERT(pContainer->getY() == iY);
1957 //
1958 // This is to speedup redraws.
1959 //
1960 fp_TableContainer * pTab = NULL;
1961 fp_TOCContainer * pTOC = NULL;
1962 UT_sint32 iHeight = pContainer->getHeight();
1963 if(pContainer->getContainerType() == FP_CONTAINER_TABLE)
1964 {
1965 pTab = static_cast<fp_TableContainer *>(pContainer);
1966 iHeight = pTab->getHeight();
1967 }
1968 if(pContainer->getContainerType() == FP_CONTAINER_TOC)
1969 {
1970 pTOC = static_cast<fp_TOCContainer *>(pContainer);
1971 iHeight = pTOC->getHeight();
1972 // This is incorrect; if the TOC has been delete in revisions mode, is will
1973 // have 0 height
1974 // UT_ASSERT(iHeight > 0);
1975 }
1976 else if(pContainer->getContainerType() == FP_CONTAINER_LINE)
1977 {
1978 pLastLine = static_cast<fp_Line *>(pContainer);
1979 iHeight = pLastLine->getHeight();
1980 UT_sint32 count = vecBlocks.getItemCount();
1981 if(count == 0)
1982 {
1983 vecBlocks.addItem(pLastLine->getBlock());
1984 }
1985 else
1986 {
1987 if(vecBlocks.getNthItem(count-1) != pLastLine->getBlock())
1988 {
1989 vecBlocks.addItem(pLastLine->getBlock());
1990 }
1991 }
1992 }
1993 if(iHeight > _getMaxContainerHeight())
1994 {
1995 _setMaxContainerHeight(iHeight);
1996 }
1997 UT_sint32 iContainerHeight = iHeight;
1998 if(pTab)
1999 {
2000 iContainerHeight = pTab->getHeight();
2001 }
2002 if(pTOC)
2003 {
2004 iContainerHeight = pTOC->getHeight();
2005 }
2006 iContainerMarginAfter = pContainer->getMarginAfter();
2007 xxx_UT_DEBUGMSG(("Layout: container %d Height %d Margin %d setY %d \n",i,iContainerHeight,iContainerMarginAfter,iY));
2008 // UT_ASSERT(iContainerHeight > 0);
2009 // Update height of previous line now we know the gap between
2010 // it and the current line.
2011 if (pPrevContainer)
2012 {
2013 if(pPrevContainer->getContainerType() == FP_CONTAINER_LINE)
2014 {
2015 fp_Line * pLine = static_cast<fp_Line *>(pPrevContainer);
2016 while(pLine && pLine->isSameYAsPrevious())
2017 {
2018 pLine->setAssignedScreenHeight(iY - iPrevY2);
2019 pLine = static_cast<fp_Line *>(pLine->getPrev());
2020 }
2021 if(pLine)
2022 {
2023 pLine->setAssignedScreenHeight(iY - iPrevY2);
2024 }
2025 }
2026 else
2027 {
2028 xxx_UT_DEBUGMSG(("layout: Assigned screen height %x %d \n",pPrevContainer,iY-iPrevY2));
2029 pPrevContainer->setAssignedScreenHeight(iY - iPrevY2);
2030 }
2031 }
2032 iPrevY2 = iY;
2033 iY += iContainerHeight;
2034 iY += iContainerMarginAfter;
2035 #if DEBUG
2036 if (iY - iContainerMarginAfter > getMaxHeight())
2037 {
2038 UT_DEBUGMSG(("Problem; MaxColHeight: %d present height: %d\n",
2039 getMaxHeight(), iY - iContainerMarginAfter));
2040 UT_ASSERT(UT_SHOULD_NOT_HAPPEN);
2041 }
2042 #endif
2043 pPrevContainer = pContainer;
2044 }
2045 // Correct height position of the last line
2046 if (pPrevContainer)
2047 {
2048 UT_ASSERT((iY - iPrevY2 + getGraphics()->tlu(1)) > 0);
2049 iY -= iContainerMarginAfter;
2050 if(pPrevContainer->getContainerType() == FP_CONTAINER_LINE)
2051 {
2052 fp_Line * pLine = static_cast<fp_Line *>(pPrevContainer);
2053 while(pLine && pLine->isSameYAsPrevious())
2054 {
2055 pLine->setAssignedScreenHeight(iY - iPrevY2);
2056 pLine = static_cast<fp_Line *>(pLine->getPrev());
2057 }
2058 if(pLine)
2059 {
2060 pLine->setAssignedScreenHeight(iY - iPrevY2);
2061 }
2062 }
2063 }
2064 //
2065 // Set the frames on the page
2066 //
2067 UT_sint32 count = vecBlocks.getItemCount();
2068 for(i=0; i < count; i++)
2069 {
2070 fl_BlockLayout * pBlock = vecBlocks.getNthItem(i);
2071 if(i < count -1)
2072 {
2073 pBlock->setFramesOnPage(NULL);
2074 }
2075 else
2076 {
2077 pBlock->setFramesOnPage(pLastLine);
2078 }
2079 }
2080 // validate();
2081
2082 if (getHeight() == iY)
2083 {
2084 return;
2085 }
2086
2087 setHeight(iY);
2088 getPage()->columnHeightChanged(this);
2089 fl_DocSectionLayout * pDSL = getPage()->getOwningSection();
2090 pDSL = pDSL->getNextDocSection();
2091 while(pDSL)
2092 {
2093 pDSL->setNeedsSectionBreak(true,NULL);
2094 pDSL = pDSL->getNextDocSection();
2095 }
2096 }
2097
getMaxHeight(void) const2098 UT_sint32 fp_Column::getMaxHeight(void) const
2099 {
2100 const fp_VerticalContainer * pVC = static_cast<const fp_VerticalContainer *>(this);
2101 UT_sint32 iMaxHeight = 0;
2102 if(!getPage())
2103 {
2104 iMaxHeight = pVC->getMaxHeight();
2105 }
2106 else
2107 {
2108 iMaxHeight = getPage()->getAvailableHeightForColumn(this);
2109 }
2110 //UT_ASSERT(iMaxHeight > 0);
2111 return iMaxHeight;
2112 }
2113
getDocSectionLayout(void) const2114 fl_DocSectionLayout* fp_Column::getDocSectionLayout(void) const
2115 {
2116 UT_ASSERT(getSectionLayout()->getType() == FL_SECTION_DOC ||
2117 getSectionLayout()->getType() == FL_SECTION_HDRFTR ||
2118 getSectionLayout()->getType() == FL_SECTION_ENDNOTE);
2119
2120 return static_cast<fl_DocSectionLayout*>(getSectionLayout());
2121 }
2122
2123 /*!
2124 * This container is actually to display HdrFtrShadows which are repeated
2125 * for every page in the document. If the text is too high it is clipped to
2126 * to fit in the container. It's up to the user to adjust the height of the
2127 * header/footer region to fit the text.
2128 */
fp_ShadowContainer(UT_sint32 iX,UT_sint32 iY,UT_sint32 iWidth,UT_sint32 iHeight,fl_SectionLayout * pSectionLayout)2129 fp_ShadowContainer::fp_ShadowContainer(UT_sint32 iX,
2130 UT_sint32 iY,
2131 UT_sint32 iWidth,
2132 UT_sint32 iHeight,
2133 fl_SectionLayout* pSectionLayout)
2134 : fp_VerticalContainer(FP_CONTAINER_COLUMN_SHADOW, pSectionLayout)
2135 {
2136 _setX(iX);
2137 _setY(iY);
2138 setWidth(iWidth);
2139 setHeight(iHeight);
2140 setMaxHeight(iHeight);
2141 m_bHdrFtrBoxDrawn = false;
2142 }
2143
~fp_ShadowContainer()2144 fp_ShadowContainer::~fp_ShadowContainer()
2145 {
2146 xxx_UT_DEBUGMSG(("Delete Shadow Container %x from shadow Layout %x \n",this,getSectionLayout()));
2147 getSectionLayout()->setFirstContainer(NULL);
2148 }
2149
2150
layout(void)2151 void fp_ShadowContainer::layout(void)
2152 {
2153 layout(false);
2154 }
2155
layout(bool bForceLayout)2156 void fp_ShadowContainer::layout(bool bForceLayout)
2157 {
2158 UT_sint32 iY = 5;
2159 UT_uint32 iCountContainers = countCons();
2160 FV_View * pView = getPage()->getDocLayout()->getView();
2161 bool doLayout = true;
2162 if(pView)
2163 {
2164 doLayout = pView->getViewMode() == VIEW_PRINT;
2165 }
2166 if(bForceLayout)
2167 {
2168 doLayout = true;
2169 }
2170 for (UT_uint32 i=0; i < iCountContainers; i++)
2171 {
2172 fp_Container* pContainer = static_cast<fp_Container*>(getNthCon(i));
2173 fp_TableContainer * pTab = NULL;
2174 fp_TOCContainer * pTOC = NULL;
2175 if(pContainer->getContainerType() == FP_CONTAINER_TABLE)
2176 {
2177 pTab = static_cast<fp_TableContainer *>(pContainer);
2178 xxx_UT_DEBUGMSG(("Found Table in shadow!!! height = %d \n",pTab->getHeight()));
2179 }
2180 else if(pContainer->getContainerType() == FP_CONTAINER_TOC)
2181 {
2182 pTOC = static_cast<fp_TOCContainer *>(pContainer);
2183 UT_DEBUGMSG(("Found TOC in shadow!!!\n"));
2184 }
2185 //
2186 // FIXME: Implement this one day. Tables in header/footers.
2187 // if((pTab!= NULL) && !pTab->isThisBroken())
2188 // {
2189 // fp_Container * pBroke = static_cast<fp_Container *>(pTab->VBreakAt(0));
2190 // }
2191 UT_sint32 iContainerHeight = pContainer->getHeight();
2192 if(pTab != NULL)
2193 {
2194 iContainerHeight = pTab->getHeight();
2195 }
2196 if(pTOC != NULL)
2197 {
2198 iContainerHeight = pTOC->getHeight();
2199 }
2200 UT_sint32 iContainerMarginAfter = pContainer->getMarginAfter();
2201 UT_sint32 sum = iContainerHeight + iContainerMarginAfter;
2202 if(((iY + sum) <= (getMaxHeight())) && doLayout)
2203 {
2204 pContainer->setY(iY);
2205 }
2206 iY += iContainerHeight;
2207 iY += iContainerMarginAfter;
2208 }
2209
2210 UT_sint32 iNewHeight = iY;
2211 if (getHeight() == iNewHeight)
2212 {
2213 return;
2214 }
2215
2216 if(iY <= getMaxHeight())
2217 {
2218 setHeight(iNewHeight);
2219 }
2220 else
2221 {
2222 fl_HdrFtrSectionLayout * pHFSL = getHdrFtrSectionLayout();
2223 fl_DocSectionLayout * pDSL = pHFSL->getDocSectionLayout();
2224 bool bHdrFtr = (pHFSL->getHFType() <= FL_HDRFTR_HEADER_LAST);
2225 if(iNewHeight > getPage()->getHeight()/3)
2226 {
2227 iNewHeight = getPage()->getHeight()/3;
2228 }
2229 pDSL->setHdrFtrHeightChange(bHdrFtr,iNewHeight+getGraphics()->tlu(3));
2230 setHeight(getMaxHeight());
2231 }
2232 }
2233
2234 /*!
2235 * get the shadow associated with this hdrftrContainer
2236 */
2237
getShadow(void)2238 fl_HdrFtrShadow * fp_ShadowContainer::getShadow(void)
2239 {
2240 fl_HdrFtrSectionLayout* pHdrFtrSL = getHdrFtrSectionLayout();
2241 return pHdrFtrSL->findShadow( getPage() );
2242 }
2243
2244 /*!
2245 * Set the page for this shadow. Also set the fg_FillType parent.
2246 */
2247
setPage(fp_Page * pPage)2248 void fp_ShadowContainer::setPage(fp_Page *pPage)
2249 {
2250 m_pPage = pPage;
2251 if(pPage)
2252 {
2253 getFillType().setParent(&pPage->getFillType());
2254 }
2255 }
2256
getHdrFtrSectionLayout(void) const2257 fl_HdrFtrSectionLayout* fp_ShadowContainer::getHdrFtrSectionLayout(void) const
2258 {
2259 UT_ASSERT(getSectionLayout()->getType() == FL_SECTION_HDRFTR);
2260
2261 return static_cast<fl_HdrFtrSectionLayout*>(getSectionLayout());
2262 }
2263
2264
2265 /*!
2266 Clear container content from screen.
2267 */
clearScreen(void)2268 void fp_ShadowContainer::clearScreen(void)
2269 {
2270 FV_View * pView = getPage()->getDocLayout()->getView();
2271 if(pView->getViewMode() != VIEW_PRINT)
2272 {
2273 UT_DEBUGMSG(("SEVIOR: Attempting to clear Header/Footer in Normal Mode \n"));
2274 return;
2275 }
2276 int count = countCons();
2277 for (int i = 0; i<count; i++)
2278 {
2279 fp_ContainerObject* pContainer = static_cast<fp_ContainerObject*>(getNthCon(i));
2280
2281 pContainer->clearScreen();
2282 }
2283 clearHdrFtrBoundaries();
2284 }
2285
2286
2287
2288 /*!
2289 Draw container content
2290 \param pDA Draw arguments
2291 */
2292
draw(dg_DrawArgs * pDA)2293 void fp_ShadowContainer::draw(dg_DrawArgs* pDA)
2294 {
2295 FV_View * pView = getPage()->getDocLayout()->getView();
2296 if((pView->getViewMode() != VIEW_PRINT) && pDA->pG->queryProperties(GR_Graphics::DGP_SCREEN) )
2297 {
2298 UT_DEBUGMSG(("SEVIOR: Attempting to draw Header/Footer in Normal Mode \n"));
2299 return;
2300 }
2301 if((pView->getViewMode() != VIEW_PRINT) && pDA->pG->queryProperties(GR_Graphics::DGP_PAPER) )
2302 {
2303 layout(true);
2304 }
2305
2306 UT_sint32 count = countCons();
2307 UT_sint32 iY= 0;
2308 for (UT_sint32 i = 0; i<count; i++)
2309 {
2310 fp_Container* pContainer = static_cast<fp_Container*>(getNthCon(i));
2311
2312 dg_DrawArgs da = *pDA;
2313 da.xoff += pContainer->getX();
2314 da.yoff += pContainer->getY();
2315
2316 UT_sint32 iContainerHeight = pContainer->getHeight();
2317 UT_sint32 iContainerMarginAfter = pContainer->getMarginAfter();
2318 iY += iContainerHeight;
2319 iY += iContainerMarginAfter;
2320 //
2321 // Clip to keep inside header/footer container
2322 //
2323 if(iY > getMaxHeight())
2324 break;
2325 pContainer->draw(&da);
2326 }
2327 if(pView && pView->isHdrFtrEdit() && pDA->pG->queryProperties(GR_Graphics::DGP_SCREEN) && pView->getEditShadow() == getShadow())
2328 {
2329 _drawHdrFtrBoundaries(pDA);
2330 }
2331 else
2332 {
2333 clearHdrFtrBoundaries();
2334 _drawBoundaries(pDA);
2335 }
2336 if((pView->getViewMode() != VIEW_PRINT) && pDA->pG->queryProperties(GR_Graphics::DGP_PAPER) )
2337 {
2338 layout(false);
2339 }
2340 }
2341
2342 /*!
2343 * This method draws a solid box around the currently editted Header/Footer
2344 */
_drawHdrFtrBoundaries(dg_DrawArgs * pDA)2345 void fp_ShadowContainer::_drawHdrFtrBoundaries(dg_DrawArgs * pDA)
2346 {
2347 if(!pDA->pG->queryProperties(GR_Graphics::DGP_SCREEN))
2348 {
2349 return;
2350 }
2351 FV_View * pView = getPage()->getDocLayout()->getView();
2352 if(pView->getViewMode() != VIEW_PRINT)
2353 {
2354 UT_DEBUGMSG(("SEVIOR: Attempting to draw Header/Footer in Normal Mode \n"));
2355 return;
2356 }
2357 //
2358 // Can put this in to speed things up.
2359 //
2360 // if(m_bHdrFtrBoxDrawn)
2361 // return;
2362 UT_RGBColor clrDrawHdrFtr(127,127,127);
2363 getGraphics()->setLineWidth(getGraphics()->tlu(1));
2364 getGraphics()->setColor(clrDrawHdrFtr);
2365 //
2366 // These magic numbers stop clearscreens from blanking the lines
2367 //
2368 m_ixoffBegin = pDA->xoff-2;
2369 m_iyoffBegin = pDA->yoff+2;
2370 m_ixoffEnd = pDA->xoff + getWidth() + getGraphics()->tlu(1);
2371 m_iyoffEnd = pDA->yoff + getMaxHeight() - getGraphics()->tlu(1);
2372
2373 GR_Painter painter(getGraphics());
2374
2375 painter.drawLine(m_ixoffBegin, m_iyoffBegin, m_ixoffEnd, m_iyoffBegin);
2376 painter.drawLine(m_ixoffBegin, m_iyoffEnd, m_ixoffEnd, m_iyoffEnd);
2377 painter.drawLine(m_ixoffBegin, m_iyoffBegin, m_ixoffBegin, m_iyoffEnd);
2378 painter.drawLine(m_ixoffEnd, m_iyoffBegin, m_ixoffEnd, m_iyoffEnd);
2379 getGraphics()->setLineWidth(getGraphics()->tlu(1));
2380 m_bHdrFtrBoxDrawn = true;
2381 }
2382
2383
2384 /*!
2385 * This method clears the solid box around the curently editted Header/Footer
2386 */
clearHdrFtrBoundaries(void)2387 void fp_ShadowContainer::clearHdrFtrBoundaries(void)
2388 {
2389 if(!m_bHdrFtrBoxDrawn)
2390 return;
2391 const UT_RGBColor * pClr = getPage()->getFillType().getColor();
2392 getGraphics()->setLineWidth(getGraphics()->tlu(1));
2393 getGraphics()->setColor(*pClr);
2394 //
2395 // Paint over the previous lines with the page color
2396 //
2397
2398 GR_Painter painter(getGraphics());
2399
2400 painter.drawLine(m_ixoffBegin, m_iyoffBegin, m_ixoffEnd, m_iyoffBegin);
2401 painter.drawLine(m_ixoffBegin, m_iyoffEnd, m_ixoffEnd, m_iyoffEnd);
2402 painter.drawLine(m_ixoffBegin, m_iyoffBegin, m_ixoffBegin, m_iyoffEnd);
2403 painter.drawLine(m_ixoffEnd, m_iyoffBegin, m_ixoffEnd, m_iyoffEnd);
2404 getGraphics()->setLineWidth(getGraphics()->tlu(1));
2405 m_bHdrFtrBoxDrawn = false;
2406 }
2407
2408 /*!
2409 * Ok this container class is for the hdrftrSectionLayout. It never gets drawn
2410 * on the screen, only the shadows get drawn. The page pointer contains a NULL.
2411 * This makes it possible to format the hdrftrSectionLayout and to do
2412 * editting operations on header/footers like regular text.
2413 \param iwidth width of the page in pixels?? I think.
2414 \param IwidthLayout width of the screen in layout units
2415 \param fl_SectionLayout * pSectionLayout pointer to the
2416 fl_HdrFtrSectionLayout that owns this container.
2417 */
2418
fp_HdrFtrContainer(UT_sint32 iWidth,fl_SectionLayout * pSectionLayout)2419 fp_HdrFtrContainer::fp_HdrFtrContainer(UT_sint32 iWidth,
2420 fl_SectionLayout* pSectionLayout)
2421 : fp_VerticalContainer(FP_CONTAINER_HDRFTR, pSectionLayout)
2422 {
2423 _setX(0);
2424 _setY(0);
2425 setWidth(iWidth);
2426 setHeight(0);
2427 }
2428
~fp_HdrFtrContainer()2429 fp_HdrFtrContainer::~fp_HdrFtrContainer()
2430 {
2431 }
2432
2433 /*!
2434 * Overloaded layout for VirtualCOntainer. We don't care about the height or
2435 * of the container.
2436 */
2437
layout(void)2438 void fp_HdrFtrContainer::layout(void)
2439 {
2440 UT_sint32 iY = 0;
2441
2442 UT_uint32 iCountContainers = countCons();
2443
2444 for (UT_uint32 i=0; i < iCountContainers; i++)
2445 {
2446 fp_Container* pContainer = static_cast<fp_Container*>(getNthCon(i));
2447 fp_TableContainer * pTab = NULL;
2448 if(pContainer->getContainerType() == FP_CONTAINER_TABLE)
2449 {
2450 pTab = static_cast<fp_TableContainer *>(pContainer);
2451 }
2452
2453 UT_sint32 iContainerHeight = pContainer->getHeight();
2454 if(pTab)
2455 {
2456 iContainerHeight = pTab->getHeight();
2457 }
2458 UT_sint32 iContainerMarginAfter = pContainer->getMarginAfter();
2459
2460 pContainer->setY(iY);
2461 iY += iContainerHeight;
2462 iY += iContainerMarginAfter;
2463 }
2464
2465 UT_sint32 iNewHeight = iY;
2466
2467 if (getHeight() == iNewHeight)
2468 {
2469 return;
2470 }
2471
2472 setHeight(iNewHeight);
2473 }
2474
2475 /*!
2476 * Returns a pointer to the HdrFtrSectionLayout that owns this container
2477 */
getHdrFtrSectionLayout(void) const2478 fl_HdrFtrSectionLayout* fp_HdrFtrContainer::getHdrFtrSectionLayout(void) const
2479 {
2480 UT_ASSERT(getSectionLayout()->getType() == FL_SECTION_HDRFTR);
2481
2482 return static_cast<fl_HdrFtrSectionLayout*>(getSectionLayout());
2483 }
2484
2485
2486 /*!
2487 Get line's offsets relative to the screen for this method we just return
2488 * -100000 since virtual containers are never drawn.
2489 \param pContainer Container
2490 \retval xoff Container's X offset relative the screen actually -10000
2491 \retval yoff Container's Y offset relative the screen actually -10000
2492 */
getScreenOffsets(fp_ContainerObject *,UT_sint32 & xoff,UT_sint32 & yoff)2493 void fp_HdrFtrContainer::getScreenOffsets(fp_ContainerObject* /*pContainer*/,
2494 UT_sint32& xoff, UT_sint32& yoff)
2495 {
2496 xoff = -100000;
2497 yoff = -100000;
2498 }
2499
2500
2501 /*!
2502 NOP's for clear screen.
2503 */
clearScreen(void)2504 void fp_HdrFtrContainer::clearScreen(void)
2505 {
2506
2507 }
2508
2509 /*!
2510 NOP for Draw's
2511 \param pDA Draw arguments
2512 */
draw(dg_DrawArgs *)2513 void fp_HdrFtrContainer::draw(dg_DrawArgs* /*pDA*/)
2514 {
2515
2516 }
2517