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();
185 return false;
186 }
189 else
191
193 {
198 }
200 return true;
201
202 case KEY_MOD1:
203 // allow Control only for Multi-Select
205 {
207 ReleaseMouse();
208 return true; // skip Mouse-Click
209 }
211 {
212 // pFunctionSet->CreateCursor();
215 }
216 if ( pFunctionSet->IsSelectionAtPoint( aPos ) )
217 {
219 pFunctionSet->SetCursorAtPoint( aPos, true );
220 }
221 else
222 {
224 }
225 return true;
226
227 case KEY_SHIFT + KEY_MOD1:
229 {
230 ReleaseMouse();
232 return false;
233 }
234 nFlags |= SelectionEngineFlags::IN_ADD; //bIsInAddMode = true;
236 {
239 }
241 return true;
242 }
243
244 return false;
245}
246
248{
249 aWTimer.Stop();
250 if (!pFunctionSet)
251 {
253 nFlags &= ~nMask;
254 return false;
255 }
256
257 if (!rMEvt.IsRight())
258 ReleaseMouse();
259
260#if defined IOS || defined ANDROID
261 const bool bDoMessWithSelection = !rMEvt.IsRight();
262#else
263 constexpr bool bDoMessWithSelection = true;
264#endif
265
268 {
269 // MouseButtonDown in Sel but no CommandEvent yet
270 // ==> deselect
271 sal_uInt16 nModifier = aLastMove.GetModifier() | nLockedMods;
272 if( nModifier == KEY_MOD1 || IsAlwaysAdding() )
273 {
274 if( !(nModifier & KEY_SHIFT) )
275 {
277 nFlags &= ~SelectionEngineFlags::HAS_ANCH; // uncheck anchor
278 }
280 nFlags &= ~SelectionEngineFlags::HAS_ANCH; // uncheck anchor
281 if (bDoMessWithSelection)
283 }
284 else
285 {
286 if (bDoMessWithSelection)
288 nFlags &= ~SelectionEngineFlags::HAS_ANCH; // uncheck anchor
289 if (bDoMessWithSelection)
291 }
292 }
293
295 nFlags &= ~nMask;
296 return true;
297}
298
300{
301 if (!pWin || !pWin->IsMouseCaptured())
302 return;
304}
305
307{
308 if (!pWin || pWin->IsMouseCaptured())
309 return;
311}
312
314{
315
318 return false;
319
321 return false; // wait for DragEvent!
322
323 aLastMove = rMEvt;
324 // if the mouse is outside the area, the frequency of
325 // SetCursorAtPoint() is only set by the Timer
326 if( aWTimer.IsActive() && !aArea.Contains( rMEvt.GetPosPixel() ))
327 return true;
328
331 // Generating fake mouse moves does not work with LOK.
332 aWTimer.Start();
334 {
336 {
339 }
340 }
341
343
344 return true;
345}
346
348{
349 if( pNewWin != pWin )
350 {
352 ReleaseMouse();
353 pWin = pNewWin;
355 CaptureMouse();
356 }
357}
358
360{
361 aWTimer.Stop();
363 ReleaseMouse();
365 nLockedMods = 0;
366}
367
369{
370 // Timer aWTimer is active during enlarging a selection
371 if ( !pFunctionSet || aWTimer.IsActive() )
372 return false;
373 aWTimer.Stop();
374 if ( rCEvt.GetCommand() != CommandEventId::StartDrag )
375 return false;
376
379 {
380 SAL_WARN_IF( !rCEvt.IsMouseEvent(), "vcl", "STARTDRAG: Not a MouseEvent" );
382 {
388 nFlags &= ~nMask;
389 }
390 else
392 }
393 else
395 return true;
396}
397
399{
400 if (nInterval < SELENG_AUTOREPEAT_INTERVAL_MIN)
401 // Set a lower threshold. On Windows, setting this value too low
402 // would cause selection to get updated indefinitely.
404
405 if (nUpdateInterval == nInterval)
406 // no update needed.
407 return;
408
409 if (aWTimer.IsActive())
410 {
411 // reset the timer right away on interval change.
412 aWTimer.Stop();
413 aWTimer.SetTimeout(nInterval);
414 aWTimer.Start();
415 }
416 else
417 aWTimer.SetTimeout(nInterval);
418
419 nUpdateInterval = nInterval;
420}
421
422/* 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:368
Timer aWTimer
Definition: seleng.hxx:84
bool SelMouseMove(const MouseEvent &rMEvt)
Definition: seleng.cxx:313
bool ShouldDeselect(bool bModifierKey1) const
Definition: seleng.cxx:30
bool IsAddMode() const
Definition: seleng.hxx:174
void Reset()
Definition: seleng.cxx:359
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:347
void ReleaseMouse()
Definition: seleng.cxx:299
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:398
void CaptureMouse()
Definition: seleng.cxx:306
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:247
bool IsActive() const
Definition: task.hxx:101
void Stop()
Definition: scheduler.cxx:599
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