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.IsInside( 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 
261  {
262  // MouseButtonDown in Sel but no CommandEvent yet
263  // ==> deselect
264  sal_uInt16 nModifier = aLastMove.GetModifier() | nLockedMods;
265  if( nModifier == KEY_MOD1 || IsAlwaysAdding() )
266  {
267  if( !(nModifier & KEY_SHIFT) )
268  {
270  nFlags &= ~SelectionEngineFlags::HAS_ANCH; // uncheck anchor
271  }
273  nFlags &= ~SelectionEngineFlags::HAS_ANCH; // uncheck anchor
275  }
276  else
277  {
279  nFlags &= ~SelectionEngineFlags::HAS_ANCH; // uncheck anchor
281  }
282  }
283 
284  const SelectionEngineFlags nMask = SelectionEngineFlags::CMDEVT | SelectionEngineFlags::WAIT_UPEVT | SelectionEngineFlags::IN_SEL;
285  nFlags &= ~nMask;
286  return true;
287 }
288 
290 {
291  if (!pWin || !pWin->IsMouseCaptured())
292  return;
293  pWin->ReleaseMouse();
294 }
295 
297 {
298  if (!pWin || pWin->IsMouseCaptured())
299  return;
300  pWin->CaptureMouse();
301 }
302 
304 {
305 
308  return false;
309 
311  return false; // wait for DragEvent!
312 
313  aLastMove = rMEvt;
314  // if the mouse is outside the area, the frequency of
315  // SetCursorAtPoint() is only set by the Timer
316  if( aWTimer.IsActive() && !aArea.IsInside( rMEvt.GetPosPixel() ))
317  return true;
318 
321  // Generating fake mouse moves does not work with LOK.
322  aWTimer.Start();
324  {
326  {
329  }
330  }
331 
333 
334  return true;
335 }
336 
338 {
339  if( pNewWin != pWin )
340  {
342  ReleaseMouse();
343  pWin = pNewWin;
344  if (nFlags & SelectionEngineFlags::IN_SEL)
345  CaptureMouse();
346  }
347 }
348 
350 {
351  aWTimer.Stop();
353  ReleaseMouse();
354  nFlags &= ~SelectionEngineFlags(SelectionEngineFlags::HAS_ANCH | SelectionEngineFlags::IN_SEL);
355  nLockedMods = 0;
356 }
357 
359 {
360  // Timer aWTimer is active during enlarging a selection
361  if ( !pFunctionSet || aWTimer.IsActive() )
362  return;
363  aWTimer.Stop();
364  if ( rCEvt.GetCommand() == CommandEventId::StartDrag )
365  {
368  {
369  SAL_WARN_IF( !rCEvt.IsMouseEvent(), "vcl", "STARTDRAG: Not a MouseEvent" );
371  {
377  nFlags &= ~nMask;
378  }
379  else
381  }
382  else
384  }
385 }
386 
388 {
389  if (nInterval < SELENG_AUTOREPEAT_INTERVAL_MIN)
390  // Set a lower threshold. On Windows, setting this value too low
391  // would cause selection to get updated indefinitely.
392  nInterval = SELENG_AUTOREPEAT_INTERVAL_MIN;
393 
394  if (nUpdateInterval == nInterval)
395  // no update needed.
396  return;
397 
398  if (aWTimer.IsActive())
399  {
400  // reset the timer right away on interval change.
401  aWTimer.Stop();
402  aWTimer.SetTimeout(nInterval);
403  aWTimer.Start();
404  }
405  else
406  aWTimer.SetTimeout(nInterval);
407 
408  nUpdateInterval = nInterval;
409 }
410 
411 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool SelMouseButtonDown(const MouseEvent &rMEvt)
Definition: seleng.cxx:115
void CaptureMouse()
Definition: mouse.cxx:440
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:79
sal_uIntPtr sal_uLong
MouseEventModifiers GetMode() const
Definition: event.hxx:121
bool ShouldDeselect(bool bModifierKey1) const
Definition: seleng.cxx:30
virtual bool IsSelectionAtPoint(const Point &rPointPixel)=0
void Reset()
Definition: seleng.cxx:349
SelectionMode
Definition: vclenum.hxx:26
VclPtr< vcl::Window > pWin
Definition: seleng.hxx:78
void Command(const CommandEvent &rCEvt)
Definition: seleng.cxx:358
void CursorPosChanging(bool bShift, bool bMod1)
Definition: seleng.cxx:67
virtual void DestroyAnchor()=0
MouseEvent aLastMove
Definition: seleng.hxx:81
bool IsActive() const
Definition: task.hxx:90
sal_uInt16 GetClicks() const
Definition: event.hxx:123
void SetUpdateInterval(sal_uLong nInterval)
Definition: seleng.cxx:387
sal_uInt16 GetButtons() const
Definition: event.hxx:144
#define SELENG_AUTOREPEAT_INTERVAL
Definition: seleng.hxx:33
bool IsMouseEvent() const
SelectionEngine(vcl::Window *pWindow, FunctionSet *pFunctions=nullptr)
Definition: seleng.cxx:37
void SetDebugName(const char *pDebugName)
Definition: task.hxx:81
virtual void DeselectAtPoint(const Point &rPointPixel)=0
#define SELENG_AUTOREPEAT_INTERVAL_MIN
Definition: seleng.hxx:34
void CaptureMouse()
Definition: seleng.cxx:296
bool SelMouseMove(const MouseEvent &rMEvt)
Definition: seleng.cxx:303
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() override
Activates the timer task.
Definition: timer.cxx:83
virtual void BeginDrag()=0
bool IsInside(const Point &rPOINT) const
bool IsMouseCaptured() const
Definition: mouse.cxx:469
void ReleaseMouse()
Definition: seleng.cxx:289
sal_uInt16 GetModifier() const
Definition: event.hxx:153
Timer aWTimer
Definition: seleng.hxx:80
constexpr sal_uInt16 KEY_MOD2
Definition: keycodes.hxx:32
void SetTimeout(sal_uInt64 nTimeoutMs)
Definition: timer.cxx:89
void SetWindow(vcl::Window *)
Definition: seleng.cxx:337
bool IsAddMode() const
Definition: seleng.hxx:163
virtual void DeselectAll()=0
const Point & GetMousePosPixel() const
void ReleaseMouse()
Definition: mouse.cxx:458
void Stop()
Definition: scheduler.cxx:593
#define SAL_WARN_IF(condition, area, stream)
sal_uInt16 nLockedMods
Definition: seleng.hxx:84
SelectionMode eSelMode
Definition: seleng.hxx:82
SelectionEngineFlags nFlags
Definition: seleng.hxx:85
void SetInvokeHandler(const Link< Timer *, void > &rLink)
Definition: timer.hxx:56
sal_uLong nUpdateInterval
Definition: seleng.hxx:83
const Point & GetPosPixel() const
Definition: event.hxx:120
FunctionSet * pFunctionSet
Definition: seleng.hxx:77
Definition: timer.hxx:26
bool IsRight() const
Definition: event.hxx:150
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:195
SelectionEngineFlags
Definition: seleng.hxx:59