/* -*- 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 <vcl/event.hxx>
#include <vcl/metaact.hxx>
#include <vcl/virdev.hxx>
#include <svtools/valueset.hxx>
#include <svl/eitem.hxx>
#include <svl/itemset.hxx>
#include <sfx2/dispatch.hxx>
#include <svtools/colrdlg.hxx>
 
#include <svx/colorbox.hxx>
#include <svx/dialmgr.hxx>
#include <svx/bmpmask.hxx>
#include <svx/strings.hrc>
#include <svx/svxids.hrc>
#include <memory>
#include <helpids.h>
 
#define OWN_CALLMODE    SfxCallMode::ASYNCHRON | SfxCallMode::RECORD
 
 
#define TEST_COLS()                                                 \
{                                                                   \
    nR = aCol.GetRed(); nG = aCol.GetGreen(); nB = aCol.GetBlue();  \
    for( i = 0; i < nCount; i++ )                                   \
    {                                                               \
        if ( ( pMinR[i] <= nR ) && ( pMaxR[i] >= nR ) &&            \
             ( pMinG[i] <= nG ) && ( pMaxG[i] >= nG ) &&            \
             ( pMinB[i] <= nB ) && ( pMaxB[i] >= nB ) )             \
        {                                                           \
            aCol = pDstCols[i]; bReplace = true; break;             \
        }                                                           \
    }                                                               \
}
 
SFX_IMPL_DOCKINGWINDOW_WITHID( SvxBmpMaskChildWindow, SID_BMPMASK )
 
class BmpColorWindow : public weld::CustomWidgetController
{
    Color       aColor;
 
 
public:
    explicit BmpColorWindow()
        : aColor( COL_WHITE )
    {
    }
 
    void SetColor( const Color& rColor )
    {
        aColor = rColor;
        Invalidate();
    }
 
    virtual void Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& rRect ) override;
 
    virtual void SetDrawingArea(weld::DrawingArea* pArea) override
    {
        Size aSize(pArea->get_ref_device().LogicToPixel(Size(43, 14), MapMode(MapUnit::MapAppFont)));
        CustomWidgetController::SetDrawingArea(pArea);
        pArea->set_size_request(aSize.Width(), aSize.Height());
        SetOutputSizePixel(aSize);
    }
};
 
class MaskSet : public ValueSet
{
    VclPtr<SvxBmpMask> pSvxBmpMask;
 
public:
    MaskSet(SvxBmpMask* pMask);
    virtual void Select() override;
    virtual bool KeyInput( const KeyEvent& rKEvt ) override;
    virtual void GetFocus() override;
    virtual void SetDrawingArea(weld::DrawingArea* pArea) override
    {
        Size aSize(pArea->get_ref_device().LogicToPixel(Size(24, 12), MapMode(MapUnit::MapAppFont)));
        ValueSet::SetDrawingArea(pArea);
        pArea->set_size_request(aSize.Width(), aSize.Height());
        SetOutputSizePixel(aSize);
        SetHelpId(HID_BMPMASK_CTL_QCOL_1);
    }
    void onEditColor();
};
 
MaskSet::MaskSet(SvxBmpMask* pMask)
    : ValueSet(nullptr)
    , pSvxBmpMask(pMask)
{
}
 
void MaskSet::Select()
{
    ValueSet::Select();
 
    pSvxBmpMask->onSelect( this );
}
 
void MaskSet::GetFocus()
{
    ValueSet::GetFocus();
    SelectItem( 1 );
    pSvxBmpMask->onSelect( this );
}
 
bool MaskSet::KeyInput( const KeyEvent& rKEvt )
{
    bool bRet = false;
 
    vcl::KeyCode aCode = rKEvt.GetKeyCode();
 
    // if the key has a modifier we don't care
    if( aCode.GetModifier() )
    {
        bRet = ValueSet::KeyInput( rKEvt );
    }
    else
    {
        // check for keys that interests us
        switch ( aCode.GetCode() )
        {
            case KEY_SPACE:
                onEditColor();
                bRet = true;
                break;
            default:
                bRet = ValueSet::KeyInput( rKEvt );
        }
    }
    return bRet;
}
 
void MaskSet::onEditColor()
{
    SvColorDialog aColorDlg;
 
    aColorDlg.SetColor(GetItemColor(1));
 
    if (aColorDlg.Execute(pSvxBmpMask->GetFrameWeld()))
        SetItemColor(1, aColorDlg.GetColor());
}
 
class MaskData
{
    VclPtr<SvxBmpMask> pMask;
    bool            bIsReady;
    bool            bExecState;
    SfxBindings&    rBindings;
 
public:
                MaskData( SvxBmpMask* pBmpMask, SfxBindings& rBind );
 
    bool        IsCbxReady() const { return bIsReady; }
    void        SetExecState( bool bState ) { bExecState = bState; }
    bool        IsExecReady() const { return bExecState; }
 
                DECL_LINK( PipetteHdl, const OUString&, void );
                DECL_LINK( CbxHdl, weld::Toggleable&, void);
                DECL_LINK( CbxTransHdl, weld::Toggleable&, void );
                DECL_LINK( FocusLbHdl, weld::Widget&, void );
                DECL_LINK(ExecHdl, weld::Button&, void);
};
 
 
MaskData::MaskData( SvxBmpMask* pBmpMask, SfxBindings& rBind ) :
 
    pMask       ( pBmpMask ),
    bIsReady    ( false ),
    bExecState  ( false ),
    rBindings   ( rBind )
 
{
}
 
IMPL_LINK( MaskData, PipetteHdl, const OUString&, rId, void )
{
    SfxBoolItem aBItem( SID_BMPMASK_PIPETTE,
                        pMask->m_xTbxPipette->get_item_active(rId) );
 
    rBindings.GetDispatcher()->ExecuteList(SID_BMPMASK_PIPETTE, OWN_CALLMODE,
            { &aBItem });
}
 
IMPL_LINK( MaskData, CbxHdl, weld::Toggleable&, rCbx, void )
{
    bIsReady =  pMask->m_xCbx1->get_active() || pMask->m_xCbx2->get_active() ||
                pMask->m_xCbx3->get_active() || pMask->m_xCbx4->get_active();
 
    if ( bIsReady && IsExecReady() )
        pMask->m_xBtnExec->set_sensitive(true);
    else
        pMask->m_xBtnExec->set_sensitive(false);
 
    // When a checkbox is checked, the pipette is enabled
    if ( !rCbx.get_active() )
        return;
 
    MaskSet* pSet = nullptr;
 
    if (&rCbx == pMask->m_xCbx1.get())
        pSet = pMask->m_xQSet1.get();
    else if (&rCbx == pMask->m_xCbx2.get())
        pSet = pMask->m_xQSet2.get();
    else if (&rCbx == pMask->m_xCbx3.get())
        pSet = pMask->m_xQSet3.get();
    else // if ( &rCbx == pMask->m_xCbx4 )
        pSet = pMask->m_xQSet4.get();
 
    pSet->SelectItem( 1 );
    pSet->Select();
 
    pMask->m_xTbxPipette->set_item_active(u"pipette"_ustr, true);
    PipetteHdl(u"pipette"_ustr);
}
 
IMPL_LINK( MaskData, CbxTransHdl, weld::Toggleable&, rCbx, void )
{
    bIsReady = rCbx.get_active();
    if ( bIsReady )
    {
        pMask->m_xQSet1->Disable();
        pMask->m_xQSet2->Disable();
        pMask->m_xQSet3->Disable();
        pMask->m_xQSet4->Disable();
        pMask->m_xCtlPipette->Disable();
        pMask->m_xCbx1->set_sensitive(false);
        pMask->m_xSp1->set_sensitive(false);
        pMask->m_xCbx2->set_sensitive(false);
        pMask->m_xSp2->set_sensitive(false);
        pMask->m_xCbx3->set_sensitive(false);
        pMask->m_xSp3->set_sensitive(false);
        pMask->m_xCbx4->set_sensitive(false);
        pMask->m_xSp4->set_sensitive(false);
        pMask->m_xTbxPipette->set_sensitive(false);
 
        pMask->m_xLbColor1->set_sensitive(false);
        pMask->m_xLbColor2->set_sensitive(false);
        pMask->m_xLbColor3->set_sensitive(false);
        pMask->m_xLbColor4->set_sensitive(false);
        pMask->m_xLbColorTrans->set_sensitive(true);
    }
    else
    {
        pMask->m_xQSet1->Enable();
        pMask->m_xQSet2->Enable();
        pMask->m_xQSet3->Enable();
        pMask->m_xQSet4->Enable();
        pMask->m_xCtlPipette->Enable();
        pMask->m_xCbx1->set_sensitive(true);
        pMask->m_xSp1->set_sensitive(true);
        pMask->m_xCbx2->set_sensitive(true);
        pMask->m_xSp2->set_sensitive(true);
        pMask->m_xCbx3->set_sensitive(true);
        pMask->m_xSp3->set_sensitive(true);
        pMask->m_xCbx4->set_sensitive(true);
        pMask->m_xSp4->set_sensitive(true);
        pMask->m_xTbxPipette->set_sensitive(true);
 
        pMask->m_xLbColor1->set_sensitive(true);
        pMask->m_xLbColor2->set_sensitive(true);
        pMask->m_xLbColor3->set_sensitive(true);
        pMask->m_xLbColor4->set_sensitive(true);
        pMask->m_xLbColorTrans->set_sensitive(false);
 
        bIsReady = pMask->m_xCbx1->get_active() || pMask->m_xCbx2->get_active() ||
                   pMask->m_xCbx3->get_active() || pMask->m_xCbx4->get_active();
    }
 
    if ( bIsReady && IsExecReady() )
        pMask->m_xBtnExec->set_sensitive(true);
    else
        pMask->m_xBtnExec->set_sensitive(false);
}
 
IMPL_LINK( MaskData, FocusLbHdl, weld::Widget&, rLb, void )
{
    pMask->m_xQSet1->SelectItem( &rLb == &pMask->m_xLbColor1->get_widget() ? 1 : 0 /* , false */ );
    pMask->m_xQSet2->SelectItem( &rLb == &pMask->m_xLbColor2->get_widget() ? 1 : 0 /* , false */ );
    pMask->m_xQSet3->SelectItem( &rLb == &pMask->m_xLbColor3->get_widget() ? 1 : 0 /* , false */ );
    pMask->m_xQSet4->SelectItem( &rLb == &pMask->m_xLbColor4->get_widget() ? 1 : 0 /* , false */ );
}
 
IMPL_LINK_NOARG(MaskData, ExecHdl, weld::Button&, void)
{
    SfxBoolItem aBItem( SID_BMPMASK_EXEC, true );
    rBindings.GetDispatcher()->ExecuteList(SID_BMPMASK_EXEC, OWN_CALLMODE,
            { &aBItem });
}
 
void BmpColorWindow::Paint( vcl::RenderContext& rRenderContext, const tools::Rectangle& /*Rect*/)
{
    rRenderContext.Push(vcl::PushFlags::LINECOLOR | vcl::PushFlags::FILLCOLOR);
    rRenderContext.SetLineColor(aColor);
    rRenderContext.SetFillColor(aColor);
    rRenderContext.DrawRect(tools::Rectangle(Point(), GetOutputSizePixel()));
    rRenderContext.Pop();
}
 
SvxBmpMaskSelectItem::SvxBmpMaskSelectItem( SvxBmpMask& rMask,
                                            SfxBindings& rBindings ) :
            SfxControllerItem   ( SID_BMPMASK_EXEC, rBindings ),
            rBmpMask            ( rMask)
{
}
 
void SvxBmpMaskSelectItem::StateChangedAtToolBoxControl( sal_uInt16 nSID, SfxItemState /*eState*/,
                                         const SfxPoolItem* pItem )
{
    if ( ( nSID == SID_BMPMASK_EXEC ) && pItem )
    {
        const SfxBoolItem* pStateItem = dynamic_cast<const SfxBoolItem*>( pItem  );
        assert(pStateItem); // SfxBoolItem expected
        if (pStateItem)
            rBmpMask.SetExecState( pStateItem->GetValue() );
    }
}
 
SvxBmpMaskChildWindow::SvxBmpMaskChildWindow(vcl::Window* pParent_, sal_uInt16 nId,
                                             SfxBindings* pBindings,
                                             SfxChildWinInfo* pInfo)
    : SfxChildWindow(pParent_, nId)
{
    VclPtr<SvxBmpMask> pDlg = VclPtr<SvxBmpMask>::Create(pBindings, this, pParent_);
 
    SetWindow( pDlg );
 
    pDlg->Initialize( pInfo );
}
 
SvxBmpMask::SvxBmpMask(SfxBindings *pBindinx, SfxChildWindow *pCW, vcl::Window* pParent)
    : SfxDockingWindow(pBindinx, pCW, pParent, u"DockingColorReplace"_ustr,
                       u"svx/ui/dockingcolorreplace.ui"_ustr)
    , m_xTbxPipette(m_xBuilder->weld_toolbar(u"toolbar"_ustr))
    , m_xCtlPipette(new BmpColorWindow)
    , m_xCtlPipetteWin(new weld::CustomWeld(*m_xBuilder, u"toolcolor"_ustr, *m_xCtlPipette))
    , m_xBtnExec(m_xBuilder->weld_button(u"replace"_ustr))
    , m_xCbx1(m_xBuilder->weld_check_button(u"cbx1"_ustr))
    , m_xQSet1(new MaskSet(this))
    , m_xQSetWin1(new weld::CustomWeld(*m_xBuilder, u"qset1"_ustr, *m_xQSet1))
    , m_xSp1(m_xBuilder->weld_metric_spin_button(u"tol1"_ustr, FieldUnit::PERCENT))
    , m_xLbColor1(new ColorListBox(m_xBuilder->weld_menu_button(u"color1"_ustr), [this]{ return GetFrameWeld(); }))
    , m_xCbx2(m_xBuilder->weld_check_button(u"cbx2"_ustr))
    , m_xQSet2(new MaskSet(this))
    , m_xQSetWin2(new weld::CustomWeld(*m_xBuilder, u"qset2"_ustr, *m_xQSet2))
     , m_xSp2(m_xBuilder->weld_metric_spin_button(u"tol2"_ustr, FieldUnit::PERCENT))
    , m_xLbColor2(new ColorListBox(m_xBuilder->weld_menu_button(u"color2"_ustr), [this]{ return GetFrameWeld(); }))
    , m_xCbx3(m_xBuilder->weld_check_button(u"cbx3"_ustr))
    , m_xQSet3(new MaskSet(this))
    , m_xQSetWin3(new weld::CustomWeld(*m_xBuilder, u"qset3"_ustr, *m_xQSet3))
    , m_xSp3(m_xBuilder->weld_metric_spin_button(u"tol3"_ustr, FieldUnit::PERCENT))
    , m_xLbColor3(new ColorListBox(m_xBuilder->weld_menu_button(u"color3"_ustr), [this]{ return GetFrameWeld(); }))
    , m_xCbx4(m_xBuilder->weld_check_button(u"cbx4"_ustr))
    , m_xQSet4(new MaskSet(this))
    , m_xQSetWin4(new weld::CustomWeld(*m_xBuilder, u"qset4"_ustr, *m_xQSet4))
    , m_xSp4(m_xBuilder->weld_metric_spin_button(u"tol4"_ustr, FieldUnit::PERCENT))
    , m_xLbColor4(new ColorListBox(m_xBuilder->weld_menu_button(u"color4"_ustr), [this]{ return GetFrameWeld(); }))
    , m_xCbxTrans(m_xBuilder->weld_check_button(u"cbx5"_ustr))
    , m_xLbColorTrans(new ColorListBox(m_xBuilder->weld_menu_button(u"color5"_ustr), [this]{ return GetFrameWeld(); }))
    , m_xData(new MaskData(this, *pBindinx))
    , aPipetteColor(COL_WHITE)
    , aSelItem(*this, *pBindinx)
{
    SetText(SvxResId(RID_SVXDLG_BMPMASK_STR_TITLE));
 
    m_xLbColor1->SetSlotId(SID_BMPMASK_COLOR);
    m_xLbColor2->SetSlotId(SID_BMPMASK_COLOR);
    m_xLbColor3->SetSlotId(SID_BMPMASK_COLOR);
    m_xLbColor4->SetSlotId(SID_BMPMASK_COLOR);
 
    m_xLbColorTrans->SelectEntry(COL_BLACK);
    m_xLbColor1->SelectEntry(COL_TRANSPARENT);
    m_xLbColor2->SelectEntry(COL_TRANSPARENT);
    m_xLbColor3->SelectEntry(COL_TRANSPARENT);
    m_xLbColor4->SelectEntry(COL_TRANSPARENT);
 
    m_xTbxPipette->connect_clicked( LINK( m_xData.get(), MaskData, PipetteHdl ) );
    m_xBtnExec->connect_clicked( LINK( m_xData.get(), MaskData, ExecHdl ) );
 
    m_xCbx1->connect_toggled( LINK( m_xData.get(), MaskData, CbxHdl ) );
    m_xCbx2->connect_toggled( LINK( m_xData.get(), MaskData, CbxHdl ) );
    m_xCbx3->connect_toggled( LINK( m_xData.get(), MaskData, CbxHdl ) );
    m_xCbx4->connect_toggled( LINK( m_xData.get(), MaskData, CbxHdl ) );
    m_xCbxTrans->connect_toggled( LINK( m_xData.get(), MaskData, CbxTransHdl ) );
 
    SetAccessibleNames ();
 
    m_xLbColor1->connect_focus_in( LINK( m_xData.get(), MaskData, FocusLbHdl ) );
    m_xLbColor2->connect_focus_in( LINK( m_xData.get(), MaskData, FocusLbHdl ) );
    m_xLbColor3->connect_focus_in( LINK( m_xData.get(), MaskData, FocusLbHdl ) );
    m_xLbColor4->connect_focus_in( LINK( m_xData.get(), MaskData, FocusLbHdl ) );
    m_xLbColorTrans->set_sensitive(false);
 
    OUString sColorPalette (SvxResId( RID_SVXDLG_BMPMASK_STR_PALETTE));
    OUString sColorPaletteN;
 
    m_xQSet1->SetStyle( m_xQSet1->GetStyle() | WB_DOUBLEBORDER | WB_ITEMBORDER );
    m_xQSet1->SetColCount();
    m_xQSet1->SetLineCount( 1 );
    sColorPaletteN = sColorPalette + " 1";
    m_xQSet1->InsertItem( 1, aPipetteColor, sColorPaletteN);
    m_xQSet1->SelectItem( 1 );
 
    m_xQSet2->SetStyle( m_xQSet2->GetStyle() | WB_DOUBLEBORDER | WB_ITEMBORDER );
    m_xQSet2->SetColCount();
    m_xQSet2->SetLineCount( 1 );
    sColorPaletteN = sColorPalette + " 2";
    m_xQSet2->InsertItem( 1, aPipetteColor, sColorPaletteN);
    m_xQSet2->SelectItem( 0 );
 
    m_xQSet3->SetStyle( m_xQSet3->GetStyle() | WB_DOUBLEBORDER | WB_ITEMBORDER );
    m_xQSet3->SetColCount();
    m_xQSet3->SetLineCount( 1 );
    sColorPaletteN = sColorPalette + " 3";
    m_xQSet3->InsertItem( 1, aPipetteColor, sColorPaletteN);
    m_xQSet3->SelectItem( 0 );
 
    m_xQSet4->SetStyle( m_xQSet4->GetStyle() | WB_DOUBLEBORDER | WB_ITEMBORDER );
    m_xQSet4->SetColCount();
    m_xQSet4->SetLineCount( 1 );
    sColorPaletteN = sColorPalette + " 4";
    m_xQSet4->InsertItem( 1, aPipetteColor, sColorPaletteN);
    m_xQSet4->SelectItem( 0 );
 
    m_xQSet1->Show();
    m_xQSet2->Show();
    m_xQSet3->Show();
    m_xQSet4->Show();
}
 
SvxBmpMask::~SvxBmpMask()
{
    disposeOnce();
}
 
void SvxBmpMask::dispose()
{
    m_xQSetWin1.reset();
    m_xQSet1.reset();
    m_xQSetWin2.reset();
    m_xQSet2.reset();
    m_xQSetWin3.reset();
    m_xQSet3.reset();
    m_xQSetWin4.reset();
    m_xQSet4.reset();
    m_xCtlPipetteWin.reset();
    m_xCtlPipette.reset();
    m_xData.reset();
    m_xTbxPipette.reset();
    m_xBtnExec.reset();
    m_xCbx1.reset();
    m_xSp1.reset();
    m_xLbColor1.reset();
    m_xCbx2.reset();
    m_xSp2.reset();
    m_xLbColor2.reset();
    m_xCbx3.reset();
    m_xSp3.reset();
    m_xLbColor3.reset();
    m_xCbx4.reset();
    m_xSp4.reset();
    m_xLbColor4.reset();
    m_xCbxTrans.reset();
    m_xLbColorTrans.reset();
    aSelItem.dispose();
    SfxDockingWindow::dispose();
}
 
/** is called by a MaskSet when it is selected */
void SvxBmpMask::onSelect( const MaskSet* pSet )
{
    // now deselect all other value sets
    if( pSet != m_xQSet1.get() )
        m_xQSet1->SelectItem( 0 );
 
    if( pSet != m_xQSet2.get() )
        m_xQSet2->SelectItem( 0 );
 
    if( pSet != m_xQSet3.get() )
        m_xQSet3->SelectItem( 0 );
 
    if( pSet != m_xQSet4.get() )
        m_xQSet4->SelectItem( 0 );
}
 
bool SvxBmpMask::Close()
{
    SfxBoolItem aItem2( SID_BMPMASK_PIPETTE, false );
    GetBindings().GetDispatcher()->ExecuteList(SID_BMPMASK_PIPETTE,
            OWN_CALLMODE, { &aItem2 });
 
    return SfxDockingWindow::Close();
}
 
void SvxBmpMask::SetColor( const Color& rColor )
{
    aPipetteColor = rColor;
    m_xCtlPipette->SetColor( aPipetteColor );
}
 
void SvxBmpMask::PipetteClicked()
{
    if( m_xQSet1->GetSelectedItemId() == 1 )
    {
        m_xCbx1->set_active(true);
        m_xData->CbxHdl(*m_xCbx1);
        m_xQSet1->SetItemColor( 1, aPipetteColor );
        m_xQSet1->SetFormat();
    }
    else if( m_xQSet2->GetSelectedItemId() == 1 )
    {
        m_xCbx2->set_active(true);
        m_xData->CbxHdl(*m_xCbx2);
        m_xQSet2->SetItemColor( 1, aPipetteColor );
        m_xQSet2->SetFormat();
    }
    else if( m_xQSet3->GetSelectedItemId() == 1 )
    {
        m_xCbx3->set_active(true);
        m_xData->CbxHdl(*m_xCbx3);
        m_xQSet3->SetItemColor( 1, aPipetteColor );
        m_xQSet3->SetFormat();
    }
    else if( m_xQSet4->GetSelectedItemId() == 1 )
    {
        m_xCbx4->set_active(true);
        m_xData->CbxHdl(*m_xCbx4);
        m_xQSet4->SetItemColor( 1, aPipetteColor );
        m_xQSet4->SetFormat();
    }
 
    m_xTbxPipette->set_item_active(u"pipette"_ustr, false);
    m_xData->PipetteHdl(u"pipette"_ustr);
}
 
void SvxBmpMask::SetExecState( bool bEnable )
{
    m_xData->SetExecState( bEnable );
 
    if ( m_xData->IsExecReady() && m_xData->IsCbxReady() )
        m_xBtnExec->set_sensitive(true);
    else
        m_xBtnExec->set_sensitive(false);
}
 
 
sal_uInt16 SvxBmpMask::InitColorArrays( Color* pSrcCols, Color* pDstCols, sal_uInt8* pTols )
{
    sal_uInt16  nCount = 0;
 
    if ( m_xCbx1->get_active() )
    {
        pSrcCols[nCount] = m_xQSet1->GetItemColor( 1 );
        pDstCols[nCount] = m_xLbColor1->GetSelectEntryColor();
        pTols[nCount++] = static_cast<sal_uInt8>(m_xSp1->get_value(FieldUnit::PERCENT));
    }
 
    if ( m_xCbx2->get_active() )
    {
        pSrcCols[nCount] = m_xQSet2->GetItemColor( 1 );
        pDstCols[nCount] = m_xLbColor2->GetSelectEntryColor();
        pTols[nCount++] = static_cast<sal_uInt8>(m_xSp2->get_value(FieldUnit::PERCENT));
    }
 
    if ( m_xCbx3->get_active() )
    {
        pSrcCols[nCount] = m_xQSet3->GetItemColor( 1 );
        pDstCols[nCount] = m_xLbColor3->GetSelectEntryColor();
        pTols[nCount++] = static_cast<sal_uInt8>(m_xSp3->get_value(FieldUnit::PERCENT));
    }
 
    if ( m_xCbx4->get_active() )
    {
        pSrcCols[nCount] = m_xQSet4->GetItemColor( 1 );
        pDstCols[nCount] = m_xLbColor4->GetSelectEntryColor();
        pTols[nCount++] = static_cast<sal_uInt8>(m_xSp4->get_value(FieldUnit::PERCENT));
    }
 
    return nCount;
}
 
void SvxBmpMask::ImpMask( BitmapEx& rBitmap )
{
    Color           pSrcCols[4];
    Color           pDstCols[4];
    sal_uInt8       pTols[4];
    const sal_uInt16 nCount = InitColorArrays( pSrcCols, pDstCols, pTols );
 
    EnterWait();
    rBitmap.Replace( pSrcCols, pDstCols, nCount, pTols );
    LeaveWait();
}
 
BitmapEx SvxBmpMask::ImpMaskTransparent( const BitmapEx& rBitmapEx, const Color& rColor, const sal_uInt8 nTol )
{
    EnterWait();
 
    BitmapEx    aBmpEx;
    AlphaMask   aMask( rBitmapEx.GetBitmap().CreateAlphaMask( rColor, nTol ) );
 
    if( rBitmapEx.IsAlpha() )
        aMask.AlphaCombineOr( rBitmapEx.GetAlphaMask() );
 
    aBmpEx = BitmapEx( rBitmapEx.GetBitmap(), aMask );
    LeaveWait();
 
    return aBmpEx;
}
 
 
Animation SvxBmpMask::ImpMask( const Animation& rAnimation )
{
    Animation   aAnimation( rAnimation );
    Color       pSrcCols[4];
    Color       pDstCols[4];
    sal_uInt8   pTols[4];
    InitColorArrays( pSrcCols, pDstCols, pTols );
    sal_uInt16  nAnimationCount = aAnimation.Count();
 
    for( sal_uInt16 i = 0; i < nAnimationCount; i++ )
    {
        AnimationFrame aAnimationFrame( aAnimation.Get( i ) );
        aAnimationFrame.maBitmapEx = Mask(aAnimationFrame.maBitmapEx).GetBitmapEx();
        aAnimation.Replace(aAnimationFrame, i);
    }
 
    return aAnimation;
}
 
 
GDIMetaFile SvxBmpMask::ImpMask( const GDIMetaFile& rMtf )
{
    GDIMetaFile aMtf;
    Color       pSrcCols[4];
    Color       pDstCols[4];
    sal_uInt8   pTols[4];
    sal_uInt16  nCount = InitColorArrays( pSrcCols, pDstCols, pTols );
 
    // If no color is selected, we copy only the Mtf
    if( !nCount )
        aMtf = rMtf;
    else
    {
        bool        pTrans[4];
        Color       aCol;
        tools::Long        nR;
        tools::Long        nG;
        tools::Long        nB;
        std::unique_ptr<tools::Long[]> pMinR(new tools::Long[nCount]);
        std::unique_ptr<tools::Long[]> pMaxR(new tools::Long[nCount]);
        std::unique_ptr<tools::Long[]> pMinG(new tools::Long[nCount]);
        std::unique_ptr<tools::Long[]> pMaxG(new tools::Long[nCount]);
        std::unique_ptr<tools::Long[]> pMinB(new tools::Long[nCount]);
        std::unique_ptr<tools::Long[]> pMaxB(new tools::Long[nCount]);
        sal_uInt16      i;
 
        aMtf.SetPrefSize( rMtf.GetPrefSize() );
        aMtf.SetPrefMapMode( rMtf.GetPrefMapMode() );
 
        // Prepare Color comparison array
        for( i = 0; i < nCount; i++ )
        {
            tools::Long nTol = ( pTols[i] * 255 ) / 100;
 
            tools::Long nVal = static_cast<tools::Long>(pSrcCols[i].GetRed());
            pMinR[i] = std::max( nVal - nTol, tools::Long(0) );
            pMaxR[i] = std::min( nVal + nTol, tools::Long(255) );
 
            nVal = static_cast<tools::Long>(pSrcCols[i].GetGreen());
            pMinG[i] = std::max( nVal - nTol, tools::Long(0) );
            pMaxG[i] = std::min( nVal + nTol, tools::Long(255) );
 
            nVal = static_cast<tools::Long>(pSrcCols[i].GetBlue());
            pMinB[i] = std::max( nVal - nTol, tools::Long(0) );
            pMaxB[i] = std::min( nVal + nTol, tools::Long(255) );
 
            pTrans[ i ] = (pDstCols[ i ] == COL_TRANSPARENT);
        }
 
        // Investigate actions and if necessary replace colors
        for( size_t nAct = 0, nActCount = rMtf.GetActionSize(); nAct < nActCount; nAct++ )
        {
            MetaAction* pAction = rMtf.GetAction( nAct );
 
            bool bReplace = false;
 
            switch( pAction->GetType() )
            {
                case MetaActionType::PIXEL:
                {
                    MetaPixelAction* pAct = static_cast<MetaPixelAction*>(pAction);
 
                    aCol = pAct->GetColor();
                    TEST_COLS();
 
                    if( bReplace )
                        pAct = new MetaPixelAction( pAct->GetPoint(), aCol );
 
                    aMtf.AddAction( pAct );
                }
                break;
 
                case MetaActionType::LINECOLOR:
                {
                    MetaLineColorAction* pAct = static_cast<MetaLineColorAction*>(pAction);
 
                    aCol = pAct->GetColor();
                    TEST_COLS();
 
                    if( bReplace )
                        pAct = new MetaLineColorAction( aCol, !pTrans[ i ] );
 
                    aMtf.AddAction( pAct );
                }
                break;
 
                case MetaActionType::FILLCOLOR:
                {
                    MetaFillColorAction* pAct = static_cast<MetaFillColorAction*>(pAction);
 
                    aCol = pAct->GetColor();
                    TEST_COLS();
 
                    if( bReplace )
                        pAct = new MetaFillColorAction( aCol, !pTrans[ i ] );
 
                    aMtf.AddAction( pAct );
                }
                break;
 
                case MetaActionType::TEXTCOLOR:
                {
                    MetaTextColorAction* pAct = static_cast<MetaTextColorAction*>(pAction);
 
                    aCol = pAct->GetColor();
                    TEST_COLS();
 
                    if( bReplace )
                        pAct = new MetaTextColorAction( aCol );
 
                    aMtf.AddAction( pAct );
                }
                break;
 
                case MetaActionType::TEXTFILLCOLOR:
                {
                    MetaTextFillColorAction* pAct = static_cast<MetaTextFillColorAction*>(pAction);
 
                    aCol = pAct->GetColor();
                    TEST_COLS();
 
                    if( bReplace )
                        pAct = new MetaTextFillColorAction( aCol, !pTrans[ i ] );
 
                    aMtf.AddAction( pAct );
                }
                break;
 
                case MetaActionType::FONT:
                {
                    MetaFontAction* pAct = static_cast<MetaFontAction*>(pAction);
                    vcl::Font       aFont( pAct->GetFont() );
 
                    aCol = aFont.GetColor();
                    TEST_COLS();
 
                    if( bReplace )
                    {
                        aFont.SetColor( aCol );
                        pAct = new MetaFontAction( std::move(aFont) );
                    }
 
                    aMtf.AddAction( pAct );
                }
                break;
 
                case MetaActionType::WALLPAPER:
                {
                    MetaWallpaperAction*    pAct = static_cast<MetaWallpaperAction*>(pAction);
                    Wallpaper               aWall( pAct->GetWallpaper() );
 
                    aCol = aWall.GetColor();
                    TEST_COLS();
 
                    if( bReplace )
                    {
                        aWall.SetColor( aCol );
                        pAct = new MetaWallpaperAction( pAct->GetRect(), std::move(aWall) );
                    }
 
                    aMtf.AddAction( pAct );
                }
                break;
 
                case MetaActionType::BMP:
                {
                    MetaBmpAction*  pAct = static_cast<MetaBmpAction*>(pAction);
                    const Bitmap    aBmp( Mask(BitmapEx(pAct->GetBitmap())).GetBitmapEx().GetBitmap() );
 
                    pAct = new MetaBmpAction( pAct->GetPoint(), aBmp );
                    aMtf.AddAction( pAct );
                }
                break;
 
                case MetaActionType::BMPSCALE:
                {
                    MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pAction);
                    const Bitmap        aBmp( Mask(BitmapEx(pAct->GetBitmap())).GetBitmapEx().GetBitmap() );
 
                    pAct = new MetaBmpScaleAction( pAct->GetPoint(), pAct->GetSize(), aBmp );
                    aMtf.AddAction( pAct );
                }
                break;
 
                case MetaActionType::BMPSCALEPART:
                {
                    MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pAction);
                    const Bitmap            aBmp( Mask(BitmapEx(pAct->GetBitmap())).GetBitmapEx().GetBitmap() );
 
                    pAct = new MetaBmpScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
                                                       pAct->GetSrcPoint(), pAct->GetSrcSize(), aBmp );
                    aMtf.AddAction( pAct );
                }
                break;
 
                case MetaActionType::BMPEX:
                {
                    MetaBmpExAction*    pAct = static_cast<MetaBmpExAction*>(pAction);
                    const BitmapEx      aBmpEx( Mask( pAct->GetBitmapEx() ).GetBitmapEx() );
 
                    pAct = new MetaBmpExAction( pAct->GetPoint(), aBmpEx );
                    aMtf.AddAction( pAct );
                }
                break;
 
                case MetaActionType::BMPEXSCALE:
                {
                    MetaBmpExScaleAction*   pAct = static_cast<MetaBmpExScaleAction*>(pAction);
                    const BitmapEx          aBmpEx( Mask( pAct->GetBitmapEx() ).GetBitmapEx() );
 
                    pAct = new MetaBmpExScaleAction( pAct->GetPoint(), pAct->GetSize(), aBmpEx );
                    aMtf.AddAction( pAct );
                }
                break;
 
                case MetaActionType::BMPEXSCALEPART:
                {
                    MetaBmpExScalePartAction*   pAct = static_cast<MetaBmpExScalePartAction*>(pAction);
                    const BitmapEx              aBmpEx( Mask( pAct->GetBitmapEx() ).GetBitmapEx() );
 
                    pAct = new MetaBmpExScalePartAction( pAct->GetDestPoint(), pAct->GetDestSize(),
                                                         pAct->GetSrcPoint(), pAct->GetSrcSize(), aBmpEx );
                    aMtf.AddAction( pAct );
                }
                break;
 
                default:
                {
                    aMtf.AddAction( pAction );
                }
                break;
            }
        }
    }
 
    LeaveWait();
 
    return aMtf;
}
 
 
Animation SvxBmpMask::ImpReplaceTransparency( const Animation& rAnim, const Color& rColor )
{
    Animation   aAnimation( rAnim );
    sal_uInt16      nAnimationCount = aAnimation.Count();
 
    for( sal_uInt16 i = 0; i < nAnimationCount; i++ )
    {
        AnimationFrame aAnimationFrame(aAnimation.Get(i));
        aAnimationFrame.maBitmapEx.ReplaceTransparency(rColor);
        aAnimation.Replace(aAnimationFrame, i);
    }
 
    return aAnimation;
}
 
 
GDIMetaFile SvxBmpMask::ImpReplaceTransparency( const GDIMetaFile& rMtf, const Color& rColor )
{
    ScopedVclPtrInstance< VirtualDevice > pVDev;
    GDIMetaFile     aMtf;
    const MapMode&  rPrefMap = rMtf.GetPrefMapMode();
    const Size&     rPrefSize = rMtf.GetPrefSize();
    const size_t    nActionCount = rMtf.GetActionSize();
 
    pVDev->EnableOutput( false );
    aMtf.Record( pVDev );
    aMtf.SetPrefSize( rPrefSize );
    aMtf.SetPrefMapMode( rPrefMap );
    pVDev->SetLineColor( rColor );
    pVDev->SetFillColor( rColor );
 
    // retrieve one action at the time; first
    // set the whole area to the replacement color.
    pVDev->DrawRect( tools::Rectangle( rPrefMap.GetOrigin(), rPrefSize ) );
    for ( size_t i = 0; i < nActionCount; i++ )
    {
        MetaAction* pAct = rMtf.GetAction( i );
        aMtf.AddAction( pAct );
    }
 
    aMtf.Stop();
    aMtf.WindStart();
 
    return aMtf;
}
 
GDIMetaFile SvxBmpMask::GetMetaFile(const Graphic& rGraphic)
{
    // Replace transparency?
    if (m_xCbxTrans->get_active())
        return ImpReplaceTransparency(rGraphic.GetGDIMetaFile(), m_xLbColorTrans->GetSelectEntryColor());
    return ImpMask(rGraphic.GetGDIMetaFile());
}
 
Graphic SvxBmpMask::Mask( const Graphic& rGraphic )
{
    Graphic     aGraphic( rGraphic );
    const Color aReplColor( m_xLbColorTrans->GetSelectEntryColor() );
 
    switch( rGraphic.GetType() )
    {
        case GraphicType::Bitmap:
        {
            if( rGraphic.IsAnimated() )
            {
                // Replace transparency?
                if ( m_xCbxTrans->get_active() )
                    aGraphic = ImpReplaceTransparency( rGraphic.GetAnimation(), aReplColor );
                else
                    aGraphic = ImpMask( rGraphic.GetAnimation() );
            }
            else
            {
                // Replace transparency?
                if( m_xCbxTrans->get_active() )
                {
                    BitmapEx aBmpEx = aGraphic.GetBitmapEx();
                    aBmpEx.ReplaceTransparency(aReplColor);
                    aGraphic = aBmpEx;
                }
                else
                {
                    Color   pSrcCols[4];
                    Color   pDstCols[4];
                    sal_uInt8   pTols[4];
                    sal_uInt16  nCount = InitColorArrays( pSrcCols, pDstCols, pTols );
 
                    if( nCount )
                    {
                        // first set all transparent colors
                        for( sal_uInt16 i = 0; i < nCount; i++ )
                        {
                            // Do we have a transparent color?
                            if (pDstCols[i] == COL_TRANSPARENT)
                            {
                                BitmapEx    aBmpEx( ImpMaskTransparent( aGraphic.GetBitmapEx(),
                                                                        pSrcCols[ i ], pTols[ i ] ) );
                                const Size  aSize( aBmpEx.GetSizePixel() );
 
                                if( aSize.Width() && aSize.Height() )
                                    aGraphic = aBmpEx;
                            }
                        }
 
                        // now replace it again with the normal colors
                        BitmapEx  aBitmapEx( aGraphic.GetBitmapEx() );
                        if ( aBitmapEx.GetSizePixel().Width() && aBitmapEx.GetSizePixel().Height() )
                        {
                            ImpMask( aBitmapEx );
                            aGraphic = Graphic( aBitmapEx );
                        }
                    }
                }
            }
        }
        break;
 
        case GraphicType::GdiMetafile:
        {
            GDIMetaFile aMtf(GetMetaFile(rGraphic));
            Size aSize( aMtf.GetPrefSize() );
            if ( aSize.Width() && aSize.Height() )
                aGraphic = Graphic( aMtf );
            else
                aGraphic = rGraphic;
        }
        break;
 
        default:
            aGraphic = rGraphic;
        break;
    }
 
    if( aGraphic != rGraphic )
    {
        aGraphic.SetPrefSize( rGraphic.GetPrefSize() );
        aGraphic.SetPrefMapMode( rGraphic.GetPrefMapMode() );
    }
 
    return aGraphic;
}
 
bool SvxBmpMask::IsEyedropping() const
{
    return m_xTbxPipette->get_item_active(u"pipette"_ustr);
}
 
/** Set an accessible name for the source color check boxes.  Without this
    the lengthy description is read.
*/
void SvxBmpMask::SetAccessibleNames()
{
    // set the accessible name for valueset
    OUString sColorPalette (SvxResId( RID_SVXDLG_BMPMASK_STR_PALETTE));
    OUString sColorPaletteN;
 
    sColorPaletteN = sColorPalette + " 1";
    m_xQSet1->SetText (sColorPaletteN);
    sColorPaletteN = sColorPalette + " 2";
    m_xQSet2->SetText (sColorPaletteN);
    sColorPaletteN = sColorPalette + " 3";
    m_xQSet3->SetText (sColorPaletteN);
    sColorPaletteN = sColorPalette + " 4";
    m_xQSet4->SetText (sColorPaletteN);
}
 
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

V530 The return value of function 'ExecuteList' is required to be utilized.

V530 The return value of function 'ExecuteList' is required to be utilized.

V530 The return value of function 'ExecuteList' is required to be utilized.