Kaydet (Commit) 3aa8a048 authored tarafından Tomaž Vajngerl's avatar Tomaž Vajngerl Kaydeden (comit) Tomaž Vajngerl

tdf#58941 Manipulate with font features using FontFeatureDialog

This adds a font feature dialog activated on the Character page,
which adds a way to manipulate the available font features for the
current selected font (by adding them to the font name).

Change-Id: Icd0eda31b235d3cc8ef6eaee582fb78b4b346d78
Reviewed-on: https://gerrit.libreoffice.org/55894
Tested-by: Jenkins
Reviewed-by: 's avatarTomaž Vajngerl <quikee@gmail.com>
üst 0af04819
......@@ -102,6 +102,7 @@ $(eval $(call gb_Library_add_exception_objects,cui,\
cui/source/dialogs/cuiimapwnd \
cui/source/dialogs/cuitbxform \
cui/source/dialogs/dlgname \
cui/source/dialogs/FontFeaturesDialog \
cui/source/dialogs/hangulhanjadlg \
cui/source/dialogs/hldocntp \
cui/source/dialogs/hldoctp \
......
......@@ -63,6 +63,7 @@ $(eval $(call gb_UIConfig_add_uifiles,cui,\
cui/uiconfig/ui/effectspage \
cui/uiconfig/ui/eventsconfigpage \
cui/uiconfig/ui/formatcellsdialog \
cui/uiconfig/ui/fontfeaturesdialog \
cui/uiconfig/ui/galleryapplyprogress \
cui/uiconfig/ui/galleryfilespage \
cui/uiconfig/ui/gallerygeneralpage \
......
/* -*- 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 <FontFeaturesDialog.hxx>
#include <vcl/font/FeatureParser.hxx>
#include <svx/strings.hrc>
#include <svx/dialmgr.hxx>
using namespace css;
namespace cui
{
FontFeaturesDialog::FontFeaturesDialog(vcl::Window* pParent, OUString const& rFontName)
: ModalDialog(pParent, "FontFeaturesDialog", "cui/ui/fontfeaturesdialog.ui")
, m_sFontName(rFontName)
{
get(m_pContentGrid, "contentGrid");
get(m_pPreviewWindow, "preview");
initialize();
}
FontFeaturesDialog::~FontFeaturesDialog() { disposeOnce(); }
VclPtr<ComboBox> makeEnumComboBox(vcl::Window* pParent,
vcl::font::FeatureDefinition const& rFeatureDefinition)
{
VclPtr<ComboBox> aNameBox(
VclPtr<ComboBox>::Create(pParent, WB_TABSTOP | WB_DROPDOWN | WB_AUTOHSCROLL));
aNameBox->InsertEntry(SvxResId(RID_SVXSTR_NONE));
for (vcl::font::FeatureParameter const& rParameter : rFeatureDefinition.getEnumParameters())
{
aNameBox->InsertEntry(rParameter.getDescription());
}
aNameBox->EnableAutoSize(true);
return aNameBox;
}
void FontFeaturesDialog::initialize()
{
ScopedVclPtrInstance<VirtualDevice> aVDev(*Application::GetDefaultDevice(),
DeviceFormat::DEFAULT, DeviceFormat::DEFAULT);
aVDev->SetOutputSizePixel(Size(10, 10));
vcl::Font aFont = aVDev->GetFont();
aFont.SetFamilyName(m_sFontName);
aVDev->SetFont(aFont);
std::vector<vcl::font::Feature> rFontFeatures;
if (!aVDev->GetFontFeatures(rFontFeatures))
return;
vcl::font::FeatureParser aParser(m_sFontName);
std::unordered_map<sal_uInt32, sal_uInt32> aExistingFeatures = aParser.getFeaturesMap();
std::unordered_set<sal_uInt32> aDoneFeatures;
sal_Int32 i = 0;
for (vcl::font::Feature const& rFontFeature : rFontFeatures)
{
sal_uInt32 nFontFeatureCode = rFontFeature.m_aID.m_aFeatureCode;
if (aDoneFeatures.find(nFontFeatureCode) != aDoneFeatures.end())
continue;
aDoneFeatures.insert(nFontFeatureCode);
vcl::font::FeatureDefinition aDefinition;
if (rFontFeature.m_aDefinition)
aDefinition = rFontFeature.m_aDefinition;
if (!aDefinition)
aDefinition = { nFontFeatureCode, nullptr };
m_aFeatureItems.emplace_back();
sal_uInt32 nValue = 0;
if (aExistingFeatures.find(nFontFeatureCode) != aExistingFeatures.end())
nValue = aExistingFeatures.at(nFontFeatureCode);
FontFeatureItem& aCurrentItem = m_aFeatureItems.back();
aCurrentItem.m_aFeatureCode = nFontFeatureCode;
sal_Int32 nGridPositionX = (i % 2) * 2;
sal_Int32 nGridPositionY = i / 2;
Link<ComboBox&, void> aComboBoxSelectHandler
= LINK(this, FontFeaturesDialog, ComboBoxSelectedHdl);
Link<CheckBox&, void> aCheckBoxToggleHandler
= LINK(this, FontFeaturesDialog, CheckBoxToggledHdl);
if (aDefinition.getType() == vcl::font::FeatureParameterType::ENUM)
{
aCurrentItem.m_pText
= VclPtr<FixedText>::Create(m_pContentGrid, WB_LEFT | WB_VCENTER | WB_3DLOOK);
aCurrentItem.m_pText->set_grid_left_attach(nGridPositionX);
aCurrentItem.m_pText->set_grid_top_attach(nGridPositionY);
aCurrentItem.m_pText->set_margin_left(6);
aCurrentItem.m_pText->set_margin_right(6);
aCurrentItem.m_pText->set_margin_top(3);
aCurrentItem.m_pText->set_margin_bottom(3);
aCurrentItem.m_pText->SetText(aDefinition.getDescription());
aCurrentItem.m_pText->Show();
aCurrentItem.m_pCombo = makeEnumComboBox(m_pContentGrid, aDefinition);
aCurrentItem.m_pCombo->SelectEntryPos(nValue);
aCurrentItem.m_pCombo->set_grid_left_attach(nGridPositionX + 1);
aCurrentItem.m_pCombo->set_grid_top_attach(nGridPositionY);
aCurrentItem.m_pCombo->set_margin_left(6);
aCurrentItem.m_pCombo->set_margin_right(6);
aCurrentItem.m_pCombo->set_margin_top(3);
aCurrentItem.m_pCombo->set_margin_bottom(3);
aCurrentItem.m_pCombo->SetSelectHdl(aComboBoxSelectHandler);
aCurrentItem.m_pCombo->Show();
}
else
{
aCurrentItem.m_pCheck = VclPtr<CheckBox>::Create(
m_pContentGrid, WB_CLIPCHILDREN | WB_LEFT | WB_VCENTER | WB_3DLOOK);
aCurrentItem.m_pCheck->set_grid_left_attach(nGridPositionX);
aCurrentItem.m_pCheck->set_grid_top_attach(nGridPositionY);
aCurrentItem.m_pCheck->set_grid_width(2);
aCurrentItem.m_pCheck->set_margin_left(6);
aCurrentItem.m_pCheck->set_margin_right(6);
aCurrentItem.m_pCheck->set_margin_top(3);
aCurrentItem.m_pCheck->set_margin_bottom(3);
aCurrentItem.m_pCheck->Check(nValue > 0);
aCurrentItem.m_pCheck->SetText(aDefinition.getDescription());
aCurrentItem.m_pCheck->SetToggleHdl(aCheckBoxToggleHandler);
aCurrentItem.m_pCheck->Show();
}
i++;
}
updateFontPreview();
}
void FontFeaturesDialog::updateFontPreview()
{
vcl::Font rPreviewFont = m_pPreviewWindow->GetFont();
vcl::Font rPreviewFontCJK = m_pPreviewWindow->GetCJKFont();
vcl::Font rPreviewFontCTL = m_pPreviewWindow->GetCTLFont();
OUString sNewFontName = createFontNameWithFeatures();
rPreviewFont.SetFamilyName(sNewFontName);
rPreviewFontCJK.SetFamilyName(sNewFontName);
rPreviewFontCTL.SetFamilyName(sNewFontName);
m_pPreviewWindow->SetFont(rPreviewFont, rPreviewFontCJK, rPreviewFontCTL);
}
void FontFeaturesDialog::dispose()
{
m_pContentGrid.clear();
m_pPreviewWindow.clear();
for (FontFeatureItem& rItem : m_aFeatureItems)
{
rItem.m_pText.disposeAndClear();
rItem.m_pCombo.disposeAndClear();
rItem.m_pCheck.disposeAndClear();
}
ModalDialog::dispose();
}
IMPL_LINK_NOARG(FontFeaturesDialog, CheckBoxToggledHdl, CheckBox&, void) { updateFontPreview(); }
IMPL_LINK_NOARG(FontFeaturesDialog, ComboBoxSelectedHdl, ComboBox&, void) { updateFontPreview(); }
OUString FontFeaturesDialog::createFontNameWithFeatures()
{
OUString sResultFontName;
OUString sNameSuffix;
bool bFirst = true;
for (FontFeatureItem& rItem : m_aFeatureItems)
{
if (rItem.m_pCheck)
{
if (rItem.m_pCheck->IsChecked())
{
if (!bFirst)
sNameSuffix += OUString(vcl::font::FeatureSeparator);
else
bFirst = false;
sNameSuffix += vcl::font::featureCodeAsString(rItem.m_aFeatureCode);
}
}
else if (rItem.m_pCombo && rItem.m_pText)
{
sal_uInt32 nSelection = rItem.m_pCombo->GetSelectedEntryPos();
if (nSelection > 0)
{
if (!bFirst)
sNameSuffix += OUString(vcl::font::FeatureSeparator);
else
bFirst = false;
sNameSuffix += vcl::font::featureCodeAsString(rItem.m_aFeatureCode);
sNameSuffix += "=";
sNameSuffix += OUString::number(nSelection);
}
}
}
sResultFontName = vcl::font::trimFontNameFeatures(m_sFontName);
if (!sNameSuffix.isEmpty())
sResultFontName += OUString(vcl::font::FeaturePrefix) + sNameSuffix;
return sResultFontName;
}
short FontFeaturesDialog::Execute()
{
short nResult = ModalDialog::Execute();
if (nResult == RET_OK)
{
m_sResultFontName = createFontNameWithFeatures();
}
return nResult;
}
} // end svx namespace
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
/* -*- 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/.
*
*/
#ifndef INCLUDED_CUI_SOURCE_INC_FONTFEATURESDIALOG_HXX
#define INCLUDED_CUI_SOURCE_INC_FONTFEATURESDIALOG_HXX
#include <vcl/layout.hxx>
#include <vcl/font/Feature.hxx>
#include <svx/fntctrl.hxx>
#include "chardlg.hxx"
#include <memory>
namespace cui
{
struct FontFeatureItem
{
FontFeatureItem()
: m_aFeatureCode(0)
{
}
sal_uInt32 m_aFeatureCode;
VclPtr<Control> m_pText;
VclPtr<ComboBox> m_pCombo;
VclPtr<CheckBox> m_pCheck;
};
class FontFeaturesDialog : public ModalDialog
{
private:
VclPtr<VclGrid> m_pContentGrid;
VclPtr<SvxFontPrevWindow> m_pPreviewWindow;
std::vector<FontFeatureItem> m_aFeatureItems;
OUString m_sFontName;
OUString m_sResultFontName;
void initialize();
OUString createFontNameWithFeatures();
DECL_LINK(ComboBoxSelectedHdl, ComboBox&, void);
DECL_LINK(CheckBoxToggledHdl, CheckBox&, void);
public:
FontFeaturesDialog(vcl::Window* pParent, OUString const& rFontName);
~FontFeaturesDialog() override;
void dispose() override;
short Execute() override;
OUString getResultFontName() { return m_sResultFontName; }
void updateFontPreview();
};
} // end svx namespaces
#endif // INCLUDED_CUI_SOURCE_INC_FONTFEATURESDIALOG_HXX
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -27,6 +27,7 @@
#include <svx/langbox.hxx>
#include <vcl/layout.hxx>
#include <vcl/weld.hxx>
#include <vcl/button.hxx>
#include <memory>
// forward ---------------------------------------------------------------
......@@ -109,6 +110,7 @@ private:
VclPtr<FixedText> m_pWestFontLanguageFT;
VclPtr<SvxLanguageComboBox> m_pWestFontLanguageLB;
VclPtr<FixedText> m_pWestFontTypeFT;
VclPtr<PushButton> m_pWestFontFeaturesButton;
VclPtr<VclContainer> m_pEastFrame;
VclPtr<FixedText> m_pEastFontNameFT;
......@@ -120,6 +122,7 @@ private:
VclPtr<FixedText> m_pEastFontLanguageFT;
VclPtr<SvxLanguageBox> m_pEastFontLanguageLB;
VclPtr<FixedText> m_pEastFontTypeFT;
VclPtr<PushButton> m_pEastFontFeaturesButton;
VclPtr<VclContainer> m_pCTLFrame;
VclPtr<FixedText> m_pCTLFontNameFT;
......@@ -131,6 +134,7 @@ private:
VclPtr<FixedText> m_pCTLFontLanguageFT;
VclPtr<SvxLanguageBox> m_pCTLFontLanguageLB;
VclPtr<FixedText> m_pCTLFontTypeFT;
VclPtr<PushButton> m_pCTLFontFeaturesButton;
std::unique_ptr<SvxCharNamePage_Impl> m_pImpl;
......@@ -164,6 +168,8 @@ private:
DECL_LINK( FontModifyEditHdl_Impl, Edit&, void );
DECL_LINK( FontModifyListBoxHdl_Impl, ListBox&, void );
DECL_LINK( FontModifyComboBoxHdl_Impl, ComboBox&, void );
DECL_LINK(FontFeatureButtonClicked, Button*, void);
void FontModifyHdl_Impl(void const *);
public:
......
......@@ -69,6 +69,7 @@
#include <svl/intitem.hxx>
#include <sfx2/request.hxx>
#include <svx/flagsdef.hxx>
#include <FontFeaturesDialog.hxx>
using namespace ::com::sun::star;
......@@ -302,6 +303,8 @@ SvxCharNamePage::SvxCharNamePage( vcl::Window* pParent, const SfxItemSet& rInSet
get(m_pWestFontLanguageFT, "westlangft-cjk");
get(m_pWestFontLanguageLB, "westlanglb-cjk");
get(m_pWestFontTypeFT, "westfontinfo-cjk");
get(m_pWestFontFeaturesButton, "west_features_button-cjk");
}
else
{
......@@ -328,6 +331,7 @@ SvxCharNamePage::SvxCharNamePage( vcl::Window* pParent, const SfxItemSet& rInSet
get(m_pEastFontLanguageFT, "eastlangft");
get(m_pEastFontLanguageLB, "eastlanglb");
get(m_pEastFontTypeFT, "eastfontinfo");
get(m_pEastFontFeaturesButton, "east_features_button");
get(m_pCTLFrame, "ctl");
get(m_pCTLFontNameFT, "ctlfontnameft");
......@@ -339,6 +343,7 @@ SvxCharNamePage::SvxCharNamePage( vcl::Window* pParent, const SfxItemSet& rInSet
get(m_pCTLFontLanguageFT, "ctllangft");
get(m_pCTLFontLanguageLB, "ctllanglb");
get(m_pCTLFontTypeFT, "ctlfontinfo");
get(m_pCTLFontFeaturesButton, "ctl_features_button");
//In MacOSX the standard dialogs name font-name, font-style as
//Family, Typeface
......@@ -404,6 +409,7 @@ void SvxCharNamePage::dispose()
m_pWestFontSizeLB.clear();
m_pWestFontLanguageFT.clear();
m_pWestFontLanguageLB.clear();
m_pWestFontFeaturesButton.clear();
m_pWestFontTypeFT.clear();
m_pEastFrame.clear();
m_pEastFontNameFT.clear();
......@@ -415,6 +421,7 @@ void SvxCharNamePage::dispose()
m_pEastFontLanguageFT.clear();
m_pEastFontLanguageLB.clear();
m_pEastFontTypeFT.clear();
m_pEastFontFeaturesButton.clear();
m_pCTLFrame.clear();
m_pCTLFontNameFT.clear();
m_pCTLFontNameLB.clear();
......@@ -425,6 +432,8 @@ void SvxCharNamePage::dispose()
m_pCTLFontLanguageFT.clear();
m_pCTLFontLanguageLB.clear();
m_pCTLFontTypeFT.clear();
m_pCTLFontFeaturesButton.clear();
SvxCharBasePage::dispose();
}
......@@ -438,14 +447,20 @@ void SvxCharNamePage::Initialize()
m_pWestFontStyleLB->SetModifyHdl( aLink );
m_pWestFontSizeLB->SetModifyHdl( aLink );
m_pWestFontLanguageLB->SetSelectHdl( LINK( this, SvxCharNamePage, FontModifyComboBoxHdl_Impl ) );
m_pWestFontFeaturesButton->SetClickHdl(LINK(this, SvxCharNamePage, FontFeatureButtonClicked));
m_pEastFontNameLB->SetModifyHdl( aLink );
m_pEastFontStyleLB->SetModifyHdl( aLink );
m_pEastFontSizeLB->SetModifyHdl( aLink );
m_pEastFontLanguageLB->SetSelectHdl( LINK( this, SvxCharNamePage, FontModifyListBoxHdl_Impl ) );
m_pEastFontFeaturesButton->SetClickHdl(LINK(this, SvxCharNamePage, FontFeatureButtonClicked));
m_pCTLFontNameLB->SetModifyHdl( aLink );
m_pCTLFontStyleLB->SetModifyHdl( aLink );
m_pCTLFontSizeLB->SetModifyHdl( aLink );
m_pCTLFontLanguageLB->SetSelectHdl( LINK( this, SvxCharNamePage, FontModifyListBoxHdl_Impl ) );
m_pCTLFontFeaturesButton->SetClickHdl(LINK(this, SvxCharNamePage, FontFeatureButtonClicked));
m_pImpl->m_aUpdateIdle.SetInvokeHandler( LINK( this, SvxCharNamePage, UpdateHdl_Impl ) );
}
......@@ -1185,6 +1200,38 @@ IMPL_LINK( SvxCharNamePage, FontModifyEditHdl_Impl, Edit&, rBox, void )
{
FontModifyHdl_Impl(&rBox);
}
IMPL_LINK(SvxCharNamePage, FontFeatureButtonClicked, Button*, pButton, void )
{
OUString sFontName;
FontNameBox * pNameBox = nullptr;
if (pButton == m_pWestFontFeaturesButton.get())
{
pNameBox = m_pWestFontNameLB;
sFontName = GetPreviewFont().GetFamilyName();
}
else if (pButton == m_pEastFontFeaturesButton.get())
{
pNameBox = m_pEastFontNameLB;
sFontName = GetPreviewCJKFont().GetFamilyName();
}
else if (pButton == m_pCTLFontFeaturesButton.get())
{
pNameBox = m_pCTLFontNameLB;
sFontName = GetPreviewCTLFont().GetFamilyName();
}
if (!sFontName.isEmpty() && pNameBox)
{
ScopedVclPtrInstance<cui::FontFeaturesDialog> pDialog(this, sFontName);
if (pDialog->Execute() == RET_OK)
{
pNameBox->SetText(pDialog->getResultFontName());
UpdatePreview_Impl();
}
}
}
void SvxCharNamePage::FontModifyHdl_Impl(void const * pNameBox)
{
m_pImpl->m_aUpdateIdle.Start();
......
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.22.1 -->
<interface domain="cui">
<requires lib="gtk+" version="3.18"/>
<requires lib="LibreOffice" version="1.0"/>
<object class="GtkDialog" id="FontFeaturesDialog">
<property name="can_focus">False</property>
<property name="border_width">6</property>
<property name="title" translatable="yes" context="newtabledialog|NewTableDialog">Font Features</property>
<property name="modal">True</property>
<property name="default_width">1</property>
<property name="default_height">1</property>
<property name="type_hint">dialog</property>
<child>
<placeholder/>
</child>
<child internal-child="vbox">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">12</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="help">
<property name="label">gtk-help</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
<property name="secondary">True</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ok">
<property name="label">gtk-ok</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
<property name="has_default">True</property>
<property name="receives_default">False</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="cancel">
<property name="label">gtk-cancel</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="use_stock">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkGrid" id="contentGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkAlignment" id="alignment4">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="valign">end</property>
<property name="top_padding">6</property>
<property name="left_padding">12</property>
<property name="right_padding">12</property>
<child>
<object class="svxlo-SvxFontPrevWindow" id="preview:border">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child internal-child="accessible">
<object class="AtkObject" id="preview:border-atkobject">
<property name="AtkObject::accessible-name" translatable="yes" context="fontfeaturesdialog|preview-atkobject">Preview</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack_type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
<action-widgets>
<action-widget response="-11">help</action-widget>
<action-widget response="-5">ok</action-widget>
<action-widget response="-6">cancel</action-widget>
</action-widgets>
</object>
</interface>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment