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  if ( nModifier & KEY_MOD2 )
123  return false;
124  // in SingleSelection: filter Control-Key,
125  // so that a D&D can be also started with a Ctrl-Click
126  if ( nModifier == KEY_MOD1 && eSelMode == SelectionMode::Single )
127  nModifier = 0;
128 
129  Point aPos = rMEvt.GetPosPixel();
130  aLastMove = rMEvt;
131 
132  if( !rMEvt.IsRight() )
133  {
134  CaptureMouse();
136  }
137  else
138  {
139  nModifier = 0;
140  }
141 
142  switch ( nModifier )
143  {
144  case 0: // KEY_NO_KEY
145  {
146  bool bSelAtPoint = pFunctionSet->IsSelectionAtPoint( aPos );
148  if ( (nFlags & SelectionEngineFlags::DRG_ENAB) && bSelAtPoint )
149  {
152  ReleaseMouse();
153  return true; // wait for STARTDRAG-Command-Event
154  }
156  {
157  if( !IsAddMode() )
159  else
161  nFlags &= ~SelectionEngineFlags::HAS_ANCH; // bHasAnchor = false;
162  }
164  // special case Single-Selection, to enable simple Select+Drag
165  if (eSelMode == SelectionMode::Single && (nFlags & SelectionEngineFlags::DRG_ENAB))
167  return true;
168  }
169 
170  case KEY_SHIFT:
172  {
173  ReleaseMouse();
175  return false;
176  }
179  else
181 
183  {
188  }
190  return true;
191 
192  case KEY_MOD1:
193  // allow Control only for Multi-Select
195  {
197  ReleaseMouse();
198  return true; // skip Mouse-Click
199  }
200  if ( nFlags & SelectionEngineFlags::HAS_ANCH )
201  {
202  // pFunctionSet->CreateCursor();
205  }
206  if ( pFunctionSet->IsSelectionAtPoint( aPos ) )
207  {
208  pFunctionSet->DeselectAtPoint( aPos );
209  pFunctionSet->SetCursorAtPoint( aPos, true );
210  }
211  else
212  {
214  }
215  return true;
216 
217  case KEY_SHIFT + KEY_MOD1:
219  {
220  ReleaseMouse();
222  return false;
223  }
224  nFlags |= SelectionEngineFlags::IN_ADD; //bIsInAddMode = true;
225  if ( !(nFlags & SelectionEngineFlags::HAS_ANCH) )
226  {
229  }
231  return true;
232  }
233 
234  return false;
235 }
236 
238 {
239  aWTimer.Stop();
240  if (!pFunctionSet)
241  {
243  nFlags &= ~nMask;
244  return false;
245  }
246 
247  if (!rMEvt.IsRight())
248  ReleaseMouse();
249 
252  {
253  // MouseButtonDown in Sel but no CommandEvent yet
254  // ==> deselect
255  sal_uInt16 nModifier = aLastMove.GetModifier() | nLockedMods;
256  if( nModifier == KEY_MOD1 || IsAlwaysAdding() )
257  {
258  if( !(nModifier & KEY_SHIFT) )
259  {
261  nFlags &= ~SelectionEngineFlags::HAS_ANCH; // uncheck anchor
262  }
264  nFlags &= ~SelectionEngineFlags::HAS_ANCH; // uncheck anchor
266  }
267  else
268  {
270  nFlags &= ~SelectionEngineFlags::HAS_ANCH; // uncheck anchor
272  }
273  }
274 
275  const SelectionEngineFlags nMask = SelectionEngineFlags::CMDEVT | SelectionEngineFlags::WAIT_UPEVT | SelectionEngineFlags::IN_SEL;
276  nFlags &= ~nMask;
277  return true;
278 }
279 
281 {
282  if (!pWin || !pWin->IsMouseCaptured())
283  return;
284  pWin->ReleaseMouse();
285 }
286 
288 {
289  if (!pWin || pWin->IsMouseCaptured())
290  return;
291  pWin->CaptureMouse();
292 }
293 
295 {
296 
299  return false;
300 
302  return false; // wait for DragEvent!
303 
304  aLastMove = rMEvt;
305  // if the mouse is outside the area, the frequency of
306  // SetCursorAtPoint() is only set by the Timer
307  if( aWTimer.IsActive() && !aArea.IsInside( rMEvt.GetPosPixel() ))
308  return true;
309 
312  // Generating fake mouse moves does not work with LOK.
313  aWTimer.Start();
315  {
317  {
320  }
321  }
322 
324 
325  return true;
326 }
327 
329 {
330  if( pNewWin != pWin )
331  {
333  ReleaseMouse();
334  pWin = pNewWin;
335  if (nFlags & SelectionEngineFlags::IN_SEL)
336  CaptureMouse();
337  }
338 }
339 
341 {
342  aWTimer.Stop();
344  ReleaseMouse();
345  nFlags &= ~SelectionEngineFlags(SelectionEngineFlags::HAS_ANCH | SelectionEngineFlags::IN_SEL);
346  nLockedMods = 0;
347 }
348 
350 {
351  // Timer aWTimer is active during enlarging a selection
352  if ( !pFunctionSet || aWTimer.IsActive() )
353  return;
354  aWTimer.Stop();
355  if ( rCEvt.GetCommand() == CommandEventId::StartDrag )
356  {
359  {
360  SAL_WARN_IF( !rCEvt.IsMouseEvent(), "vcl", "STARTDRAG: Not a MouseEvent" );
362  {
368  nFlags &= ~nMask;
369  }
370  else
372  }
373  else
375  }
376 }
377 
379 {
380  if (nInterval < SELENG_AUTOREPEAT_INTERVAL_MIN)
381  // Set a lower threshold. On Windows, setting this value too low
382  // would cause selection to get updated indefinitely.
383  nInterval = SELENG_AUTOREPEAT_INTERVAL_MIN;
384 
385  if (nUpdateInterval == nInterval)
386  // no update needed.
387  return;
388 
389  if (aWTimer.IsActive())
390  {
391  // reset the timer right away on interval change.
392  aWTimer.Stop();
393  aWTimer.SetTimeout(nInterval);
394  aWTimer.Start();
395  }
396  else
397  aWTimer.SetTimeout(nInterval);
398 
399  nUpdateInterval = nInterval;
400 }
401 
402 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool SelMouseButtonDown(const MouseEvent &rMEvt)
Definition: seleng.cxx:115
void CaptureMouse()
Definition: mouse.cxx:439
virtual void SetCursorAtPoint(const Point &rPointPixel, bool bDontSelectAtCursor=false)=0
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:118
bool ShouldDeselect(bool bModifierKey1) const
Definition: seleng.cxx:30
#define KEY_SHIFT
Definition: keycodes.hxx:30
virtual bool IsSelectionAtPoint(const Point &rPointPixel)=0
#define KEY_MOD1
Definition: keycodes.hxx:31
void Reset()
Definition: seleng.cxx:340
SelectionMode
Definition: vclenum.hxx:26
VclPtr< vcl::Window > pWin
Definition: seleng.hxx:78
void Command(const CommandEvent &rCEvt)
Definition: seleng.cxx:349
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:120
void SetUpdateInterval(sal_uLong nInterval)
Definition: seleng.cxx:378
sal_uInt16 GetButtons() const
Definition: event.hxx:131
#define KEY_MOD2
Definition: keycodes.hxx:32
#define SELENG_AUTOREPEAT_INTERVAL
Definition: seleng.hxx:33
bool IsMouseEvent() const
SelectionEngine(vcl::Window *pWindow, FunctionSet *pFunctions=nullptr)
Definition: seleng.cxx:37
virtual void DeselectAtPoint(const Point &rPointPixel)=0
#define SELENG_AUTOREPEAT_INTERVAL_MIN
Definition: seleng.hxx:34
void CaptureMouse()
Definition: seleng.cxx:287
bool SelMouseMove(const MouseEvent &rMEvt)
Definition: seleng.cxx:294
bool SelMouseButtonUp(const MouseEvent &rMEvt)
Definition: seleng.cxx:237
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:280
sal_uInt16 GetModifier() const
Definition: event.hxx:140
Timer aWTimer
Definition: seleng.hxx:80
void SetTimeout(sal_uInt64 nTimeoutMs)
Definition: timer.cxx:89
void SetWindow(vcl::Window *)
Definition: seleng.cxx:328
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:117
FunctionSet * pFunctionSet
Definition: seleng.hxx:77
Definition: timer.hxx:26
bool IsRight() const
Definition: event.hxx:137
virtual void CreateAnchor()=0
virtual ~FunctionSet()=0
Definition: seleng.cxx:26
bool IsAlwaysAdding() const
Definition: seleng.hxx:195
void SetDebugName(const sal_Char *pDebugName)
Definition: task.hxx:81
SelectionEngineFlags
Definition: seleng.hxx:59