1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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())
60 int tmpSelected
= nSelectedIndex
;
64 switch (aCode
.GetCode())
67 return SvxShowCharSet::KeyInput(rKEvt
);
69 aDoubleClkHdl
.Call(this);
78 tmpSelected
-= COLUMN_COUNT
;
81 tmpSelected
+= COLUMN_COUNT
;
84 tmpSelected
-= ROW_COUNT
* COLUMN_COUNT
;
87 tmpSelected
+= ROW_COUNT
* COLUMN_COUNT
;
93 tmpSelected
= getMaxCharCount() - 1;
95 case KEY_TAB
: // some fonts have a character at these unicode control codes
98 tmpSelected
= - 1; // mark as invalid
106 if ( tmpSelected
>= 0 )
108 SelectIndex( tmpSelected
, true );
109 aPreSelectHdl
.Call( this );
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();
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
;
136 SelectIndex( nMapIndex
);
138 // move selected item to top row if not in focus
139 //TO.DO aVscrollSB->SetThumbPos( nMapIndex / COLUMN_COUNT );
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())
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());
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
);
187 std::unordered_map
<sal_Int32
, sal_UCS4
>::const_iterator got
= m_aItemList
.find (i
);
190 if(got
== m_aItemList
.end())
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
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();
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();
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
);
237 rRenderContext
.DrawRect(tools::Rectangle(Point(x
- 1, y
- 1), Size(nX
+ 3, nY
+ 3)), 1, 1);
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
);
251 Color aLineCol
= rRenderContext
.GetLineColor();
252 Color aFillCol
= rRenderContext
.GetFillColor();
253 rRenderContext
.SetLineColor();
254 Point
aPointUL(x
+ 1, y
+ 1);
257 rRenderContext
.SetFillColor(aHighlightColor
);
258 rRenderContext
.DrawRect(getGridRectangle(aPointUL
, aOutputSize
));
260 rRenderContext
.SetTextColor(aHighlightTextColor
);
261 rRenderContext
.DrawText(aPointTxTy
, aCharStr
);
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())
310 void SvxSearchCharSet::RecalculateFont(vcl::RenderContext
& rRenderContext
)
312 if (!mbRecalculateFont
)
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
);
327 getFavCharacterList();
329 nX
= aSize
.Width() / COLUMN_COUNT
;
330 nY
= aSize
.Height() / ROW_COUNT
;
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()
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
);
356 mxScrollArea
->vadjustment_set_value(0);
357 nSelectedIndex
= bFocus
? 0 : -1;
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
;
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
;
381 else if (nOldPos
!= mxScrollArea
->vadjustment_get_value())
388 nSelectedIndex
= nNewIndex
;
392 if( nSelectedIndex
>= 0 )
395 if( m_xAccessible
.is() )
397 svx::SvxShowCharSetItem
* pItem
= ImplGetItem(nSelectedIndex
);
398 // Don't fire the focus event.
400 m_xAccessible
->fireEvent( AccessibleEventId::ACTIVE_DESCENDANT_CHANGED
, Any(), makeAny(pItem
->GetAccessible()) ); // this call assures that m_pItem is set
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.
409 pItem
->m_xItem
->fireEvent( AccessibleEventId::STATE_CHANGED
, aOldAny
, aNewAny
);
411 aNewAny
<<= AccessibleStateType::SELECTED
;
412 pItem
->m_xItem
->fireEvent( AccessibleEventId::STATE_CHANGED
, aOldAny
, aNewAny
);
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?");
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
;
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()
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: */