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 ************************************************************************/
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>
48 : public rtl::StaticWithInit
<Wallpaper
, ImplBlackWall
> {
49 Wallpaper
operator () () {
50 return Wallpaper(COL_BLACK
);
54 : public rtl::StaticWithInit
<Wallpaper
, ImplWhiteWall
> {
55 Wallpaper
operator () () {
56 return Wallpaper(COL_LIGHTGRAY
);
61 // =======================================================================
63 void Splitter::ImplInitSplitterData()
65 ImplGetWindowImpl()->mbSplitter
= sal_True
;
70 mbDragFull
= sal_False
;
71 mbKbdSplitting
= sal_False
;
73 mnKeyboardStepSize
= SPLITTER_DEFAULTSTEPSIZE
;
76 // -----------------------------------------------------------------------
78 void Splitter::ImplInit( Window
* pParent
, WinBits nWinStyle
)
80 Window::ImplInit( pParent
, nWinStyle
, NULL
);
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
) );
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() );
108 SetBackground( ImplBlackWall::get() );
110 TaskPaneList
*pTList
= GetSystemWindow()->GetTaskPaneList();
111 pTList
->AddWindow( this );
114 // -----------------------------------------------------------------------
116 void Splitter::ImplSplitMousePos( Point
& rPos
)
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;
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
);
142 aInvRect
.Left() = maDragPos
.X() - 1;
143 aInvRect
.Right() = maDragPos
.X() + 1;
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
) )
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
;
202 if( pWin
->ImplIsSplitter() )
204 pSplitter
= (Splitter
*) pWin
;
205 if( pSplitter
!= this && IsHorizontal() != pSplitter
->IsHorizontal() )
208 pWin
= pWin
->GetWindow( WINDOW_NEXT
);
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();
227 if( aSize
.Width() == nB
&& aSize
.Height() == nA
)
232 if( aSize
.Width() == nA
&& aSize
.Height() == nB
)
238 // -----------------------------------------------------------------------
240 void Splitter::MouseButtonDown( const MouseEvent
& rMEvt
)
242 if ( rMEvt
.GetClicks() == 2 )
244 if ( mnLastSplitPos
!= mnSplitPos
)
247 Point aPos
= rMEvt
.GetPosPixel();
249 aPos
.X() = mnLastSplitPos
;
251 aPos
.Y() = mnLastSplitPos
;
252 ImplSplitMousePos( aPos
);
254 ImplSplitMousePos( aPos
);
255 long nTemp
= mnSplitPos
;
257 SetSplitPosPixel( aPos
.X() );
259 SetSplitPosPixel( aPos
.Y() );
260 mnLastSplitPos
= nTemp
;
269 // -----------------------------------------------------------------------
271 void Splitter::Tracking( const TrackingEvent
& rTEvt
)
273 if ( rTEvt
.IsTrackingEnded() )
278 if ( !rTEvt
.IsTrackingCanceled() )
282 nNewPos
= maDragPos
.X();
284 nNewPos
= maDragPos
.Y();
285 if ( nNewPos
!= mnStartSplitPos
)
287 SetSplitPosPixel( nNewPos
);
293 else if ( mbDragFull
)
295 SetSplitPosPixel( mnStartSplitPos
);
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
);
310 if ( aNewPos
.X() == maDragPos
.X() )
315 if ( aNewPos
.Y() == maDragPos
.Y() )
324 nNewPos
= maDragPos
.X();
326 nNewPos
= maDragPos
.Y();
327 if ( nNewPos
!= mnSplitPos
)
329 SetSplitPosPixel( nNewPos
);
334 GetParent()->Update();
345 // -----------------------------------------------------------------------
347 void Splitter::ImplKbdTracking( KeyCode aKeyCode
)
349 sal_uInt16 nCode
= aKeyCode
.GetCode();
350 if ( nCode
== KEY_ESCAPE
|| nCode
== KEY_RETURN
)
352 if( !mbKbdSplitting
)
355 mbKbdSplitting
= sal_False
;
357 if ( nCode
!= KEY_ESCAPE
)
361 nNewPos
= maDragPos
.X();
363 nNewPos
= maDragPos
.Y();
364 if ( nNewPos
!= mnStartSplitPos
)
366 SetSplitPosPixel( nNewPos
);
373 SetSplitPosPixel( mnStartSplitPos
);
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
389 aNewPos
= Point( ImplSplitterActive() ? aPos
.X() : mnSplitPos
, aKeyCode
.IsShift() ? 0 : aSize
.Height()/2);
391 aNewPos
= Point( aKeyCode
.IsShift() ? 0 : aSize
.Width()/2, ImplSplitterActive() ? aPos
.Y() : mnSplitPos
);
393 Point aOldWindowPos
= GetPosPixel();
395 int maxiter
= 500; // avoid endless loop
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() )
427 maxiter
= 0; // leave loop
430 ImplSplitMousePos( aNewPos
);
431 Splitting( aNewPos
);
432 ImplSplitMousePos( aNewPos
);
436 if ( aNewPos
.X() == maDragPos
.X() )
441 if ( aNewPos
.Y() == maDragPos
.Y() )
448 nNewPos
= maDragPos
.X();
450 nNewPos
= maDragPos
.Y();
451 if ( nNewPos
!= mnSplitPos
)
453 SetSplitPosPixel( nNewPos
);
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
;
496 mpRefWin
= GetParent();
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()
527 // Start-Positon ermitteln
528 maDragPos
= mpRefWin
->GetPointerPosPixel();
529 ImplSplitMousePos( maDragPos
);
530 Splitting( maDragPos
);
531 ImplSplitMousePos( maDragPos
);
533 mnStartSplitPos
= maDragPos
.X();
535 mnStartSplitPos
= maDragPos
.Y();
537 mbDragFull
= (Application::GetSettings().GetStyleSettings().GetDragFullOptions() & DRAGFULL_OPTION_SPLIT
) != 0;
543 // -----------------------------------------------------------------------
545 void Splitter::ImplStartKbdSplitting()
550 mbKbdSplitting
= sal_True
;
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();
561 maDragPos
= Point( ImplSplitterActive() ? aPos
.X() : mnSplitPos
, aSize
.Height()/2 );
563 maDragPos
= Point( aSize
.Width()/2, ImplSplitterActive() ? aPos
.Y() : mnSplitPos
);
564 ImplSplitMousePos( maDragPos
);
565 Splitting( maDragPos
);
566 ImplSplitMousePos( maDragPos
);
568 mnStartSplitPos
= maDragPos
.X();
570 mnStartSplitPos
= maDragPos
.Y();
573 // -----------------------------------------------------------------------
575 void Splitter::ImplRestoreSplitter()
577 // set splitter in the center of the ref window
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)
585 aPos
.X() = mnLastSplitPos
;
587 aPos
.Y() = mnLastSplitPos
;
590 ImplSplitMousePos( aPos
);
592 ImplSplitMousePos( aPos
);
593 long nTemp
= mnSplitPos
;
595 SetSplitPosPixel( aPos
.X() );
597 SetSplitPosPixel( aPos
.Y() );
598 mnLastSplitPos
= nTemp
;
604 // -----------------------------------------------------------------------
606 void Splitter::GetFocus()
608 if( !ImplSplitterActive() )
609 ImplRestoreSplitter();
614 // -----------------------------------------------------------------------
616 void Splitter::LoseFocus()
620 KeyCode
aReturnKey( KEY_RETURN
);
621 ImplKbdTracking( aReturnKey
);
622 mbKbdSplitting
= sal_False
;
627 // -----------------------------------------------------------------------
629 void Splitter::KeyInput( const KeyEvent
& rKEvt
)
636 Splitter
*pSibling
= ImplFindSibling();
637 KeyCode aKeyCode
= rKEvt
.GetKeyCode();
638 sal_uInt16 nCode
= aKeyCode
.GetCode();
645 ImplStartKbdSplitting();
646 ImplKbdTracking( aKeyCode
);
652 pSibling
->GrabFocus();
653 pSibling
->KeyInput( rKEvt
);
661 ImplStartKbdSplitting();
662 ImplKbdTracking( aKeyCode
);
668 pSibling
->GrabFocus();
669 pSibling
->KeyInput( rKEvt
);
675 if( ImplSplitterActive() )
679 KeyCode
aKey( KEY_ESCAPE
);
680 ImplKbdTracking( aKey
);
689 ImplSplitMousePos( aPos
);
691 ImplSplitMousePos( aPos
);
692 long nTemp
= mnSplitPos
;
694 SetSplitPosPixel( aPos
.X() );
696 SetSplitPosPixel( aPos
.Y() );
697 mnLastSplitPos
= nTemp
;
701 // Shift-Del deletes both splitters
702 if( aKeyCode
.IsShift() && pSibling
)
703 pSibling
->KeyInput( rKEvt
);
705 GrabFocusToDocument();
711 ImplKbdTracking( aKeyCode
);
713 GrabFocusToDocument();
717 ImplKbdTracking( aKeyCode
);
718 GrabFocusToDocument();
720 default: // let any key input fix the splitter
721 Window::KeyInput( rKEvt
);
722 GrabFocusToDocument();
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() );
749 SetBackground( ImplBlackWall::get() );
754 // -----------------------------------------------------------------------
756 void Splitter::Paint( const Rectangle
& rPaintRect
)
758 if( HasFocus() || mbKbdSplitting
)
760 Color oldFillCol
= GetFillColor();
761 Color oldLineCol
= GetLineColor();
764 SetFillColor( GetSettings().GetStyleSettings().GetFaceColor() );
765 DrawRect( rPaintRect
);
767 Color
aSelectionBorderCol( GetSettings().GetStyleSettings().GetActiveColor() );
768 SetFillColor( aSelectionBorderCol
);
771 Polygon
aPoly( rPaintRect
);
772 PolyPolygon
aPolyPoly( aPoly
);
773 DrawTransparent( aPolyPoly
, 85 );
775 SetLineColor( aSelectionBorderCol
);
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
);
790 DrawRect( rPaintRect
);
792 SetFillColor( oldFillCol
);
793 SetLineColor( oldLineCol
);
797 Window::Paint( rPaintRect
);
801 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */