Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / svx / source / dialog / searchcharmap.cxx
blobdc3ef7bcecabe325fb0814b95b31b88ed0b1bead
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <config_wasm_strip.h>
22 #include <vcl/event.hxx>
23 #include <vcl/svapp.hxx>
24 #include <vcl/settings.hxx>
25 #include <vcl/virdev.hxx>
27 #include <svx/ucsubset.hxx>
28 #include <unordered_map>
30 #include <svx/searchcharmap.hxx>
32 #include <charmapacc.hxx>
34 #include <rtl/ustrbuf.hxx>
36 using namespace ::com::sun::star::accessibility;
37 using namespace ::com::sun::star::uno;
38 using namespace ::com::sun::star;
41 SvxSearchCharSet::SvxSearchCharSet(std::unique_ptr<weld::ScrolledWindow> pScrolledWindow, const VclPtr<VirtualDevice>& rVirDev)
42 : SvxShowCharSet(std::move(pScrolledWindow), rVirDev)
46 int SvxSearchCharSet::LastInView() const
48 int nIndex = FirstInView();
49 nIndex += ROW_COUNT * COLUMN_COUNT - 1;
50 return std::min<int>(nIndex, getMaxCharCount() -1);
53 bool SvxSearchCharSet::KeyInput(const KeyEvent& rKEvt)
55 vcl::KeyCode aCode = rKEvt.GetKeyCode();
57 if (aCode.GetModifier())
58 return false;
60 int tmpSelected = nSelectedIndex;
62 bool bRet = true;
64 switch (aCode.GetCode())
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;
106 if ( tmpSelected >= 0 )
108 SelectIndex( tmpSelected, true );
109 aPreSelectHdl.Call( this );
112 return bRet;
115 void SvxSearchCharSet::SelectCharacter( const Subset* sub )
117 if (!mxFontCharMap.is())
118 RecalculateFont(*mxVirDev);
120 // get next available char of current font
121 sal_UCS4 cChar = sub->GetRangeMin();
122 int nMapIndex = 0;
124 while(cChar <= sub->GetRangeMax() && nMapIndex == 0)
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++;
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();
143 void SvxSearchCharSet::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&)
145 InitSettings(rRenderContext);
146 RecalculateFont(rRenderContext);
147 DrawChars_Impl(rRenderContext, FirstInView(), LastInView());
150 void SvxSearchCharSet::DrawChars_Impl(vcl::RenderContext& rRenderContext, int n1, int n2)
152 if (n1 > LastInView() || n2 < FirstInView())
153 return;
155 Size aOutputSize(GetOutputSizePixel());
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());
165 int i;
166 rRenderContext.SetLineColor(aShadowColor);
167 for (i = 1; i < COLUMN_COUNT; ++i)
169 rRenderContext.DrawLine(Point(nX * i + m_nXGap, 0),
170 Point(nX * i + m_nXGap, aOutputSize.Height()));
172 for (i = 1; i < ROW_COUNT; ++i)
174 rRenderContext.DrawLine(Point(0, nY * i + m_nYGap),
175 Point(aOutputSize.Width(), nY * i + m_nYGap));
178 int nTextHeight = rRenderContext.GetTextHeight();
179 tools::Rectangle aBoundRect;
180 for (i = n1; i <= n2; ++i)
182 Point pix = MapIndexToPixel(i);
183 int x = pix.X();
184 int y = pix.Y();
186 OUStringBuffer buf;
187 std::unordered_map<sal_Int32, sal_UCS4>::const_iterator got = m_aItemList.find (i);
188 sal_UCS4 sName;
190 if(got == m_aItemList.end())
191 continue;
192 else
193 sName = got->second;
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);
202 // adjust position before it gets out of bounds
203 if (rRenderContext.GetTextBoundRect(aBoundRect, aCharStr) && !aBoundRect.IsEmpty())
205 // zero advance width => use ink width to center glyph
206 if (!nTextWidth)
208 aPointTxTy.setX( x - aBoundRect.Left() + (nX - aBoundRect.GetWidth() + 1) / 2 );
211 aBoundRect += aPointTxTy;
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 );
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 );
230 // tdf#109214 - highlight the favorite characters
231 if (isFavChar(aCharStr, mxVirDev->GetFont().GetFamilyName()))
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);
243 Color aTextCol = rRenderContext.GetTextColor();
244 if (i != nSelectedIndex)
246 rRenderContext.SetTextColor(aWindowTextColor);
247 rRenderContext.DrawText(aPointTxTy, aCharStr);
249 else
251 Color aLineCol = rRenderContext.GetLineColor();
252 Color aFillCol = rRenderContext.GetFillColor();
253 rRenderContext.SetLineColor();
254 Point aPointUL(x + 1, y + 1);
255 if (HasFocus())
257 rRenderContext.SetFillColor(aHighlightColor);
258 rRenderContext.DrawRect(getGridRectangle(aPointUL, aOutputSize));
260 rRenderContext.SetTextColor(aHighlightTextColor);
261 rRenderContext.DrawText(aPointTxTy, aCharStr);
263 else
265 rRenderContext.SetFillColor(aFaceColor);
266 rRenderContext.DrawRect(getGridRectangle(aPointUL, aOutputSize));
268 rRenderContext.SetLineColor(aLightColor);
269 rRenderContext.DrawLine(aPointUL, Point(x + nX - 1, y + 1));
270 rRenderContext.DrawLine(aPointUL, Point(x + 1, y + nY - 1));
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));
276 rRenderContext.DrawText(aPointTxTy, aCharStr);
278 rRenderContext.SetLineColor(aLineCol);
279 rRenderContext.SetFillColor(aFillCol);
281 rRenderContext.SetTextColor(aTextCol);
284 // tdf#141319 - mark empty/unused cells
285 if (n2 - n1 < ROW_COUNT * COLUMN_COUNT)
287 rRenderContext.SetFillColor(rStyleSettings.GetDisableColor());
288 for (i = n2 - n1 + 1; i < ROW_COUNT * COLUMN_COUNT; i++)
290 rRenderContext.DrawRect(
291 tools::Rectangle(MapIndexToPixel(i + n1), Size(nX + 2, nY + 2)));
296 sal_UCS4 SvxSearchCharSet::GetSelectCharacter() const
298 if( nSelectedIndex >= 0 )
300 std::unordered_map<sal_Int32,sal_UCS4>::const_iterator got = m_aItemList.find (nSelectedIndex);
302 if(got == m_aItemList.end())
303 return 1;
304 else
305 return got->second;
307 return 1;
310 void SvxSearchCharSet::RecalculateFont(vcl::RenderContext& rRenderContext)
312 if (!mbRecalculateFont)
313 return;
315 Size aSize(GetOutputSizePixel());
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();
327 getFavCharacterList();
329 nX = aSize.Width() / COLUMN_COUNT;
330 nY = aSize.Height() / ROW_COUNT;
332 UpdateScrollRange();
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;
339 mbRecalculateFont = false;
342 void SvxSearchCharSet::UpdateScrollRange()
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);
349 void SvxSearchCharSet::SelectIndex(int nNewIndex, bool bFocus)
351 if (!mxFontCharMap.is())
352 RecalculateFont(*mxVirDev);
354 if( nNewIndex < 0 )
356 mxScrollArea->vadjustment_set_value(0);
357 nSelectedIndex = bFocus ? 0 : -1;
358 Invalidate();
360 else if( nNewIndex < FirstInView() )
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();
369 else if( nNewIndex > LastInView() )
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);
376 if (nNewIndex < getMaxCharCount())
378 nSelectedIndex = nNewIndex;
379 Invalidate();
381 else if (nOldPos != mxScrollArea->vadjustment_get_value())
383 Invalidate();
386 else
388 nSelectedIndex = nNewIndex;
389 Invalidate();
392 if( nSelectedIndex >= 0 )
394 #if 0
395 if( m_xAccessible.is() )
397 svx::SvxShowCharSetItem* pItem = ImplGetItem(nSelectedIndex);
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
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 );
411 aNewAny <<= AccessibleStateType::SELECTED;
412 pItem->m_xItem->fireEvent( AccessibleEventId::STATE_CHANGED, aOldAny, aNewAny );
414 #endif
415 aSelectHdl.Call(this);
417 aHighHdl.Call( this );
420 SvxSearchCharSet::~SvxSearchCharSet()
424 svx::SvxShowCharSetItem* SvxSearchCharSet::ImplGetItem( int _nPos )
426 ItemsMap::iterator aFind = m_aItems.find(_nPos);
427 if ( aFind == m_aItems.end() )
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) );
444 return aFind->second.get();
447 sal_Int32 SvxSearchCharSet::getMaxCharCount() const
449 return m_aItemList.size();
452 void SvxSearchCharSet::ClearPreviousData()
454 m_aItemList.clear();
455 Invalidate();
458 void SvxSearchCharSet::AppendCharToList(sal_UCS4 sChar)
460 m_aItemList.insert(std::make_pair(m_aItemList.size(), sChar));
463 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */