LibreOffice Module cui (master) 1
FontFeaturesDialog.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 */
10
12#include <rtl/ustrbuf.hxx>
13#include <utility>
15#include <FontFeatures.hxx>
16#include <unordered_set>
17
18using namespace css;
19
20namespace cui
21{
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))
33{
34 initialize();
35}
36
38
39static sal_Int32 makeEnumComboBox(weld::ComboBox& rNameBox,
40 vcl::font::FeatureDefinition const& rFeatureDefinition,
41 uint32_t nDefault)
42{
43 sal_Int32 nRes = 0;
44 int count = 0;
45 for (vcl::font::FeatureParameter const& rParameter : rFeatureDefinition.getEnumParameters())
46 {
47 rNameBox.append(OUString::number(rParameter.getCode()), rParameter.getDescription());
48 if (rParameter.getCode() == nDefault)
49 nRes = count;
50 ++count;
51 }
52 return nRes;
53}
54
56{
58 DeviceFormat::WITH_ALPHA);
59 std::vector<vcl::font::Feature> rFontFeatures = getFontFeatureList(m_sFontName, *aVDev);
60
61 std::unordered_set<sal_uInt32> aDoneFeatures;
62 std::vector<vcl::font::Feature> rFilteredFontFeatures;
63
64 for (vcl::font::Feature const& rFontFeature : rFontFeatures)
65 {
66 sal_uInt32 nFontFeatureCode = rFontFeature.m_nCode;
67 if (!aDoneFeatures.insert(nFontFeatureCode).second)
68 continue;
69 rFilteredFontFeatures.push_back(rFontFeature);
70 }
71
72 int nRowHeight = fillGrid(rFilteredFontFeatures);
73
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)));
80
81 if (nRowHeight)
82 {
83 // tdf#141333 use row height + the 6 px spacing of contentGrid
84 m_xContentWindow->vadjustment_set_step_increment(nRowHeight + 6);
85 }
86
88}
89
90int FontFeaturesDialog::fillGrid(std::vector<vcl::font::Feature> const& rFontFeatures)
91{
92 int nRowHeight(0);
93
95 auto aExistingFeatures = aParser.getFeaturesMap();
96
97 sal_Int32 nIdx, nStylisticSets(0), nCharacterVariants(0), nOtherFeatures(0);
98 for (vcl::font::Feature const& rFontFeature : rFontFeatures)
99 {
100 sal_uInt32 nFontFeatureCode = rFontFeature.m_nCode;
101
103 if (rFontFeature.m_aDefinition)
104 aDefinition = rFontFeature.m_aDefinition;
105 if (!aDefinition)
106 aDefinition = { nFontFeatureCode, "" };
107
108 if (rFontFeature.isStylisticSet())
109 {
110 nIdx = nStylisticSets++;
111 m_xStylisticSetsBox->set_visible(true);
112 m_aFeatureItems.emplace_back(
113 std::make_unique<FontFeatureItem>(m_xStylisticSetsGrid.get()));
114 }
115 else if (rFontFeature.isCharacterVariant())
116 {
117 nIdx = nCharacterVariants++;
118 m_xCharacterVariantsBox->set_visible(true);
119 m_aFeatureItems.emplace_back(
120 std::make_unique<FontFeatureItem>(m_xCharacterVariantsGrid.get()));
121 }
122 else
123 {
124 nIdx = nOtherFeatures++;
125 m_xContentBox->set_visible(true);
126 m_aFeatureItems.emplace_back(std::make_unique<FontFeatureItem>(m_xContentGrid.get()));
127 }
128
129 int32_t nValue = 0;
130 if (aExistingFeatures.find(nFontFeatureCode) != aExistingFeatures.end())
131 nValue = aExistingFeatures.at(nFontFeatureCode);
132 else
133 nValue = aDefinition.getDefault();
134
135 FontFeatureItem& aCurrentItem = *m_aFeatureItems.back();
136 aCurrentItem.m_aFeatureCode = nFontFeatureCode;
137 aCurrentItem.m_nDefault = aDefinition.getDefault();
138
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);
143
144 Link<weld::ComboBox&, void> aComboBoxSelectHandler
145 = LINK(this, FontFeaturesDialog, ComboBoxSelectedHdl);
146 Link<weld::Toggleable&, void> aCheckBoxToggleHandler
147 = LINK(this, FontFeaturesDialog, CheckBoxToggledHdl);
148
150 {
151 aCurrentItem.m_xText->set_label(aDefinition.getDescription());
152 aCurrentItem.m_xText->show();
153
154 sal_Int32 nInit = makeEnumComboBox(*aCurrentItem.m_xCombo, aDefinition, nValue);
155
156 aCurrentItem.m_xCombo->set_active(nInit);
157 aCurrentItem.m_xCombo->connect_changed(aComboBoxSelectHandler);
158 aCurrentItem.m_xCombo->show();
159 }
160 else
161 {
162 if (nValue < 0)
163 {
164 aCurrentItem.m_xCheck->set_state(TRISTATE_INDET);
165 aCurrentItem.m_aTriStateEnabled.bTriStateEnabled = true;
167 }
168 else
169 {
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();
173 }
174 aCurrentItem.m_xCheck->set_label(aDefinition.getDescription());
175 aCurrentItem.m_aToggleHdl = aCheckBoxToggleHandler;
176 aCurrentItem.m_xCheck->show();
177 }
178
179 nRowHeight
180 = std::max<int>(nRowHeight, aCurrentItem.m_xContainer->get_preferred_size().Height());
181 }
182
183 return nRowHeight;
184}
185
187{
188 vcl::Font rPreviewFont = m_aPreviewWindow.GetFont();
189 vcl::Font rPreviewFontCJK = m_aPreviewWindow.GetCJKFont();
190 vcl::Font rPreviewFontCTL = m_aPreviewWindow.GetCTLFont();
191
192 OUString sNewFontName = createFontNameWithFeatures();
193
194 rPreviewFont.SetFamilyName(sNewFontName);
195 rPreviewFontCJK.SetFamilyName(sNewFontName);
196 rPreviewFontCTL.SetFamilyName(sNewFontName);
197
198 m_aPreviewWindow.SetFont(rPreviewFont, rPreviewFontCJK, rPreviewFontCTL);
199}
200
201IMPL_LINK(FontFeatureItem, CheckBoxToggledHdl, weld::Toggleable&, rToggle, void)
202{
203 m_aTriStateEnabled.ButtonToggled(rToggle);
204 m_aTriStateEnabled.bTriStateEnabled = false;
205 m_aToggleHdl.Call(rToggle);
206}
207
209{
210 updateFontPreview();
211}
212
214{
215 updateFontPreview();
216}
217
219{
220 OUString sResultFontName;
221 OUStringBuffer sNameSuffix;
222 bool bFirst = true;
223
224 for (const auto& rEntry : m_aFeatureItems)
225 {
226 const FontFeatureItem& rItem(*rEntry);
227 if (rItem.m_xCheck->get_visible())
228 {
229 if (rItem.m_xCheck->get_state() != TRISTATE_INDET)
230 {
231 if (!bFirst)
232 sNameSuffix.append(vcl::font::FeatureSeparator);
233 else
234 bFirst = false;
235
236 sNameSuffix.append(vcl::font::featureCodeAsString(rItem.m_aFeatureCode));
237 if (rItem.m_xCheck->get_state() == TRISTATE_FALSE)
238 sNameSuffix.append("=0");
239 }
240 }
241 else if (rItem.m_xCombo->get_visible() && rItem.m_xText->get_visible())
242 {
243 sal_Int32 nSelection = rItem.m_xCombo->get_active_id().toInt32();
244 if (nSelection != int(rItem.m_nDefault))
245 {
246 if (!bFirst)
247 sNameSuffix.append(vcl::font::FeatureSeparator);
248 else
249 bFirst = false;
250
251 sNameSuffix.append(vcl::font::featureCodeAsString(rItem.m_aFeatureCode) + "="
252 + OUString::number(nSelection));
253 }
254 }
255 }
257 if (!sNameSuffix.isEmpty())
258 sResultFontName += OUStringChar(vcl::font::FeaturePrefix) + sNameSuffix;
259 return sResultFontName;
260}
261
263{
264 short nResult = GenericDialogController::run();
265 if (nResult == RET_OK)
266 {
268 }
269 return nResult;
270}
271
272} // end svx namespace
273
274/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
std::vector< vcl::font::Feature > getFontFeatureList(OUString const &rFontName, VirtualDevice &rVDev)
static OutputDevice * GetDefaultDevice()
SvxFont & GetFont()
SvxFont & GetCTLFont()
void SetFont(const SvxFont &rNormalFont, const SvxFont &rCJKFont, const SvxFont &rCTLFont)
SvxFont & GetCJKFont()
std::unique_ptr< weld::Container > m_xContentBox
virtual short run() override
std::vector< std::unique_ptr< FontFeatureItem > > m_aFeatureItems
std::unique_ptr< weld::Container > m_xStylisticSetsGrid
std::unique_ptr< weld::ScrolledWindow > m_xContentWindow
std::unique_ptr< weld::Container > m_xStylisticSetsBox
FontFeaturesDialog(weld::Window *pParent, OUString aFontName)
std::unique_ptr< weld::Container > m_xCharacterVariantsGrid
std::unique_ptr< weld::Container > m_xCharacterVariantsBox
std::unique_ptr< weld::Container > m_xContentGrid
SvxFontPrevWindow m_aPreviewWindow
int fillGrid(std::vector< vcl::font::Feature > const &rFontFeatures)
void SetFamilyName(const OUString &rFamilyName)
FeatureParameterType getType() const
const std::vector< FeatureParameter > & getEnumParameters() const
OUString getDescription() const
std::unordered_map< uint32_t, int32_t > getFeaturesMap() const
void append(const weld::ComboBoxEntry &rItem)
sal_Int16 nValue
TRISTATE_FALSE
TRISTATE_INDET
TRISTATE_TRUE
static sal_Int32 makeEnumComboBox(weld::ComboBox &rNameBox, vcl::font::FeatureDefinition const &rFeatureDefinition, uint32_t nDefault)
IMPL_LINK_NOARG(ColorPickerDialog, ColorFieldControlModifydl, ColorFieldControl &, void)
IMPL_LINK(ColorPickerDialog, ColorModifyMetricHdl, weld::MetricSpinButton &, rEdit, void)
long Long
constexpr const char FeaturePrefix
OUString trimFontNameFeatures(OUString const &rFontName)
OUString featureCodeAsString(uint32_t nFeature)
constexpr const char FeatureSeparator
std::unique_ptr< weld::Widget > m_xContainer
std::unique_ptr< weld::ComboBox > m_xCombo
std::unique_ptr< weld::CheckButton > m_xCheck
weld::TriStateEnabled m_aTriStateEnabled
std::unique_ptr< weld::Label > m_xText
Link< weld::Toggleable &, void > m_aToggleHdl
RET_OK