1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
11 #include <FontFeaturesDialog.hxx>
12 #include <rtl/ustrbuf.hxx>
14 #include <vcl/font/FeatureParser.hxx>
15 #include <FontFeatures.hxx>
16 #include <unordered_set>
22 FontFeaturesDialog::FontFeaturesDialog(weld::Window
* pParent
, OUString aFontName
)
23 : GenericDialogController(pParent
, "cui/ui/fontfeaturesdialog.ui", "FontFeaturesDialog")
24 , m_sFontName(std::move(aFontName
))
25 , m_xContentWindow(m_xBuilder
->weld_scrolled_window("contentWindow"))
26 , m_xContentBox(m_xBuilder
->weld_container("contentBox"))
27 , m_xContentGrid(m_xBuilder
->weld_container("contentGrid"))
28 , m_xStylisticSetsBox(m_xBuilder
->weld_container("stylisticSetsBox"))
29 , m_xStylisticSetsGrid(m_xBuilder
->weld_container("stylisticSetsGrid"))
30 , m_xCharacterVariantsBox(m_xBuilder
->weld_container("characterVariantsBox"))
31 , m_xCharacterVariantsGrid(m_xBuilder
->weld_container("characterVariantsGrid"))
32 , m_xPreviewWindow(new weld::CustomWeld(*m_xBuilder
, "preview", m_aPreviewWindow
))
37 FontFeaturesDialog::~FontFeaturesDialog() {}
39 static sal_Int32
makeEnumComboBox(weld::ComboBox
& rNameBox
,
40 vcl::font::FeatureDefinition
const& rFeatureDefinition
,
45 for (vcl::font::FeatureParameter
const& rParameter
: rFeatureDefinition
.getEnumParameters())
47 rNameBox
.append(OUString::number(rParameter
.getCode()), rParameter
.getDescription());
48 if (rParameter
.getCode() == nDefault
)
55 void FontFeaturesDialog::initialize()
57 ScopedVclPtrInstance
<VirtualDevice
> aVDev(*Application::GetDefaultDevice(),
58 DeviceFormat::WITH_ALPHA
);
59 std::vector
<vcl::font::Feature
> rFontFeatures
= getFontFeatureList(m_sFontName
, *aVDev
);
61 std::unordered_set
<sal_uInt32
> aDoneFeatures
;
62 std::vector
<vcl::font::Feature
> rFilteredFontFeatures
;
64 for (vcl::font::Feature
const& rFontFeature
: rFontFeatures
)
66 sal_uInt32 nFontFeatureCode
= rFontFeature
.m_nCode
;
67 if (!aDoneFeatures
.insert(nFontFeatureCode
).second
)
69 rFilteredFontFeatures
.push_back(rFontFeature
);
72 int nRowHeight
= fillGrid(rFilteredFontFeatures
);
74 auto nFeaturesHeight
= m_xContentBox
->get_preferred_size().Height()
75 + m_xStylisticSetsBox
->get_preferred_size().Height()
76 + m_xCharacterVariantsBox
->get_preferred_size().Height();
77 m_xContentWindow
->set_size_request(
78 -1, std::min(std::max(m_xContentWindow
->get_preferred_size().Height(), nFeaturesHeight
),
79 static_cast<tools::Long
>(300L)));
83 // tdf#141333 use row height + the 6 px spacing of contentGrid
84 m_xContentWindow
->vadjustment_set_step_increment(nRowHeight
+ 6);
90 int FontFeaturesDialog::fillGrid(std::vector
<vcl::font::Feature
> const& rFontFeatures
)
94 vcl::font::FeatureParser
aParser(m_sFontName
);
95 auto aExistingFeatures
= aParser
.getFeaturesMap();
97 sal_Int32 nIdx
, nStylisticSets(0), nCharacterVariants(0), nOtherFeatures(0);
98 for (vcl::font::Feature
const& rFontFeature
: rFontFeatures
)
100 sal_uInt32 nFontFeatureCode
= rFontFeature
.m_nCode
;
102 vcl::font::FeatureDefinition aDefinition
;
103 if (rFontFeature
.m_aDefinition
)
104 aDefinition
= rFontFeature
.m_aDefinition
;
106 aDefinition
= { nFontFeatureCode
, "" };
108 if (rFontFeature
.isStylisticSet())
110 nIdx
= nStylisticSets
++;
111 m_xStylisticSetsBox
->set_visible(true);
112 m_aFeatureItems
.emplace_back(
113 std::make_unique
<FontFeatureItem
>(m_xStylisticSetsGrid
.get()));
115 else if (rFontFeature
.isCharacterVariant())
117 nIdx
= nCharacterVariants
++;
118 m_xCharacterVariantsBox
->set_visible(true);
119 m_aFeatureItems
.emplace_back(
120 std::make_unique
<FontFeatureItem
>(m_xCharacterVariantsGrid
.get()));
124 nIdx
= nOtherFeatures
++;
125 m_xContentBox
->set_visible(true);
126 m_aFeatureItems
.emplace_back(std::make_unique
<FontFeatureItem
>(m_xContentGrid
.get()));
130 if (aExistingFeatures
.find(nFontFeatureCode
) != aExistingFeatures
.end())
131 nValue
= aExistingFeatures
.at(nFontFeatureCode
);
133 nValue
= aDefinition
.getDefault();
135 FontFeatureItem
& aCurrentItem
= *m_aFeatureItems
.back();
136 aCurrentItem
.m_aFeatureCode
= nFontFeatureCode
;
137 aCurrentItem
.m_nDefault
= aDefinition
.getDefault();
139 sal_Int32 nGridPositionX
= (nIdx
% 2) * 2;
140 sal_Int32 nGridPositionY
= nIdx
/ 2;
141 aCurrentItem
.m_xContainer
->set_grid_left_attach(nGridPositionX
);
142 aCurrentItem
.m_xContainer
->set_grid_top_attach(nGridPositionY
);
144 Link
<weld::ComboBox
&, void> aComboBoxSelectHandler
145 = LINK(this, FontFeaturesDialog
, ComboBoxSelectedHdl
);
146 Link
<weld::Toggleable
&, void> aCheckBoxToggleHandler
147 = LINK(this, FontFeaturesDialog
, CheckBoxToggledHdl
);
149 if (aDefinition
.getType() == vcl::font::FeatureParameterType::ENUM
)
151 aCurrentItem
.m_xText
->set_label(aDefinition
.getDescription());
152 aCurrentItem
.m_xText
->show();
154 sal_Int32 nInit
= makeEnumComboBox(*aCurrentItem
.m_xCombo
, aDefinition
, nValue
);
156 aCurrentItem
.m_xCombo
->set_active(nInit
);
157 aCurrentItem
.m_xCombo
->connect_changed(aComboBoxSelectHandler
);
158 aCurrentItem
.m_xCombo
->show();
164 aCurrentItem
.m_xCheck
->set_state(TRISTATE_INDET
);
165 aCurrentItem
.m_aTriStateEnabled
.bTriStateEnabled
= true;
166 aCurrentItem
.m_aTriStateEnabled
.eState
= TRISTATE_INDET
;
170 aCurrentItem
.m_xCheck
->set_state(nValue
> 0 ? TRISTATE_TRUE
: TRISTATE_FALSE
);
171 aCurrentItem
.m_aTriStateEnabled
.bTriStateEnabled
= false;
172 aCurrentItem
.m_aTriStateEnabled
.eState
= aCurrentItem
.m_xCheck
->get_state();
174 aCurrentItem
.m_xCheck
->set_label(aDefinition
.getDescription());
175 aCurrentItem
.m_aToggleHdl
= aCheckBoxToggleHandler
;
176 aCurrentItem
.m_xCheck
->show();
180 = std::max
<int>(nRowHeight
, aCurrentItem
.m_xContainer
->get_preferred_size().Height());
186 void FontFeaturesDialog::updateFontPreview()
188 vcl::Font rPreviewFont
= m_aPreviewWindow
.GetFont();
189 vcl::Font rPreviewFontCJK
= m_aPreviewWindow
.GetCJKFont();
190 vcl::Font rPreviewFontCTL
= m_aPreviewWindow
.GetCTLFont();
192 OUString sNewFontName
= createFontNameWithFeatures();
194 rPreviewFont
.SetFamilyName(sNewFontName
);
195 rPreviewFontCJK
.SetFamilyName(sNewFontName
);
196 rPreviewFontCTL
.SetFamilyName(sNewFontName
);
198 m_aPreviewWindow
.SetFont(rPreviewFont
, rPreviewFontCJK
, rPreviewFontCTL
);
201 IMPL_LINK(FontFeatureItem
, CheckBoxToggledHdl
, weld::Toggleable
&, rToggle
, void)
203 m_aTriStateEnabled
.ButtonToggled(rToggle
);
204 m_aTriStateEnabled
.bTriStateEnabled
= false;
205 m_aToggleHdl
.Call(rToggle
);
208 IMPL_LINK_NOARG(FontFeaturesDialog
, CheckBoxToggledHdl
, weld::Toggleable
&, void)
213 IMPL_LINK_NOARG(FontFeaturesDialog
, ComboBoxSelectedHdl
, weld::ComboBox
&, void)
218 OUString
FontFeaturesDialog::createFontNameWithFeatures()
220 OUString sResultFontName
;
221 OUStringBuffer sNameSuffix
;
224 for (const auto& rEntry
: m_aFeatureItems
)
226 const FontFeatureItem
& rItem(*rEntry
);
227 if (rItem
.m_xCheck
->get_visible())
229 if (rItem
.m_xCheck
->get_state() != TRISTATE_INDET
)
232 sNameSuffix
.append(vcl::font::FeatureSeparator
);
236 sNameSuffix
.append(vcl::font::featureCodeAsString(rItem
.m_aFeatureCode
));
237 if (rItem
.m_xCheck
->get_state() == TRISTATE_FALSE
)
238 sNameSuffix
.append("=0");
241 else if (rItem
.m_xCombo
->get_visible() && rItem
.m_xText
->get_visible())
243 sal_Int32 nSelection
= rItem
.m_xCombo
->get_active_id().toInt32();
244 if (nSelection
!= int(rItem
.m_nDefault
))
247 sNameSuffix
.append(vcl::font::FeatureSeparator
);
251 sNameSuffix
.append(vcl::font::featureCodeAsString(rItem
.m_aFeatureCode
) + "="
252 + OUString::number(nSelection
));
256 sResultFontName
= vcl::font::trimFontNameFeatures(m_sFontName
);
257 if (!sNameSuffix
.isEmpty())
258 sResultFontName
+= OUStringChar(vcl::font::FeaturePrefix
) + sNameSuffix
;
259 return sResultFontName
;
262 short FontFeaturesDialog::run()
264 short nResult
= GenericDialogController::run();
265 if (nResult
== RET_OK
)
267 m_sResultFontName
= createFontNameWithFeatures();
272 } // end svx namespace
274 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */