xref: /trunk/main/vcl/source/window/seleng.cxx (revision 9f62ea84)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_vcl.hxx"
26 
27 #include <tools/ref.hxx>
28 #include <vcl/window.hxx>
29 #include <vcl/seleng.hxx>
30 #include <tools/debug.hxx>
31 
32 
33 
34 
ShouldDeselect(sal_Bool bModifierKey1) const35 inline sal_Bool SelectionEngine::ShouldDeselect( sal_Bool bModifierKey1 ) const
36 {
37 //	return !( eSelMode == MULTIPLE_SELECTION && bModifierKey1 );
38 	return eSelMode != MULTIPLE_SELECTION || !bModifierKey1;
39 }
40 
41 
42 // TODO: FunctionSet::SelectAtPoint raus
43 
44 /*************************************************************************
45 |*
46 |*    SelectionEngine::SelectionEngine()
47 |*
48 |*    Beschreibung      SELENG.SDW
49 |*    Ersterstellung    OV 10.10.94
50 |*    Letzte Aenderung  OV 10.10.94
51 |*
52 *************************************************************************/
53 
SelectionEngine(Window * pWindow,FunctionSet * pFuncSet)54 SelectionEngine::SelectionEngine( Window* pWindow, FunctionSet* pFuncSet ) :
55                     pWin( pWindow )
56 {
57     eSelMode = SINGLE_SELECTION;
58     pFunctionSet = pFuncSet;
59     nFlags = SELENG_EXPANDONMOVE;
60     nLockedMods = 0;
61 
62     aWTimer.SetTimeoutHdl( LINK( this, SelectionEngine, ImpWatchDog ) );
63     aWTimer.SetTimeout( SELENG_AUTOREPEAT_INTERVAL );
64 }
65 
66 /*************************************************************************
67 |*
68 |*    SelectionEngine::~SelectionEngine()
69 |*
70 |*    Beschreibung      SELENG.SDW
71 |*    Ersterstellung    OV 10.10.94
72 |*    Letzte Aenderung  OV 10.10.94
73 |*
74 *************************************************************************/
75 
~SelectionEngine()76 SelectionEngine::~SelectionEngine()
77 {
78     aWTimer.Stop();
79 }
80 
81 /*************************************************************************
82 |*
83 |*    SelectionEngine::ImpWatchDog()
84 |*
85 |*    Beschreibung      SELENG.SDW
86 |*    Ersterstellung    OV 10.10.94
87 |*    Letzte Aenderung  OV 10.10.94
88 |*
89 *************************************************************************/
90 
IMPL_LINK(SelectionEngine,ImpWatchDog,Timer *,EMPTYARG)91 IMPL_LINK( SelectionEngine, ImpWatchDog, Timer*, EMPTYARG )
92 {
93     if ( !aArea.IsInside( aLastMove.GetPosPixel() ) )
94         SelMouseMove( aLastMove );
95     return 0;
96 }
97 
98 /*************************************************************************
99 |*
100 |*    SelectionEngine::SetSelectionMode()
101 |*
102 |*    Beschreibung      SELENG.SDW
103 |*    Ersterstellung    OV 10.10.94
104 |*    Letzte Aenderung  OV 10.10.94
105 |*
106 *************************************************************************/
107 
SetSelectionMode(SelectionMode eMode)108 void SelectionEngine::SetSelectionMode( SelectionMode eMode )
109 {
110     eSelMode = eMode;
111 }
112 
113 /*************************************************************************
114 |*
115 |*    SelectionEngine::ActivateDragMode()
116 |*
117 |*    Beschreibung      SELENG.SDW
118 |*    Ersterstellung    OV 10.10.94
119 |*    Letzte Aenderung  OV 10.10.94
120 |*
121 *************************************************************************/
122 
ActivateDragMode()123 void SelectionEngine::ActivateDragMode()
124 {
125     DBG_ERRORFILE( "SelectionEngine::ActivateDragMode not implemented" );
126 }
127 
128 /*************************************************************************
129 |*
130 |*    SelectionEngine::CursorPosChanging()
131 |*
132 |*    Beschreibung      SELENG.SDW
133 |*    Ersterstellung    OV 10.10.94
134 |*    Letzte Aenderung  GT 2002-04-04
135 |*
136 *************************************************************************/
137 
CursorPosChanging(sal_Bool bShift,sal_Bool bMod1)138 void SelectionEngine::CursorPosChanging( sal_Bool bShift, sal_Bool bMod1 )
139 {
140     if ( !pFunctionSet )
141         return;
142 
143     if ( bShift && eSelMode != SINGLE_SELECTION )
144     {
145         if ( IsAddMode() )
146         {
147             if ( !(nFlags & SELENG_HAS_ANCH) )
148             {
149                 pFunctionSet->CreateAnchor();
150                 nFlags |= SELENG_HAS_ANCH;
151             }
152         }
153         else
154         {
155             if ( !(nFlags & SELENG_HAS_ANCH) )
156             {
157                 if( ShouldDeselect( bMod1 ) )
158                     pFunctionSet->DeselectAll();
159                 pFunctionSet->CreateAnchor();
160                 nFlags |= SELENG_HAS_ANCH;
161             }
162         }
163     }
164     else
165     {
166         if ( IsAddMode() )
167         {
168             if ( nFlags & SELENG_HAS_ANCH )
169             {
170                 // pFunctionSet->CreateCursor();
171 				pFunctionSet->DestroyAnchor();
172                 nFlags &= (~SELENG_HAS_ANCH);
173             }
174         }
175         else
176         {
177             if( ShouldDeselect( bMod1 ) )
178                 pFunctionSet->DeselectAll();
179 			else
180 				pFunctionSet->DestroyAnchor();
181             nFlags &= (~SELENG_HAS_ANCH);
182         }
183     }
184 }
185 
186 /*************************************************************************
187 |*
188 |*    SelectionEngine::SelMouseButtonDown()
189 |*
190 |*    Beschreibung      SELENG.SDW
191 |*    Ersterstellung    OV 10.10.94
192 |*    Letzte Aenderung  OV 07.06.95
193 |*
194 *************************************************************************/
195 
SelMouseButtonDown(const MouseEvent & rMEvt)196 sal_Bool SelectionEngine::SelMouseButtonDown( const MouseEvent& rMEvt )
197 {
198     nFlags &= (~SELENG_CMDEVT);
199     if ( !pFunctionSet || !pWin || rMEvt.GetClicks() > 1 || rMEvt.IsRight() )
200         return sal_False;
201 
202     sal_uInt16 nModifier = rMEvt.GetModifier() | nLockedMods;
203     if ( nModifier & KEY_MOD2 )
204         return sal_False;
205     // in SingleSelection: Control-Taste filtern (damit auch
206     // mit Ctrl-Click ein D&D gestartet werden kann)
207     if ( nModifier == KEY_MOD1 && eSelMode == SINGLE_SELECTION )
208         nModifier = 0;
209 
210     Point aPos = rMEvt.GetPosPixel();
211     aLastMove = rMEvt;
212 
213 	if( !rMEvt.IsRight() )
214 	{
215 	    pWin->CaptureMouse();
216 		nFlags |= SELENG_IN_SEL;
217 	}
218 	else
219 	{
220 		nModifier = 0;
221 	}
222 
223     switch ( nModifier )
224     {
225         case 0:     // KEY_NO_KEY
226         {
227             sal_Bool bSelAtPoint = pFunctionSet->IsSelectionAtPoint( aPos );
228             nFlags &= (~SELENG_IN_ADD);
229             if ( (nFlags & SELENG_DRG_ENAB) && bSelAtPoint )
230             {
231                 nFlags |= SELENG_WAIT_UPEVT;
232                 nFlags &= ~(SELENG_IN_SEL);
233                 pWin->ReleaseMouse();
234                 return sal_True;  //auf STARTDRAG-Command-Event warten
235             }
236             if ( eSelMode != SINGLE_SELECTION )
237 			{
238 				if( !IsAddMode() )
239 	                pFunctionSet->DeselectAll();
240 				else
241 					pFunctionSet->DestroyAnchor();
242                	nFlags &= (~SELENG_HAS_ANCH); // bHasAnchor = sal_False;
243 			}
244             pFunctionSet->SetCursorAtPoint( aPos );
245             // Sonderbehandlung Single-Selection, damit Select+Drag
246             // in einem Zug moeglich ist
247             if (eSelMode == SINGLE_SELECTION && (nFlags & SELENG_DRG_ENAB))
248                 nFlags |= SELENG_WAIT_UPEVT;
249             return sal_True;
250         }
251 
252         case KEY_SHIFT:
253             if ( eSelMode == SINGLE_SELECTION )
254             {
255                 pWin->ReleaseMouse();
256                 nFlags &= (~SELENG_IN_SEL);
257                 return sal_False;
258             }
259             if ( nFlags & SELENG_ADD_ALW )
260                 nFlags |= SELENG_IN_ADD;
261             else
262                 nFlags &= (~SELENG_IN_ADD);
263 
264             if( !(nFlags & SELENG_HAS_ANCH) )
265             {
266                 if ( !(nFlags & SELENG_IN_ADD) )
267                     pFunctionSet->DeselectAll();
268                 pFunctionSet->CreateAnchor();
269                 nFlags |= SELENG_HAS_ANCH;
270             }
271             pFunctionSet->SetCursorAtPoint( aPos );
272             return sal_True;
273 
274         case KEY_MOD1:
275             // Control nur bei Mehrfachselektion erlaubt
276             if ( eSelMode != MULTIPLE_SELECTION )
277             {
278                 nFlags &= (~SELENG_IN_SEL);
279                 pWin->ReleaseMouse();
280                 return sal_True;  // Mausclick verschlucken
281             }
282             if ( nFlags & SELENG_HAS_ANCH )
283             {
284                 // pFunctionSet->CreateCursor();
285 				pFunctionSet->DestroyAnchor();
286                 nFlags &= (~SELENG_HAS_ANCH);
287             }
288             if ( pFunctionSet->IsSelectionAtPoint( aPos ) )
289             {
290                 pFunctionSet->DeselectAtPoint( aPos );
291                 pFunctionSet->SetCursorAtPoint( aPos, sal_True );
292             }
293             else
294             {
295                 pFunctionSet->SetCursorAtPoint( aPos );
296             }
297             return sal_True;
298 
299         case KEY_SHIFT + KEY_MOD1:
300             if ( eSelMode != MULTIPLE_SELECTION )
301             {
302                 pWin->ReleaseMouse();
303                 nFlags &= (~SELENG_IN_SEL);
304                 return sal_False;
305             }
306             nFlags |= SELENG_IN_ADD; //bIsInAddMode = sal_True;
307             if ( !(nFlags & SELENG_HAS_ANCH) )
308             {
309                 pFunctionSet->CreateAnchor();
310                 nFlags |= SELENG_HAS_ANCH;
311             }
312             pFunctionSet->SetCursorAtPoint( aPos );
313             return sal_True;
314     }
315 
316     return sal_False;
317 }
318 
319 /*************************************************************************
320 |*
321 |*    SelectionEngine::SelMouseButtonUp()
322 |*
323 |*    Beschreibung      SELENG.SDW
324 |*    Ersterstellung    OV 10.10.94
325 |*    Letzte Aenderung  OV 10.10.94
326 |*
327 *************************************************************************/
328 
SelMouseButtonUp(const MouseEvent & rMEvt)329 sal_Bool SelectionEngine::SelMouseButtonUp( const MouseEvent& rMEvt )
330 {
331     aWTimer.Stop();
332     //DbgOut("Up");
333     if( !pFunctionSet || !pWin )
334     {
335         nFlags &= ~(SELENG_CMDEVT | SELENG_WAIT_UPEVT | SELENG_IN_SEL);
336         return sal_False;
337     }
338 
339 	if( !rMEvt.IsRight() )
340 	{
341 	   pWin->ReleaseMouse();
342 	}
343 
344     if( (nFlags & SELENG_WAIT_UPEVT) && !(nFlags & SELENG_CMDEVT) &&
345         eSelMode != SINGLE_SELECTION)
346     {
347         // MouseButtonDown in Sel aber kein CommandEvent eingetrudelt
348         // ==> deselektieren
349         sal_uInt16 nModifier = aLastMove.GetModifier() | nLockedMods;
350         if( nModifier == KEY_MOD1 || IsAlwaysAdding() )
351 		{
352 			if( !(nModifier & KEY_SHIFT) )
353 			{
354 				pFunctionSet->DestroyAnchor();
355 		        nFlags &= (~SELENG_HAS_ANCH); // nix Anker
356 			}
357 			pFunctionSet->DeselectAtPoint( aLastMove.GetPosPixel() );
358         	nFlags &= (~SELENG_HAS_ANCH); // nix Anker
359 	        pFunctionSet->SetCursorAtPoint( aLastMove.GetPosPixel(), sal_True );
360 		}
361 		else
362 		{
363             pFunctionSet->DeselectAll();
364 	        nFlags &= (~SELENG_HAS_ANCH); // nix Anker
365         	pFunctionSet->SetCursorAtPoint( aLastMove.GetPosPixel() );
366 		}
367     }
368 
369     nFlags &= ~(SELENG_CMDEVT | SELENG_WAIT_UPEVT | SELENG_IN_SEL);
370     return sal_True;
371 }
372 
373 /*************************************************************************
374 |*
375 |*    SelectionEngine::SelMouseMove()
376 |*
377 |*    Beschreibung      SELENG.SDW
378 |*    Ersterstellung    OV 10.10.94
379 |*    Letzte Aenderung  OV 10.10.94
380 |*
381 *************************************************************************/
382 
SelMouseMove(const MouseEvent & rMEvt)383 sal_Bool SelectionEngine::SelMouseMove( const MouseEvent& rMEvt )
384 {
385 
386     if ( !pFunctionSet || !(nFlags & SELENG_IN_SEL) ||
387          (nFlags & (SELENG_CMDEVT | SELENG_WAIT_UPEVT)) )
388         return sal_False;
389 
390 	if( !(nFlags & SELENG_EXPANDONMOVE) )
391 		return sal_False; // auf DragEvent warten!
392 
393     aLastMove = rMEvt;
394     // wenn die Maus ausserhalb der Area steht, dann wird die
395     // Frequenz des SetCursorAtPoint() nur durch den Timer bestimmt
396     if( aWTimer.IsActive() && !aArea.IsInside( rMEvt.GetPosPixel() ))
397         return sal_True;
398 
399 
400     aWTimer.Start();
401     if ( eSelMode != SINGLE_SELECTION )
402     {
403         if ( !(nFlags & SELENG_HAS_ANCH) )
404         {
405             pFunctionSet->CreateAnchor();
406             //DbgOut("Move:Creating anchor");
407             nFlags |= SELENG_HAS_ANCH;
408         }
409     }
410 
411     //DbgOut("Move:SetCursor");
412     pFunctionSet->SetCursorAtPoint( rMEvt.GetPosPixel() );
413 
414     return sal_True;
415 }
416 
417 /*************************************************************************
418 |*
419 |*    SelectionEngine::SetWindow()
420 |*
421 |*    Beschreibung      SELENG.SDW
422 |*    Ersterstellung    OV 10.10.94
423 |*    Letzte Aenderung  OV 10.10.94
424 |*
425 *************************************************************************/
426 
SetWindow(Window * pNewWin)427 void SelectionEngine::SetWindow( Window* pNewWin )
428 {
429     if( pNewWin != pWin )
430     {
431         if ( pWin && (nFlags & SELENG_IN_SEL) )
432             pWin->ReleaseMouse();
433         pWin = pNewWin;
434         if ( pWin && ( nFlags & SELENG_IN_SEL ) )
435             pWin->CaptureMouse();
436     }
437 }
438 
439 /*************************************************************************
440 |*
441 |*    SelectionEngine::Reset()
442 |*
443 |*    Beschreibung      SELENG.SDW
444 |*    Ersterstellung    OV 07.07.95
445 |*    Letzte Aenderung  OV 07.07.95
446 |*
447 *************************************************************************/
448 
Reset()449 void SelectionEngine::Reset()
450 {
451     aWTimer.Stop();
452     if ( nFlags & SELENG_IN_SEL )
453         pWin->ReleaseMouse();
454     nFlags &= ~(SELENG_HAS_ANCH | SELENG_IN_SEL);
455     nLockedMods = 0;
456 }
457 
458 /*************************************************************************
459 |*
460 |*    SelectionEngine::Command()
461 |*
462 |*    Beschreibung      SELENG.SDW
463 |*    Ersterstellung    OV 07.07.95
464 |*    Letzte Aenderung  OV 07.07.95
465 |*
466 *************************************************************************/
467 
Command(const CommandEvent & rCEvt)468 void SelectionEngine::Command( const CommandEvent& rCEvt )
469 {
470     // Timer aWTimer ist beim Aufspannen einer Selektion aktiv
471     if ( !pFunctionSet || !pWin || aWTimer.IsActive() )
472         return;
473     aWTimer.Stop();
474     nFlags |= SELENG_CMDEVT;
475     if ( rCEvt.GetCommand() == COMMAND_STARTDRAG )
476     {
477         if ( nFlags & SELENG_DRG_ENAB )
478         {
479             DBG_ASSERT( rCEvt.IsMouseEvent(), "STARTDRAG: Not a MouseEvent" );
480             if ( pFunctionSet->IsSelectionAtPoint( rCEvt.GetMousePosPixel() ) )
481             {
482             	aLastMove = MouseEvent( rCEvt.GetMousePosPixel(),
483            					aLastMove.GetClicks(), aLastMove.GetMode(),
484            					aLastMove.GetButtons(), aLastMove.GetModifier() );
485                 pFunctionSet->BeginDrag();
486                 nFlags &= ~(SELENG_CMDEVT|SELENG_WAIT_UPEVT|SELENG_IN_SEL);
487             }
488             else
489                 nFlags &= ~SELENG_CMDEVT;
490         }
491         else
492             nFlags &= ~SELENG_CMDEVT;
493     }
494 }
495