/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace ::com::sun::star::uno; // useful caption height for title bar buttons #define MIN_CAPTION_HEIGHT 18 namespace vcl { void Window::ImplCalcSymbolRect( tools::Rectangle& rRect ) { // Add border, not shown in the non-default representation, // as we want to use it for small buttons rRect.AdjustLeft( -1 ); rRect.AdjustTop( -1 ); rRect.AdjustRight( 1 ); rRect.AdjustBottom( 1 ); // we leave 5% room between the symbol and the button border tools::Long nExtraWidth = ((rRect.GetWidth()*50)+500)/1000; tools::Long nExtraHeight = ((rRect.GetHeight()*50)+500)/1000; rRect.AdjustLeft(nExtraWidth ); rRect.AdjustRight( -nExtraWidth ); rRect.AdjustTop(nExtraHeight ); rRect.AdjustBottom( -nExtraHeight ); } } /* namespace vcl */ static void ImplDrawBrdWinSymbol( vcl::RenderContext* pDev, const tools::Rectangle& rRect, SymbolType eSymbol ) { // we leave 5% room between the symbol and the button border DecorationView aDecoView( pDev ); tools::Rectangle aTempRect = rRect; vcl::Window::ImplCalcSymbolRect( aTempRect ); aDecoView.DrawSymbol( aTempRect, eSymbol, pDev->GetSettings().GetStyleSettings().GetButtonTextColor() ); } static void ImplDrawBrdWinSymbolButton( vcl::RenderContext* pDev, const tools::Rectangle& rRect, SymbolType eSymbol, DrawButtonFlags nState ) { bool bMouseOver(nState & DrawButtonFlags::Highlight); nState &= ~DrawButtonFlags::Highlight; tools::Rectangle aTempRect; vcl::Window *pWin = pDev->GetOwnerWindow(); if( pWin ) { if( bMouseOver ) { // provide a bright background for selection effect pDev->SetFillColor( pDev->GetSettings().GetStyleSettings().GetWindowColor() ); pDev->SetLineColor(); pDev->DrawRect( rRect ); pWin->DrawSelectionBackground( rRect, 2, bool(nState & DrawButtonFlags::Pressed), true ); } aTempRect = rRect; aTempRect.AdjustLeft(3 ); aTempRect.AdjustRight( -4 ); aTempRect.AdjustTop(3 ); aTempRect.AdjustBottom( -4 ); } else { DecorationView aDecoView( pDev ); aTempRect = aDecoView.DrawButton( rRect, nState|DrawButtonFlags::Flat ); } ImplDrawBrdWinSymbol( pDev, aTempRect, eSymbol ); } ImplBorderWindowView::~ImplBorderWindowView() { } bool ImplBorderWindowView::MouseMove( const MouseEvent& ) { return false; } bool ImplBorderWindowView::MouseButtonDown( const MouseEvent& ) { return false; } bool ImplBorderWindowView::Tracking( const TrackingEvent& ) { return false; } OUString ImplBorderWindowView::RequestHelp( const Point&, tools::Rectangle& ) { return OUString(); } tools::Rectangle ImplBorderWindowView::GetMenuRect() const { return tools::Rectangle(); } void ImplBorderWindowView::ImplInitTitle(ImplBorderFrameData* pData) { ImplBorderWindow* pBorderWindow = pData->mpBorderWindow; if ( !(pBorderWindow->GetStyle() & (WB_MOVEABLE | WB_POPUP)) || (pData->mnTitleType == BorderWindowTitleType::NONE) ) { pData->mnTitleType = BorderWindowTitleType::NONE; pData->mnTitleHeight = 0; } else { const StyleSettings& rStyleSettings = pData->mpOutDev->GetSettings().GetStyleSettings(); if (pData->mnTitleType == BorderWindowTitleType::Tearoff) pData->mnTitleHeight = ToolBox::ImplGetDragWidth(*pData->mpBorderWindow, false) + 2; else { if (pData->mnTitleType == BorderWindowTitleType::Small) { pBorderWindow->SetPointFont(*pBorderWindow->GetOutDev(), rStyleSettings.GetFloatTitleFont() ); pData->mnTitleHeight = rStyleSettings.GetFloatTitleHeight(); } else // pData->mnTitleType == BorderWindowTitleType::Normal { // FIXME RenderContext pBorderWindow->SetPointFont(*pBorderWindow->GetOutDev(), rStyleSettings.GetTitleFont()); pData->mnTitleHeight = rStyleSettings.GetTitleHeight(); } tools::Long nTextHeight = pBorderWindow->GetTextHeight(); if (nTextHeight > pData->mnTitleHeight) pData->mnTitleHeight = nTextHeight; } } } BorderWindowHitTest ImplBorderWindowView::ImplHitTest( ImplBorderFrameData const * pData, const Point& rPos ) { ImplBorderWindow* pBorderWindow = pData->mpBorderWindow; if ( pData->maTitleRect.Contains( rPos ) ) { if ( pData->maCloseRect.Contains( rPos ) ) return BorderWindowHitTest::Close; else if ( pData->maMenuRect.Contains( rPos ) ) return BorderWindowHitTest::Menu; else if ( pData->maDockRect.Contains( rPos ) ) return BorderWindowHitTest::Dock; else if ( pData->maHideRect.Contains( rPos ) ) return BorderWindowHitTest::Hide; else if ( pData->maHelpRect.Contains( rPos ) ) return BorderWindowHitTest::Help; else return BorderWindowHitTest::Title; } if (pBorderWindow->GetStyle() & WB_SIZEABLE) { tools::Long nSizeWidth = pData->mnNoTitleTop+pData->mnTitleHeight; if ( nSizeWidth < 16 ) nSizeWidth = 16; // no corner resize for floating toolbars, which would lead to jumps while formatting // setting nSizeWidth = 0 will only return pure left,top,right,bottom if( pBorderWindow->GetStyle() & (WB_OWNERDRAWDECORATION | WB_POPUP) ) nSizeWidth = 0; if ( rPos.X() < pData->mnLeftBorder ) { if ( rPos.Y() < nSizeWidth ) return BorderWindowHitTest::TopLeft; else if ( rPos.Y() >= pData->mnHeight-nSizeWidth ) return BorderWindowHitTest::BottomLeft; else return BorderWindowHitTest::Left; } else if ( rPos.X() >= pData->mnWidth-pData->mnRightBorder ) { if ( rPos.Y() < nSizeWidth ) return BorderWindowHitTest::TopRight; else if ( rPos.Y() >= pData->mnHeight-nSizeWidth ) return BorderWindowHitTest::BottomRight; else return BorderWindowHitTest::Right; } else if ( rPos.Y() < pData->mnNoTitleTop ) { if ( rPos.X() < nSizeWidth ) return BorderWindowHitTest::TopLeft; else if ( rPos.X() >= pData->mnWidth-nSizeWidth ) return BorderWindowHitTest::TopRight; else return BorderWindowHitTest::Top; } else if ( rPos.Y() >= pData->mnHeight-pData->mnBottomBorder ) { if ( rPos.X() < nSizeWidth ) return BorderWindowHitTest::BottomLeft; else if ( rPos.X() >= pData->mnWidth-nSizeWidth ) return BorderWindowHitTest::BottomRight; else return BorderWindowHitTest::Bottom; } } return BorderWindowHitTest::NONE; } void ImplBorderWindowView::ImplMouseMove( ImplBorderFrameData* pData, const MouseEvent& rMEvt ) { DrawButtonFlags oldCloseState = pData->mnCloseState; DrawButtonFlags oldMenuState = pData->mnMenuState; pData->mnCloseState &= ~DrawButtonFlags::Highlight; pData->mnMenuState &= ~DrawButtonFlags::Highlight; Point aMousePos = rMEvt.GetPosPixel(); BorderWindowHitTest nHitTest = ImplHitTest( pData, aMousePos ); PointerStyle ePtrStyle = PointerStyle::Arrow; if ( nHitTest & BorderWindowHitTest::Left ) ePtrStyle = PointerStyle::WindowWSize; else if ( nHitTest & BorderWindowHitTest::Right ) ePtrStyle = PointerStyle::WindowESize; else if ( nHitTest & BorderWindowHitTest::Top ) ePtrStyle = PointerStyle::WindowNSize; else if ( nHitTest & BorderWindowHitTest::Bottom ) ePtrStyle = PointerStyle::WindowSSize; else if ( nHitTest & BorderWindowHitTest::TopLeft ) ePtrStyle = PointerStyle::WindowNWSize; else if ( nHitTest & BorderWindowHitTest::BottomRight ) ePtrStyle = PointerStyle::WindowSESize; else if ( nHitTest & BorderWindowHitTest::TopRight ) ePtrStyle = PointerStyle::WindowNESize; else if ( nHitTest & BorderWindowHitTest::BottomLeft ) ePtrStyle = PointerStyle::WindowSWSize; else if ( nHitTest & BorderWindowHitTest::Close ) pData->mnCloseState |= DrawButtonFlags::Highlight; else if ( nHitTest & BorderWindowHitTest::Menu ) pData->mnMenuState |= DrawButtonFlags::Highlight; else if ( nHitTest & BorderWindowHitTest::Title && pData->mnTitleType == BorderWindowTitleType::Tearoff && !rMEvt.IsLeaveWindow() ) ePtrStyle = PointerStyle::Move; pData->mpBorderWindow->SetPointer( ePtrStyle ); if( pData->mnCloseState != oldCloseState ) pData->mpBorderWindow->Invalidate( pData->maCloseRect ); if( pData->mnMenuState != oldMenuState ) pData->mpBorderWindow->Invalidate( pData->maMenuRect ); } OUString ImplBorderWindowView::ImplRequestHelp( ImplBorderFrameData const * pData, const Point& rPos, tools::Rectangle& rHelpRect ) { TranslateId pHelpId; OUString aHelpStr; BorderWindowHitTest nHitTest = ImplHitTest( pData, rPos ); if ( nHitTest != BorderWindowHitTest::NONE ) { if ( nHitTest & BorderWindowHitTest::Close ) { pHelpId = SV_HELPTEXT_CLOSE; rHelpRect = pData->maCloseRect; } else if ( nHitTest & BorderWindowHitTest::Dock ) { pHelpId = SV_HELPTEXT_MAXIMIZE; rHelpRect = pData->maDockRect; } else if ( nHitTest & BorderWindowHitTest::Hide ) { pHelpId = SV_HELPTEXT_MINIMIZE; rHelpRect = pData->maHideRect; } else if ( nHitTest & BorderWindowHitTest::Help ) { pHelpId = SV_HELPTEXT_HELP; rHelpRect = pData->maHelpRect; } else if ( nHitTest & BorderWindowHitTest::Title ) { if( !pData->maTitleRect.IsEmpty() ) { // tooltip only if title truncated if( pData->mbTitleClipped ) { rHelpRect = pData->maTitleRect; // no help id, use window title as help string aHelpStr = pData->mpBorderWindow->GetText(); } } } } if (pHelpId) aHelpStr = VclResId(pHelpId); return aHelpStr; } tools::Long ImplBorderWindowView::ImplCalcTitleWidth( const ImplBorderFrameData* pData ) { // title is not visible therefore no width if ( !pData->mnTitleHeight ) return 0; ImplBorderWindow* pBorderWindow = pData->mpBorderWindow; tools::Long nTitleWidth = pBorderWindow->GetTextWidth( pBorderWindow->GetText() )+6; auto nCloseRectWidth = pData->maCloseRect.GetWidth(); assert(nCloseRectWidth >= 0 && "coverity 2023.12.2"); nTitleWidth += nCloseRectWidth; auto nDockRectWidth = pData->maDockRect.GetWidth(); assert(nDockRectWidth >= 0 && "coverity 2023.12.2"); nTitleWidth += nDockRectWidth; auto nMenuRectWidth = pData->maMenuRect.GetWidth(); assert(nMenuRectWidth >= 0 && "coverity 2023.12.2"); nTitleWidth += nMenuRectWidth; auto nHideRectWidth = pData->maHideRect.GetWidth(); assert(nHideRectWidth >= 0 && "coverity 2023.12.2"); nTitleWidth += nHideRectWidth; auto nHelpRectWidth = pData->maHelpRect.GetWidth(); assert(nHelpRectWidth >= 0 && "coverity 2023.12.2"); nTitleWidth += nHelpRectWidth; nTitleWidth += pData->mnLeftBorder+pData->mnRightBorder; return nTitleWidth; } ImplNoBorderWindowView::ImplNoBorderWindowView() { } void ImplNoBorderWindowView::Init( OutputDevice*, tools::Long, tools::Long ) { } void ImplNoBorderWindowView::GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const { rLeftBorder = 0; rTopBorder = 0; rRightBorder = 0; rBottomBorder = 0; } tools::Long ImplNoBorderWindowView::CalcTitleWidth() const { return 0; } void ImplNoBorderWindowView::DrawWindow(vcl::RenderContext&, const Point*) { } ImplSmallBorderWindowView::ImplSmallBorderWindowView( ImplBorderWindow* pBorderWindow ) : mpBorderWindow(pBorderWindow) , mpOutDev(nullptr) , mnWidth(0) , mnHeight(0) , mnLeftBorder(0) , mnTopBorder(0) , mnRightBorder(0) , mnBottomBorder(0) , mbNWFBorder(false) { } void ImplSmallBorderWindowView::Init( OutputDevice* pDev, tools::Long nWidth, tools::Long nHeight ) { mpOutDev = pDev; mnWidth = nWidth; mnHeight = nHeight; mbNWFBorder = false; vcl::Window *pWin = mpOutDev->GetOwnerWindow(); vcl::Window *pCtrl = nullptr; vcl::Window *pSubEdit = nullptr; if (pWin) pCtrl = mpBorderWindow->GetWindow(GetWindowType::Client); tools::Long nOrigLeftBorder = mnLeftBorder; tools::Long nOrigTopBorder = mnTopBorder; tools::Long nOrigRightBorder = mnRightBorder; tools::Long nOrigBottomBorder = mnBottomBorder; WindowBorderStyle nBorderStyle = mpBorderWindow->GetBorderStyle(); if ( nBorderStyle & WindowBorderStyle::NOBORDER ) { mnLeftBorder = 0; mnTopBorder = 0; mnRightBorder = 0; mnBottomBorder = 0; } else { // FIXME: this is currently only on macOS, check with other // platforms if( ImplGetSVData()->maNWFData.mbNoFocusRects && !( nBorderStyle & WindowBorderStyle::NWF ) ) { // for native widget drawing we must find out what // control this border belongs to ControlType aCtrlType = ControlType::Generic; ControlPart aCtrlPart = ControlPart::Entire; if (pCtrl && !(pCtrl->GetBorderStyle() & WindowBorderStyle::NONATIVEBORDER)) { switch( pCtrl->GetType() ) { case WindowType::LISTBOX: if( pCtrl->GetStyle() & WB_DROPDOWN ) { aCtrlType = ControlType::Listbox; mbNWFBorder = true; pSubEdit = static_cast(pCtrl)->GetSubEdit(); } break; case WindowType::LISTBOXWINDOW: aCtrlType = ControlType::Listbox; aCtrlPart = ControlPart::ListboxWindow; mbNWFBorder = true; break; case WindowType::COMBOBOX: if( pCtrl->GetStyle() & WB_DROPDOWN ) { aCtrlType = ControlType::Combobox; mbNWFBorder = true; pSubEdit = static_cast(pCtrl)->GetSubEdit(); } break; case WindowType::MULTILINEEDIT: aCtrlType = ControlType::MultilineEditbox; mbNWFBorder = true; break; case WindowType::EDIT: case WindowType::PATTERNFIELD: case WindowType::METRICFIELD: case WindowType::CURRENCYFIELD: case WindowType::DATEFIELD: case WindowType::TIMEFIELD: case WindowType::SPINFIELD: case WindowType::FORMATTEDFIELD: mbNWFBorder = true; if (pCtrl->GetStyle() & WB_SPIN) aCtrlType = ControlType::Spinbox; else aCtrlType = ControlType::Editbox; pSubEdit = static_cast(pCtrl)->GetSubEdit(); break; default: break; } } if( mbNWFBorder ) { ImplControlValue aControlValue; Size aMinSize( mnWidth, mnHeight ); if( aMinSize.Width() < 10 ) aMinSize.setWidth( 10 ); if( aMinSize.Height() < 10 ) aMinSize.setHeight( 10 ); tools::Rectangle aCtrlRegion( Point(), aMinSize ); tools::Rectangle aBounds, aContent; if( pWin->GetNativeControlRegion( aCtrlType, aCtrlPart, aCtrlRegion, ControlState::ENABLED, aControlValue, aBounds, aContent ) ) { aBounds.AdjustLeft(mnLeftBorder); aBounds.AdjustRight(-mnRightBorder); aBounds.AdjustTop(mnTopBorder); aBounds.AdjustBottom(-mnBottomBorder); aContent.AdjustLeft(mnLeftBorder); aContent.AdjustRight(-mnRightBorder); aContent.AdjustTop(mnTopBorder); aContent.AdjustBottom(-mnBottomBorder); mnLeftBorder = aContent.Left() - aBounds.Left(); mnRightBorder = aBounds.Right() - aContent.Right(); mnTopBorder = aContent.Top() - aBounds.Top(); mnBottomBorder = aBounds.Bottom() - aContent.Bottom(); if( mnWidth && mnHeight ) { mpBorderWindow->SetPaintTransparent( true ); mpBorderWindow->SetBackground(); if (!pCtrl->IsControlBackground()) { pCtrl->SetPaintTransparent(true); if (pSubEdit) pSubEdit->SetPaintTransparent(true); } vcl::Window* pCompoundParent = nullptr; if( pWin->GetParent() && pWin->GetParent()->IsCompoundControl() ) pCompoundParent = pWin->GetParent(); if( pCompoundParent ) pCompoundParent->SetPaintTransparent( true ); if( mnWidth < aBounds.GetWidth() || mnHeight < aBounds.GetHeight() ) { if( ! pCompoundParent ) // compound controls have to fix themselves { Point aPos( mpBorderWindow->GetPosPixel() ); if( mnWidth < aBounds.GetWidth() ) aPos.AdjustX( -((aBounds.GetWidth() - mnWidth) / 2) ); if( mnHeight < aBounds.GetHeight() ) aPos.AdjustY( -((aBounds.GetHeight() - mnHeight) / 2) ); mpBorderWindow->SetPosSizePixel( aPos, aBounds.GetSize() ); } } } } else mbNWFBorder = false; } } if( ! mbNWFBorder ) { DrawFrameStyle nStyle = DrawFrameStyle::NONE; DrawFrameFlags nFlags = DrawFrameFlags::NoDraw; // move border outside if border was converted or if the BorderWindow is a frame window, if ( mpBorderWindow->mbSmallOutBorder ) nStyle = DrawFrameStyle::DoubleOut; else if ( nBorderStyle & WindowBorderStyle::NWF ) nStyle = DrawFrameStyle::NWF; else nStyle = DrawFrameStyle::DoubleIn; if ( nBorderStyle & WindowBorderStyle::MONO ) nFlags |= DrawFrameFlags::Mono; DecorationView aDecoView( mpOutDev ); tools::Rectangle aRect( 0, 0, 10, 10 ); tools::Rectangle aCalcRect = aDecoView.DrawFrame( aRect, nStyle, nFlags ); mnLeftBorder = aCalcRect.Left(); mnTopBorder = aCalcRect.Top(); mnRightBorder = aRect.Right()-aCalcRect.Right(); mnBottomBorder = aRect.Bottom()-aCalcRect.Bottom(); } } if (pCtrl) { //fdo#57090 If the borders have changed, then trigger a queue_resize on //the bordered window, which will resync its borders at that point if (nOrigLeftBorder != mnLeftBorder || nOrigTopBorder != mnTopBorder || nOrigRightBorder != mnRightBorder || nOrigBottomBorder != mnBottomBorder) { pCtrl->queue_resize(); } } } void ImplSmallBorderWindowView::GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const { rLeftBorder = mnLeftBorder; rTopBorder = mnTopBorder; rRightBorder = mnRightBorder; rBottomBorder = mnBottomBorder; } tools::Long ImplSmallBorderWindowView::CalcTitleWidth() const { return 0; } void ImplSmallBorderWindowView::DrawWindow(vcl::RenderContext& rRenderContext, const Point*) { WindowBorderStyle nBorderStyle = mpBorderWindow->GetBorderStyle(); if (nBorderStyle & WindowBorderStyle::NOBORDER) return; bool bNativeOK = false; // for native widget drawing we must find out what // control this border belongs to vcl::Window* pCtrl = mpBorderWindow->GetWindow(GetWindowType::Client); ControlType aCtrlType = ControlType::Generic; ControlPart aCtrlPart = ControlPart::Entire; if (pCtrl) { switch (pCtrl->GetType()) { case WindowType::MULTILINEEDIT: aCtrlType = ControlType::MultilineEditbox; break; case WindowType::EDIT: case WindowType::PATTERNFIELD: case WindowType::METRICFIELD: case WindowType::CURRENCYFIELD: case WindowType::DATEFIELD: case WindowType::TIMEFIELD: case WindowType::SPINFIELD: case WindowType::FORMATTEDFIELD: if (pCtrl->GetStyle() & WB_SPIN) aCtrlType = ControlType::Spinbox; else aCtrlType = ControlType::Editbox; break; case WindowType::LISTBOX: case WindowType::MULTILISTBOX: case WindowType::TREELISTBOX: aCtrlType = ControlType::Listbox; if (pCtrl->GetStyle() & WB_DROPDOWN) aCtrlPart = ControlPart::Entire; else aCtrlPart = ControlPart::ListboxWindow; break; case WindowType::LISTBOXWINDOW: aCtrlType = ControlType::Listbox; aCtrlPart = ControlPart::ListboxWindow; break; case WindowType::COMBOBOX: case WindowType::PATTERNBOX: case WindowType::NUMERICBOX: case WindowType::METRICBOX: case WindowType::CURRENCYBOX: case WindowType::DATEBOX: case WindowType::TIMEBOX: case WindowType::LONGCURRENCYBOX: if (pCtrl->GetStyle() & WB_DROPDOWN) { aCtrlType = ControlType::Combobox; aCtrlPart = ControlPart::Entire; } else { aCtrlType = ControlType::Listbox; aCtrlPart = ControlPart::ListboxWindow; } break; default: break; } } if (aCtrlType != ControlType::Generic && pCtrl->IsNativeControlSupported(aCtrlType, aCtrlPart)) { ImplControlValue aControlValue; ControlState nState = ControlState::ENABLED; if (!mpBorderWindow->IsEnabled()) nState &= ~ControlState::ENABLED; if (mpBorderWindow->HasFocus() || pCtrl->HasFocus() || pCtrl->HasChildPathFocus()) nState |= ControlState::FOCUSED; bool bMouseOver = pCtrl->IsMouseOver(); if (!bMouseOver) { vcl::Window *pCtrlChild = pCtrl->GetWindow(GetWindowType::FirstChild); while(pCtrlChild) { bMouseOver = pCtrlChild->IsMouseOver(); if (bMouseOver) break; pCtrlChild = pCtrlChild->GetWindow(GetWindowType::Next); } } if (bMouseOver) nState |= ControlState::ROLLOVER; Point aPoint; tools::Rectangle aCtrlRegion(aPoint, Size(mnWidth, mnHeight)); tools::Rectangle aBoundingRgn(aPoint, Size(mnWidth, mnHeight)); tools::Rectangle aContentRgn(aCtrlRegion); if (!ImplGetSVData()->maNWFData.mbCanDrawWidgetAnySize && rRenderContext.GetNativeControlRegion(aCtrlType, aCtrlPart, aCtrlRegion, nState, aControlValue, aBoundingRgn, aContentRgn)) { aCtrlRegion=aContentRgn; } Color aBackgroundColor = COL_AUTO; if (pCtrl->IsControlBackground()) aBackgroundColor = pCtrl->GetBackgroundColor(); bNativeOK = rRenderContext.DrawNativeControl(aCtrlType, aCtrlPart, aCtrlRegion, nState, aControlValue, OUString(), aBackgroundColor); // if the native theme draws the spinbuttons in one call, make sure the proper settings // are passed, this might force a redraw though... (TODO: improve) if ((aCtrlType == ControlType::Spinbox) && !pCtrl->IsNativeControlSupported(ControlType::Spinbox, ControlPart::ButtonUp)) { Edit* pEdit = static_cast(pCtrl)->GetSubEdit(); if (pEdit && !pEdit->SupportsDoubleBuffering()) pCtrl->Paint(*pCtrl->GetOutDev(), tools::Rectangle()); // make sure the buttons are also drawn as they might overwrite the border } } if (bNativeOK) return; DrawFrameStyle nStyle = DrawFrameStyle::NONE; DrawFrameFlags nFlags = DrawFrameFlags::NONE; // move border outside if border was converted or if the border window is a frame window, if (mpBorderWindow->mbSmallOutBorder) nStyle = DrawFrameStyle::DoubleOut; else if (nBorderStyle & WindowBorderStyle::NWF) nStyle = DrawFrameStyle::NWF; else nStyle = DrawFrameStyle::DoubleIn; if (nBorderStyle & WindowBorderStyle::MONO) nFlags |= DrawFrameFlags::Mono; if (nBorderStyle & WindowBorderStyle::MENU) nFlags |= DrawFrameFlags::Menu; // tell DrawFrame that we're drawing a window border of a frame window to avoid round corners if (mpBorderWindow == mpBorderWindow->ImplGetFrameWindow()) nFlags |= DrawFrameFlags::WindowBorder; DecorationView aDecoView(&rRenderContext); tools::Rectangle aInRect(Point(), Size(mnWidth, mnHeight)); aDecoView.DrawFrame(aInRect, nStyle, nFlags); } ImplStdBorderWindowView::ImplStdBorderWindowView( ImplBorderWindow* pBorderWindow ) { maFrameData.mpBorderWindow = pBorderWindow; maFrameData.mbDragFull = false; maFrameData.mnHitTest = BorderWindowHitTest::NONE; maFrameData.mnCloseState = DrawButtonFlags::NONE; maFrameData.mnDockState = DrawButtonFlags::NONE; maFrameData.mnMenuState = DrawButtonFlags::NONE; maFrameData.mnHideState = DrawButtonFlags::NONE; maFrameData.mnHelpState = DrawButtonFlags::NONE; maFrameData.mbTitleClipped = false; } ImplStdBorderWindowView::~ImplStdBorderWindowView() { } bool ImplStdBorderWindowView::MouseMove( const MouseEvent& rMEvt ) { ImplMouseMove( &maFrameData, rMEvt ); return true; } bool ImplStdBorderWindowView::MouseButtonDown( const MouseEvent& rMEvt ) { ImplBorderWindow* pBorderWindow = maFrameData.mpBorderWindow; if ( rMEvt.IsLeft() || rMEvt.IsRight() ) { maFrameData.maMouseOff = rMEvt.GetPosPixel(); maFrameData.mnHitTest = ImplHitTest( &maFrameData, maFrameData.maMouseOff ); if ( maFrameData.mnHitTest != BorderWindowHitTest::NONE ) { DragFullOptions nDragFullTest = DragFullOptions::NONE; bool bTracking = true; bool bHitTest = true; if ( maFrameData.mnHitTest & BorderWindowHitTest::Close ) { maFrameData.mnCloseState |= DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); } else if ( maFrameData.mnHitTest & BorderWindowHitTest::Dock ) { maFrameData.mnDockState |= DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); } else if ( maFrameData.mnHitTest & BorderWindowHitTest::Menu ) { maFrameData.mnMenuState |= DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); // call handler already on mouse down if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() ) { SystemWindow* pClientWindow = static_cast(pBorderWindow->ImplGetClientWindow()); pClientWindow->TitleButtonClick( TitleButton::Menu ); } maFrameData.mnMenuState &= ~DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); bTracking = false; } else if ( maFrameData.mnHitTest & BorderWindowHitTest::Hide ) { maFrameData.mnHideState |= DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); } else if ( maFrameData.mnHitTest & BorderWindowHitTest::Help ) { maFrameData.mnHelpState |= DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); } else { if ( rMEvt.GetClicks() == 1 ) { Point aPos = pBorderWindow->GetPosPixel(); Size aSize = pBorderWindow->GetOutputSizePixel(); maFrameData.mnTrackX = aPos.X(); maFrameData.mnTrackY = aPos.Y(); maFrameData.mnTrackWidth = aSize.Width(); maFrameData.mnTrackHeight = aSize.Height(); if (maFrameData.mnHitTest & BorderWindowHitTest::Title) nDragFullTest = DragFullOptions::WindowMove; else nDragFullTest = DragFullOptions::WindowSize; } else { bTracking = false; if ( (maFrameData.mnHitTest & BorderWindowHitTest::Title) && ((rMEvt.GetClicks() % 2) == 0) ) { maFrameData.mnHitTest = BorderWindowHitTest::NONE; bHitTest = false; if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() ) { SystemWindow* pClientWindow = static_cast(pBorderWindow->ImplGetClientWindow()); // always perform docking on double click, no button required pClientWindow->TitleButtonClick( TitleButton::Docking ); } } } } if ( bTracking ) { maFrameData.mbDragFull = false; if ( nDragFullTest != DragFullOptions::NONE ) maFrameData.mbDragFull = true; // always fulldrag for proper docking, ignore system settings pBorderWindow->StartTracking(); } else if ( bHitTest ) maFrameData.mnHitTest = BorderWindowHitTest::NONE; } } return true; } bool ImplStdBorderWindowView::Tracking( const TrackingEvent& rTEvt ) { ImplBorderWindow* pBorderWindow = maFrameData.mpBorderWindow; if ( rTEvt.IsTrackingEnded() ) { BorderWindowHitTest nHitTest = maFrameData.mnHitTest; maFrameData.mnHitTest = BorderWindowHitTest::NONE; if ( nHitTest & BorderWindowHitTest::Close ) { if ( maFrameData.mnCloseState & DrawButtonFlags::Pressed ) { maFrameData.mnCloseState &= ~DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); // do not call a Click-Handler when aborting if ( !rTEvt.IsTrackingCanceled() ) { // dispatch to correct window type (why is Close() not virtual ??? ) // TODO: make Close() virtual VclPtr pWin = pBorderWindow->ImplGetClientWindow()->ImplGetWindow(); SystemWindow *pSysWin = dynamic_cast(pWin.get()); DockingWindow *pDockWin = dynamic_cast(pWin.get()); if ( pSysWin ) pSysWin->Close(); else if ( pDockWin ) pDockWin->Close(); } } } else if ( nHitTest & BorderWindowHitTest::Dock ) { if ( maFrameData.mnDockState & DrawButtonFlags::Pressed ) { maFrameData.mnDockState &= ~DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); // do not call a Click-Handler when aborting if ( !rTEvt.IsTrackingCanceled() ) { if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() ) { SystemWindow* pClientWindow = static_cast(pBorderWindow->ImplGetClientWindow()); pClientWindow->TitleButtonClick( TitleButton::Docking ); } } } } else if ( nHitTest & BorderWindowHitTest::Menu ) { if ( maFrameData.mnMenuState & DrawButtonFlags::Pressed ) { maFrameData.mnMenuState &= ~DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); // handler already called on mouse down } } else if ( nHitTest & BorderWindowHitTest::Hide ) { if ( maFrameData.mnHideState & DrawButtonFlags::Pressed ) { maFrameData.mnHideState &= ~DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); // do not call a Click-Handler when aborting if ( !rTEvt.IsTrackingCanceled() ) { if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() ) { SystemWindow* pClientWindow = static_cast(pBorderWindow->ImplGetClientWindow()); pClientWindow->TitleButtonClick( TitleButton::Hide ); } } } } else if ( nHitTest & BorderWindowHitTest::Help ) { if ( maFrameData.mnHelpState & DrawButtonFlags::Pressed ) { maFrameData.mnHelpState &= ~DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); } } else { if ( maFrameData.mbDragFull ) { // restore old state when aborting if ( rTEvt.IsTrackingCanceled() ) pBorderWindow->SetPosSizePixel( Point( maFrameData.mnTrackX, maFrameData.mnTrackY ), Size( maFrameData.mnTrackWidth, maFrameData.mnTrackHeight ) ); } else { pBorderWindow->HideTracking(); if ( !rTEvt.IsTrackingCanceled() ) pBorderWindow->SetPosSizePixel( Point( maFrameData.mnTrackX, maFrameData.mnTrackY ), Size( maFrameData.mnTrackWidth, maFrameData.mnTrackHeight ) ); } if ( !rTEvt.IsTrackingCanceled() ) { if ( pBorderWindow->ImplGetClientWindow()->ImplIsFloatingWindow() ) { if ( static_cast(pBorderWindow->ImplGetClientWindow())->IsInPopupMode() ) static_cast(pBorderWindow->ImplGetClientWindow())->EndPopupMode( FloatWinPopupEndFlags::TearOff ); } } } } else if ( !rTEvt.GetMouseEvent().IsSynthetic() ) { Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel(); if ( maFrameData.mnHitTest & BorderWindowHitTest::Close ) { if ( maFrameData.maCloseRect.Contains( aMousePos ) ) { if ( !(maFrameData.mnCloseState & DrawButtonFlags::Pressed) ) { maFrameData.mnCloseState |= DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); } } else { if ( maFrameData.mnCloseState & DrawButtonFlags::Pressed ) { maFrameData.mnCloseState &= ~DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); } } } else if ( maFrameData.mnHitTest & BorderWindowHitTest::Dock ) { if ( maFrameData.maDockRect.Contains( aMousePos ) ) { if ( !(maFrameData.mnDockState & DrawButtonFlags::Pressed) ) { maFrameData.mnDockState |= DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); } } else { if ( maFrameData.mnDockState & DrawButtonFlags::Pressed ) { maFrameData.mnDockState &= ~DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); } } } else if ( maFrameData.mnHitTest & BorderWindowHitTest::Menu ) { if ( maFrameData.maMenuRect.Contains( aMousePos ) ) { if ( !(maFrameData.mnMenuState & DrawButtonFlags::Pressed) ) { maFrameData.mnMenuState |= DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); } } else { if ( maFrameData.mnMenuState & DrawButtonFlags::Pressed ) { maFrameData.mnMenuState &= ~DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); } } } else if ( maFrameData.mnHitTest & BorderWindowHitTest::Hide ) { if ( maFrameData.maHideRect.Contains( aMousePos ) ) { if ( !(maFrameData.mnHideState & DrawButtonFlags::Pressed) ) { maFrameData.mnHideState |= DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); } } else { if ( maFrameData.mnHideState & DrawButtonFlags::Pressed ) { maFrameData.mnHideState &= ~DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); } } } else if ( maFrameData.mnHitTest & BorderWindowHitTest::Help ) { if ( maFrameData.maHelpRect.Contains( aMousePos ) ) { if ( !(maFrameData.mnHelpState & DrawButtonFlags::Pressed) ) { maFrameData.mnHelpState |= DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); } } else { if ( maFrameData.mnHelpState & DrawButtonFlags::Pressed ) { maFrameData.mnHelpState &= ~DrawButtonFlags::Pressed; pBorderWindow->InvalidateBorder(); } } } else { aMousePos.AdjustX( -(maFrameData.maMouseOff.X()) ); aMousePos.AdjustY( -(maFrameData.maMouseOff.Y()) ); if ( maFrameData.mnHitTest & BorderWindowHitTest::Title ) { maFrameData.mpBorderWindow->SetPointer( PointerStyle::Move ); Point aPos = pBorderWindow->GetPosPixel(); aPos.AdjustX(aMousePos.X() ); aPos.AdjustY(aMousePos.Y() ); if ( maFrameData.mbDragFull ) { pBorderWindow->SetPosPixel( aPos ); pBorderWindow->ImplUpdateAll(); pBorderWindow->ImplGetFrameWindow()->ImplUpdateAll(); } else { maFrameData.mnTrackX = aPos.X(); maFrameData.mnTrackY = aPos.Y(); pBorderWindow->ShowTracking( tools::Rectangle( pBorderWindow->ScreenToOutputPixel( aPos ), pBorderWindow->GetOutputSizePixel() ), ShowTrackFlags::Big ); } } else { Point aOldPos = pBorderWindow->GetPosPixel(); Size aSize = pBorderWindow->GetSizePixel(); tools::Rectangle aNewRect( aOldPos, aSize ); tools::Long nOldWidth = aSize.Width(); tools::Long nOldHeight = aSize.Height(); tools::Long nBorderWidth = maFrameData.mnLeftBorder+maFrameData.mnRightBorder; tools::Long nBorderHeight = maFrameData.mnTopBorder+maFrameData.mnBottomBorder; tools::Long nMinWidth = pBorderWindow->mnMinWidth+nBorderWidth; tools::Long nMinHeight = pBorderWindow->mnMinHeight+nBorderHeight; tools::Long nMinWidth2 = nBorderWidth; tools::Long nMaxWidth = pBorderWindow->mnMaxWidth+nBorderWidth; tools::Long nMaxHeight = pBorderWindow->mnMaxHeight+nBorderHeight; if ( maFrameData.mnTitleHeight ) { nMinWidth2 += 4; if ( pBorderWindow->GetStyle() & WB_CLOSEABLE ) nMinWidth2 += maFrameData.maCloseRect.GetWidth(); } if ( nMinWidth2 > nMinWidth ) nMinWidth = nMinWidth2; if ( maFrameData.mnHitTest & (BorderWindowHitTest::Left | BorderWindowHitTest::TopLeft | BorderWindowHitTest::BottomLeft) ) { aNewRect.AdjustLeft(aMousePos.X() ); if ( aNewRect.GetWidth() < nMinWidth ) aNewRect.SetLeft( aNewRect.Right()-nMinWidth+1 ); else if ( aNewRect.GetWidth() > nMaxWidth ) aNewRect.SetLeft( aNewRect.Right()-nMaxWidth+1 ); } else if ( maFrameData.mnHitTest & (BorderWindowHitTest::Right | BorderWindowHitTest::TopRight | BorderWindowHitTest::BottomRight) ) { aNewRect.AdjustRight(aMousePos.X() ); if ( aNewRect.GetWidth() < nMinWidth ) aNewRect.SetRight( aNewRect.Left()+nMinWidth+1 ); else if ( aNewRect.GetWidth() > nMaxWidth ) aNewRect.SetRight( aNewRect.Left()+nMaxWidth+1 ); } if ( maFrameData.mnHitTest & (BorderWindowHitTest::Top | BorderWindowHitTest::TopLeft | BorderWindowHitTest::TopRight) ) { aNewRect.AdjustTop(aMousePos.Y() ); if ( aNewRect.GetHeight() < nMinHeight ) aNewRect.SetTop( aNewRect.Bottom()-nMinHeight+1 ); else if ( aNewRect.GetHeight() > nMaxHeight ) aNewRect.SetTop( aNewRect.Bottom()-nMaxHeight+1 ); } else if ( maFrameData.mnHitTest & (BorderWindowHitTest::Bottom | BorderWindowHitTest::BottomLeft | BorderWindowHitTest::BottomRight) ) { aNewRect.AdjustBottom(aMousePos.Y() ); if ( aNewRect.GetHeight() < nMinHeight ) aNewRect.SetBottom( aNewRect.Top()+nMinHeight+1 ); else if ( aNewRect.GetHeight() > nMaxHeight ) aNewRect.SetBottom( aNewRect.Top()+nMaxHeight+1 ); } // call Resizing-Handler for SystemWindows if ( pBorderWindow->ImplGetClientWindow()->IsSystemWindow() ) { // adjust size for Resizing-call aSize = aNewRect.GetSize(); aSize.AdjustWidth( -nBorderWidth ); aSize.AdjustHeight( -nBorderHeight ); static_cast(pBorderWindow->ImplGetClientWindow())->Resizing( aSize ); aSize.AdjustWidth(nBorderWidth ); aSize.AdjustHeight(nBorderHeight ); if ( aSize.Width() < nMinWidth ) aSize.setWidth( nMinWidth ); if ( aSize.Height() < nMinHeight ) aSize.setHeight( nMinHeight ); if ( aSize.Width() > nMaxWidth ) aSize.setWidth( nMaxWidth ); if ( aSize.Height() > nMaxHeight ) aSize.setHeight( nMaxHeight ); if ( maFrameData.mnHitTest & (BorderWindowHitTest::Left | BorderWindowHitTest::TopLeft | BorderWindowHitTest::BottomLeft) ) aNewRect.SetLeft( aNewRect.Right()-aSize.Width()+1 ); else aNewRect.SetRight( aNewRect.Left()+aSize.Width()-1 ); if ( maFrameData.mnHitTest & (BorderWindowHitTest::Top | BorderWindowHitTest::TopLeft | BorderWindowHitTest::TopRight) ) aNewRect.SetTop( aNewRect.Bottom()-aSize.Height()+1 ); else aNewRect.SetBottom( aNewRect.Top()+aSize.Height()-1 ); } if ( maFrameData.mbDragFull ) { // no move (only resize) if position did not change if( aOldPos != aNewRect.TopLeft() ) pBorderWindow->setPosSizePixel( aNewRect.Left(), aNewRect.Top(), aNewRect.GetWidth(), aNewRect.GetHeight() ); else pBorderWindow->setPosSizePixel( aNewRect.Left(), aNewRect.Top(), aNewRect.GetWidth(), aNewRect.GetHeight(), PosSizeFlags::Size ); pBorderWindow->ImplUpdateAll(); pBorderWindow->ImplGetFrameWindow()->ImplUpdateAll(); if ( maFrameData.mnHitTest & (BorderWindowHitTest::Right | BorderWindowHitTest::TopRight | BorderWindowHitTest::BottomRight) ) maFrameData.maMouseOff.AdjustX(aNewRect.GetWidth()-nOldWidth ); if ( maFrameData.mnHitTest & (BorderWindowHitTest::Bottom | BorderWindowHitTest::BottomLeft | BorderWindowHitTest::BottomRight) ) maFrameData.maMouseOff.AdjustY(aNewRect.GetHeight()-nOldHeight ); } else { maFrameData.mnTrackX = aNewRect.Left(); maFrameData.mnTrackY = aNewRect.Top(); maFrameData.mnTrackWidth = aNewRect.GetWidth(); maFrameData.mnTrackHeight = aNewRect.GetHeight(); pBorderWindow->ShowTracking( tools::Rectangle( pBorderWindow->ScreenToOutputPixel( aNewRect.TopLeft() ), aNewRect.GetSize() ), ShowTrackFlags::Big ); } } } } return true; } OUString ImplStdBorderWindowView::RequestHelp( const Point& rPos, tools::Rectangle& rHelpRect ) { return ImplRequestHelp( &maFrameData, rPos, rHelpRect ); } tools::Rectangle ImplStdBorderWindowView::GetMenuRect() const { return maFrameData.maMenuRect; } void ImplStdBorderWindowView::Init( OutputDevice* pDev, tools::Long nWidth, tools::Long nHeight ) { ImplBorderFrameData* pData = &maFrameData; ImplBorderWindow* pBorderWindow = maFrameData.mpBorderWindow; const StyleSettings& rStyleSettings = pDev->GetSettings().GetStyleSettings(); DecorationView aDecoView( pDev ); tools::Rectangle aRect( 0, 0, 10, 10 ); tools::Rectangle aCalcRect = aDecoView.DrawFrame( aRect, DrawFrameStyle::DoubleOut, DrawFrameFlags::NoDraw ); pData->mpOutDev = pDev; pData->mnWidth = nWidth; pData->mnHeight = nHeight; pData->mnTitleType = pBorderWindow->mnTitleType; if ( !(pBorderWindow->GetStyle() & (WB_MOVEABLE | WB_POPUP)) || (pData->mnTitleType == BorderWindowTitleType::NONE) ) pData->mnBorderSize = 0; else if ( pData->mnTitleType == BorderWindowTitleType::Tearoff ) pData->mnBorderSize = 0; else pData->mnBorderSize = StyleSettings::GetBorderSize(); pData->mnLeftBorder = aCalcRect.Left(); pData->mnTopBorder = aCalcRect.Top(); pData->mnRightBorder = aRect.Right()-aCalcRect.Right(); pData->mnBottomBorder = aRect.Bottom()-aCalcRect.Bottom(); pData->mnLeftBorder += pData->mnBorderSize; pData->mnTopBorder += pData->mnBorderSize; pData->mnRightBorder += pData->mnBorderSize; pData->mnBottomBorder += pData->mnBorderSize; pData->mnNoTitleTop = pData->mnTopBorder; ImplInitTitle(&maFrameData); if (pData->mnTitleHeight) { // to improve symbol display force a minimum title height if (pData->mnTitleType != BorderWindowTitleType::Tearoff && pData->mnTitleHeight < MIN_CAPTION_HEIGHT) pData->mnTitleHeight = MIN_CAPTION_HEIGHT; // set a proper background for drawing // highlighted buttons in the title pBorderWindow->SetBackground( rStyleSettings.GetFaceColor() ); pData->maTitleRect.SetLeft( pData->mnLeftBorder ); pData->maTitleRect.SetRight( nWidth-pData->mnRightBorder-1 ); pData->maTitleRect.SetTop( pData->mnTopBorder ); pData->maTitleRect.SetBottom( pData->maTitleRect.Top()+pData->mnTitleHeight-1 ); if ( pData->mnTitleType & (BorderWindowTitleType::Normal | BorderWindowTitleType::Small) ) { tools::Long nRight = pData->maTitleRect.Right() - 3; tools::Long const nItemTop = pData->maTitleRect.Top() + 2; tools::Long const nItemBottom = pData->maTitleRect.Bottom() - 2; auto addSquareOnRight = [&nRight, nItemTop, nItemBottom]( tools::Rectangle & rect, tools::Long gap) { rect.SetTop( nItemTop ); rect.SetBottom( nItemBottom ); rect.SetRight( nRight ); rect.SetLeft( rect.Right() - rect.GetHeight() + 1 ); nRight -= rect.GetWidth() + gap; }; if ( pBorderWindow->GetStyle() & WB_CLOSEABLE ) { addSquareOnRight(pData->maCloseRect, 3); } if ( pBorderWindow->mbMenuBtn ) { addSquareOnRight(pData->maMenuRect, 0); } if ( pBorderWindow->mbDockBtn ) { addSquareOnRight(pData->maDockRect, 0); } if ( pBorderWindow->mbHideBtn ) { addSquareOnRight(pData->maHideRect, 0); } } else { pData->maCloseRect.SetEmpty(); pData->maDockRect.SetEmpty(); pData->maMenuRect.SetEmpty(); pData->maHideRect.SetEmpty(); pData->maHelpRect.SetEmpty(); } pData->mnTopBorder += pData->mnTitleHeight; } else { pData->maTitleRect.SetEmpty(); pData->maCloseRect.SetEmpty(); pData->maDockRect.SetEmpty(); pData->maMenuRect.SetEmpty(); pData->maHideRect.SetEmpty(); pData->maHelpRect.SetEmpty(); } } void ImplStdBorderWindowView::GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const { rLeftBorder = maFrameData.mnLeftBorder; rTopBorder = maFrameData.mnTopBorder; rRightBorder = maFrameData.mnRightBorder; rBottomBorder = maFrameData.mnBottomBorder; } tools::Long ImplStdBorderWindowView::CalcTitleWidth() const { return ImplCalcTitleWidth( &maFrameData ); } void ImplStdBorderWindowView::DrawWindow(vcl::RenderContext& rRenderContext, const Point* pOffset) { ImplBorderFrameData* pData = &maFrameData; ImplBorderWindow* pBorderWindow = pData->mpBorderWindow; Point aTmpPoint = pOffset ? *pOffset : Point(); tools::Rectangle aInRect( aTmpPoint, Size( pData->mnWidth, pData->mnHeight ) ); const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); Color aFaceColor(rStyleSettings.GetFaceColor()); Color aFrameColor(aFaceColor); aFrameColor.DecreaseContrast(sal_uInt8(0.5 * 255)); // Draw Frame vcl::Region oldClipRgn(rRenderContext.GetClipRegion()); // for popups, don't draw part of the frame const bool bShowJunctionToLauncher = !(pData->mnTitleType & (BorderWindowTitleType::Normal | BorderWindowTitleType::Small)); if (bShowJunctionToLauncher && !ImplGetSVData()->maNWFData.mbNoFrameJunctionForPopups) { FloatingWindow* pWin = dynamic_cast(pData->mpBorderWindow->GetWindow(GetWindowType::Client)); if (pWin) { vcl::Region aClipRgn(aInRect); AbsoluteScreenPixelRectangle aItemClipRect(pWin->ImplGetItemEdgeClipRect()); if (!aItemClipRect.IsEmpty()) { tools::Rectangle aTmp(pData->mpBorderWindow->AbsoluteScreenToOutputPixel(aItemClipRect.TopLeft()), aItemClipRect.GetSize()); aClipRgn.Exclude(aTmp); rRenderContext.SetClipRegion(aClipRgn); } } } // single line frame rRenderContext.SetLineColor(aFrameColor); rRenderContext.SetFillColor(); rRenderContext.DrawRect(aInRect); aInRect.AdjustLeft( 1 ); aInRect.AdjustRight( -1 ); aInRect.AdjustTop( 1 ); aInRect.AdjustBottom( -1 ); // restore if (!(pData->mnTitleType & (BorderWindowTitleType::Normal | BorderWindowTitleType::Small))) rRenderContext.SetClipRegion(oldClipRgn); // Draw Border rRenderContext.SetLineColor(); tools::Long nBorderSize = pData->mnBorderSize; if (nBorderSize) { rRenderContext.SetFillColor(rStyleSettings.GetFaceColor()); rRenderContext.DrawRect(tools::Rectangle(Point(aInRect.Left(), aInRect.Top()), Size(aInRect.GetWidth(), nBorderSize))); rRenderContext.DrawRect(tools::Rectangle(Point(aInRect.Left(), aInRect.Top() + nBorderSize), Size(nBorderSize, aInRect.GetHeight() - nBorderSize))); rRenderContext.DrawRect(tools::Rectangle(Point(aInRect.Left(), aInRect.Bottom() - nBorderSize + 1), Size(aInRect.GetWidth(), nBorderSize))); rRenderContext.DrawRect(tools::Rectangle(Point(aInRect.Right()-nBorderSize + 1, aInRect.Top() + nBorderSize), Size(nBorderSize, aInRect.GetHeight() - nBorderSize))); } // Draw Title if (!pData->maTitleRect.IsEmpty()) { aInRect = pData->maTitleRect; // use no gradient anymore, just a static titlecolor if (pData->mnTitleType == BorderWindowTitleType::Tearoff) rRenderContext.SetFillColor(rStyleSettings.GetFaceGradientColor()); else if (pData->mnTitleType == BorderWindowTitleType::Popup) rRenderContext.SetFillColor(aFaceColor); else rRenderContext.SetFillColor(aFrameColor); rRenderContext.SetTextColor(rStyleSettings.GetButtonTextColor()); tools::Rectangle aTitleRect(pData->maTitleRect); if(pOffset) aTitleRect.Move(pOffset->X(), pOffset->Y()); rRenderContext.DrawRect(aTitleRect); if (pData->mnTitleType != BorderWindowTitleType::Tearoff) { aInRect.AdjustLeft(2 ); aInRect.AdjustRight( -2 ); if (!pData->maHelpRect.IsEmpty()) aInRect.SetRight( pData->maHelpRect.Left() - 2 ); else if (!pData->maHideRect.IsEmpty()) aInRect.SetRight( pData->maHideRect.Left() - 2 ); else if (!pData->maDockRect.IsEmpty()) aInRect.SetRight( pData->maDockRect.Left() - 2 ); else if (!pData->maMenuRect.IsEmpty()) aInRect.SetRight( pData->maMenuRect.Left() - 2 ); else if (!pData->maCloseRect.IsEmpty()) aInRect.SetRight( pData->maCloseRect.Left() - 2 ); if (pOffset) aInRect.Move(pOffset->X(), pOffset->Y()); DrawTextFlags nTextStyle = DrawTextFlags::Left | DrawTextFlags::VCenter | DrawTextFlags::EndEllipsis | DrawTextFlags::Clip; // must show tooltip ? TextRectInfo aInfo; rRenderContext.GetTextRect(aInRect, pBorderWindow->GetText(), nTextStyle, &aInfo); pData->mbTitleClipped = aInfo.IsEllipses(); rRenderContext.DrawText(aInRect, pBorderWindow->GetText(), nTextStyle); } else { ToolBox::ImplDrawGrip(rRenderContext, aTitleRect, ToolBox::ImplGetDragWidth(rRenderContext, false), WindowAlign::Left, false); } } if (!pData->maCloseRect.IsEmpty()) { tools::Rectangle aSymbolRect(pData->maCloseRect); if (pOffset) aSymbolRect.Move(pOffset->X(), pOffset->Y()); ImplDrawBrdWinSymbolButton(&rRenderContext, aSymbolRect, SymbolType::CLOSE, pData->mnCloseState); } if (!pData->maDockRect.IsEmpty()) { tools::Rectangle aSymbolRect(pData->maDockRect); if (pOffset) aSymbolRect.Move(pOffset->X(), pOffset->Y()); ImplDrawBrdWinSymbolButton(&rRenderContext, aSymbolRect, SymbolType::DOCK, pData->mnDockState); } if (!pData->maMenuRect.IsEmpty()) { tools::Rectangle aSymbolRect(pData->maMenuRect); if (pOffset) aSymbolRect.Move(pOffset->X(), pOffset->Y()); ImplDrawBrdWinSymbolButton(&rRenderContext, aSymbolRect, SymbolType::MENU, pData->mnMenuState); } if (!pData->maHideRect.IsEmpty()) { tools::Rectangle aSymbolRect(pData->maHideRect); if (pOffset) aSymbolRect.Move(pOffset->X(), pOffset->Y()); ImplDrawBrdWinSymbolButton(&rRenderContext, aSymbolRect, SymbolType::HIDE, pData->mnHideState); } if (!pData->maHelpRect.IsEmpty()) { tools::Rectangle aSymbolRect(pData->maHelpRect); if (pOffset) aSymbolRect.Move(pOffset->X(), pOffset->Y()); ImplDrawBrdWinSymbolButton(&rRenderContext, aSymbolRect, SymbolType::HELP, pData->mnHelpState); } } void ImplBorderWindow::ImplInit( vcl::Window* pParent, WinBits nStyle, BorderWindowStyle nTypeStyle, SystemParentData* pSystemParentData ) { // remove all unwanted WindowBits WinBits nOrgStyle = nStyle; WinBits nTestStyle = (WB_MOVEABLE | WB_SIZEABLE | WB_CLOSEABLE | WB_STANDALONE | WB_DIALOGCONTROL | WB_NODIALOGCONTROL | WB_SYSTEMFLOATWIN | WB_INTROWIN | WB_DEFAULTWIN | WB_TOOLTIPWIN | WB_NOSHADOW | WB_OWNERDRAWDECORATION | WB_SYSTEMCHILDWINDOW | WB_POPUP); if ( nTypeStyle & BorderWindowStyle::App ) nTestStyle |= WB_APP; nStyle &= nTestStyle; mpWindowImpl->mbBorderWin = true; mbSmallOutBorder = false; if ( nTypeStyle & BorderWindowStyle::Frame ) { mpWindowImpl->mbOverlapWin = true; mpWindowImpl->mbFrame = true; if( nStyle & WB_SYSTEMCHILDWINDOW ) { mbFrameBorder = false; } else if( nStyle & (WB_OWNERDRAWDECORATION | WB_POPUP) ) { mbFrameBorder = (nOrgStyle & WB_NOBORDER) == 0; } else { mbFrameBorder = false; // closeable windows may have a border as well, eg. system floating windows without caption if ( (nOrgStyle & (WB_BORDER | WB_NOBORDER | WB_MOVEABLE | WB_SIZEABLE/* | WB_CLOSEABLE*/)) == WB_BORDER ) mbSmallOutBorder = true; } } else if ( nTypeStyle & BorderWindowStyle::Overlap ) { mpWindowImpl->mbOverlapWin = true; mbFrameBorder = true; } else mbFrameBorder = false; if ( nTypeStyle & BorderWindowStyle::Float ) mbFloatWindow = true; else mbFloatWindow = false; Window::ImplInit( pParent, nStyle, pSystemParentData ); SetBackground(); SetTextFillColor(); mpMenuBarWindow = nullptr; mnMinWidth = 0; mnMinHeight = 0; mnMaxWidth = SHRT_MAX; mnMaxHeight = SHRT_MAX; mnOrgMenuHeight = 0; mbMenuHide = false; mbDockBtn = false; mbMenuBtn = false; mbHideBtn = false; mbDisplayActive = IsActive(); if ( nTypeStyle & BorderWindowStyle::Float ) mnTitleType = BorderWindowTitleType::Small; else mnTitleType = BorderWindowTitleType::Normal; mnBorderStyle = WindowBorderStyle::NORMAL; InitView(); } ImplBorderWindow::ImplBorderWindow( vcl::Window* pParent, SystemParentData* pSystemParentData, WinBits nStyle, BorderWindowStyle nTypeStyle ) : Window( WindowType::BORDERWINDOW ) { ImplInit( pParent, nStyle, nTypeStyle, pSystemParentData ); } ImplBorderWindow::ImplBorderWindow( vcl::Window* pParent, WinBits nStyle , BorderWindowStyle nTypeStyle ) : Window( WindowType::BORDERWINDOW ) { ImplInit( pParent, nStyle, nTypeStyle, nullptr ); } ImplBorderWindow::~ImplBorderWindow() { disposeOnce(); } void ImplBorderWindow::dispose() { mpBorderView.reset(); mpMenuBarWindow.clear(); mpNotebookBar.disposeAndClear(); vcl::Window::dispose(); } void ImplBorderWindow::MouseMove( const MouseEvent& rMEvt ) { if (mpBorderView) mpBorderView->MouseMove( rMEvt ); } void ImplBorderWindow::MouseButtonDown( const MouseEvent& rMEvt ) { if (mpBorderView) mpBorderView->MouseButtonDown( rMEvt ); } void ImplBorderWindow::Tracking( const TrackingEvent& rTEvt ) { if (mpBorderView) mpBorderView->Tracking( rTEvt ); } void ImplBorderWindow::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& ) { if (mpBorderView) mpBorderView->DrawWindow(rRenderContext); } void ImplBorderWindow::Draw( OutputDevice* pOutDev, const Point& rPos ) { if (mpBorderView) mpBorderView->DrawWindow(*pOutDev, &rPos); } void ImplBorderWindow::Activate() { SetDisplayActive( true ); Window::Activate(); } void ImplBorderWindow::Deactivate() { // remove active windows from the ruler, also ignore the Deactivate // if a menu becomes active if (GetActivateMode() != ActivateModeFlags::NONE && !ImplGetSVData()->mpWinData->mbNoDeactivate) SetDisplayActive( false ); Window::Deactivate(); } void ImplBorderWindow::RequestHelp( const HelpEvent& rHEvt ) { // no keyboard help for border window if ( rHEvt.GetMode() & (HelpEventMode::BALLOON | HelpEventMode::QUICK) && !rHEvt.KeyboardActivated() ) { Point aMousePosPixel = ScreenToOutputPixel( rHEvt.GetMousePosPixel() ); tools::Rectangle aHelpRect; OUString aHelpStr( mpBorderView->RequestHelp( aMousePosPixel, aHelpRect ) ); // retrieve rectangle if ( !aHelpStr.isEmpty() ) { aHelpRect.SetPos( OutputToScreenPixel( aHelpRect.TopLeft() ) ); if ( rHEvt.GetMode() & HelpEventMode::BALLOON ) Help::ShowBalloon( this, aHelpRect.Center(), aHelpRect, aHelpStr ); else Help::ShowQuickHelp( this, aHelpRect, aHelpStr ); return; } } Window::RequestHelp( rHEvt ); } void ImplBorderWindow::Resize() { Size aSize = GetOutputSizePixel(); vcl::Window* pClientWindow = ImplGetClientWindow(); sal_Int32 nLeftBorder; sal_Int32 nTopBorder; sal_Int32 nRightBorder; sal_Int32 nBottomBorder; mpBorderView->GetBorder( nLeftBorder, nTopBorder, nRightBorder, nBottomBorder ); if (mpMenuBarWindow) { tools::Long nMenuHeight = mpMenuBarWindow->GetSizePixel().Height(); if ( mbMenuHide ) { if ( nMenuHeight ) mnOrgMenuHeight = nMenuHeight; nMenuHeight = 0; } else { if ( !nMenuHeight ) nMenuHeight = mnOrgMenuHeight; } mpMenuBarWindow->setPosSizePixel( nLeftBorder, nTopBorder, aSize.Width()-nLeftBorder-nRightBorder, nMenuHeight); // shift the notebookbar down accordingly nTopBorder += nMenuHeight; } if (mpNotebookBar) { tools::Long nNotebookBarHeight = mpNotebookBar->GetSizePixel().Height(); mpNotebookBar->setPosSizePixel( nLeftBorder, nTopBorder, aSize.Width() - nLeftBorder - nRightBorder, nNotebookBarHeight); } GetBorder( pClientWindow->mpWindowImpl->mnLeftBorder, pClientWindow->mpWindowImpl->mnTopBorder, pClientWindow->mpWindowImpl->mnRightBorder, pClientWindow->mpWindowImpl->mnBottomBorder ); pClientWindow->ImplPosSizeWindow( pClientWindow->mpWindowImpl->mnLeftBorder, pClientWindow->mpWindowImpl->mnTopBorder, aSize.Width()-pClientWindow->mpWindowImpl->mnLeftBorder-pClientWindow->mpWindowImpl->mnRightBorder, aSize.Height()-pClientWindow->mpWindowImpl->mnTopBorder-pClientWindow->mpWindowImpl->mnBottomBorder, PosSizeFlags::X | PosSizeFlags::Y | PosSizeFlags::Width | PosSizeFlags::Height ); // UpdateView mpBorderView->Init( GetOutDev(), aSize.Width(), aSize.Height() ); InvalidateBorder(); Window::Resize(); } void ImplBorderWindow::StateChanged( StateChangedType nType ) { if ( (nType == StateChangedType::Text) || (nType == StateChangedType::Data) ) { if (IsReallyVisible() && mbFrameBorder) InvalidateBorder(); } Window::StateChanged( nType ); } void ImplBorderWindow::DataChanged( const DataChangedEvent& rDCEvt ) { if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) || (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) || ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) ) { if ( !mpWindowImpl->mbFrame || (GetStyle() & (WB_OWNERDRAWDECORATION | WB_POPUP)) ) UpdateView( true, ImplGetWindow()->GetOutputSizePixel() ); } Window::DataChanged( rDCEvt ); } void ImplBorderWindow::InitView() { if ( mbSmallOutBorder ) mpBorderView.reset(new ImplSmallBorderWindowView( this )); else if ( mpWindowImpl->mbFrame ) { if( mbFrameBorder ) mpBorderView.reset(new ImplStdBorderWindowView( this )); else mpBorderView.reset(new ImplNoBorderWindowView); } else if ( !mbFrameBorder ) mpBorderView.reset(new ImplSmallBorderWindowView( this )); else mpBorderView.reset(new ImplStdBorderWindowView( this )); Size aSize = GetOutputSizePixel(); mpBorderView->Init( GetOutDev(), aSize.Width(), aSize.Height() ); } void ImplBorderWindow::UpdateView( bool bNewView, const Size& rNewOutSize ) { sal_Int32 nLeftBorder; sal_Int32 nTopBorder; sal_Int32 nRightBorder; sal_Int32 nBottomBorder; Size aOldSize = GetSizePixel(); Size aOutputSize = rNewOutSize; if ( bNewView ) { mpBorderView.reset(); InitView(); } else { Size aSize = aOutputSize; mpBorderView->GetBorder( nLeftBorder, nTopBorder, nRightBorder, nBottomBorder ); aSize.AdjustWidth(nLeftBorder+nRightBorder ); aSize.AdjustHeight(nTopBorder+nBottomBorder ); mpBorderView->Init( GetOutDev(), aSize.Width(), aSize.Height() ); } vcl::Window* pClientWindow = ImplGetClientWindow(); if ( pClientWindow ) { GetBorder( pClientWindow->mpWindowImpl->mnLeftBorder, pClientWindow->mpWindowImpl->mnTopBorder, pClientWindow->mpWindowImpl->mnRightBorder, pClientWindow->mpWindowImpl->mnBottomBorder ); } GetBorder( nLeftBorder, nTopBorder, nRightBorder, nBottomBorder ); if ( aOldSize.Width() || aOldSize.Height() ) { aOutputSize.AdjustWidth(nLeftBorder+nRightBorder ); aOutputSize.AdjustHeight(nTopBorder+nBottomBorder ); if ( aOutputSize == GetSizePixel() ) InvalidateBorder(); else SetSizePixel( aOutputSize ); } } void ImplBorderWindow::InvalidateBorder() { if ( !IsReallyVisible() ) return; // invalidate only if we have a border sal_Int32 nLeftBorder; sal_Int32 nTopBorder; sal_Int32 nRightBorder; sal_Int32 nBottomBorder; mpBorderView->GetBorder( nLeftBorder, nTopBorder, nRightBorder, nBottomBorder ); if ( !(nLeftBorder || nTopBorder || nRightBorder || nBottomBorder) ) return; tools::Rectangle aWinRect( Point( 0, 0 ), GetOutputSizePixel() ); vcl::Region aRegion( aWinRect ); aWinRect.AdjustLeft(nLeftBorder ); aWinRect.AdjustTop(nTopBorder ); aWinRect.AdjustRight( -nRightBorder ); aWinRect.AdjustBottom( -nBottomBorder ); // no output area anymore, now invalidate all if ( (aWinRect.Right() < aWinRect.Left()) || (aWinRect.Bottom() < aWinRect.Top()) ) Invalidate( InvalidateFlags::NoChildren ); else { aRegion.Exclude( aWinRect ); Invalidate( aRegion, InvalidateFlags::NoChildren ); } } void ImplBorderWindow::SetDisplayActive( bool bActive ) { if ( mbDisplayActive != bActive ) { mbDisplayActive = bActive; if ( mbFrameBorder ) InvalidateBorder(); } } void ImplBorderWindow::SetTitleType( BorderWindowTitleType nTitleType, const Size& rSize ) { mnTitleType = nTitleType; UpdateView( false, rSize ); } void ImplBorderWindow::SetBorderStyle( WindowBorderStyle nStyle ) { if ( !mbFrameBorder && (mnBorderStyle != nStyle) ) { mnBorderStyle = nStyle; UpdateView( false, ImplGetWindow()->GetOutputSizePixel() ); } } void ImplBorderWindow::SetCloseButton() { SetStyle( GetStyle() | WB_CLOSEABLE ); Size aSize = GetOutputSizePixel(); mpBorderView->Init( GetOutDev(), aSize.Width(), aSize.Height() ); InvalidateBorder(); } void ImplBorderWindow::SetDockButton( bool bDockButton ) { mbDockBtn = bDockButton; Size aSize = GetOutputSizePixel(); mpBorderView->Init( GetOutDev(), aSize.Width(), aSize.Height() ); InvalidateBorder(); } void ImplBorderWindow::SetHideButton( bool bHideButton ) { mbHideBtn = bHideButton; Size aSize = GetOutputSizePixel(); mpBorderView->Init( GetOutDev(), aSize.Width(), aSize.Height() ); InvalidateBorder(); } void ImplBorderWindow::SetMenuButton( bool bMenuButton ) { mbMenuBtn = bMenuButton; Size aSize = GetOutputSizePixel(); mpBorderView->Init( GetOutDev(), aSize.Width(), aSize.Height() ); InvalidateBorder(); } void ImplBorderWindow::UpdateMenuHeight() { Resize(); } void ImplBorderWindow::SetMenuBarWindow( vcl::Window* pWindow ) { mpMenuBarWindow = pWindow; UpdateMenuHeight(); if ( pWindow ) pWindow->Show(); } void ImplBorderWindow::SetMenuBarMode( bool bHide ) { mbMenuHide = bHide; UpdateMenuHeight(); } void ImplBorderWindow::SetNotebookBar(const OUString& rUIXMLDescription, const css::uno::Reference& rFrame, const NotebookBarAddonsItem& aNotebookBarAddonsItem) { if (mpNotebookBar) mpNotebookBar.disposeAndClear(); mpNotebookBar = VclPtr::Create(this, "NotebookBar", rUIXMLDescription, rFrame, aNotebookBarAddonsItem); Resize(); } void ImplBorderWindow::CloseNotebookBar() { if (mpNotebookBar) mpNotebookBar.disposeAndClear(); mpNotebookBar = nullptr; Resize(); } void ImplBorderWindow::GetBorder( sal_Int32& rLeftBorder, sal_Int32& rTopBorder, sal_Int32& rRightBorder, sal_Int32& rBottomBorder ) const { mpBorderView->GetBorder(rLeftBorder, rTopBorder, rRightBorder, rBottomBorder); if (mpMenuBarWindow && !mbMenuHide) rTopBorder += mpMenuBarWindow->GetSizePixel().Height(); if (mpNotebookBar && mpNotebookBar->IsVisible()) rTopBorder += mpNotebookBar->GetSizePixel().Height(); } tools::Long ImplBorderWindow::CalcTitleWidth() const { return mpBorderView->CalcTitleWidth(); } tools::Rectangle ImplBorderWindow::GetMenuRect() const { return mpBorderView->GetMenuRect(); } Size ImplBorderWindow::GetOptimalSize() const { const vcl::Window* pClientWindow = ImplGetClientWindow(); if (pClientWindow) return pClientWindow->GetOptimalSize(); return Size(mnMinWidth, mnMinHeight); } void ImplBorderWindow::queue_resize(StateChangedType eReason) { //if we are floating, then we don't want to inform our parent that it needs //to calculate a new layout allocation. Because while we are a child //of our parent we are not embedded into the parent so it doesn't care //about us. if (mbFloatWindow) return; vcl::Window::queue_resize(eReason); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */