1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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
) :
48 nUpdateInterval( nAutoRepeatInterval
)
50 eSelMode
= SINGLE_SELECTION
;
51 pFunctionSet
= pFuncSet
;
52 nFlags
= SELENG_EXPANDONMOVE
;
55 aWTimer
.SetTimeoutHdl( LINK( this, SelectionEngine
, ImpWatchDog
) );
56 aWTimer
.SetTimeout( nUpdateInterval
);
59 /*************************************************************************
61 |* SelectionEngine::~SelectionEngine()
63 *************************************************************************/
65 SelectionEngine::~SelectionEngine()
70 /*************************************************************************
72 |* SelectionEngine::ImpWatchDog()
74 *************************************************************************/
76 IMPL_LINK_NOARG(SelectionEngine
, ImpWatchDog
)
78 if ( !aArea
.IsInside( aLastMove
.GetPosPixel() ) )
79 SelMouseMove( aLastMove
);
83 /*************************************************************************
85 |* SelectionEngine::SetSelectionMode()
87 *************************************************************************/
89 void SelectionEngine::SetSelectionMode( SelectionMode eMode
)
94 /*************************************************************************
96 |* SelectionEngine::CursorPosChanging()
98 *************************************************************************/
100 void SelectionEngine::CursorPosChanging( sal_Bool bShift
, sal_Bool bMod1
)
105 if ( bShift
&& eSelMode
!= SINGLE_SELECTION
)
109 if ( !(nFlags
& SELENG_HAS_ANCH
) )
111 pFunctionSet
->CreateAnchor();
112 nFlags
|= SELENG_HAS_ANCH
;
117 if ( !(nFlags
& SELENG_HAS_ANCH
) )
119 if( ShouldDeselect( bMod1
) )
120 pFunctionSet
->DeselectAll();
121 pFunctionSet
->CreateAnchor();
122 nFlags
|= SELENG_HAS_ANCH
;
130 if ( nFlags
& SELENG_HAS_ANCH
)
132 // pFunctionSet->CreateCursor();
133 pFunctionSet
->DestroyAnchor();
134 nFlags
&= (~SELENG_HAS_ANCH
);
139 if( ShouldDeselect( bMod1
) )
140 pFunctionSet
->DeselectAll();
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() )
160 sal_uInt16 nModifier
= rMEvt
.GetModifier() | nLockedMods
;
161 if ( nModifier
& KEY_MOD2
)
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
)
168 Point aPos
= rMEvt
.GetPosPixel();
171 if( !rMEvt
.IsRight() )
173 pWin
->CaptureMouse();
174 nFlags
|= SELENG_IN_SEL
;
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
)
197 pFunctionSet
->DeselectAll();
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
;
211 if ( eSelMode
== SINGLE_SELECTION
)
213 pWin
->ReleaseMouse();
214 nFlags
&= (~SELENG_IN_SEL
);
217 if ( nFlags
& SELENG_ADD_ALW
)
218 nFlags
|= SELENG_IN_ADD
;
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
);
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
);
253 pFunctionSet
->SetCursorAtPoint( aPos
);
257 case KEY_SHIFT
+ KEY_MOD1
:
258 if ( eSelMode
!= MULTIPLE_SELECTION
)
260 pWin
->ReleaseMouse();
261 nFlags
&= (~SELENG_IN_SEL
);
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
);
277 /*************************************************************************
279 |* SelectionEngine::SelMouseButtonUp()
281 *************************************************************************/
283 sal_Bool
SelectionEngine::SelMouseButtonUp( const MouseEvent
& rMEvt
)
287 if( !pFunctionSet
|| !pWin
)
289 nFlags
&= ~(SELENG_CMDEVT
| SELENG_WAIT_UPEVT
| SELENG_IN_SEL
);
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
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
);
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
);
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
)) )
340 if( !(nFlags
& SELENG_EXPANDONMOVE
) )
341 return sal_False
; // auf DragEvent warten!
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() ))
349 aWTimer
.SetTimeout( nUpdateInterval
);
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() );
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();
380 if ( pWin
&& ( nFlags
& SELENG_IN_SEL
) )
381 pWin
->CaptureMouse();
385 /*************************************************************************
387 |* SelectionEngine::Reset()
389 *************************************************************************/
391 void SelectionEngine::Reset()
394 if ( nFlags
& SELENG_IN_SEL
)
395 pWin
->ReleaseMouse();
396 nFlags
&= ~(SELENG_HAS_ANCH
| SELENG_IN_SEL
);
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() )
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
);
427 nFlags
&= ~SELENG_CMDEVT
;
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
)
445 if (aWTimer
.IsActive())
447 // reset the timer right away on interval change.
449 aWTimer
.SetTimeout(nInterval
);
453 aWTimer
.SetTimeout(nInterval
);
455 nUpdateInterval
= nInterval
;
458 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */