/* -*- 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 class ImplHeadItem { public: sal_uInt16 mnId; HeaderBarItemBits mnBits; long mnSize; OString maHelpId; Image maImage; OUString maOutText; OUString maText; OUString maHelpText; }; #define HEAD_ARROWSIZE1 4 #define HEAD_ARROWSIZE2 7 #define HEADERBAR_TEXTOFF 2 #define HEADERBAR_ARROWOFF 5 #define HEADERBAR_SPLITOFF 3 #define HEADERBAR_DRAGOUTOFF 15 #define HEAD_HITTEST_ITEM ((sal_uInt16)0x0001) #define HEAD_HITTEST_DIVIDER ((sal_uInt16)0x0002) void HeaderBar::ImplInit( WinBits nWinStyle ) { mpItemList = new ImplHeadItemList; mnBorderOff1 = 0; mnBorderOff2 = 0; mnOffset = 0; mnDX = 0; mnDY = 0; mnDragSize = 0; mnStartPos = 0; mnDragPos = 0; mnMouseOff = 0; mnCurItemId = 0; mnItemDragPos = HEADERBAR_ITEM_NOTFOUND; mbDrag = false; mbItemDrag = false; mbOutDrag = false; mbItemMode = false; m_pVCLXHeaderBar = NULL; // StyleBits auswerten if ( nWinStyle & WB_DRAG ) mbDragable = true; else mbDragable = false; if ( nWinStyle & WB_BUTTONSTYLE ) mbButtonStyle = true; else mbButtonStyle = false; if ( nWinStyle & WB_BORDER ) { mnBorderOff1 = 1; mnBorderOff2 = 1; } else { if ( nWinStyle & WB_BOTTOMBORDER ) mnBorderOff2 = 1; } ImplInitSettings( true, true, true ); } HeaderBar::HeaderBar( vcl::Window* pParent, WinBits nWinStyle ) : Window( pParent, nWinStyle & WB_3DLOOK ) { ImplInit( nWinStyle ); SetSizePixel( CalcWindowSizePixel() ); } HeaderBar::~HeaderBar() { disposeOnce(); } void HeaderBar::dispose() { if (mpItemList) { for ( size_t i = 0, n = mpItemList->size(); i < n; ++i ) delete (*mpItemList)[ i ]; delete mpItemList; mpItemList = NULL; } Window::dispose(); } void HeaderBar::ApplySettings(vcl::RenderContext& rRenderContext) { const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); ApplyControlFont(rRenderContext, rStyleSettings.GetToolFont()); ApplyControlForeground(rRenderContext, rStyleSettings.GetButtonTextColor()); SetTextFillColor(); ApplyControlBackground(rRenderContext, rStyleSettings.GetFaceColor()); } void HeaderBar::ImplInitSettings(bool bFont, bool bForeground, bool bBackground) { const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings(); if (bFont) ApplyControlFont(*this, rStyleSettings.GetToolFont()); if (bForeground || bFont) { ApplyControlForeground(*this, rStyleSettings.GetButtonTextColor()); SetTextFillColor(); } if (bBackground) ApplyControlBackground(*this, rStyleSettings.GetFaceColor()); } long HeaderBar::ImplGetItemPos( sal_uInt16 nPos ) const { long nX = -mnOffset; for ( size_t i = 0; i < nPos; i++ ) nX += (*mpItemList)[ i ]->mnSize; return nX; } Rectangle HeaderBar::ImplGetItemRect( sal_uInt16 nPos ) const { Rectangle aRect( ImplGetItemPos( nPos ), 0, 0, mnDY-1 ); aRect.Right() = aRect.Left() + (*mpItemList)[ nPos ]->mnSize - 1; // check for overflow on various systems if ( aRect.Right() > 16000 ) aRect.Right() = 16000; return aRect; } sal_uInt16 HeaderBar::ImplHitTest( const Point& rPos, long& nMouseOff, sal_uInt16& nPos ) const { ImplHeadItem* pItem; size_t nCount = (sal_uInt16)mpItemList->size(); bool bLastFixed = true; long nX = -mnOffset; for ( size_t i = 0; i < nCount; i++ ) { pItem = (*mpItemList)[ i ]; if ( rPos.X() < (nX+pItem->mnSize) ) { sal_uInt16 nMode; if ( !bLastFixed && (rPos.X() < (nX+HEADERBAR_SPLITOFF)) ) { nMode = HEAD_HITTEST_DIVIDER; nPos = i-1; nMouseOff = rPos.X()-nX+1; } else { nPos = i; if ( !(pItem->mnBits & HeaderBarItemBits::FIXED) && (rPos.X() >= (nX+pItem->mnSize-HEADERBAR_SPLITOFF)) ) { nMode = HEAD_HITTEST_DIVIDER; nMouseOff = rPos.X()-(nX+pItem->mnSize); } else { nMode = HEAD_HITTEST_ITEM; nMouseOff = rPos.X()-nX; } } return nMode; } if ( pItem->mnBits & HeaderBarItemBits::FIXED ) bLastFixed = true; else bLastFixed = false; nX += pItem->mnSize; } if ( !bLastFixed ) { pItem = (*mpItemList)[ nCount-1 ]; if ( (pItem->mnSize < 4) && (rPos.X() < (nX+HEADERBAR_SPLITOFF)) ) { nPos = nCount-1; nMouseOff = rPos.X()-nX+1; return HEAD_HITTEST_DIVIDER; } } return 0; } void HeaderBar::ImplInvertDrag( sal_uInt16 nStartPos, sal_uInt16 nEndPos ) { Rectangle aRect1 = ImplGetItemRect( nStartPos ); Rectangle aRect2 = ImplGetItemRect( nEndPos ); Point aStartPos = aRect1.Center(); Point aEndPos = aStartPos; Rectangle aStartRect( aStartPos.X()-2, aStartPos.Y()-2, aStartPos.X()+2, aStartPos.Y()+2 ); if ( nEndPos > nStartPos ) { aStartPos.X() += 3; aEndPos.X() = aRect2.Right()-6; } else { aStartPos.X() -= 3; aEndPos.X() = aRect2.Left()+6; } SetRasterOp( ROP_INVERT ); DrawRect( aStartRect ); DrawLine( aStartPos, aEndPos ); if ( nEndPos > nStartPos ) { DrawLine( Point( aEndPos.X()+1, aEndPos.Y()-3 ), Point( aEndPos.X()+1, aEndPos.Y()+3 ) ); DrawLine( Point( aEndPos.X()+2, aEndPos.Y()-2 ), Point( aEndPos.X()+2, aEndPos.Y()+2 ) ); DrawLine( Point( aEndPos.X()+3, aEndPos.Y()-1 ), Point( aEndPos.X()+3, aEndPos.Y()+1 ) ); DrawPixel( Point( aEndPos.X()+4, aEndPos.Y() ) ); } else { DrawLine( Point( aEndPos.X()-1, aEndPos.Y()-3 ), Point( aEndPos.X()-1, aEndPos.Y()+3 ) ); DrawLine( Point( aEndPos.X()-2, aEndPos.Y()-2 ), Point( aEndPos.X()-2, aEndPos.Y()+2 ) ); DrawLine( Point( aEndPos.X()-3, aEndPos.Y()-1 ), Point( aEndPos.X()-3, aEndPos.Y()+1 ) ); DrawPixel( Point( aEndPos.X()-4, aEndPos.Y() ) ); } SetRasterOp( ROP_OVERPAINT ); } void HeaderBar::ImplDrawItem(vcl::RenderContext& rRenderContext, sal_uInt16 nPos, bool bHigh, bool bDrag, const Rectangle& rItemRect, const Rectangle* pRect, sal_uLong ) { ImplControlValue aControlValue(0); Rectangle aCtrlRegion; ControlState nState(ControlState::NONE); Rectangle aRect = rItemRect; // do not display if there is no space if (aRect.GetWidth() <= 1) return; // check of rectangle is visible if (pRect) { if (aRect.Right() < pRect->Left()) return; else if (aRect.Left() > pRect->Right()) return; } else { if (aRect.Right() < 0) return; else if (aRect.Left() > mnDX) return; } ImplHeadItem* pItem = (*mpItemList)[nPos]; HeaderBarItemBits nBits = pItem->mnBits; const StyleSettings& rStyleSettings = rRenderContext.GetSettings().GetStyleSettings(); if (rRenderContext.IsNativeControlSupported(CTRL_WINDOW_BACKGROUND, PART_ENTIRE_CONTROL)) { aCtrlRegion = aRect; rRenderContext.DrawNativeControl(CTRL_WINDOW_BACKGROUND, PART_ENTIRE_CONTROL, aCtrlRegion, nState, aControlValue, OUString()); } else { // do not draw border aRect.Top() += mnBorderOff1; aRect.Bottom() -= mnBorderOff2; // delete background if ( !pRect || bDrag ) { if (bDrag) { rRenderContext.SetLineColor(); rRenderContext.SetFillColor(rStyleSettings.GetCheckedColor()); rRenderContext.DrawRect(aRect); } else rRenderContext.DrawWallpaper(aRect, rRenderContext.GetBackground()); } } Color aSelectionTextColor(COL_TRANSPARENT); if (rRenderContext.IsNativeControlSupported(CTRL_LISTHEADER, PART_BUTTON)) { aCtrlRegion = aRect; aControlValue.setTristateVal(BUTTONVALUE_ON); nState |= ControlState::ENABLED; if (bHigh) nState |= ControlState::PRESSED; rRenderContext.DrawNativeControl(CTRL_LISTHEADER, PART_BUTTON, aCtrlRegion, nState, aControlValue, OUString()); } else { // draw separation line rRenderContext.SetLineColor(rStyleSettings.GetDarkShadowColor()); rRenderContext.DrawLine(Point(aRect.Right(), aRect.Top()), Point(aRect.Right(), aRect.Bottom())); // draw ButtonStyle // avoid 3D borders if (bHigh) vcl::RenderTools::DrawSelectionBackground(rRenderContext, *this, aRect, 1, true, false, false, &aSelectionTextColor); else if (!mbButtonStyle || (nBits & HeaderBarItemBits::FLAT)) vcl::RenderTools::DrawSelectionBackground(rRenderContext, *this, aRect, 0, true, false, false, &aSelectionTextColor); } // do not draw if there is no space if (aRect.GetWidth() < 1) return; // calculate size and position and draw content pItem->maOutText = pItem->maText; Size aImageSize = pItem->maImage.GetSizePixel(); Size aTxtSize(rRenderContext.GetTextWidth(pItem->maOutText), 0); if (!pItem->maOutText.isEmpty()) aTxtSize.Height() = rRenderContext.GetTextHeight(); long nArrowWidth = 0; if (nBits & (HeaderBarItemBits::UPARROW | HeaderBarItemBits::DOWNARROW)) nArrowWidth = HEAD_ARROWSIZE2 + HEADERBAR_ARROWOFF; // do not draw if there is not enough space for the image long nTestHeight = aImageSize.Height(); if (!(nBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE))) nTestHeight += aTxtSize.Height(); if ((aImageSize.Width() > aRect.GetWidth()) || (nTestHeight > aRect.GetHeight())) { aImageSize.Width() = 0; aImageSize.Height() = 0; } // cut text to correct length bool bLeftText = false; long nMaxTxtWidth = aRect.GetWidth() - (HEADERBAR_TEXTOFF * 2) - nArrowWidth; if (nBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE)) nMaxTxtWidth -= aImageSize.Width(); long nTxtWidth = aTxtSize.Width(); if (nTxtWidth > nMaxTxtWidth) { bLeftText = true; OUStringBuffer aBuf(pItem->maOutText); aBuf.append("..."); do { aBuf.remove(aBuf.getLength() - 3 - 1, 1); nTxtWidth = rRenderContext.GetTextWidth(aBuf.toString()); } while ((nTxtWidth > nMaxTxtWidth) && (aBuf.getLength() > 3)); pItem->maOutText = aBuf.makeStringAndClear(); if (pItem->maOutText.getLength() == 3) { nTxtWidth = 0; pItem->maOutText.clear(); } } // calculate text/imageposition long nTxtPos; if (!bLeftText && (nBits & HeaderBarItemBits::RIGHT)) { nTxtPos = aRect.Right() - nTxtWidth - HEADERBAR_TEXTOFF; if (nBits & HeaderBarItemBits::RIGHTIMAGE) nTxtPos -= aImageSize.Width(); } else if (!bLeftText && (nBits & HeaderBarItemBits::CENTER)) { long nTempWidth = nTxtWidth; if (nBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE)) nTempWidth += aImageSize.Width(); nTxtPos = aRect.Left() + (aRect.GetWidth() - nTempWidth) / 2; if (nBits & HeaderBarItemBits::LEFTIMAGE) nTxtPos += aImageSize.Width(); if (nArrowWidth) { if (nTxtPos + nTxtWidth + nArrowWidth >= aRect.Right()) { nTxtPos = aRect.Left() + HEADERBAR_TEXTOFF; if (nBits & HeaderBarItemBits::LEFTIMAGE) nTxtPos += aImageSize.Width(); } } } else { nTxtPos = aRect.Left() + HEADERBAR_TEXTOFF; if (nBits & HeaderBarItemBits::LEFTIMAGE) nTxtPos += aImageSize.Width(); if (nBits & HeaderBarItemBits::RIGHT) nTxtPos += nArrowWidth; } // calculate text/imageposition long nTxtPosY = 0; if (!pItem->maOutText.isEmpty() || (nArrowWidth && aTxtSize.Height())) { if (nBits & HeaderBarItemBits::TOP) { nTxtPosY = aRect.Top(); if (!(nBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE))) nTxtPosY += aImageSize.Height(); } else if (nBits & HeaderBarItemBits::BOTTOM) nTxtPosY = aRect.Bottom()-aTxtSize.Height(); else { long nTempHeight = aTxtSize.Height(); nTempHeight += aImageSize.Height(); nTxtPosY = aRect.Top()+((aRect.GetHeight()-nTempHeight)/2); if (!(nBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE))) nTxtPosY += aImageSize.Height(); } } // display text if (!pItem->maOutText.isEmpty()) { if (aSelectionTextColor != Color(COL_TRANSPARENT)) { rRenderContext.Push(PushFlags::TEXTCOLOR); rRenderContext.SetTextColor(aSelectionTextColor); } if (IsEnabled()) rRenderContext.DrawText(Point(nTxtPos, nTxtPosY), pItem->maOutText); else rRenderContext.DrawCtrlText(Point(nTxtPos, nTxtPosY), pItem->maOutText, 0, pItem->maOutText.getLength(), DrawTextFlags::Disable); if (aSelectionTextColor != Color(COL_TRANSPARENT)) rRenderContext.Pop(); } // calculate the position and draw image if it is available long nImagePosY = 0; if (aImageSize.Width() && aImageSize.Height()) { long nImagePos = nTxtPos; if (nBits & HeaderBarItemBits::LEFTIMAGE) { nImagePos -= aImageSize.Width(); if (nBits & HeaderBarItemBits::RIGHT) nImagePos -= nArrowWidth; } else if (nBits & HeaderBarItemBits::RIGHTIMAGE) { nImagePos += nTxtWidth; if (!(nBits & HeaderBarItemBits::RIGHT)) nImagePos += nArrowWidth; } else { if (nBits & HeaderBarItemBits::RIGHT ) nImagePos = aRect.Right()-aImageSize.Width(); else if (nBits & HeaderBarItemBits::CENTER) nImagePos = aRect.Left() + (aRect.GetWidth() - aImageSize.Width()) / 2; else nImagePos = aRect.Left() + HEADERBAR_TEXTOFF; } if (nBits & HeaderBarItemBits::TOP) nImagePosY = aRect.Top(); else if (nBits & HeaderBarItemBits::BOTTOM) { nImagePosY = aRect.Bottom() - aImageSize.Height(); if (!(nBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE))) nImagePosY -= aTxtSize.Height(); } else { long nTempHeight = aImageSize.Height(); if (!(nBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE))) nTempHeight += aTxtSize.Height(); nImagePosY = aRect.Top() + ((aRect.GetHeight() - nTempHeight) / 2); } if (nImagePos + aImageSize.Width() <= aRect.Right()) { sal_uInt16 nStyle = 0; if (!IsEnabled()) nStyle |= IMAGE_DRAW_DISABLE; rRenderContext.DrawImage(Point(nImagePos, nImagePosY), pItem->maImage, nStyle); } } if (nBits & (HeaderBarItemBits::UPARROW | HeaderBarItemBits::DOWNARROW)) { long nArrowX = nTxtPos; if (nBits & HeaderBarItemBits::RIGHT) nArrowX -= nArrowWidth; else nArrowX += nTxtWidth + HEADERBAR_ARROWOFF; if (!(nBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE)) && pItem->maText.isEmpty()) { if (nBits & HeaderBarItemBits::RIGHT) nArrowX -= aImageSize.Width(); else nArrowX += aImageSize.Width(); } // is there enough space to draw the item? bool bDraw = true; if (nArrowX < aRect.Left() + HEADERBAR_TEXTOFF) bDraw = false; else if (nArrowX + HEAD_ARROWSIZE2 > aRect.Right()) bDraw = false; if (bDraw) { if (rRenderContext.IsNativeControlSupported(CTRL_LISTHEADER, PART_ARROW)) { aCtrlRegion = Rectangle(Point(nArrowX, aRect.Top()), Size(nArrowWidth, aRect.GetHeight())); // control value passes 1 if arrow points down, 0 otherwise aControlValue.setNumericVal((nBits & HeaderBarItemBits::DOWNARROW) ? 1 : 0); nState |= ControlState::ENABLED; if (bHigh) nState |= ControlState::PRESSED; rRenderContext.DrawNativeControl(CTRL_LISTHEADER, PART_ARROW, aCtrlRegion, nState, aControlValue, OUString()); } else { long nArrowY; if (aTxtSize.Height()) nArrowY = nTxtPosY + (aTxtSize.Height() / 2); else if (aImageSize.Width() && aImageSize.Height()) nArrowY = nImagePosY + (aImageSize.Height() / 2); else { if (nBits & HeaderBarItemBits::TOP) nArrowY = aRect.Top() + 1; else if (nBits & HeaderBarItemBits::BOTTOM) nArrowY = aRect.Bottom() - HEAD_ARROWSIZE2 - 1; else nArrowY = aRect.Top() + ((aRect.GetHeight() - HEAD_ARROWSIZE2) / 2); } nArrowY -= HEAD_ARROWSIZE1 - 1; if (nBits & HeaderBarItemBits::DOWNARROW) { rRenderContext.SetLineColor(rStyleSettings.GetLightColor()); rRenderContext.DrawLine(Point(nArrowX, nArrowY), Point(nArrowX + HEAD_ARROWSIZE2, nArrowY)); rRenderContext.DrawLine(Point(nArrowX, nArrowY), Point(nArrowX + HEAD_ARROWSIZE1, nArrowY + HEAD_ARROWSIZE2)); rRenderContext.SetLineColor(rStyleSettings.GetShadowColor()); rRenderContext.DrawLine(Point(nArrowX + HEAD_ARROWSIZE1, nArrowY + HEAD_ARROWSIZE2), Point(nArrowX + HEAD_ARROWSIZE2, nArrowY)); } else { rRenderContext.SetLineColor(rStyleSettings.GetLightColor()); rRenderContext.DrawLine(Point(nArrowX, nArrowY + HEAD_ARROWSIZE2), Point(nArrowX + HEAD_ARROWSIZE1, nArrowY)); rRenderContext.SetLineColor(rStyleSettings.GetShadowColor()); rRenderContext.DrawLine(Point(nArrowX, nArrowY + HEAD_ARROWSIZE2), Point(nArrowX + HEAD_ARROWSIZE2, nArrowY + HEAD_ARROWSIZE2)); rRenderContext.DrawLine(Point(nArrowX + HEAD_ARROWSIZE2, nArrowY + HEAD_ARROWSIZE2), Point(nArrowX + HEAD_ARROWSIZE1, nArrowY)); } } } } } void HeaderBar::ImplDrawItem(vcl::RenderContext& rRenderContext, sal_uInt16 nPos, bool bHigh, bool bDrag, const Rectangle* pRect ) { Rectangle aRect = ImplGetItemRect(nPos); ImplDrawItem(rRenderContext, nPos, bHigh, bDrag, aRect, pRect, 0 ); } void HeaderBar::ImplUpdate(sal_uInt16 nPos, bool bEnd, bool /*bDirect*/) { if (IsVisible() && IsUpdateMode()) { Rectangle aRect; size_t nItemCount = mpItemList->size(); if (nPos < nItemCount) aRect = ImplGetItemRect(nPos); else { aRect.Bottom() = mnDY - 1; if (nItemCount) aRect.Left() = ImplGetItemRect(nItemCount - 1).Right(); } if (bEnd) aRect.Right() = mnDX - 1; aRect.Top() += mnBorderOff1; aRect.Bottom() -= mnBorderOff2; Invalidate(aRect); } } void HeaderBar::ImplStartDrag( const Point& rMousePos, bool bCommand ) { sal_uInt16 nPos; sal_uInt16 nHitTest = ImplHitTest( rMousePos, mnMouseOff, nPos ); if ( nHitTest ) { mbDrag = false; ImplHeadItem* pItem = (*mpItemList)[ nPos ]; if ( nHitTest & HEAD_HITTEST_DIVIDER ) mbDrag = true; else { if ( ((pItem->mnBits & HeaderBarItemBits::CLICKABLE) && !(pItem->mnBits & HeaderBarItemBits::FLAT)) || (mbDragable && !(pItem->mnBits & HeaderBarItemBits::FIXEDPOS)) ) { mbItemMode = true; mbDrag = true; if ( bCommand ) { if ( mbDragable ) mbItemDrag = true; else { mbItemMode = false; mbDrag = false; } } } else { if ( !bCommand ) { mnCurItemId = pItem->mnId; Select(); mnCurItemId = 0; } } } if ( mbDrag ) { mbOutDrag = false; mnCurItemId = pItem->mnId; mnItemDragPos = nPos; StartTracking(); mnStartPos = rMousePos.X()-mnMouseOff; mnDragPos = mnStartPos; StartDrag(); if (mbItemMode) Invalidate(); else { Rectangle aSizeRect( mnDragPos, 0, mnDragPos, mnDragSize+mnDY ); ShowTracking( aSizeRect, SHOWTRACK_SPLIT ); } } else mnMouseOff = 0; } } void HeaderBar::ImplDrag( const Point& rMousePos ) { sal_uInt16 nPos = GetItemPos( mnCurItemId ); mnDragPos = rMousePos.X()-mnMouseOff; if ( mbItemMode ) { bool bNewOutDrag; Rectangle aItemRect = ImplGetItemRect( nPos ); if ( aItemRect.IsInside( rMousePos ) ) bNewOutDrag = false; else bNewOutDrag = true; // if needed switch on ItemDrag if ( bNewOutDrag && mbDragable && !mbItemDrag && !((*mpItemList)[ nPos ]->mnBits & HeaderBarItemBits::FIXEDPOS) ) { if ( (rMousePos.Y() >= aItemRect.Top()) && (rMousePos.Y() <= aItemRect.Bottom()) ) { mbItemDrag = true; Invalidate(); } } sal_uInt16 nOldItemDragPos = mnItemDragPos; if ( mbItemDrag ) { if ( (rMousePos.Y() < -HEADERBAR_DRAGOUTOFF) || (rMousePos.Y() > mnDY+HEADERBAR_DRAGOUTOFF) ) bNewOutDrag = true; else bNewOutDrag = false; if ( bNewOutDrag ) mnItemDragPos = HEADERBAR_ITEM_NOTFOUND; else { sal_uInt16 nTempId = GetItemId( Point( rMousePos.X(), 2 ) ); if ( nTempId ) mnItemDragPos = GetItemPos( nTempId ); else { if ( rMousePos.X() <= 0 ) mnItemDragPos = 0; else mnItemDragPos = GetItemCount()-1; } // do not use non-movable items if ( mnItemDragPos < nPos ) { while ( ((*mpItemList)[ mnItemDragPos ]->mnBits & HeaderBarItemBits::FIXEDPOS) && (mnItemDragPos < nPos) ) mnItemDragPos++; } else if ( mnItemDragPos > nPos ) { while ( ((*mpItemList)[ mnItemDragPos ]->mnBits & HeaderBarItemBits::FIXEDPOS) && (mnItemDragPos > nPos) ) mnItemDragPos--; } } if ( (mnItemDragPos != nOldItemDragPos) && (nOldItemDragPos != nPos) && (nOldItemDragPos != HEADERBAR_ITEM_NOTFOUND) ) { ImplInvertDrag( nPos, nOldItemDragPos ); Invalidate(); } } if ( bNewOutDrag != mbOutDrag ) Invalidate(); if ( mbItemDrag ) { if ( (mnItemDragPos != nOldItemDragPos) && (mnItemDragPos != nPos) && (mnItemDragPos != HEADERBAR_ITEM_NOTFOUND) ) { Invalidate(); ImplInvertDrag( nPos, mnItemDragPos ); } } mbOutDrag = bNewOutDrag; } else { Rectangle aItemRect = ImplGetItemRect( nPos ); if ( mnDragPos < aItemRect.Left() ) mnDragPos = aItemRect.Left(); if ( (mnDragPos < 0) || (mnDragPos > mnDX-1) ) HideTracking(); else { Rectangle aSizeRect( mnDragPos, 0, mnDragPos, mnDragSize+mnDY ); ShowTracking( aSizeRect, SHOWTRACK_SPLIT ); } } Drag(); } void HeaderBar::ImplEndDrag( bool bCancel ) { HideTracking(); if ( bCancel || mbOutDrag ) { if ( mbItemMode && (!mbOutDrag || mbItemDrag) ) { Invalidate(); } mnCurItemId = 0; } else { sal_uInt16 nPos = GetItemPos( mnCurItemId ); if ( mbItemMode ) { if ( mbItemDrag ) { Pointer aPointer( POINTER_ARROW ); SetPointer( aPointer ); if ( (mnItemDragPos != nPos) && (mnItemDragPos != HEADERBAR_ITEM_NOTFOUND) ) { ImplInvertDrag( nPos, mnItemDragPos ); MoveItem( mnCurItemId, mnItemDragPos ); } else Invalidate(); } else { Select(); ImplUpdate( nPos ); } } else { long nDelta = mnDragPos - mnStartPos; if ( nDelta ) { ImplHeadItem* pItem = (*mpItemList)[ nPos ]; pItem->mnSize += nDelta; ImplUpdate( nPos, true ); } } } mbDrag = false; EndDrag(); mnCurItemId = 0; mnItemDragPos = HEADERBAR_ITEM_NOTFOUND; mbOutDrag = false; mbItemMode = false; mbItemDrag = false; } void HeaderBar::MouseButtonDown( const MouseEvent& rMEvt ) { if ( rMEvt.IsLeft() ) { if ( rMEvt.GetClicks() == 2 ) { long nTemp; sal_uInt16 nPos; sal_uInt16 nHitTest = ImplHitTest( rMEvt.GetPosPixel(), nTemp, nPos ); if ( nHitTest ) { ImplHeadItem* pItem = (*mpItemList)[ nPos ]; if ( nHitTest & HEAD_HITTEST_DIVIDER ) mbItemMode = false; else mbItemMode = true; mnCurItemId = pItem->mnId; DoubleClick(); mbItemMode = false; mnCurItemId = 0; } } else ImplStartDrag( rMEvt.GetPosPixel(), false ); } } void HeaderBar::MouseMove( const MouseEvent& rMEvt ) { long nTemp1; sal_uInt16 nTemp2; PointerStyle eStyle = POINTER_ARROW; sal_uInt16 nHitTest = ImplHitTest( rMEvt.GetPosPixel(), nTemp1, nTemp2 ); if ( nHitTest & HEAD_HITTEST_DIVIDER ) eStyle = POINTER_HSIZEBAR; Pointer aPtr( eStyle ); SetPointer( aPtr ); } void HeaderBar::Tracking( const TrackingEvent& rTEvt ) { Point aMousePos = rTEvt.GetMouseEvent().GetPosPixel(); if ( rTEvt.IsTrackingEnded() ) ImplEndDrag( rTEvt.IsTrackingCanceled() ); else ImplDrag( aMousePos ); } void HeaderBar::Paint(vcl::RenderContext& rRenderContext, const Rectangle& rRect) { if (mnBorderOff1 || mnBorderOff2) { rRenderContext.SetLineColor(rRenderContext.GetSettings().GetStyleSettings().GetDarkShadowColor()); if (mnBorderOff1) rRenderContext.DrawLine(Point(0, 0), Point(mnDX - 1, 0)); if (mnBorderOff2) rRenderContext.DrawLine(Point(0, mnDY - 1), Point(mnDX - 1, mnDY - 1)); // #i40393# draw left and right border, if WB_BORDER was set in ImplInit() if (mnBorderOff1 && mnBorderOff2) { rRenderContext.DrawLine(Point(0, 0), Point(0, mnDY - 1)); rRenderContext.DrawLine(Point(mnDX - 1, 0), Point(mnDX - 1, mnDY - 1)); } } sal_uInt16 nCurItemPos; if (mbDrag) nCurItemPos = GetItemPos(mnCurItemId); else nCurItemPos = HEADERBAR_ITEM_NOTFOUND; sal_uInt16 nItemCount = static_cast(mpItemList->size()); for (sal_uInt16 i = 0; i < nItemCount; i++) ImplDrawItem(rRenderContext, i, (i == nCurItemPos), false, &rRect); } void HeaderBar::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong nFlags ) { Point aPos = pDev->LogicToPixel( rPos ); Size aSize = pDev->LogicToPixel( rSize ); Rectangle aRect( aPos, aSize ); vcl::Font aFont = GetDrawPixelFont( pDev ); pDev->Push(); pDev->SetMapMode(); pDev->SetFont( aFont ); if ( nFlags & WINDOW_DRAW_MONO ) pDev->SetTextColor( Color( COL_BLACK ) ); else pDev->SetTextColor( GetTextColor() ); pDev->SetTextFillColor(); if ( !(nFlags & WINDOW_DRAW_NOBACKGROUND) ) { pDev->DrawWallpaper( aRect, GetBackground() ); if ( mnBorderOff1 || mnBorderOff2 ) { pDev->SetLineColor( GetSettings().GetStyleSettings().GetDarkShadowColor() ); if ( mnBorderOff1 ) pDev->DrawLine( aRect.TopLeft(), Point( aRect.Right(), aRect.Top() ) ); if ( mnBorderOff2 ) pDev->DrawLine( Point( aRect.Left(), aRect.Bottom() ), Point( aRect.Right(), aRect.Bottom() ) ); // #i40393# draw left and right border, if WB_BORDER was set in ImplInit() if ( mnBorderOff1 && mnBorderOff2 ) { pDev->DrawLine( aRect.TopLeft(), Point( aRect.Left(), aRect.Bottom() ) ); pDev->DrawLine( Point( aRect.Right(), aRect.Top() ), Point( aRect.Right(), aRect.Bottom() ) ); } } } Rectangle aItemRect( aRect ); size_t nItemCount = mpItemList->size(); for ( size_t i = 0; i < nItemCount; i++ ) { aItemRect.Left() = aRect.Left()+ImplGetItemPos( i ); aItemRect.Right() = aItemRect.Left() + (*mpItemList)[ i ]->mnSize - 1; // check for overflow on some systems if ( aItemRect.Right() > 16000 ) aItemRect.Right() = 16000; vcl::Region aRegion( aRect ); pDev->SetClipRegion( aRegion ); ImplDrawItem(*pDev, i, false, false, aItemRect, &aRect, nFlags ); pDev->SetClipRegion(); } pDev->Pop(); } void HeaderBar::Resize() { Size aSize = GetOutputSizePixel(); if ( IsVisible() && (mnDY != aSize.Height()) ) Invalidate(); mnDX = aSize.Width(); mnDY = aSize.Height(); } void HeaderBar::Command( const CommandEvent& rCEvt ) { if ( rCEvt.IsMouseEvent() && (rCEvt.GetCommand() == CommandEventId::StartDrag) && !mbDrag ) { ImplStartDrag( rCEvt.GetMousePosPixel(), true ); return; } Window::Command( rCEvt ); } void HeaderBar::RequestHelp( const HelpEvent& rHEvt ) { sal_uInt16 nItemId = GetItemId( ScreenToOutputPixel( rHEvt.GetMousePosPixel() ) ); if ( nItemId ) { if ( rHEvt.GetMode() & (HelpEventMode::QUICK | HelpEventMode::BALLOON) ) { Rectangle aItemRect = GetItemRect( nItemId ); Point aPt = OutputToScreenPixel( aItemRect.TopLeft() ); aItemRect.Left() = aPt.X(); aItemRect.Top() = aPt.Y(); aPt = OutputToScreenPixel( aItemRect.BottomRight() ); aItemRect.Right() = aPt.X(); aItemRect.Bottom() = aPt.Y(); OUString aStr = GetHelpText( nItemId ); if ( aStr.isEmpty() || !(rHEvt.GetMode() & HelpEventMode::BALLOON) ) { ImplHeadItem* pItem = (*mpItemList)[ GetItemPos( nItemId ) ]; // Quick-help is only displayed if the text is not fully visible. // Otherwise we display Helptext only if the items do not contain text if ( pItem->maOutText != pItem->maText ) aStr = pItem->maText; else if (!pItem->maText.isEmpty()) aStr.clear(); } if (!aStr.isEmpty()) { if ( rHEvt.GetMode() & HelpEventMode::BALLOON ) Help::ShowBalloon( this, aItemRect.Center(), aItemRect, aStr ); else Help::ShowQuickHelp( this, aItemRect, aStr ); return; } } else if ( rHEvt.GetMode() & HelpEventMode::EXTENDED ) { OUString aHelpId( OStringToOUString( GetHelpId( nItemId ), RTL_TEXTENCODING_UTF8 ) ); if ( !aHelpId.isEmpty() ) { // display it if help is available Help* pHelp = Application::GetHelp(); if ( pHelp ) pHelp->Start( aHelpId, this ); return; } } } Window::RequestHelp( rHEvt ); } void HeaderBar::StateChanged( StateChangedType nType ) { Window::StateChanged( nType ); if ( nType == StateChangedType::Enable ) Invalidate(); else if ( (nType == StateChangedType::Zoom) || (nType == StateChangedType::ControlFont) ) { ImplInitSettings( true, false, false ); Invalidate(); } else if ( nType == StateChangedType::ControlForeground ) { ImplInitSettings( false, true, false ); Invalidate(); } else if ( nType == StateChangedType::ControlBackground ) { ImplInitSettings( false, false, true ); Invalidate(); } } void HeaderBar::DataChanged( const DataChangedEvent& rDCEvt ) { Window::DataChanged( rDCEvt ); if ( (rDCEvt.GetType() == DataChangedEventType::FONTS) || (rDCEvt.GetType() == DataChangedEventType::FONTSUBSTITUTION) || ((rDCEvt.GetType() == DataChangedEventType::SETTINGS) && (rDCEvt.GetFlags() & AllSettingsFlags::STYLE)) ) { ImplInitSettings( true, true, true ); Invalidate(); } } void HeaderBar::StartDrag() { maStartDragHdl.Call( this ); } void HeaderBar::Drag() { maDragHdl.Call( this ); } void HeaderBar::EndDrag() { maEndDragHdl.Call( this ); } void HeaderBar::Select() { maSelectHdl.Call( this ); } void HeaderBar::DoubleClick() { maDoubleClickHdl.Call( this ); } void HeaderBar::InsertItem( sal_uInt16 nItemId, const OUString& rText, long nSize, HeaderBarItemBits nBits, sal_uInt16 nPos ) { DBG_ASSERT( nItemId, "HeaderBar::InsertItem(): ItemId == 0" ); DBG_ASSERT( GetItemPos( nItemId ) == HEADERBAR_ITEM_NOTFOUND, "HeaderBar::InsertItem(): ItemId already exists" ); // create item and insert in the list ImplHeadItem* pItem = new ImplHeadItem; pItem->mnId = nItemId; pItem->mnBits = nBits; pItem->mnSize = nSize; pItem->maText = rText; if ( nPos < mpItemList->size() ) { ImplHeadItemList::iterator it = mpItemList->begin(); ::std::advance( it, nPos ); mpItemList->insert( it, pItem ); } else { mpItemList->push_back( pItem ); } // update display ImplUpdate( nPos, true ); } void HeaderBar::RemoveItem( sal_uInt16 nItemId ) { sal_uInt16 nPos = GetItemPos( nItemId ); if ( nPos != HEADERBAR_ITEM_NOTFOUND ) { if ( nPos < mpItemList->size() ) { ImplHeadItemList::iterator it = mpItemList->begin(); ::std::advance( it, nPos ); delete *it; mpItemList->erase( it ); } } } void HeaderBar::MoveItem( sal_uInt16 nItemId, sal_uInt16 nNewPos ) { sal_uInt16 nPos = GetItemPos( nItemId ); if ( nPos != HEADERBAR_ITEM_NOTFOUND ) { if ( nPos != nNewPos ) { ImplHeadItemList::iterator it = mpItemList->begin(); ::std::advance( it, nPos ); ImplHeadItem* pItem = *it; mpItemList->erase( it ); if ( nNewPos < nPos ) nPos = nNewPos; it = mpItemList->begin(); ::std::advance( it, nNewPos ); mpItemList->insert( it, pItem ); ImplUpdate( nPos, true); } } } void HeaderBar::Clear() { // delete all items for ( size_t i = 0, n = mpItemList->size(); i < n; ++i ) { delete (*mpItemList)[ i ]; } mpItemList->clear(); ImplUpdate( 0, true ); } void HeaderBar::SetOffset( long nNewOffset ) { // move area Rectangle aRect( 0, mnBorderOff1, mnDX-1, mnDY-mnBorderOff1-mnBorderOff2-1 ); long nDelta = mnOffset-nNewOffset; mnOffset = nNewOffset; Scroll( nDelta, 0, aRect ); } sal_uInt16 HeaderBar::GetItemCount() const { return (sal_uInt16)mpItemList->size(); } sal_uInt16 HeaderBar::GetItemPos( sal_uInt16 nItemId ) const { for ( size_t i = 0, n = mpItemList->size(); i < n; ++i ) { ImplHeadItem* pItem = (*mpItemList)[ i ]; if ( pItem->mnId == nItemId ) return (sal_uInt16)i; } return HEADERBAR_ITEM_NOTFOUND; } sal_uInt16 HeaderBar::GetItemId( sal_uInt16 nPos ) const { ImplHeadItem* pItem = (nPos < mpItemList->size() ) ? (*mpItemList)[ nPos ] : NULL; if ( pItem ) return pItem->mnId; else return 0; } sal_uInt16 HeaderBar::GetItemId( const Point& rPos ) const { for ( size_t i = 0, n = mpItemList->size(); i < n; ++i ) { if ( ImplGetItemRect( i ).IsInside( rPos ) ) { return GetItemId( i ); } } return 0; } Rectangle HeaderBar::GetItemRect( sal_uInt16 nItemId ) const { Rectangle aRect; sal_uInt16 nPos = GetItemPos( nItemId ); if ( nPos != HEADERBAR_ITEM_NOTFOUND ) aRect = ImplGetItemRect( nPos ); return aRect; } void HeaderBar::SetItemSize( sal_uInt16 nItemId, long nNewSize ) { sal_uInt16 nPos = GetItemPos( nItemId ); if ( nPos != HEADERBAR_ITEM_NOTFOUND ) { ImplHeadItem* pItem = (*mpItemList)[ nPos ]; if ( pItem->mnSize != nNewSize ) { pItem->mnSize = nNewSize; ImplUpdate( nPos, true ); } } } long HeaderBar::GetItemSize( sal_uInt16 nItemId ) const { sal_uInt16 nPos = GetItemPos( nItemId ); if ( nPos != HEADERBAR_ITEM_NOTFOUND ) return (*mpItemList)[ nPos ]->mnSize; else return 0; } void HeaderBar::SetItemBits( sal_uInt16 nItemId, HeaderBarItemBits nNewBits ) { sal_uInt16 nPos = GetItemPos( nItemId ); if ( nPos != HEADERBAR_ITEM_NOTFOUND ) { ImplHeadItem* pItem = (*mpItemList)[ nPos ]; if ( pItem->mnBits != nNewBits ) { pItem->mnBits = nNewBits; ImplUpdate( nPos ); } } } HeaderBarItemBits HeaderBar::GetItemBits( sal_uInt16 nItemId ) const { sal_uInt16 nPos = GetItemPos( nItemId ); if ( nPos != HEADERBAR_ITEM_NOTFOUND ) return (*mpItemList)[ nPos ]->mnBits; else return HeaderBarItemBits::NONE; } void HeaderBar::SetItemText( sal_uInt16 nItemId, const OUString& rText ) { sal_uInt16 nPos = GetItemPos( nItemId ); if ( nPos != HEADERBAR_ITEM_NOTFOUND ) { (*mpItemList)[ nPos ]->maText = rText; ImplUpdate( nPos ); } } OUString HeaderBar::GetItemText( sal_uInt16 nItemId ) const { sal_uInt16 nPos = GetItemPos( nItemId ); if ( nPos != HEADERBAR_ITEM_NOTFOUND ) return (*mpItemList)[ nPos ]->maText; return OUString(); } OUString HeaderBar::GetHelpText( sal_uInt16 nItemId ) const { sal_uInt16 nPos = GetItemPos( nItemId ); if ( nPos != HEADERBAR_ITEM_NOTFOUND ) { ImplHeadItem* pItem = (*mpItemList)[ nPos ]; if ( pItem->maHelpText.isEmpty() && !pItem->maHelpId.isEmpty() ) { Help* pHelp = Application::GetHelp(); if ( pHelp ) pItem->maHelpText = pHelp->GetHelpText( OStringToOUString( pItem->maHelpId, RTL_TEXTENCODING_UTF8 ), this ); } return pItem->maHelpText; } return OUString(); } OString HeaderBar::GetHelpId( sal_uInt16 nItemId ) const { sal_uInt16 nPos = GetItemPos( nItemId ); OString aRet; if ( nPos != HEADERBAR_ITEM_NOTFOUND ) return (*mpItemList)[ nPos ]->maHelpId; return aRet; } Size HeaderBar::CalcWindowSizePixel() const { long nMaxImageSize = 0; Size aSize( 0, GetTextHeight() ); for ( size_t i = 0, n = mpItemList->size(); i < n; ++i ) { ImplHeadItem* pItem = (*mpItemList)[ i ]; // take image size into account long nImageHeight = pItem->maImage.GetSizePixel().Height(); if ( !(pItem->mnBits & (HeaderBarItemBits::LEFTIMAGE | HeaderBarItemBits::RIGHTIMAGE)) && !pItem->maText.isEmpty() ) nImageHeight += aSize.Height(); if ( nImageHeight > nMaxImageSize ) nMaxImageSize = nImageHeight; // add width aSize.Width() += pItem->mnSize; } if ( nMaxImageSize > aSize.Height() ) aSize.Height() = nMaxImageSize; // add border if ( mbButtonStyle ) aSize.Height() += 4; else aSize.Height() += 2; aSize.Height() += mnBorderOff1+mnBorderOff2; return aSize; } ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > HeaderBar::CreateAccessible() { if ( !mxAccessible.is() ) { if ( maCreateAccessibleHdl.IsSet() ) maCreateAccessibleHdl.Call( this ); if ( !mxAccessible.is() ) mxAccessible = Window::CreateAccessible(); } return mxAccessible; } void HeaderBar::SetAccessible( ::com::sun::star::uno::Reference< ::com::sun::star::accessibility::XAccessible > _xAccessible ) { mxAccessible = _xAccessible; } ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > HeaderBar::GetComponentInterface( bool bCreate ) { ::com::sun::star::uno::Reference< ::com::sun::star::awt::XWindowPeer > xPeer (Window::GetComponentInterface(false)); if ( !xPeer.is() && bCreate ) { ::com::sun::star::awt::XWindowPeer* mxPeer = new VCLXHeaderBar(this); m_pVCLXHeaderBar = static_cast(mxPeer); SetComponentInterface(mxPeer); return mxPeer; } else return xPeer; } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */