LibreOffice Module svx (master) 1
searchcharmap.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <config_wasm_strip.h>
21
22#include <vcl/event.hxx>
23#include <vcl/svapp.hxx>
24#include <vcl/settings.hxx>
25#include <vcl/virdev.hxx>
26
27#include <svx/ucsubset.hxx>
28#include <unordered_map>
29
30#include <svx/searchcharmap.hxx>
31
32#include <charmapacc.hxx>
33
34#include <rtl/ustrbuf.hxx>
35
36using namespace ::com::sun::star::accessibility;
37using namespace ::com::sun::star::uno;
38using namespace ::com::sun::star;
39
40
41SvxSearchCharSet::SvxSearchCharSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow, const VclPtr<VirtualDevice>& rVirDev)
42 : SvxShowCharSet(std::move(pScrolledWindow), rVirDev)
43{
44}
45
47{
48 int nIndex = FirstInView();
50 return std::min<int>(nIndex, getMaxCharCount() -1);
51}
52
54{
55 vcl::KeyCode aCode = rKEvt.GetKeyCode();
56
57 if (aCode.GetModifier())
58 return false;
59
60 int tmpSelected = nSelectedIndex;
61
62 bool bRet = true;
63
64 switch (aCode.GetCode())
65 {
66 case KEY_RETURN:
67 return SvxShowCharSet::KeyInput(rKEvt);
68 case KEY_SPACE:
69 aDoubleClkHdl.Call(this);
70 return true;
71 case KEY_LEFT:
72 --tmpSelected;
73 break;
74 case KEY_RIGHT:
75 ++tmpSelected;
76 break;
77 case KEY_UP:
78 tmpSelected -= COLUMN_COUNT;
79 break;
80 case KEY_DOWN:
81 tmpSelected += COLUMN_COUNT;
82 break;
83 case KEY_PAGEUP:
84 tmpSelected -= ROW_COUNT * COLUMN_COUNT;
85 break;
86 case KEY_PAGEDOWN:
87 tmpSelected += ROW_COUNT * COLUMN_COUNT;
88 break;
89 case KEY_HOME:
90 tmpSelected = 0;
91 break;
92 case KEY_END:
93 tmpSelected = getMaxCharCount() - 1;
94 break;
95 case KEY_TAB: // some fonts have a character at these unicode control codes
96 case KEY_ESCAPE:
97 bRet = false;
98 tmpSelected = - 1; // mark as invalid
99 break;
100 default:
101 tmpSelected = -1;
102 bRet = false;
103 break;
104 }
105
106 if ( tmpSelected >= 0 )
107 {
108 SelectIndex( tmpSelected, true );
109 aPreSelectHdl.Call( this );
110 }
111
112 return bRet;
113}
114
116{
117 if (!mxFontCharMap.is())
119
120 // get next available char of current font
121 sal_UCS4 cChar = sub->GetRangeMin();
122 int nMapIndex = 0;
123
124 while(cChar <= sub->GetRangeMax() && nMapIndex == 0)
125 {
126 auto it = std::find_if(m_aItemList.begin(), m_aItemList.end(),
127 [&cChar](const std::pair<const sal_Int32, sal_UCS4>& rItem) { return rItem.second == cChar; });
128 if (it != m_aItemList.end())
129 nMapIndex = it->first;
130 cChar++;
131 }
132
133 if(nMapIndex == 0)
134 SelectIndex( 0 );
135 else
136 SelectIndex( nMapIndex );
137 aHighHdl.Call(this);
138 // move selected item to top row if not in focus
139 //TO.DO aVscrollSB->SetThumbPos( nMapIndex / COLUMN_COUNT );
140 Invalidate();
141}
142
144{
145 InitSettings(rRenderContext);
146 RecalculateFont(rRenderContext);
147 DrawChars_Impl(rRenderContext, FirstInView(), LastInView());
148}
149
150void SvxSearchCharSet::DrawChars_Impl(vcl::RenderContext& rRenderContext, int n1, int n2)
151{
152 if (n1 > LastInView() || n2 < FirstInView())
153 return;
154
155 Size aOutputSize(GetOutputSizePixel());
156
157 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
158 const Color aWindowTextColor(rStyleSettings.GetFieldTextColor());
159 Color aHighlightColor(rStyleSettings.GetHighlightColor());
160 Color aHighlightTextColor(rStyleSettings.GetHighlightTextColor());
161 Color aFaceColor(rStyleSettings.GetFaceColor());
162 Color aLightColor(rStyleSettings.GetLightColor());
163 Color aShadowColor(rStyleSettings.GetShadowColor());
164
165 int i;
166 rRenderContext.SetLineColor(aShadowColor);
167 for (i = 1; i < COLUMN_COUNT; ++i)
168 {
169 rRenderContext.DrawLine(Point(nX * i + m_nXGap, 0),
170 Point(nX * i + m_nXGap, aOutputSize.Height()));
171 }
172 for (i = 1; i < ROW_COUNT; ++i)
173 {
174 rRenderContext.DrawLine(Point(0, nY * i + m_nYGap),
175 Point(aOutputSize.Width(), nY * i + m_nYGap));
176 }
177
178 int nTextHeight = rRenderContext.GetTextHeight();
179 tools::Rectangle aBoundRect;
180 for (i = n1; i <= n2; ++i)
181 {
182 Point pix = MapIndexToPixel(i);
183 int x = pix.X();
184 int y = pix.Y();
185
186 OUStringBuffer buf;
187 std::unordered_map<sal_Int32, sal_UCS4>::const_iterator got = m_aItemList.find (i);
189
190 if(got == m_aItemList.end())
191 continue;
192 else
193 sName = got->second;
194
195 buf.appendUtf32(sName);
196 OUString aCharStr(buf.makeStringAndClear());
197 int nTextWidth = rRenderContext.GetTextWidth(aCharStr);
198 int tx = x + (nX - nTextWidth + 1) / 2;
199 int ty = y + (nY - nTextHeight + 1) / 2;
200 Point aPointTxTy(tx, ty);
201
202 // adjust position before it gets out of bounds
203 if (rRenderContext.GetTextBoundRect(aBoundRect, aCharStr) && !aBoundRect.IsEmpty())
204 {
205 // zero advance width => use ink width to center glyph
206 if (!nTextWidth)
207 {
208 aPointTxTy.setX( x - aBoundRect.Left() + (nX - aBoundRect.GetWidth() + 1) / 2 );
209 }
210
211 aBoundRect += aPointTxTy;
212
213 // shift back vertically if needed
214 int nYLDelta = aBoundRect.Top() - y;
215 int nYHDelta = (y + nY) - aBoundRect.Bottom();
216 if (nYLDelta <= 0)
217 aPointTxTy.AdjustY( -(nYLDelta - 1) );
218 else if (nYHDelta <= 0)
219 aPointTxTy.AdjustY(nYHDelta - 1 );
220
221 // shift back horizontally if needed
222 int nXLDelta = aBoundRect.Left() - x;
223 int nXHDelta = (x + nX) - aBoundRect.Right();
224 if (nXLDelta <= 0)
225 aPointTxTy.AdjustX( -(nXLDelta - 1) );
226 else if (nXHDelta <= 0)
227 aPointTxTy.AdjustX(nXHDelta - 1 );
228 }
229
230 // tdf#109214 - highlight the favorite characters
231 if (isFavChar(aCharStr, mxVirDev->GetFont().GetFamilyName()))
232 {
233 const Color aLineCol = rRenderContext.GetLineColor();
234 rRenderContext.SetLineColor(aHighlightColor);
235 rRenderContext.SetFillColor(COL_TRANSPARENT);
236 // Outer border
237 rRenderContext.DrawRect(tools::Rectangle(Point(x - 1, y - 1), Size(nX + 3, nY + 3)), 1, 1);
238 // Inner border
239 rRenderContext.DrawRect(tools::Rectangle(Point(x, y), Size(nX + 1, nY + 1)), 1, 1);
240 rRenderContext.SetLineColor(aLineCol);
241 }
242
243 Color aTextCol = rRenderContext.GetTextColor();
244 if (i != nSelectedIndex)
245 {
246 rRenderContext.SetTextColor(aWindowTextColor);
247 rRenderContext.DrawText(aPointTxTy, aCharStr);
248 }
249 else
250 {
251 Color aLineCol = rRenderContext.GetLineColor();
252 Color aFillCol = rRenderContext.GetFillColor();
253 rRenderContext.SetLineColor();
254 Point aPointUL(x + 1, y + 1);
255 if (HasFocus())
256 {
257 rRenderContext.SetFillColor(aHighlightColor);
258 rRenderContext.DrawRect(getGridRectangle(aPointUL, aOutputSize));
259
260 rRenderContext.SetTextColor(aHighlightTextColor);
261 rRenderContext.DrawText(aPointTxTy, aCharStr);
262 }
263 else
264 {
265 rRenderContext.SetFillColor(aFaceColor);
266 rRenderContext.DrawRect(getGridRectangle(aPointUL, aOutputSize));
267
268 rRenderContext.SetLineColor(aLightColor);
269 rRenderContext.DrawLine(aPointUL, Point(x + nX - 1, y + 1));
270 rRenderContext.DrawLine(aPointUL, Point(x + 1, y + nY - 1));
271
272 rRenderContext.SetLineColor(aShadowColor);
273 rRenderContext.DrawLine(Point(x + 1, y + nY - 1), Point(x + nX - 1, y + nY - 1));
274 rRenderContext.DrawLine(Point(x + nX - 1, y + nY - 1), Point(x + nX - 1, y + 1));
275
276 rRenderContext.DrawText(aPointTxTy, aCharStr);
277 }
278 rRenderContext.SetLineColor(aLineCol);
279 rRenderContext.SetFillColor(aFillCol);
280 }
281 rRenderContext.SetTextColor(aTextCol);
282 }
283
284 // tdf#141319 - mark empty/unused cells
285 if (n2 - n1 < ROW_COUNT * COLUMN_COUNT)
286 {
287 rRenderContext.SetFillColor(rStyleSettings.GetDisableColor());
288 for (i = n2 - n1 + 1; i < ROW_COUNT * COLUMN_COUNT; i++)
289 {
290 rRenderContext.DrawRect(
291 tools::Rectangle(MapIndexToPixel(i + n1), Size(nX + 2, nY + 2)));
292 }
293 }
294}
295
297{
298 if( nSelectedIndex >= 0 )
299 {
300 std::unordered_map<sal_Int32,sal_UCS4>::const_iterator got = m_aItemList.find (nSelectedIndex);
301
302 if(got == m_aItemList.end())
303 return 1;
304 else
305 return got->second;
306 }
307 return 1;
308}
309
311{
313 return;
314
315 Size aSize(GetOutputSizePixel());
316
317 vcl::Font aFont = rRenderContext.GetFont();
318 aFont.SetWeight(WEIGHT_LIGHT);
319 aFont.SetAlignment(ALIGN_TOP);
320 int nFontHeight = (aSize.Height() - 5) * 2 / (3 * ROW_COUNT);
321 maFontSize = rRenderContext.PixelToLogic(Size(0, nFontHeight));
322 aFont.SetFontSize(maFontSize);
323 aFont.SetTransparent(true);
324 rRenderContext.SetFont(aFont);
325 rRenderContext.GetFontCharMap(mxFontCharMap);
326 m_aItems.clear();
328
329 nX = aSize.Width() / COLUMN_COUNT;
330 nY = aSize.Height() / ROW_COUNT;
331
333
334 // rearrange CharSet element in sync with nX- and nY-multiples
335 Size aDrawSize(nX * COLUMN_COUNT, nY * ROW_COUNT);
336 m_nXGap = (aSize.Width() - aDrawSize.Width()) / 2;
337 m_nYGap = (aSize.Height() - aDrawSize.Height()) / 2;
338
339 mbRecalculateFont = false;
340}
341
343{
344 //scrollbar settings
345 int nLastRow = (getMaxCharCount() - 1 + COLUMN_COUNT) / COLUMN_COUNT;
346 mxScrollArea->vadjustment_configure(mxScrollArea->vadjustment_get_value(), 0, nLastRow, 1, ROW_COUNT - 1, ROW_COUNT);
347}
348
349void SvxSearchCharSet::SelectIndex(int nNewIndex, bool bFocus)
350{
351 if (!mxFontCharMap.is())
353
354 if( nNewIndex < 0 )
355 {
356 mxScrollArea->vadjustment_set_value(0);
357 nSelectedIndex = bFocus ? 0 : -1;
358 Invalidate();
359 }
360 else if( nNewIndex < FirstInView() )
361 {
362 // need to scroll up to see selected item
363 int nOldPos = mxScrollArea->vadjustment_get_value();
364 int nDelta = (FirstInView() - nNewIndex + COLUMN_COUNT-1) / COLUMN_COUNT;
365 mxScrollArea->vadjustment_set_value(nOldPos - nDelta);
366 nSelectedIndex = nNewIndex;
367 Invalidate();
368 }
369 else if( nNewIndex > LastInView() )
370 {
371 // need to scroll down to see selected item
372 int nOldPos = mxScrollArea->vadjustment_get_value();
373 int nDelta = (nNewIndex - LastInView() + COLUMN_COUNT) / COLUMN_COUNT;
374 mxScrollArea->vadjustment_set_value(nOldPos + nDelta);
375
376 if (nNewIndex < getMaxCharCount())
377 {
378 nSelectedIndex = nNewIndex;
379 Invalidate();
380 }
381 else if (nOldPos != mxScrollArea->vadjustment_get_value())
382 {
383 Invalidate();
384 }
385 }
386 else
387 {
388 nSelectedIndex = nNewIndex;
389 Invalidate();
390 }
391
392 if( nSelectedIndex >= 0 )
393 {
394#if 0
395 if( m_xAccessible.is() )
396 {
398 // Don't fire the focus event.
399 if ( bFocus )
400 m_xAccessible->fireEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, Any(), makeAny(pItem->GetAccessible()) ); // this call assures that m_pItem is set
401 else
402 m_xAccessible->fireEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS, Any(), makeAny(pItem->GetAccessible()) ); // this call assures that m_pItem is set
403
404 assert(pItem->m_xItem.is() && "No accessible created!");
405 Any aOldAny, aNewAny;
406 aNewAny <<= AccessibleStateType::FOCUSED;
407 // Don't fire the focus event.
408 if ( bFocus )
409 pItem->m_xItem->fireEvent( AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny );
410
411 aNewAny <<= AccessibleStateType::SELECTED;
412 pItem->m_xItem->fireEvent( AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny );
413 }
414#endif
415 aSelectHdl.Call(this);
416 }
417 aHighHdl.Call( this );
418}
419
421{
422}
423
425{
426 ItemsMap::iterator aFind = m_aItems.find(_nPos);
427 if ( aFind == m_aItems.end() )
428 {
429#if !ENABLE_WASM_STRIP_ACCESSIBILITY
430 OSL_ENSURE(m_xAccessible.is(), "Who wants to create a child of my table without a parent?");
431#endif
432 auto xItem = std::make_shared<svx::SvxShowCharSetItem>(*this,
433 m_xAccessible.get(), sal::static_int_cast< sal_uInt16 >(_nPos));
434 aFind = m_aItems.emplace(_nPos, xItem).first;
435 OUStringBuffer buf;
436 std::unordered_map<sal_Int32,sal_UCS4>::const_iterator got = m_aItemList.find (_nPos);
437 if (got != m_aItemList.end())
438 buf.appendUtf32(got->second);
439 aFind->second->maText = buf.makeStringAndClear();
440 Point pix = MapIndexToPixel( _nPos );
441 aFind->second->maRect = tools::Rectangle( Point( pix.X() + 1, pix.Y() + 1 ), Size(nX-1,nY-1) );
442 }
443
444 return aFind->second.get();
445}
446
448{
449 return m_aItemList.size();
450}
451
453{
454 m_aItemList.clear();
455 Invalidate();
456}
457
459{
460 m_aItemList.insert(std::make_pair(m_aItemList.size(), sChar));
461}
462
463/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
#define COLUMN_COUNT
Definition: charmap.hxx:46
#define ROW_COUNT
Definition: charmap.hxx:47
const StyleSettings & GetStyleSettings() const
static const AllSettings & GetSettings()
const vcl::KeyCode & GetKeyCode() const
const vcl::Font & GetFont() const
void SetFont(const vcl::Font &rNewFont)
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
void DrawRect(const tools::Rectangle &rRect)
void DrawLine(const Point &rStartPt, const Point &rEndPt)
bool GetTextBoundRect(tools::Rectangle &rRect, const OUString &rStr, sal_Int32 nBase=0, sal_Int32 nIndex=0, sal_Int32 nLen=-1, sal_uLong nLayoutWidth=0, KernArraySpan aDXArray=KernArraySpan(), o3tl::span< const sal_Bool > pKashidaArray={}, const SalLayoutGlyphs *pGlyphs=nullptr) const
void SetLineColor()
tools::Long GetTextWidth(const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, vcl::text::TextLayoutCache const *=nullptr, SalLayoutGlyphs const *const pLayoutCache=nullptr) const
void SetTextColor(const Color &rColor)
bool GetFontCharMap(FontCharMapRef &rxFontCharMap) const
void SetFillColor()
const Color & GetLineColor() const
const Color & GetTextColor() const
tools::Long GetTextHeight() const
void DrawText(const Point &rStartPt, const OUString &rStr, sal_Int32 nIndex=0, sal_Int32 nLen=-1, std::vector< tools::Rectangle > *pVector=nullptr, OUString *pDisplayText=nullptr, const SalLayoutGlyphs *pLayoutCache=nullptr)
const Color & GetFillColor() const
constexpr tools::Long Y() const
constexpr tools::Long X() const
constexpr tools::Long Height() const
constexpr tools::Long Width() const
const Color & GetFieldTextColor() const
const Color & GetShadowColor() const
const Color & GetLightColor() const
const Color & GetHighlightColor() const
const Color & GetFaceColor() const
const Color & GetHighlightTextColor() const
const Color & GetDisableColor() const
sal_UCS4 GetRangeMin() const
Definition: ucsubset.hxx:40
virtual void DrawChars_Impl(vcl::RenderContext &rRenderContext, int n1, int n2) override
void SelectCharacter(const Subset *sub)
std::unordered_map< sal_Int32, sal_UCS4 > m_aItemList
virtual bool KeyInput(const KeyEvent &rKEvt) override
virtual ~SvxSearchCharSet() override
virtual void SelectIndex(int index, bool bFocus=false) override
void AppendCharToList(sal_UCS4 cChar)
virtual void RecalculateFont(vcl::RenderContext &rRenderContext) override
virtual sal_Int32 getMaxCharCount() const override
SvxSearchCharSet(std::unique_ptr< weld::ScrolledWindow > pScrolledWindow, const VclPtr< VirtualDevice > &rDevice)
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect) override
virtual int LastInView() const override
virtual sal_UCS4 GetSelectCharacter() const override
virtual svx::SvxShowCharSetItem * ImplGetItem(int _nPos) override
FontCharMapRef mxFontCharMap
Definition: charmap.hxx:141
int FirstInView() const
Definition: charmap.cxx:349
VclPtr< VirtualDevice > mxVirDev
Definition: charmap.hxx:58
sal_Int32 nSelectedIndex
Definition: charmap.hxx:139
void InitSettings(vcl::RenderContext &rRenderContext)
Definition: charmap.cxx:642
void getFavCharacterList()
Definition: charmap.cxx:218
Point MapIndexToPixel(int) const
Definition: charmap.cxx:364
Link< SvxShowCharSet *, void > aHighHdl
Definition: charmap.hxx:126
tools::Long nX
Definition: charmap.hxx:133
std::unique_ptr< weld::ScrolledWindow > mxScrollArea
Definition: charmap.hxx:60
Link< SvxShowCharSet *, void > aSelectHdl
Definition: charmap.hxx:124
tools::Long nY
Definition: charmap.hxx:134
tools::Long m_nYGap
Definition: charmap.hxx:136
bool isFavChar(std::u16string_view sTitle, std::u16string_view rFont)
Definition: charmap.cxx:231
Link< SvxShowCharSet *, void > aDoubleClkHdl
Definition: charmap.hxx:122
Link< SvxShowCharSet *, void > aPreSelectHdl
Definition: charmap.hxx:127
bool mbRecalculateFont
Definition: charmap.hxx:144
tools::Long m_nXGap
Definition: charmap.hxx:135
ItemsMap m_aItems
Definition: charmap.hxx:121
virtual bool KeyInput(const KeyEvent &) override
Definition: charmap.cxx:383
tools::Rectangle getGridRectangle(const Point &rPointUL, const Size &rOutputSize) const
Definition: charmap.cxx:474
rtl::Reference< svx::SvxShowCharSetAcc > m_xAccessible
Definition: charmap.hxx:132
constexpr tools::Long GetWidth() const
constexpr tools::Long Top() const
constexpr tools::Long Right() const
constexpr tools::Long Left() const
constexpr tools::Long Bottom() const
constexpr bool IsEmpty() const
bool is() const
void SetFontSize(const Size &)
void SetTransparent(bool bTransparent)
void SetWeight(FontWeight)
void SetAlignment(TextAlign)
sal_uInt16 GetCode() const
sal_uInt16 GetModifier() const
Size const & GetOutputSizePixel() const
constexpr ::Color COL_TRANSPARENT(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
float y
float x
ALIGN_TOP
WEIGHT_LIGHT
OUString sName
sal_Int32 nIndex
constexpr sal_uInt16 KEY_RETURN
constexpr sal_uInt16 KEY_ESCAPE
constexpr sal_uInt16 KEY_HOME
constexpr sal_uInt16 KEY_LEFT
constexpr sal_uInt16 KEY_PAGEDOWN
constexpr sal_uInt16 KEY_TAB
constexpr sal_uInt16 KEY_UP
constexpr sal_uInt16 KEY_RIGHT
constexpr sal_uInt16 KEY_DOWN
constexpr sal_uInt16 KEY_SPACE
constexpr sal_uInt16 KEY_PAGEUP
constexpr sal_uInt16 KEY_END
int n2
int n1
int i
css::uno::Any SAL_CALL makeAny(const SharedUNOComponent< INTERFACE, COMPONENT > &value)
Simple struct to hold some information about the single items of the table.
Definition: charmapacc.hxx:44
css::uno::Reference< css::accessibility::XAccessible > GetAccessible()
Definition: charmapacc.cxx:59
rtl::Reference< SvxShowCharSetItemAcc > m_xItem
Definition: charmapacc.hxx:49
sal_uInt32 sal_UCS4
sal_Int32 _nPos