Version 3.6.0.2, tag libreoffice-3.6.0.2
[LibreOffice.git] / vcl / source / window / split.cxx
bloba13e4fa84ffe6d1cf148a7ebd6aa45b14a238bba
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <tools/rc.h>
31 #include <tools/poly.hxx>
33 #include <vcl/event.hxx>
34 #include <vcl/split.hxx>
35 #include <vcl/svapp.hxx>
36 #include <vcl/syswin.hxx>
37 #include <vcl/taskpanelist.hxx>
38 #include <vcl/gradient.hxx>
39 #include <vcl/lineinfo.hxx>
41 #include <rtl/instance.hxx>
43 #include <window.h>
45 namespace
47 struct ImplBlackWall
48 : public rtl::StaticWithInit<Wallpaper, ImplBlackWall> {
49 Wallpaper operator () () {
50 return Wallpaper(COL_BLACK);
53 struct ImplWhiteWall
54 : public rtl::StaticWithInit<Wallpaper, ImplWhiteWall> {
55 Wallpaper operator () () {
56 return Wallpaper(COL_LIGHTGRAY);
61 // =======================================================================
63 void Splitter::ImplInitSplitterData()
65 ImplGetWindowImpl()->mbSplitter = sal_True;
66 mpRefWin = NULL;
67 mnSplitPos = 0;
68 mnLastSplitPos = 0;
69 mnStartSplitPos = 0;
70 mbDragFull = sal_False;
71 mbKbdSplitting = sal_False;
72 mbInKeyEvent = 0;
73 mnKeyboardStepSize = SPLITTER_DEFAULTSTEPSIZE;
76 // -----------------------------------------------------------------------
78 void Splitter::ImplInit( Window* pParent, WinBits nWinStyle )
80 Window::ImplInit( pParent, nWinStyle, NULL );
82 mpRefWin = pParent;
84 const StyleSettings& rSettings = GetSettings().GetStyleSettings();
85 long nA = rSettings.GetScrollBarSize();
86 long nB = rSettings.GetSplitSize();
88 PointerStyle ePointerStyle;
90 if ( nWinStyle & WB_HSCROLL )
92 ePointerStyle = POINTER_HSPLIT;
93 mbHorzSplit = sal_True;
94 SetSizePixel( Size( nB, nA ) );
96 else
98 ePointerStyle = POINTER_VSPLIT;
99 mbHorzSplit = sal_False;
100 SetSizePixel( Size( nA, nB ) );
103 SetPointer( Pointer( ePointerStyle ) );
105 if( GetSettings().GetStyleSettings().GetFaceColor().IsDark() )
106 SetBackground( ImplWhiteWall::get() );
107 else
108 SetBackground( ImplBlackWall::get() );
110 TaskPaneList *pTList = GetSystemWindow()->GetTaskPaneList();
111 pTList->AddWindow( this );
114 // -----------------------------------------------------------------------
116 void Splitter::ImplSplitMousePos( Point& rPos )
118 if ( mbHorzSplit )
120 if ( rPos.X() > maDragRect.Right()-1 )
121 rPos.X() = maDragRect.Right()-1;
122 if ( rPos.X() < maDragRect.Left()+1 )
123 rPos.X() = maDragRect.Left()+1;
125 else
127 if ( rPos.Y() > maDragRect.Bottom()-1 )
128 rPos.Y() = maDragRect.Bottom()-1;
129 if ( rPos.Y() < maDragRect.Top()+1 )
130 rPos.Y() = maDragRect.Top()+1;
134 // -----------------------------------------------------------------------
136 void Splitter::ImplDrawSplitter()
138 Rectangle aInvRect( maDragRect );
140 if ( mbHorzSplit )
142 aInvRect.Left() = maDragPos.X() - 1;
143 aInvRect.Right() = maDragPos.X() + 1;
145 else
147 aInvRect.Top() = maDragPos.Y() - 1;
148 aInvRect.Bottom() = maDragPos.Y() + 1;
151 mpRefWin->InvertTracking( mpRefWin->PixelToLogic(aInvRect), SHOWTRACK_SPLIT );
154 // -----------------------------------------------------------------------
156 Splitter::Splitter( Window* pParent, WinBits nStyle ) :
157 Window( WINDOW_SPLITTER )
159 ImplInitSplitterData();
160 ImplInit( pParent, nStyle );
163 // -----------------------------------------------------------------------
165 Splitter::Splitter( Window* pParent, const ResId& rResId ) :
166 Window( WINDOW_SPLITTER )
168 ImplInitSplitterData();
169 rResId.SetRT( RSC_SPLITTER );
170 WinBits nStyle = ImplInitRes( rResId );
171 ImplInit( pParent, nStyle );
172 ImplLoadRes( rResId );
174 if ( !(nStyle & WB_HIDE) )
175 Show();
178 // -----------------------------------------------------------------------
180 Splitter::~Splitter()
182 TaskPaneList *pTList = GetSystemWindow()->GetTaskPaneList();
183 pTList->RemoveWindow( this );
186 // -----------------------------------------------------------------------
188 void Splitter::SetKeyboardStepSize( long nStepSize )
190 mnKeyboardStepSize = nStepSize;
193 // -----------------------------------------------------------------------
195 Splitter* Splitter::ImplFindSibling()
197 // look for another splitter with the same parent but different orientation
198 Window *pWin = GetParent()->GetWindow( WINDOW_FIRSTCHILD );
199 Splitter *pSplitter = NULL;
200 while( pWin )
202 if( pWin->ImplIsSplitter() )
204 pSplitter = (Splitter*) pWin;
205 if( pSplitter != this && IsHorizontal() != pSplitter->IsHorizontal() )
206 return pSplitter;
208 pWin = pWin->GetWindow( WINDOW_NEXT );
210 return NULL;
213 // -----------------------------------------------------------------------
215 sal_Bool Splitter::ImplSplitterActive()
217 // is splitter in document or at scrollbar handle ?
219 sal_Bool bActive = sal_True;
220 const StyleSettings& rSettings = GetSettings().GetStyleSettings();
221 long nA = rSettings.GetScrollBarSize();
222 long nB = rSettings.GetSplitSize();
224 Size aSize = GetOutputSize();
225 if ( mbHorzSplit )
227 if( aSize.Width() == nB && aSize.Height() == nA )
228 bActive = sal_False;
230 else
232 if( aSize.Width() == nA && aSize.Height() == nB )
233 bActive = sal_False;
235 return bActive;
238 // -----------------------------------------------------------------------
240 void Splitter::MouseButtonDown( const MouseEvent& rMEvt )
242 if ( rMEvt.GetClicks() == 2 )
244 if ( mnLastSplitPos != mnSplitPos )
246 StartSplit();
247 Point aPos = rMEvt.GetPosPixel();
248 if ( mbHorzSplit )
249 aPos.X() = mnLastSplitPos;
250 else
251 aPos.Y() = mnLastSplitPos;
252 ImplSplitMousePos( aPos );
253 Splitting( aPos );
254 ImplSplitMousePos( aPos );
255 long nTemp = mnSplitPos;
256 if ( mbHorzSplit )
257 SetSplitPosPixel( aPos.X() );
258 else
259 SetSplitPosPixel( aPos.Y() );
260 mnLastSplitPos = nTemp;
261 Split();
262 EndSplit();
265 else
266 StartDrag();
269 // -----------------------------------------------------------------------
271 void Splitter::Tracking( const TrackingEvent& rTEvt )
273 if ( rTEvt.IsTrackingEnded() )
275 if ( !mbDragFull )
276 ImplDrawSplitter();
278 if ( !rTEvt.IsTrackingCanceled() )
280 long nNewPos;
281 if ( mbHorzSplit )
282 nNewPos = maDragPos.X();
283 else
284 nNewPos = maDragPos.Y();
285 if ( nNewPos != mnStartSplitPos )
287 SetSplitPosPixel( nNewPos );
288 mnLastSplitPos = 0;
289 Split();
291 EndSplit();
293 else if ( mbDragFull )
295 SetSplitPosPixel( mnStartSplitPos );
296 Split();
298 mnStartSplitPos = 0;
300 else
302 //Point aNewPos = mpRefWin->ScreenToOutputPixel( OutputToScreenPixel( rTEvt.GetMouseEvent().GetPosPixel() ) );
303 Point aNewPos = mpRefWin->NormalizedScreenToOutputPixel( OutputToNormalizedScreenPixel( rTEvt.GetMouseEvent().GetPosPixel() ) );
304 ImplSplitMousePos( aNewPos );
305 Splitting( aNewPos );
306 ImplSplitMousePos( aNewPos );
308 if ( mbHorzSplit )
310 if ( aNewPos.X() == maDragPos.X() )
311 return;
313 else
315 if ( aNewPos.Y() == maDragPos.Y() )
316 return;
319 if ( mbDragFull )
321 maDragPos = aNewPos;
322 long nNewPos;
323 if ( mbHorzSplit )
324 nNewPos = maDragPos.X();
325 else
326 nNewPos = maDragPos.Y();
327 if ( nNewPos != mnSplitPos )
329 SetSplitPosPixel( nNewPos );
330 mnLastSplitPos = 0;
331 Split();
334 GetParent()->Update();
336 else
338 ImplDrawSplitter();
339 maDragPos = aNewPos;
340 ImplDrawSplitter();
345 // -----------------------------------------------------------------------
347 void Splitter::ImplKbdTracking( KeyCode aKeyCode )
349 sal_uInt16 nCode = aKeyCode.GetCode();
350 if ( nCode == KEY_ESCAPE || nCode == KEY_RETURN )
352 if( !mbKbdSplitting )
353 return;
354 else
355 mbKbdSplitting = sal_False;
357 if ( nCode != KEY_ESCAPE )
359 long nNewPos;
360 if ( mbHorzSplit )
361 nNewPos = maDragPos.X();
362 else
363 nNewPos = maDragPos.Y();
364 if ( nNewPos != mnStartSplitPos )
366 SetSplitPosPixel( nNewPos );
367 mnLastSplitPos = 0;
368 Split();
371 else
373 SetSplitPosPixel( mnStartSplitPos );
374 Split();
375 EndSplit();
377 mnStartSplitPos = 0;
379 else
381 Point aNewPos;
382 Size aSize = mpRefWin->GetOutputSize();
383 Point aPos = GetPosPixel();
384 // depending on the position calc allows continous moves or snaps to row/columns
385 // continous mode is active when position is at the origin or end of the splitter
386 // otherwise snap mode is active
387 // default here is snap, holding shift sets continous mode
388 if( mbHorzSplit )
389 aNewPos = Point( ImplSplitterActive() ? aPos.X() : mnSplitPos, aKeyCode.IsShift() ? 0 : aSize.Height()/2);
390 else
391 aNewPos = Point( aKeyCode.IsShift() ? 0 : aSize.Width()/2, ImplSplitterActive() ? aPos.Y() : mnSplitPos );
393 Point aOldWindowPos = GetPosPixel();
395 int maxiter = 500; // avoid endless loop
396 int delta=0;
397 int delta_step = mbHorzSplit ? aSize.Width()/10 : aSize.Height()/10;
399 // use the specified step size if it was set
400 if( mnKeyboardStepSize != SPLITTER_DEFAULTSTEPSIZE )
401 delta_step = mnKeyboardStepSize;
403 while( maxiter-- && aOldWindowPos == GetPosPixel() )
405 // inc/dec position until application performs changes
406 // thus a single key press really moves the splitter
407 if( aKeyCode.IsShift() )
408 delta++;
409 else
410 delta += delta_step;
412 switch( nCode )
414 case KEY_LEFT:
415 aNewPos.X()-=delta;
416 break;
417 case KEY_RIGHT:
418 aNewPos.X()+=delta;
419 break;
420 case KEY_UP:
421 aNewPos.Y()-=delta;
422 break;
423 case KEY_DOWN:
424 aNewPos.Y()+=delta;
425 break;
426 default:
427 maxiter = 0; // leave loop
428 break;
430 ImplSplitMousePos( aNewPos );
431 Splitting( aNewPos );
432 ImplSplitMousePos( aNewPos );
434 if ( mbHorzSplit )
436 if ( aNewPos.X() == maDragPos.X() )
437 continue;
439 else
441 if ( aNewPos.Y() == maDragPos.Y() )
442 continue;
445 maDragPos = aNewPos;
446 long nNewPos;
447 if ( mbHorzSplit )
448 nNewPos = maDragPos.X();
449 else
450 nNewPos = maDragPos.Y();
451 if ( nNewPos != mnSplitPos )
453 SetSplitPosPixel( nNewPos );
454 mnLastSplitPos = 0;
455 Split();
457 GetParent()->Update();
462 // -----------------------------------------------------------------------
464 void Splitter::StartSplit()
466 maStartSplitHdl.Call( this );
469 // -----------------------------------------------------------------------
471 void Splitter::Split()
473 maSplitHdl.Call( this );
476 // -----------------------------------------------------------------------
478 void Splitter::EndSplit()
480 if ( maEndSplitHdl.IsSet() )
481 maEndSplitHdl.Call( this );
484 // -----------------------------------------------------------------------
486 void Splitter::Splitting( Point& /* rSplitPos */ )
490 // -----------------------------------------------------------------------
492 void Splitter::SetDragRectPixel( const Rectangle& rDragRect, Window* _pRefWin )
494 maDragRect = rDragRect;
495 if ( !_pRefWin )
496 mpRefWin = GetParent();
497 else
498 mpRefWin = _pRefWin;
501 // -----------------------------------------------------------------------
503 void Splitter::SetSplitPosPixel( long nNewPos )
505 mnSplitPos = nNewPos;
508 // -----------------------------------------------------------------------
510 void Splitter::SetLastSplitPosPixel( long nNewPos )
512 mnLastSplitPos = nNewPos;
515 // -----------------------------------------------------------------------
517 void Splitter::StartDrag()
519 if ( IsTracking() )
520 return;
522 StartSplit();
524 // Tracking starten
525 StartTracking();
527 // Start-Positon ermitteln
528 maDragPos = mpRefWin->GetPointerPosPixel();
529 ImplSplitMousePos( maDragPos );
530 Splitting( maDragPos );
531 ImplSplitMousePos( maDragPos );
532 if ( mbHorzSplit )
533 mnStartSplitPos = maDragPos.X();
534 else
535 mnStartSplitPos = maDragPos.Y();
537 mbDragFull = (Application::GetSettings().GetStyleSettings().GetDragFullOptions() & DRAGFULL_OPTION_SPLIT) != 0;
538 if ( !mbDragFull )
539 ImplDrawSplitter();
543 // -----------------------------------------------------------------------
545 void Splitter::ImplStartKbdSplitting()
547 if( mbKbdSplitting )
548 return;
550 mbKbdSplitting = sal_True;
552 StartSplit();
554 // determine start position
555 // because we have no mouse position we take either the position
556 // of the splitter window or the last split position
557 // the other coordinate is just the center of the reference window
558 Size aSize = mpRefWin->GetOutputSize();
559 Point aPos = GetPosPixel();
560 if( mbHorzSplit )
561 maDragPos = Point( ImplSplitterActive() ? aPos.X() : mnSplitPos, aSize.Height()/2 );
562 else
563 maDragPos = Point( aSize.Width()/2, ImplSplitterActive() ? aPos.Y() : mnSplitPos );
564 ImplSplitMousePos( maDragPos );
565 Splitting( maDragPos );
566 ImplSplitMousePos( maDragPos );
567 if ( mbHorzSplit )
568 mnStartSplitPos = maDragPos.X();
569 else
570 mnStartSplitPos = maDragPos.Y();
573 // -----------------------------------------------------------------------
575 void Splitter::ImplRestoreSplitter()
577 // set splitter in the center of the ref window
578 StartSplit();
579 Size aSize = mpRefWin->GetOutputSize();
580 Point aPos = Point( aSize.Width()/2 , aSize.Height()/2);
581 if ( mnLastSplitPos != mnSplitPos && mnLastSplitPos > 5 )
583 // restore last pos if it was a useful position (>5)
584 if ( mbHorzSplit )
585 aPos.X() = mnLastSplitPos;
586 else
587 aPos.Y() = mnLastSplitPos;
590 ImplSplitMousePos( aPos );
591 Splitting( aPos );
592 ImplSplitMousePos( aPos );
593 long nTemp = mnSplitPos;
594 if ( mbHorzSplit )
595 SetSplitPosPixel( aPos.X() );
596 else
597 SetSplitPosPixel( aPos.Y() );
598 mnLastSplitPos = nTemp;
599 Split();
600 EndSplit();
604 // -----------------------------------------------------------------------
606 void Splitter::GetFocus()
608 if( !ImplSplitterActive() )
609 ImplRestoreSplitter();
611 Invalidate();
614 // -----------------------------------------------------------------------
616 void Splitter::LoseFocus()
618 if( mbKbdSplitting )
620 KeyCode aReturnKey( KEY_RETURN );
621 ImplKbdTracking( aReturnKey );
622 mbKbdSplitting = sal_False;
624 Invalidate();
627 // -----------------------------------------------------------------------
629 void Splitter::KeyInput( const KeyEvent& rKEvt )
631 if( mbInKeyEvent )
632 return;
634 mbInKeyEvent = 1;
636 Splitter *pSibling = ImplFindSibling();
637 KeyCode aKeyCode = rKEvt.GetKeyCode();
638 sal_uInt16 nCode = aKeyCode.GetCode();
639 switch ( nCode )
641 case KEY_UP:
642 case KEY_DOWN:
643 if( !mbHorzSplit )
645 ImplStartKbdSplitting();
646 ImplKbdTracking( aKeyCode );
648 else
650 if( pSibling )
652 pSibling->GrabFocus();
653 pSibling->KeyInput( rKEvt );
656 break;
657 case KEY_RIGHT:
658 case KEY_LEFT:
659 if( mbHorzSplit )
661 ImplStartKbdSplitting();
662 ImplKbdTracking( aKeyCode );
664 else
666 if( pSibling )
668 pSibling->GrabFocus();
669 pSibling->KeyInput( rKEvt );
672 break;
674 case KEY_DELETE:
675 if( ImplSplitterActive() )
677 if( mbKbdSplitting )
679 KeyCode aKey( KEY_ESCAPE );
680 ImplKbdTracking( aKey );
683 StartSplit();
684 Point aPos;
685 if ( mbHorzSplit )
686 aPos.X() = 0;
687 else
688 aPos.Y() = 0;
689 ImplSplitMousePos( aPos );
690 Splitting( aPos );
691 ImplSplitMousePos( aPos );
692 long nTemp = mnSplitPos;
693 if ( mbHorzSplit )
694 SetSplitPosPixel( aPos.X() );
695 else
696 SetSplitPosPixel( aPos.Y() );
697 mnLastSplitPos = nTemp;
698 Split();
699 EndSplit();
701 // Shift-Del deletes both splitters
702 if( aKeyCode.IsShift() && pSibling )
703 pSibling->KeyInput( rKEvt );
705 GrabFocusToDocument();
707 break;
709 case KEY_ESCAPE:
710 if( mbKbdSplitting )
711 ImplKbdTracking( aKeyCode );
712 else
713 GrabFocusToDocument();
714 break;
716 case KEY_RETURN:
717 ImplKbdTracking( aKeyCode );
718 GrabFocusToDocument();
719 break;
720 default: // let any key input fix the splitter
721 Window::KeyInput( rKEvt );
722 GrabFocusToDocument();
723 break;
725 mbInKeyEvent = 0;
728 // -----------------------------------------------------------------------
730 long Splitter::Notify( NotifyEvent& rNEvt )
732 return Window::Notify( rNEvt );
735 // -----------------------------------------------------------------------
737 void Splitter::DataChanged( const DataChangedEvent& rDCEvt )
739 Window::DataChanged( rDCEvt );
740 if( rDCEvt.GetType() == DATACHANGED_SETTINGS )
742 Color oldFaceColor = ((AllSettings *) rDCEvt.GetData())->GetStyleSettings().GetFaceColor();
743 Color newFaceColor = Application::GetSettings().GetStyleSettings().GetFaceColor();
744 if( oldFaceColor.IsDark() != newFaceColor.IsDark() )
746 if( newFaceColor.IsDark() )
747 SetBackground( ImplWhiteWall::get() );
748 else
749 SetBackground( ImplBlackWall::get() );
754 // -----------------------------------------------------------------------
756 void Splitter::Paint( const Rectangle& rPaintRect )
758 if( HasFocus() || mbKbdSplitting )
760 Color oldFillCol = GetFillColor();
761 Color oldLineCol = GetLineColor();
763 SetLineColor();
764 SetFillColor( GetSettings().GetStyleSettings().GetFaceColor() );
765 DrawRect( rPaintRect );
767 Color aSelectionBorderCol( GetSettings().GetStyleSettings().GetActiveColor() );
768 SetFillColor( aSelectionBorderCol );
769 SetLineColor();
771 Polygon aPoly( rPaintRect );
772 PolyPolygon aPolyPoly( aPoly );
773 DrawTransparent( aPolyPoly, 85 );
775 SetLineColor( aSelectionBorderCol );
776 SetFillColor();
778 if( mbKbdSplitting )
780 LineInfo aInfo( LINE_DASH );
781 //aInfo.SetDashLen( 2 );
782 //aInfo.SetDashCount( 1 );
783 aInfo.SetDistance( 1 );
784 aInfo.SetDotLen( 2 );
785 aInfo.SetDotCount( 1 );
787 DrawPolyLine( aPoly, aInfo );
789 else
790 DrawRect( rPaintRect );
792 SetFillColor( oldFillCol);
793 SetLineColor( oldLineCol);
795 else
797 Window::Paint( rPaintRect );
801 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */