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
30inline 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 aWTimer( "vcl::SelectionEngine aWTimer" ),
40 nUpdateInterval( SELENG_AUTOREPEAT_INTERVAL )
41{
43 pFunctionSet = pFuncSet;
45 nLockedMods = 0;
46
47 aWTimer.SetInvokeHandler( LINK( this, SelectionEngine, ImpWatchDog ) );
49}
50
52{
53 aWTimer.Stop();
54}
55
57{
58 if ( !aArea.Contains( aLastMove.GetPosPixel() ) )
59 SelMouseMove( aLastMove );
60}
61
63{
65}
66
67void 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
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 }
210 {
211 // pFunctionSet->CreateCursor();
214 }
215 if ( pFunctionSet->IsSelectionAtPoint( aPos ) )
216 {
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;
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
294 nFlags &= ~nMask;
295 return true;
296}
297
299{
300 if (!pWin || !pWin->IsMouseCaptured())
301 return;
303}
304
306{
307 if (!pWin || pWin->IsMouseCaptured())
308 return;
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;
354 CaptureMouse();
355 }
356}
357
359{
360 aWTimer.Stop();
362 ReleaseMouse();
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.
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: */
CommandEventId GetCommand() const
const Point & GetMousePosPixel() const
bool IsMouseEvent() const
virtual void DeselectAtPoint(const Point &rPointPixel)=0
virtual ~FunctionSet()=0
Definition: seleng.cxx:26
virtual void DestroyAnchor()=0
virtual void SetCursorAtPoint(const Point &rPointPixel, bool bDontSelectAtCursor=false)=0
virtual void CreateAnchor()=0
virtual void BeginDrag()=0
virtual void DeselectAll()=0
virtual bool IsSelectionAtPoint(const Point &rPointPixel)=0
MouseEventModifiers GetMode() const
Definition: event.hxx:124
sal_uInt16 GetModifier() const
Definition: event.hxx:156
sal_uInt16 GetClicks() const
Definition: event.hxx:126
bool IsRight() const
Definition: event.hxx:153
sal_uInt16 GetButtons() const
Definition: event.hxx:147
const Point & GetPosPixel() const
Definition: event.hxx:123
bool Command(const CommandEvent &rCEvt)
Definition: seleng.cxx:367
Timer aWTimer
Definition: seleng.hxx:84
bool SelMouseMove(const MouseEvent &rMEvt)
Definition: seleng.cxx:312
bool ShouldDeselect(bool bModifierKey1) const
Definition: seleng.cxx:30
bool IsAddMode() const
Definition: seleng.hxx:174
void Reset()
Definition: seleng.cxx:358
bool SelMouseButtonDown(const MouseEvent &rMEvt)
Definition: seleng.cxx:115
VclPtr< vcl::Window > pWin
Definition: seleng.hxx:82
tools::Rectangle aArea
Definition: seleng.hxx:83
void SetWindow(vcl::Window *)
Definition: seleng.cxx:346
void ReleaseMouse()
Definition: seleng.cxx:298
sal_uInt16 nLockedMods
Definition: seleng.hxx:88
SelectionEngine(vcl::Window *pWindow, FunctionSet *pFunctions=nullptr)
Definition: seleng.cxx:37
SelectionEngineFlags nFlags
Definition: seleng.hxx:89
bool IsAlwaysAdding() const
Definition: seleng.hxx:206
FunctionSet * pFunctionSet
Definition: seleng.hxx:81
void SetSelectionMode(SelectionMode eMode)
Definition: seleng.cxx:62
void CursorPosChanging(bool bShift, bool bMod1)
Definition: seleng.cxx:67
void SetUpdateInterval(sal_uLong nInterval)
Definition: seleng.cxx:397
void CaptureMouse()
Definition: seleng.cxx:305
MouseEvent aLastMove
Definition: seleng.hxx:85
SelectionMode eSelMode
Definition: seleng.hxx:86
sal_uLong nUpdateInterval
Definition: seleng.hxx:87
bool SelMouseButtonUp(const MouseEvent &rMEvt)
Definition: seleng.cxx:246
bool IsActive() const
Definition: task.hxx:101
void Stop()
Definition: scheduler.cxx:590
Definition: timer.hxx:27
void SetTimeout(sal_uInt64 nTimeoutMs)
Definition: timer.cxx:90
void SetInvokeHandler(const Link< Timer *, void > &rLink)
Definition: timer.hxx:56
virtual void Start(bool bStartTimer=true) override
Schedules the task for execution.
Definition: timer.cxx:83
bool Contains(const Point &rPOINT) const
bool IsMouseCaptured() const
Definition: mouse.cxx:481
void ReleaseMouse()
Definition: mouse.cxx:469
void CaptureMouse()
Definition: mouse.cxx:451
Mode eMode
constexpr sal_uInt16 KEY_MOD2
Definition: keycodes.hxx:32
constexpr sal_uInt16 KEY_MOD1
Definition: keycodes.hxx:31
constexpr sal_uInt16 KEY_SHIFT
Definition: keycodes.hxx:30
#define SAL_WARN_IF(condition, area, stream)
IMPL_LINK_NOARG(SelectionEngine, ImpWatchDog, Timer *, void)
Definition: seleng.cxx:56
SelectionEngineFlags
Definition: seleng.hxx:63
#define SELENG_AUTOREPEAT_INTERVAL
Definition: seleng.hxx:37
#define SELENG_AUTOREPEAT_INTERVAL_MIN
Definition: seleng.hxx:38
sal_uIntPtr sal_uLong
SelectionMode
Definition: vclenum.hxx:26