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 <tools/poly.hxx>
23 #include <vcl/event.hxx>
24 #include <vcl/split.hxx>
25 #include <vcl/svapp.hxx>
26 #include <vcl/syswin.hxx>
27 #include <vcl/taskpanelist.hxx>
28 #include <vcl/gradient.hxx>
29 #include <vcl/lineinfo.hxx>
31 #include <rtl/instance.hxx>
38 : public rtl::StaticWithInit
<Wallpaper
, ImplBlackWall
> {
39 Wallpaper
operator () () {
40 return Wallpaper(COL_BLACK
);
44 : public rtl::StaticWithInit
<Wallpaper
, ImplWhiteWall
> {
45 Wallpaper
operator () () {
46 return Wallpaper(COL_LIGHTGRAY
);
51 // =======================================================================
53 void Splitter::ImplInitSplitterData()
55 ImplGetWindowImpl()->mbSplitter
= sal_True
;
60 mbDragFull
= sal_False
;
61 mbKbdSplitting
= sal_False
;
63 mnKeyboardStepSize
= SPLITTER_DEFAULTSTEPSIZE
;
66 // -----------------------------------------------------------------------
68 // Should only be called from a ImplInit method for initialization or
69 // after checking bNew is different from the current mbHorzSplit value.
70 // The public method that does that check is Splitter::SetHorizontal().
71 void Splitter::ImplInitHorVer(bool bNew
)
75 PointerStyle ePointerStyle
;
76 const StyleSettings
& rSettings
= GetSettings().GetStyleSettings();
80 ePointerStyle
= POINTER_HSPLIT
;
81 SetSizePixel( Size( rSettings
.GetSplitSize(), rSettings
.GetScrollBarSize() ) );
85 ePointerStyle
= POINTER_VSPLIT
;
86 SetSizePixel( Size( rSettings
.GetScrollBarSize(), rSettings
.GetSplitSize() ) );
89 SetPointer( Pointer( ePointerStyle
) );
92 // -----------------------------------------------------------------------
94 void Splitter::ImplInit( Window
* pParent
, WinBits nWinStyle
)
96 Window::ImplInit( pParent
, nWinStyle
, NULL
);
100 ImplInitHorVer(nWinStyle
& WB_HSCROLL
);
102 if( GetSettings().GetStyleSettings().GetFaceColor().IsDark() )
103 SetBackground( ImplWhiteWall::get() );
105 SetBackground( ImplBlackWall::get() );
107 TaskPaneList
*pTList
= GetSystemWindow()->GetTaskPaneList();
108 pTList
->AddWindow( this );
111 // -----------------------------------------------------------------------
113 void Splitter::ImplSplitMousePos( Point
& rPos
)
117 if ( rPos
.X() > maDragRect
.Right()-1 )
118 rPos
.X() = maDragRect
.Right()-1;
119 if ( rPos
.X() < maDragRect
.Left()+1 )
120 rPos
.X() = maDragRect
.Left()+1;
124 if ( rPos
.Y() > maDragRect
.Bottom()-1 )
125 rPos
.Y() = maDragRect
.Bottom()-1;
126 if ( rPos
.Y() < maDragRect
.Top()+1 )
127 rPos
.Y() = maDragRect
.Top()+1;
131 // -----------------------------------------------------------------------
133 void Splitter::ImplDrawSplitter()
135 Rectangle
aInvRect( maDragRect
);
139 aInvRect
.Left() = maDragPos
.X() - 1;
140 aInvRect
.Right() = maDragPos
.X() + 1;
144 aInvRect
.Top() = maDragPos
.Y() - 1;
145 aInvRect
.Bottom() = maDragPos
.Y() + 1;
148 mpRefWin
->InvertTracking( mpRefWin
->PixelToLogic(aInvRect
), SHOWTRACK_SPLIT
);
151 // -----------------------------------------------------------------------
153 Splitter::Splitter( Window
* pParent
, WinBits nStyle
) :
154 Window( WINDOW_SPLITTER
)
156 ImplInitSplitterData();
157 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
);
177 if ( !(nStyle
& WB_HIDE
) )
181 // -----------------------------------------------------------------------
183 Splitter::~Splitter()
185 TaskPaneList
*pTList
= GetSystemWindow()->GetTaskPaneList();
186 pTList
->RemoveWindow( this );
189 // -----------------------------------------------------------------------
191 void Splitter::SetHorizontal(bool bNew
)
193 if(bNew
!= (bool)mbHorzSplit
)
195 ImplInitHorVer(bNew
);
199 // -----------------------------------------------------------------------
201 void Splitter::SetKeyboardStepSize( long nStepSize
)
203 mnKeyboardStepSize
= nStepSize
;
206 // -----------------------------------------------------------------------
208 Splitter
* Splitter::ImplFindSibling()
210 // look for another splitter with the same parent but different orientation
211 Window
*pWin
= GetParent()->GetWindow( WINDOW_FIRSTCHILD
);
212 Splitter
*pSplitter
= NULL
;
215 if( pWin
->ImplIsSplitter() )
217 pSplitter
= (Splitter
*) pWin
;
218 if( pSplitter
!= this && IsHorizontal() != pSplitter
->IsHorizontal() )
221 pWin
= pWin
->GetWindow( WINDOW_NEXT
);
226 // -----------------------------------------------------------------------
228 sal_Bool
Splitter::ImplSplitterActive()
230 // is splitter in document or at scrollbar handle ?
232 sal_Bool bActive
= sal_True
;
233 const StyleSettings
& rSettings
= GetSettings().GetStyleSettings();
234 long nA
= rSettings
.GetScrollBarSize();
235 long nB
= rSettings
.GetSplitSize();
237 Size aSize
= GetOutputSize();
240 if( aSize
.Width() == nB
&& aSize
.Height() == nA
)
245 if( aSize
.Width() == nA
&& aSize
.Height() == nB
)
251 // -----------------------------------------------------------------------
253 void Splitter::MouseButtonDown( const MouseEvent
& rMEvt
)
255 if ( rMEvt
.GetClicks() == 2 )
257 if ( mnLastSplitPos
!= mnSplitPos
)
260 Point aPos
= rMEvt
.GetPosPixel();
262 aPos
.X() = mnLastSplitPos
;
264 aPos
.Y() = mnLastSplitPos
;
265 ImplSplitMousePos( aPos
);
267 ImplSplitMousePos( aPos
);
268 long nTemp
= mnSplitPos
;
270 SetSplitPosPixel( aPos
.X() );
272 SetSplitPosPixel( aPos
.Y() );
273 mnLastSplitPos
= nTemp
;
282 // -----------------------------------------------------------------------
284 void Splitter::Tracking( const TrackingEvent
& rTEvt
)
286 if ( rTEvt
.IsTrackingEnded() )
291 if ( !rTEvt
.IsTrackingCanceled() )
295 nNewPos
= maDragPos
.X();
297 nNewPos
= maDragPos
.Y();
298 if ( nNewPos
!= mnStartSplitPos
)
300 SetSplitPosPixel( nNewPos
);
306 else if ( mbDragFull
)
308 SetSplitPosPixel( mnStartSplitPos
);
315 //Point aNewPos = mpRefWin->ScreenToOutputPixel( OutputToScreenPixel( rTEvt.GetMouseEvent().GetPosPixel() ) );
316 Point aNewPos
= mpRefWin
->NormalizedScreenToOutputPixel( OutputToNormalizedScreenPixel( rTEvt
.GetMouseEvent().GetPosPixel() ) );
317 ImplSplitMousePos( aNewPos
);
318 Splitting( aNewPos
);
319 ImplSplitMousePos( aNewPos
);
323 if ( aNewPos
.X() == maDragPos
.X() )
328 if ( aNewPos
.Y() == maDragPos
.Y() )
337 nNewPos
= maDragPos
.X();
339 nNewPos
= maDragPos
.Y();
340 if ( nNewPos
!= mnSplitPos
)
342 SetSplitPosPixel( nNewPos
);
347 GetParent()->Update();
358 // -----------------------------------------------------------------------
360 void Splitter::ImplKbdTracking( KeyCode aKeyCode
)
362 sal_uInt16 nCode
= aKeyCode
.GetCode();
363 if ( nCode
== KEY_ESCAPE
|| nCode
== KEY_RETURN
)
365 if( !mbKbdSplitting
)
368 mbKbdSplitting
= sal_False
;
370 if ( nCode
!= KEY_ESCAPE
)
374 nNewPos
= maDragPos
.X();
376 nNewPos
= maDragPos
.Y();
377 if ( nNewPos
!= mnStartSplitPos
)
379 SetSplitPosPixel( nNewPos
);
386 SetSplitPosPixel( mnStartSplitPos
);
395 Size aSize
= mpRefWin
->GetOutputSize();
396 Point aPos
= GetPosPixel();
397 // depending on the position calc allows continous moves or snaps to row/columns
398 // continous mode is active when position is at the origin or end of the splitter
399 // otherwise snap mode is active
400 // default here is snap, holding shift sets continous mode
402 aNewPos
= Point( ImplSplitterActive() ? aPos
.X() : mnSplitPos
, aKeyCode
.IsShift() ? 0 : aSize
.Height()/2);
404 aNewPos
= Point( aKeyCode
.IsShift() ? 0 : aSize
.Width()/2, ImplSplitterActive() ? aPos
.Y() : mnSplitPos
);
406 Point aOldWindowPos
= GetPosPixel();
408 int maxiter
= 500; // avoid endless loop
410 int delta_step
= mbHorzSplit
? aSize
.Width()/10 : aSize
.Height()/10;
412 // use the specified step size if it was set
413 if( mnKeyboardStepSize
!= SPLITTER_DEFAULTSTEPSIZE
)
414 delta_step
= mnKeyboardStepSize
;
416 while( maxiter
-- && aOldWindowPos
== GetPosPixel() )
418 // inc/dec position until application performs changes
419 // thus a single key press really moves the splitter
420 if( aKeyCode
.IsShift() )
440 maxiter
= 0; // leave loop
443 ImplSplitMousePos( aNewPos
);
444 Splitting( aNewPos
);
445 ImplSplitMousePos( aNewPos
);
449 if ( aNewPos
.X() == maDragPos
.X() )
454 if ( aNewPos
.Y() == maDragPos
.Y() )
461 nNewPos
= maDragPos
.X();
463 nNewPos
= maDragPos
.Y();
464 if ( nNewPos
!= mnSplitPos
)
466 SetSplitPosPixel( nNewPos
);
470 GetParent()->Update();
475 // -----------------------------------------------------------------------
477 void Splitter::StartSplit()
479 maStartSplitHdl
.Call( this );
482 // -----------------------------------------------------------------------
484 void Splitter::Split()
486 maSplitHdl
.Call( this );
489 // -----------------------------------------------------------------------
491 void Splitter::EndSplit()
493 if ( maEndSplitHdl
.IsSet() )
494 maEndSplitHdl
.Call( this );
497 // -----------------------------------------------------------------------
499 void Splitter::Splitting( Point
& /* rSplitPos */ )
503 // -----------------------------------------------------------------------
505 void Splitter::SetDragRectPixel( const Rectangle
& rDragRect
, Window
* _pRefWin
)
507 maDragRect
= rDragRect
;
509 mpRefWin
= GetParent();
514 // -----------------------------------------------------------------------
516 void Splitter::SetSplitPosPixel( long nNewPos
)
518 mnSplitPos
= nNewPos
;
521 // -----------------------------------------------------------------------
523 void Splitter::StartDrag()
533 // Start-Positon ermitteln
534 maDragPos
= mpRefWin
->GetPointerPosPixel();
535 ImplSplitMousePos( maDragPos
);
536 Splitting( maDragPos
);
537 ImplSplitMousePos( maDragPos
);
539 mnStartSplitPos
= maDragPos
.X();
541 mnStartSplitPos
= maDragPos
.Y();
543 mbDragFull
= (Application::GetSettings().GetStyleSettings().GetDragFullOptions() & DRAGFULL_OPTION_SPLIT
) != 0;
549 // -----------------------------------------------------------------------
551 void Splitter::ImplStartKbdSplitting()
556 mbKbdSplitting
= sal_True
;
560 // determine start position
561 // because we have no mouse position we take either the position
562 // of the splitter window or the last split position
563 // the other coordinate is just the center of the reference window
564 Size aSize
= mpRefWin
->GetOutputSize();
565 Point aPos
= GetPosPixel();
567 maDragPos
= Point( ImplSplitterActive() ? aPos
.X() : mnSplitPos
, aSize
.Height()/2 );
569 maDragPos
= Point( aSize
.Width()/2, ImplSplitterActive() ? aPos
.Y() : mnSplitPos
);
570 ImplSplitMousePos( maDragPos
);
571 Splitting( maDragPos
);
572 ImplSplitMousePos( maDragPos
);
574 mnStartSplitPos
= maDragPos
.X();
576 mnStartSplitPos
= maDragPos
.Y();
579 // -----------------------------------------------------------------------
581 void Splitter::ImplRestoreSplitter()
583 // set splitter in the center of the ref window
585 Size aSize
= mpRefWin
->GetOutputSize();
586 Point aPos
= Point( aSize
.Width()/2 , aSize
.Height()/2);
587 if ( mnLastSplitPos
!= mnSplitPos
&& mnLastSplitPos
> 5 )
589 // restore last pos if it was a useful position (>5)
591 aPos
.X() = mnLastSplitPos
;
593 aPos
.Y() = mnLastSplitPos
;
596 ImplSplitMousePos( aPos
);
598 ImplSplitMousePos( aPos
);
599 long nTemp
= mnSplitPos
;
601 SetSplitPosPixel( aPos
.X() );
603 SetSplitPosPixel( aPos
.Y() );
604 mnLastSplitPos
= nTemp
;
610 // -----------------------------------------------------------------------
612 void Splitter::GetFocus()
614 if( !ImplSplitterActive() )
615 ImplRestoreSplitter();
620 // -----------------------------------------------------------------------
622 void Splitter::LoseFocus()
626 KeyCode
aReturnKey( KEY_RETURN
);
627 ImplKbdTracking( aReturnKey
);
628 mbKbdSplitting
= sal_False
;
633 // -----------------------------------------------------------------------
635 void Splitter::KeyInput( const KeyEvent
& rKEvt
)
642 Splitter
*pSibling
= ImplFindSibling();
643 KeyCode aKeyCode
= rKEvt
.GetKeyCode();
644 sal_uInt16 nCode
= aKeyCode
.GetCode();
651 ImplStartKbdSplitting();
652 ImplKbdTracking( aKeyCode
);
658 pSibling
->GrabFocus();
659 pSibling
->KeyInput( rKEvt
);
667 ImplStartKbdSplitting();
668 ImplKbdTracking( aKeyCode
);
674 pSibling
->GrabFocus();
675 pSibling
->KeyInput( rKEvt
);
681 if( ImplSplitterActive() )
685 KeyCode
aKey( KEY_ESCAPE
);
686 ImplKbdTracking( aKey
);
695 ImplSplitMousePos( aPos
);
697 ImplSplitMousePos( aPos
);
698 long nTemp
= mnSplitPos
;
700 SetSplitPosPixel( aPos
.X() );
702 SetSplitPosPixel( aPos
.Y() );
703 mnLastSplitPos
= nTemp
;
707 // Shift-Del deletes both splitters
708 if( aKeyCode
.IsShift() && pSibling
)
709 pSibling
->KeyInput( rKEvt
);
711 GrabFocusToDocument();
717 ImplKbdTracking( aKeyCode
);
719 GrabFocusToDocument();
723 ImplKbdTracking( aKeyCode
);
724 GrabFocusToDocument();
726 default: // let any key input fix the splitter
727 Window::KeyInput( rKEvt
);
728 GrabFocusToDocument();
734 // -----------------------------------------------------------------------
736 long Splitter::Notify( NotifyEvent
& rNEvt
)
738 return Window::Notify( rNEvt
);
741 // -----------------------------------------------------------------------
743 void Splitter::DataChanged( const DataChangedEvent
& rDCEvt
)
745 Window::DataChanged( rDCEvt
);
746 if( rDCEvt
.GetType() == DATACHANGED_SETTINGS
)
748 const AllSettings
* pOldSettings
= rDCEvt
.GetOldSettings();
752 Color oldFaceColor
= pOldSettings
->GetStyleSettings().GetFaceColor();
753 Color newFaceColor
= Application::GetSettings().GetStyleSettings().GetFaceColor();
754 if( oldFaceColor
.IsDark() != newFaceColor
.IsDark() )
756 if( newFaceColor
.IsDark() )
757 SetBackground( ImplWhiteWall::get() );
759 SetBackground( ImplBlackWall::get() );
764 // -----------------------------------------------------------------------
766 void Splitter::Paint( const Rectangle
& rPaintRect
)
768 DrawRect( rPaintRect
);
770 Polygon
aPoly( rPaintRect
);
771 PolyPolygon
aPolyPoly( aPoly
);
772 DrawTransparent( aPolyPoly
, 85 );
776 LineInfo
aInfo( LINE_DASH
);
777 //aInfo.SetDashLen( 2 );
778 //aInfo.SetDashCount( 1 );
779 aInfo
.SetDistance( 1 );
780 aInfo
.SetDotLen( 2 );
781 aInfo
.SetDotCount( 3 );
783 DrawPolyLine( aPoly
, aInfo
);
787 DrawRect( rPaintRect
);
791 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */