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::DEFAULT, DeviceFormat::DEFAULT);
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(m_xStylisticSetsGrid.get());
113 }
114 else if (rFontFeature.isCharacterVariant())
115 {
116 nIdx = nCharacterVariants++;
117 m_xCharacterVariantsBox->set_visible(true);
118 m_aFeatureItems.emplace_back(m_xCharacterVariantsGrid.get());
119 }
120 else
121 {
122 nIdx = nOtherFeatures++;
123 m_xContentBox->set_visible(true);
124 m_aFeatureItems.emplace_back(m_xContentGrid.get());
125 }
126
127 int32_t nValue = 0;
128 if (aExistingFeatures.find(nFontFeatureCode) != aExistingFeatures.end())
129 nValue = aExistingFeatures.at(nFontFeatureCode);
130 else
131 nValue = aDefinition.getDefault();
132
133 FontFeatureItem& aCurrentItem = m_aFeatureItems.back();
134 aCurrentItem.m_aFeatureCode = nFontFeatureCode;
135 aCurrentItem.m_nDefault = aDefinition.getDefault();
136
137 sal_Int32 nGridPositionX = (nIdx % 2) * 2;
138 sal_Int32 nGridPositionY = nIdx / 2;
139 aCurrentItem.m_xContainer->set_grid_left_attach(nGridPositionX);
140 aCurrentItem.m_xContainer->set_grid_top_attach(nGridPositionY);
141
142 Link<weld::ComboBox&, void> aComboBoxSelectHandler
143 = LINK(this, FontFeaturesDialog, ComboBoxSelectedHdl);
144 Link<weld::Toggleable&, void> aCheckBoxToggleHandler
145 = LINK(this, FontFeaturesDialog, CheckBoxToggledHdl);
146
148 {
149 aCurrentItem.m_xText->set_label(aDefinition.getDescription());
150 aCurrentItem.m_xText->show();
151
152 sal_Int32 nInit = makeEnumComboBox(*aCurrentItem.m_xCombo, aDefinition, nValue);
153
154 aCurrentItem.m_xCombo->set_active(nInit);
155 aCurrentItem.m_xCombo->connect_changed(aComboBoxSelectHandler);
156 aCurrentItem.m_xCombo->show();
157 }
158 else
159 {
160 if (nValue < 0)
161 {
162 // If feature is not set, we don’t know if it is enabled by
163 // default or not. But we know that stylistic sets and
164 // character variants are not enabled by default.
165 if (rFontFeature.isStylisticSet() || rFontFeature.isCharacterVariant())
166 aCurrentItem.m_xCheck->set_state(TRISTATE_FALSE);
167 else
168 aCurrentItem.m_xCheck->set_state(TRISTATE_INDET);
169 }
170 else
171 aCurrentItem.m_xCheck->set_state(nValue > 0 ? TRISTATE_TRUE : TRISTATE_FALSE);
172 aCurrentItem.m_xCheck->set_label(aDefinition.getDescription());
173 aCurrentItem.m_xCheck->connect_toggled(aCheckBoxToggleHandler);
174 aCurrentItem.m_xCheck->show();
175 }
176
177 nRowHeight
178 = std::max<int>(nRowHeight, aCurrentItem.m_xContainer->get_preferred_size().Height());
179 }
180
181 return nRowHeight;
182}
183
185{
186 vcl::Font rPreviewFont = m_aPreviewWindow.GetFont();
187 vcl::Font rPreviewFontCJK = m_aPreviewWindow.GetCJKFont();
188 vcl::Font rPreviewFontCTL = m_aPreviewWindow.GetCTLFont();
189
190 OUString sNewFontName = createFontNameWithFeatures();
191
192 rPreviewFont.SetFamilyName(sNewFontName);
193 rPreviewFontCJK.SetFamilyName(sNewFontName);
194 rPreviewFontCTL.SetFamilyName(sNewFontName);
195
196 m_aPreviewWindow.SetFont(rPreviewFont, rPreviewFontCJK, rPreviewFontCTL);
197}
198
200{
201 updateFontPreview();
202}
203
205{
206 updateFontPreview();
207}
208
210{
211 OUString sResultFontName;
212 OUStringBuffer sNameSuffix;
213 bool bFirst = true;
214
215 for (const FontFeatureItem& rItem : m_aFeatureItems)
216 {
217 if (rItem.m_xCheck->get_visible())
218 {
219 if (rItem.m_xCheck->get_state() != TRISTATE_INDET)
220 {
221 if (!bFirst)
222 sNameSuffix.append(vcl::font::FeatureSeparator);
223 else
224 bFirst = false;
225
226 sNameSuffix.append(vcl::font::featureCodeAsString(rItem.m_aFeatureCode));
227 if (rItem.m_xCheck->get_state() == TRISTATE_FALSE)
228 sNameSuffix.append("=0");
229 }
230 }
231 else if (rItem.m_xCombo->get_visible() && rItem.m_xText->get_visible())
232 {
233 sal_Int32 nSelection = rItem.m_xCombo->get_active_id().toInt32();
234 if (nSelection != int(rItem.m_nDefault))
235 {
236 if (!bFirst)
237 sNameSuffix.append(vcl::font::FeatureSeparator);
238 else
239 bFirst = false;
240
241 sNameSuffix.append(vcl::font::featureCodeAsString(rItem.m_aFeatureCode));
242 sNameSuffix.append("=");
243 sNameSuffix.append(OUString::number(nSelection));
244 }
245 }
246 }
248 if (!sNameSuffix.isEmpty())
249 sResultFontName += OUStringChar(vcl::font::FeaturePrefix) + sNameSuffix;
250 return sResultFontName;
251}
252
254{
255 short nResult = GenericDialogController::run();
256 if (nResult == RET_OK)
257 {
259 }
260 return nResult;
261}
262
263} // end svx namespace
264
265/* 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< 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 OUString &rId, const OUString &rStr)
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)
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
std::unique_ptr< weld::Label > m_xText
RET_OK