nss: upgrade to release 3.73
[LibreOffice.git] / vcl / source / window / seleng.cxx
blobf4eaeef726cc74b1b46edd2d6c38fb1c132a2807
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
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>
26 FunctionSet::~FunctionSet()
30 inline bool SelectionEngine::ShouldDeselect( bool bModifierKey1 ) const
32 return eSelMode != SelectionMode::Multiple || !bModifierKey1;
35 // TODO: throw out FunctionSet::SelectAtPoint
37 SelectionEngine::SelectionEngine( vcl::Window* pWindow, FunctionSet* pFuncSet ) :
38 pWin( pWindow ),
39 nUpdateInterval( SELENG_AUTOREPEAT_INTERVAL )
41 eSelMode = SelectionMode::Single;
42 pFunctionSet = pFuncSet;
43 nFlags = SelectionEngineFlags::EXPANDONMOVE;
44 nLockedMods = 0;
46 aWTimer.SetInvokeHandler( LINK( this, SelectionEngine, ImpWatchDog ) );
47 aWTimer.SetTimeout( nUpdateInterval );
48 aWTimer.SetDebugName( "vcl::SelectionEngine aWTimer" );
51 SelectionEngine::~SelectionEngine()
53 aWTimer.Stop();
56 IMPL_LINK_NOARG(SelectionEngine, ImpWatchDog, Timer *, void)
58 if ( !aArea.IsInside( aLastMove.GetPosPixel() ) )
59 SelMouseMove( aLastMove );
62 void SelectionEngine::SetSelectionMode( SelectionMode eMode )
64 eSelMode = eMode;
67 void SelectionEngine::CursorPosChanging( bool bShift, bool bMod1 )
69 if ( !pFunctionSet )
70 return;
72 if ( bShift && eSelMode != SelectionMode::Single )
74 if ( IsAddMode() )
76 if ( !(nFlags & SelectionEngineFlags::HAS_ANCH) )
78 pFunctionSet->CreateAnchor();
79 nFlags |= SelectionEngineFlags::HAS_ANCH;
82 else
84 if ( !(nFlags & SelectionEngineFlags::HAS_ANCH) )
86 if( ShouldDeselect( bMod1 ) )
87 pFunctionSet->DeselectAll();
88 pFunctionSet->CreateAnchor();
89 nFlags |= SelectionEngineFlags::HAS_ANCH;
93 else
95 if ( IsAddMode() )
97 if ( nFlags & SelectionEngineFlags::HAS_ANCH )
99 // pFunctionSet->CreateCursor();
100 pFunctionSet->DestroyAnchor();
101 nFlags &= ~SelectionEngineFlags::HAS_ANCH;
104 else
106 if( ShouldDeselect( bMod1 ) )
107 pFunctionSet->DeselectAll();
108 else
109 pFunctionSet->DestroyAnchor();
110 nFlags &= ~SelectionEngineFlags::HAS_ANCH;
115 bool SelectionEngine::SelMouseButtonDown( const MouseEvent& rMEvt )
117 nFlags &= ~SelectionEngineFlags::CMDEVT;
118 if ( !pFunctionSet || rMEvt.GetClicks() > 1 )
119 return false;
121 sal_uInt16 nModifier = rMEvt.GetModifier() | nLockedMods;
122 bool nSwap = comphelper::LibreOfficeKit::isActive() && (nModifier & KEY_MOD1) && (nModifier & KEY_MOD2);
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;
131 Point aPos = rMEvt.GetPosPixel();
132 aLastMove = rMEvt;
134 if( !rMEvt.IsRight() )
136 CaptureMouse();
137 nFlags |= SelectionEngineFlags::IN_SEL;
139 else
141 nModifier = 0;
144 if (nSwap)
146 pFunctionSet->CreateAnchor();
147 pFunctionSet->SetCursorAtPoint( aPos );
148 return true;
151 switch ( nModifier )
153 case 0: // KEY_NO_KEY
155 bool bSelAtPoint = pFunctionSet->IsSelectionAtPoint( aPos );
156 nFlags &= ~SelectionEngineFlags::IN_ADD;
157 if ( (nFlags & SelectionEngineFlags::DRG_ENAB) && bSelAtPoint )
159 nFlags |= SelectionEngineFlags::WAIT_UPEVT;
160 nFlags &= ~SelectionEngineFlags::IN_SEL;
161 ReleaseMouse();
162 return true; // wait for STARTDRAG-Command-Event
164 if ( eSelMode != SelectionMode::Single )
166 if( !IsAddMode() )
167 pFunctionSet->DeselectAll();
168 else
169 pFunctionSet->DestroyAnchor();
170 nFlags &= ~SelectionEngineFlags::HAS_ANCH; // bHasAnchor = false;
172 pFunctionSet->SetCursorAtPoint( aPos );
173 // special case Single-Selection, to enable simple Select+Drag
174 if (eSelMode == SelectionMode::Single && (nFlags & SelectionEngineFlags::DRG_ENAB))
175 nFlags |= SelectionEngineFlags::WAIT_UPEVT;
176 return true;
179 case KEY_SHIFT:
180 if ( eSelMode == SelectionMode::Single )
182 ReleaseMouse();
183 nFlags &= ~SelectionEngineFlags::IN_SEL;
184 return false;
186 if ( nFlags & SelectionEngineFlags::ADD_ALW )
187 nFlags |= SelectionEngineFlags::IN_ADD;
188 else
189 nFlags &= ~SelectionEngineFlags::IN_ADD;
191 if( !(nFlags & SelectionEngineFlags::HAS_ANCH) )
193 if ( !(nFlags & SelectionEngineFlags::IN_ADD) )
194 pFunctionSet->DeselectAll();
195 pFunctionSet->CreateAnchor();
196 nFlags |= SelectionEngineFlags::HAS_ANCH;
198 pFunctionSet->SetCursorAtPoint( aPos );
199 return true;
201 case KEY_MOD1:
202 // allow Control only for Multi-Select
203 if ( eSelMode != SelectionMode::Multiple )
205 nFlags &= ~SelectionEngineFlags::IN_SEL;
206 ReleaseMouse();
207 return true; // skip Mouse-Click
209 if ( nFlags & SelectionEngineFlags::HAS_ANCH )
211 // pFunctionSet->CreateCursor();
212 pFunctionSet->DestroyAnchor();
213 nFlags &= ~SelectionEngineFlags::HAS_ANCH;
215 if ( pFunctionSet->IsSelectionAtPoint( aPos ) )
217 pFunctionSet->DeselectAtPoint( aPos );
218 pFunctionSet->SetCursorAtPoint( aPos, true );
220 else
222 pFunctionSet->SetCursorAtPoint( aPos );
224 return true;
226 case KEY_SHIFT + KEY_MOD1:
227 if ( eSelMode != SelectionMode::Multiple )
229 ReleaseMouse();
230 nFlags &= ~SelectionEngineFlags::IN_SEL;
231 return false;
233 nFlags |= SelectionEngineFlags::IN_ADD; //bIsInAddMode = true;
234 if ( !(nFlags & SelectionEngineFlags::HAS_ANCH) )
236 pFunctionSet->CreateAnchor();
237 nFlags |= SelectionEngineFlags::HAS_ANCH;
239 pFunctionSet->SetCursorAtPoint( aPos );
240 return true;
243 return false;
246 bool SelectionEngine::SelMouseButtonUp( const MouseEvent& rMEvt )
248 aWTimer.Stop();
249 if (!pFunctionSet)
251 const SelectionEngineFlags nMask = SelectionEngineFlags::CMDEVT | SelectionEngineFlags::WAIT_UPEVT | SelectionEngineFlags::IN_SEL;
252 nFlags &= ~nMask;
253 return false;
256 if (!rMEvt.IsRight())
257 ReleaseMouse();
259 if( (nFlags & SelectionEngineFlags::WAIT_UPEVT) && !(nFlags & SelectionEngineFlags::CMDEVT) &&
260 eSelMode != SelectionMode::Single)
262 // MouseButtonDown in Sel but no CommandEvent yet
263 // ==> deselect
264 sal_uInt16 nModifier = aLastMove.GetModifier() | nLockedMods;
265 if( nModifier == KEY_MOD1 || IsAlwaysAdding() )
267 if( !(nModifier & KEY_SHIFT) )
269 pFunctionSet->DestroyAnchor();
270 nFlags &= ~SelectionEngineFlags::HAS_ANCH; // uncheck anchor
272 pFunctionSet->DeselectAtPoint( aLastMove.GetPosPixel() );
273 nFlags &= ~SelectionEngineFlags::HAS_ANCH; // uncheck anchor
274 pFunctionSet->SetCursorAtPoint( aLastMove.GetPosPixel(), true );
276 else
278 pFunctionSet->DeselectAll();
279 nFlags &= ~SelectionEngineFlags::HAS_ANCH; // uncheck anchor
280 pFunctionSet->SetCursorAtPoint( aLastMove.GetPosPixel() );
284 const SelectionEngineFlags nMask = SelectionEngineFlags::CMDEVT | SelectionEngineFlags::WAIT_UPEVT | SelectionEngineFlags::IN_SEL;
285 nFlags &= ~nMask;
286 return true;
289 void SelectionEngine::ReleaseMouse()
291 if (!pWin || !pWin->IsMouseCaptured())
292 return;
293 pWin->ReleaseMouse();
296 void SelectionEngine::CaptureMouse()
298 if (!pWin || pWin->IsMouseCaptured())
299 return;
300 pWin->CaptureMouse();
303 bool SelectionEngine::SelMouseMove( const MouseEvent& rMEvt )
306 if ( !pFunctionSet || !(nFlags & SelectionEngineFlags::IN_SEL) ||
307 (nFlags & (SelectionEngineFlags::CMDEVT | SelectionEngineFlags::WAIT_UPEVT)) )
308 return false;
310 if( !(nFlags & SelectionEngineFlags::EXPANDONMOVE) )
311 return false; // wait for DragEvent!
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;
319 aWTimer.SetTimeout( nUpdateInterval );
320 if (!comphelper::LibreOfficeKit::isActive())
321 // Generating fake mouse moves does not work with LOK.
322 aWTimer.Start();
323 if ( eSelMode != SelectionMode::Single )
325 if ( !(nFlags & SelectionEngineFlags::HAS_ANCH) )
327 pFunctionSet->CreateAnchor();
328 nFlags |= SelectionEngineFlags::HAS_ANCH;
332 pFunctionSet->SetCursorAtPoint( rMEvt.GetPosPixel() );
334 return true;
337 void SelectionEngine::SetWindow( vcl::Window* pNewWin )
339 if( pNewWin != pWin )
341 if (nFlags & SelectionEngineFlags::IN_SEL)
342 ReleaseMouse();
343 pWin = pNewWin;
344 if (nFlags & SelectionEngineFlags::IN_SEL)
345 CaptureMouse();
349 void SelectionEngine::Reset()
351 aWTimer.Stop();
352 if (nFlags & SelectionEngineFlags::IN_SEL)
353 ReleaseMouse();
354 nFlags &= ~SelectionEngineFlags(SelectionEngineFlags::HAS_ANCH | SelectionEngineFlags::IN_SEL);
355 nLockedMods = 0;
358 void SelectionEngine::Command( const CommandEvent& rCEvt )
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 return;
367 nFlags |= SelectionEngineFlags::CMDEVT;
368 if ( nFlags & SelectionEngineFlags::DRG_ENAB )
370 SAL_WARN_IF( !rCEvt.IsMouseEvent(), "vcl", "STARTDRAG: Not a MouseEvent" );
371 if ( pFunctionSet->IsSelectionAtPoint( rCEvt.GetMousePosPixel() ) )
373 aLastMove = MouseEvent( rCEvt.GetMousePosPixel(),
374 aLastMove.GetClicks(), aLastMove.GetMode(),
375 aLastMove.GetButtons(), aLastMove.GetModifier() );
376 pFunctionSet->BeginDrag();
377 const SelectionEngineFlags nMask = SelectionEngineFlags::CMDEVT|SelectionEngineFlags::WAIT_UPEVT|SelectionEngineFlags::IN_SEL;
378 nFlags &= ~nMask;
380 else
381 nFlags &= ~SelectionEngineFlags::CMDEVT;
383 else
384 nFlags &= ~SelectionEngineFlags::CMDEVT;
387 void SelectionEngine::SetUpdateInterval( sal_uLong nInterval )
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;
394 if (nUpdateInterval == nInterval)
395 // no update needed.
396 return;
398 if (aWTimer.IsActive())
400 // reset the timer right away on interval change.
401 aWTimer.Stop();
402 aWTimer.SetTimeout(nInterval);
403 aWTimer.Start();
405 else
406 aWTimer.SetTimeout(nInterval);
408 nUpdateInterval = nInterval;
411 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */