Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/vcl/source/window/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 17 kB image not shown  

Quelle  bubblewindow.cxx   Sprache: C

 
/* -*- 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 <rtl/ustrbuf.hxx>
#include <utility>
#include <vcl/menubarupdateicon.hxx>
#include <vcl/lineinfo.hxx>
#include <vcl/settings.hxx>
#include <vcl/svapp.hxx>
#include <unotools/resmgr.hxx>
#include <bubblewindow.hxx>
#include <bitmaps.hlst>

#define TIP_HEIGHT             15
#define TIP_WIDTH               7
#define TIP_RIGHT_OFFSET       18
#define BUBBLE_BORDER          10
#define TEXT_MAX_WIDTH        300
#define TEXT_MAX_HEIGHT       200

BubbleWindow::BubbleWindow( vcl::Window* pParent, OUString aTitle,
                            OUString aText, Image aImage )
    : FloatingWindow( pParent, WB_SYSTEMWINDOW
                               | WB_OWNERDRAWDECORATION
                               | WB_NOBORDER
                    )
    , maBubbleTitle(std::move( aTitle ))
    , maBubbleText(std::move( aText ))
    , maBubbleImage(std::move( aImage ))
    , maMaxTextSize( TEXT_MAX_WIDTH, TEXT_MAX_HEIGHT )
    , mnTipOffset( 0 )
{
    SetBackground( Wallpaper( GetSettings().GetStyleSettings().GetHelpColor() ) );
}

void BubbleWindow::Resize()
{
    FloatingWindow::Resize();

    Size aSize = GetSizePixel();

    if ( ( aSize.Height() < 20 ) || ( aSize.Width() < 60 ) )
        return;

    tools::Rectangle aRect( 0, TIP_HEIGHT, aSize.Width(), aSize.Height() - TIP_HEIGHT );
    maRectPoly = tools::Polygon( aRect, 6, 6 );
    vcl::Region aRegion( maRectPoly );
    tools::Long nTipOffset = aSize.Width() - TIP_RIGHT_OFFSET + mnTipOffset;

    Point aPointArr[4];
    aPointArr[0] = Point( nTipOffset, TIP_HEIGHT );
    aPointArr[1] = Point( nTipOffset, 0 );
    aPointArr[2] = Point( nTipOffset + TIP_WIDTH , TIP_HEIGHT );
    aPointArr[3] = Point( nTipOffset, TIP_HEIGHT );
    maTriPoly = tools::Polygon( 4, aPointArr );
    vcl::Region aTriRegion( maTriPoly );

    aRegion.Union( aTriRegion);
    maBounds = std::move(aRegion);

    SetWindowRegionPixel( maBounds );
}

void BubbleWindow::SetTitleAndText( const OUString& rTitle,
                                    const OUString& rText,
                                    const Image& rImage )
{
    maBubbleTitle = rTitle;
    maBubbleText = rText;
    maBubbleImage = rImage;

    Resize();
}

void BubbleWindow::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle& /*rRect*/)
{
    LineInfo aThickLine( LineStyle::Solid, 2 );

    rRenderContext.DrawPolyLine( maRectPoly, aThickLine );
    rRenderContext.DrawPolyLine( maTriPoly );

    Color aOldLine = rRenderContext.GetLineColor();
    Size aSize = GetSizePixel();
    tools::Long nTipOffset = aSize.Width() - TIP_RIGHT_OFFSET + mnTipOffset;

    rRenderContext.SetLineColor( GetSettings().GetStyleSettings().GetHelpColor() );
    rRenderContext.DrawLine( Point( nTipOffset+2, TIP_HEIGHT ),
              Point( nTipOffset + TIP_WIDTH -1 , TIP_HEIGHT ),
              aThickLine );
    rRenderContext.SetLineColor( aOldLine );

    Size aImgSize = maBubbleImage.GetSizePixel();

    rRenderContext.DrawImage( Point( BUBBLE_BORDER, BUBBLE_BORDER + TIP_HEIGHT ), maBubbleImage );

    vcl::Font aOldFont = GetFont();
    vcl::Font aBoldFont = aOldFont;
    aBoldFont.SetWeight( WEIGHT_BOLD );

    SetFont( aBoldFont );
    tools::Rectangle aTitleRect = maTitleRect;
    aTitleRect.Move( aImgSize.Width(), 0 );
    rRenderContext.DrawText( aTitleRect, maBubbleTitle, DrawTextFlags::MultiLine | DrawTextFlags::WordBreak );

    SetFont( aOldFont );
    tools::Rectangle aTextRect = maTextRect;
    aTextRect.Move( aImgSize.Width(), 0 );
    rRenderContext.DrawText( aTextRect, maBubbleText, DrawTextFlags::MultiLine | DrawTextFlags::WordBreak );
}

void BubbleWindow::MouseButtonDown( const MouseEvent& )
{
    Show( false );
}

void BubbleWindow::Show( bool bVisible )
{
    if ( !bVisible )
    {
        FloatingWindow::Show( bVisible );
        return;
    }

    // don't show bubbles without a text
    if ( ( maBubbleTitle.isEmpty() ) && ( maBubbleText.isEmpty() ) )
        return;

    Size aWindowSize = GetSizePixel();

    Size aImgSize = maBubbleImage.GetSizePixel();

    RecalcTextRects();

    aWindowSize.setHeight( maTitleRect.GetHeight() * 7 / 4+ maTextRect.GetHeight() +
                           3 * BUBBLE_BORDER + TIP_HEIGHT );

    if ( maTitleRect.GetWidth() > maTextRect.GetWidth() )
        aWindowSize.setWidth( maTitleRect.GetWidth() );
    else
        aWindowSize.setWidth( maTextRect.GetWidth() );

    aWindowSize.setWidth( aWindowSize.Width() + 3 * BUBBLE_BORDER + aImgSize.Width() );

    if ( aWindowSize.Height() < aImgSize.Height() + TIP_HEIGHT + 2 * BUBBLE_BORDER )
        aWindowSize.setHeight( aImgSize.Height() + TIP_HEIGHT + 2 * BUBBLE_BORDER );

    Point aPos;
    aPos.setX( maTipPos.X() - aWindowSize.Width() + TIP_RIGHT_OFFSET );
    aPos.setY( maTipPos.Y() );
    AbsoluteScreenPixelPoint aScreenPos = GetParent()->OutputToAbsoluteScreenPixel( aPos );
    if ( aScreenPos.X() < 0 )
    {
        mnTipOffset = aScreenPos.X();
        aPos.AdjustX( -mnTipOffset );
    }
    SetPosSizePixel( aPos, aWindowSize );

    FloatingWindow::Show( bVisible, ShowFlags::NoActivate );
}

void BubbleWindow::RecalcTextRects()
{
    Size aTotalSize;
    bool bFinished = false;
    vcl::Font aOldFont = GetFont();
    vcl::Font aBoldFont = aOldFont;

    aBoldFont.SetWeight( WEIGHT_BOLD );

    while ( !bFinished )
    {
        SetFont( aBoldFont );

        maTitleRect = GetTextRect( tools::Rectangle( Point( 0, 0 ), maMaxTextSize ),
                                   maBubbleTitle,
                                   DrawTextFlags::MultiLine | DrawTextFlags::WordBreak );

        SetFont( aOldFont );
        maTextRect = GetTextRect( tools::Rectangle( Point( 0, 0 ), maMaxTextSize ),
                                  maBubbleText,
                                  DrawTextFlags::MultiLine | DrawTextFlags::WordBreak );

        if ( maTextRect.GetHeight() < 10 )
            maTextRect.setHeight( 10 );

        aTotalSize.setHeight( maTitleRect.GetHeight() +
                              aBoldFont.GetFontHeight() * 3 / 4 +
                              maTextRect.GetHeight() +
                              3 * BUBBLE_BORDER + TIP_HEIGHT );
        if ( aTotalSize.Height() > maMaxTextSize.Height() )
        {
            maMaxTextSize.setWidth( maMaxTextSize.Width() * 3 / 2 );
            maMaxTextSize.setHeight( maMaxTextSize.Height() * 3 / 2 );
        }
        else
            bFinished = true;
    }
    maTitleRect.Move( 2*BUBBLE_BORDER, BUBBLE_BORDER + TIP_HEIGHT );
    maTextRect.Move( 2*BUBBLE_BORDER, BUBBLE_BORDER + TIP_HEIGHT + maTitleRect.GetHeight() + aBoldFont.GetFontHeight() * 3 / 4 );
}

MenuBarUpdateIconManager::MenuBarUpdateIconManager()
    : maTimeoutTimer("MenuBarUpdateIconManager")
    , maWaitIdle("vcl MenuBarUpdateIconManager maWaitIdle")
    , mbShowMenuIcon(false)
    , mbShowBubble(false)
    , mbBubbleChanged( false )
{
    maTimeoutTimer.SetTimeout( 10000 );
    maTimeoutTimer.SetInvokeHandler(LINK(this, MenuBarUpdateIconManager, TimeOutHdl));

    maWaitIdle.SetPriority( TaskPriority::LOWEST );
    maWaitIdle.SetInvokeHandler(LINK(this, MenuBarUpdateIconManager, WaitTimeOutHdl));

    maApplicationEventHdl = LINK(this, MenuBarUpdateIconManager, ApplicationEventHdl);
    Application::AddEventListener( maApplicationEventHdl );

    maWindowEventHdl = LINK(this, MenuBarUpdateIconManager, WindowEventHdl);
}

sal_uInt16 MenuBarUpdateIconManager::GetIconID(MenuBar* pMenuBar) const
{
    auto aI = std::find(maIconMBars.begin(), maIconMBars.end(), pMenuBar);
    if (aI == maIconMBars.end())
        return 0;
    return maIconIDs[std::distance(maIconMBars.begin(), aI)];
}

VclPtr<BubbleWindow> MenuBarUpdateIconManager::GetBubbleWindow()
{
    if (!mpActiveSysWin)
        return nullptr;

    tools::Rectangle aIconRect = mpActiveMBar->GetMenuBarButtonRectPixel(GetIconID(mpActiveMBar));
    if( aIconRect.IsEmpty() )
        return nullptr;

    auto pBubbleWin = mpBubbleWin;

    if ( !pBubbleWin ) {
        pBubbleWin = VclPtr<BubbleWindow>::Create( mpActiveSysWin, maBubbleTitle,
                                       maBubbleText, maBubbleImage );
        mbBubbleChanged = false;
    }
    else if ( mbBubbleChanged ) {
        pBubbleWin->SetTitleAndText( maBubbleTitle, maBubbleText,
                                     maBubbleImage );
        mbBubbleChanged = false;
    }

    Point aWinPos = aIconRect.BottomCenter();

    pBubbleWin->SetTipPosPixel( aWinPos );

    return pBubbleWin;
}

IMPL_LINK_NOARG(MenuBarUpdateIconManager, TimeOutHdl, Timer *, void)
{
    RemoveBubbleWindow();
}

IMPL_LINK(MenuBarUpdateIconManager, WindowEventHdl, VclWindowEvent&, rEvent, void)
{
    VclEventId nEventID = rEvent.GetId();

    if ( VclEventId::ObjectDying == nEventID )
    {
        if (mpActiveSysWin == rEvent.GetWindow())
        {
            RemoveBubbleWindow();
            mpActiveSysWin = nullptr;
            mpActiveMBar = nullptr;
        }
    }
    else if ( VclEventId::WindowMenubarAdded == nEventID )
    {
        vcl::Window *pWindow = rEvent.GetWindow();
        if ( pWindow )
        {
            SystemWindow *pSysWin = pWindow->GetSystemWindow();
            if (pSysWin)
                AddMenuBarIcon(*pSysWin, false);
        }
    }
    else if ( VclEventId::WindowMenubarRemoved == nEventID )
    {
        MenuBar *pMBar = static_cast<MenuBar*>(rEvent.GetData());
        if (pMBar)
        {
            if (pMBar == mpActiveMBar)
            {
                RemoveBubbleWindow();
                mpActiveMBar = nullptr;
            }
            RemoveMenuBarIcon(pMBar);
        }
    }
    else if ( ( nEventID == VclEventId::WindowMove ) ||
              ( nEventID == VclEventId::WindowResize ) )
    {
        if ( mpActiveSysWin == rEvent.GetWindow() &&
             mpBubbleWin && mpActiveMBar )
        {
            tools::Rectangle aIconRect = mpActiveMBar->GetMenuBarButtonRectPixel(GetIconID(mpActiveMBar));
            Point aWinPos = aIconRect.BottomCenter();
            mpBubbleWin->SetTipPosPixel( aWinPos );
            if ( mpBubbleWin->IsVisible() )
                mpBubbleWin->Show();    // This will recalc the screen position of the bubble
        }
    }
}

IMPL_LINK(MenuBarUpdateIconManager, ApplicationEventHdl, VclSimpleEvent&, rEventvoid)
{
    switch (rEvent.GetId())
    {
        case VclEventId::WindowShow:
        case VclEventId::WindowActivate:
        case VclEventId::WindowGetFocus: {

            vcl::Window *pWindow = static_cast< VclWindowEvent * >(&rEvent)->GetWindow();
            if ( pWindow && pWindow->IsTopWindow() )
            {
                SystemWindow *pSysWin = pWindow->GetSystemWindow();
                MenuBar *pMBar = pSysWin ? pSysWin->GetMenuBar() : nullptr;
                if (pMBar)
                    AddMenuBarIcon(*pSysWin, true);
            }
            break;
        }
        defaultbreak;
    }
}

IMPL_LINK_NOARG(MenuBarUpdateIconManager, UserEventHdl, void*, void)
{
    vcl::Window *pTopWin = Application::GetFirstTopLevelWindow();
    vcl::Window *pActiveWin = Application::GetActiveTopWindow();
    SystemWindow *pActiveSysWin = nullptr;

    vcl::Window *pBubbleWin = nullptr;
    if ( mpBubbleWin )
        pBubbleWin = mpBubbleWin;

    if ( pActiveWin && ( pActiveWin != pBubbleWin ) && pActiveWin->IsTopWindow() )
        pActiveSysWin = pActiveWin->GetSystemWindow();

    if ( pActiveWin == pBubbleWin )
        pActiveSysWin = nullptr;

    while ( !pActiveSysWin && pTopWin )
    {
        if ( ( pTopWin != pBubbleWin ) && pTopWin->IsTopWindow() )
            pActiveSysWin = pTopWin->GetSystemWindow();
        if ( !pActiveSysWin )
            pTopWin = Application::GetNextTopLevelWindow( pTopWin );
    }

    if ( pActiveSysWin )
        AddMenuBarIcon(*pActiveSysWin, true);
}

IMPL_LINK_NOARG(MenuBarUpdateIconManager, ClickHdl, MenuBarButtonCallbackArg&, bool)
{
    maWaitIdle.Stop();
    if ( mpBubbleWin )
        mpBubbleWin->Show( false );

    maClickHdl.Call(nullptr);

    return false;
}

IMPL_LINK(MenuBarUpdateIconManager, HighlightHdl, MenuBarButtonCallbackArg&, rData, bool)
{
    if ( rData.bHighlight )
        maWaitIdle.Start();
    else
        RemoveBubbleWindow();

    return false;
}

IMPL_LINK_NOARG(MenuBarUpdateIconManager, WaitTimeOutHdl, Timer *, void)
{
    mpBubbleWin = GetBubbleWindow();

    if ( mpBubbleWin )
    {
        mpBubbleWin->Show();
    }
}

MenuBarUpdateIconManager::~MenuBarUpdateIconManager()
{
    Application::RemoveEventListener( maApplicationEventHdl );

    RemoveBubbleWindow();
    RemoveMenuBarIcons();
}

void MenuBarUpdateIconManager::RemoveMenuBarIcons()
{
    while (!maIconMBars.empty())
        RemoveMenuBarIcon(maIconMBars[0]);
}

void MenuBarUpdateIconManager::SetShowMenuIcon(bool bShowMenuIcon)
{
    if ( bShowMenuIcon != mbShowMenuIcon )
    {
        mbShowMenuIcon = bShowMenuIcon;
        if ( bShowMenuIcon )
            Application::PostUserEvent(LINK(this, MenuBarUpdateIconManager, UserEventHdl));
        else
        {
            RemoveBubbleWindow();
            RemoveMenuBarIcons();
        }
    }
}

void MenuBarUpdateIconManager::SetShowBubble(bool bShowBubble)
{
    mbShowBubble = bShowBubble;
    if ( mbShowBubble )
        Application::PostUserEvent(LINK(this, MenuBarUpdateIconManager, UserEventHdl));
    else if ( mpBubbleWin )
        mpBubbleWin->Show( false );
}

void MenuBarUpdateIconManager::SetBubbleChanged()
{
    mbBubbleChanged = true;
    if (mbBubbleChanged && mpBubbleWin)
        mpBubbleWin->Show( false );
}

void MenuBarUpdateIconManager::SetBubbleImage(const Image& rImage)
{
    maBubbleImage = rImage;
    SetBubbleChanged();
}

void MenuBarUpdateIconManager::SetBubbleTitle(const OUString& rTitle)
{
    if (rTitle != maBubbleTitle)
    {
        maBubbleTitle = rTitle;
        SetBubbleChanged();
    }
}

void MenuBarUpdateIconManager::SetBubbleText(const OUString& rText)
{
    if (rText != maBubbleText)
    {
        maBubbleText = rText;
        SetBubbleChanged();
    }
}

namespace {
Image GetMenuBarIcon( MenuBar const * pMBar )
{
    OUString sResID;
    vcl::Window *pMBarWin = pMBar->GetWindow();
    sal_uInt32 nMBarHeight = 20;

    if ( pMBarWin )
        nMBarHeight = pMBarWin->GetOutputSizePixel().getHeight();

    if (nMBarHeight >= 35)
        sResID = RID_UPDATE_AVAILABLE_26;
    else
        sResID = RID_UPDATE_AVAILABLE_16;

    return Image(StockImage::Yes, sResID);
}
}

void MenuBarUpdateIconManager::AddMenuBarIcon(SystemWindow& rSysWin, bool bAddEventHdl)
{
    if (!mbShowMenuIcon)
        return;

    MenuBar *pActiveMBar = rSysWin.GetMenuBar();
    if (&rSysWin != mpActiveSysWin || pActiveMBar != mpActiveMBar)
        RemoveBubbleWindow();

    auto aI = std::find(maIconMBars.begin(), maIconMBars.end(), pActiveMBar);
    if (aI == maIconMBars.end())
    {
        if (pActiveMBar)
        {
            OUStringBuffer aBuf;
            if( !maBubbleTitle.isEmpty() )
                aBuf.append( maBubbleTitle );
            if( !maBubbleText.isEmpty() )
            {
                if( !maBubbleTitle.isEmpty() )
                    aBuf.append( "\n\n" );
                aBuf.append( maBubbleText );
            }

            Image aImage = GetMenuBarIcon( pActiveMBar );
            sal_uInt16 nIconID = pActiveMBar->AddMenuBarButton( aImage,
                                    LINK( this, MenuBarUpdateIconManager, ClickHdl ),
                                    aBuf.makeStringAndClear() );
            maIconMBars.push_back(pActiveMBar);
            maIconIDs.push_back(nIconID);
        }

        if (bAddEventHdl)
            rSysWin.AddEventListener( maWindowEventHdl );
    }

    if (mpActiveMBar != pActiveMBar)
    {
        if (mpActiveMBar)
        {
            mpActiveMBar->SetMenuBarButtonHighlightHdl(GetIconID(mpActiveMBar),
                Link<MenuBarButtonCallbackArg&,bool>());
        }
        mpActiveMBar = pActiveMBar;
        if (mpActiveMBar)
        {
            mpActiveMBar->SetMenuBarButtonHighlightHdl(GetIconID(mpActiveMBar),
                LINK(this, MenuBarUpdateIconManager, HighlightHdl));
        }
    }

    mpActiveSysWin = &rSysWin;

    if (mbShowBubble && pActiveMBar)
    {
        mpBubbleWin = GetBubbleWindow();
        if ( mpBubbleWin )
        {
            mpBubbleWin->Show();
            maTimeoutTimer.Start();
        }
        mbShowBubble = false;
    }
}

void MenuBarUpdateIconManager::RemoveMenuBarIcon(MenuBar* pMenuBar)
{
    auto aI = std::find(maIconMBars.begin(), maIconMBars.end(), pMenuBar);
    if (aI == maIconMBars.end())
        return;

    auto aIconI = maIconIDs.begin() + std::distance(maIconMBars.begin(), aI);

    try
    {
        pMenuBar->RemoveMenuBarButton(*aIconI);
    }
    catch (...)
    {
    }

    maIconMBars.erase(aI);
    maIconIDs.erase(aIconI);
}

void MenuBarUpdateIconManager::RemoveBubbleWindow()
{
    maWaitIdle.Stop();
    maTimeoutTimer.Stop();
    mpBubbleWin.disposeAndClear();
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Messung V0.5
C=99 H=83 G=91

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.