LibreOffice Module vcl (master)  1
seleng.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 <vcl/commandevent.hxx>
21 #include <vcl/window.hxx>
22 #include <vcl/seleng.hxx>
23 #include <comphelper/lok.hxx>
24 #include <sal/log.hxx>
25 
27 {
28 }
29 
30 inline bool SelectionEngine::ShouldDeselect( bool bModifierKey1 ) const
31 {
32  return eSelMode != SelectionMode::Multiple || !bModifierKey1;
33 }
34 
35 // TODO: throw out FunctionSet::SelectAtPoint
36 
38  pWin( pWindow ),
39  nUpdateInterval( SELENG_AUTOREPEAT_INTERVAL )
40 {
42  pFunctionSet = pFuncSet;
44  nLockedMods = 0;
45 
46  aWTimer.SetInvokeHandler( LINK( this, SelectionEngine, ImpWatchDog ) );
48  aWTimer.SetDebugName( "vcl::SelectionEngine aWTimer" );
49 }
50 
52 {
53  aWTimer.Stop();
54 }
55 
56 IMPL_LINK_NOARG(SelectionEngine, ImpWatchDog, Timer *, void)
57 {
58  if ( !aArea.Contains( aLastMove.GetPosPixel() ) )
59  SelMouseMove( aLastMove );
60 }
61 
63 {
64  eSelMode = eMode;
65 }
66 
67 void SelectionEngine::CursorPosChanging( bool bShift, bool bMod1 )
68 {
69  if ( !pFunctionSet )
70  return;
71 
72  if ( bShift && eSelMode != SelectionMode::Single )
73  {
74  if ( IsAddMode() )
75  {
77  {
80  }
81  }
82  else
83  {
85  {
86  if( ShouldDeselect( bMod1 ) )
90  }
91  }
92  }
93  else
94  {
95  if ( IsAddMode() )
96  {
98  {
99  // pFunctionSet->CreateCursor();
102  }
103  }
104  else
105  {
106  if( ShouldDeselect( bMod1 ) )
108  else
111  }
112  }
113 }
114 
116 {
118  if ( !pFunctionSet || rMEvt.GetClicks() > 1 )
119  return false;
120 
121  sal_uInt16 nModifier = rMEvt.GetModifier() | nLockedMods;
122  bool nSwap = comphelper::LibreOfficeKit::isActive() && (nModifier & KEY_MOD1) && (nModifier & KEY_MOD2);
123 
124  if ( !nSwap && (nModifier & KEY_MOD2) )
125  return false;
126  // in SingleSelection: filter Control-Key,
127  // so that a D&D can be also started with a Ctrl-Click
128  if ( nModifier == KEY_MOD1 && eSelMode == SelectionMode::Single )
129  nModifier = 0;
130 
131  Point aPos = rMEvt.GetPosPixel();
132  aLastMove = rMEvt;
133 
134  if( !rMEvt.IsRight() )
135  {
136  CaptureMouse();
138  }
139  else
140  {
141  nModifier = 0;
142  }
143 
144  if (nSwap)
145  {
148  return true;
149  }
150 
151  switch ( nModifier )
152  {
153  case 0: // KEY_NO_KEY
154  {
155  bool bSelAtPoint = pFunctionSet->IsSelectionAtPoint( aPos );
157  if ( (nFlags & SelectionEngineFlags::DRG_ENAB) && bSelAtPoint )
158  {
161  ReleaseMouse();
162  return true; // wait for STARTDRAG-Command-Event
163  }
165  {
166  if( !IsAddMode() )
168  else
170  nFlags &= ~SelectionEngineFlags::HAS_ANCH; // bHasAnchor = false;
171  }
173  // special case Single-Selection, to enable simple Select+Drag
174  if (eSelMode == SelectionMode::Single && (nFlags & SelectionEngineFlags::DRG_ENAB))
176  return true;
177  }
178 
179  case KEY_SHIFT:
181  {
182  ReleaseMouse();
184  return false;
185  }
188  else
190 
192  {
197  }
199  return true;
200 
201  case KEY_MOD1:
202  // allow Control only for Multi-Select
204  {
206  ReleaseMouse();
207  return true; // skip Mouse-Click
208  }
209  if ( nFlags & SelectionEngineFlags::HAS_ANCH )
210  {
211  // pFunctionSet->CreateCursor();
214  }
215  if ( pFunctionSet->IsSelectionAtPoint( aPos ) )
216  {
217  pFunctionSet->DeselectAtPoint( aPos );
218  pFunctionSet->SetCursorAtPoint( aPos, true );
219  }
220  else
221  {
223  }
224  return true;
225 
226  case KEY_SHIFT + KEY_MOD1:
228  {
229  ReleaseMouse();
231  return false;
232  }
233  nFlags |= SelectionEngineFlags::IN_ADD; //bIsInAddMode = true;
234  if ( !(nFlags & SelectionEngineFlags::HAS_ANCH) )
235  {
238  }
240  return true;
241  }
242 
243  return false;
244 }
245 
247 {
248  aWTimer.Stop();
249  if (!pFunctionSet)
250  {
252  nFlags &= ~nMask;
253  return false;
254  }
255 
256  if (!rMEvt.IsRight())
257  ReleaseMouse();
258 
259 #if defined IOS || defined ANDROID
260  const bool bDoMessWithSelection = !rMEvt.IsRight();
261 #else
262  constexpr bool bDoMessWithSelection = true;
263 #endif
264 
267  {
268  // MouseButtonDown in Sel but no CommandEvent yet
269  // ==> deselect
270  sal_uInt16 nModifier = aLastMove.GetModifier() | nLockedMods;
271  if( nModifier == KEY_MOD1 || IsAlwaysAdding() )
272  {
273  if( !(nModifier & KEY_SHIFT) )
274  {
276  nFlags &= ~SelectionEngineFlags::HAS_ANCH; // uncheck anchor
277  }
279  nFlags &= ~SelectionEngineFlags::HAS_ANCH; // uncheck anchor
280  if (bDoMessWithSelection)
282  }
283  else
284  {
285  if (bDoMessWithSelection)
287  nFlags &= ~SelectionEngineFlags::HAS_ANCH; // uncheck anchor
288  if (bDoMessWithSelection)
290  }
291  }
292 
293  const SelectionEngineFlags nMask = SelectionEngineFlags::CMDEVT | SelectionEngineFlags::WAIT_UPEVT | SelectionEngineFlags::IN_SEL;
294  nFlags &= ~nMask;
295  return true;
296 }
297 
299 {
300  if (!pWin || !pWin->IsMouseCaptured())
301  return;
302  pWin->ReleaseMouse();
303 }
304 
306 {
307  if (!pWin || pWin->IsMouseCaptured())
308  return;
309  pWin->CaptureMouse();
310 }
311 
313 {
314 
317  return false;
318 
320  return false; // wait for DragEvent!
321 
322  aLastMove = rMEvt;
323  // if the mouse is outside the area, the frequency of
324  // SetCursorAtPoint() is only set by the Timer
325  if( aWTimer.IsActive() && !aArea.Contains( rMEvt.GetPosPixel() ))
326  return true;
327 
330  // Generating fake mouse moves does not work with LOK.
331  aWTimer.Start();
333  {
335  {
338  }
339  }
340 
342 
343  return true;
344 }
345 
347 {
348  if( pNewWin != pWin )
349  {
351  ReleaseMouse();
352  pWin = pNewWin;
353  if (nFlags & SelectionEngineFlags::IN_SEL)
354  CaptureMouse();
355  }
356 }
357 
359 {
360  aWTimer.Stop();
362  ReleaseMouse();
363  nFlags &= ~SelectionEngineFlags(SelectionEngineFlags::HAS_ANCH | SelectionEngineFlags::IN_SEL);
364  nLockedMods = 0;
365 }
366 
368 {
369  // Timer aWTimer is active during enlarging a selection
370  if ( !pFunctionSet || aWTimer.IsActive() )
371  return false;
372  aWTimer.Stop();
373  if ( rCEvt.GetCommand() != CommandEventId::StartDrag )
374  return false;
375 
378  {
379  SAL_WARN_IF( !rCEvt.IsMouseEvent(), "vcl", "STARTDRAG: Not a MouseEvent" );
381  {
387  nFlags &= ~nMask;
388  }
389  else
391  }
392  else
394  return true;
395 }
396 
398 {
399  if (nInterval < SELENG_AUTOREPEAT_INTERVAL_MIN)
400  // Set a lower threshold. On Windows, setting this value too low
401  // would cause selection to get updated indefinitely.
402  nInterval = SELENG_AUTOREPEAT_INTERVAL_MIN;
403 
404  if (nUpdateInterval == nInterval)
405  // no update needed.
406  return;
407 
408  if (aWTimer.IsActive())
409  {
410  // reset the timer right away on interval change.
411  aWTimer.Stop();
412  aWTimer.SetTimeout(nInterval);
413  aWTimer.Start();
414  }
415  else
416  aWTimer.SetTimeout(nInterval);
417 
418  nUpdateInterval = nInterval;
419 }
420 
421 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool SelMouseButtonDown(const MouseEvent &rMEvt)
Definition: seleng.cxx:115
void CaptureMouse()
Definition: mouse.cxx:445
virtual void SetCursorAtPoint(const Point &rPointPixel, bool bDontSelectAtCursor=false)=0
constexpr sal_uInt16 KEY_MOD1
Definition: keycodes.hxx:31
void SetSelectionMode(SelectionMode eMode)
Definition: seleng.cxx:62
tools::Rectangle aArea
Definition: seleng.hxx:83
bool Contains(const Point &rPOINT) const
sal_uIntPtr sal_uLong
MouseEventModifiers GetMode() const
Definition: event.hxx:124
bool ShouldDeselect(bool bModifierKey1) const
Definition: seleng.cxx:30
virtual bool IsSelectionAtPoint(const Point &rPointPixel)=0
void Reset()
Definition: seleng.cxx:358
SelectionMode
Definition: vclenum.hxx:26
VclPtr< vcl::Window > pWin
Definition: seleng.hxx:82
void CursorPosChanging(bool bShift, bool bMod1)
Definition: seleng.cxx:67
virtual void DestroyAnchor()=0
MouseEvent aLastMove
Definition: seleng.hxx:85
bool IsActive() const
Definition: task.hxx:102
sal_uInt16 GetClicks() const
Definition: event.hxx:126
void SetUpdateInterval(sal_uLong nInterval)
Definition: seleng.cxx:397
sal_uInt16 GetButtons() const
Definition: event.hxx:147
#define SELENG_AUTOREPEAT_INTERVAL
Definition: seleng.hxx:37
bool IsMouseEvent() const
SelectionEngine(vcl::Window *pWindow, FunctionSet *pFunctions=nullptr)
Definition: seleng.cxx:37
void SetDebugName(const char *pDebugName)
Definition: task.hxx:82
virtual void DeselectAtPoint(const Point &rPointPixel)=0
#define SELENG_AUTOREPEAT_INTERVAL_MIN
Definition: seleng.hxx:38
void CaptureMouse()
Definition: seleng.cxx:305
bool SelMouseMove(const MouseEvent &rMEvt)
Definition: seleng.cxx:312
bool SelMouseButtonUp(const MouseEvent &rMEvt)
Definition: seleng.cxx:246
IMPL_LINK_NOARG(SelectionEngine, ImpWatchDog, Timer *, void)
Definition: seleng.cxx:56
CommandEventId GetCommand() const
virtual void Start(bool bStartTimer=true) override
Schedules the task for execution.
Definition: timer.cxx:83
virtual void BeginDrag()=0
bool IsMouseCaptured() const
Definition: mouse.cxx:475
void ReleaseMouse()
Definition: seleng.cxx:298
sal_uInt16 GetModifier() const
Definition: event.hxx:156
Timer aWTimer
Definition: seleng.hxx:84
constexpr sal_uInt16 KEY_MOD2
Definition: keycodes.hxx:32
void SetTimeout(sal_uInt64 nTimeoutMs)
Definition: timer.cxx:90
void SetWindow(vcl::Window *)
Definition: seleng.cxx:346
bool IsAddMode() const
Definition: seleng.hxx:174
virtual void DeselectAll()=0
const Point & GetMousePosPixel() const
void ReleaseMouse()
Definition: mouse.cxx:463
void Stop()
Definition: scheduler.cxx:590
#define SAL_WARN_IF(condition, area, stream)
bool Command(const CommandEvent &rCEvt)
Definition: seleng.cxx:367
sal_uInt16 nLockedMods
Definition: seleng.hxx:88
SelectionMode eSelMode
Definition: seleng.hxx:86
SelectionEngineFlags nFlags
Definition: seleng.hxx:89
void SetInvokeHandler(const Link< Timer *, void > &rLink)
Definition: timer.hxx:56
sal_uLong nUpdateInterval
Definition: seleng.hxx:87
const Point & GetPosPixel() const
Definition: event.hxx:123
FunctionSet * pFunctionSet
Definition: seleng.hxx:81
Definition: timer.hxx:26
bool IsRight() const
Definition: event.hxx:153
virtual void CreateAnchor()=0
constexpr sal_uInt16 KEY_SHIFT
Definition: keycodes.hxx:30
virtual ~FunctionSet()=0
Definition: seleng.cxx:26
bool IsAlwaysAdding() const
Definition: seleng.hxx:206
SelectionEngineFlags
Definition: seleng.hxx:63