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
, u
"cui/ui/fontfeaturesdialog.ui"_ustr
,
24 u
"FontFeaturesDialog"_ustr
)
25 , m_sFontName(std::move(aFontName
))
26 , m_xContentWindow(m_xBuilder
->weld_scrolled_window(u
"contentWindow"_ustr
))
27 , m_xContentBox(m_xBuilder
->weld_container(u
"contentBox"_ustr
))
28 , m_xContentGrid(m_xBuilder
->weld_container(u
"contentGrid"_ustr
))
29 , m_xStylisticSetsBox(m_xBuilder
->weld_container(u
"stylisticSetsBox"_ustr
))
30 , m_xStylisticSetsGrid(m_xBuilder
->weld_container(u
"stylisticSetsGrid"_ustr
))
31 , m_xCharacterVariantsBox(m_xBuilder
->weld_container(u
"characterVariantsBox"_ustr
))
32 , m_xCharacterVariantsGrid(m_xBuilder
->weld_container(u
"characterVariantsGrid"_ustr
))
33 , m_xPreviewWindow(new weld::CustomWeld(*m_xBuilder
, u
"preview"_ustr
, m_aPreviewWindow
))
38 FontFeaturesDialog::~FontFeaturesDialog() {}
40 static sal_Int32
makeEnumComboBox(weld::ComboBox
& rNameBox
,
41 vcl::font::FeatureDefinition
const& rFeatureDefinition
,
46 for (vcl::font::FeatureParameter
const& rParameter
: rFeatureDefinition
.getEnumParameters())
48 rNameBox
.append(OUString::number(rParameter
.getCode()), rParameter
.getDescription());
49 if (rParameter
.getCode() == nDefault
)
56 void FontFeaturesDialog::initialize()
58 ScopedVclPtrInstance
<VirtualDevice
> aVDev(*Application::GetDefaultDevice(),
59 DeviceFormat::WITH_ALPHA
);
60 std::vector
<vcl::font::Feature
> rFontFeatures
= getFontFeatureList(m_sFontName
, *aVDev
);
62 std::unordered_set
<sal_uInt32
> aDoneFeatures
;
63 std::vector
<vcl::font::Feature
> rFilteredFontFeatures
;
65 for (vcl::font::Feature
const& rFontFeature
: rFontFeatures
)
67 sal_uInt32 nFontFeatureCode
= rFontFeature
.m_nCode
;
68 if (!aDoneFeatures
.insert(nFontFeatureCode
).second
)
70 rFilteredFontFeatures
.push_back(rFontFeature
);
73 int nRowHeight
= fillGrid(rFilteredFontFeatures
);
75 auto nFeaturesHeight
= m_xContentBox
->get_preferred_size().Height()
76 + m_xStylisticSetsBox
->get_preferred_size().Height()
77 + m_xCharacterVariantsBox
->get_preferred_size().Height();
78 m_xContentWindow
->set_size_request(
79 -1, std::min(std::max(m_xContentWindow
->get_preferred_size().Height(), nFeaturesHeight
),
80 static_cast<tools::Long
>(300L)));
84 // tdf#141333 use row height + the 6 px spacing of contentGrid
85 m_xContentWindow
->vadjustment_set_step_increment(nRowHeight
+ 6);
91 int FontFeaturesDialog::fillGrid(std::vector
<vcl::font::Feature
> const& rFontFeatures
)
95 vcl::font::FeatureParser
aParser(m_sFontName
);
96 auto aExistingFeatures
= aParser
.getFeaturesMap();
98 sal_Int32 nIdx
, nStylisticSets(0), nCharacterVariants(0), nOtherFeatures(0);
99 for (vcl::font::Feature
const& rFontFeature
: rFontFeatures
)
101 sal_uInt32 nFontFeatureCode
= rFontFeature
.m_nCode
;
103 vcl::font::FeatureDefinition aDefinition
;
104 if (rFontFeature
.m_aDefinition
)
105 aDefinition
= rFontFeature
.m_aDefinition
;
107 aDefinition
= { nFontFeatureCode
, u
""_ustr
};
109 if (rFontFeature
.isStylisticSet())
111 nIdx
= nStylisticSets
++;
112 m_xStylisticSetsBox
->set_visible(true);
113 m_aFeatureItems
.emplace_back(
114 std::make_unique
<FontFeatureItem
>(m_xStylisticSetsGrid
.get()));
116 else if (rFontFeature
.isCharacterVariant())
118 nIdx
= nCharacterVariants
++;
119 m_xCharacterVariantsBox
->set_visible(true);
120 m_aFeatureItems
.emplace_back(
121 std::make_unique
<FontFeatureItem
>(m_xCharacterVariantsGrid
.get()));
125 nIdx
= nOtherFeatures
++;
126 m_xContentBox
->set_visible(true);
127 m_aFeatureItems
.emplace_back(std::make_unique
<FontFeatureItem
>(m_xContentGrid
.get()));
131 if (aExistingFeatures
.find(nFontFeatureCode
) != aExistingFeatures
.end())
132 nValue
= aExistingFeatures
.at(nFontFeatureCode
);
134 nValue
= aDefinition
.getDefault();
136 FontFeatureItem
& aCurrentItem
= *m_aFeatureItems
.back();
137 aCurrentItem
.m_aFeatureCode
= nFontFeatureCode
;
138 aCurrentItem
.m_nDefault
= aDefinition
.getDefault();
140 sal_Int32 nGridPositionX
= (nIdx
% 2) * 2;
141 sal_Int32 nGridPositionY
= nIdx
/ 2;
142 aCurrentItem
.m_xContainer
->set_grid_left_attach(nGridPositionX
);
143 aCurrentItem
.m_xContainer
->set_grid_top_attach(nGridPositionY
);
145 Link
<weld::ComboBox
&, void> aComboBoxSelectHandler
146 = LINK(this, FontFeaturesDialog
, ComboBoxSelectedHdl
);
147 Link
<weld::Toggleable
&, void> aCheckBoxToggleHandler
148 = LINK(this, FontFeaturesDialog
, CheckBoxToggledHdl
);
150 if (aDefinition
.getType() == vcl::font::FeatureParameterType::ENUM
)
152 aCurrentItem
.m_xText
->set_label(aDefinition
.getDescription());
153 aCurrentItem
.m_xText
->show();
155 sal_Int32 nInit
= makeEnumComboBox(*aCurrentItem
.m_xCombo
, aDefinition
, nValue
);
157 aCurrentItem
.m_xCombo
->set_active(nInit
);
158 aCurrentItem
.m_xCombo
->connect_changed(aComboBoxSelectHandler
);
159 aCurrentItem
.m_xCombo
->show();
165 aCurrentItem
.m_xCheck
->set_state(TRISTATE_INDET
);
166 aCurrentItem
.m_aTriStateEnabled
.bTriStateEnabled
= true;
167 aCurrentItem
.m_aTriStateEnabled
.eState
= TRISTATE_INDET
;
171 aCurrentItem
.m_xCheck
->set_state(nValue
> 0 ? TRISTATE_TRUE
: TRISTATE_FALSE
);
172 aCurrentItem
.m_aTriStateEnabled
.bTriStateEnabled
= false;
173 aCurrentItem
.m_aTriStateEnabled
.eState
= aCurrentItem
.m_xCheck
->get_state();
175 aCurrentItem
.m_xCheck
->set_label(aDefinition
.getDescription());
176 aCurrentItem
.m_aToggleHdl
= aCheckBoxToggleHandler
;
177 aCurrentItem
.m_xCheck
->show();
181 = std::max
<int>(nRowHeight
, aCurrentItem
.m_xContainer
->get_preferred_size().Height());
187 void FontFeaturesDialog::updateFontPreview()
189 vcl::Font rPreviewFont
= m_aPreviewWindow
.GetFont();
190 vcl::Font rPreviewFontCJK
= m_aPreviewWindow
.GetCJKFont();
191 vcl::Font rPreviewFontCTL
= m_aPreviewWindow
.GetCTLFont();
193 OUString sNewFontName
= createFontNameWithFeatures();
195 rPreviewFont
.SetFamilyName(sNewFontName
);
196 rPreviewFontCJK
.SetFamilyName(sNewFontName
);
197 rPreviewFontCTL
.SetFamilyName(sNewFontName
);
199 m_aPreviewWindow
.SetFont(rPreviewFont
, rPreviewFontCJK
, rPreviewFontCTL
);
202 IMPL_LINK(FontFeatureItem
, CheckBoxToggledHdl
, weld::Toggleable
&, rToggle
, void)
204 m_aTriStateEnabled
.ButtonToggled(rToggle
);
205 m_aTriStateEnabled
.bTriStateEnabled
= false;
206 m_aToggleHdl
.Call(rToggle
);
209 IMPL_LINK_NOARG(FontFeaturesDialog
, CheckBoxToggledHdl
, weld::Toggleable
&, void)
214 IMPL_LINK_NOARG(FontFeaturesDialog
, ComboBoxSelectedHdl
, weld::ComboBox
&, void)
219 OUString
FontFeaturesDialog::createFontNameWithFeatures()
221 OUString sResultFontName
;
222 OUStringBuffer sNameSuffix
;
225 for (const auto& rEntry
: m_aFeatureItems
)
227 const FontFeatureItem
& rItem(*rEntry
);
228 if (rItem
.m_xCheck
->get_visible())
230 if (rItem
.m_xCheck
->get_state() != TRISTATE_INDET
)
233 sNameSuffix
.append(vcl::font::FeatureSeparator
);
237 sNameSuffix
.append(vcl::font::featureCodeAsString(rItem
.m_aFeatureCode
));
238 if (rItem
.m_xCheck
->get_state() == TRISTATE_FALSE
)
239 sNameSuffix
.append("=0");
242 else if (rItem
.m_xCombo
->get_visible() && rItem
.m_xText
->get_visible())
244 sal_Int32 nSelection
= rItem
.m_xCombo
->get_active_id().toInt32();
245 if (nSelection
!= int(rItem
.m_nDefault
))
248 sNameSuffix
.append(vcl::font::FeatureSeparator
);
252 sNameSuffix
.append(vcl::font::featureCodeAsString(rItem
.m_aFeatureCode
) + "="
253 + OUString::number(nSelection
));
257 sResultFontName
= vcl::font::trimFontNameFeatures(m_sFontName
);
258 if (!sNameSuffix
.isEmpty())
259 sResultFontName
+= OUStringChar(vcl::font::FeaturePrefix
) + sNameSuffix
;
260 return sResultFontName
;
263 short FontFeaturesDialog::run()
265 short nResult
= GenericDialogController::run();
266 if (nResult
== RET_OK
)
268 m_sResultFontName
= createFontNameWithFeatures();
273 } // end svx namespace
275 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */