update dev300-m58
[ooovba.git] / vcl / source / window / split.cxx
blobb8d77fe37deed9e518fa63579f3fe55a167652fc
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: split.cxx,v $
10 * $Revision: 1.23 $
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"
34 #ifndef _SV_RC_H
35 #include <tools/rc.h>
36 #endif
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>
48 namespace
50 struct ImplBlackWall
51 : public rtl::StaticWithInit<Wallpaper, ImplBlackWall> {
52 Wallpaper operator () () {
53 return Wallpaper(COL_BLACK);
56 struct ImplWhiteWall
57 : public rtl::StaticWithInit<Wallpaper, ImplWhiteWall> {
58 Wallpaper operator () () {
59 return Wallpaper(COL_LIGHTGRAY);
61 };
64 // =======================================================================
66 void Splitter::ImplInitSplitterData()
68 ImplGetWindowImpl()->mbSplitter = TRUE;
69 mpRefWin = NULL;
70 mnSplitPos = 0;
71 mnLastSplitPos = 0;
72 mnStartSplitPos = 0;
73 mbDragFull = FALSE;
74 mbKbdSplitting = FALSE;
75 mbInKeyEvent = 0;
76 mnKeyboardStepSize = SPLITTER_DEFAULTSTEPSIZE;
79 // -----------------------------------------------------------------------
81 void Splitter::ImplInit( Window* pParent, WinBits nWinStyle )
83 Window::ImplInit( pParent, nWinStyle, NULL );
85 mpRefWin = pParent;
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;
96 mbHorzSplit = TRUE;
97 SetSizePixel( Size( nB, nA ) );
99 else
101 ePointerStyle = POINTER_VSPLIT;
102 mbHorzSplit = FALSE;
103 SetSizePixel( Size( nA, nB ) );
106 SetPointer( Pointer( ePointerStyle ) );
108 if( GetSettings().GetStyleSettings().GetFaceColor().IsDark() )
109 SetBackground( ImplWhiteWall::get() );
110 else
111 SetBackground( ImplBlackWall::get() );
113 TaskPaneList *pTList = GetSystemWindow()->GetTaskPaneList();
114 pTList->AddWindow( this );
117 // -----------------------------------------------------------------------
119 void Splitter::ImplSplitMousePos( Point& rPos )
121 if ( mbHorzSplit )
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;
128 else
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 );
143 if ( mbHorzSplit )
145 aInvRect.Left() = maDragPos.X() - 1;
146 aInvRect.Right() = maDragPos.X() + 1;
148 else
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) )
178 Show();
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;
210 while( pWin )
212 if( pWin->ImplIsSplitter() )
214 pSplitter = (Splitter*) pWin;
215 if( pSplitter != this && IsHorizontal() != pSplitter->IsHorizontal() )
216 return pSplitter;
218 pWin = pWin->GetWindow( WINDOW_NEXT );
220 return NULL;
223 // -----------------------------------------------------------------------
225 BOOL Splitter::ImplSplitterActive()
227 // is splitter in document or at scrollbar handle ?
229 BOOL bActive = TRUE;
230 const StyleSettings& rSettings = GetSettings().GetStyleSettings();
231 long nA = rSettings.GetScrollBarSize();
232 long nB = rSettings.GetSplitSize();
234 Size aSize = GetOutputSize();
235 if ( mbHorzSplit )
237 if( aSize.Width() == nB && aSize.Height() == nA )
238 bActive = FALSE;
240 else
242 if( aSize.Width() == nA && aSize.Height() == nB )
243 bActive = FALSE;
245 return bActive;
248 // -----------------------------------------------------------------------
250 void Splitter::MouseButtonDown( const MouseEvent& rMEvt )
252 if ( rMEvt.GetClicks() == 2 )
254 if ( mnLastSplitPos != mnSplitPos )
256 StartSplit();
257 Point aPos = rMEvt.GetPosPixel();
258 if ( mbHorzSplit )
259 aPos.X() = mnLastSplitPos;
260 else
261 aPos.Y() = mnLastSplitPos;
262 ImplSplitMousePos( aPos );
263 Splitting( aPos );
264 ImplSplitMousePos( aPos );
265 long nTemp = mnSplitPos;
266 if ( mbHorzSplit )
267 SetSplitPosPixel( aPos.X() );
268 else
269 SetSplitPosPixel( aPos.Y() );
270 mnLastSplitPos = nTemp;
271 Split();
272 EndSplit();
275 else
276 StartDrag();
279 // -----------------------------------------------------------------------
281 void Splitter::Tracking( const TrackingEvent& rTEvt )
283 if ( rTEvt.IsTrackingEnded() )
285 if ( !mbDragFull )
286 ImplDrawSplitter();
288 if ( !rTEvt.IsTrackingCanceled() )
290 long nNewPos;
291 if ( mbHorzSplit )
292 nNewPos = maDragPos.X();
293 else
294 nNewPos = maDragPos.Y();
295 if ( nNewPos != mnStartSplitPos )
297 SetSplitPosPixel( nNewPos );
298 mnLastSplitPos = 0;
299 Split();
301 EndSplit();
303 else if ( mbDragFull )
305 SetSplitPosPixel( mnStartSplitPos );
306 Split();
308 mnStartSplitPos = 0;
310 else
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 );
318 if ( mbHorzSplit )
320 if ( aNewPos.X() == maDragPos.X() )
321 return;
323 else
325 if ( aNewPos.Y() == maDragPos.Y() )
326 return;
329 if ( mbDragFull )
331 maDragPos = aNewPos;
332 long nNewPos;
333 if ( mbHorzSplit )
334 nNewPos = maDragPos.X();
335 else
336 nNewPos = maDragPos.Y();
337 if ( nNewPos != mnSplitPos )
339 SetSplitPosPixel( nNewPos );
340 mnLastSplitPos = 0;
341 Split();
344 GetParent()->Update();
346 else
348 ImplDrawSplitter();
349 maDragPos = aNewPos;
350 ImplDrawSplitter();
355 // -----------------------------------------------------------------------
357 void Splitter::ImplKbdTracking( KeyCode aKeyCode )
359 USHORT nCode = aKeyCode.GetCode();
360 if ( nCode == KEY_ESCAPE || nCode == KEY_RETURN )
362 if( !mbKbdSplitting )
363 return;
364 else
365 mbKbdSplitting = FALSE;
367 if ( nCode != KEY_ESCAPE )
369 long nNewPos;
370 if ( mbHorzSplit )
371 nNewPos = maDragPos.X();
372 else
373 nNewPos = maDragPos.Y();
374 if ( nNewPos != mnStartSplitPos )
376 SetSplitPosPixel( nNewPos );
377 mnLastSplitPos = 0;
378 Split();
381 else
383 SetSplitPosPixel( mnStartSplitPos );
384 Split();
385 EndSplit();
387 mnStartSplitPos = 0;
389 else
391 Point aNewPos;
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
398 if( mbHorzSplit )
399 aNewPos = Point( ImplSplitterActive() ? aPos.X() : mnSplitPos, aKeyCode.IsShift() ? 0 : aSize.Height()/2);
400 else
401 aNewPos = Point( aKeyCode.IsShift() ? 0 : aSize.Width()/2, ImplSplitterActive() ? aPos.Y() : mnSplitPos );
403 Point aOldWindowPos = GetPosPixel();
405 int maxiter = 500; // avoid endless loop
406 int delta=0;
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() )
418 delta++;
419 else
420 delta += delta_step;
422 switch( nCode )
424 case KEY_LEFT:
425 aNewPos.X()-=delta;
426 break;
427 case KEY_RIGHT:
428 aNewPos.X()+=delta;
429 break;
430 case KEY_UP:
431 aNewPos.Y()-=delta;
432 break;
433 case KEY_DOWN:
434 aNewPos.Y()+=delta;
435 break;
436 default:
437 maxiter = 0; // leave loop
438 break;
440 ImplSplitMousePos( aNewPos );
441 Splitting( aNewPos );
442 ImplSplitMousePos( aNewPos );
444 if ( mbHorzSplit )
446 if ( aNewPos.X() == maDragPos.X() )
447 continue;
449 else
451 if ( aNewPos.Y() == maDragPos.Y() )
452 continue;
455 maDragPos = aNewPos;
456 long nNewPos;
457 if ( mbHorzSplit )
458 nNewPos = maDragPos.X();
459 else
460 nNewPos = maDragPos.Y();
461 if ( nNewPos != mnSplitPos )
463 SetSplitPosPixel( nNewPos );
464 mnLastSplitPos = 0;
465 Split();
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;
505 if ( !_pRefWin )
506 mpRefWin = GetParent();
507 else
508 mpRefWin = _pRefWin;
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()
529 if ( IsTracking() )
530 return;
532 StartSplit();
534 // Tracking starten
535 StartTracking();
537 // Start-Positon ermitteln
538 maDragPos = mpRefWin->GetPointerPosPixel();
539 ImplSplitMousePos( maDragPos );
540 Splitting( maDragPos );
541 ImplSplitMousePos( maDragPos );
542 if ( mbHorzSplit )
543 mnStartSplitPos = maDragPos.X();
544 else
545 mnStartSplitPos = maDragPos.Y();
547 mbDragFull = (Application::GetSettings().GetStyleSettings().GetDragFullOptions() & DRAGFULL_OPTION_SPLIT) != 0;
548 if ( !mbDragFull )
549 ImplDrawSplitter();
553 // -----------------------------------------------------------------------
555 void Splitter::ImplStartKbdSplitting()
557 if( mbKbdSplitting )
558 return;
560 mbKbdSplitting = TRUE;
562 StartSplit();
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();
570 if( mbHorzSplit )
571 maDragPos = Point( ImplSplitterActive() ? aPos.X() : mnSplitPos, aSize.Height()/2 );
572 else
573 maDragPos = Point( aSize.Width()/2, ImplSplitterActive() ? aPos.Y() : mnSplitPos );
574 ImplSplitMousePos( maDragPos );
575 Splitting( maDragPos );
576 ImplSplitMousePos( maDragPos );
577 if ( mbHorzSplit )
578 mnStartSplitPos = maDragPos.X();
579 else
580 mnStartSplitPos = maDragPos.Y();
583 // -----------------------------------------------------------------------
585 void Splitter::ImplRestoreSplitter()
587 // set splitter in the center of the ref window
588 StartSplit();
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)
594 if ( mbHorzSplit )
595 aPos.X() = mnLastSplitPos;
596 else
597 aPos.Y() = mnLastSplitPos;
600 ImplSplitMousePos( aPos );
601 Splitting( aPos );
602 ImplSplitMousePos( aPos );
603 long nTemp = mnSplitPos;
604 if ( mbHorzSplit )
605 SetSplitPosPixel( aPos.X() );
606 else
607 SetSplitPosPixel( aPos.Y() );
608 mnLastSplitPos = nTemp;
609 Split();
610 EndSplit();
614 // -----------------------------------------------------------------------
616 void Splitter::GetFocus()
618 if( !ImplSplitterActive() )
619 ImplRestoreSplitter();
621 Invalidate();
624 // -----------------------------------------------------------------------
626 void Splitter::LoseFocus()
628 if( mbKbdSplitting )
630 KeyCode aReturnKey( KEY_RETURN );
631 ImplKbdTracking( aReturnKey );
632 mbKbdSplitting = FALSE;
634 Invalidate();
637 // -----------------------------------------------------------------------
639 void Splitter::KeyInput( const KeyEvent& rKEvt )
641 if( mbInKeyEvent )
642 return;
644 mbInKeyEvent = 1;
646 Splitter *pSibling = ImplFindSibling();
647 KeyCode aKeyCode = rKEvt.GetKeyCode();
648 USHORT nCode = aKeyCode.GetCode();
649 switch ( nCode )
651 case KEY_UP:
652 case KEY_DOWN:
653 if( !mbHorzSplit )
655 ImplStartKbdSplitting();
656 ImplKbdTracking( aKeyCode );
658 else
660 if( pSibling )
662 pSibling->GrabFocus();
663 pSibling->KeyInput( rKEvt );
666 break;
667 case KEY_RIGHT:
668 case KEY_LEFT:
669 if( mbHorzSplit )
671 ImplStartKbdSplitting();
672 ImplKbdTracking( aKeyCode );
674 else
676 if( pSibling )
678 pSibling->GrabFocus();
679 pSibling->KeyInput( rKEvt );
682 break;
684 case KEY_DELETE:
685 if( ImplSplitterActive() )
687 if( mbKbdSplitting )
689 KeyCode aKey( KEY_ESCAPE );
690 ImplKbdTracking( aKey );
693 StartSplit();
694 Point aPos;
695 if ( mbHorzSplit )
696 aPos.X() = 0;
697 else
698 aPos.Y() = 0;
699 ImplSplitMousePos( aPos );
700 Splitting( aPos );
701 ImplSplitMousePos( aPos );
702 long nTemp = mnSplitPos;
703 if ( mbHorzSplit )
704 SetSplitPosPixel( aPos.X() );
705 else
706 SetSplitPosPixel( aPos.Y() );
707 mnLastSplitPos = nTemp;
708 Split();
709 EndSplit();
711 // Shift-Del deletes both splitters
712 if( aKeyCode.IsShift() && pSibling )
713 pSibling->KeyInput( rKEvt );
715 GrabFocusToDocument();
717 break;
719 case KEY_ESCAPE:
720 if( mbKbdSplitting )
721 ImplKbdTracking( aKeyCode );
722 else
723 GrabFocusToDocument();
724 break;
726 case KEY_RETURN:
727 ImplKbdTracking( aKeyCode );
728 GrabFocusToDocument();
729 break;
730 default: // let any key input fix the splitter
731 Window::KeyInput( rKEvt );
732 GrabFocusToDocument();
733 break;
735 mbInKeyEvent = 0;
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() );
758 else
759 SetBackground( ImplBlackWall::get() );
764 // -----------------------------------------------------------------------
766 void Splitter::Paint( const Rectangle& rPaintRect )
768 if( HasFocus() || mbKbdSplitting )
770 Color oldFillCol = GetFillColor();
771 Color oldLineCol = GetLineColor();
773 SetLineColor();
774 SetFillColor( GetSettings().GetStyleSettings().GetFaceColor() );
775 DrawRect( rPaintRect );
777 Color aSelectionBorderCol( GetSettings().GetStyleSettings().GetActiveColor() );
778 SetFillColor( aSelectionBorderCol );
779 SetLineColor();
781 Polygon aPoly( rPaintRect );
782 PolyPolygon aPolyPoly( aPoly );
783 DrawTransparent( aPolyPoly, 85 );
785 SetLineColor( aSelectionBorderCol );
786 SetFillColor();
788 if( mbKbdSplitting )
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 );
799 else
800 DrawRect( rPaintRect );
802 SetFillColor( oldFillCol);
803 SetLineColor( oldLineCol);
805 else
807 Window::Paint( rPaintRect );