summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaolán McNamara <caolanm@redhat.com>2020-04-07 12:21:47 +0100
committerCaolán McNamara <caolanm@redhat.com>2020-04-21 10:19:41 +0200
commit2e0a32b51681fb356699b4a722f461f55a46b890 (patch)
treeac96e726d777aba5b6f57513f5b00b3d766e34d3
parent6c559b122add7db32b06faa15854df58b30460f6 (diff)
weld FontNameBox
with custom row rendering Change-Id: Ia909b5b9ad56b6ea4611e9ea0a1e2cb0064a8cd4 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/91841 Tested-by: Jenkins Reviewed-by: Caolán McNamara <caolanm@redhat.com>
-rw-r--r--compilerplugins/clang/badstatics.cxx4
-rw-r--r--cui/source/tabpages/chardlg.cxx2
-rw-r--r--include/svtools/ctrlbox.hxx61
-rw-r--r--include/vcl/combobox.hxx3
-rw-r--r--include/vcl/weld.hxx39
-rw-r--r--sd/source/ui/animations/CustomAnimationList.cxx5
-rw-r--r--svtools/inc/pch/precompiled_svt.hxx6
-rw-r--r--svtools/source/control/ctrlbox.cxx503
-rw-r--r--svx/UIConfig_svx.mk1
-rw-r--r--svx/source/tbxctrls/tbcontrl.cxx296
-rw-r--r--svx/source/tbxctrls/tbunocontroller.cxx8
-rw-r--r--svx/uiconfig/ui/fontnamebox.ui30
-rw-r--r--sw/inc/pch/precompiled_swui.hxx8
-rw-r--r--vcl/source/app/salvtables.cxx120
-rw-r--r--vcl/source/control/combobox.cxx12
-rw-r--r--vcl/source/control/imp_listbox.cxx5
-rw-r--r--vcl/unx/gtk3/gtk3gtkinst.cxx718
17 files changed, 1271 insertions, 550 deletions
diff --git a/compilerplugins/clang/badstatics.cxx b/compilerplugins/clang/badstatics.cxx
index 60abc11c222b..e2a48f3462cc 100644
--- a/compilerplugins/clang/badstatics.cxx
+++ b/compilerplugins/clang/badstatics.cxx
@@ -197,7 +197,9 @@ public:
// sc/source/core/tool/adiasync.cxx, would leak
// ScAddInAsync* keys if that set is not empty at exit
|| name == "g_aWindowList"
- //vcl/unx/gtk/a11y/atkutil.cxx, asserted empty at exit
+ //vcl/unx/gtk3/a11y/gtk3atkutil.cxx, asserted empty at exit
+ || name == "gFontPreviewVirDevs"
+ //svtools/source/control/ctrlbox.cxx, empty at exit
|| name == "aLogger" // FormulaLogger& FormulaLogger::get() in sc/source/core/tool/formulalogger.cxx
|| name == "m_aUncommittedRegistrations" // sw/source/uibase/dbui/dbmgr.cxx
|| (loplugin::DeclCheck(pVarDecl).Var("aAllListeners")
diff --git a/cui/source/tabpages/chardlg.cxx b/cui/source/tabpages/chardlg.cxx
index 68eca4fb4d48..11aaf87aa0fc 100644
--- a/cui/source/tabpages/chardlg.cxx
+++ b/cui/source/tabpages/chardlg.cxx
@@ -766,7 +766,7 @@ void SvxCharNamePage::Reset_Impl( const SfxItemSet& rSet, LanguageGroup eLangGrp
}
else
{
- pSizeBox->set_entry_text( OUString() );
+ pSizeBox->set_active_or_entry_text(OUString());
if ( eState <= SfxItemState::READONLY )
{
pSizeBox->set_sensitive(false);
diff --git a/include/svtools/ctrlbox.hxx b/include/svtools/ctrlbox.hxx
index a86722a7a603..3dd48f9dd985 100644
--- a/include/svtools/ctrlbox.hxx
+++ b/include/svtools/ctrlbox.hxx
@@ -21,10 +21,8 @@
#define INCLUDED_SVTOOLS_CTRLBOX_HXX
#include <svtools/svtdllapi.h>
-
#include <editeng/borderline.hxx>
-
-#include <vcl/combobox.hxx>
+#include <vcl/idle.hxx>
#include <vcl/metric.hxx>
#include <vcl/weld.hxx>
@@ -33,6 +31,7 @@
namespace weld { class CustomWeld; }
class VirtualDevice;
+class BitmapEx;
class BorderWidthImpl;
class FontList;
@@ -327,30 +326,66 @@ private:
void set_label_from_date();
};
-class SVT_DLLPUBLIC FontNameBox : public ComboBox
+class SVT_DLLPUBLIC FontNameBox
{
private:
+ std::unique_ptr<weld::ComboBox> m_xComboBox;
std::unique_ptr<ImplFontList> mpFontList;
+ size_t mnPreviewProgress;
bool mbWYSIWYG;
OUString maFontMRUEntriesFile;
+ Idle maUpdateIdle;
SVT_DLLPRIVATE void ImplCalcUserItemSize();
SVT_DLLPRIVATE void ImplDestroyFontList();
-protected:
+ DECL_LINK(CustomRenderHdl, weld::ComboBox::render_args, void);
+ DECL_STATIC_LINK(FontNameBox, CustomGetSizeHdl, weld::ComboBox::get_size_args, Size);
+ DECL_LINK(UpdateHdl, Timer*, void);
+
void LoadMRUEntries( const OUString& aFontMRUEntriesFile );
void SaveMRUEntries( const OUString& aFontMRUEntriesFile ) const;
-public:
- FontNameBox( vcl::Window* pParent,
- WinBits nWinStyle );
- virtual ~FontNameBox() override;
- virtual void dispose() override;
- virtual void UserDraw( const UserDrawEvent& rUDEvt ) override;
+ OutputDevice& CachePreview(size_t nIndex, Point* pTopLeft);
+
+public:
+ FontNameBox(std::unique_ptr<weld::ComboBox> p);
+ ~FontNameBox();
void Fill( const FontList* pList );
- void EnableWYSIWYG( bool bEnable );
+ void EnableWYSIWYG();
+
+ void connect_changed(const Link<weld::ComboBox&, void>& rLink) { m_xComboBox->connect_changed(rLink); }
+ void connect_focus_in(const Link<weld::Widget&, void>& rLink) { m_xComboBox->connect_focus_in(rLink); }
+ void connect_focus_out(const Link<weld::Widget&, void>& rLink) { m_xComboBox->connect_focus_out(rLink); }
+ void connect_key_press(const Link<const KeyEvent&, bool>& rLink) { m_xComboBox->connect_key_press(rLink); }
+ int get_active() const { return m_xComboBox->get_active(); }
+ OUString get_active_text() const { return m_xComboBox->get_active_text(); }
+ void set_active_or_entry_text(const OUString& rText);
+ int get_count() const { return m_xComboBox->get_count(); }
+ OUString get_text(int nIndex) const { return m_xComboBox->get_text(nIndex); }
+ void set_sensitive(bool bSensitive) { m_xComboBox->set_sensitive(bSensitive); }
+ void save_value() { m_xComboBox->save_value(); }
+ OUString const& get_saved_value() const { return m_xComboBox->get_saved_value(); }
+ void select_entry_region(int nStartPos, int nEndPos) { m_xComboBox->select_entry_region(nStartPos, nEndPos); }
+ bool get_entry_selection_bounds(int& rStartPos, int& rEndPos) { return m_xComboBox->get_entry_selection_bounds(rStartPos, rEndPos); }
+ void clear() { m_xComboBox->clear(); }
+ void grab_focus() { m_xComboBox->grab_focus(); }
+ bool has_focus() const { return m_xComboBox->has_focus(); }
+ void connect_entry_activate(const Link<weld::ComboBox&, bool>& rLink) { m_xComboBox->connect_entry_activate(rLink); }
+ void connect_get_property_tree(const Link<boost::property_tree::ptree&, void>& rLink) { m_xComboBox->connect_get_property_tree(rLink); }
+ void set_entry_width_chars(int nWidth) { m_xComboBox->set_entry_width_chars(nWidth); }
+ void set_size_request(int nWidth, int nHeight) { m_xComboBox->set_size_request(nWidth, nHeight); }
+ int get_max_mru_count() { return m_xComboBox->get_max_mru_count(); }
+ void set_max_mru_count(int nCount) { m_xComboBox->set_max_mru_count(nCount); }
+
+ // font size is in points, not pixels, e.g. see Window::[G]etPointFont
+ vcl::Font get_font() { return m_xComboBox->get_font(); }
+ void set_entry_font(const vcl::Font& rFont) { m_xComboBox->set_entry_font(rFont); }
+ vcl::Font get_entry_font() { return m_xComboBox->get_entry_font(); }
+
+ void set_tooltip_text(const OUString& rTip) { m_xComboBox->set_tooltip_text(rTip); }
private:
void InitFontMRUEntriesFile();
@@ -438,7 +473,7 @@ public:
void connect_focus_out(const Link<weld::Widget&, void>& rLink) { m_aFocusOutHdl = rLink; }
void connect_key_press(const Link<const KeyEvent&, bool>& rLink) { m_xComboBox->connect_key_press(rLink); }
OUString get_active_text() const { return m_xComboBox->get_active_text(); }
- void set_entry_text(const OUString& rText);
+ void set_active_or_entry_text(const OUString& rText);
void set_sensitive(bool bSensitive) { m_xComboBox->set_sensitive(bSensitive); }
int get_active() const { return m_xComboBox->get_active(); }
int get_value() const;
diff --git a/include/vcl/combobox.hxx b/include/vcl/combobox.hxx
index 562072baa9ef..ef04fff46330 100644
--- a/include/vcl/combobox.hxx
+++ b/include/vcl/combobox.hxx
@@ -120,6 +120,7 @@ public:
void SetDoubleClickHdl(const Link<ComboBox&,void>& rLink);
const Link<ComboBox&,void>& GetDoubleClickHdl() const;
void SetEntryActivateHdl(const Link<Edit&,bool>& rLink);
+ void SetUserDrawHdl(const Link<UserDrawEvent*, void>& rLink);
Size CalcMinimumSize() const override;
virtual Size GetOptimalSize() const override;
@@ -183,6 +184,8 @@ public:
void SetWidthInChars(sal_Int32 nWidthInChars);
+ long GetDropDownEntryHeight() const;
+
virtual bool set_property(const OString &rKey, const OUString &rValue) override;
virtual FactoryFunction GetUITestFactory() const override;
diff --git a/include/vcl/weld.hxx b/include/vcl/weld.hxx
index 951b591f654b..2d94323d6434 100644
--- a/include/vcl/weld.hxx
+++ b/include/vcl/weld.hxx
@@ -591,6 +591,12 @@ class VCL_DLLPUBLIC ComboBox : virtual public Container
private:
OUString m_sSavedValue;
+public:
+ // OUString is the id of the row, it may be null to measure the height of a generic line
+ typedef std::pair<vcl::RenderContext&, const OUString&> get_size_args;
+ typedef std::tuple<vcl::RenderContext&, const tools::Rectangle&, bool, const OUString&>
+ render_args;
+
protected:
Link<ComboBox&, void> m_aChangeHdl;
Link<ComboBox&, void> m_aPopupToggledHdl;
@@ -600,6 +606,21 @@ protected:
void signal_changed() { m_aChangeHdl.Call(*this); }
virtual void signal_popup_toggled() { m_aPopupToggledHdl.Call(*this); }
+ Link<render_args, void> m_aRenderHdl;
+ void signal_custom_render(vcl::RenderContext& rDevice, const tools::Rectangle& rRect,
+ bool bSelected, const OUString& rId)
+ {
+ m_aRenderHdl.Call(
+ std::tuple<vcl::RenderContext&, const tools::Rectangle, bool, const OUString&>(
+ rDevice, rRect, bSelected, rId));
+ }
+
+ Link<get_size_args, Size> m_aGetSizeHdl;
+ Size signal_custom_get_size(vcl::RenderContext& rDevice, const OUString& rId)
+ {
+ return m_aGetSizeHdl.Call(std::pair<vcl::RenderContext&, const OUString&>(rDevice, rId));
+ }
+
public:
virtual void insert(int pos, const OUString& rStr, const OUString* pId,
const OUString* pIconName, VirtualDevice* pImageSurface)
@@ -694,6 +715,20 @@ public:
void save_value() { m_sSavedValue = get_active_text(); }
OUString const& get_saved_value() const { return m_sSavedValue; }
bool get_value_changed_from_saved() const { return m_sSavedValue != get_active_text(); }
+
+ // for custom rendering a row
+ void connect_custom_get_size(const Link<get_size_args, Size>& rLink) { m_aGetSizeHdl = rLink; }
+ void connect_custom_render(const Link<render_args, void>& rLink) { m_aRenderHdl = rLink; }
+ // call set_custom_renderer after setting custom callbacks
+ virtual void set_custom_renderer() = 0;
+ // create a virtual device compatible with the device passed in render_args wrt alpha
+ virtual VclPtr<VirtualDevice> create_render_virtual_device() const = 0;
+
+ // for mru support
+ virtual int get_max_mru_count() const = 0;
+ virtual void set_max_mru_count(int nCount) = 0;
+ virtual OUString get_mru_entries() const = 0;
+ virtual void set_mru_entries(const OUString& rEntries) = 0;
};
class VCL_DLLPUBLIC TreeIter
@@ -734,6 +769,7 @@ protected:
std::function<int(const weld::TreeIter&, const weld::TreeIter&)> m_aCustomSort;
public:
+ // OUString is the id of the row, it may be null to measure the height of a generic line
typedef std::pair<vcl::RenderContext&, const OUString&> get_size_args;
typedef std::tuple<vcl::RenderContext&, const tools::Rectangle&, bool, const OUString&>
render_args;
@@ -1094,9 +1130,10 @@ public:
bool get_value_changed_from_saved() const { return m_sSavedValue != get_selected_text(); }
// for custom rendering a cell
- virtual void set_column_custom_renderer(int nColumn) = 0;
void connect_custom_get_size(const Link<get_size_args, Size>& rLink) { m_aGetSizeHdl = rLink; }
void connect_custom_render(const Link<render_args, void>& rLink) { m_aRenderHdl = rLink; }
+ // call set_column_custom_renderer after setting custom callbacks
+ virtual void set_column_custom_renderer(int nColumn) = 0;
// for dnd
virtual bool get_dest_row_at_pos(const Point& rPos, weld::TreeIter* pResult) = 0;
diff --git a/sd/source/ui/animations/CustomAnimationList.cxx b/sd/source/ui/animations/CustomAnimationList.cxx
index 68ecf1362ce9..3b4c3b3afaa6 100644
--- a/sd/source/ui/animations/CustomAnimationList.cxx
+++ b/sd/source/ui/animations/CustomAnimationList.cxx
@@ -230,6 +230,7 @@ private:
OUString msEffectName;
CustomAnimationEffectPtr mpEffect;
+public:
static const long nIconWidth = 19;
static const long nItemMinHeight = 38;
};
@@ -275,6 +276,8 @@ IMPL_STATIC_LINK(CustomAnimationList, CustomGetSizeHdl, weld::TreeView::get_size
const OUString& rId = aPayload.second;
CustomAnimationListEntryItem* pItem = reinterpret_cast<CustomAnimationListEntryItem*>(rId.toInt64());
+ if (!pItem)
+ return Size(CustomAnimationListEntryItem::nIconWidth, CustomAnimationListEntryItem::nItemMinHeight);
return pItem->GetSize(rRenderContext);
}
@@ -426,7 +429,6 @@ CustomAnimationList::CustomAnimationList(std::unique_ptr<weld::TreeView> xTreeVi
mxEmptyLabel->set_stack_background();
mxTreeView->set_selection_mode(SelectionMode::Multiple);
- mxTreeView->set_column_custom_renderer(0);
mxTreeView->connect_changed(LINK(this, CustomAnimationList, SelectHdl));
mxTreeView->connect_key_press(LINK(this, CustomAnimationList, KeyInputHdl));
mxTreeView->connect_popup_menu(LINK(this, CustomAnimationList, CommandHdl));
@@ -436,6 +438,7 @@ CustomAnimationList::CustomAnimationList(std::unique_ptr<weld::TreeView> xTreeVi
mxTreeView->connect_drag_begin(LINK(this, CustomAnimationList, DragBeginHdl));
mxTreeView->connect_custom_get_size(LINK(this, CustomAnimationList, CustomGetSizeHdl));
mxTreeView->connect_custom_render(LINK(this, CustomAnimationList, CustomRenderHdl));
+ mxTreeView->set_column_custom_renderer(0);
}
CustomAnimationListDropTarget::CustomAnimationListDropTarget(CustomAnimationList& rTreeView)
diff --git a/svtools/inc/pch/precompiled_svt.hxx b/svtools/inc/pch/precompiled_svt.hxx
index 2797de08da3a..40cfe76421db 100644
--- a/svtools/inc/pch/precompiled_svt.hxx
+++ b/svtools/inc/pch/precompiled_svt.hxx
@@ -13,7 +13,7 @@
manual changes will be rewritten by the next run of update_pch.sh (which presumably
also fixes all possible problems, so it's usually better to use it).
- Generated on 2020-02-19 12:45:36 using:
+ Generated on 2020-04-07 17:26:37 using:
./bin/update_pch svtools svt --cutoff=4 --exclude:system --include:module --exclude:local
If after updating build fails, use the following command to locate conflicting headers:
@@ -37,6 +37,7 @@
#include <math.h>
#include <memory>
#include <new>
+#include <optional>
#include <ostream>
#include <set>
#include <stddef.h>
@@ -102,7 +103,6 @@
#include <vcl/builder.hxx>
#include <vcl/button.hxx>
#include <vcl/checksum.hxx>
-#include <vcl/combobox.hxx>
#include <vcl/commandevent.hxx>
#include <vcl/ctrl.hxx>
#include <vcl/dllapi.h>
@@ -162,6 +162,7 @@
#include <basegfx/tuple/b2dtuple.hxx>
#include <basegfx/tuple/b2ituple.hxx>
#include <basegfx/tuple/b3dtuple.hxx>
+#include <basegfx/utils/common.hxx>
#include <basegfx/vector/b2dsize.hxx>
#include <basegfx/vector/b2dvector.hxx>
#include <basegfx/vector/b2enums.hxx>
@@ -314,7 +315,6 @@
#include <i18nutil/transliteration.hxx>
#include <o3tl/cow_wrapper.hxx>
#include <o3tl/deleter.hxx>
-#include <optional>
#include <o3tl/safeint.hxx>
#include <o3tl/strong_int.hxx>
#include <o3tl/typed_flags_set.hxx>
diff --git a/svtools/source/control/ctrlbox.cxx b/svtools/source/control/ctrlbox.cxx
index 51895051551f..d1b9943dfd2c 100644
--- a/svtools/source/control/ctrlbox.cxx
+++ b/svtools/source/control/ctrlbox.cxx
@@ -61,7 +61,6 @@
#define IMGOUTERTEXTSPACE 5
#define EXTRAFONTSIZE 5
#define GAPTOEXTRAPREVIEW 10
-#define MAXPREVIEWWIDTH 120
#define MINGAPWIDTH 2
#define FONTNAMEBOXMRUENTRIESFILE "/user/config/fontnameboxmruentries"
@@ -329,31 +328,43 @@ void DrawLine( OutputDevice& rDev, const basegfx::B2DPoint& rP1, const basegfx::
}
-FontNameBox::FontNameBox( vcl::Window* pParent, WinBits nWinStyle ) :
- ComboBox( pParent, nWinStyle )
+static Size gUserItemSz;
+static int gFontNameBoxes;
+static size_t gPreviewsPerDevice;
+static std::vector<VclPtr<VirtualDevice>> gFontPreviewVirDevs;
+static std::vector<OUString> gRenderedFontNames;
+
+FontNameBox::FontNameBox(std::unique_ptr<weld::ComboBox> p)
+ : m_xComboBox(std::move(p))
+ , mnPreviewProgress(0)
+ , mbWYSIWYG(false)
+ , maUpdateIdle("FontNameBox Preview Update")
{
- mbWYSIWYG = false;
+ ++gFontNameBoxes;
InitFontMRUEntriesFile();
-}
-FontNameBox::~FontNameBox()
-{
- disposeOnce();
+ maUpdateIdle.SetPriority(TaskPriority::LOWEST);
+ maUpdateIdle.SetInvokeHandler(LINK(this, FontNameBox, UpdateHdl));
}
-void FontNameBox::dispose()
+FontNameBox::~FontNameBox()
{
if (mpFontList)
{
SaveMRUEntries (maFontMRUEntriesFile);
ImplDestroyFontList();
}
- ComboBox::dispose();
+ --gFontNameBoxes;
+ if (!gFontNameBoxes)
+ {
+ gFontPreviewVirDevs.clear();
+ gRenderedFontNames.clear();
+ }
}
-void FontNameBox::SaveMRUEntries( const OUString& aFontMRUEntriesFile ) const
+void FontNameBox::SaveMRUEntries(const OUString& aFontMRUEntriesFile) const
{
- OString aEntries(OUStringToOString(GetMRUEntries(),
+ OString aEntries(OUStringToOString(m_xComboBox->get_mru_entries(),
RTL_TEXTENCODING_UTF8));
if (aEntries.isEmpty() || aFontMRUEntriesFile.isEmpty())
@@ -392,7 +403,7 @@ void FontNameBox::LoadMRUEntries( const OUString& aFontMRUEntriesFile )
aStream.ReadLine( aLine );
OUString aEntries = OStringToOUString(aLine,
RTL_TEXTENCODING_UTF8);
- SetMRUEntries( aEntries );
+ m_xComboBox->set_mru_entries(aEntries);
}
void FontNameBox::InitFontMRUEntriesFile()
@@ -415,61 +426,71 @@ void FontNameBox::ImplDestroyFontList()
void FontNameBox::Fill( const FontList* pList )
{
// store old text and clear box
- OUString aOldText = GetText();
- OUString rEntries = GetMRUEntries();
+ OUString aOldText = m_xComboBox->get_active_text();
+ OUString rEntries = m_xComboBox->get_mru_entries();
bool bLoadFromFile = rEntries.isEmpty();
- Clear();
+ m_xComboBox->freeze();
+ m_xComboBox->clear();
ImplDestroyFontList();
mpFontList.reset(new ImplFontList);
// insert fonts
- sal_uInt16 nFontCount = pList->GetFontNameCount();
- for ( sal_uInt16 i = 0; i < nFontCount; i++ )
+ size_t nFontCount = pList->GetFontNameCount();
+ for (size_t i = 0; i < nFontCount; ++i)
{
- const FontMetric& rFontMetric = pList->GetFontName( i );
- sal_Int32 nIndex = InsertEntry( rFontMetric.GetFamilyName() );
- if ( nIndex < static_cast<sal_Int32>(mpFontList->size()) ) {
- ImplFontList::iterator it = mpFontList->begin();
- ::std::advance( it, nIndex );
- mpFontList->insert( it, rFontMetric );
- } else {
- mpFontList->push_back( rFontMetric );
- }
+ const FontMetric& rFontMetric = pList->GetFontName(i);
+ m_xComboBox->append(OUString::number(i), rFontMetric.GetFamilyName());
+ mpFontList->push_back(rFontMetric);
}
- if ( bLoadFromFile )
- LoadMRUEntries (maFontMRUEntriesFile);
+ if (bLoadFromFile)
+ LoadMRUEntries(maFontMRUEntriesFile);
else
- SetMRUEntries( rEntries );
+ m_xComboBox->set_mru_entries(rEntries);
- ImplCalcUserItemSize();
+ m_xComboBox->thaw();
+
+ if (mbWYSIWYG)
+ {
+ mnPreviewProgress = 0;
+ maUpdateIdle.Start();
+ }
// restore text
if (!aOldText.isEmpty())
- SetText( aOldText );
+ set_active_or_entry_text(aOldText);
}
-void FontNameBox::EnableWYSIWYG( bool bEnable )
+void FontNameBox::EnableWYSIWYG()
{
- if ( bEnable != mbWYSIWYG )
+ if (mbWYSIWYG)
+ return;
+ mbWYSIWYG = true;
+
+ static bool bGlobalsInited;
+ if (!bGlobalsInited)
{
- mbWYSIWYG = bEnable;
- EnableUserDraw( mbWYSIWYG );
- ImplCalcUserItemSize();
+ gUserItemSz = Size(m_xComboBox->get_approximate_digit_width() * 52, m_xComboBox->get_text_height());
+ gUserItemSz.setHeight(gUserItemSz.Height() * 16);
+ gUserItemSz.setHeight(gUserItemSz.Height() / 10);
+
+ size_t nMaxDeviceHeight = SAL_MAX_INT16 / 2; // see limitXCreatePixmap
+ gPreviewsPerDevice = nMaxDeviceHeight / gUserItemSz.Height();
+
+ bGlobalsInited = true;
}
+
+ m_xComboBox->connect_custom_get_size(LINK(this, FontNameBox, CustomGetSizeHdl));
+ m_xComboBox->connect_custom_render(LINK(this, FontNameBox, CustomRenderHdl));
+ m_xComboBox->set_custom_renderer();
+
+ mbWYSIWYG = true;
}
-void FontNameBox::ImplCalcUserItemSize()
+IMPL_STATIC_LINK_NOARG(FontNameBox, CustomGetSizeHdl, weld::ComboBox::get_size_args, Size)
{
- Size aUserItemSz;
- if ( mbWYSIWYG && mpFontList )
- {
- aUserItemSz = Size(MAXPREVIEWWIDTH, GetTextHeight() );
- aUserItemSz.setHeight( aUserItemSz.Height() * 16 );
- aUserItemSz.setHeight( aUserItemSz.Height() / 10 );
- }
- SetUserItemSize( aUserItemSz );
+ return gUserItemSz;
}
namespace
@@ -500,192 +521,275 @@ namespace
}
}
-void FontNameBox::UserDraw( const UserDrawEvent& rUDEvt )
+IMPL_LINK_NOARG(FontNameBox, UpdateHdl, Timer*, void)
{
- assert( mpFontList );
+ CachePreview(mnPreviewProgress++, nullptr);
+ if (mnPreviewProgress < mpFontList->size())
+ maUpdateIdle.Start();
+}
- FontMetric& rFontMetric = (*mpFontList)[ rUDEvt.GetItemId() ];
- Point aTopLeft = rUDEvt.GetRect().TopLeft();
- long nX = aTopLeft.X();
- long nH = rUDEvt.GetRect().GetHeight();
+static void DrawPreview(const FontMetric& rFontMetric, const Point& rTopLeft, OutputDevice& rDevice, bool bSelected)
+{
+ rDevice.Push(PushFlags::TEXTCOLOR);
- if ( mbWYSIWYG )
- {
- nX += IMGOUTERTEXTSPACE;
+ const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
+ if (bSelected)
+ rDevice.SetTextColor(rStyleSettings.GetHighlightTextColor());
+ else
+ rDevice.SetTextColor(rStyleSettings.GetDialogTextColor());
- const bool bSymbolFont = isSymbolFont(rFontMetric);
- vcl::RenderContext* pRenderContext = rUDEvt.GetRenderContext();
+ long nX = rTopLeft.X();
+ long nH = gUserItemSz.Height();
- Color aTextColor = pRenderContext->GetTextColor();
- vcl::Font aOldFont(pRenderContext->GetFont());
- Size aSize( aOldFont.GetFontSize() );
- aSize.AdjustHeight(EXTRAFONTSIZE );
- vcl::Font aFont( rFontMetric );
- aFont.SetFontSize( aSize );
- pRenderContext->SetFont(aFont);
- pRenderContext->SetTextColor(aTextColor);
+ nX += IMGOUTERTEXTSPACE;
- bool bUsingCorrectFont = true;
- tools::Rectangle aTextRect;
+ const bool bSymbolFont = isSymbolFont(rFontMetric);
- // Preview the font name
- const OUString& sFontName = rFontMetric.GetFamilyName();
+ vcl::Font aOldFont(rDevice.GetFont());
+ Size aSize( aOldFont.GetFontSize() );
+ aSize.AdjustHeight(EXTRAFONTSIZE );
+ vcl::Font aFont( rFontMetric );
+ aFont.SetFontSize( aSize );
+ rDevice.SetFont(aFont);
- //If it shouldn't or can't draw its own name because it doesn't have the glyphs
- if (!canRenderNameOfSelectedFont(*pRenderContext))
- bUsingCorrectFont = false;
- else
- {
- //Make sure it fits in the available height, shrinking the font if necessary
- bUsingCorrectFont = shrinkFontToFit(sFontName, nH, aFont, *pRenderContext, aTextRect) != 0;
- }
+ bool bUsingCorrectFont = true;
+ tools::Rectangle aTextRect;
- if (!bUsingCorrectFont)
- {
- pRenderContext->SetFont(aOldFont);
- pRenderContext->GetTextBoundRect(aTextRect, sFontName);
- }
+ // Preview the font name
+ const OUString& sFontName = rFontMetric.GetFamilyName();
- long nTextHeight = aTextRect.GetHeight();
- long nDesiredGap = (nH-nTextHeight)/2;
- long nVertAdjust = nDesiredGap - aTextRect.Top();
- Point aPos( nX, aTopLeft.Y() + nVertAdjust );
- pRenderContext->DrawText(aPos, sFontName);
- long nTextX = aPos.X() + aTextRect.GetWidth() + GAPTOEXTRAPREVIEW;
+ //If it shouldn't or can't draw its own name because it doesn't have the glyphs
+ if (!canRenderNameOfSelectedFont(rDevice))
+ bUsingCorrectFont = false;
+ else
+ {
+ //Make sure it fits in the available height, shrinking the font if necessary
+ bUsingCorrectFont = shrinkFontToFit(sFontName, nH, aFont, rDevice, aTextRect) != 0;
+ }
- if (!bUsingCorrectFont)
- pRenderContext->SetFont(aFont);
+ if (!bUsingCorrectFont)
+ {
+ rDevice.SetFont(aOldFont);
+ rDevice.GetTextBoundRect(aTextRect, sFontName);
+ }
- OUString sSampleText;
+ long nTextHeight = aTextRect.GetHeight();
+ long nDesiredGap = (nH-nTextHeight)/2;
+ long nVertAdjust = nDesiredGap - aTextRect.Top();
+ Point aPos( nX, rTopLeft.Y() + nVertAdjust );
+ rDevice.DrawText(aPos, sFontName);
+ long nTextX = aPos.X() + aTextRect.GetWidth() + GAPTOEXTRAPREVIEW;
- if (!bSymbolFont)
- {
- const bool bNameBeginsWithLatinText = rFontMetric.GetFamilyName()[0] <= 'z';
+ if (!bUsingCorrectFont)
+ rDevice.SetFont(aFont);
- if (bNameBeginsWithLatinText || !bUsingCorrectFont)
- sSampleText = makeShortRepresentativeTextForSelectedFont(*pRenderContext);
- }
+ OUString sSampleText;
+
+ if (!bSymbolFont)
+ {
+ const bool bNameBeginsWithLatinText = rFontMetric.GetFamilyName()[0] <= 'z';
- //If we're not a symbol font, but could neither render our own name and
- //we can't determine what script it would like to render, then try a
- //few well known scripts
- if (sSampleText.isEmpty() && !bUsingCorrectFont)
+ if (bNameBeginsWithLatinText || !bUsingCorrectFont)
+ sSampleText = makeShortRepresentativeTextForSelectedFont(rDevice);
+ }
+
+ //If we're not a symbol font, but could neither render our own name and
+ //we can't determine what script it would like to render, then try a
+ //few well known scripts
+ if (sSampleText.isEmpty() && !bUsingCorrectFont)
+ {
+ static const UScriptCode aScripts[] =
{
- static const UScriptCode aScripts[] =
- {
- USCRIPT_ARABIC,
- USCRIPT_HEBREW,
-
- USCRIPT_BENGALI,
- USCRIPT_GURMUKHI,
- USCRIPT_GUJARATI,
- USCRIPT_ORIYA,
- USCRIPT_TAMIL,
- USCRIPT_TELUGU,
- USCRIPT_KANNADA,
- USCRIPT_MALAYALAM,
- USCRIPT_SINHALA,
- USCRIPT_DEVANAGARI,
-
- USCRIPT_THAI,
- USCRIPT_LAO,
- USCRIPT_GEORGIAN,
- USCRIPT_TIBETAN,
- USCRIPT_SYRIAC,
- USCRIPT_MYANMAR,
- USCRIPT_ETHIOPIC,
- USCRIPT_KHMER,
- USCRIPT_MONGOLIAN,
-
- USCRIPT_KOREAN,
- USCRIPT_JAPANESE,
- USCRIPT_HAN,
- USCRIPT_SIMPLIFIED_HAN,
- USCRIPT_TRADITIONAL_HAN,
-
- USCRIPT_GREEK
- };
-
- for (const UScriptCode& rScript : aScripts)
+ USCRIPT_ARABIC,
+ USCRIPT_HEBREW,
+
+ USCRIPT_BENGALI,
+ USCRIPT_GURMUKHI,
+ USCRIPT_GUJARATI,
+ USCRIPT_ORIYA,
+ USCRIPT_TAMIL,
+ USCRIPT_TELUGU,
+ USCRIPT_KANNADA,
+ USCRIPT_MALAYALAM,
+ USCRIPT_SINHALA,
+ USCRIPT_DEVANAGARI,
+
+ USCRIPT_THAI,
+ USCRIPT_LAO,
+ USCRIPT_GEORGIAN,
+ USCRIPT_TIBETAN,
+ USCRIPT_SYRIAC,
+ USCRIPT_MYANMAR,
+ USCRIPT_ETHIOPIC,
+ USCRIPT_KHMER,
+ USCRIPT_MONGOLIAN,
+
+ USCRIPT_KOREAN,
+ USCRIPT_JAPANESE,
+ USCRIPT_HAN,
+ USCRIPT_SIMPLIFIED_HAN,
+ USCRIPT_TRADITIONAL_HAN,
+
+ USCRIPT_GREEK
+ };
+
+ for (const UScriptCode& rScript : aScripts)
+ {
+ OUString sText = makeShortRepresentativeTextForScript(rScript);
+ if (!sText.isEmpty())
{
- OUString sText = makeShortRepresentativeTextForScript(rScript);
- if (!sText.isEmpty())
+ bool bHasSampleTextGlyphs = (-1 == rDevice.HasGlyphs(aFont, sText));
+ if (bHasSampleTextGlyphs)
{
- bool bHasSampleTextGlyphs = (-1 == pRenderContext->HasGlyphs(aFont, sText));
- if (bHasSampleTextGlyphs)
- {
- sSampleText = sText;
- break;
- }
+ sSampleText = sText;
+ break;
}
}
+ }
- static const UScriptCode aMinimalScripts[] =
- {
- USCRIPT_HEBREW, //e.g. biblical hebrew
- USCRIPT_GREEK
- };
+ static const UScriptCode aMinimalScripts[] =
+ {
+ USCRIPT_HEBREW, //e.g. biblical hebrew
+ USCRIPT_GREEK
+ };
- for (const UScriptCode& rMinimalScript : aMinimalScripts)
+ for (const UScriptCode& rMinimalScript : aMinimalScripts)
+ {
+ OUString sText = makeShortMinimalTextForScript(rMinimalScript);
+ if (!sText.isEmpty())
{
- OUString sText = makeShortMinimalTextForScript(rMinimalScript);
- if (!sText.isEmpty())
+ bool bHasSampleTextGlyphs = (-1 == rDevice.HasGlyphs(aFont, sText));
+ if (bHasSampleTextGlyphs)
{
- bool bHasSampleTextGlyphs = (-1 == pRenderContext->HasGlyphs(aFont, sText));
- if (bHasSampleTextGlyphs)
- {
- sSampleText = sText;
- break;
- }
+ sSampleText = sText;
+ break;
}
}
}
+ }
- //If we're a symbol font, or for some reason the font still couldn't
- //render something representative of what it would like to render then
- //make up some semi-random text that it *can* display
- if (bSymbolFont || (!bUsingCorrectFont && sSampleText.isEmpty()))
- sSampleText = makeShortRepresentativeSymbolTextForSelectedFont(*pRenderContext);
+ //If we're a symbol font, or for some reason the font still couldn't
+ //render something representative of what it would like to render then
+ //make up some semi-random text that it *can* display
+ if (bSymbolFont || (!bUsingCorrectFont && sSampleText.isEmpty()))
+ sSampleText = makeShortRepresentativeSymbolTextForSelectedFont(rDevice);
- if (!sSampleText.isEmpty())
- {
- const Size &rItemSize = rUDEvt.GetWindow()->GetOutputSize();
+ if (!sSampleText.isEmpty())
+ {
+ const Size &rItemSize = gUserItemSz;
- //leave a little border at the edge
- long nSpace = rItemSize.Width() - nTextX - IMGOUTERTEXTSPACE;
- if (nSpace >= 0)
+ //leave a little border at the edge
+ long nSpace = rItemSize.Width() - nTextX - IMGOUTERTEXTSPACE;
+ if (nSpace >= 0)
+ {
+ //Make sure it fits in the available height, and get how wide that would be
+ long nWidth = shrinkFontToFit(sSampleText, nH, aFont, rDevice, aTextRect);
+ //Chop letters off until it fits in the available width
+ while (nWidth > nSpace || nWidth > gUserItemSz.Width())
{
- //Make sure it fits in the available height, and get how wide that would be
- long nWidth = shrinkFontToFit(sSampleText, nH, aFont, *pRenderContext, aTextRect);
- //Chop letters off until it fits in the available width
- while (nWidth > nSpace || nWidth > MAXPREVIEWWIDTH)
- {
- sSampleText = sSampleText.copy(0, sSampleText.getLength()-1);
- nWidth = pRenderContext->GetTextBoundRect(aTextRect, sSampleText) ?
- aTextRect.GetWidth() : 0;
- }
+ sSampleText = sSampleText.copy(0, sSampleText.getLength()-1);
+ nWidth = rDevice.GetTextBoundRect(aTextRect, sSampleText) ?
+ aTextRect.GetWidth() : 0;
+ }
- //center the text on the line
- if (!sSampleText.isEmpty() && nWidth)
- {
- nTextHeight = aTextRect.GetHeight();
- nDesiredGap = (nH-nTextHeight)/2;
- nVertAdjust = nDesiredGap - aTextRect.Top();
- aPos = Point(nTextX + nSpace - nWidth, aTopLeft.Y() + nVertAdjust);
- pRenderContext->DrawText(aPos, sSampleText);
- }
+ //center the text on the line
+ if (!sSampleText.isEmpty() && nWidth)
+ {
+ nTextHeight = aTextRect.GetHeight();
+ nDesiredGap = (nH-nTextHeight)/2;
+ nVertAdjust = nDesiredGap - aTextRect.Top();
+ aPos = Point(nTextX + nSpace - nWidth, rTopLeft.Y() + nVertAdjust);
+ rDevice.DrawText(aPos, sSampleText);
}
}
+ }
+
+ rDevice.SetFont(aOldFont);
+ rDevice.Pop();
+}
+
+OutputDevice& FontNameBox::CachePreview(size_t nIndex, Point* pTopLeft)
+{
+ SolarMutexGuard aGuard;
+ const FontMetric& rFontMetric = (*mpFontList)[nIndex];
+ const OUString& rFontName = rFontMetric.GetFamilyName();
+
+ size_t nPreviewIndex;
+ auto xFind = std::find(gRenderedFontNames.begin(), gRenderedFontNames.end(), rFontName);
+ bool bPreviewAvailable = xFind != gRenderedFontNames.end();
+ if (!bPreviewAvailable)
+ {
+ nPreviewIndex = gRenderedFontNames.size();
+ gRenderedFontNames.push_back(rFontName);
+ }
+ else
+ nPreviewIndex = std::distance(gRenderedFontNames.begin(), xFind);
+
+ size_t nPage = nPreviewIndex / gPreviewsPerDevice;
+ size_t nIndexInPage = nPreviewIndex - (nPage * gPreviewsPerDevice);
+
+ Point aTopLeft(0, gUserItemSz.Height() * nIndexInPage);
+
+ if (!bPreviewAvailable)
+ {
+ if (nPage >= gFontPreviewVirDevs.size())
+ {
+ gFontPreviewVirDevs.emplace_back(m_xComboBox->create_render_virtual_device());
+ VirtualDevice& rDevice = *gFontPreviewVirDevs.back();
+ rDevice.SetOutputSizePixel(Size(gUserItemSz.Width(), gUserItemSz.Height() * gPreviewsPerDevice));
+ if (vcl::Window* pDefaultDevice = dynamic_cast<vcl::Window*>(Application::GetDefaultDevice()))
+ pDefaultDevice->SetPointFont(rDevice, m_xComboBox->get_font());
+ assert(gFontPreviewVirDevs.size() == nPage + 1);
+ }
+
+ DrawPreview(rFontMetric, aTopLeft, *gFontPreviewVirDevs.back(), false);
+ }
+
+ if (pTopLeft)
+ *pTopLeft = aTopLeft;
+
+ return *gFontPreviewVirDevs[nPage];
+}
+
+IMPL_LINK(FontNameBox, CustomRenderHdl, weld::ComboBox::render_args, aPayload, void)
+{
+ vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
+ const ::tools::Rectangle& rRect = std::get<1>(aPayload);
+ bool bSelected = std::get<2>(aPayload);
+ const OUString& rId = std::get<3>(aPayload);
+
+ sal_uInt32 nIndex = rId.toUInt32();
+
+ Point aDestPoint(rRect.TopLeft());
+ auto nMargin = (rRect.GetHeight() - gUserItemSz.Height()) / 2;
+ aDestPoint.AdjustY(nMargin);
- pRenderContext->SetFont(aOldFont);
- DrawEntry( rUDEvt, false, false); // draw separator
+ if (bSelected)
+ {
+ const FontMetric& rFontMetric = (*mpFontList)[nIndex];
+ DrawPreview(rFontMetric, aDestPoint, rRenderContext, true);
}
else
{
- DrawEntry( rUDEvt, true, true );
+ // use cache of unselected entries
+ Point aTopLeft;
+ OutputDevice& rDevice = CachePreview(nIndex, &aTopLeft);
+
+ rRenderContext.DrawOutDev(aDestPoint, gUserItemSz,
+ aTopLeft, gUserItemSz,
+ rDevice);
}
}
+void FontNameBox::set_active_or_entry_text(const OUString& rText)
+{
+ const int nFound = m_xComboBox->find_text(rText);
+ if (nFound != -1)
+ m_xComboBox->set_active(nFound);
+ else
+ m_xComboBox->set_entry_text(rText);
+}
+
FontStyleBox::FontStyleBox(std::unique_ptr<weld::ComboBox> p)
: m_xComboBox(std::move(p))
{
@@ -866,9 +970,13 @@ FontSizeBox::FontSizeBox(std::unique_ptr<weld::ComboBox> p)
m_xComboBox->connect_changed(LINK(this, FontSizeBox, ModifyHdl));
}
-void FontSizeBox::set_entry_text(const OUString& rText)
+void FontSizeBox::set_active_or_entry_text(const OUString& rText)
{
- m_xComboBox->set_entry_text(rText);
+ const int nFound = m_xComboBox->find_text(rText);
+ if (nFound != -1)
+ m_xComboBox->set_active(nFound);
+ else
+ m_xComboBox->set_entry_text(rText);
}
IMPL_LINK(FontSizeBox, ReformatHdl, weld::Widget&, rWidget, void)
@@ -1020,7 +1128,7 @@ void FontSizeBox::Fill( const FontMetric* pFontMetric, const FontList* pList )
++pTempAry;
}
- m_xComboBox->set_entry_text(aStr);
+ set_active_or_entry_text(aStr);
m_xComboBox->select_entry_region(nSelectionStart, nSelectionEnd);
m_xComboBox->thaw();
}
@@ -1105,7 +1213,7 @@ void FontSizeBox::SetRelative( bool bNewRelative )
Fill( &aFontMetric, pFontList );
}
- m_xComboBox->set_entry_text(aStr);
+ set_active_or_entry_text(aStr);
m_xComboBox->select_entry_region(nSelectionStart, nSelectionEnd);
}
@@ -1157,10 +1265,7 @@ void FontSizeBox::SetValue(int nNewValue, FieldUnit eInUnit)
}
}
OUString aResult = format_number(nTempValue);
- const int nFound = m_xComboBox->find_text(aResult);
- if (nFound != -1)
- m_xComboBox->set_active(nFound);
- m_xComboBox->set_entry_text(aResult);
+ set_active_or_entry_text(aResult);
}
void FontSizeBox::set_value(int nNewValue)
diff --git a/svx/UIConfig_svx.mk b/svx/UIConfig_svx.mk
index 567464c49cb5..98ef36a88c6c 100644
--- a/svx/UIConfig_svx.mk
+++ b/svx/UIConfig_svx.mk
@@ -64,6 +64,7 @@ $(eval $(call gb_UIConfig_add_uifiles,svx,\
svx/uiconfig/ui/fontworkgallerydialog \
svx/uiconfig/ui/fontworkspacingdialog \
svx/uiconfig/ui/fontsizebox \
+ svx/uiconfig/ui/fontnamebox \
svx/uiconfig/ui/formdatamenu \
svx/uiconfig/ui/formfielddialog \
svx/uiconfig/ui/formlinkwarndialog \
diff --git a/svx/source/tbxctrls/tbcontrl.cxx b/svx/source/tbxctrls/tbcontrl.cxx
index 17a956579d88..9dd130a1dcc1 100644
--- a/svx/source/tbxctrls/tbcontrl.cxx
+++ b/svx/source/tbxctrls/tbcontrl.cxx
@@ -25,6 +25,7 @@
#include <svl/poolitem.hxx>
#include <svl/itemset.hxx>
#include <vcl/commandinfoprovider.hxx>
+#include <vcl/combobox.hxx>
#include <vcl/event.hxx>
#include <vcl/menubtn.hxx>
#include <vcl/toolbox.hxx>
@@ -35,6 +36,7 @@
#include <svl/style.hxx>
#include <svtools/ctrltool.hxx>
#include <svtools/borderhelper.hxx>
+#include <sfx2/InterimItemWindow.hxx>
#include <sfx2/tplpitem.hxx>
#include <sfx2/sfxstatuslistener.hxx>
#include <toolkit/helper/vclunohelper.hxx>
@@ -176,24 +178,25 @@ private:
namespace {
-class SvxFontNameBox_Impl : public FontNameBox
+class SvxFontNameBox_Impl final : public InterimItemWindow
{
private:
+ std::unique_ptr<FontNameBox> m_xWidget;
const FontList* pFontList;
::std::unique_ptr<FontList> m_aOwnFontList;
vcl::Font aCurFont;
- Size aLogicalSize;
OUString aCurText;
sal_uInt16 nFtCount;
bool bRelease;
Reference< XDispatchProvider > m_xDispatchProvider;
Reference< XFrame > m_xFrame;
- bool mbEndPreview;
bool mbCheckingUnknownFont;
void ReleaseFocus_Impl();
void EnableControls_Impl();
+ void Select(bool bNonTravelSelect);
+
void EndPreview()
{
Sequence< PropertyValue > aArgs;
@@ -201,33 +204,44 @@ private:
".uno:CharEndPreviewFontName",
aArgs );
}
- DECL_LINK( CheckAndMarkUnknownFont, VclWindowEvent&, void );
+ void CheckAndMarkUnknownFont();
void SetOptimalSize();
-protected:
- virtual void Select() override;
virtual void DataChanged( const DataChangedEvent& rDCEvt ) override;
+ virtual void GetFocus() override;
public:
- SvxFontNameBox_Impl( vcl::Window* pParent, const Reference< XDispatchProvider >& rDispatchProvider,const Reference< XFrame >& _xFrame
- , WinBits nStyle
- );
+ SvxFontNameBox_Impl(vcl::Window* pParent, const Reference<XDispatchProvider>& rDispatchProvider, const Reference<XFrame>& _xFrame);
virtual ~SvxFontNameBox_Impl() override;
virtual void dispose() override;
void FillList();
void Update( const css::awt::FontDescriptor* pFontDesc );
sal_uInt16 GetListCount() const { return nFtCount; }
- void Clear() { FontNameBox::Clear(); nFtCount = 0; }
+ void Clear() { m_xWidget->clear(); nFtCount = 0; }
void Fill( const FontList* pList )
- { FontNameBox::Fill( pList );
- nFtCount = pList->GetFontNameCount(); }
- virtual bool PreNotify( NotifyEvent& rNEvt ) override;
- virtual bool EventNotify( NotifyEvent& rNEvt ) override;
+ {
+ m_xWidget->Fill(pList);
+ nFtCount = pList->GetFontNameCount();
+ }
+
virtual Reference< css::accessibility::XAccessible > CreateAccessible() override;
void SetOwnFontList(::std::unique_ptr<FontList> && _aOwnFontList) { m_aOwnFontList = std::move(_aOwnFontList); }
- virtual boost::property_tree::ptree DumpAsPropertyTree() override;
+
+ void Enable() {m_xWidget->set_sensitive(true); InterimItemWindow::Enable();}
+ void Disable() {m_xWidget->set_sensitive(false); InterimItemWindow::Disable();}
+
+ void set_active_or_entry_text(const OUString& rText);
+
+ void statusChanged_Impl(const css::frame::FeatureStateEvent& rEvent);
+
+ DECL_LINK(SelectHdl, weld::ComboBox&, void);
+ DECL_LINK(KeyInputHdl, const KeyEvent&, bool);
+ DECL_LINK(ActivateHdl, weld::ComboBox&, bool);
+ DECL_LINK(FocusInHdl, weld::Widget&, void);
+ DECL_LINK(FocusOutHdl, weld::Widget&, void);
+ DECL_LINK(DumpAsPropertyTreeHdl, boost::property_tree::ptree&, void);
};
// SelectHdl needs the Modifiers, get them in MouseButtonUp
@@ -1304,22 +1318,34 @@ static bool lcl_GetDocFontList( const FontList** ppFontList, SvxFontNameBox_Impl
return bChanged;
}
-SvxFontNameBox_Impl::SvxFontNameBox_Impl( vcl::Window* pParent, const Reference< XDispatchProvider >& rDispatchProvider,const Reference< XFrame >& _xFrame, WinBits nStyle ) :
-
- FontNameBox ( pParent, nStyle | WinBits( WB_DROPDOWN | WB_AUTOHSCROLL ) ),
- pFontList ( nullptr ),
- aLogicalSize ( 60,160 ),
- nFtCount ( 0 ),
- bRelease ( true ),
- m_xDispatchProvider( rDispatchProvider ),
- m_xFrame (_xFrame),
- mbEndPreview(false),
- mbCheckingUnknownFont(false)
+SvxFontNameBox_Impl::SvxFontNameBox_Impl(vcl::Window* pParent, const Reference<XDispatchProvider>& rDispatchProvider,
+ const Reference<XFrame>& _xFrame)
+ : InterimItemWindow(pParent, "svx/ui/fontnamebox.ui", "FontNameBox")
+ , m_xWidget(new FontNameBox(m_xBuilder->weld_combo_box("fontnamecombobox")))
+ , pFontList(nullptr)
+ , nFtCount(0)
+ , bRelease(true)
+ , m_xDispatchProvider(rDispatchProvider)
+ , m_xFrame(_xFrame)
+ , mbCheckingUnknownFont(false)
{
- SetOptimalSize();
EnableControls_Impl();
- GetSubEdit()->AddEventListener( LINK( this, SvxFontNameBox_Impl, CheckAndMarkUnknownFont ));
set_id("fontnamecombobox");
+
+ m_xWidget->connect_changed(LINK(this, SvxFontNameBox_Impl, SelectHdl));
+ m_xWidget->connect_key_press(LINK(this, SvxFontNameBox_Impl, KeyInputHdl));
+ m_xWidget->connect_entry_activate(LINK(this, SvxFontNameBox_Impl, ActivateHdl));
+ m_xWidget->connect_focus_in(LINK(this, SvxFontNameBox_Impl, FocusInHdl));
+ m_xWidget->connect_focus_out(LINK(this, SvxFontNameBox_Impl, FocusOutHdl));
+ m_xWidget->connect_get_property_tree(LINK(this, SvxFontNameBox_Impl, DumpAsPropertyTreeHdl));
+
+ const Size aLogicalSize(60, 0);
+ Size aSize(LogicToPixel(aLogicalSize, MapMode(MapUnit::MapAppFont)));
+ // set width in chars low so the size request will not be overridden
+ m_xWidget->set_entry_width_chars(1);
+ m_xWidget->set_size_request(aSize.Width(), -1);
+
+ SetOptimalSize();
}
SvxFontNameBox_Impl::~SvxFontNameBox_Impl()
@@ -1329,38 +1355,41 @@ SvxFontNameBox_Impl::~SvxFontNameBox_Impl()
void SvxFontNameBox_Impl::dispose()
{
- GetSubEdit()->RemoveEventListener( LINK( this, SvxFontNameBox_Impl, CheckAndMarkUnknownFont ));
- FontNameBox::dispose();
+ m_xWidget.reset();
+ InterimItemWindow::dispose();
}
void SvxFontNameBox_Impl::FillList()
{
+ if (!m_xWidget) // e.g. disposed
+ return;
// Save old Selection, set back in the end
- Selection aOldSel = GetSelection();
+ int nStartPos, nEndPos;
+ m_xWidget->get_entry_selection_bounds(nStartPos, nEndPos);
+
// Did Doc-Fontlist change?
- lcl_GetDocFontList( &pFontList, this );
- aCurText = GetText();
- SetSelection( aOldSel );
+ lcl_GetDocFontList(&pFontList, this);
+
+ aCurText = m_xWidget->get_active_text();
+ m_xWidget->select_entry_region(nStartPos, nEndPos);
}
-IMPL_LINK( SvxFontNameBox_Impl, CheckAndMarkUnknownFont, VclWindowEvent&, event, void )
+void SvxFontNameBox_Impl::CheckAndMarkUnknownFont()
{
- if( event.GetId() != VclEventId::EditModify )
- return;
if (mbCheckingUnknownFont) //tdf#117537 block rentry
return;
mbCheckingUnknownFont = true;
- OUString fontname = GetSubEdit()->GetText();
+ OUString fontname = m_xWidget->get_active_text();
lcl_GetDocFontList( &pFontList, this );
// If the font is unknown, show it in italic.
- vcl::Font font = GetControlFont();
+ vcl::Font font = m_xWidget->get_entry_font();
if( pFontList != nullptr && pFontList->IsAvailable( fontname ))
{
if( font.GetItalic() != ITALIC_NONE )
{
font.SetItalic( ITALIC_NONE );
- SetControlFont( font );
- SetQuickHelpText( SvxResId( RID_SVXSTR_CHARFONTNAME ));
+ m_xWidget->set_entry_font(font);
+ m_xWidget->set_tooltip_text(SvxResId(RID_SVXSTR_CHARFONTNAME));
}
}
else
@@ -1368,8 +1397,8 @@ IMPL_LINK( SvxFontNameBox_Impl, CheckAndMarkUnknownFont, VclWindowEvent&, event,
if( font.GetItalic() != ITALIC_NORMAL )
{
font.SetItalic( ITALIC_NORMAL );
- SetControlFont( font );
- SetQuickHelpText( SvxResId( RID_SVXSTR_CHARFONTNAME_NOTAVAILABLE ));
+ m_xWidget->set_entry_font(font);
+ m_xWidget->set_tooltip_text(SvxResId(RID_SVXSTR_CHARFONTNAME_NOTAVAILABLE));
}
}
mbCheckingUnknownFont = false;
@@ -1386,72 +1415,61 @@ void SvxFontNameBox_Impl::Update( const css::awt::FontDescriptor* pFontDesc )
aCurFont.SetCharSet ( rtl_TextEncoding( pFontDesc->CharSet ) );
}
OUString aCurName = aCurFont.GetFamilyName();
- if ( GetText() != aCurName )
- SetText( aCurName );
+ OUString aText = m_xWidget->get_active_text();
+ if (aText != aCurName)
+ set_active_or_entry_text(aCurName);
}
-bool SvxFontNameBox_Impl::PreNotify( NotifyEvent& rNEvt )
+void SvxFontNameBox_Impl::set_active_or_entry_text(const OUString& rText)
{
- MouseNotifyEvent nType = rNEvt.GetType();
+ m_xWidget->set_active_or_entry_text(rText);
+ CheckAndMarkUnknownFont();
+}
- if ( MouseNotifyEvent::MOUSEBUTTONDOWN == nType || MouseNotifyEvent::GETFOCUS == nType )
- {
- EnableControls_Impl();
- FillList();
- }
- return FontNameBox::PreNotify( rNEvt );
+IMPL_LINK_NOARG(SvxFontNameBox_Impl, FocusInHdl, weld::Widget&, void)
+{
+ EnableControls_Impl();
+ FillList();
}
-bool SvxFontNameBox_Impl::EventNotify( NotifyEvent& rNEvt )
+IMPL_LINK(SvxFontNameBox_Impl, KeyInputHdl, const KeyEvent&, rKEvt, bool)
{
bool bHandled = false;
- mbEndPreview = false;
- if ( rNEvt.GetType() == MouseNotifyEvent::KEYUP )
- mbEndPreview = true;
- if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT )
- {
- sal_uInt16 nCode = rNEvt.GetKeyEvent()->GetKeyCode().GetCode();
+ sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode();
- switch ( nCode )
- {
- case KEY_RETURN:
- case KEY_TAB:
- {
- if ( KEY_TAB == nCode )
- bRelease = false;
- else
- bHandled = true;
- Select();
- break;
- }
+ switch (nCode)
+ {
+ case KEY_TAB:
+ bRelease = false;
+ Select(true);
+ break;
- case KEY_ESCAPE:
- SetText( aCurText );
- if ( typeid( *GetParent() ) != typeid( sfx2::sidebar::SidebarToolBox ) )
- ReleaseFocus_Impl();
- EndPreview();
- break;
- }
+ case KEY_ESCAPE:
+ set_active_or_entry_text(aCurText);
+ if ( typeid( *GetParent() ) != typeid( sfx2::sidebar::SidebarToolBox ) )
+ ReleaseFocus_Impl();
+ EndPreview();
+ bHandled = true;
+ break;
}
- else if ( MouseNotifyEvent::LOSEFOCUS == rNEvt.GetType() )
+
+ return bHandled || ChildKeyInput(rKEvt);
+}
+
+IMPL_LINK_NOARG(SvxFontNameBox_Impl, FocusOutHdl, weld::Widget&, void)
+{
+ if (!m_xWidget->has_focus()) // a combobox can be comprised of different subwidget so double-check if none of those has focus
{
- vcl::Window* pFocusWin = Application::GetFocusWindow();
- if ( !HasFocus() && GetSubEdit() != pFocusWin )
- SetText( GetSavedValue() );
+ set_active_or_entry_text(m_xWidget->get_saved_value());
// send EndPreview
EndPreview();
}
-
- return bHandled || FontNameBox::EventNotify( rNEvt );
}
void SvxFontNameBox_Impl::SetOptimalSize()
{
- Size aSize(LogicToPixel(aLogicalSize, MapMode(MapUnit::MapAppFont)));
- set_width_request(aSize.Width());
- set_height_request(aSize.Height());
- SetSizePixel(aSize);
+ SetSizePixel(get_preferred_size());
}
void SvxFontNameBox_Impl::DataChanged( const DataChangedEvent& rDCEvt )
@@ -1468,8 +1486,6 @@ void SvxFontNameBox_Impl::DataChanged( const DataChangedEvent& rDCEvt )
// the new one before doing anything further.
lcl_GetDocFontList( &pFontList, this );
}
-
- FontNameBox::DataChanged( rDCEvt );
}
void SvxFontNameBox_Impl::ReleaseFocus_Impl()
@@ -1488,27 +1504,36 @@ void SvxFontNameBox_Impl::EnableControls_Impl()
SvtFontOptions aFontOpt;
bool bEnable = aFontOpt.IsFontHistoryEnabled();
sal_uInt16 nEntries = bEnable ? MAX_MRU_FONTNAME_ENTRIES : 0;
- if ( GetMaxMRUCount() != nEntries )
+ if (m_xWidget->get_max_mru_count() != nEntries)
{
// refill in the next GetFocus-Handler
pFontList = nullptr;
Clear();
- SetMaxMRUCount( nEntries );
+ m_xWidget->set_max_mru_count(nEntries);
}
- bEnable = aFontOpt.IsFontWYSIWYGEnabled();
- EnableWYSIWYG( bEnable );
+ if (aFontOpt.IsFontWYSIWYGEnabled())
+ m_xWidget->EnableWYSIWYG();
}
-void SvxFontNameBox_Impl::Select()
+IMPL_LINK(SvxFontNameBox_Impl, SelectHdl, weld::ComboBox&, rCombo, void)
{
- FontNameBox::Select();
+ Select(rCombo.changed_by_direct_pick()); // only when picked from the list
+}
+IMPL_LINK_NOARG(SvxFontNameBox_Impl, ActivateHdl, weld::ComboBox&, bool)
+{
+ Select(true);
+ return true;
+}
+
+void SvxFontNameBox_Impl::Select(bool bNonTravelSelect)
+{
Sequence< PropertyValue > aArgs( 1 );
std::unique_ptr<SvxFontItem> pFontItem;
if ( pFontList )
{
- FontMetric aFontMetric( pFontList->Get( GetText(),
+ FontMetric aFontMetric( pFontList->Get(m_xWidget->get_active_text(),
aCurFont.GetWeight(),
aCurFont.GetItalic() ) );
aCurFont = aFontMetric;
@@ -1524,8 +1549,10 @@ void SvxFontNameBox_Impl::Select()
pFontItem->QueryValue( a );
aArgs[0].Value = a;
}
- if ( !IsTravelSelect() )
+
+ if (bNonTravelSelect)
{
+ CheckAndMarkUnknownFont();
// #i33380# DR 2004-09-03 Moved the following line above the Dispatch() call.
// This instance may be deleted in the meantime (i.e. when a dialog is opened
// while in Dispatch()), accessing members will crash in this case.
@@ -1541,11 +1568,6 @@ void SvxFontNameBox_Impl::Select()
}
else
{
- if ( mbEndPreview )
- {
- EndPreview();
- return;
- }
if (pFontItem)
{
aArgs[0].Name = "CharPreviewFontName";
@@ -1556,35 +1578,39 @@ void SvxFontNameBox_Impl::Select()
}
}
-boost::property_tree::ptree SvxFontNameBox_Impl::DumpAsPropertyTree()
+void SvxFontNameBox_Impl::GetFocus()
{
- boost::property_tree::ptree aTree(FontNameBox::DumpAsPropertyTree());
+ if (m_xWidget)
+ m_xWidget->grab_focus();
+ InterimItemWindow::GetFocus();
+}
+IMPL_LINK(SvxFontNameBox_Impl, DumpAsPropertyTreeHdl, boost::property_tree::ptree&, rTree, void)
+{
boost::property_tree::ptree aEntries;
- for (int i = 0; i < GetEntryCount(); ++i)
+ for (int i = 0, nEntryCount = m_xWidget->get_count(); i < nEntryCount; ++i)
{
boost::property_tree::ptree aEntry;
- aEntry.put("", GetEntry(i));
+ aEntry.put("", m_xWidget->get_text(i));
aEntries.push_back(std::make_pair("", aEntry));
}
- aTree.add_child("entries", aEntries);
+ rTree.add_child("entries", aEntries);
boost::property_tree::ptree aSelected;
- for (int i = 0; i < GetSelectedEntryCount(); ++i)
+ int nSelectedEntry = m_xWidget->get_active();
+ if (nSelectedEntry != -1)
{
boost::property_tree::ptree aEntry;
- aEntry.put("", GetSelectedEntryPos(i));
+ aEntry.put("", m_xWidget->get_text(nSelectedEntry));
aSelected.push_back(std::make_pair("", aEntry));
}
- aTree.put("selectedCount", GetSelectedEntryCount());
- aTree.add_child("selectedEntries", aSelected);
- aTree.put("command", ".uno:CharFontName");
-
- return aTree;
+ rTree.put("selectedCount", nSelectedEntry == -1 ? 0 : 1);
+ rTree.add_child("selectedEntries", aSelected);
+ rTree.put("command", ".uno:CharFontName");
}
ColorWindow::ColorWindow(const OUString& rCommand,
@@ -2846,40 +2872,44 @@ SvxFontNameToolBoxControl::SvxFontNameToolBoxControl()
{
}
-void SvxFontNameToolBoxControl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+void SvxFontNameBox_Impl::statusChanged_Impl( const css::frame::FeatureStateEvent& rEvent )
{
- SolarMutexGuard aGuard;
- ToolBox* pToolBox = nullptr;
- sal_uInt16 nId = 0;
- if ( !getToolboxId( nId, &pToolBox ) )
- return;
-
if ( !rEvent.IsEnabled )
{
- m_pBox->Disable();
- m_pBox->Update( nullptr );
+ Disable();
+ Update( nullptr );
}
else
{
- m_pBox->Enable();
+ Enable();
css::awt::FontDescriptor aFontDesc;
if ( rEvent.State >>= aFontDesc )
- m_pBox->Update( &aFontDesc );
+ Update(&aFontDesc);
else
- m_pBox->SetText( "" );
- m_pBox->SaveValue();
+ set_active_or_entry_text("");
+ m_xWidget->save_value();
}
+}
+
+void SvxFontNameToolBoxControl::statusChanged( const css::frame::FeatureStateEvent& rEvent )
+{
+ SolarMutexGuard aGuard;
+ ToolBox* pToolBox = nullptr;
+ sal_uInt16 nId = 0;
+ if ( !getToolboxId( nId, &pToolBox ) )
+ return;
+ m_pBox->statusChanged_Impl(rEvent);
pToolBox->EnableItem( nId, rEvent.IsEnabled );
}
css::uno::Reference< css::awt::XWindow > SvxFontNameToolBoxControl::createItemWindow( const css::uno::Reference< css::awt::XWindow >& rParent )
{
SolarMutexGuard aGuard;
- m_pBox = VclPtr<SvxFontNameBox_Impl>::Create( VCLUnoHelper::GetWindow( rParent ),
- Reference< XDispatchProvider >( m_xFrame->getController(), UNO_QUERY ),
- m_xFrame, 0);
+ m_pBox = VclPtr<SvxFontNameBox_Impl>::Create(VCLUnoHelper::GetWindow(rParent),
+ Reference< XDispatchProvider >(m_xFrame->getController(), UNO_QUERY),
+ m_xFrame);
return VCLUnoHelper::GetInterface( m_pBox );
}
@@ -3510,7 +3540,7 @@ com_sun_star_comp_svx_CurrencyToolBoxControl_get_implementation(
Reference< css::accessibility::XAccessible > SvxFontNameBox_Impl::CreateAccessible()
{
FillList();
- return FontNameBox::CreateAccessible();
+ return InterimItemWindow::CreateAccessible();
}
//static
diff --git a/svx/source/tbxctrls/tbunocontroller.cxx b/svx/source/tbxctrls/tbunocontroller.cxx
index 3e3d9ce2751b..cc638c794a1f 100644
--- a/svx/source/tbxctrls/tbunocontroller.cxx
+++ b/svx/source/tbxctrls/tbunocontroller.cxx
@@ -180,7 +180,7 @@ SvxFontSizeBox_Base::SvxFontSizeBox_Base(std::unique_ptr<weld::ComboBox> xWidget
, m_xWidget(new FontSizeBox(std::move(xWidget)))
{
m_xWidget->set_value(0);
- m_xWidget->set_entry_text("");
+ m_xWidget->set_active_or_entry_text("");
m_xWidget->disable_entry_completion();
m_xWidget->connect_changed(LINK(this, SvxFontSizeBox_Base, SelectHdl));
@@ -246,7 +246,7 @@ void SvxFontSizeBox_Base::statusChanged_Impl( long nPoint, bool bErase )
{
// delete value in the display
m_xWidget->set_value(-1L);
- m_xWidget->set_entry_text("");
+ m_xWidget->set_active_or_entry_text("");
}
m_aCurText = m_xWidget->get_active_text();
}
@@ -292,7 +292,7 @@ bool SvxFontSizeBox_Base::DoKeyInput(const KeyEvent& rKEvt)
break;
case KEY_ESCAPE:
- m_xWidget->set_entry_text(m_aCurText);
+ m_xWidget->set_active_or_entry_text(m_aCurText);
if (!m_rCtrl.IsInSidebar())
{
ReleaseFocus_Impl();
@@ -312,7 +312,7 @@ bool SvxFontSizeBox_Impl::DoKeyInput(const KeyEvent& rKEvt)
IMPL_LINK_NOARG(SvxFontSizeBox_Base, FocusOutHdl, weld::Widget&, void)
{
if (!m_xWidget->has_focus()) // a combobox can be comprised of different subwidget so double-check if none of those has focus
- m_xWidget->set_entry_text(m_aCurText);
+ m_xWidget->set_active_or_entry_text(m_aCurText);
}
void SvxFontSizeBox_Impl::SetOptimalSize()
diff --git a/svx/uiconfig/ui/fontnamebox.ui b/svx/uiconfig/ui/fontnamebox.ui
new file mode 100644
index 000000000000..ca1d3e71f570
--- /dev/null
+++ b/svx/uiconfig/ui/fontnamebox.ui
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.2 -->
+<interface domain="svx">
+ <requires lib="gtk+" version="3.18"/>
+ <object class="GtkBox" id="FontNameBox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkComboBoxText" id="fontnamecombobox">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="has_entry">True</property>
+ <property name="popup_fixed_width">False</property>
+ <child internal-child="entry">
+ <object class="GtkEntry">
+ <property name="can_focus">True</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+</interface>
diff --git a/sw/inc/pch/precompiled_swui.hxx b/sw/inc/pch/precompiled_swui.hxx
index cc71c3c666e1..22537bd6e566 100644
--- a/sw/inc/pch/precompiled_swui.hxx
+++ b/sw/inc/pch/precompiled_swui.hxx
@@ -13,7 +13,7 @@
manual changes will be rewritten by the next run of update_pch.sh (which presumably
also fixes all possible problems, so it's usually better to use it).
- Generated on 2020-03-04 21:22:13 using:
+ Generated on 2020-04-07 17:26:59 using:
./bin/update_pch sw swui --cutoff=3 --exclude:system --include:module --include:local
If after updating build fails, use the following command to locate conflicting headers:
@@ -106,10 +106,8 @@
#include <vcl/bitmapex.hxx>
#include <vcl/builder.hxx>
#include <vcl/builderpage.hxx>
-#include <vcl/button.hxx>
#include <vcl/cairo.hxx>
#include <vcl/checksum.hxx>
-#include <vcl/combobox.hxx>
#include <vcl/ctrl.hxx>
#include <vcl/customweld.hxx>
#include <vcl/devicecoordinate.hxx>
@@ -119,7 +117,6 @@
#include <vcl/edit.hxx>
#include <vcl/errcode.hxx>
#include <vcl/event.hxx>
-#include <vcl/fixed.hxx>
#include <vcl/floatwin.hxx>
#include <vcl/fntstyle.hxx>
#include <vcl/font.hxx>
@@ -131,10 +128,8 @@
#include <vcl/image.hxx>
#include <vcl/keycod.hxx>
#include <vcl/keycodes.hxx>
-#include <vcl/lstbox.hxx>
#include <vcl/mapmod.hxx>
#include <vcl/menu.hxx>
-#include <vcl/menubtn.hxx>
#include <vcl/metaactiontypes.hxx>
#include <vcl/metric.hxx>
#include <vcl/outdev.hxx>
@@ -178,6 +173,7 @@
#include <basegfx/tuple/b2dtuple.hxx>
#include <basegfx/tuple/b2ituple.hxx>
#include <basegfx/tuple/b3dtuple.hxx>
+#include <basegfx/utils/common.hxx>
#include <basegfx/vector/b2dsize.hxx>
#include <basegfx/vector/b2dvector.hxx>
#include <basegfx/vector/b2enums.hxx>
diff --git a/vcl/source/app/salvtables.cxx b/vcl/source/app/salvtables.cxx
index ed219871af24..7cc4d9ebbc50 100644
--- a/vcl/source/app/salvtables.cxx
+++ b/vcl/source/app/salvtables.cxx
@@ -5824,6 +5824,24 @@ public:
ensure_event_listener();
}
+ void call_signal_custom_render(UserDrawEvent* pEvent)
+ {
+ vcl::RenderContext* pRenderContext = pEvent->GetRenderContext();
+ auto nPos = pEvent->GetItemId();
+ signal_custom_render(*pRenderContext, pEvent->GetRect(), pEvent->IsSelected(), get_id(nPos));
+ m_xComboBox->DrawEntry(*pEvent, false, false); // draw separator
+ }
+
+ Size call_signal_custom_get_size(VirtualDevice& rOutput, const OUString& rId)
+ {
+ return signal_custom_get_size(rOutput, rId);
+ }
+
+ VclPtr<VirtualDevice> create_render_virtual_device() const override
+ {
+ return VclPtr<VirtualDevice>::Create();
+ }
+
virtual void HandleEventListener(VclWindowEvent& rEvent) override
{
if (rEvent.GetId() == VclEventId::DropdownPreOpen
@@ -5908,6 +5926,33 @@ public:
virtual vcl::Font get_entry_font() override { assert(false); return vcl::Font(); }
+ virtual void set_custom_renderer() override
+ {
+ assert(false && "not implemented");
+ }
+
+ virtual int get_max_mru_count() const override
+ {
+ assert(false && "not implemented");
+ return 0;
+ }
+
+ virtual void set_max_mru_count(int) override
+ {
+ assert(false && "not implemented");
+ }
+
+ virtual OUString get_mru_entries() const override
+ {
+ assert(false && "not implemented");
+ return OUString();
+ }
+
+ virtual void set_mru_entries(const OUString&) override
+ {
+ assert(false && "not implemented");
+ }
+
virtual ~SalInstanceComboBoxWithoutEdit() override
{
m_xComboBox->SetSelectHdl(Link<ListBox&, void>());
@@ -5929,6 +5974,7 @@ private:
DECL_LINK(ChangeHdl, Edit&, void);
DECL_LINK(EntryActivateHdl, Edit&, bool);
DECL_LINK(SelectHdl, ::ComboBox&, void);
+ DECL_LINK(UserDrawHdl, UserDrawEvent*, void);
WeldTextFilter m_aTextFilter;
bool m_bInSelect;
public:
@@ -6038,6 +6084,43 @@ public:
return pEdit->GetPointFont(*pEdit);
}
+ virtual void set_custom_renderer() override
+ {
+ auto nOldEntryHeight = m_xComboBox->GetDropDownEntryHeight();
+ auto nDropDownLineCount = m_xComboBox->GetDropDownLineCount();
+
+ Size aRowSize(signal_custom_get_size(*m_xComboBox, OUString()));
+ m_xComboBox->EnableUserDraw(true);
+ m_xComboBox->SetUserItemSize(aRowSize);
+ m_xComboBox->SetUserDrawHdl(LINK(this, SalInstanceComboBoxWithEdit, UserDrawHdl));
+
+ // adjust the line count to fit approx the height it would have been before
+ // using a custom renderer
+ auto nNewEntryHeight = m_xComboBox->GetDropDownEntryHeight();
+ double fRatio = nOldEntryHeight / static_cast<double>(nNewEntryHeight);
+ m_xComboBox->SetDropDownLineCount(nDropDownLineCount * fRatio);
+ }
+
+ virtual int get_max_mru_count() const override
+ {
+ return m_xComboBox->GetMaxMRUCount();
+ }
+
+ virtual void set_max_mru_count(int nCount) override
+ {
+ return m_xComboBox->SetMaxMRUCount(nCount);
+ }
+
+ virtual OUString get_mru_entries() const override
+ {
+ return m_xComboBox->GetMRUEntries();
+ }
+
+ virtual void set_mru_entries(const OUString& rEntries) override
+ {
+ m_xComboBox->SetMRUEntries(rEntries);
+ }
+
virtual ~SalInstanceComboBoxWithEdit() override
{
m_xComboBox->SetTextFilter(nullptr);
@@ -6067,6 +6150,11 @@ IMPL_LINK_NOARG(SalInstanceComboBoxWithEdit, EntryActivateHdl, Edit&, bool)
return m_aEntryActivateHdl.Call(*this);
}
+IMPL_LINK(SalInstanceComboBoxWithEdit, UserDrawHdl, UserDrawEvent*, pEvent, void)
+{
+ call_signal_custom_render(pEvent);
+}
+
class SalInstanceEntryTreeView : public SalInstanceContainer, public virtual weld::EntryTreeView
{
private:
@@ -6142,6 +6230,38 @@ public:
virtual bool changed_by_direct_pick() const override { return m_bTreeChange; }
+ virtual void set_custom_renderer() override
+ {
+ assert(false && "not implemented");
+ }
+
+ virtual int get_max_mru_count() const override
+ {
+ assert(false && "not implemented");
+ return 0;
+ }
+
+ virtual void set_max_mru_count(int) override
+ {
+ assert(false && "not implemented");
+ }
+
+ virtual OUString get_mru_entries() const override
+ {
+ assert(false && "not implemented");
+ return OUString();
+ }
+
+ virtual void set_mru_entries(const OUString&) override
+ {
+ assert(false && "not implemented");
+ }
+
+ VclPtr<VirtualDevice> create_render_virtual_device() const override
+ {
+ return VclPtr<VirtualDevice>::Create();
+ }
+
virtual ~SalInstanceEntryTreeView() override
{
Edit& rEntry = m_pEntry->getEntry();
diff --git a/vcl/source/control/combobox.cxx b/vcl/source/control/combobox.cxx
index 36f35704c4cf..ef1e3c1cebf5 100644
--- a/vcl/source/control/combobox.cxx
+++ b/vcl/source/control/combobox.cxx
@@ -1135,6 +1135,11 @@ Size ComboBox::CalcBlockSize( sal_uInt16 nColumns, sal_uInt16 nLines ) const
return aSz;
}
+long ComboBox::GetDropDownEntryHeight() const
+{
+ return m_pImpl->m_pImplLB->GetEntryHeight();
+}
+
void ComboBox::GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines ) const
{
long nCharWidth = GetTextWidth(OUString(u'x'));
@@ -1142,7 +1147,7 @@ void ComboBox::GetMaxVisColumnsAndLines( sal_uInt16& rnCols, sal_uInt16& rnLines
{
Size aOutSz = m_pImpl->m_pImplLB->GetMainWindow()->GetOutputSizePixel();
rnCols = (nCharWidth > 0) ? static_cast<sal_uInt16>(aOutSz.Width()/nCharWidth) : 1;
- rnLines = static_cast<sal_uInt16>(aOutSz.Height()/m_pImpl->m_pImplLB->GetEntryHeight());
+ rnLines = static_cast<sal_uInt16>(aOutSz.Height()/GetDropDownEntryHeight());
}
else
{
@@ -1264,6 +1269,11 @@ void ComboBox::UserDraw( const UserDrawEvent& )
{
}
+void ComboBox::SetUserDrawHdl(const Link<UserDrawEvent*, void>& rLink)
+{
+ m_pImpl->m_pImplLB->SetUserDrawHdl(rLink);
+}
+
void ComboBox::SetUserItemSize( const Size& rSz )
{
m_pImpl->m_pImplLB->GetMainWindow()->SetUserItemSize( rSz );
diff --git a/vcl/source/control/imp_listbox.cxx b/vcl/source/control/imp_listbox.cxx
index a2a3a1615275..3fe90de21906 100644
--- a/vcl/source/control/imp_listbox.cxx
+++ b/vcl/source/control/imp_listbox.cxx
@@ -1714,7 +1714,8 @@ void ImplListBoxWindow::ImplPaint(vcl::RenderContext& rRenderContext, sal_Int32
long nY = mpEntryList->GetAddedHeight(nPos, mnTop);
tools::Rectangle aRect(Point(0, nY), Size(nWidth, pEntry->getHeightWithMargin()));
- if (mpEntryList->IsEntryPosSelected(nPos))
+ bool bSelected = mpEntryList->IsEntryPosSelected(nPos);
+ if (bSelected)
{
rRenderContext.SetTextColor(!IsEnabled() ? rStyleSettings.GetDisableColor() : rStyleSettings.GetHighlightTextColor());
rRenderContext.SetFillColor(rStyleSettings.GetHighlightColor());
@@ -1738,7 +1739,7 @@ void ImplListBoxWindow::ImplPaint(vcl::RenderContext& rRenderContext, sal_Int32
nPos = GetEntryList()->FindEntry(GetEntryList()->GetEntryText(nPos));
nPos = nPos - GetEntryList()->GetMRUCount();
- UserDrawEvent aUDEvt(this, &rRenderContext, aRect, nPos);
+ UserDrawEvent aUDEvt(this, &rRenderContext, aRect, nPos, bSelected);
maUserDrawHdl.Call( &aUDEvt );
mbInUserDraw = false;
}
diff --git a/vcl/unx/gtk3/gtk3gtkinst.cxx b/vcl/unx/gtk3/gtk3gtkinst.cxx
index ff07a983813d..4a0f975b2fd1 100644
--- a/vcl/unx/gtk3/gtk3gtkinst.cxx
+++ b/vcl/unx/gtk3/gtk3gtkinst.cxx
@@ -11237,7 +11237,7 @@ public:
}
};
-void ensure_device(CustomCellRendererSurface *cellsurface, weld::TreeView* pTreeView)
+void ensure_device(CustomCellRendererSurface *cellsurface, weld::Widget* pWidget)
{
if (!cellsurface->device)
{
@@ -11245,110 +11245,12 @@ void ensure_device(CustomCellRendererSurface *cellsurface, weld::TreeView* pTree
cellsurface->device->SetBackground(COL_TRANSPARENT);
// expand the point size of the desired font to the equivalent pixel size
if (vcl::Window* pDefaultDevice = dynamic_cast<vcl::Window*>(Application::GetDefaultDevice()))
- pDefaultDevice->SetPointFont(*cellsurface->device, pTreeView->get_font());
+ pDefaultDevice->SetPointFont(*cellsurface->device, pWidget->get_font());
}
}
}
-bool custom_cell_renderer_surface_get_preferred_size(GtkCellRenderer *cell,
- GtkOrientation orientation,
- gint *minimum_size,
- gint *natural_size)
-{
- GValue value = G_VALUE_INIT;
- g_value_init(&value, G_TYPE_STRING);
- g_object_get_property(G_OBJECT(cell), "id", &value);
-
- const char* pStr = g_value_get_string(&value);
-
- if (!pStr)
- {
- // this happens if we're empty
- return false;
- }
-
- OUString sId(pStr, strlen(pStr), RTL_TEXTENCODING_UTF8);
-
- value = G_VALUE_INIT;
- g_value_init(&value, G_TYPE_POINTER);
- g_object_get_property(G_OBJECT(cell), "instance", &value);
-
- CustomCellRendererSurface *cellsurface = CUSTOM_CELL_RENDERER_SURFACE(cell);
-
- GtkInstanceTreeView* pTreeView = static_cast<GtkInstanceTreeView*>(g_value_get_pointer(&value));
-
- ensure_device(cellsurface, pTreeView);
-
- Size aSize = pTreeView->call_signal_custom_get_size(*cellsurface->device, sId);
-
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- if (minimum_size)
- *minimum_size = aSize.Width();
-
- if (natural_size)
- *natural_size = aSize.Width();
- }
- else
- {
- if (minimum_size)
- *minimum_size = aSize.Height();
-
- if (natural_size)
- *natural_size = aSize.Height();
- }
-
- return true;
-}
-
-void custom_cell_renderer_surface_render(GtkCellRenderer* cell,
- cairo_t* cr,
- GtkWidget* /*widget*/,
- const GdkRectangle* /*background_area*/,
- const GdkRectangle* cell_area,
- GtkCellRendererState flags)
-{
- GValue value = G_VALUE_INIT;
- g_value_init(&value, G_TYPE_STRING);
- g_object_get_property(G_OBJECT(cell), "id", &value);
-
- const char* pStr = g_value_get_string(&value);
- OUString sId(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8);
-
- value = G_VALUE_INIT;
- g_value_init(&value, G_TYPE_POINTER);
- g_object_get_property(G_OBJECT(cell), "instance", &value);
-
- CustomCellRendererSurface *cellsurface = CUSTOM_CELL_RENDERER_SURFACE(cell);
-
- GtkInstanceTreeView* pTreeView = static_cast<GtkInstanceTreeView*>(g_value_get_pointer(&value));
-
- ensure_device(cellsurface, pTreeView);
-
- Size aSize(cell_area->width, cell_area->height);
- // false to not bother setting the bg on resize as we'll do that
- // ourself via cairo
- cellsurface->device->SetOutputSizePixel(aSize, false);
-
- cairo_surface_t* pSurface = get_underlying_cairo_surface(*cellsurface->device);
-
- // fill surface as transparent so it can be blended with the potentially
- // selected background
- cairo_t* tempcr = cairo_create(pSurface);
- cairo_set_source_rgba(tempcr, 0, 0, 0, 0);
- cairo_set_operator(tempcr, CAIRO_OPERATOR_SOURCE);
- cairo_paint(tempcr);
- cairo_destroy(tempcr);
- cairo_surface_flush(pSurface);
-
- pTreeView->call_signal_custom_render(*cellsurface->device, tools::Rectangle(Point(0, 0), aSize), flags & GTK_CELL_RENDERER_SELECTED, sId);
- cairo_surface_mark_dirty(pSurface);
-
- cairo_set_source_surface(cr, pSurface, cell_area->x, cell_area->y);
- cairo_paint(cr);
-}
-
IMPL_LINK_NOARG(GtkInstanceTreeView, async_signal_changed, void*, void)
{
m_pChangeEvent = nullptr;
@@ -12619,6 +12521,14 @@ GtkBuilder* makeComboBoxBuilder()
return gtk_builder_new_from_file(OUStringToOString(aPath, RTL_TEXTENCODING_UTF8).getStr());
}
+struct GtkTreeRowReferenceDeleter
+{
+ void operator()(GtkTreeRowReference* p) const
+ {
+ gtk_tree_row_reference_free(p);
+ }
+};
+
class GtkInstanceComboBox : public GtkInstanceContainer, public vcl::ISearchableStringList, public virtual weld::ComboBox
{
private:
@@ -12635,7 +12545,7 @@ private:
std::unique_ptr<vcl::Font> m_xFont;
std::unique_ptr<comphelper::string::NaturalStringSorter> m_xSorter;
vcl::QuickSelectionEngine m_aQuickSelectionEngine;
- std::vector<int> m_aSeparatorRows;
+ std::vector<std::unique_ptr<GtkTreeRowReference, GtkTreeRowReferenceDeleter>> m_aSeparatorRows;
bool m_bHoverSelection;
bool m_bPopupActive;
bool m_bAutoComplete;
@@ -12658,6 +12568,8 @@ private:
guint m_nAutoCompleteIdleId;
gint m_nNonCustomLineHeight;
gint m_nPrePopupCursorPos;
+ int m_nMRUCount;
+ int m_nMaxMRUCount;
static gboolean idleAutoComplete(gpointer widget)
{
@@ -12685,6 +12597,10 @@ private:
int nPos = -1;
+ int nZeroRow = 0;
+ if (m_nMRUCount)
+ nZeroRow += (m_nMRUCount + 1);
+
if (!m_bAutoCompleteCaseSensitive)
{
// Try match case insensitive from current position
@@ -12692,7 +12608,7 @@ private:
if (nPos == -1 && nStart != 0)
{
// Try match case insensitive, but from start
- nPos = starts_with(m_pTreeModel, aStartText, 0, 0, false);
+ nPos = starts_with(m_pTreeModel, aStartText, 0, nZeroRow, false);
}
}
@@ -12703,13 +12619,13 @@ private:
if (nPos == -1 && nStart != 0)
{
// Try match case sensitive, but from start
- nPos = starts_with(m_pTreeModel, aStartText, 0, 0, true);
+ nPos = starts_with(m_pTreeModel, aStartText, 0, nZeroRow, true);
}
}
if (nPos != -1)
{
- OUString aText = get_text(nPos);
+ OUString aText = get_text_including_mru(nPos);
if (aText != aStartText)
set_active_text(aText);
select_entry_region(aText.getLength(), aStartText.getLength());
@@ -12769,10 +12685,18 @@ private:
pThis->signal_popup_toggled();
}
- int get_popup_height()
+ int get_popup_height(gint& rPopupWidth)
{
- int nMaxRows = Application::GetSettings().GetStyleSettings().GetListBoxMaximumLineCount();
- int nRows = std::min(nMaxRows, get_count());
+ const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings();
+
+ int nMaxRows = rSettings.GetListBoxMaximumLineCount();
+ bool bAddScrollWidth = false;
+ int nRows = get_count_including_mru();
+ if (nMaxRows < nRows)
+ {
+ nRows = nMaxRows;
+ bAddScrollWidth = true;
+ }
GList* pColumns = gtk_tree_view_get_columns(m_pTreeView);
gint nRowHeight = get_height_row(m_pTreeView, pColumns);
@@ -12795,6 +12719,9 @@ private:
}
}
+ if (bAddScrollWidth)
+ rPopupWidth += rSettings.GetScrollBarSize();
+
return nHeight;
}
@@ -12817,8 +12744,10 @@ private:
// so gdk_window_move_to_rect will work again the next time
gtk_widget_unrealize(GTK_WIDGET(m_pMenuWindow));
+ gtk_widget_set_size_request(GTK_WIDGET(m_pMenuWindow), -1, -1);
+
if (!m_bActivateCalled)
- set_cursor(m_nPrePopupCursorPos);
+ tree_view_set_cursor(m_nPrePopupCursorPos);
// undo show_menu tooltip blocking
GtkWidget* pParent = gtk_widget_get_toplevel(m_pToggleButton);
@@ -12834,14 +12763,20 @@ private:
GtkRequisition size;
gtk_widget_get_preferred_size(GTK_WIDGET(m_pMenuWindow), nullptr, &size);
- gint nPopupWidth = std::max(size.width, nComboWidth);
- gint nPopupHeight = get_popup_height();
+ gint nPopupWidth = size.width;
+ gint nPopupHeight = get_popup_height(nPopupWidth);
+ nPopupWidth = std::max(nPopupWidth, nComboWidth);
gtk_widget_set_size_request(GTK_WIDGET(m_pMenuWindow), nPopupWidth, nPopupHeight);
m_nPrePopupCursorPos = get_active();
m_bActivateCalled = false;
+
+ // if we are in mru mode always start with the cursor at the top of the menu
+ if (m_nMaxMRUCount)
+ tree_view_set_cursor(0);
+
show_menu(pComboBox, m_pMenuWindow);
}
}
@@ -12913,6 +12848,7 @@ private:
if (m_aEntryActivateHdl.Call(*this))
g_signal_stop_emission_by_name(m_pEntry, "activate");
}
+ update_mru();
}
OUString get(int pos, int col) const
@@ -12939,14 +12875,22 @@ private:
}
}
- int find(const OUString& rStr, int col) const
+ int find(const OUString& rStr, int col, bool bSearchMRUArea) const
{
GtkTreeIter iter;
if (!gtk_tree_model_get_iter_first(m_pTreeModel, &iter))
return -1;
- OString aStr(OUStringToOString(rStr, RTL_TEXTENCODING_UTF8).getStr());
int nRet = 0;
+
+ if (!bSearchMRUArea && m_nMRUCount)
+ {
+ if (!gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, m_nMRUCount + 1))
+ return -1;
+ nRet += (m_nMRUCount + 1);
+ }
+
+ OString aStr(OUStringToOString(rStr, RTL_TEXTENCODING_UTF8).getStr());
do
{
gchar* pStr;
@@ -12961,22 +12905,38 @@ private:
return -1;
}
- bool separator_function(int nIndex)
+ bool separator_function(GtkTreePath* path)
+ {
+ bool bFound = false;
+ for (auto& a : m_aSeparatorRows)
+ {
+ GtkTreePath* seppath = gtk_tree_row_reference_get_path(a.get());
+ if (seppath)
+ {
+ bFound = gtk_tree_path_compare(path, seppath) == 0;
+ gtk_tree_path_free(seppath);
+ }
+ if (bFound)
+ break;
+ }
+ return bFound;
+ }
+
+ bool separator_function(int pos)
{
- return std::find(m_aSeparatorRows.begin(), m_aSeparatorRows.end(), nIndex) != m_aSeparatorRows.end();
+ GtkTreePath* path = gtk_tree_path_new_from_indices(pos, -1);
+ bool bRet = separator_function(path);
+ gtk_tree_path_free(path);
+ return bRet;
}
static gboolean separatorFunction(GtkTreeModel* pTreeModel, GtkTreeIter* pIter, gpointer widget)
{
GtkInstanceComboBox* pThis = static_cast<GtkInstanceComboBox*>(widget);
GtkTreePath* path = gtk_tree_model_get_path(pTreeModel, pIter);
-
- gint depth;
- gint* indices = gtk_tree_path_get_indices_with_depth(path, &depth);
- int nIndex = indices[depth-1];
-
+ bool bRet = pThis->separator_function(path);
gtk_tree_path_free(path);
- return pThis->separator_function(nIndex);
+ return bRet;
}
// https://gitlab.gnome.org/GNOME/gtk/issues/310
@@ -13031,12 +12991,12 @@ private:
sal_uInt16 nKeyMod = aKeyCode.GetModifier();
if (!nKeyMod)
{
- int nCount = get_count();
- int nActive = get_active() + 1;
+ int nCount = get_count_including_mru();
+ int nActive = get_active_including_mru() + 1;
while (nActive < nCount && separator_function(nActive))
++nActive;
if (nActive < nCount)
- set_active(nActive);
+ set_active_including_mru(nActive);
bDone = true;
}
else if (nKeyMod == KEY_MOD2 && !m_bPopupActive)
@@ -13051,11 +13011,12 @@ private:
sal_uInt16 nKeyMod = aKeyCode.GetModifier();
if (!nKeyMod)
{
- int nActive = get_active() - 1;
- while (nActive >= 0 && separator_function(nActive))
+ int nStartBound = m_bPopupActive ? 0 : (m_nMRUCount + 1);
+ int nActive = get_active_including_mru() - 1;
+ while (nActive >= nStartBound && separator_function(nActive))
--nActive;
- if (nActive >= 0)
- set_active(nActive);
+ if (nActive >= nStartBound)
+ set_active_including_mru(nActive);
bDone = true;
}
break;
@@ -13065,12 +13026,13 @@ private:
sal_uInt16 nKeyMod = aKeyCode.GetModifier();
if (!nKeyMod)
{
- int nCount = get_count();
- int nActive = 0;
+ int nCount = get_count_including_mru();
+ int nStartBound = m_bPopupActive ? 0 : (m_nMRUCount + 1);
+ int nActive = nStartBound;
while (nActive < nCount && separator_function(nActive))
++nActive;
if (nActive < nCount)
- set_active(nActive);
+ set_active_including_mru(nActive);
bDone = true;
}
break;
@@ -13080,11 +13042,12 @@ private:
sal_uInt16 nKeyMod = aKeyCode.GetModifier();
if (!nKeyMod)
{
- int nActive = get_count() - 1;
- while (nActive >= 0 && separator_function(nActive))
+ int nActive = get_count_including_mru() - 1;
+ int nStartBound = m_bPopupActive ? 0 : (m_nMRUCount + 1);
+ while (nActive >= nStartBound && separator_function(nActive))
--nActive;
- if (nActive >= 0)
- set_active(nActive);
+ if (nActive >= nStartBound)
+ set_active_including_mru(nActive);
bDone = true;
}
break;
@@ -13170,10 +13133,10 @@ private:
vcl::StringEntryIdentifier typeahead_getEntry(int nPos, OUString& out_entryText) const
{
- int nEntryCount(get_count());
+ int nEntryCount(get_count_including_mru());
if (nPos >= nEntryCount)
nPos = 0;
- out_entryText = get_text(nPos);
+ out_entryText = get_text_including_mru(nPos);
// vcl::StringEntryIdentifier does not allow for 0 values, but our position is 0-based
// => normalize
@@ -13186,7 +13149,7 @@ private:
return reinterpret_cast<sal_Int64>(entry) - 1;
}
- void set_cursor(int pos)
+ void tree_view_set_cursor(int pos)
{
if (pos == -1)
{
@@ -13228,15 +13191,15 @@ private:
if (m_bPopupActive)
return tree_view_get_cursor();
else
- return get_active();
+ return get_active_including_mru();
}
void set_selected_entry(int nSelect)
{
if (m_bPopupActive)
- set_cursor(nSelect);
+ tree_view_set_cursor(nSelect);
else
- set_active(nSelect);
+ set_active_including_mru(nSelect);
}
virtual vcl::StringEntryIdentifier CurrentEntry(OUString& out_entryText) const override
@@ -13262,7 +13225,7 @@ private:
}
// normalize
- int nCount = get_count();
+ int nCount = get_count_including_mru();
if (nSelect >= nCount)
nSelect = nCount ? nCount-1 : -1;
@@ -13355,10 +13318,175 @@ private:
if (m_pEntry)
gtk_entry_set_text(GTK_ENTRY(m_pEntry), OUStringToOString(get_text(nActive), RTL_TEXTENCODING_UTF8).getStr());
else
- set_cursor(nActive);
+ tree_view_set_cursor(nActive);
enable_notify_events();
gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(m_pToggleButton), false);
fire_signal_changed();
+ update_mru();
+ }
+
+ void do_clear()
+ {
+ disable_notify_events();
+ gtk_tree_view_set_row_separator_func(m_pTreeView, nullptr, nullptr, nullptr);
+ m_aSeparatorRows.clear();
+ gtk_list_store_clear(GTK_LIST_STORE(m_pTreeModel));
+ m_nMRUCount = 0;
+ enable_notify_events();
+ }
+
+ virtual int get_max_mru_count() const override
+ {
+ return m_nMaxMRUCount;
+ }
+
+ virtual void set_max_mru_count(int nMaxMRUCount) override
+ {
+ m_nMaxMRUCount = nMaxMRUCount;
+ update_mru();
+ }
+
+ void update_mru()
+ {
+ int nMRUCount = m_nMRUCount;
+
+ if (m_nMaxMRUCount)
+ {
+ OUString sActiveText = get_active_text();
+ OUString sActiveId = get_active_id();
+ insert_including_mru(0, sActiveText, &sActiveId, nullptr, nullptr);
+ ++m_nMRUCount;
+
+ for (int i = 1; i < m_nMRUCount - 1; ++i)
+ {
+ if (get_text_including_mru(i) == sActiveText)
+ {
+ remove_including_mru(i);
+ --m_nMRUCount;
+ break;
+ }
+ }
+
+//TODO set_active(0);
+ }
+
+ while (m_nMRUCount > m_nMaxMRUCount)
+ {
+ remove_including_mru(m_nMRUCount - 1);
+ --m_nMRUCount;
+ }
+
+ if (m_nMRUCount && !nMRUCount)
+ insert_separator_including_mru(m_nMRUCount, "separator");
+ else if (!m_nMRUCount && nMRUCount)
+ remove_including_mru(m_nMRUCount); // remove separator
+ }
+
+ int get_count_including_mru() const
+ {
+ return gtk_tree_model_iter_n_children(m_pTreeModel, nullptr);
+ }
+
+ int get_active_including_mru() const
+ {
+ return tree_view_get_cursor();
+ }
+
+ void set_active_including_mru(int pos)
+ {
+ disable_notify_events();
+
+ tree_view_set_cursor(pos);
+
+ if (m_pEntry)
+ {
+ if (pos != -1)
+ gtk_entry_set_text(GTK_ENTRY(m_pEntry), OUStringToOString(get_text_including_mru(pos), RTL_TEXTENCODING_UTF8).getStr());
+ else
+ gtk_entry_set_text(GTK_ENTRY(m_pEntry), "");
+ }
+
+ m_bChangedByMenu = false;
+ enable_notify_events();
+ }
+
+ int find_text_including_mru(const OUString& rStr, bool bSearchMRU) const
+ {
+ return find(rStr, m_nTextCol, bSearchMRU);
+ }
+
+ int find_id_including_mru(const OUString& rId, bool bSearchMRU) const
+ {
+ return find(rId, m_nIdCol, bSearchMRU);
+ }
+
+ OUString get_text_including_mru(int pos) const
+ {
+ return get(pos, m_nTextCol);
+ }
+
+ OUString get_id_including_mru(int pos) const
+ {
+ return get(pos, m_nIdCol);
+ }
+
+ void set_id_including_mru(int pos, const OUString& rId)
+ {
+ set(pos, m_nIdCol, rId);
+ }
+
+ void remove_including_mru(int pos)
+ {
+ disable_notify_events();
+ GtkTreeIter iter;
+ gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, pos);
+ if (!m_aSeparatorRows.empty())
+ {
+ bool bFound = false;
+
+ GtkTreePath* pPath = gtk_tree_path_new_from_indices(pos, -1);
+
+ for (auto aIter = m_aSeparatorRows.begin(); aIter != m_aSeparatorRows.end(); ++aIter)
+ {
+ GtkTreePath* seppath = gtk_tree_row_reference_get_path(aIter->get());
+ if (seppath)
+ {
+ if (gtk_tree_path_compare(pPath, seppath) == 0)
+ bFound = true;
+ gtk_tree_path_free(seppath);
+ }
+ if (bFound)
+ {
+ m_aSeparatorRows.erase(aIter);
+ break;
+ }
+ }
+
+ gtk_tree_path_free(pPath);
+ }
+ gtk_list_store_remove(GTK_LIST_STORE(m_pTreeModel), &iter);
+ enable_notify_events();
+ }
+
+ void insert_separator_including_mru(int pos, const OUString& rId)
+ {
+ disable_notify_events();
+ GtkTreeIter iter;
+ if (!gtk_tree_view_get_row_separator_func(m_pTreeView))
+ gtk_tree_view_set_row_separator_func(m_pTreeView, separatorFunction, this, nullptr);
+ insert_row(GTK_LIST_STORE(m_pTreeModel), iter, pos, &rId, "", nullptr, nullptr);
+ GtkTreePath* pPath = gtk_tree_path_new_from_indices(pos, -1);
+ m_aSeparatorRows.emplace_back(gtk_tree_row_reference_new(m_pTreeModel, pPath));
+ gtk_tree_path_free(pPath);
+ enable_notify_events();
+ }
+
+ void insert_including_mru(int pos, const OUString& rText, const OUString* pId, const OUString* pIconName, VirtualDevice* pImageSurface)
+ {
+ disable_notify_events();
+ GtkTreeIter iter;
+ insert_row(GTK_LIST_STORE(m_pTreeModel), iter, pos, pId, rText, pIconName, pImageSurface);
+ enable_notify_events();
}
public:
@@ -13390,6 +13518,8 @@ public:
, m_nAutoCompleteIdleId(0)
, m_nNonCustomLineHeight(-1)
, m_nPrePopupCursorPos(-1)
+ , m_nMRUCount(0)
+ , m_nMaxMRUCount(0)
{
insertParent(GTK_WIDGET(m_pComboBox), GTK_WIDGET(getContainer()));
gtk_widget_set_visible(GTK_WIDGET(m_pComboBox), false);
@@ -13489,7 +13619,19 @@ public:
virtual int get_active() const override
{
- return tree_view_get_cursor();
+ int nActive = get_active_including_mru();
+ if (nActive == -1)
+ return -1;
+
+ if (m_nMRUCount)
+ {
+ if (nActive < m_nMRUCount)
+ nActive = find_text(get_text_including_mru(nActive));
+ else
+ nActive -= (m_nMRUCount + 1);
+ }
+
+ return nActive;
}
virtual OUString get_active_id() const override
@@ -13543,20 +13685,9 @@ public:
virtual void set_active(int pos) override
{
- disable_notify_events();
-
- set_cursor(pos);
-
- if (m_pEntry)
- {
- if (pos != -1)
- gtk_entry_set_text(GTK_ENTRY(m_pEntry), OUStringToOString(get_text(pos), RTL_TEXTENCODING_UTF8).getStr());
- else
- gtk_entry_set_text(GTK_ENTRY(m_pEntry), "");
- }
-
- m_bChangedByMenu = false;
- enable_notify_events();
+ if (m_nMRUCount && pos != -1)
+ pos += (m_nMRUCount + 1);
+ set_active_including_mru(pos);
}
virtual OUString get_active_text() const override
@@ -13576,17 +13707,23 @@ public:
virtual OUString get_text(int pos) const override
{
- return get(pos, m_nTextCol);
+ if (m_nMRUCount)
+ pos += (m_nMRUCount + 1);
+ return get_text_including_mru(pos);
}
virtual OUString get_id(int pos) const override
{
- return get(pos, m_nIdCol);
+ if (m_nMRUCount)
+ pos += (m_nMRUCount + 1);
+ return get_id_including_mru(pos);
}
virtual void set_id(int pos, const OUString& rId) override
{
- set(pos, m_nIdCol, rId);
+ if (m_nMRUCount)
+ pos += (m_nMRUCount + 1);
+ set_id_including_mru(pos, rId);
}
virtual void insert_vector(const std::vector<weld::ComboBoxEntry>& rItems, bool bKeepExisting) override
@@ -13605,56 +13742,53 @@ public:
virtual void remove(int pos) override
{
- disable_notify_events();
- GtkTreeIter iter;
- gtk_tree_model_iter_nth_child(m_pTreeModel, &iter, nullptr, pos);
- gtk_list_store_remove(GTK_LIST_STORE(m_pTreeModel), &iter);
- m_aSeparatorRows.erase(std::remove(m_aSeparatorRows.begin(), m_aSeparatorRows.end(), pos), m_aSeparatorRows.end());
- enable_notify_events();
+ if (m_nMRUCount)
+ pos += (m_nMRUCount + 1);
+ remove_including_mru(pos);
}
virtual void insert(int pos, const OUString& rText, const OUString* pId, const OUString* pIconName, VirtualDevice* pImageSurface) override
{
- disable_notify_events();
- GtkTreeIter iter;
- insert_row(GTK_LIST_STORE(m_pTreeModel), iter, pos, pId, rText, pIconName, pImageSurface);
- enable_notify_events();
+ if (m_nMRUCount && pos != -1)
+ pos += (m_nMRUCount + 1);
+ insert_including_mru(pos, rText, pId, pIconName, pImageSurface);
}
virtual void insert_separator(int pos, const OUString& rId) override
{
- disable_notify_events();
- GtkTreeIter iter;
pos = pos == -1 ? get_count() : pos;
- m_aSeparatorRows.push_back(pos);
- if (!gtk_tree_view_get_row_separator_func(m_pTreeView))
- gtk_tree_view_set_row_separator_func(m_pTreeView, separatorFunction, this, nullptr);
- insert_row(GTK_LIST_STORE(m_pTreeModel), iter, pos, &rId, "", nullptr, nullptr);
- enable_notify_events();
+ if (m_nMRUCount)
+ pos += (m_nMRUCount + 1);
+ insert_separator_including_mru(pos, rId);
}
virtual int get_count() const override
{
- return gtk_tree_model_iter_n_children(m_pTreeModel, nullptr);
+ int nCount = get_count_including_mru();
+ if (m_nMRUCount)
+ nCount -= (m_nMRUCount + 1);
+ return nCount;
}
virtual int find_text(const OUString& rStr) const override
{
- return find(rStr, m_nTextCol);
+ int nPos = find_text_including_mru(rStr, false);
+ if (m_nMRUCount)
+ nPos -= (m_nMRUCount + 1);
+ return nPos;
}
virtual int find_id(const OUString& rId) const override
{
- return find(rId, m_nIdCol);
+ int nPos = find_id_including_mru(rId, false);
+ if (m_nMRUCount)
+ nPos -= (m_nMRUCount + 1);
+ return nPos;
}
virtual void clear() override
{
- disable_notify_events();
- gtk_list_store_clear(GTK_LIST_STORE(m_pTreeModel));
- m_aSeparatorRows.clear();
- gtk_combo_box_set_row_separator_func(m_pComboBox, nullptr, nullptr, nullptr);
- enable_notify_events();
+ do_clear();
}
virtual void make_sorted() override
@@ -13860,8 +13994,88 @@ public:
return m_bChangedByMenu;
}
+ virtual void set_custom_renderer() override
+ {
+ GList* pColumns = gtk_tree_view_get_columns(m_pTreeView);
+ // keep the original height around for optimal popup height calculation
+ m_nNonCustomLineHeight = ::get_height_row(m_pTreeView, pColumns);
+ GtkTreeViewColumn* pColumn = GTK_TREE_VIEW_COLUMN(pColumns->data);
+ gtk_cell_layout_clear(GTK_CELL_LAYOUT(pColumn));
+ GtkCellRenderer *pRenderer = custom_cell_renderer_surface_new();
+ GValue value = G_VALUE_INIT;
+ g_value_init(&value, G_TYPE_POINTER);
+ g_value_set_pointer(&value, static_cast<gpointer>(this));
+ g_object_set_property(G_OBJECT(pRenderer), "instance", &value);
+ gtk_tree_view_column_pack_start(pColumn, pRenderer, true);
+ gtk_tree_view_column_add_attribute(pColumn, pRenderer, "text", m_nTextCol);
+ gtk_tree_view_column_add_attribute(pColumn, pRenderer, "id", m_nIdCol);
+ g_list_free(pColumns);
+ }
+
+ void call_signal_custom_render(VirtualDevice& rOutput, const tools::Rectangle& rRect, bool bSelected, const OUString& rId)
+ {
+ signal_custom_render(rOutput, rRect, bSelected, rId);
+ }
+
+ Size call_signal_custom_get_size(VirtualDevice& rOutput, const OUString& rId)
+ {
+ return signal_custom_get_size(rOutput, rId);
+ }
+
+ VclPtr<VirtualDevice> create_render_virtual_device() const override
+ {
+ return create_virtual_device();
+ }
+
+ OUString get_mru_entries() const override
+ {
+ const sal_Unicode cSep = ';';
+
+ OUStringBuffer aEntries;
+ for (sal_Int32 n = 0; n < m_nMRUCount; n++)
+ {
+ aEntries.append(get_text_including_mru(n));
+ if (n < m_nMRUCount - 1)
+ aEntries.append(cSep);
+ }
+ return aEntries.makeStringAndClear();
+ }
+
+ virtual void set_mru_entries(const OUString& rEntries) override
+ {
+ const sal_Unicode cSep = ';';
+
+ // Remove old MRU entries
+ for (sal_Int32 n = m_nMRUCount; n;)
+ remove_including_mru(--n);
+
+ sal_Int32 nMRUCount = 0;
+ sal_Int32 nIndex = 0;
+ do
+ {
+ OUString aEntry = rEntries.getToken(0, cSep, nIndex);
+ // Accept only existing entries
+ int nPos = find_text(aEntry);
+ if (nPos != -1)
+ {
+ OUString sId = get_id(nPos);
+ insert_including_mru(0, aEntry, &sId, nullptr, nullptr);
+ ++nMRUCount;
+ }
+ }
+ while (nIndex >= 0);
+
+ if (nMRUCount && !m_nMRUCount)
+ insert_separator_including_mru(nMRUCount, "separator");
+ else if (!nMRUCount && m_nMRUCount)
+ remove_including_mru(m_nMRUCount); // remove separator
+
+ m_nMRUCount = nMRUCount;
+ }
+
virtual ~GtkInstanceComboBox() override
{
+ do_clear();
if (m_nAutoCompleteIdleId)
g_source_remove(m_nAutoCompleteIdleId);
if (m_pEntry)
@@ -13886,6 +14100,108 @@ public:
}
};
+}
+
+bool custom_cell_renderer_surface_get_preferred_size(GtkCellRenderer *cell,
+ GtkOrientation orientation,
+ gint *minimum_size,
+ gint *natural_size)
+{
+ GValue value = G_VALUE_INIT;
+ g_value_init(&value, G_TYPE_STRING);
+ g_object_get_property(G_OBJECT(cell), "id", &value);
+
+ const char* pStr = g_value_get_string(&value);
+
+ OUString sId(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8);
+
+ value = G_VALUE_INIT;
+ g_value_init(&value, G_TYPE_POINTER);
+ g_object_get_property(G_OBJECT(cell), "instance", &value);
+
+ CustomCellRendererSurface *cellsurface = CUSTOM_CELL_RENDERER_SURFACE(cell);
+
+ GtkInstanceWidget* pWidget = static_cast<GtkInstanceWidget*>(g_value_get_pointer(&value));
+
+ ensure_device(cellsurface, pWidget);
+
+ Size aSize;
+ if (GtkInstanceTreeView* pTreeView = dynamic_cast<GtkInstanceTreeView*>(pWidget))
+ aSize = pTreeView->call_signal_custom_get_size(*cellsurface->device, sId);
+ else if (GtkInstanceComboBox* pComboBox = dynamic_cast<GtkInstanceComboBox*>(pWidget))
+ aSize = pComboBox->call_signal_custom_get_size(*cellsurface->device, sId);
+
+ if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ if (minimum_size)
+ *minimum_size = aSize.Width();
+
+ if (natural_size)
+ *natural_size = aSize.Width();
+ }
+ else
+ {
+ if (minimum_size)
+ *minimum_size = aSize.Height();
+
+ if (natural_size)
+ *natural_size = aSize.Height();
+ }
+
+ return true;
+}
+
+void custom_cell_renderer_surface_render(GtkCellRenderer* cell,
+ cairo_t* cr,
+ GtkWidget* /*widget*/,
+ const GdkRectangle* /*background_area*/,
+ const GdkRectangle* cell_area,
+ GtkCellRendererState flags)
+{
+ GValue value = G_VALUE_INIT;
+ g_value_init(&value, G_TYPE_STRING);
+ g_object_get_property(G_OBJECT(cell), "id", &value);
+
+ const char* pStr = g_value_get_string(&value);
+ OUString sId(pStr, pStr ? strlen(pStr) : 0, RTL_TEXTENCODING_UTF8);
+
+ value = G_VALUE_INIT;
+ g_value_init(&value, G_TYPE_POINTER);
+ g_object_get_property(G_OBJECT(cell), "instance", &value);
+
+ CustomCellRendererSurface *cellsurface = CUSTOM_CELL_RENDERER_SURFACE(cell);
+
+ GtkInstanceWidget* pWidget = static_cast<GtkInstanceWidget*>(g_value_get_pointer(&value));
+ ensure_device(cellsurface, pWidget);
+
+ Size aSize(cell_area->width, cell_area->height);
+ // false to not bother setting the bg on resize as we'll do that
+ // ourself via cairo
+ cellsurface->device->SetOutputSizePixel(aSize, false);
+
+ cairo_surface_t* pSurface = get_underlying_cairo_surface(*cellsurface->device);
+
+ // fill surface as transparent so it can be blended with the potentially
+ // selected background
+ cairo_t* tempcr = cairo_create(pSurface);
+ cairo_set_source_rgba(tempcr, 0, 0, 0, 0);
+ cairo_set_operator(tempcr, CAIRO_OPERATOR_SOURCE);
+ cairo_paint(tempcr);
+ cairo_destroy(tempcr);
+ cairo_surface_flush(pSurface);
+
+ if (GtkInstanceTreeView* pTreeView = dynamic_cast<GtkInstanceTreeView*>(pWidget))
+ pTreeView->call_signal_custom_render(*cellsurface->device, tools::Rectangle(Point(0, 0), aSize), flags & GTK_CELL_RENDERER_SELECTED, sId);
+ else if (GtkInstanceComboBox* pComboBox = dynamic_cast<GtkInstanceComboBox*>(pWidget))
+ pComboBox->call_signal_custom_render(*cellsurface->device, tools::Rectangle(Point(0, 0), aSize), flags & GTK_CELL_RENDERER_SELECTED, sId);
+ cairo_surface_mark_dirty(pSurface);
+
+ cairo_set_source_surface(cr, pSurface, cell_area->x, cell_area->y);
+ cairo_paint(cr);
+}
+
+namespace {
+
class GtkInstanceEntryTreeView : public GtkInstanceContainer, public virtual weld::EntryTreeView
{
private:
@@ -14103,6 +14419,38 @@ public:
return m_bTreeChange;
}
+ virtual void set_custom_renderer() override
+ {
+ assert(false && "not implemented");
+ }
+
+ virtual int get_max_mru_count() const override
+ {
+ assert(false && "not implemented");
+ return 0;
+ }
+
+ virtual void set_max_mru_count(int) override
+ {
+ assert(false && "not implemented");
+ }
+
+ virtual OUString get_mru_entries() const override
+ {
+ assert(false && "not implemented");
+ return OUString();
+ }
+
+ virtual void set_mru_entries(const OUString&) override
+ {
+ assert(false && "not implemented");
+ }
+
+ VclPtr<VirtualDevice> create_render_virtual_device() const override
+ {
+ return create_virtual_device();
+ }
+
virtual ~GtkInstanceEntryTreeView() override
{
if (m_nAutoCompleteIdleId)