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