1 /* AbiWord
2 * Copyright (c) 2003 Martin Sevior <msevior@physics.unimelb.edu.au>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version 2
7 * of the License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA.
18 */
19
20 #include "fv_FrameEdit.h"
21 #include "fl_DocLayout.h"
22 #include "pd_Document.h"
23 #include "gr_DrawArgs.h"
24 #include "gr_Graphics.h"
25 #include "ut_units.h"
26 #include "ut_debugmsg.h"
27 #include "fl_BlockLayout.h"
28 #include "fp_Line.h"
29 #include "fp_Run.h"
30 #include "pf_Frag.h"
31 #include "pf_Frag_Strux.h"
32 #include "fp_FrameContainer.h"
33 #include "fv_View.h"
34 #include "ev_Mouse.h"
35 #include "xap_Frame.h"
36 #include "gr_Painter.h"
37 #include "xap_App.h"
38 #include "fv_ViewDoubleBuffering.h"
39
FV_FrameEdit(FV_View * pView)40 FV_FrameEdit::FV_FrameEdit (FV_View * pView)
41 : FV_Base (pView),
42 m_iFrameEditMode(FV_FrameEdit_NOT_ACTIVE),
43 m_pFrameLayout(NULL),
44 m_pFrameContainer(NULL),
45 m_iLastX(0),
46 m_iLastY(0),
47 m_iInitialDragX(0),
48 m_iInitialDragY(0),
49 m_bInitialClick(false),
50 m_pFrameImage(NULL),
51 m_pAutoScrollTimer(NULL),
52 m_iInitialFrameX(0),
53 m_iInitialFrameY(0),
54 m_sRelWidth(""),
55 m_sMinHeight(""),
56 m_sExpandHeight("")
57 {
58 UT_ASSERT_HARMLESS(pView);
59 }
60
~FV_FrameEdit()61 FV_FrameEdit::~FV_FrameEdit()
62 {
63 DELETEP(m_pFrameImage);
64 if(m_pAutoScrollTimer)
65 {
66 m_pAutoScrollTimer->stop();
67 DELETEP(m_pAutoScrollTimer);
68 }
69 }
70
setPointInside(void)71 void FV_FrameEdit::setPointInside(void)
72 {
73 fl_FrameLayout * pFL = getFrameLayout();
74 if(pFL == NULL)
75 {
76 return;
77 }
78 PT_DocPosition pos = pFL->getPosition(true) + pFL->getLength()-1;
79 setMode(FV_FrameEdit_NOT_ACTIVE);
80 m_pView->_setPoint(pos);
81 }
82
isActive(void) const83 bool FV_FrameEdit::isActive(void) const
84 {
85 return (FV_FrameEdit_NOT_ACTIVE != m_iFrameEditMode);
86 }
87
setMode(FV_FrameEditMode iEditMode)88 void FV_FrameEdit::setMode(FV_FrameEditMode iEditMode)
89 {
90 UT_DEBUGMSG(("Frame Edit mode set to %d \n",iEditMode));
91 if(iEditMode == FV_FrameEdit_NOT_ACTIVE)
92 {
93 m_pFrameLayout = NULL;
94 m_pFrameContainer = NULL;
95 DELETEP(m_pFrameImage);
96 m_recCurFrame.width = 0;
97 m_recCurFrame.height = 0;
98 setDragWhat( FV_DragNothing );
99 m_iLastX = 0;
100 m_iLastY = 0;
101 }
102 m_iFrameEditMode = iEditMode;
103 if(getGraphics() && iEditMode != FV_FrameEdit_NOT_ACTIVE)
104 {
105 getGraphics()->allCarets()->disable();
106 m_pView->m_countDisable++;
107 }
108 }
109
110
111 static bool bScrollRunning = false;
112 static UT_Worker * s_pScroll = NULL;
113 static UT_sint32 iExtra = 0;
114
_actuallyScroll(UT_Worker * pWorker)115 void FV_FrameEdit::_actuallyScroll(UT_Worker * pWorker)
116 {
117 // this is a static callback method and does not have a 'this' pointer.
118
119 FV_FrameEdit * pFE = static_cast<FV_FrameEdit *>(pWorker->getInstanceData());
120 UT_return_if_fail(pFE);
121 if(pFE->getFrameEditMode() != FV_FrameEdit_DRAG_EXISTING)
122 {
123 if(pFE->m_pAutoScrollTimer)
124 pFE->m_pAutoScrollTimer->stop();
125 DELETEP(pFE->m_pAutoScrollTimer);
126 iExtra = 0;
127 s_pScroll->stop();
128 delete s_pScroll;
129 s_pScroll = NULL;
130 bScrollRunning = false;
131 return;
132 }
133 FV_View * pView = pFE->m_pView;
134 UT_sint32 x = pFE->m_xLastMouse;
135 UT_sint32 y = pFE->m_yLastMouse;
136 bool bScrollDown = false;
137 bool bScrollUp = false;
138 bool bScrollLeft = false;
139 bool bScrollRight = false;
140 bool bStop = false;
141 if(y<=0)
142 {
143 if(pView->getYScrollOffset() <= 10)
144 {
145 pView->setYScrollOffset(0);
146 pView->updateScreen(false);
147 bStop = true;
148 }
149 else
150 {
151 bScrollUp = true;
152 }
153 }
154 else if( y >= pView->getWindowHeight())
155 {
156 if((pView->getYScrollOffset()+pView->getWindowHeight()+10) >= pView->getLayout()->getHeight())
157 {
158 pView->setYScrollOffset(pView->getLayout()->getHeight() - pView->getWindowHeight());
159 pView->updateScreen(false);
160 bStop = true;
161 UT_DEBUGMSG(("!!!!!!!!!!!!PLLLLLLLLLEEEEAAAASSSEEEEE STOOPPP!!!! \n"));
162 }
163 else
164 {
165 bScrollDown = true;
166 }
167 }
168 if(x <= 0)
169 {
170 bScrollLeft = true;
171 }
172 else if(x >= pView->getWindowWidth())
173 {
174 bScrollRight = true;
175 }
176 if(!bStop && (bScrollDown || bScrollUp || bScrollLeft || bScrollRight))
177 {
178 pFE->getGraphics()->setClipRect(&pFE->m_recCurFrame);
179 pView->updateScreen(false);
180 pFE->getGraphics()->setClipRect(NULL);
181 UT_sint32 minScroll = pFE->getGraphics()->tlu(20);
182 if(bScrollUp)
183 {
184 UT_sint32 yscroll = abs(y);
185 if(yscroll < minScroll)
186 yscroll = minScroll;
187 pView->cmdScroll(AV_SCROLLCMD_LINEUP, static_cast<UT_uint32>( yscroll +iExtra));
188 }
189 else if(bScrollDown)
190 {
191 UT_sint32 yscroll = y - pView->getWindowHeight();
192 if(yscroll < minScroll)
193 yscroll = minScroll;
194 pView->cmdScroll(AV_SCROLLCMD_LINEDOWN, static_cast<UT_uint32>(yscroll+iExtra));
195 }
196 if(bScrollLeft)
197 {
198 pView->cmdScroll(AV_SCROLLCMD_LINELEFT, static_cast<UT_uint32>(-x));
199 }
200 else if(bScrollRight)
201 {
202 pView->cmdScroll(AV_SCROLLCMD_LINERIGHT, static_cast<UT_uint32>(x -pView->getWindowWidth()));
203 }
204 pFE->drawFrame(true);
205 iExtra = 0;
206 return;
207 }
208 else
209 {
210 if(pFE->m_pAutoScrollTimer)
211 pFE->m_pAutoScrollTimer->stop();
212 DELETEP(pFE->m_pAutoScrollTimer);
213
214 }
215 iExtra = 0;
216 s_pScroll->stop();
217 delete s_pScroll;
218 s_pScroll = NULL;
219 bScrollRunning = false;
220 }
221
_autoScroll(UT_Worker * pWorker)222 void FV_FrameEdit::_autoScroll(UT_Worker * pWorker)
223 {
224 UT_return_if_fail(pWorker);
225 // this is a static callback method and does not have a 'this' pointer.
226
227 FV_FrameEdit * pFE = static_cast<FV_FrameEdit *>(pWorker->getInstanceData());
228 UT_return_if_fail(pFE);
229 if(bScrollRunning)
230 {
231 if(iExtra < pFE->getGraphics()->tlu(600))
232 iExtra += pFE->getGraphics()->tlu(20);
233 UT_DEBUGMSG(("Dropping FrameEditautoscroll !!!!!!! \n"));
234 return;
235 }
236
237 UT_DEBUGMSG(("_autoscroll started!! \n"));
238 int inMode = UT_WorkerFactory::IDLE | UT_WorkerFactory::TIMER;
239 // int inMode = UT_WorkerFactory::TIMER;
240 UT_WorkerFactory::ConstructMode outMode = UT_WorkerFactory::NONE;
241 s_pScroll = UT_WorkerFactory::static_constructor (_actuallyScroll,pFE, inMode, outMode);
242
243 // If the worker is working on a timer instead of in the idle
244 // time, set the frequency of the checks.
245 if ( UT_WorkerFactory::TIMER == outMode )
246 {
247 // this is really a timer, so it's safe to static_cast it
248 static_cast<UT_Timer*>(s_pScroll)->set(100);
249 }
250 bScrollRunning = true;
251 iExtra = 0;
252 s_pScroll->start();
253 }
254
255 /*!
256 * Returns 0 if the frame has never been dragged at all.
257 * Returns 1 if the frame has been dragged a little bit
258 * Return 10 if the frame has been dragged a lot.
259 */
haveDragged(void) const260 UT_sint32 FV_FrameEdit::haveDragged(void) const
261 {
262 if(!m_bFirstDragDone)
263 {
264 return 0;
265 }
266 if((abs(m_xLastMouse - m_iFirstEverX) + abs(m_yLastMouse - m_iFirstEverY)) <
267 getGraphics()->tlu(3))
268 {
269 UT_DEBUGMSG(("Not dragged enough - return 1 \n"));
270 return 1;
271 }
272 return 10;
273 }
274
_mouseDrag(UT_sint32 x,UT_sint32 y)275 void FV_FrameEdit::_mouseDrag(UT_sint32 x, UT_sint32 y)
276 {
277 FV_ViewDoubleBuffering dblBuffObj(m_pView, false, false);
278 dblBuffObj.beginDoubleBuffering();
279
280 UT_sint32 dx = 0;
281 UT_sint32 dy = 0;
282 UT_Rect expX(0,m_recCurFrame.top,0,m_recCurFrame.height);
283 UT_Rect expY(m_recCurFrame.left,0,m_recCurFrame.width,0);
284
285 FV_Base::_doMouseDrag( x, y, dx, dy, expX, expY );
286 if (getDragWhat()==FV_DragWhole)
287 {
288 UT_sint32 diffx = 0;
289 UT_sint32 diffy = 0;
290 UT_sint32 iext = getGraphics()->tlu(3);
291
292 bool bScrollDown = false;
293 bool bScrollUp = false;
294 bool bScrollLeft = false;
295 bool bScrollRight = false;
296 if(y<=0)
297 {
298 if(m_pView->getYScrollOffset() <= 0)
299 {
300 m_pView->setYScrollOffset(0);
301 m_pView->updateScreen(false);
302 if(m_pAutoScrollTimer)
303 m_pAutoScrollTimer->stop();
304 DELETEP(m_pAutoScrollTimer);
305 }
306 else
307 {
308 bScrollUp = true;
309 }
310 }
311 else if( y >= m_pView->getWindowHeight())
312 {
313 if(m_pView->getYScrollOffset() >= m_pView->getLayout()->getHeight())
314 {
315 m_pView->setYScrollOffset(m_pView->getLayout()->getHeight());
316 m_pView->updateScreen(false);
317 if(m_pAutoScrollTimer)
318 m_pAutoScrollTimer->stop();
319 DELETEP(m_pAutoScrollTimer);
320 }
321 else
322 {
323 bScrollDown = true;
324 }
325 }
326 if(x <= 0)
327 {
328 bScrollLeft = true;
329 }
330 else if(x >= m_pView->getWindowWidth())
331 {
332 bScrollRight = true;
333 }
334 if(bScrollDown || bScrollUp || bScrollLeft || bScrollRight)
335 {
336 if(m_pAutoScrollTimer != NULL)
337 {
338 return;
339 }
340 m_pAutoScrollTimer = UT_Timer::static_constructor(_autoScroll, this);
341 m_pAutoScrollTimer->set(AUTO_SCROLL_MSECS);
342 m_pAutoScrollTimer->start();
343 return;
344 }
345 diffx = m_iLastX - x;
346 diffy = m_iLastY - y;
347 dx = -diffx;
348 dy = - diffy;
349 m_recCurFrame.left -= diffx;
350 m_recCurFrame.top -= diffy;
351 UT_DEBUGMSG(("Doing drag whole frame left %d top %d \n",m_recCurFrame.left, m_recCurFrame.top));
352 if(dx < 0)
353 {
354 expX.left = m_recCurFrame.left+m_recCurFrame.width -iext;
355 expX.width = -dx + 2*iext;
356 if(dy > 0)
357 {
358 expX.top -= iext;
359 expX.height += dy + 2*iext;
360 }
361 else
362 {
363 expX.top -= iext;
364 expX.height += (-dy + 2*iext);
365 }
366 }
367 else
368 {
369 expX.left = m_recCurFrame.left - dx - iext;
370 expX.width = dx + 2*iext;
371 if(dy > 0)
372 {
373 expX.top -= iext;
374 expX.height += dy + 2*iext;
375 }
376 else
377 {
378 expX.top -= iext;
379 expX.height += (-dy + 2*iext);
380 }
381 }
382 expY.left -= iext;
383 expY.width += 2*iext;
384 if(dy < 0)
385 {
386 expY.top = m_recCurFrame.top + m_recCurFrame.height -iext;
387 expY.height = -dy + 2*iext;
388 }
389 else
390 {
391 expY.top = m_recCurFrame.top - dy - iext;
392 expY.height = dy + 2*iext;
393 }
394 }
395 _checkDimensions();
396
397 if(FV_FrameEdit_RESIZE_INSERT == m_iFrameEditMode)
398 {
399 xxx_UT_DEBUGMSG(("width after drag %d \n",m_recCurFrame.width));
400 }
401 else
402 {
403 if (FV_FrameEdit_RESIZE_EXISTING == m_iFrameEditMode)
404 {
405 UT_sint32 iW = m_recCurFrame.width;
406 UT_sint32 iH = m_recCurFrame.height;
407 m_pFrameLayout->localCollapse();
408 m_pFrameLayout->setFrameWidth(iW);
409 m_pFrameLayout->setFrameHeight(iH);
410 m_pFrameContainer->_setWidth(iW);
411 m_pFrameContainer->_setHeight(iH);
412 m_pFrameLayout->miniFormat();
413 m_pFrameLayout->getDocSectionLayout()->setNeedsSectionBreak(false,NULL);
414 }
415
416 if (FV_FrameEdit_RESIZE_EXISTING == m_iFrameEditMode || FV_FrameEdit_DRAG_EXISTING == m_iFrameEditMode)
417 {
418 UT_sint32 newX = m_pFrameContainer->getFullX();
419 UT_sint32 newY = m_pFrameContainer->getFullY();
420 newX += dx;
421 newY += dy;
422 m_pFrameContainer->_setX(newX);
423 m_pFrameContainer->_setY(newY);
424 if(expX.width > 0)
425 {
426 getGraphics()->setClipRect(&expX);
427 m_pView->updateScreen(false);
428 }
429 if(expY.height > 0)
430 {
431 getGraphics()->setClipRect(&expY);
432 m_pView->updateScreen(false);
433 }
434 getGraphics()->setClipRect(NULL);
435
436 drawFrame(true);
437 }
438 }
439 m_iLastX = x;
440 m_iLastY = y;
441 }
442
443 /*!
444 * This method finds the correct frame on the screen associated with the
445 * (x,y) point.
446 * It sets the FV_FrameEditMode and the FV_FrameEditDragWhat mode depending
447 * on which control is selected at the (x,y) position.
448 *
449 * top left top edge top right
450 * X----------X----------X
451 * | |
452 * | |
453 * left edge X X right edge
454 * | |
455 * | |
456 * X----------X----------X
457 * Bot left Bot edge Bot right
458 *
459 * An (x,y) point that does not fall in a specified control sets drag
460 * whole frame mode.
461 *
462 * The method also sets the fl_FrameLayout and FP_FrameContainer pointers.
463 */
setDragType(UT_sint32 x,UT_sint32 y,bool bDrawFrame)464 void FV_FrameEdit::setDragType(UT_sint32 x, UT_sint32 y, bool bDrawFrame)
465 {
466 xxx_UT_DEBUGMSG(("setDragType called frameEdit mode %d \n",m_iFrameEditMode));
467 PT_DocPosition posAtXY = m_pView->getDocPositionFromXY(x,y,false);
468 fp_FrameContainer * pFCon = NULL;
469 fl_FrameLayout * pFL = NULL;
470 fl_BlockLayout * pBL = NULL;
471 if(getDoc()->isFrameAtPos(posAtXY))
472 {
473 fl_ContainerLayout* psfh = NULL;
474 getDoc()->getStruxOfTypeFromPosition(m_pView->getLayout()->getLID(),posAtXY+1,
475 PTX_SectionFrame, &psfh);
476 pFL = static_cast<fl_FrameLayout *>(psfh);
477 UT_ASSERT(pFL->getContainerType() == FL_CONTAINER_FRAME);
478 pFCon = static_cast<fp_FrameContainer *>(pFL->getFirstContainer());
479 UT_ASSERT(pFCon->getContainerType() == FP_CONTAINER_FRAME);
480 }
481 else
482 {
483 pBL = m_pView->_findBlockAtPosition(posAtXY);
484 UT_return_if_fail(pBL);
485 }
486 if(!isActive() && (pFCon == NULL))
487 {
488 m_iFrameEditMode = FV_FrameEdit_EXISTING_SELECTED;
489 if(getGraphics())
490 {
491 getGraphics()->allCarets()->disable();
492 m_pView->m_countDisable++;
493 }
494 fl_ContainerLayout * pCL = pBL->myContainingLayout();
495 while(pCL && (pCL->getContainerType() != FL_CONTAINER_FRAME) && (pCL->getContainerType() != FL_CONTAINER_DOCSECTION))
496 {
497 pCL = pCL->myContainingLayout();
498 }
499 UT_return_if_fail(pCL);
500 if(pCL->getContainerType() != FL_CONTAINER_FRAME)
501 {
502 return;
503 }
504 m_pFrameLayout = static_cast<fl_FrameLayout *>(pCL);
505 UT_ASSERT(m_pFrameLayout->getContainerType() == FL_CONTAINER_FRAME);
506 m_pFrameContainer = static_cast<fp_FrameContainer *>(m_pFrameLayout->getFirstContainer());
507 UT_ASSERT(m_pFrameContainer);
508 if(bDrawFrame)
509 {
510 drawFrame(true);
511 }
512 m_iLastX = x;
513 m_iLastY = y;
514 setDragWhat( FV_DragWhole );
515 return;
516 }
517 if(!isActive())
518 {
519 m_iFrameEditMode = FV_FrameEdit_EXISTING_SELECTED;
520 if(getGraphics())
521 {
522 getGraphics()->allCarets()->disable();
523 m_pView->m_countDisable++;
524 }
525 m_pFrameLayout = pFL;
526 UT_ASSERT(m_pFrameLayout->getContainerType() == FL_CONTAINER_FRAME);
527 m_pFrameContainer = pFCon;
528 UT_ASSERT(m_pFrameContainer);
529 if(bDrawFrame)
530 {
531 drawFrame(true);
532 }
533 m_iLastX = x;
534 m_iLastY = y;
535 setDragWhat( FV_DragWhole );
536 return;
537 }
538 //
539 // OK find the coordinates of the frame.
540 //
541 UT_sint32 xPage,yPage;
542 UT_sint32 xClick, yClick;
543 fp_Page* pPage = m_pView->_getPageForXY(x, y, xClick, yClick);
544 m_pView->getPageScreenOffsets(pPage,xPage,yPage);
545 if(m_iFrameEditMode == FV_FrameEdit_EXISTING_SELECTED)
546 {
547 pFCon = m_pFrameContainer;
548 pFL = m_pFrameLayout;
549 }
550 else
551 {
552 if(pBL)
553 {
554 pFL = static_cast<fl_FrameLayout *>(pBL->myContainingLayout());
555 pFCon = static_cast<fp_FrameContainer *>(pFL->getFirstContainer());
556 }
557 else
558 {
559 UT_ASSERT(pFL);
560 UT_ASSERT(pFCon);
561 }
562 }
563 UT_return_if_fail(pFCon);
564 UT_sint32 ires = getGraphics()->tlu(FRAME_HANDLE_SIZE); // 6 pixels wide hit area
565 UT_sint32 iLeft = xPage + pFCon->getFullX();
566 UT_sint32 iRight = xPage + pFCon->getFullX() + pFCon->getFullWidth();
567 UT_sint32 iTop = yPage + pFCon->getFullY();
568 UT_sint32 iBot = yPage + pFCon->getFullY() + pFCon->getFullHeight();
569 bool bX = (iLeft - ires < x) && (x < iRight + ires);
570 bool bY = (iTop - ires < y) && (iBot + ires > y);
571 bool bLeft = (iLeft - ires < x) && (x < iLeft + ires);
572 bool bRight = (iRight - ires < x) && (x < iRight + ires);
573 bool bTop = (iTop - ires < y) && (y < iTop + ires);
574 bool bBot = (iBot - ires < y) && (y < iBot + ires);
575 //
576 // top left
577 //
578 if((iLeft < x) && (x < iLeft + ires) && (iTop < y) && (y < iTop + ires))
579 {
580 setDragWhat( FV_DragTopLeftCorner );
581 }
582 //
583 // top Right
584 //
585 else if((iRight - ires < x) && (x < iRight) && (iTop < y) && (y < iTop + ires))
586 {
587 setDragWhat( FV_DragTopRightCorner );
588 }
589 //
590 // bot left
591 //
592 else if((iLeft < x) && (x < iLeft + ires) && (iBot > y) && (y > iBot - ires))
593 {
594 setDragWhat( FV_DragBotLeftCorner );
595 }
596 //
597 // Bot Right
598 //
599 else if((iRight - ires < x) && (x < iRight) && (iBot > y) && (y > iBot - ires))
600 {
601 setDragWhat( FV_DragBotRightCorner );
602 }
603 //
604 // top Edge
605 //
606 else if( bX && bTop)
607 {
608 setDragWhat( FV_DragTopEdge );
609 }
610 //
611 // left Edge
612 //
613 else if(bLeft && bY)
614 {
615 setDragWhat( FV_DragLeftEdge );
616 }
617 //
618 // right Edge
619 //
620 else if(bRight && bY)
621 {
622 setDragWhat( FV_DragRightEdge );
623 }
624 //
625 // bot Edge
626 //
627 else if(bBot && bX)
628 {
629 setDragWhat( FV_DragBotEdge );
630 }
631 else
632 {
633 if( bX && bY)
634 {
635 setDragWhat( FV_DragWhole );
636 xxx_UT_DEBUGMSG(("Dragging Whole Frame \n"));
637 }
638 else
639 {
640 setDragWhat( FV_DragNothing );
641 return;
642 }
643 }
644 if(bDrawFrame && (m_recCurFrame.width > 0) && (m_recCurFrame.height >0))
645 {
646 drawFrame(true);
647 }
648 const PP_AttrProp * pAP = NULL;
649 pFL->getAP(pAP);
650 const char * pszPercentWidth = NULL;
651 const char * pszMinHeight = NULL;
652 const char * pszExpandHeight = NULL;
653 if(pAP && pAP->getProperty("frame-rel-width",pszPercentWidth))
654 {
655 if(pszPercentWidth)
656 {
657 m_sRelWidth = pszPercentWidth;
658 }
659 }
660 if(pAP && pAP->getProperty("frame-min-height",pszMinHeight))
661 {
662 if(pszMinHeight)
663 {
664 m_sMinHeight = pszMinHeight;
665 }
666 }
667 if(pAP && pAP->getProperty("frame-expand-height",pszExpandHeight))
668 {
669 m_sExpandHeight = pszExpandHeight;
670 }
671 m_recCurFrame.left = iLeft;
672 m_recCurFrame.top = iTop;
673 m_recCurFrame.width = (iRight - iLeft);
674 m_recCurFrame.height = (iBot - iTop);
675 m_iLastX = x;
676 m_iLastY = y;
677 m_iInitialDragX = iLeft;
678 m_iInitialDragY = iTop;
679
680 xxx_UT_DEBUGMSG(("Initial width %d \n",m_recCurFrame.width));
681 xxx_UT_DEBUGMSG((" Dragging What %d \n",getDragWhat()));
682 m_pView->setCursorToContext();
683 if(getGraphics())
684 {
685 getGraphics()->allCarets()->disable();
686 m_pView->m_countDisable++;
687 }
688 }
689
690 /*!
691 * This method responds to a mouse click and decides what to do with it.
692 */
mouseLeftPress(UT_sint32 x,UT_sint32 y)693 void FV_FrameEdit::mouseLeftPress(UT_sint32 x, UT_sint32 y)
694 {
695 m_bFirstDragDone = false;
696 UT_DEBUGMSG(("Mouse Left Press \n"));
697 m_pView->_clearSelection();
698 if(!isActive())
699 {
700 setDragType(x,y,true);
701 UT_DEBUGMSG(("Was not active now %d FrameLayout %p \n",getFrameEditMode(),getFrameLayout()));
702 return;
703 }
704 //
705 // Find the type of drag we should do.
706 //
707 if(FV_FrameEdit_EXISTING_SELECTED == m_iFrameEditMode )
708 {
709 setDragType(x,y,true);
710 UT_DEBUGMSG(("Was Existing Selected now %d \n",getFrameEditMode()));
711 if(FV_DragNothing == getDragWhat())
712 {
713 m_bFirstDragDone = false;
714 m_iFrameEditMode = FV_FrameEdit_NOT_ACTIVE;
715 drawFrame(false);
716 if(m_pFrameContainer && m_pFrameLayout)
717 {
718 if(m_pFrameLayout->getFrameType() > FL_FRAME_TEXTBOX_TYPE)
719 {
720 if(m_pFrameContainer->isTightWrapped())
721 {
722 // m_pFrameContainer->clearScreen();
723 m_pView->updateScreen(false);
724 }
725 }
726 }
727 m_pFrameLayout = NULL;
728 m_pFrameContainer = NULL;
729 DELETEP(m_pFrameImage);
730 XAP_Frame * pFrame = static_cast<XAP_Frame*>(m_pView->getParentData());
731 if(pFrame)
732 {
733 EV_Mouse * pMouse = pFrame->getMouse();
734 if(pMouse)
735 {
736 pMouse->clearMouseContext();
737 }
738 }
739 m_pView->m_prevMouseContext = EV_EMC_TEXT;
740 m_pView->setCursorToContext();
741 m_recCurFrame.width = 0;
742 m_recCurFrame.height = 0;
743 setDragWhat( FV_DragNothing );
744 m_iLastX = 0;
745 m_iLastY = 0;
746 while(m_iGlobCount > 0)
747 _endGlob();
748 m_pView->warpInsPtToXY(x,y,true);
749 }
750 else
751 {
752 if( getDragWhat() != FV_DragWhole)
753 {
754 m_iFrameEditMode = FV_FrameEdit_RESIZE_EXISTING;
755 }
756 else
757 {
758 m_iFrameEditMode = FV_FrameEdit_DRAG_EXISTING;
759 m_iInitialDragX = m_recCurFrame.left;
760 m_iInitialDragY = m_recCurFrame.top;
761 m_iInitialFrameX = m_pFrameContainer->getFullX();
762 m_iInitialFrameY = m_pFrameContainer->getFullY();
763 }
764 if(getGraphics())
765 {
766 getGraphics()->allCarets()->disable();
767 m_pView->m_countDisable++;
768 }
769 }
770 return;
771 }
772 //
773 // We're waiting for the first click to interactively enter the initial
774 // frame size.
775 //
776 if( FV_FrameEdit_WAIT_FOR_FIRST_CLICK_INSERT == m_iFrameEditMode )
777 {
778 //
779 // Draw a marker at the current position
780 //
781 //
782 // Now insert a text box
783 //
784 UT_sint32 iCursorOff = getGraphics()->tlu(8);
785 UT_sint32 origX = x + iCursorOff;
786 UT_sint32 origY = y + iCursorOff;
787 UT_sint32 iSize = getGraphics()->tlu(32);
788 m_recCurFrame.left = origX - iSize;
789 m_recCurFrame.top = origY - iSize;
790 m_recCurFrame.width = iSize;
791 m_recCurFrame.height = iSize;
792 m_iFrameEditMode = FV_FrameEdit_RESIZE_INSERT;
793 _beginGlob();
794 // mouseRelease(x,y);
795 mouseRelease(origX,origY);
796 m_iFrameEditMode = FV_FrameEdit_RESIZE_EXISTING;
797 m_iLastX = x;
798 m_iLastY = y;
799 m_iInitialDragX = m_recCurFrame.left;
800 m_iInitialDragY = m_recCurFrame.top;
801 setDragWhat( FV_DragBotRightCorner );
802 m_bFirstDragDone = false;
803 m_bInitialClick = true;
804 if(getGraphics())
805 {
806 getGraphics()->allCarets()->disable();
807 m_pView->m_countDisable++;
808 }
809 getGraphics()->setCursor(GR_Graphics::GR_CURSOR_IMAGESIZE_SE);
810 }
811 }
812
isImageWrapper(void) const813 bool FV_FrameEdit::isImageWrapper(void) const
814 {
815 if(m_pFrameLayout == NULL)
816 {
817 return false;
818 }
819 if(m_pFrameLayout->getFrameType() == FL_FRAME_WRAPPER_IMAGE)
820 {
821 return true;
822 }
823 return false;
824 }
825
getFrameStrings(UT_sint32 x,UT_sint32 y,fv_FrameStrings & FrameStrings,fl_BlockLayout ** pCloseBL,fp_Page ** ppPage)826 bool FV_FrameEdit::getFrameStrings(UT_sint32 x, UT_sint32 y,
827 fv_FrameStrings & FrameStrings,
828 fl_BlockLayout ** pCloseBL,
829 fp_Page ** ppPage)
830 {
831 //
832 // Find the block that contains (x,y). We'll insert the frame after
833 // this block in PT and position it on the page relative to this block.
834 //
835 //
836 // X and y are the (x,y) coords of the frame on the screen.
837 //
838 PT_DocPosition posAtXY = 0;
839 posAtXY = m_pView->getDocPositionFromXY(x,y,true);
840 fl_BlockLayout * pBL = NULL;
841 fp_Run * pRun = NULL;
842 fp_Line * pLine = NULL;
843 UT_sint32 x1,x2,y1,y2;
844 UT_uint32 height;
845 bool bEOL=false;
846 bool bDir=false;
847 m_pView->_findPositionCoords(posAtXY,bEOL,x1,y1,x2,y2,height,bDir,&pBL,&pRun);
848 xxx_UT_DEBUGMSG((" Requested y %d frameEdit y1= %d y2= %d \n",y,y1,y2));
849 fp_Run * pRunOrig = pRun;
850 if((pBL == NULL) || (pRun == NULL))
851 {
852 return false;
853 }
854 fl_BlockLayout * pPrevBL = pBL;
855 while(pBL && pBL->myContainingLayout() &&
856 ((pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_ENDNOTE) ||
857 (pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_FOOTNOTE) ||
858 (pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_TOC) ||
859 (pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_FRAME) ||
860 (pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_CELL) ||
861 (pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_SHADOW) ||
862 (pBL->myContainingLayout()->getContainerType() == FL_CONTAINER_HDRFTR)))
863 {
864 UT_DEBUGMSG(("Skipping Block %p \n",pBL));
865 pPrevBL = pBL;
866 pBL = pBL->getPrevBlockInDocument();
867 }
868 if(pBL == NULL)
869 {
870 pBL = pPrevBL;
871 }
872 pLine = pRun->getLine();
873 if(pLine == NULL)
874 {
875 return false;
876 }
877 UT_ASSERT(pBL->myContainingLayout() && (pBL->myContainingLayout()->getContainerType() != FL_CONTAINER_HDRFTR)
878 && (pBL->myContainingLayout()->getContainerType() != FL_CONTAINER_SHADOW));
879 *pCloseBL = pBL;
880 posAtXY = pBL->getPosition();
881
882 // don't let widths and heights be too big
883
884 double dWidth = static_cast<double>(m_recCurFrame.width)/static_cast<double>(UT_LAYOUT_RESOLUTION);
885 double dHeight = static_cast<double>(m_recCurFrame.height)/static_cast<double>(UT_LAYOUT_RESOLUTION);
886 if(m_pView->getPageSize().Width(DIM_IN) < dWidth)
887 {
888 dWidth = m_pView->getPageSize().Width(DIM_IN)*0.99;
889 m_recCurFrame.width = static_cast<UT_sint32>(dWidth*UT_LAYOUT_RESOLUTION);
890 }
891 if(m_pView->getPageSize().Height(DIM_IN) < dHeight)
892 {
893 dHeight = m_pView->getPageSize().Height(DIM_IN)*0.99;
894 m_recCurFrame.height = static_cast<UT_sint32>(dHeight*UT_LAYOUT_RESOLUTION);
895 }
896 //
897 // Need this for offset to column
898 //
899 UT_return_val_if_fail(pBL->getFirstRun(),false);
900 UT_return_val_if_fail(pBL->getFirstRun()->getLine(),false);
901 UT_return_val_if_fail(pBL->getFirstRun()->getLine()->getColumn(),false);
902 fp_Container * pCol = pRunOrig->getLine()->getColumn();
903 UT_ASSERT(pCol->getContainerType() == FP_CONTAINER_COLUMN);
904 //
905 // Find the screen coords of pCol and substract then from x,y
906 //
907 UT_sint32 iColx = 0;
908 UT_sint32 iColy = 0;
909 fp_Page * pPage = pCol->getPage();
910 if(!pPage)
911 {
912 return false;
913 }
914 else
915 {
916 pPage->getScreenOffsets(pCol,iColx,iColy);
917 }
918 UT_sint32 xp=0;
919 UT_sint32 yp= 0;
920 m_pView->getPageScreenOffsets(pPage,xp,yp);
921 UT_sint32 finalColx = x - iColx;
922 if(finalColx + iColx - xp < 0)
923 {
924 x += -finalColx -iColx +xp;
925 }
926 else if(pPage && (finalColx + iColx + m_recCurFrame.width - xp > pPage->getWidth()))
927 {
928 x = pPage->getWidth() - m_recCurFrame.width;
929 }
930 finalColx = x - iColx;
931
932 UT_sint32 finalColy = y - iColy;
933 if(finalColy + iColy - yp < 0 )
934 {
935 y += -iColy - finalColy +yp;
936 }
937 else if (pPage && (finalColy + iColy - yp+ m_recCurFrame.height > pPage->getHeight()))
938 {
939 y = pPage->getHeight() - m_recCurFrame.height;
940 }
941 finalColy = y - iColy;
942
943 double xPos = static_cast<double>(finalColx)/static_cast<double>(UT_LAYOUT_RESOLUTION);
944 double yPos = static_cast<double>(finalColy)/static_cast<double>(UT_LAYOUT_RESOLUTION);
945 FrameStrings.sColXpos = UT_formatDimensionedValue(xPos,"in", NULL);
946 FrameStrings.sColYpos = UT_formatDimensionedValue(yPos,"in", NULL);
947 //
948 // OK calculate relative to page now
949 //
950 xPos += static_cast<double>(pCol->getX())/static_cast<double>(UT_LAYOUT_RESOLUTION);
951 yPos += static_cast<double>(pCol->getY())/static_cast<double>(UT_LAYOUT_RESOLUTION);
952 FrameStrings.sPageXpos = UT_formatDimensionedValue(xPos,"in", NULL);
953 FrameStrings.sPageYpos = UT_formatDimensionedValue(yPos,"in", NULL);
954
955 //
956 // Find the screen coords of pLine, then work out the offset to the (x,y)
957 // point. After that workout the offset to the first line of the block.
958 //
959 //
960 UT_sint32 xBlockOff =0;
961 UT_sint32 yBlockOff = 0;
962 UT_DebugOnly<bool> bValid = false;
963 bValid = pBL->getXYOffsetToLine(xBlockOff,yBlockOff,pLine);
964 UT_ASSERT(bValid);
965 fp_Line * pFirstL = static_cast<fp_Line *>(pBL->getFirstContainer());
966 UT_sint32 xFirst,yFirst;
967 pFirstL->getScreenOffsets(pFirstL->getFirstRun(),xFirst,yFirst);
968 xxx_UT_DEBUGMSG(("First line x %d y %d \n",xFirst,yFirst));
969 xxx_UT_DEBUGMSG(("xBlockOffset %d yBlockOffset %d \n",xBlockOff,yBlockOff));
970 UT_sint32 xLineOff = 0;
971 UT_sint32 yLineOff = 0;
972 fp_VerticalContainer * pVCon = static_cast<fp_VerticalContainer *>(pLine->getContainer());
973 pVCon->getOffsets(pLine,xLineOff,yLineOff);
974 xLineOff -= pLine->getX();
975 xxx_UT_DEBUGMSG(("Closest Line yLineoff %d \n",yLineOff));
976
977 // OK correct for page offsets
978 pPage = pVCon->getPage();
979 if(pPage == NULL)
980 {
981 return false;
982 }
983 m_pView->getPageScreenOffsets(pPage,xp,yp);
984 xLineOff = x -xp - xLineOff;
985 // yLineOff = y + pRun->getY() - yLineOff + yBlockOff;
986 yLineOff = y - yp - yLineOff + yBlockOff;
987 UT_DEBUGMSG(("fv_FrameEdit: (x,y) %d %d xLineOff %d yLineOff %d \n",x,y,xLineOff,yLineOff));
988 //
989 // The sXpos and sYpos values are the numbers that need to be added from the
990 // top left corner of thefirst line of the block to reach the top left
991 // corner of the frame. We now have these in layout units. Convert to inches
992 // now
993 //
994 xPos = static_cast<double>(xLineOff)/static_cast<double>(UT_LAYOUT_RESOLUTION);
995 yPos = static_cast<double>(yLineOff)/static_cast<double>(UT_LAYOUT_RESOLUTION);
996 FrameStrings.sXpos = UT_formatDimensionedValue(xPos,"in", NULL);
997 FrameStrings.sYpos = UT_formatDimensionedValue(yPos,"in", NULL);
998 FrameStrings.sWidth = UT_formatDimensionedValue(dWidth,"in", NULL);
999 FrameStrings.sHeight = UT_formatDimensionedValue(dHeight,"in", NULL);
1000 *ppPage = pPage;
1001 UT_sint32 iPage = getView()->getLayout()->findPage(pPage);
1002 UT_String_sprintf(FrameStrings.sPrefPage,"%d",iPage);
1003 fp_Column * pColumn = static_cast<fp_Column *>(pCol);
1004 UT_sint32 iColumn = pColumn->getColumnIndex();
1005 UT_String_sprintf(FrameStrings.sPrefColumn,"%d",iColumn);
1006
1007 return true;
1008 }
1009
1010 //
1011 // Abort the current drag
1012 //
1013 //
abortDrag(void)1014 void FV_FrameEdit::abortDrag(void)
1015 {
1016 FV_ViewDoubleBuffering dblBuffObj(m_pView, true, true);
1017 dblBuffObj.beginDoubleBuffering();
1018
1019
1020 UT_DEBUGMSG(("Doing Abort Drag \n"));
1021 m_xLastMouse = m_iFirstEverX;
1022 m_yLastMouse = m_iFirstEverY;
1023 mouseRelease(m_iInitialDragX,m_iInitialDragY);
1024 getView()->updateScreen(false);
1025 }
1026
mouseRelease(UT_sint32 x,UT_sint32 y)1027 void FV_FrameEdit::mouseRelease(UT_sint32 x, UT_sint32 y)
1028 {
1029 //
1030 // If we've just selected the frame, ignore this event.
1031 //
1032
1033 FV_ViewDoubleBuffering dblBuffObj(m_pView, true, true);
1034 dblBuffObj.beginDoubleBuffering();
1035
1036 UT_DEBUGMSG(("Doing mouse release now! Mode %d \n", getFrameEditMode()));
1037 if(FV_FrameEdit_EXISTING_SELECTED == m_iFrameEditMode)
1038 {
1039 UT_DEBUGMSG(("Existing Frame selected now released button isActive() %d \n",isActive()));
1040 return;
1041 }
1042 if(m_pAutoScrollTimer != NULL)
1043 {
1044 m_pAutoScrollTimer->stop();
1045 DELETEP(m_pAutoScrollTimer);
1046 }
1047
1048 PT_DocPosition posAtXY = 0;
1049
1050 if(m_iFrameEditMode == FV_FrameEdit_RESIZE_INSERT)
1051 {
1052 // Signal PieceTable Change
1053 m_pView->_saveAndNotifyPieceTableChange();
1054
1055 // Turn off list updates
1056
1057 getDoc()->disableListUpdates();
1058 _beginGlob();
1059
1060 fv_FrameStrings FrameStrings;
1061 fl_BlockLayout * pCloseBL = NULL;
1062 fp_Page * pPage = NULL;
1063 getFrameStrings(m_recCurFrame.left,m_recCurFrame.top,FrameStrings,&pCloseBL,&pPage);
1064 pf_Frag_Strux * pfFrame = NULL;
1065 // WARNING: Will need to change this to accomodate variable styles without constantly resetting to solid.
1066 // Recommend to do whatever is done for thickness, which must also have a default set but not
1067 // reverted to on every change.
1068 // TODO: if(pAP->getProperty("*-thickness", somePropHolder)) sLeftThickness = gchar_strdup(somePropHolder); else sLeftThickness = "1px";
1069 const gchar * props[48] = {"frame-type","textbox",
1070 "wrap-mode","wrapped-both",
1071 "position-to","column-above-text",
1072 "xpos",FrameStrings.sXpos.c_str(),
1073 "ypos",FrameStrings.sYpos.c_str(),
1074 "frame-width",FrameStrings.sWidth.c_str(),
1075 "frame-height",FrameStrings.sHeight.c_str(),
1076 "frame-col-xpos",FrameStrings.sColXpos.c_str(),
1077 "frame-col-ypos",FrameStrings.sColYpos.c_str(),
1078 "frame-page-xpos",FrameStrings.sPageXpos.c_str(),
1079 "frame-page-ypos",FrameStrings.sPageYpos.c_str(),
1080 "frame-pref-page",FrameStrings.sPrefPage.c_str(),
1081 "frame-pref-column",FrameStrings.sPrefColumn.c_str(),
1082 "background-color", "ffffff",
1083 "left-style","1",
1084 "right-style","1",
1085 "top-style","1",
1086 "bot-style","1",
1087 "bg-style","1",
1088 "tight-wrap","0",
1089 "frame-rel-width",m_sRelWidth.c_str(),
1090 "frame-min-height",m_sMinHeight.c_str(),
1091 "frame-expand-height",m_sExpandHeight.c_str(),
1092 NULL,NULL};
1093 //
1094 // This should place the the frame strux immediately after the block containing
1095 // position posXY.
1096 // It returns the Frag_Strux of the new frame.
1097 //
1098 const PP_AttrProp* pBlockAP = NULL;
1099 pCloseBL->getAP(pBlockAP);
1100 posAtXY = pCloseBL->getPosition();
1101 getDoc()->insertStrux(posAtXY,PTX_SectionFrame,NULL,props,&pfFrame);
1102 PT_DocPosition posFrame = pfFrame->getPos();
1103 PT_DocPosition posEOD= 0;
1104 m_pView->getEditableBounds(true,posEOD);
1105 getDoc()->insertStrux(posFrame+1,PTX_Block,NULL,pBlockAP->getProperties());
1106 getDoc()->insertStrux(posFrame+2,PTX_EndFrame);
1107 m_pView->insertParaBreakIfNeededAtPos(posFrame+3);
1108
1109 // Place the insertion point in the Frame
1110
1111 m_pView->setPoint(posFrame+2);
1112
1113 // Finish up with the usual stuff
1114
1115 m_pView->_generalUpdate();
1116
1117 _endGlob();
1118
1119
1120 // restore updates and clean up dirty lists
1121 getDoc()->enableListUpdates();
1122 getDoc()->updateDirtyLists();
1123
1124 // Signal PieceTable Changes have finished
1125 m_pView->_restorePieceTableState();
1126 m_pView->notifyListeners(AV_CHG_HDRFTR);
1127 m_pView->_fixInsertionPointCoords();
1128 m_pView->_ensureInsertionPointOnScreen();
1129
1130 //
1131 m_iFrameEditMode = FV_FrameEdit_EXISTING_SELECTED;
1132 if(getGraphics())
1133 {
1134 getGraphics()->allCarets()->disable();
1135 m_pView->m_countDisable++;
1136 }
1137 fl_BlockLayout * pBL = m_pView->_findBlockAtPosition(posFrame+2);
1138 fl_ContainerLayout * pCL = pBL->myContainingLayout();
1139 while(pCL && (pCL->getContainerType() != FL_CONTAINER_FRAME) && (pCL->getContainerType() != FL_CONTAINER_DOCSECTION))
1140 {
1141 pCL = pCL->myContainingLayout();
1142 }
1143 UT_return_if_fail(pCL);
1144 if(pCL->getContainerType() != FL_CONTAINER_FRAME)
1145 {
1146 return;
1147 }
1148 m_pFrameLayout = static_cast<fl_FrameLayout *>(pCL);
1149 UT_ASSERT(m_pFrameLayout->getContainerType() == FL_CONTAINER_FRAME);
1150 m_pFrameContainer = static_cast<fp_FrameContainer *>(m_pFrameLayout->getFirstContainer());
1151 UT_ASSERT(m_pFrameContainer);
1152 drawFrame(true);
1153 m_bFirstDragDone = false;
1154 return;
1155 }
1156
1157 // Do Resize and Drag of frame
1158
1159 else if((m_iFrameEditMode == FV_FrameEdit_RESIZE_EXISTING) ||
1160 (m_iFrameEditMode == FV_FrameEdit_DRAG_EXISTING))
1161 {
1162 const PP_AttrProp* pSectionAP = NULL;
1163 m_pFrameLayout->getAP(pSectionAP);
1164
1165 //
1166 // If there was no drag, the user just clicked and released the left mouse
1167 // no need to change anything.
1168 //
1169 if(haveDragged() < 10)
1170 {
1171 m_iFrameEditMode = FV_FrameEdit_NOT_ACTIVE;
1172 setDragWhat( FV_DragNothing );
1173 m_pFrameContainer->_setX(m_iInitialFrameX);
1174 m_pFrameContainer->_setY(m_iInitialFrameY);
1175 m_iInitialFrameX = 0;
1176 m_iInitialFrameY = 0;
1177 drawFrame(false);
1178 m_pFrameLayout = NULL;
1179 m_pFrameContainer = NULL;
1180 DELETEP(m_pFrameImage);
1181 XAP_Frame * pFrame = static_cast<XAP_Frame*>(m_pView->getParentData());
1182 if(pFrame)
1183 {
1184 EV_Mouse * pMouse = pFrame->getMouse();
1185 if(pMouse)
1186 {
1187 pMouse->clearMouseContext();
1188 }
1189 }
1190 m_pView->m_prevMouseContext = EV_EMC_TEXT;
1191 m_pView->setCursorToContext();
1192 m_recCurFrame.width = 0;
1193 m_recCurFrame.height = 0;
1194 m_iLastX = 0;
1195 m_iLastY = 0;
1196 m_bFirstDragDone = false;
1197 while(m_iGlobCount > 0)
1198 _endGlob();
1199 m_pView->warpInsPtToXY(x,y,true);
1200 UT_DEBUGMSG(("Completed small drag \n"));
1201 return;
1202 }
1203 //
1204 // OK get the properties of the current frame, update them with the new
1205 // the position and size of this drag.
1206 //
1207
1208 // Frame Image
1209
1210 fv_FrameStrings FrameStrings;
1211 fl_BlockLayout * pCloseBL = NULL;
1212 fp_Page * pPage = NULL;
1213 fl_FrameLayout *pFL = m_pFrameLayout;
1214 getFrameStrings(m_recCurFrame.left,m_recCurFrame.top,FrameStrings,
1215 &pCloseBL,&pPage);
1216 posAtXY = pCloseBL->getPosition();
1217
1218 const gchar * props[] = {"xpos",FrameStrings.sXpos.c_str(),
1219 "ypos",FrameStrings.sYpos.c_str(),
1220 "frame-col-xpos",FrameStrings.sColXpos.c_str(),
1221 "frame-col-ypos",FrameStrings.sColYpos.c_str(),
1222 "frame-page-xpos",FrameStrings.sPageXpos.c_str(),
1223 "frame-page-ypos",FrameStrings.sPageYpos.c_str(),
1224 "frame-pref-page",FrameStrings.sPrefPage.c_str(),
1225 "frame-pref-column",FrameStrings.sPrefColumn.c_str(),
1226 "frame-width",FrameStrings.sWidth.c_str(),
1227 "frame-height",FrameStrings.sHeight.c_str(),
1228 NULL};
1229 // Signal PieceTable Change
1230 m_pView->_saveAndNotifyPieceTableChange();
1231 getDoc()->disableListUpdates();
1232 _beginGlob();
1233
1234 m_pView->_clearSelection();
1235
1236 if (pFL->getParentContainer() == pCloseBL)
1237 {
1238 PT_DocPosition posStart = pFL->getPosition(true)+1;
1239 PT_DocPosition posEnd = posStart;
1240 UT_DebugOnly<bool> bRet = getDoc()->changeStruxFmt(PTC_AddFmt,posStart,posEnd,NULL,
1241 props,PTX_SectionFrame);
1242 UT_ASSERT(bRet);
1243 }
1244 else
1245 {
1246 pFL = getLayout()->relocateFrame(pFL,pCloseBL,NULL,props);
1247 }
1248
1249 // Finish up with the usual stuff
1250 m_pView->_generalUpdate();
1251
1252 // restore updates and clean up dirty lists
1253 getDoc()->enableListUpdates();
1254 getDoc()->updateDirtyLists();
1255 m_pView->_restorePieceTableState();
1256 PT_DocPosition posFrame = getDoc()->getStruxPosition(pFL->getStruxDocHandle());
1257 m_pView->setPoint(posFrame+1);
1258 bool bOK = true;
1259 while(!m_pView->isPointLegal() && bOK)
1260 {
1261 bOK = m_pView->_charMotion(true,1);
1262 }
1263 m_pView->notifyListeners(AV_CHG_HDRFTR);
1264 m_pView->_fixInsertionPointCoords();
1265 //
1266 // If this was a drag following the initial click, wrap it in a
1267 // endUserAtomicGlob so it undo's in a single click.
1268 //
1269 while(m_iGlobCount > 0)
1270 _endGlob();
1271
1272 m_bInitialClick = false;
1273 //
1274 // Finish up by putting the editmode back to existing selected.
1275 //
1276 m_pView->updateScreen(false);
1277 m_pFrameLayout = pFL;
1278 setMode(FV_FrameEdit_EXISTING_SELECTED);
1279 if(getGraphics())
1280 {
1281 getGraphics()->allCarets()->disable();
1282 m_pView->m_countDisable++;
1283 }
1284 if(m_pFrameLayout)
1285 m_pFrameContainer = static_cast<fp_FrameContainer *>(m_pFrameLayout->getFirstContainer());
1286 drawFrame(true);
1287 m_bFirstDragDone = false;
1288 // This must be done after painting because it will finish the cairo surface, see #13622
1289 m_pView->_ensureInsertionPointOnScreen();
1290 }
1291 m_bFirstDragDone = false;
1292 }
1293
1294 /*
1295 * Return the bytebuf of the image for this.
1296 */
getPNGImage(const UT_ByteBuf ** ppByteBuf)1297 const char * FV_FrameEdit::getPNGImage(const UT_ByteBuf ** ppByteBuf )
1298 {
1299
1300 // Frame Image
1301 const PP_AttrProp* pSectionAP = NULL;
1302 m_pFrameLayout->getAP(pSectionAP);
1303
1304 const char * pszDataID = NULL;
1305 pSectionAP->getAttribute(PT_STRUX_IMAGE_DATAID, (const gchar *&)pszDataID);
1306 if(!pszDataID)
1307 {
1308 *ppByteBuf = NULL;
1309 return NULL;
1310 }
1311 m_pView->getDocument()->getDataItemDataByName(pszDataID,ppByteBuf,NULL,NULL);
1312 return pszDataID;
1313 }
1314
1315 /*!
1316 * This method deletes the current selected frame
1317 */
deleteFrame(fl_FrameLayout * pFL)1318 void FV_FrameEdit::deleteFrame(fl_FrameLayout * pFL)
1319 {
1320 if(m_pFrameLayout == NULL)
1321 {
1322 m_pFrameLayout = pFL;
1323 if(m_pFrameLayout == NULL)
1324 {
1325 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
1326 return;
1327 }
1328 }
1329
1330 FV_ViewDoubleBuffering dblBuffObj(m_pView, true, true);
1331 dblBuffObj.beginDoubleBuffering();
1332
1333 PP_AttrProp * p_AttrProp_Before = NULL;
1334
1335 // Signal PieceTable Change
1336 m_pView->_saveAndNotifyPieceTableChange();
1337
1338 // Turn off list updates
1339
1340 getDoc()->disableListUpdates();
1341 _beginGlob();
1342
1343 // Delete the frame
1344
1345 pf_Frag_Strux* sdhStart = m_pFrameLayout->getStruxDocHandle();
1346 pf_Frag_Strux* sdhEnd = NULL;
1347 PT_DocPosition posStart = getDoc()->getStruxPosition(sdhStart);
1348 getDoc()->getNextStruxOfType(sdhStart, PTX_EndFrame, &sdhEnd);
1349 PT_DocPosition posEnd = getDoc()->getStruxPosition(sdhEnd)+1;
1350 UT_uint32 iRealDeleteCount;
1351
1352 getDoc()->deleteSpan(posStart, posEnd, p_AttrProp_Before, iRealDeleteCount,true);
1353
1354 //special handling is required for delete in revisions mode
1355 //where we have to move the insertion point
1356 if(m_pView->isMarkRevisions())
1357 {
1358 UT_ASSERT( iRealDeleteCount <= posEnd - posStart + 1 );
1359 m_pView->_charMotion(true,posEnd - posStart - iRealDeleteCount);
1360 }
1361
1362 // Finish up with the usual stuff
1363
1364 m_pView->_generalUpdate();
1365
1366 // restore updates and clean up dirty lists
1367 getDoc()->enableListUpdates();
1368 getDoc()->updateDirtyLists();
1369
1370 // Signal PieceTable Changes have finished
1371 m_pView->_restorePieceTableState();
1372 m_pView->notifyListeners(AV_CHG_HDRFTR);
1373 m_pView->_fixInsertionPointCoords();
1374 m_pView->_ensureInsertionPointOnScreen();
1375 while(m_iGlobCount > 0)
1376 _endGlob();
1377
1378 // Clear all internal variables
1379
1380 m_pFrameLayout = NULL;
1381 m_pFrameContainer = NULL;
1382 DELETEP(m_pFrameImage);
1383 m_recCurFrame.width = 0;
1384 m_recCurFrame.height = 0;
1385 setDragWhat( FV_DragNothing );
1386 m_iLastX = 0;
1387 m_iLastY = 0;
1388
1389 m_iFrameEditMode = FV_FrameEdit_NOT_ACTIVE;
1390 m_bFirstDragDone = false;
1391 m_pView->_setPoint(m_pView->getPoint());
1392 }
1393
1394 /*!
1395 * Method to deal with mouse coordinates.
1396 */
mouseMotion(UT_sint32,UT_sint32)1397 FV_DragWhat FV_FrameEdit::mouseMotion(UT_sint32 /*x*/, UT_sint32 /*y*/)
1398 {
1399 return getDragWhat();
1400 }
1401
drawFrame(bool bWithHandles)1402 void FV_FrameEdit::drawFrame(bool bWithHandles)
1403 {
1404 if(m_pFrameContainer == NULL)
1405 {
1406 UT_ASSERT_HARMLESS(UT_SHOULD_NOT_HAPPEN);
1407 return;
1408 }
1409 fp_Page * pPage = m_pFrameContainer->getPage();
1410 dg_DrawArgs da;
1411 da.pG = getGraphics();
1412 da.bDirtyRunsOnly = false;
1413 UT_sint32 xPage,yPage;
1414 m_pView->getPageScreenOffsets(pPage,xPage,yPage);
1415 da.xoff = xPage + m_pFrameContainer->getX();
1416 da.yoff = yPage + m_pFrameContainer->getY();
1417 if((m_pFrameImage == NULL) || (getDragWhat() != FV_DragWhole) )
1418 {
1419 // m_pFrameContainer->clearScreen();
1420 m_pFrameContainer->draw(&da);
1421 if(bWithHandles)
1422 {
1423 m_pFrameContainer->drawHandles(&da);
1424 }
1425 if(getDragWhat() == FV_DragWhole)
1426 {
1427 GR_Painter painter (getGraphics());
1428 if(m_pFrameLayout->getFrameType() == FL_FRAME_TEXTBOX_TYPE)
1429 {
1430 m_pFrameImage = painter.genImageFromRectangle(m_recCurFrame);
1431 }
1432 else
1433 {
1434 UT_Rect rec = m_recCurFrame;
1435 rec.left = 0;
1436 rec.top = 0;
1437 UT_return_if_fail(m_pFrameLayout->getBackgroundImage());
1438 m_pFrameImage = m_pFrameLayout->getBackgroundImage()->createImageSegment(getGraphics(),rec);
1439 }
1440 }
1441 }
1442 else
1443 {
1444 GR_Painter painter(getGraphics());
1445 m_pView->draw(&m_recCurFrame);
1446 painter.drawImage(m_pFrameImage,m_recCurFrame.left,m_recCurFrame.top);
1447 }
1448 }
1449