bump product version to 4.1.6.2
[LibreOffice.git] / vcl / source / window / seleng.cxx
blobf07ccaa203d6a1e188cb53b880b5ec06eee05d96
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 .
21 #include <vcl/window.hxx>
22 #include <vcl/seleng.hxx>
23 #include <tools/debug.hxx>
25 FunctionSet::~FunctionSet()
30 inline sal_Bool SelectionEngine::ShouldDeselect( sal_Bool bModifierKey1 ) const
32 // return !( eSelMode == MULTIPLE_SELECTION && bModifierKey1 );
33 return eSelMode != MULTIPLE_SELECTION || !bModifierKey1;
37 // TODO: FunctionSet::SelectAtPoint raus
39 /*************************************************************************
41 |* SelectionEngine::SelectionEngine()
43 *************************************************************************/
45 SelectionEngine::SelectionEngine( Window* pWindow, FunctionSet* pFuncSet,
46 sal_uLong nAutoRepeatInterval ) :
47 pWin( pWindow ),
48 nUpdateInterval( nAutoRepeatInterval )
50 eSelMode = SINGLE_SELECTION;
51 pFunctionSet = pFuncSet;
52 nFlags = SELENG_EXPANDONMOVE;
53 nLockedMods = 0;
55 aWTimer.SetTimeoutHdl( LINK( this, SelectionEngine, ImpWatchDog ) );
56 aWTimer.SetTimeout( nUpdateInterval );
59 /*************************************************************************
61 |* SelectionEngine::~SelectionEngine()
63 *************************************************************************/
65 SelectionEngine::~SelectionEngine()
67 aWTimer.Stop();
70 /*************************************************************************
72 |* SelectionEngine::ImpWatchDog()
74 *************************************************************************/
76 IMPL_LINK_NOARG(SelectionEngine, ImpWatchDog)
78 if ( !aArea.IsInside( aLastMove.GetPosPixel() ) )
79 SelMouseMove( aLastMove );
80 return 0;
83 /*************************************************************************
85 |* SelectionEngine::SetSelectionMode()
87 *************************************************************************/
89 void SelectionEngine::SetSelectionMode( SelectionMode eMode )
91 eSelMode = eMode;
94 /*************************************************************************
96 |* SelectionEngine::CursorPosChanging()
98 *************************************************************************/
100 void SelectionEngine::CursorPosChanging( sal_Bool bShift, sal_Bool bMod1 )
102 if ( !pFunctionSet )
103 return;
105 if ( bShift && eSelMode != SINGLE_SELECTION )
107 if ( IsAddMode() )
109 if ( !(nFlags & SELENG_HAS_ANCH) )
111 pFunctionSet->CreateAnchor();
112 nFlags |= SELENG_HAS_ANCH;
115 else
117 if ( !(nFlags & SELENG_HAS_ANCH) )
119 if( ShouldDeselect( bMod1 ) )
120 pFunctionSet->DeselectAll();
121 pFunctionSet->CreateAnchor();
122 nFlags |= SELENG_HAS_ANCH;
126 else
128 if ( IsAddMode() )
130 if ( nFlags & SELENG_HAS_ANCH )
132 // pFunctionSet->CreateCursor();
133 pFunctionSet->DestroyAnchor();
134 nFlags &= (~SELENG_HAS_ANCH);
137 else
139 if( ShouldDeselect( bMod1 ) )
140 pFunctionSet->DeselectAll();
141 else
142 pFunctionSet->DestroyAnchor();
143 nFlags &= (~SELENG_HAS_ANCH);
148 /*************************************************************************
150 |* SelectionEngine::SelMouseButtonDown()
152 *************************************************************************/
154 sal_Bool SelectionEngine::SelMouseButtonDown( const MouseEvent& rMEvt )
156 nFlags &= (~SELENG_CMDEVT);
157 if ( !pFunctionSet || !pWin || rMEvt.GetClicks() > 1 || rMEvt.IsRight() )
158 return sal_False;
160 sal_uInt16 nModifier = rMEvt.GetModifier() | nLockedMods;
161 if ( nModifier & KEY_MOD2 )
162 return sal_False;
163 // in SingleSelection: Control-Taste filtern (damit auch
164 // mit Ctrl-Click ein D&D gestartet werden kann)
165 if ( nModifier == KEY_MOD1 && eSelMode == SINGLE_SELECTION )
166 nModifier = 0;
168 Point aPos = rMEvt.GetPosPixel();
169 aLastMove = rMEvt;
171 if( !rMEvt.IsRight() )
173 pWin->CaptureMouse();
174 nFlags |= SELENG_IN_SEL;
176 else
178 nModifier = 0;
181 switch ( nModifier )
183 case 0: // KEY_NO_KEY
185 sal_Bool bSelAtPoint = pFunctionSet->IsSelectionAtPoint( aPos );
186 nFlags &= (~SELENG_IN_ADD);
187 if ( (nFlags & SELENG_DRG_ENAB) && bSelAtPoint )
189 nFlags |= SELENG_WAIT_UPEVT;
190 nFlags &= ~(SELENG_IN_SEL);
191 pWin->ReleaseMouse();
192 return sal_True; //auf STARTDRAG-Command-Event warten
194 if ( eSelMode != SINGLE_SELECTION )
196 if( !IsAddMode() )
197 pFunctionSet->DeselectAll();
198 else
199 pFunctionSet->DestroyAnchor();
200 nFlags &= (~SELENG_HAS_ANCH); // bHasAnchor = sal_False;
202 pFunctionSet->SetCursorAtPoint( aPos );
203 // Sonderbehandlung Single-Selection, damit Select+Drag
204 // in einem Zug moeglich ist
205 if (eSelMode == SINGLE_SELECTION && (nFlags & SELENG_DRG_ENAB))
206 nFlags |= SELENG_WAIT_UPEVT;
207 return sal_True;
210 case KEY_SHIFT:
211 if ( eSelMode == SINGLE_SELECTION )
213 pWin->ReleaseMouse();
214 nFlags &= (~SELENG_IN_SEL);
215 return sal_False;
217 if ( nFlags & SELENG_ADD_ALW )
218 nFlags |= SELENG_IN_ADD;
219 else
220 nFlags &= (~SELENG_IN_ADD);
222 if( !(nFlags & SELENG_HAS_ANCH) )
224 if ( !(nFlags & SELENG_IN_ADD) )
225 pFunctionSet->DeselectAll();
226 pFunctionSet->CreateAnchor();
227 nFlags |= SELENG_HAS_ANCH;
229 pFunctionSet->SetCursorAtPoint( aPos );
230 return sal_True;
232 case KEY_MOD1:
233 // Control nur bei Mehrfachselektion erlaubt
234 if ( eSelMode != MULTIPLE_SELECTION )
236 nFlags &= (~SELENG_IN_SEL);
237 pWin->ReleaseMouse();
238 return sal_True; // Mausclick verschlucken
240 if ( nFlags & SELENG_HAS_ANCH )
242 // pFunctionSet->CreateCursor();
243 pFunctionSet->DestroyAnchor();
244 nFlags &= (~SELENG_HAS_ANCH);
246 if ( pFunctionSet->IsSelectionAtPoint( aPos ) )
248 pFunctionSet->DeselectAtPoint( aPos );
249 pFunctionSet->SetCursorAtPoint( aPos, sal_True );
251 else
253 pFunctionSet->SetCursorAtPoint( aPos );
255 return sal_True;
257 case KEY_SHIFT + KEY_MOD1:
258 if ( eSelMode != MULTIPLE_SELECTION )
260 pWin->ReleaseMouse();
261 nFlags &= (~SELENG_IN_SEL);
262 return sal_False;
264 nFlags |= SELENG_IN_ADD; //bIsInAddMode = sal_True;
265 if ( !(nFlags & SELENG_HAS_ANCH) )
267 pFunctionSet->CreateAnchor();
268 nFlags |= SELENG_HAS_ANCH;
270 pFunctionSet->SetCursorAtPoint( aPos );
271 return sal_True;
274 return sal_False;
277 /*************************************************************************
279 |* SelectionEngine::SelMouseButtonUp()
281 *************************************************************************/
283 sal_Bool SelectionEngine::SelMouseButtonUp( const MouseEvent& rMEvt )
285 aWTimer.Stop();
286 //DbgOut("Up");
287 if( !pFunctionSet || !pWin )
289 nFlags &= ~(SELENG_CMDEVT | SELENG_WAIT_UPEVT | SELENG_IN_SEL);
290 return sal_False;
293 if( !rMEvt.IsRight() )
295 pWin->ReleaseMouse();
298 if( (nFlags & SELENG_WAIT_UPEVT) && !(nFlags & SELENG_CMDEVT) &&
299 eSelMode != SINGLE_SELECTION)
301 // MouseButtonDown in Sel aber kein CommandEvent eingetrudelt
302 // ==> deselektieren
303 sal_uInt16 nModifier = aLastMove.GetModifier() | nLockedMods;
304 if( nModifier == KEY_MOD1 || IsAlwaysAdding() )
306 if( !(nModifier & KEY_SHIFT) )
308 pFunctionSet->DestroyAnchor();
309 nFlags &= (~SELENG_HAS_ANCH); // nix Anker
311 pFunctionSet->DeselectAtPoint( aLastMove.GetPosPixel() );
312 nFlags &= (~SELENG_HAS_ANCH); // nix Anker
313 pFunctionSet->SetCursorAtPoint( aLastMove.GetPosPixel(), sal_True );
315 else
317 pFunctionSet->DeselectAll();
318 nFlags &= (~SELENG_HAS_ANCH); // nix Anker
319 pFunctionSet->SetCursorAtPoint( aLastMove.GetPosPixel() );
323 nFlags &= ~(SELENG_CMDEVT | SELENG_WAIT_UPEVT | SELENG_IN_SEL);
324 return sal_True;
327 /*************************************************************************
329 |* SelectionEngine::SelMouseMove()
331 *************************************************************************/
333 sal_Bool SelectionEngine::SelMouseMove( const MouseEvent& rMEvt )
336 if ( !pFunctionSet || !(nFlags & SELENG_IN_SEL) ||
337 (nFlags & (SELENG_CMDEVT | SELENG_WAIT_UPEVT)) )
338 return sal_False;
340 if( !(nFlags & SELENG_EXPANDONMOVE) )
341 return sal_False; // auf DragEvent warten!
343 aLastMove = rMEvt;
344 // wenn die Maus ausserhalb der Area steht, dann wird die
345 // Frequenz des SetCursorAtPoint() nur durch den Timer bestimmt
346 if( aWTimer.IsActive() && !aArea.IsInside( rMEvt.GetPosPixel() ))
347 return sal_True;
349 aWTimer.SetTimeout( nUpdateInterval );
350 aWTimer.Start();
351 if ( eSelMode != SINGLE_SELECTION )
353 if ( !(nFlags & SELENG_HAS_ANCH) )
355 pFunctionSet->CreateAnchor();
356 //DbgOut("Move:Creating anchor");
357 nFlags |= SELENG_HAS_ANCH;
361 //DbgOut("Move:SetCursor");
362 pFunctionSet->SetCursorAtPoint( rMEvt.GetPosPixel() );
364 return sal_True;
367 /*************************************************************************
369 |* SelectionEngine::SetWindow()
371 *************************************************************************/
373 void SelectionEngine::SetWindow( Window* pNewWin )
375 if( pNewWin != pWin )
377 if ( pWin && (nFlags & SELENG_IN_SEL) )
378 pWin->ReleaseMouse();
379 pWin = pNewWin;
380 if ( pWin && ( nFlags & SELENG_IN_SEL ) )
381 pWin->CaptureMouse();
385 /*************************************************************************
387 |* SelectionEngine::Reset()
389 *************************************************************************/
391 void SelectionEngine::Reset()
393 aWTimer.Stop();
394 if ( nFlags & SELENG_IN_SEL )
395 pWin->ReleaseMouse();
396 nFlags &= ~(SELENG_HAS_ANCH | SELENG_IN_SEL);
397 nLockedMods = 0;
400 /*************************************************************************
402 |* SelectionEngine::Command()
404 *************************************************************************/
406 void SelectionEngine::Command( const CommandEvent& rCEvt )
408 // Timer aWTimer ist beim Aufspannen einer Selektion aktiv
409 if ( !pFunctionSet || !pWin || aWTimer.IsActive() )
410 return;
411 aWTimer.Stop();
412 nFlags |= SELENG_CMDEVT;
413 if ( rCEvt.GetCommand() == COMMAND_STARTDRAG )
415 if ( nFlags & SELENG_DRG_ENAB )
417 DBG_ASSERT( rCEvt.IsMouseEvent(), "STARTDRAG: Not a MouseEvent" );
418 if ( pFunctionSet->IsSelectionAtPoint( rCEvt.GetMousePosPixel() ) )
420 aLastMove = MouseEvent( rCEvt.GetMousePosPixel(),
421 aLastMove.GetClicks(), aLastMove.GetMode(),
422 aLastMove.GetButtons(), aLastMove.GetModifier() );
423 pFunctionSet->BeginDrag();
424 nFlags &= ~(SELENG_CMDEVT|SELENG_WAIT_UPEVT|SELENG_IN_SEL);
426 else
427 nFlags &= ~SELENG_CMDEVT;
429 else
430 nFlags &= ~SELENG_CMDEVT;
434 void SelectionEngine::SetUpdateInterval( sal_uLong nInterval )
436 if (nInterval < SELENG_AUTOREPEAT_INTERVAL_MIN)
437 // Set a lower threshold. On Windows, setting this value too low
438 // would cause selection to get updated indefinitely.
439 nInterval = SELENG_AUTOREPEAT_INTERVAL_MIN;
441 if (nUpdateInterval == nInterval)
442 // no update needed.
443 return;
445 if (aWTimer.IsActive())
447 // reset the timer right away on interval change.
448 aWTimer.Stop();
449 aWTimer.SetTimeout(nInterval);
450 aWTimer.Start();
452 else
453 aWTimer.SetTimeout(nInterval);
455 nUpdateInterval = nInterval;
458 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */