LibreOffice Module vcl (master)  1
cursor.cxx
Go to the documentation of this file.
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 <memory>
21 
22 #include <comphelper/lok.hxx>
23 #include <vcl/svapp.hxx>
24 #include <vcl/timer.hxx>
25 #include <vcl/settings.hxx>
26 #include <vcl/window.hxx>
27 #include <vcl/cursor.hxx>
28 
29 #include <window.h>
30 
31 #include <tools/poly.hxx>
32 
34 {
35  AutoTimer maTimer; // Timer
36  Point maPixPos; // Pixel-Position
37  Point maPixRotOff; // Pixel-Offset-Position
38  Size maPixSize; // Pixel-Size
39  short mnOrientation; // Pixel-Orientation
40  CursorDirection mnDirection; // indicates writing direction
41  sal_uInt16 mnStyle; // Cursor-Style
42  bool mbCurVisible; // Is cursor currently visible
43  VclPtr<vcl::Window> mpWindow; // assigned window
44 };
45 
47 {
48  tools::Rectangle aPaintRect;
49  bool bMapMode = pRenderContext->IsMapModeEnabled();
50  pRenderContext->EnableMapMode( false );
51  InvertFlags nInvertStyle;
52  if ( pData->mnStyle & CURSOR_SHADOW )
53  nInvertStyle = InvertFlags::N50;
54  else
55  nInvertStyle = InvertFlags::NONE;
56 
57  tools::Rectangle aRect( pData->maPixPos, pData->maPixSize );
58  if ( pData->mnDirection != CursorDirection::NONE || pData->mnOrientation )
59  {
60  tools::Polygon aPoly( aRect );
61  if( aPoly.GetSize() == 5 )
62  {
63  aPoly[1].AdjustX(1 ); // include the right border
64  aPoly[2].AdjustX(1 );
65 
66  // apply direction flag after slant to use the correct shape
67  if ( pData->mnDirection != CursorDirection::NONE)
68  {
69  Point pAry[7];
70  int delta = 3*aRect.getWidth()+1;
71  if( pData->mnDirection == CursorDirection::LTR )
72  {
73  // left-to-right
74  pAry[0] = aPoly.GetPoint( 0 );
75  pAry[1] = aPoly.GetPoint( 1 );
76  pAry[2] = pAry[1];
77  pAry[2].AdjustX(delta );
78  pAry[3] = pAry[1];
79  pAry[3].AdjustY(delta );
80  pAry[4] = aPoly.GetPoint( 2 );
81  pAry[5] = aPoly.GetPoint( 3 );
82  pAry[6] = aPoly.GetPoint( 4 );
83  }
84  else if( pData->mnDirection == CursorDirection::RTL )
85  {
86  // right-to-left
87  pAry[0] = aPoly.GetPoint( 0 );
88  pAry[1] = aPoly.GetPoint( 1 );
89  pAry[2] = aPoly.GetPoint( 2 );
90  pAry[3] = aPoly.GetPoint( 3 );
91  pAry[4] = pAry[0];
92  pAry[4].AdjustY(delta );
93  pAry[5] = pAry[0];
94  pAry[5].AdjustX( -delta );
95  pAry[6] = aPoly.GetPoint( 4 );
96  }
97  aPoly = tools::Polygon( 7, pAry);
98  }
99 
100  if ( pData->mnOrientation )
101  aPoly.Rotate( pData->maPixRotOff, pData->mnOrientation );
102  pRenderContext->Invert( aPoly, nInvertStyle );
103  aPaintRect = aPoly.GetBoundRect();
104  }
105  }
106  else
107  {
108  pRenderContext->Invert( aRect, nInvertStyle );
109  aPaintRect = aRect;
110  }
111  pRenderContext->EnableMapMode( bMapMode );
112  return aPaintRect;
113 }
114 
115 static void ImplCursorInvert(vcl::Window* pWindow, ImplCursorData const * pData)
116 {
117  std::unique_ptr<PaintBufferGuard> pGuard;
118  const bool bDoubleBuffering = pWindow->SupportsDoubleBuffering();
119  if (bDoubleBuffering)
120  pGuard.reset(new PaintBufferGuard(pWindow->ImplGetWindowImpl()->mpFrameData, pWindow));
121 
122  vcl::RenderContext* pRenderContext = bDoubleBuffering ? pGuard->GetRenderContext() : pWindow;
123 
124  tools::Rectangle aPaintRect = ImplCursorInvert(pRenderContext, pData);
125  if (bDoubleBuffering)
126  pGuard->SetPaintRect(pRenderContext->PixelToLogic(aPaintRect));
127 }
128 
130 {
131  if (pDevice && !rData.mbCurVisible)
132  {
133  rData.maPixPos = pDevice->LogicToPixel( maPos );
134  rData.maPixSize = pDevice->LogicToPixel( maSize );
136  rData.mnDirection = mnDirection;
137 
138  // correct the position with the offset
139  rData.maPixRotOff = rData.maPixPos;
140 
141  // use width (as set in Settings) if size is 0,
142  if (!rData.maPixSize.Width())
144  return true;
145  }
146  return false;
147 }
148 
150 {
151  if (mpData && mpData->mpWindow)
152  {
153  // calculate output area
154  if (ImplPrepForDraw(mpData->mpWindow, *mpData))
155  {
156  // display
157  ImplCursorInvert(mpData->mpWindow, mpData.get());
158  mpData->mbCurVisible = true;
159  }
160  }
161 }
162 
164 {
166  aData.mnStyle = 0;
167  aData.mbCurVisible = false;
168  // calculate output area
169  if (ImplPrepForDraw(&rRenderContext, aData))
170  {
171  // display
172  ImplCursorInvert(&rRenderContext, &aData);
173  }
174 }
175 
177 {
178  assert( mpData && mpData->mbCurVisible );
179 
180  ImplCursorInvert(mpData->mpWindow, mpData.get());
181  mpData->mbCurVisible = false;
182 }
183 
184 void vcl::Cursor::ImplDoShow( bool bDrawDirect, bool bRestore )
185 {
186  if ( mbVisible )
187  {
188  vcl::Window* pWindow;
189  if ( mpWindow )
190  pWindow = mpWindow;
191  else
192  {
193  // show the cursor, if there is an active window and the cursor
194  // has been selected in this window
195  pWindow = Application::GetFocusWindow();
196  if ( !pWindow || (pWindow->mpWindowImpl->mpCursor != this) || pWindow->mpWindowImpl->mbInPaint
197  || !pWindow->mpWindowImpl->mpFrameData->mbHasFocus )
198  pWindow = nullptr;
199  }
200 
201  if ( pWindow )
202  {
203  if ( !mpData )
204  {
205  mpData.reset( new ImplCursorData );
206  mpData->mbCurVisible = false;
207  mpData->maTimer.SetInvokeHandler( LINK( this, Cursor, ImplTimerHdl ) );
208  mpData->maTimer.SetDebugName( "vcl ImplCursorData maTimer" );
209  }
210 
211  mpData->mpWindow = pWindow;
212  mpData->mnStyle = mnStyle;
213  if ( bDrawDirect || bRestore )
214  ImplDraw();
215 
216  if ( !mpWindow && ! ( ! bDrawDirect && mpData->maTimer.IsActive()) )
217  {
218  mpData->maTimer.SetTimeout( pWindow->GetSettings().GetStyleSettings().GetCursorBlinkTime() );
219  if ( mpData->maTimer.GetTimeout() != STYLE_CURSOR_NOBLINKTIME )
220  mpData->maTimer.Start();
221  else if ( !mpData->mbCurVisible )
222  ImplDraw();
223  LOKNotify( pWindow, "cursor_invalidate" );
224  LOKNotify( pWindow, "cursor_visible" );
225  }
226  }
227  }
228 }
229 
230 void vcl::Cursor::LOKNotify( vcl::Window* pWindow, const OUString& rAction )
231 {
232  if (VclPtr<vcl::Window> pParent = pWindow->GetParentWithLOKNotifier())
233  {
234  assert(pWindow && "Cannot notify without a window");
235  assert(mpData && "Require ImplCursorData");
237 
239  return;
240 
241  const vcl::ILibreOfficeKitNotifier* pNotifier = pParent->GetLOKNotifier();
242  std::vector<vcl::LOKPayloadItem> aItems;
243  if (rAction == "cursor_visible")
244  aItems.emplace_back("visible", mpData->mbCurVisible ? "true" : "false");
245  else if (rAction == "cursor_invalidate")
246  {
247  const long nX = pWindow->GetOutOffXPixel() + pWindow->LogicToPixel(GetPos()).X();
248  const long nY = pWindow->GetOutOffYPixel() + pWindow->LogicToPixel(GetPos()).Y();
249  Size aSize = pWindow->LogicToPixel(GetSize());
250  if (!aSize.Width())
251  aSize.setWidth( pWindow->GetSettings().GetStyleSettings().GetCursorSize() );
252 
253  const tools::Rectangle aRect(Point(nX, nY), aSize);
254  aItems.emplace_back("rectangle", aRect.toString());
255  }
256 
257  pNotifier->notifyWindow(pParent->GetLOKWindowId(), rAction, aItems);
258  }
259 }
260 
261 bool vcl::Cursor::ImplDoHide( bool bSuspend )
262 {
263  bool bWasCurVisible = false;
264  if ( mpData && mpData->mpWindow )
265  {
266  bWasCurVisible = mpData->mbCurVisible;
267  if ( mpData->mbCurVisible )
268  ImplRestore();
269 
270  if ( !bSuspend )
271  {
272  LOKNotify( mpData->mpWindow, "cursor_visible" );
273  mpData->maTimer.Stop();
274  mpData->mpWindow = nullptr;
275  }
276  }
277  return bWasCurVisible;
278 }
279 
281 {
282  ImplDoShow( true/*bDrawDirect*/, false );
283 }
284 
286 {
287  ImplDoHide( false );
288 }
289 
290 void vcl::Cursor::ImplResume( bool bRestore )
291 {
292  ImplDoShow( false, bRestore );
293 }
294 
296 {
297  return ImplDoHide( true );
298 }
299 
301 {
302  if ( mbVisible && mpData && mpData->mpWindow )
303  {
304  if ( mpData->mbCurVisible )
305  ImplRestore();
306 
307  ImplDraw();
308  if ( !mpWindow )
309  {
310  LOKNotify( mpData->mpWindow, "cursor_invalidate" );
311  if ( mpData->maTimer.GetTimeout() != STYLE_CURSOR_NOBLINKTIME )
312  mpData->maTimer.Start();
313  }
314  }
315 }
316 
317 IMPL_LINK_NOARG(vcl::Cursor, ImplTimerHdl, Timer *, void)
318 {
319  if ( mpData->mbCurVisible )
320  ImplRestore();
321  else
322  ImplDraw();
323 }
324 
326 {
327  mpData = nullptr;
328  mpWindow = nullptr;
329  mnOrientation = 0;
330  mnDirection = CursorDirection::NONE;
331  mnStyle = 0;
332  mbVisible = false;
333 }
334 
335 vcl::Cursor::Cursor( const Cursor& rCursor ) :
336  maSize( rCursor.maSize ),
337  maPos( rCursor.maPos )
338 {
339  mpData = nullptr;
340  mpWindow = nullptr;
341  mnOrientation = rCursor.mnOrientation;
342  mnDirection = rCursor.mnDirection;
343  mnStyle = 0;
344  mbVisible = rCursor.mbVisible;
345 }
346 
348 {
349  if (mpData && mpData->mbCurVisible)
350  ImplRestore();
351 }
352 
353 void vcl::Cursor::SetStyle( sal_uInt16 nStyle )
354 {
355  if ( mnStyle != nStyle )
356  {
357  mnStyle = nStyle;
358  ImplNew();
359  }
360 }
361 
363 {
364  if ( !mbVisible )
365  {
366  mbVisible = true;
367  ImplShow();
368  }
369 }
370 
372 {
373  if ( mbVisible )
374  {
375  mbVisible = false;
376  ImplHide();
377  }
378 }
379 
381 {
382  if ( mpWindow.get() != pWindow )
383  {
384  mpWindow = pWindow;
385  ImplNew();
386  }
387 }
388 
389 void vcl::Cursor::SetPos( const Point& rPoint )
390 {
391  if ( maPos != rPoint )
392  {
393  maPos = rPoint;
394  ImplNew();
395  }
396 }
397 
398 void vcl::Cursor::SetSize( const Size& rSize )
399 {
400  if ( maSize != rSize )
401  {
402  maSize = rSize;
403  ImplNew();
404  }
405 }
406 
407 void vcl::Cursor::SetWidth( long nNewWidth )
408 {
409  if ( maSize.Width() != nNewWidth )
410  {
411  maSize.setWidth( nNewWidth );
412  ImplNew();
413  }
414 }
415 
416 void vcl::Cursor::SetOrientation( short nNewOrientation )
417 {
418  if ( mnOrientation != nNewOrientation )
419  {
420  mnOrientation = nNewOrientation;
421  ImplNew();
422  }
423 }
424 
426 {
427  if ( mnDirection != nNewDirection )
428  {
429  mnDirection = nNewDirection;
430  ImplNew();
431  }
432 }
433 
435 {
436  maPos = rCursor.maPos;
437  maSize = rCursor.maSize;
438  mnOrientation = rCursor.mnOrientation;
439  mnDirection = rCursor.mnDirection;
440  mbVisible = rCursor.mbVisible;
441  ImplNew();
442 
443  return *this;
444 }
445 
446 bool vcl::Cursor::operator==( const vcl::Cursor& rCursor ) const
447 {
448  return
449  ((maPos == rCursor.maPos) &&
450  (maSize == rCursor.maSize) &&
451  (mnOrientation == rCursor.mnOrientation) &&
452  (mnDirection == rCursor.mnDirection) &&
453  (mbVisible == rCursor.mbVisible))
454  ;
455 }
456 
457 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
long Width() const
void SetOrientation(short nOrientation=0)
Definition: cursor.cxx:416
void DrawToDevice(OutputDevice &rRenderContext)
Definition: cursor.cxx:163
CursorDirection mnDirection
Definition: cursor.cxx:40
std::unique_ptr< ImplCursorData > mpData
Definition: cursor.hxx:49
sal_uInt16 mnStyle
Definition: cursor.hxx:54
bool mbCurVisible
Definition: cursor.cxx:42
void SetPos(const Point &rNewPos)
Definition: cursor.cxx:389
const char aData[]
long AdjustX(long nHorzMove)
SAL_DLLPRIVATE bool ImplSuspend()
Definition: cursor.cxx:295
long getWidth() const
long GetOutOffXPixel() const
Definition: outdev.hxx:445
Point maPos
Definition: cursor.hxx:52
const StyleSettings & GetStyleSettings() const
void SetWidth(long nNewWidth)
Definition: cursor.cxx:407
bool IsMapModeEnabled() const
Definition: outdev.hxx:1669
SAL_DLLPRIVATE WindowImpl * ImplGetWindowImpl() const
Definition: window.hxx:554
SAL_DLLPRIVATE void ImplNew()
Definition: cursor.cxx:300
void EnableMapMode(bool bEnable=true)
Definition: map.cxx:647
sal_uInt16 mnStyle
Definition: cursor.cxx:41
void LOKNotify(vcl::Window *pWindow, const OUString &rAction)
Definition: cursor.cxx:230
CursorDirection mnDirection
Definition: cursor.hxx:56
Point maPixRotOff
Definition: cursor.cxx:37
AutoTimer maTimer
Definition: cursor.cxx:35
void Invert(const tools::Rectangle &rRect, InvertFlags nFlags=InvertFlags::NONE)
Definition: rect.cxx:128
Point maPixPos
Definition: cursor.cxx:36
VclPtr< vcl::Window > GetParentWithLOKNotifier()
Find the nearest parent with LOK Notifier; can be itself if this Window has LOK notifier set...
Definition: window.cxx:3251
#define CURSOR_SHADOW
Definition: cursor.hxx:36
void SetStyle(sal_uInt16 nStyle)
Definition: cursor.cxx:353
#define STYLE_CURSOR_NOBLINKTIME
Definition: settings.hxx:214
Sets up the buffer to have settings matching the window, and restores the original state in the dtor...
Definition: window.h:400
void Hide()
Definition: cursor.cxx:371
short mnOrientation
Definition: cursor.hxx:53
void Rotate(const Point &rCenter, double fSin, double fCos)
SAL_DLLPRIVATE void ImplResume(bool bRestore=false)
Definition: cursor.cxx:290
SAL_DLLPRIVATE void ImplDraw()
Definition: cursor.cxx:149
An auto-timer is a multi-shot timer re-emitting itself at interval until destroyed or stopped...
Definition: timer.hxx:72
VclPtr< vcl::Window > mpWindow
short mnOrientation
Definition: cursor.cxx:39
long GetCursorSize() const
long AdjustY(long nVertMove)
bool ImplDoHide(bool bStop)
Definition: cursor.cxx:261
SAL_DLLPRIVATE void ImplHide()
Definition: cursor.cxx:285
bool operator==(const Cursor &rCursor) const
Definition: cursor.cxx:446
Size maSize
Definition: cursor.hxx:51
CursorDirection
Definition: cursor.hxx:38
Some things multiple-inherit from VclAbstractDialog and OutputDevice, so we need to use virtual inher...
Definition: outdev.hxx:304
void SetWindow(vcl::Window *pWindow)
Definition: cursor.cxx:380
bool mbVisible
Definition: cursor.hxx:55
std::unique_ptr< WindowImpl > mpWindowImpl
Definition: window.hxx:511
SAL_DLLPRIVATE void ImplShow()
Definition: cursor.cxx:280
void Show()
Definition: cursor.cxx:362
sal_uInt16 GetSize() const
void SetSize(const Size &rNewSize)
Definition: cursor.cxx:398
const AllSettings & GetSettings() const
Definition: outdev.hxx:420
VclPtr< vcl::Window > mpWindow
Definition: cursor.cxx:43
long X() const
VclPtr< vcl::Window > mpWindow
Definition: cursor.hxx:50
Point PixelToLogic(const Point &rDevicePt) const
Definition: map.cxx:1185
Point LogicToPixel(const Point &rLogicPt) const
Definition: map.cxx:940
const Point & GetPoint(sal_uInt16 nPos) const
void ImplRestore()
Definition: cursor.cxx:176
static vcl::Window * GetFocusWindow()
Get the currently focused window.
Definition: svapp.cxx:1049
sal_uInt64 GetCursorBlinkTime() const
virtual void notifyWindow(vcl::LOKWindowId nLOKWindowId, const OUString &rAction, const std::vector< LOKPayloadItem > &rPayload=std::vector< LOKPayloadItem >()) const =0
Callbacks.
Size maPixSize
Definition: cursor.cxx:38
InvertFlags
Definition: outdev.hxx:267
long GetOutOffYPixel() const
Definition: outdev.hxx:446
Cursor & operator=(const Cursor &rCursor)
Definition: cursor.cxx:434
reference_type * get() const
Get the body.
Definition: vclptr.hxx:143
bool ImplPrepForDraw(const OutputDevice *pDevice, ImplCursorData &rData)
Definition: cursor.cxx:129
Definition: timer.hxx:26
tools::Rectangle GetBoundRect() const
static tools::Rectangle ImplCursorInvert(vcl::RenderContext *pRenderContext, ImplCursorData const *pData)
Definition: cursor.cxx:46
void ImplDoShow(bool bDrawDirect, bool bRestore)
Definition: cursor.cxx:184
rtl::OString toString() const
IMPL_LINK_NOARG(QuickSelectionEngine_Data, SearchStringTimeout, Timer *, void)
ImplFrameData * mpFrameData
Definition: window.h:224
void SetDirection(CursorDirection nDirection=CursorDirection::NONE)
Definition: cursor.cxx:425
bool SupportsDoubleBuffering() const
Can the widget derived from this Window do the double-buffering via RenderContext properly...
Definition: window.cxx:3814
void setWidth(long nWidth)
long Y() const
::basegfx::B2IVector maSize