/* -*- 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/. * */ #include #include #include #include #include #include using namespace css; namespace cui { FontFeaturesDialog::FontFeaturesDialog(weld::Window* pParent, OUString aFontName) : GenericDialogController(pParent, u"cui/ui/fontfeaturesdialog.ui"_ustr, u"FontFeaturesDialog"_ustr) , m_sFontName(std::move(aFontName)) , m_xContentWindow(m_xBuilder->weld_scrolled_window(u"contentWindow"_ustr)) , m_xContentBox(m_xBuilder->weld_container(u"contentBox"_ustr)) , m_xContentGrid(m_xBuilder->weld_container(u"contentGrid"_ustr)) , m_xStylisticSetsBox(m_xBuilder->weld_container(u"stylisticSetsBox"_ustr)) , m_xStylisticSetsGrid(m_xBuilder->weld_container(u"stylisticSetsGrid"_ustr)) , m_xCharacterVariantsBox(m_xBuilder->weld_container(u"characterVariantsBox"_ustr)) , m_xCharacterVariantsGrid(m_xBuilder->weld_container(u"characterVariantsGrid"_ustr)) , m_xPreviewWindow(new weld::CustomWeld(*m_xBuilder, u"preview"_ustr, m_aPreviewWindow)) { initialize(); } FontFeaturesDialog::~FontFeaturesDialog() {} static sal_Int32 makeEnumComboBox(weld::ComboBox& rNameBox, vcl::font::FeatureDefinition const& rFeatureDefinition, uint32_t nDefault) { sal_Int32 nRes = 0; int count = 0; for (vcl::font::FeatureParameter const& rParameter : rFeatureDefinition.getEnumParameters()) { rNameBox.append(OUString::number(rParameter.getCode()), rParameter.getDescription()); if (rParameter.getCode() == nDefault) nRes = count; ++count; } return nRes; } void FontFeaturesDialog::initialize() { ScopedVclPtrInstance aVDev(*Application::GetDefaultDevice(), DeviceFormat::WITH_ALPHA); std::vector rFontFeatures = getFontFeatureList(m_sFontName, *aVDev); std::unordered_set aDoneFeatures; std::vector rFilteredFontFeatures; for (vcl::font::Feature const& rFontFeature : rFontFeatures) { sal_uInt32 nFontFeatureCode = rFontFeature.m_nCode; if (!aDoneFeatures.insert(nFontFeatureCode).second) continue; rFilteredFontFeatures.push_back(rFontFeature); } int nRowHeight = fillGrid(rFilteredFontFeatures); auto nFeaturesHeight = m_xContentBox->get_preferred_size().Height() + m_xStylisticSetsBox->get_preferred_size().Height() + m_xCharacterVariantsBox->get_preferred_size().Height(); m_xContentWindow->set_size_request( -1, std::min(std::max(m_xContentWindow->get_preferred_size().Height(), nFeaturesHeight), static_cast(300L))); if (nRowHeight) { // tdf#141333 use row height + the 6 px spacing of contentGrid m_xContentWindow->vadjustment_set_step_increment(nRowHeight + 6); } updateFontPreview(); } int FontFeaturesDialog::fillGrid(std::vector const& rFontFeatures) { int nRowHeight(0); vcl::font::FeatureParser aParser(m_sFontName); auto aExistingFeatures = aParser.getFeaturesMap(); sal_Int32 nIdx, nStylisticSets(0), nCharacterVariants(0), nOtherFeatures(0); for (vcl::font::Feature const& rFontFeature : rFontFeatures) { sal_uInt32 nFontFeatureCode = rFontFeature.m_nCode; vcl::font::FeatureDefinition aDefinition; if (rFontFeature.m_aDefinition) aDefinition = rFontFeature.m_aDefinition; if (!aDefinition) aDefinition = { nFontFeatureCode, u""_ustr }; if (rFontFeature.isStylisticSet()) { nIdx = nStylisticSets++; m_xStylisticSetsBox->set_visible(true); m_aFeatureItems.emplace_back( std::make_unique(m_xStylisticSetsGrid.get())); } else if (rFontFeature.isCharacterVariant()) { nIdx = nCharacterVariants++; m_xCharacterVariantsBox->set_visible(true); m_aFeatureItems.emplace_back( std::make_unique(m_xCharacterVariantsGrid.get())); } else { nIdx = nOtherFeatures++; m_xContentBox->set_visible(true); m_aFeatureItems.emplace_back(std::make_unique(m_xContentGrid.get())); } int32_t nValue = 0; if (aExistingFeatures.find(nFontFeatureCode) != aExistingFeatures.end()) nValue = aExistingFeatures.at(nFontFeatureCode); else nValue = aDefinition.getDefault(); FontFeatureItem& aCurrentItem = *m_aFeatureItems.back(); aCurrentItem.m_aFeatureCode = nFontFeatureCode; aCurrentItem.m_nDefault = aDefinition.getDefault(); sal_Int32 nGridPositionX = (nIdx % 2) * 2; sal_Int32 nGridPositionY = nIdx / 2; aCurrentItem.m_xContainer->set_grid_left_attach(nGridPositionX); aCurrentItem.m_xContainer->set_grid_top_attach(nGridPositionY); Link aComboBoxSelectHandler = LINK(this, FontFeaturesDialog, ComboBoxSelectedHdl); Link aCheckBoxToggleHandler = LINK(this, FontFeaturesDialog, CheckBoxToggledHdl); if (aDefinition.getType() == vcl::font::FeatureParameterType::ENUM) { aCurrentItem.m_xText->set_label(aDefinition.getDescription()); aCurrentItem.m_xText->show(); sal_Int32 nInit = makeEnumComboBox(*aCurrentItem.m_xCombo, aDefinition, nValue); aCurrentItem.m_xCombo->set_active(nInit); aCurrentItem.m_xCombo->connect_changed(aComboBoxSelectHandler); aCurrentItem.m_xCombo->show(); } else { if (nValue < 0) { aCurrentItem.m_xCheck->set_state(TRISTATE_INDET); aCurrentItem.m_aTriStateEnabled.bTriStateEnabled = true; aCurrentItem.m_aTriStateEnabled.eState = TRISTATE_INDET; } else { aCurrentItem.m_xCheck->set_state(nValue > 0 ? TRISTATE_TRUE : TRISTATE_FALSE); aCurrentItem.m_aTriStateEnabled.bTriStateEnabled = false; aCurrentItem.m_aTriStateEnabled.eState = aCurrentItem.m_xCheck->get_state(); } aCurrentItem.m_xCheck->set_label(aDefinition.getDescription()); aCurrentItem.m_aToggleHdl = aCheckBoxToggleHandler; aCurrentItem.m_xCheck->show(); } nRowHeight = std::max(nRowHeight, aCurrentItem.m_xContainer->get_preferred_size().Height()); } return nRowHeight; } void FontFeaturesDialog::updateFontPreview() { vcl::Font rPreviewFont = m_aPreviewWindow.GetFont(); vcl::Font rPreviewFontCJK = m_aPreviewWindow.GetCJKFont(); vcl::Font rPreviewFontCTL = m_aPreviewWindow.GetCTLFont(); OUString sNewFontName = createFontNameWithFeatures(); rPreviewFont.SetFamilyName(sNewFontName); rPreviewFontCJK.SetFamilyName(sNewFontName); rPreviewFontCTL.SetFamilyName(sNewFontName); m_aPreviewWindow.SetFont(rPreviewFont, rPreviewFontCJK, rPreviewFontCTL); } IMPL_LINK(FontFeatureItem, CheckBoxToggledHdl, weld::Toggleable&, rToggle, void) { m_aTriStateEnabled.ButtonToggled(rToggle); m_aTriStateEnabled.bTriStateEnabled = false; m_aToggleHdl.Call(rToggle); } IMPL_LINK_NOARG(FontFeaturesDialog, CheckBoxToggledHdl, weld::Toggleable&, void) { updateFontPreview(); } IMPL_LINK_NOARG(FontFeaturesDialog, ComboBoxSelectedHdl, weld::ComboBox&, void) { updateFontPreview(); } OUString FontFeaturesDialog::createFontNameWithFeatures() { OUString sResultFontName; OUStringBuffer sNameSuffix; bool bFirst = true; for (const auto& rEntry : m_aFeatureItems) { const FontFeatureItem& rItem(*rEntry); if (rItem.m_xCheck->get_visible()) { if (rItem.m_xCheck->get_state() != TRISTATE_INDET) { if (!bFirst) sNameSuffix.append(vcl::font::FeatureSeparator); else bFirst = false; sNameSuffix.append(vcl::font::featureCodeAsString(rItem.m_aFeatureCode)); if (rItem.m_xCheck->get_state() == TRISTATE_FALSE) sNameSuffix.append("=0"); } } else if (rItem.m_xCombo->get_visible() && rItem.m_xText->get_visible()) { sal_Int32 nSelection = rItem.m_xCombo->get_active_id().toInt32(); if (nSelection != int(rItem.m_nDefault)) { if (!bFirst) sNameSuffix.append(vcl::font::FeatureSeparator); else bFirst = false; sNameSuffix.append(vcl::font::featureCodeAsString(rItem.m_aFeatureCode) + "=" + OUString::number(nSelection)); } } } sResultFontName = vcl::font::trimFontNameFeatures(m_sFontName); if (!sNameSuffix.isEmpty()) sResultFontName += OUStringChar(vcl::font::FeaturePrefix) + sNameSuffix; return sResultFontName; } short FontFeaturesDialog::run() { short nResult = GenericDialogController::run(); if (nResult == RET_OK) { m_sResultFontName = createFontNameWithFeatures(); } return nResult; } } // end svx namespace /* vim:set shiftwidth=4 softtabstop=4 expandtab: */