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 
36 using namespace ::com::sun::star::accessibility;
37 using namespace ::com::sun::star::uno;
38 using namespace ::com::sun::star;
39 
40 
41 SvxSearchCharSet::SvxSearchCharSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow, const VclPtr<VirtualDevice>& rVirDev)
42  : SvxShowCharSet(std::move(pScrolledWindow), rVirDev)
43  , nCount(0)
44 {
45 }
46 
48 {
49  int nIndex = FirstInView();
50  nIndex += ROW_COUNT * COLUMN_COUNT - 1;
51  int nCompare = nCount - 1;
52  if (nIndex > nCompare)
53  nIndex = nCompare;
54  return nIndex;
55 }
56 
58 {
59  vcl::KeyCode aCode = rKEvt.GetKeyCode();
60 
61  if (aCode.GetModifier())
62  return false;
63 
64  int tmpSelected = nSelectedIndex;
65 
66  bool bRet = true;
67 
68  switch (aCode.GetCode())
69  {
70  case KEY_SPACE:
71  aSelectHdl.Call( this );
72  break;
73  case KEY_LEFT:
74  --tmpSelected;
75  break;
76  case KEY_RIGHT:
77  ++tmpSelected;
78  break;
79  case KEY_UP:
80  tmpSelected -= COLUMN_COUNT;
81  break;
82  case KEY_DOWN:
83  tmpSelected += COLUMN_COUNT;
84  break;
85  case KEY_PAGEUP:
86  tmpSelected -= ROW_COUNT * COLUMN_COUNT;
87  break;
88  case KEY_PAGEDOWN:
89  tmpSelected += ROW_COUNT * COLUMN_COUNT;
90  break;
91  case KEY_HOME:
92  tmpSelected = 0;
93  break;
94  case KEY_END:
95  tmpSelected = nCount - 1;
96  break;
97  case KEY_TAB: // some fonts have a character at these unicode control codes
98  case KEY_ESCAPE:
99  case KEY_RETURN:
100  bRet = false;
101  tmpSelected = - 1; // mark as invalid
102  break;
103  default:
104  tmpSelected = -1;
105  bRet = false;
106  break;
107  }
108 
109  if ( tmpSelected >= 0 )
110  {
111  SelectIndex( tmpSelected, true );
112  aPreSelectHdl.Call( this );
113  }
114 
115  return bRet;
116 }
117 
119 {
120  if (!mxFontCharMap.is())
122 
123  // get next available char of current font
124  sal_UCS4 cChar = sub->GetRangeMin();
125  int nMapIndex = 0;
126 
127  while(cChar <= sub->GetRangeMax() && nMapIndex == 0)
128  {
129  auto it = std::find_if(m_aItemList.begin(), m_aItemList.end(),
130  [&cChar](const std::pair<const sal_Int32, sal_UCS4>& rItem) { return rItem.second == cChar; });
131  if (it != m_aItemList.end())
132  nMapIndex = it->first;
133  cChar++;
134  }
135 
136  if(nMapIndex == 0)
137  SelectIndex( 0 );
138  else
139  SelectIndex( nMapIndex );
140  aHighHdl.Call(this);
141  // move selected item to top row if not in focus
142  //TO.DO aVscrollSB->SetThumbPos( nMapIndex / COLUMN_COUNT );
143  Invalidate();
144 }
145 
147 {
148  InitSettings(rRenderContext);
149  RecalculateFont(rRenderContext);
150  DrawChars_Impl(rRenderContext, FirstInView(), LastInView());
151 }
152 
153 void SvxSearchCharSet::DrawChars_Impl(vcl::RenderContext& rRenderContext, int n1, int n2)
154 {
155  if (n1 > LastInView() || n2 < FirstInView())
156  return;
157 
158  Size aOutputSize(GetOutputSizePixel());
159 
160  int i;
161  for (i = 1; i < COLUMN_COUNT; ++i)
162  {
163  rRenderContext.DrawLine(Point(nX * i + m_nXGap, 0),
164  Point(nX * i + m_nXGap, aOutputSize.Height()));
165  }
166  for (i = 1; i < ROW_COUNT; ++i)
167  {
168  rRenderContext.DrawLine(Point(0, nY * i + m_nYGap),
169  Point(aOutputSize.Width(), nY * i + m_nYGap));
170  }
171  const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
172  const Color aWindowTextColor(rStyleSettings.GetFieldTextColor());
173  Color aHighlightColor(rStyleSettings.GetHighlightColor());
174  Color aHighlightTextColor(rStyleSettings.GetHighlightTextColor());
175  Color aFaceColor(rStyleSettings.GetFaceColor());
176  Color aLightColor(rStyleSettings.GetLightColor());
177  Color aShadowColor(rStyleSettings.GetShadowColor());
178 
179  int nTextHeight = rRenderContext.GetTextHeight();
180  tools::Rectangle aBoundRect;
181  for (i = n1; i <= n2; ++i)
182  {
183  Point pix = MapIndexToPixel(i);
184  int x = pix.X();
185  int y = pix.Y();
186 
187  OUStringBuffer buf;
188  std::unordered_map<sal_Int32, sal_UCS4>::const_iterator got = m_aItemList.find (i);
189  sal_UCS4 sName;
190 
191  if(got == m_aItemList.end())
192  continue;
193  else
194  sName = got->second;
195 
196  buf.appendUtf32(sName);
197  OUString aCharStr(buf.makeStringAndClear());
198  int nTextWidth = rRenderContext.GetTextWidth(aCharStr);
199  int tx = x + (nX - nTextWidth + 1) / 2;
200  int ty = y + (nY - nTextHeight + 1) / 2;
201  Point aPointTxTy(tx, ty);
202 
203  // adjust position before it gets out of bounds
204  if (rRenderContext.GetTextBoundRect(aBoundRect, aCharStr) && !aBoundRect.IsEmpty())
205  {
206  // zero advance width => use ink width to center glyph
207  if (!nTextWidth)
208  {
209  aPointTxTy.setX( x - aBoundRect.Left() + (nX - aBoundRect.GetWidth() + 1) / 2 );
210  }
211 
212  aBoundRect += aPointTxTy;
213 
214  // shift back vertically if needed
215  int nYLDelta = aBoundRect.Top() - y;
216  int nYHDelta = (y + nY) - aBoundRect.Bottom();
217  if (nYLDelta <= 0)
218  aPointTxTy.AdjustY( -(nYLDelta - 1) );
219  else if (nYHDelta <= 0)
220  aPointTxTy.AdjustY(nYHDelta - 1 );
221 
222  // shift back horizontally if needed
223  int nXLDelta = aBoundRect.Left() - x;
224  int nXHDelta = (x + nX) - aBoundRect.Right();
225  if (nXLDelta <= 0)
226  aPointTxTy.AdjustX( -(nXLDelta - 1) );
227  else if (nXHDelta <= 0)
228  aPointTxTy.AdjustX(nXHDelta - 1 );
229  }
230 
231  Color aTextCol = rRenderContext.GetTextColor();
232  if (i != nSelectedIndex)
233  {
234  rRenderContext.SetTextColor(aWindowTextColor);
235  rRenderContext.DrawText(aPointTxTy, aCharStr);
236  }
237  else
238  {
239  Color aLineCol = rRenderContext.GetLineColor();
240  Color aFillCol = rRenderContext.GetFillColor();
241  rRenderContext.SetLineColor();
242  Point aPointUL(x + 1, y + 1);
243  if (HasFocus())
244  {
245  rRenderContext.SetFillColor(aHighlightColor);
246  rRenderContext.DrawRect(getGridRectangle(aPointUL, aOutputSize));
247 
248  rRenderContext.SetTextColor(aHighlightTextColor);
249  rRenderContext.DrawText(aPointTxTy, aCharStr);
250  }
251  else
252  {
253  rRenderContext.SetFillColor(aFaceColor);
254  rRenderContext.DrawRect(getGridRectangle(aPointUL, aOutputSize));
255 
256  rRenderContext.SetLineColor(aLightColor);
257  rRenderContext.DrawLine(aPointUL, Point(x + nX - 1, y + 1));
258  rRenderContext.DrawLine(aPointUL, Point(x + 1, y + nY - 1));
259 
260  rRenderContext.SetLineColor(aShadowColor);
261  rRenderContext.DrawLine(Point(x + 1, y + nY - 1), Point(x + nX - 1, y + nY - 1));
262  rRenderContext.DrawLine(Point(x + nX - 1, y + nY - 1), Point(x + nX - 1, y + 1));
263 
264  rRenderContext.DrawText(aPointTxTy, aCharStr);
265  }
266  rRenderContext.SetLineColor(aLineCol);
267  rRenderContext.SetFillColor(aFillCol);
268  }
269  rRenderContext.SetTextColor(aTextCol);
270  }
271 }
272 
274 {
275  if( nSelectedIndex >= 0 )
276  {
277  std::unordered_map<sal_Int32,sal_UCS4>::const_iterator got = m_aItemList.find (nSelectedIndex);
278 
279  if(got == m_aItemList.end())
280  return 1;
281  else
282  return got->second;
283  }
284  return 1;
285 }
286 
288 {
289  if (!mbRecalculateFont)
290  return;
291 
292  Size aSize(GetOutputSizePixel());
293 
294  vcl::Font aFont = rRenderContext.GetFont();
295  aFont.SetWeight(WEIGHT_LIGHT);
296  aFont.SetAlignment(ALIGN_TOP);
297  int nFontHeight = (aSize.Height() - 5) * 2 / (3 * ROW_COUNT);
298  maFontSize = rRenderContext.PixelToLogic(Size(0, nFontHeight));
299  aFont.SetFontSize(maFontSize);
300  aFont.SetTransparent(true);
301  rRenderContext.SetFont(aFont);
302  rRenderContext.GetFontCharMap(mxFontCharMap);
304 
305  nX = aSize.Width() / COLUMN_COUNT;
306  nY = aSize.Height() / ROW_COUNT;
307 
308  //scrollbar settings -- error
309  int nLastRow = (nCount - 1 + COLUMN_COUNT) / COLUMN_COUNT;
310  mxScrollArea->vadjustment_configure(mxScrollArea->vadjustment_get_value(), 0, nLastRow, 1, ROW_COUNT - 1, ROW_COUNT);
311 
312  // rearrange CharSet element in sync with nX- and nY-multiples
313  Size aDrawSize(nX * COLUMN_COUNT, nY * ROW_COUNT);
314  m_nXGap = (aSize.Width() - aDrawSize.Width()) / 2;
315  m_nYGap = (aSize.Height() - aDrawSize.Height()) / 2;
316 
317  mbRecalculateFont = false;
318 }
319 
320 void SvxSearchCharSet::SelectIndex(int nNewIndex, bool bFocus)
321 {
322  if (!mxFontCharMap.is())
324 
325  if( nNewIndex < 0 )
326  {
327  mxScrollArea->vadjustment_set_value(0);
328  nSelectedIndex = bFocus ? 0 : -1;
329  Invalidate();
330  }
331  else if( nNewIndex < FirstInView() )
332  {
333  // need to scroll up to see selected item
334  int nOldPos = mxScrollArea->vadjustment_get_value();
335  int nDelta = (FirstInView() - nNewIndex + COLUMN_COUNT-1) / COLUMN_COUNT;
336  mxScrollArea->vadjustment_set_value(nOldPos - nDelta);
337  nSelectedIndex = nNewIndex;
338  Invalidate();
339  }
340  else if( nNewIndex > LastInView() )
341  {
342  // need to scroll down to see selected item
343  int nOldPos = mxScrollArea->vadjustment_get_value();
344  int nDelta = (nNewIndex - LastInView() + COLUMN_COUNT) / COLUMN_COUNT;
345  mxScrollArea->vadjustment_set_value(nOldPos + nDelta);
346 
347  if( nNewIndex < nCount )
348  {
349  nSelectedIndex = nNewIndex;
350  Invalidate();
351  }
352  else if (nOldPos != mxScrollArea->vadjustment_get_value())
353  {
354  Invalidate();
355  }
356  }
357  else
358  {
359  nSelectedIndex = nNewIndex;
360  Invalidate();
361  }
362 
363  if( nSelectedIndex >= 0 )
364  {
365 #if 0
366  if( m_xAccessible.is() )
367  {
369  // Don't fire the focus event.
370  if ( bFocus )
371  m_xAccessible->fireEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED, Any(), makeAny(pItem->GetAccessible()) ); // this call assures that m_pItem is set
372  else
373  m_xAccessible->fireEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED_NOFOCUS, Any(), makeAny(pItem->GetAccessible()) ); // this call assures that m_pItem is set
374 
375  assert(pItem->m_xItem.is() && "No accessible created!");
376  Any aOldAny, aNewAny;
377  aNewAny <<= AccessibleStateType::FOCUSED;
378  // Don't fire the focus event.
379  if ( bFocus )
380  pItem->m_xItem->fireEvent( AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny );
381 
382  aNewAny <<= AccessibleStateType::SELECTED;
383  pItem->m_xItem->fireEvent( AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny );
384  }
385 #endif
386  }
387  aHighHdl.Call( this );
388 }
389 
391 {
392 }
393 
395 {
396  ItemsMap::iterator aFind = m_aItems.find(_nPos);
397  if ( aFind == m_aItems.end() )
398  {
399 #if !ENABLE_WASM_STRIP_ACCESSIBILITY
400  OSL_ENSURE(m_xAccessible.is(), "Who wants to create a child of my table without a parent?");
401 #endif
402  auto xItem = std::make_shared<svx::SvxShowCharSetItem>(*this,
403  m_xAccessible.get(), sal::static_int_cast< sal_uInt16 >(_nPos));
404  aFind = m_aItems.emplace(_nPos, xItem).first;
405  OUStringBuffer buf;
406  std::unordered_map<sal_Int32,sal_UCS4>::const_iterator got = m_aItemList.find (_nPos);
407  if (got != m_aItemList.end())
408  buf.appendUtf32(got->second);
409  aFind->second->maText = buf.makeStringAndClear();
410  Point pix = MapIndexToPixel( _nPos );
411  aFind->second->maRect = tools::Rectangle( Point( pix.X() + 1, pix.Y() + 1 ), Size(nX-1,nY-1) );
412  }
413 
414  return aFind->second.get();
415 }
416 
418 {
419  return nCount;
420 }
421 
423 {
424  m_aItemList.clear();
425  nCount = 0;
426  Invalidate();
427 }
428 
430 {
431  m_aItemList.insert(std::make_pair(nCount++, sChar));
432 }
433 
434 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool is() const
const Color & GetTextColor() const
const Color & GetShadowColor() const
Link< SvxShowCharSet *, void > aHighHdl
Definition: charmap.hxx:124
bool GetFontCharMap(FontCharMapRef &rxFontCharMap) const
ItemsMap m_aItems
Definition: charmap.hxx:120
sal_Int32 nIndex
void SetFontSize(const Size &)
VclPtr< VirtualDevice > mxVirDev
Definition: charmap.hxx:58
void SelectCharacter(const Subset *sub)
sal_uInt32 sal_UCS4
const Color & GetHighlightTextColor() const
virtual bool KeyInput(const KeyEvent &rKEvt) override
std::unique_ptr< weld::ScrolledWindow > mxScrollArea
Definition: charmap.hxx:60
constexpr tools::Long Left() const
void AppendCharToList(sal_UCS4 cChar)
const StyleSettings & GetStyleSettings() const
static const AllSettings & GetSettings()
const Color & GetFaceColor() const
void SetWeight(FontWeight)
virtual void RecalculateFont(vcl::RenderContext &rRenderContext) override
sal_uInt16 GetCode() const
constexpr sal_uInt16 KEY_SPACE
SvxSearchCharSet(std::unique_ptr< weld::ScrolledWindow > pScrolledWindow, const VclPtr< VirtualDevice > &rDevice)
float x
sal_Int32 nSelectedIndex
Definition: charmap.hxx:137
WEIGHT_LIGHT
FontCharMapRef mxFontCharMap
Definition: charmap.hxx:139
const Color & GetFieldTextColor() const
constexpr sal_uInt16 KEY_UP
const Color & GetHighlightColor() const
Size const & GetOutputSizePixel() const
virtual sal_UCS4 GetSelectCharacter() const override
constexpr sal_uInt16 KEY_END
constexpr tools::Long Width() const
virtual void SelectIndex(int index, bool bFocus=false) override
virtual void DrawChars_Impl(vcl::RenderContext &rRenderContext, int n1, int n2) override
const vcl::Font & GetFont() const
int nCount
constexpr sal_uInt16 KEY_PAGEUP
const Color & GetLightColor() const
constexpr tools::Long GetWidth() const
bool GetTextBoundRect(tools::Rectangle &rRect, const OUString &rStr, sal_Int32 nBase=0, sal_Int32 nIndex=0, sal_Int32 nLen=-1, sal_uLong nLayoutWidth=0, o3tl::span< const sal_Int32 > pDXArray={}, const SalLayoutGlyphs *pGlyphs=nullptr) const
sal_uInt16 GetModifier() const
void DrawLine(const Point &rStartPt, const Point &rEndPt)
virtual svx::SvxShowCharSetItem * ImplGetItem(int _nPos) override
void DrawRect(const tools::Rectangle &rRect)
constexpr bool IsEmpty() const
float y
constexpr sal_uInt16 KEY_DOWN
void SetLineColor()
virtual void Paint(vcl::RenderContext &rRenderContext, const tools::Rectangle &rRect) override
bool mbRecalculateFont
Definition: charmap.hxx:143
tools::Long nY
Definition: charmap.hxx:132
int i
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
virtual int LastInView() const override
rtl::Reference< SvxShowCharSetItemAcc > m_xItem
Definition: charmapacc.hxx:51
OUString sName
constexpr sal_uInt16 KEY_HOME
constexpr tools::Long Right() const
void SetFillColor()
const Color & GetLineColor() const
void SetTextColor(const Color &rColor)
constexpr sal_uInt16 KEY_PAGEDOWN
constexpr tools::Long Top() const
std::unordered_map< sal_Int32, sal_UCS4 > m_aItemList
tools::Long m_nYGap
Definition: charmap.hxx:134
virtual sal_Int32 getMaxCharCount() const override
sal_UCS4 GetRangeMin() const
Definition: ucsubset.hxx:40
tools::Long nX
Definition: charmap.hxx:131
constexpr sal_uInt16 KEY_RETURN
int FirstInView() const
Definition: charmap.cxx:352
constexpr sal_uInt16 KEY_RIGHT
void SetAlignment(TextAlign)
constexpr tools::Long Bottom() const
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
css::uno::Reference< css::accessibility::XAccessible > GetAccessible()
Definition: charmapacc.cxx:59
const vcl::KeyCode & GetKeyCode() const
ALIGN_TOP
tools::Rectangle getGridRectangle(const Point &rPointUL, const Size &rOutputSize) const
Definition: charmap.cxx:471
Link< SvxShowCharSet *, void > aSelectHdl
Definition: charmap.hxx:122
void InitSettings(vcl::RenderContext &rRenderContext)
Definition: charmap.cxx:626
constexpr tools::Long Height() const
rtl::Reference< svx::SvxShowCharSetAcc > m_xAccessible
Definition: charmap.hxx:130
constexpr sal_uInt16 KEY_ESCAPE
void SetFont(const vcl::Font &rNewFont)
void SetTransparent(bool bTransparent)
tools::Long GetTextHeight() const
#define COLUMN_COUNT
Definition: charmap.hxx:46
Simple struct to hold some information about the single items of the table.
Definition: charmapacc.hxx:45
constexpr sal_uInt16 KEY_LEFT
void getFavCharacterList()
Definition: charmap.cxx:196
Point MapIndexToPixel(int) const
Definition: charmap.cxx:367
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)
tools::Long m_nXGap
Definition: charmap.hxx:133
const Color & GetFillColor() const
constexpr sal_uInt16 KEY_TAB
Link< SvxShowCharSet *, void > aPreSelectHdl
Definition: charmap.hxx:125
virtual ~SvxSearchCharSet() override
#define ROW_COUNT
Definition: charmap.hxx:47
css::uno::Any SAL_CALL makeAny(const SharedUNOComponent< INTERFACE, COMPONENT > &value)