1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <com/sun/star/accessibility/AccessibleRole.hpp>
21
22 #include <osl/diagnose.h>
23 #include <vcl/event.hxx>
24 #include <vcl/settings.hxx>
25 #include <vcl/ptrstyle.hxx>
26
27 #include "ipwin.hxx"
28 #include <hatchwindow.hxx>
29
30 /************************************************************************/
31 /*************************************************************************
32 |* SvResizeHelper::SvResizeHelper()
33 |*
34 |* Description
35 *************************************************************************/
SvResizeHelper()36 SvResizeHelper::SvResizeHelper()
37 : aBorder( 5, 5 )
38 , nGrab( -1 )
39 {
40 }
41
42 /*************************************************************************
43 |* SvResizeHelper::FillHandleRects()
44 |*
45 |* Description: the eight handles to magnify
46 *************************************************************************/
FillHandleRectsPixel() const47 std::array<tools::Rectangle,8> SvResizeHelper::FillHandleRectsPixel() const
48 {
49 std::array<tools::Rectangle,8> aRects;
50
51 // only because of EMPTY_RECT
52 Point aBottomRight = aOuter.BottomRight();
53
54 // upper left
55 aRects[ 0 ] = tools::Rectangle( aOuter.TopLeft(), aBorder );
56 // upper middle
57 aRects[ 1 ] = tools::Rectangle( Point( aOuter.Center().X() - aBorder.Width() / 2,
58 aOuter.Top() ),
59 aBorder );
60 // upper right
61 aRects[ 2 ] = tools::Rectangle( Point( aBottomRight.X() - aBorder.Width() +1,
62 aOuter.Top() ),
63 aBorder );
64 // middle right
65 aRects[ 3 ] = tools::Rectangle( Point( aBottomRight.X() - aBorder.Width() +1,
66 aOuter.Center().Y() - aBorder.Height() / 2 ),
67 aBorder );
68 // lower right
69 aRects[ 4 ] = tools::Rectangle( Point( aBottomRight.X() - aBorder.Width() +1,
70 aBottomRight.Y() - aBorder.Height() +1 ),
71 aBorder );
72 // lower middle
73 aRects[ 5 ] = tools::Rectangle( Point( aOuter.Center().X() - aBorder.Width() / 2,
74 aBottomRight.Y() - aBorder.Height() +1),
75 aBorder );
76 // lower left
77 aRects[ 6 ] = tools::Rectangle( Point( aOuter.Left(),
78 aBottomRight.Y() - aBorder.Height() +1),
79 aBorder );
80 // middle left
81 aRects[ 7 ] = tools::Rectangle( Point( aOuter.Left(),
82 aOuter.Center().Y() - aBorder.Height() / 2 ),
83 aBorder );
84 return aRects;
85 }
86
87 /*************************************************************************
88 |* SvResizeHelper::FillMoveRectsPixel()
89 |*
90 |* Description: the four edges are calculated
91 *************************************************************************/
FillMoveRectsPixel() const92 std::array<tools::Rectangle,4> SvResizeHelper::FillMoveRectsPixel() const
93 {
94 std::array<tools::Rectangle,4> aRects;
95
96 // upper
97 aRects[ 0 ] = aOuter;
98 aRects[ 0 ].SetBottom( aRects[ 0 ].Top() + aBorder.Height() -1 );
99 // right
100 aRects[ 1 ] = aOuter;
101 if (!aOuter.IsWidthEmpty())
102 aRects[ 1 ].SetLeft( aRects[ 1 ].Right() - aBorder.Width() -1 );
103 // lower
104 aRects[ 2 ] = aOuter;
105 if (!aOuter.IsHeightEmpty())
106 aRects[ 2 ].SetTop( aRects[ 2 ].Bottom() - aBorder.Height() -1 );
107 // left
108 aRects[ 3 ] = aOuter;
109 aRects[ 3 ].SetRight( aRects[ 3 ].Left() + aBorder.Width() -1 );
110
111 return aRects;
112 }
113
114 /*************************************************************************
115 |* SvResizeHelper::Draw()
116 |*
117 |* Description
118 *************************************************************************/
Draw(vcl::RenderContext & rRenderContext)119 void SvResizeHelper::Draw(vcl::RenderContext& rRenderContext)
120 {
121 rRenderContext.Push();
122 rRenderContext.SetMapMode( MapMode() );
123
124 rRenderContext.SetFillColor( COL_LIGHTGRAY );
125 rRenderContext.SetLineColor();
126
127 std::array<tools::Rectangle,4> aMoveRects = FillMoveRectsPixel();
128 sal_uInt16 i;
129 for (i = 0; i < 4; i++)
130 rRenderContext.DrawRect(aMoveRects[i]);
131 // draw handles
132 rRenderContext.SetFillColor(Color()); // black
133 std::array<tools::Rectangle,8> aRects = FillHandleRectsPixel();
134 for (i = 0; i < 8; i++)
135 rRenderContext.DrawRect( aRects[ i ] );
136 rRenderContext.Pop();
137 }
138
139 /*************************************************************************
140 |* SvResizeHelper::InvalidateBorder()
141 |*
142 |* Description
143 *************************************************************************/
InvalidateBorder(vcl::Window * pWin)144 void SvResizeHelper::InvalidateBorder( vcl::Window * pWin )
145 {
146 std::array<tools::Rectangle,4> aMoveRects = FillMoveRectsPixel();
147 for(const auto & rMoveRect : aMoveRects)
148 pWin->Invalidate( rMoveRect );
149 }
150
151 /*************************************************************************
152 |* SvResizeHelper::SelectBegin()
153 |*
154 |* Description
155 *************************************************************************/
SelectBegin(vcl::Window * pWin,const Point & rPos)156 bool SvResizeHelper::SelectBegin( vcl::Window * pWin, const Point & rPos )
157 {
158 if( -1 == nGrab )
159 {
160 nGrab = SelectMove( pWin, rPos );
161 if( -1 != nGrab )
162 {
163 aSelPos = rPos; // store start position
164 pWin->CaptureMouse();
165 return true;
166 }
167 }
168 return false;
169 }
170
171 /*************************************************************************
172 |* SvResizeHelper::SelectMove()
173 |*
174 |* Description
175 *************************************************************************/
SelectMove(vcl::Window * pWin,const Point & rPos)176 short SvResizeHelper::SelectMove( vcl::Window * pWin, const Point & rPos )
177 {
178 if( -1 == nGrab )
179 {
180 std::array<tools::Rectangle,8> aRects = FillHandleRectsPixel();
181 for( sal_uInt16 i = 0; i < 8; i++ )
182 if( aRects[ i ].IsInside( rPos ) )
183 return i;
184 // Move-Rect overlaps Handles
185 std::array<tools::Rectangle,4> aMoveRects = FillMoveRectsPixel();
186 for(const auto & rMoveRect : aMoveRects)
187 if( rMoveRect.IsInside( rPos ) )
188 return 8;
189 }
190 else
191 {
192 tools::Rectangle aRect( GetTrackRectPixel( rPos ) );
193 aRect.SetSize( pWin->PixelToLogic( aRect.GetSize() ) );
194 aRect.SetPos( pWin->PixelToLogic( aRect.TopLeft() ) );
195 pWin->ShowTracking( aRect );
196 }
197 return nGrab;
198 }
199
GetTrackPosPixel(const tools::Rectangle & rRect) const200 Point SvResizeHelper::GetTrackPosPixel( const tools::Rectangle & rRect ) const
201 {
202 // not important how the rectangle is returned, it is important
203 // which handle has been touched
204 Point aPos;
205 tools::Rectangle aRect( rRect );
206 aRect.Justify();
207 // only because of EMPTY_RECT
208 Point aBR = aOuter.BottomRight();
209 Point aTR = aOuter.TopRight();
210 Point aBL = aOuter.BottomLeft();
211 bool bRTL = AllSettings::GetLayoutRTL();
212 switch( nGrab )
213 {
214 case 0:
215 // FIXME: disable it for RTL because it's wrong calculations
216 if( bRTL )
217 break;
218 aPos = aRect.TopLeft() - aOuter.TopLeft();
219 break;
220 case 1:
221 aPos.setY( aRect.Top() - aOuter.Top() );
222 break;
223 case 2:
224 // FIXME: disable it for RTL because it's wrong calculations
225 if( bRTL )
226 break;
227 aPos = aRect.TopRight() - aTR;
228 break;
229 case 3:
230 if( bRTL )
231 aPos.setX( aRect.Left() - aTR.X() );
232 else
233 aPos.setX( aRect.Right() - aTR.X() );
234 break;
235 case 4:
236 // FIXME: disable it for RTL because it's wrong calculations
237 if( bRTL )
238 break;
239 aPos = aRect.BottomRight() - aBR;
240 break;
241 case 5:
242 aPos.setY( aRect.Bottom() - aBR.Y() );
243 break;
244 case 6:
245 // FIXME: disable it for RTL because it's wrong calculations
246 if( bRTL )
247 break;
248 aPos = aRect.BottomLeft() - aBL;
249 break;
250 case 7:
251 if( bRTL )
252 aPos.setX( aRect.Right() + aOuter.Right() - aOuter.TopRight().X() );
253 else
254 aPos.setX( aRect.Left() - aOuter.Left() );
255 break;
256 case 8:
257 aPos = aRect.TopLeft() - aOuter.TopLeft();
258 break;
259 }
260 return aPos += aSelPos;
261 }
262
263 /*************************************************************************
264 |* SvResizeHelper::GetTrackRectPixel()
265 |*
266 |* Description
267 *************************************************************************/
GetTrackRectPixel(const Point & rTrackPos) const268 tools::Rectangle SvResizeHelper::GetTrackRectPixel( const Point & rTrackPos ) const
269 {
270 tools::Rectangle aTrackRect;
271 if( -1 != nGrab )
272 {
273 Point aDiff = rTrackPos - aSelPos;
274 aTrackRect = aOuter;
275 Point aBR = aOuter.BottomRight();
276 bool bRTL = AllSettings::GetLayoutRTL();
277 switch( nGrab )
278 {
279 case 0:
280 aTrackRect.AdjustTop(aDiff.Y() );
281 // ugly solution for resizing OLE objects in RTL
282 if( bRTL )
283 aTrackRect.SetRight( aBR.X() - aDiff.X() );
284 else
285 aTrackRect.AdjustLeft(aDiff.X() );
286 break;
287 case 1:
288 aTrackRect.AdjustTop(aDiff.Y() );
289 break;
290 case 2:
291 aTrackRect.AdjustTop(aDiff.Y() );
292 // ugly solution for resizing OLE objects in RTL
293 if( bRTL )
294 aTrackRect.AdjustLeft( -(aDiff.X()) );
295 else
296 aTrackRect.SetRight( aBR.X() + aDiff.X() );
297 break;
298 case 3:
299 // ugly solution for resizing OLE objects in RTL
300 if( bRTL )
301 aTrackRect.AdjustLeft( -(aDiff.X()) );
302 else
303 aTrackRect.SetRight( aBR.X() + aDiff.X() );
304 break;
305 case 4:
306 aTrackRect.SetBottom( aBR.Y() + aDiff.Y() );
307 // ugly solution for resizing OLE objects in RTL
308 if( bRTL )
309 aTrackRect.AdjustLeft( -(aDiff.X()) );
310 else
311 aTrackRect.SetRight( aBR.X() + aDiff.X() );
312 break;
313 case 5:
314 aTrackRect.SetBottom( aBR.Y() + aDiff.Y() );
315 break;
316 case 6:
317 aTrackRect.SetBottom( aBR.Y() + aDiff.Y() );
318 // ugly solution for resizing OLE objects in RTL
319 if( bRTL )
320 aTrackRect.SetRight( aBR.X() - aDiff.X() );
321 else
322 aTrackRect.AdjustLeft(aDiff.X() );
323 break;
324 case 7:
325 // ugly solution for resizing OLE objects in RTL
326 if( bRTL )
327 aTrackRect.SetRight( aBR.X() - aDiff.X() );
328 else
329 aTrackRect.AdjustLeft(aDiff.X() );
330 break;
331 case 8:
332 if( bRTL )
333 aDiff.setX( -aDiff.X() ); // workaround for move in RTL mode
334 aTrackRect.SetPos( aTrackRect.TopLeft() + aDiff );
335 break;
336 }
337 }
338 return aTrackRect;
339 }
340
ValidateRect(tools::Rectangle & rValidate) const341 void SvResizeHelper::ValidateRect( tools::Rectangle & rValidate ) const
342 {
343 switch( nGrab )
344 {
345 case 0:
346 if( rValidate.Top() > rValidate.Bottom() )
347 rValidate.SetTop( rValidate.Bottom() );
348 if( rValidate.Left() > rValidate.Right() )
349 rValidate.SetLeft( rValidate.Right() );
350 break;
351 case 1:
352 if( rValidate.Top() > rValidate.Bottom() )
353 rValidate.SetTop( rValidate.Bottom() );
354 break;
355 case 2:
356 if( rValidate.Top() > rValidate.Bottom() )
357 rValidate.SetTop( rValidate.Bottom() );
358 if( rValidate.Left() > rValidate.Right() )
359 rValidate.SetRight( rValidate.Left() );
360 break;
361 case 3:
362 if( rValidate.Left() > rValidate.Right() )
363 rValidate.SetRight( rValidate.Left() );
364 break;
365 case 4:
366 if( rValidate.Top() > rValidate.Bottom() )
367 rValidate.SetBottom( rValidate.Top() );
368 if( rValidate.Left() > rValidate.Right() )
369 rValidate.SetRight( rValidate.Left() );
370 break;
371 case 5:
372 if( rValidate.Top() > rValidate.Bottom() )
373 rValidate.SetBottom( rValidate.Top() );
374 break;
375 case 6:
376 if( rValidate.Top() > rValidate.Bottom() )
377 rValidate.SetBottom( rValidate.Top() );
378 if( rValidate.Left() > rValidate.Right() )
379 rValidate.SetLeft( rValidate.Right() );
380 break;
381 case 7:
382 if( rValidate.Left() > rValidate.Right() )
383 rValidate.SetLeft( rValidate.Right() );
384 break;
385 }
386
387 // Mindestgr"osse 5 x 5
388 if( rValidate.Left() + 5 > rValidate.Right() )
389 rValidate.SetRight( rValidate.Left() + 5 );
390 if( rValidate.Top() + 5 > rValidate.Bottom() )
391 rValidate.SetBottom( rValidate.Top() + 5 );
392 }
393
394 /*************************************************************************
395 |* SvResizeHelper::SelectRelease()
396 |*
397 |* Description
398 *************************************************************************/
SelectRelease(vcl::Window * pWin,const Point & rPos,tools::Rectangle & rOutPosSize)399 bool SvResizeHelper::SelectRelease( vcl::Window * pWin, const Point & rPos,
400 tools::Rectangle & rOutPosSize )
401 {
402 if( -1 != nGrab )
403 {
404 rOutPosSize = GetTrackRectPixel( rPos );
405 rOutPosSize.Justify();
406 nGrab = -1;
407 pWin->ReleaseMouse();
408 pWin->HideTracking();
409 return true;
410 }
411 return false;
412 }
413
414 /*************************************************************************
415 |* SvResizeHelper::Release()
416 |*
417 |* Description
418 *************************************************************************/
Release(vcl::Window * pWin)419 void SvResizeHelper::Release( vcl::Window * pWin )
420 {
421 if( nGrab != -1 )
422 {
423 pWin->ReleaseMouse();
424 pWin->HideTracking();
425 nGrab = -1;
426 }
427 }
428
429 /*************************************************************************
430 |* SvResizeWindow::SvResizeWindow()
431 |*
432 |* Description
433 *************************************************************************/
SvResizeWindow(vcl::Window * pParent,VCLXHatchWindow * pWrapper)434 SvResizeWindow::SvResizeWindow
435 (
436 vcl::Window * pParent,
437 VCLXHatchWindow* pWrapper
438 )
439 : Window( pParent, WB_CLIPCHILDREN )
440 , m_aOldPointer(PointerStyle::Arrow)
441 , m_nMoveGrab( -1 )
442 , m_bActive( false )
443 , m_pWrapper( pWrapper )
444 {
445 OSL_ENSURE( pParent != nullptr && pWrapper != nullptr, "Wrong initialization of hatch window!" );
446 SetBackground();
447 SetAccessibleRole( css::accessibility::AccessibleRole::EMBEDDED_OBJECT );
448 m_aResizer.SetOuterRectPixel( tools::Rectangle( Point(), GetOutputSizePixel() ) );
449 }
450
451 /*************************************************************************
452 |* SvResizeWindow::SetHatchBorderPixel()
453 |*
454 |* Description
455 *************************************************************************/
SetHatchBorderPixel(const Size & rSize)456 void SvResizeWindow::SetHatchBorderPixel( const Size & rSize )
457 {
458 m_aResizer.SetBorderPixel( rSize );
459 }
460
461 /*************************************************************************
462 |* SvResizeWindow::SelectMouse()
463 |*
464 |* Description
465 *************************************************************************/
SelectMouse(const Point & rPos)466 void SvResizeWindow::SelectMouse( const Point & rPos )
467 {
468 short nGrab = m_aResizer.SelectMove( this, rPos );
469 if( nGrab >= 4 )
470 nGrab -= 4;
471 if( m_nMoveGrab == nGrab )
472 return;
473
474 // Pointer did change
475 if( -1 == nGrab )
476 SetPointer( m_aOldPointer );
477 else
478 {
479 PointerStyle aStyle = PointerStyle::Move;
480 if( nGrab == 3 )
481 aStyle = PointerStyle::ESize;
482 else if( nGrab == 2 )
483 aStyle = PointerStyle::NESize;
484 else if( nGrab == 1 )
485 aStyle = PointerStyle::SSize;
486 else if( nGrab == 0 )
487 aStyle = PointerStyle::SESize;
488 if( m_nMoveGrab == -1 ) // the first time
489 {
490 m_aOldPointer = GetPointer();
491 SetPointer( aStyle );
492 }
493 else
494 SetPointer( aStyle );
495 }
496 m_nMoveGrab = nGrab;
497 }
498
499 /*************************************************************************
500 |* SvResizeWindow::MouseButtonDown()
501 |*
502 |* Description
503 *************************************************************************/
MouseButtonDown(const MouseEvent & rEvt)504 void SvResizeWindow::MouseButtonDown( const MouseEvent & rEvt )
505 {
506 if( m_aResizer.SelectBegin( this, rEvt.GetPosPixel() ) )
507 SelectMouse( rEvt.GetPosPixel() );
508 }
509
510 /*************************************************************************
511 |* SvResizeWindow::MouseMove()
512 |*
513 |* Description
514 *************************************************************************/
MouseMove(const MouseEvent & rEvt)515 void SvResizeWindow::MouseMove( const MouseEvent & rEvt )
516 {
517 if( m_aResizer.GetGrab() == -1 )
518 SelectMouse( rEvt.GetPosPixel() );
519 else
520 {
521 tools::Rectangle aRect( m_aResizer.GetTrackRectPixel( rEvt.GetPosPixel() ) );
522 Point aDiff = GetPosPixel();
523 aRect.SetPos( aRect.TopLeft() + aDiff );
524 m_aResizer.ValidateRect( aRect );
525
526 m_pWrapper->QueryObjAreaPixel( aRect );
527 aRect.SetPos( aRect.TopLeft() - aDiff );
528 Point aPos = m_aResizer.GetTrackPosPixel( aRect );
529
530 SelectMouse( aPos );
531 }
532 }
533
534 /*************************************************************************
535 |* SvResizeWindow::MouseButtonUp()
536 |*
537 |* Description
538 *************************************************************************/
MouseButtonUp(const MouseEvent & rEvt)539 void SvResizeWindow::MouseButtonUp( const MouseEvent & rEvt )
540 {
541 if( m_aResizer.GetGrab() == -1 )
542 return;
543
544 tools::Rectangle aRect( m_aResizer.GetTrackRectPixel( rEvt.GetPosPixel() ) );
545 Point aDiff = GetPosPixel();
546 aRect.SetPos( aRect.TopLeft() + aDiff );
547 // aRect -= GetAllBorderPixel();
548 m_aResizer.ValidateRect( aRect );
549
550 m_pWrapper->QueryObjAreaPixel( aRect );
551
552 tools::Rectangle aOutRect;
553 if( m_aResizer.SelectRelease( this, rEvt.GetPosPixel(), aOutRect ) )
554 {
555 m_nMoveGrab = -1;
556 SetPointer( m_aOldPointer );
557 m_pWrapper->RequestObjAreaPixel( aRect );
558 }
559 }
560
561 /*************************************************************************
562 |* SvResizeWindow::KeyEvent()
563 |*
564 |* Description
565 *************************************************************************/
KeyInput(const KeyEvent & rEvt)566 void SvResizeWindow::KeyInput( const KeyEvent & rEvt )
567 {
568 if( rEvt.GetKeyCode().GetCode() == KEY_ESCAPE )
569 {
570 m_aResizer.Release( this );
571 m_pWrapper->InplaceDeactivate();
572 }
573 }
574
575 /*************************************************************************
576 |* SvResizeWindow::Resize()
577 |*
578 |* Description
579 *************************************************************************/
Resize()580 void SvResizeWindow::Resize()
581 {
582 m_aResizer.InvalidateBorder( this ); // old area
583 m_aResizer.SetOuterRectPixel( tools::Rectangle( Point(), GetOutputSizePixel() ) );
584 m_aResizer.InvalidateBorder( this ); // new area
585 }
586
587 /*************************************************************************
588 |* SvResizeWindow::Paint()
589 |*
590 |* Description
591 *************************************************************************/
Paint(vcl::RenderContext & rRenderContext,const tools::Rectangle &)592 void SvResizeWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle & /*rRect*/ )
593 {
594 m_aResizer.Draw(rRenderContext);
595 }
596
PreNotify(NotifyEvent & rEvt)597 bool SvResizeWindow::PreNotify( NotifyEvent& rEvt )
598 {
599 if ( rEvt.GetType() == MouseNotifyEvent::GETFOCUS && !m_bActive )
600 {
601 m_bActive = true;
602 m_pWrapper->Activated();
603 }
604
605 return Window::PreNotify(rEvt);
606 }
607
EventNotify(NotifyEvent & rEvt)608 bool SvResizeWindow::EventNotify( NotifyEvent& rEvt )
609 {
610 if ( rEvt.GetType() == MouseNotifyEvent::LOSEFOCUS && m_bActive )
611 {
612 bool bHasFocus = HasChildPathFocus(true);
613 if ( !bHasFocus )
614 {
615 m_bActive = false;
616 m_pWrapper->Deactivated();
617 }
618 }
619
620 return Window::EventNotify(rEvt);
621 }
622
623 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
624