1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: split.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_vcl.hxx"
37 #include <vcl/event.hxx>
38 #include <vcl/split.hxx>
39 #include <vcl/svapp.hxx>
40 #include <vcl/syswin.hxx>
41 #include <vcl/taskpanelist.hxx>
42 #include <vcl/gradient.hxx>
43 #include <tools/poly.hxx>
44 #include <vcl/lineinfo.hxx>
45 #include <rtl/instance.hxx>
46 #include <vcl/window.h>
51 : public rtl::StaticWithInit
<Wallpaper
, ImplBlackWall
> {
52 Wallpaper
operator () () {
53 return Wallpaper(COL_BLACK
);
57 : public rtl::StaticWithInit
<Wallpaper
, ImplWhiteWall
> {
58 Wallpaper
operator () () {
59 return Wallpaper(COL_LIGHTGRAY
);
64 // =======================================================================
66 void Splitter::ImplInitSplitterData()
68 ImplGetWindowImpl()->mbSplitter
= TRUE
;
74 mbKbdSplitting
= FALSE
;
76 mnKeyboardStepSize
= SPLITTER_DEFAULTSTEPSIZE
;
79 // -----------------------------------------------------------------------
81 void Splitter::ImplInit( Window
* pParent
, WinBits nWinStyle
)
83 Window::ImplInit( pParent
, nWinStyle
, NULL
);
87 const StyleSettings
& rSettings
= GetSettings().GetStyleSettings();
88 long nA
= rSettings
.GetScrollBarSize();
89 long nB
= rSettings
.GetSplitSize();
91 PointerStyle ePointerStyle
;
93 if ( nWinStyle
& WB_HSCROLL
)
95 ePointerStyle
= POINTER_HSPLIT
;
97 SetSizePixel( Size( nB
, nA
) );
101 ePointerStyle
= POINTER_VSPLIT
;
103 SetSizePixel( Size( nA
, nB
) );
106 SetPointer( Pointer( ePointerStyle
) );
108 if( GetSettings().GetStyleSettings().GetFaceColor().IsDark() )
109 SetBackground( ImplWhiteWall::get() );
111 SetBackground( ImplBlackWall::get() );
113 TaskPaneList
*pTList
= GetSystemWindow()->GetTaskPaneList();
114 pTList
->AddWindow( this );
117 // -----------------------------------------------------------------------
119 void Splitter::ImplSplitMousePos( Point
& rPos
)
123 if ( rPos
.X() > maDragRect
.Right()-1 )
124 rPos
.X() = maDragRect
.Right()-1;
125 if ( rPos
.X() < maDragRect
.Left()+1 )
126 rPos
.X() = maDragRect
.Left()+1;
130 if ( rPos
.Y() > maDragRect
.Bottom()-1 )
131 rPos
.Y() = maDragRect
.Bottom()-1;
132 if ( rPos
.Y() < maDragRect
.Top()+1 )
133 rPos
.Y() = maDragRect
.Top()+1;
137 // -----------------------------------------------------------------------
139 void Splitter::ImplDrawSplitter()
141 Rectangle
aInvRect( maDragRect
);
145 aInvRect
.Left() = maDragPos
.X() - 1;
146 aInvRect
.Right() = maDragPos
.X() + 1;
150 aInvRect
.Top() = maDragPos
.Y() - 1;
151 aInvRect
.Bottom() = maDragPos
.Y() + 1;
154 mpRefWin
->InvertTracking( mpRefWin
->PixelToLogic(aInvRect
), SHOWTRACK_SPLIT
);
157 // -----------------------------------------------------------------------
159 Splitter::Splitter( Window
* pParent
, WinBits nStyle
) :
160 Window( WINDOW_SPLITTER
)
162 ImplInitSplitterData();
163 ImplInit( pParent
, nStyle
);
166 // -----------------------------------------------------------------------
168 Splitter::Splitter( Window
* pParent
, const ResId
& rResId
) :
169 Window( WINDOW_SPLITTER
)
171 ImplInitSplitterData();
172 rResId
.SetRT( RSC_SPLITTER
);
173 WinBits nStyle
= ImplInitRes( rResId
);
174 ImplInit( pParent
, nStyle
);
175 ImplLoadRes( rResId
);
177 if ( !(nStyle
& WB_HIDE
) )
181 // -----------------------------------------------------------------------
183 Splitter::~Splitter()
185 TaskPaneList
*pTList
= GetSystemWindow()->GetTaskPaneList();
186 pTList
->RemoveWindow( this );
189 // -----------------------------------------------------------------------
191 void Splitter::SetKeyboardStepSize( long nStepSize
)
193 mnKeyboardStepSize
= nStepSize
;
196 // -----------------------------------------------------------------------
198 long Splitter::GetKeyboardStepSize() const
200 return mnKeyboardStepSize
;
203 // -----------------------------------------------------------------------
205 Splitter
* Splitter::ImplFindSibling()
207 // look for another splitter with the same parent but different orientation
208 Window
*pWin
= GetParent()->GetWindow( WINDOW_FIRSTCHILD
);
209 Splitter
*pSplitter
= NULL
;
212 if( pWin
->ImplIsSplitter() )
214 pSplitter
= (Splitter
*) pWin
;
215 if( pSplitter
!= this && IsHorizontal() != pSplitter
->IsHorizontal() )
218 pWin
= pWin
->GetWindow( WINDOW_NEXT
);
223 // -----------------------------------------------------------------------
225 BOOL
Splitter::ImplSplitterActive()
227 // is splitter in document or at scrollbar handle ?
230 const StyleSettings
& rSettings
= GetSettings().GetStyleSettings();
231 long nA
= rSettings
.GetScrollBarSize();
232 long nB
= rSettings
.GetSplitSize();
234 Size aSize
= GetOutputSize();
237 if( aSize
.Width() == nB
&& aSize
.Height() == nA
)
242 if( aSize
.Width() == nA
&& aSize
.Height() == nB
)
248 // -----------------------------------------------------------------------
250 void Splitter::MouseButtonDown( const MouseEvent
& rMEvt
)
252 if ( rMEvt
.GetClicks() == 2 )
254 if ( mnLastSplitPos
!= mnSplitPos
)
257 Point aPos
= rMEvt
.GetPosPixel();
259 aPos
.X() = mnLastSplitPos
;
261 aPos
.Y() = mnLastSplitPos
;
262 ImplSplitMousePos( aPos
);
264 ImplSplitMousePos( aPos
);
265 long nTemp
= mnSplitPos
;
267 SetSplitPosPixel( aPos
.X() );
269 SetSplitPosPixel( aPos
.Y() );
270 mnLastSplitPos
= nTemp
;
279 // -----------------------------------------------------------------------
281 void Splitter::Tracking( const TrackingEvent
& rTEvt
)
283 if ( rTEvt
.IsTrackingEnded() )
288 if ( !rTEvt
.IsTrackingCanceled() )
292 nNewPos
= maDragPos
.X();
294 nNewPos
= maDragPos
.Y();
295 if ( nNewPos
!= mnStartSplitPos
)
297 SetSplitPosPixel( nNewPos
);
303 else if ( mbDragFull
)
305 SetSplitPosPixel( mnStartSplitPos
);
312 //Point aNewPos = mpRefWin->ScreenToOutputPixel( OutputToScreenPixel( rTEvt.GetMouseEvent().GetPosPixel() ) );
313 Point aNewPos
= mpRefWin
->NormalizedScreenToOutputPixel( OutputToNormalizedScreenPixel( rTEvt
.GetMouseEvent().GetPosPixel() ) );
314 ImplSplitMousePos( aNewPos
);
315 Splitting( aNewPos
);
316 ImplSplitMousePos( aNewPos
);
320 if ( aNewPos
.X() == maDragPos
.X() )
325 if ( aNewPos
.Y() == maDragPos
.Y() )
334 nNewPos
= maDragPos
.X();
336 nNewPos
= maDragPos
.Y();
337 if ( nNewPos
!= mnSplitPos
)
339 SetSplitPosPixel( nNewPos
);
344 GetParent()->Update();
355 // -----------------------------------------------------------------------
357 void Splitter::ImplKbdTracking( KeyCode aKeyCode
)
359 USHORT nCode
= aKeyCode
.GetCode();
360 if ( nCode
== KEY_ESCAPE
|| nCode
== KEY_RETURN
)
362 if( !mbKbdSplitting
)
365 mbKbdSplitting
= FALSE
;
367 if ( nCode
!= KEY_ESCAPE
)
371 nNewPos
= maDragPos
.X();
373 nNewPos
= maDragPos
.Y();
374 if ( nNewPos
!= mnStartSplitPos
)
376 SetSplitPosPixel( nNewPos
);
383 SetSplitPosPixel( mnStartSplitPos
);
392 Size aSize
= mpRefWin
->GetOutputSize();
393 Point aPos
= GetPosPixel();
394 // depending on the position calc allows continous moves or snaps to row/columns
395 // continous mode is active when position is at the origin or end of the splitter
396 // otherwise snap mode is active
397 // default here is snap, holding shift sets continous mode
399 aNewPos
= Point( ImplSplitterActive() ? aPos
.X() : mnSplitPos
, aKeyCode
.IsShift() ? 0 : aSize
.Height()/2);
401 aNewPos
= Point( aKeyCode
.IsShift() ? 0 : aSize
.Width()/2, ImplSplitterActive() ? aPos
.Y() : mnSplitPos
);
403 Point aOldWindowPos
= GetPosPixel();
405 int maxiter
= 500; // avoid endless loop
407 int delta_step
= mbHorzSplit
? aSize
.Width()/10 : aSize
.Height()/10;
409 // use the specified step size if it was set
410 if( mnKeyboardStepSize
!= SPLITTER_DEFAULTSTEPSIZE
)
411 delta_step
= mnKeyboardStepSize
;
413 while( maxiter
-- && aOldWindowPos
== GetPosPixel() )
415 // inc/dec position until application performs changes
416 // thus a single key press really moves the splitter
417 if( aKeyCode
.IsShift() )
437 maxiter
= 0; // leave loop
440 ImplSplitMousePos( aNewPos
);
441 Splitting( aNewPos
);
442 ImplSplitMousePos( aNewPos
);
446 if ( aNewPos
.X() == maDragPos
.X() )
451 if ( aNewPos
.Y() == maDragPos
.Y() )
458 nNewPos
= maDragPos
.X();
460 nNewPos
= maDragPos
.Y();
461 if ( nNewPos
!= mnSplitPos
)
463 SetSplitPosPixel( nNewPos
);
467 GetParent()->Update();
472 // -----------------------------------------------------------------------
474 void Splitter::StartSplit()
476 maStartSplitHdl
.Call( this );
479 // -----------------------------------------------------------------------
481 void Splitter::Split()
483 maSplitHdl
.Call( this );
486 // -----------------------------------------------------------------------
488 void Splitter::EndSplit()
490 if ( maEndSplitHdl
.IsSet() )
491 maEndSplitHdl
.Call( this );
494 // -----------------------------------------------------------------------
496 void Splitter::Splitting( Point
& /* rSplitPos */ )
500 // -----------------------------------------------------------------------
502 void Splitter::SetDragRectPixel( const Rectangle
& rDragRect
, Window
* _pRefWin
)
504 maDragRect
= rDragRect
;
506 mpRefWin
= GetParent();
511 // -----------------------------------------------------------------------
513 void Splitter::SetSplitPosPixel( long nNewPos
)
515 mnSplitPos
= nNewPos
;
518 // -----------------------------------------------------------------------
520 void Splitter::SetLastSplitPosPixel( long nNewPos
)
522 mnLastSplitPos
= nNewPos
;
525 // -----------------------------------------------------------------------
527 void Splitter::StartDrag()
537 // Start-Positon ermitteln
538 maDragPos
= mpRefWin
->GetPointerPosPixel();
539 ImplSplitMousePos( maDragPos
);
540 Splitting( maDragPos
);
541 ImplSplitMousePos( maDragPos
);
543 mnStartSplitPos
= maDragPos
.X();
545 mnStartSplitPos
= maDragPos
.Y();
547 mbDragFull
= (Application::GetSettings().GetStyleSettings().GetDragFullOptions() & DRAGFULL_OPTION_SPLIT
) != 0;
553 // -----------------------------------------------------------------------
555 void Splitter::ImplStartKbdSplitting()
560 mbKbdSplitting
= TRUE
;
564 // determine start position
565 // because we have no mouse position we take either the position
566 // of the splitter window or the last split position
567 // the other coordinate is just the center of the reference window
568 Size aSize
= mpRefWin
->GetOutputSize();
569 Point aPos
= GetPosPixel();
571 maDragPos
= Point( ImplSplitterActive() ? aPos
.X() : mnSplitPos
, aSize
.Height()/2 );
573 maDragPos
= Point( aSize
.Width()/2, ImplSplitterActive() ? aPos
.Y() : mnSplitPos
);
574 ImplSplitMousePos( maDragPos
);
575 Splitting( maDragPos
);
576 ImplSplitMousePos( maDragPos
);
578 mnStartSplitPos
= maDragPos
.X();
580 mnStartSplitPos
= maDragPos
.Y();
583 // -----------------------------------------------------------------------
585 void Splitter::ImplRestoreSplitter()
587 // set splitter in the center of the ref window
589 Size aSize
= mpRefWin
->GetOutputSize();
590 Point aPos
= Point( aSize
.Width()/2 , aSize
.Height()/2);
591 if ( mnLastSplitPos
!= mnSplitPos
&& mnLastSplitPos
> 5 )
593 // restore last pos if it was a useful position (>5)
595 aPos
.X() = mnLastSplitPos
;
597 aPos
.Y() = mnLastSplitPos
;
600 ImplSplitMousePos( aPos
);
602 ImplSplitMousePos( aPos
);
603 long nTemp
= mnSplitPos
;
605 SetSplitPosPixel( aPos
.X() );
607 SetSplitPosPixel( aPos
.Y() );
608 mnLastSplitPos
= nTemp
;
614 // -----------------------------------------------------------------------
616 void Splitter::GetFocus()
618 if( !ImplSplitterActive() )
619 ImplRestoreSplitter();
624 // -----------------------------------------------------------------------
626 void Splitter::LoseFocus()
630 KeyCode
aReturnKey( KEY_RETURN
);
631 ImplKbdTracking( aReturnKey
);
632 mbKbdSplitting
= FALSE
;
637 // -----------------------------------------------------------------------
639 void Splitter::KeyInput( const KeyEvent
& rKEvt
)
646 Splitter
*pSibling
= ImplFindSibling();
647 KeyCode aKeyCode
= rKEvt
.GetKeyCode();
648 USHORT nCode
= aKeyCode
.GetCode();
655 ImplStartKbdSplitting();
656 ImplKbdTracking( aKeyCode
);
662 pSibling
->GrabFocus();
663 pSibling
->KeyInput( rKEvt
);
671 ImplStartKbdSplitting();
672 ImplKbdTracking( aKeyCode
);
678 pSibling
->GrabFocus();
679 pSibling
->KeyInput( rKEvt
);
685 if( ImplSplitterActive() )
689 KeyCode
aKey( KEY_ESCAPE
);
690 ImplKbdTracking( aKey
);
699 ImplSplitMousePos( aPos
);
701 ImplSplitMousePos( aPos
);
702 long nTemp
= mnSplitPos
;
704 SetSplitPosPixel( aPos
.X() );
706 SetSplitPosPixel( aPos
.Y() );
707 mnLastSplitPos
= nTemp
;
711 // Shift-Del deletes both splitters
712 if( aKeyCode
.IsShift() && pSibling
)
713 pSibling
->KeyInput( rKEvt
);
715 GrabFocusToDocument();
721 ImplKbdTracking( aKeyCode
);
723 GrabFocusToDocument();
727 ImplKbdTracking( aKeyCode
);
728 GrabFocusToDocument();
730 default: // let any key input fix the splitter
731 Window::KeyInput( rKEvt
);
732 GrabFocusToDocument();
738 // -----------------------------------------------------------------------
740 long Splitter::Notify( NotifyEvent
& rNEvt
)
742 return Window::Notify( rNEvt
);
745 // -----------------------------------------------------------------------
747 void Splitter::DataChanged( const DataChangedEvent
& rDCEvt
)
749 Window::DataChanged( rDCEvt
);
750 if( rDCEvt
.GetType() == DATACHANGED_SETTINGS
)
752 Color oldFaceColor
= ((AllSettings
*) rDCEvt
.GetData())->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 if( HasFocus() || mbKbdSplitting
)
770 Color oldFillCol
= GetFillColor();
771 Color oldLineCol
= GetLineColor();
774 SetFillColor( GetSettings().GetStyleSettings().GetFaceColor() );
775 DrawRect( rPaintRect
);
777 Color
aSelectionBorderCol( GetSettings().GetStyleSettings().GetActiveColor() );
778 SetFillColor( aSelectionBorderCol
);
781 Polygon
aPoly( rPaintRect
);
782 PolyPolygon
aPolyPoly( aPoly
);
783 DrawTransparent( aPolyPoly
, 85 );
785 SetLineColor( aSelectionBorderCol
);
790 LineInfo
aInfo( LINE_DASH
);
791 //aInfo.SetDashLen( 2 );
792 //aInfo.SetDashCount( 1 );
793 aInfo
.SetDistance( 1 );
794 aInfo
.SetDotLen( 2 );
795 aInfo
.SetDotCount( 1 );
797 DrawPolyLine( aPoly
, aInfo
);
800 DrawRect( rPaintRect
);
802 SetFillColor( oldFillCol
);
803 SetLineColor( oldLineCol
);
807 Window::Paint( rPaintRect
);