/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace css; SvxCharacterMap::SvxCharacterMap(weld::Widget* pParent, const SfxItemSet* pSet, css::uno::Reference xFrame) : SfxDialogController(pParent, u"cui/ui/specialcharacters.ui"_ustr, u"SpecialCharactersDialog"_ustr) , m_xVirDev(VclPtr::Create()) , isSearchMode(true) , m_xFrame(std::move(xFrame)) , m_aCharmapContents(*m_xBuilder, m_xVirDev, true) , m_aShowChar(m_xVirDev) , m_xOKBtn(m_xFrame.is() ? m_xBuilder->weld_button(u"insert"_ustr) : m_xBuilder->weld_button(u"ok"_ustr)) , m_xFontText(m_xBuilder->weld_label(u"fontft"_ustr)) , m_xFontLB(m_xBuilder->weld_combo_box(u"fontlb"_ustr)) , m_xSubsetText(m_xBuilder->weld_label(u"subsetft"_ustr)) , m_xSubsetLB(m_xBuilder->weld_combo_box(u"subsetlb"_ustr)) , m_xSearchText(m_xBuilder->weld_entry(u"search"_ustr)) , m_xHexCodeText(m_xBuilder->weld_entry(u"hexvalue"_ustr)) , m_xDecimalCodeText(m_xBuilder->weld_entry(u"decimalvalue"_ustr)) , m_xFavouritesBtn(m_xBuilder->weld_button(u"favbtn"_ustr)) , m_xCharName(m_xBuilder->weld_label(u"charname"_ustr)) , m_xShowChar(new weld::CustomWeld(*m_xBuilder, u"showchar"_ustr, m_aShowChar)) , m_xShowSet(new SvxShowCharSet(m_xBuilder->weld_scrolled_window(u"showscroll"_ustr, true), m_xVirDev)) , m_xShowSetArea(new weld::CustomWeld(*m_xBuilder, u"showcharset"_ustr, *m_xShowSet)) , m_xSearchSet(new SvxSearchCharSet(m_xBuilder->weld_scrolled_window(u"searchscroll"_ustr, true), m_xVirDev)) , m_xSearchSetArea(new weld::CustomWeld(*m_xBuilder, u"searchcharset"_ustr, *m_xSearchSet)) { m_aShowChar.SetCentered(true); m_xFontLB->make_sorted(); //lock the size request of this widget to the width of all possible entries fillAllSubsets(*m_xSubsetLB); m_xSubsetLB->set_size_request(m_xSubsetLB->get_preferred_size().Width(), -1); m_xCharName->set_size_request(m_aShowChar.get_preferred_size().Width(), m_xCharName->get_text_height() * 4); //lock the size request of this widget to the width of the original .ui string m_xHexCodeText->set_size_request(m_xHexCodeText->get_preferred_size().Width(), -1); init(); const SfxInt32Item* pCharItem = SfxItemSet::GetItem(pSet, SID_ATTR_CHAR, false); if ( pCharItem ) SetChar( pCharItem->GetValue() ); const SfxBoolItem* pDisableItem = SfxItemSet::GetItem(pSet, FN_PARAM_2, false); if ( pDisableItem && pDisableItem->GetValue() ) DisableFontSelection(); const SvxFontItem* pFontItem = SfxItemSet::GetItem(pSet, SID_ATTR_CHAR_FONT, false); const SfxStringItem* pFontNameItem = SfxItemSet::GetItem(pSet, SID_FONT_NAME, false); if ( pFontItem ) { vcl::Font aTmpFont( pFontItem->GetFamilyName(), pFontItem->GetStyleName(), GetCharFont().GetFontSize() ); aTmpFont.SetCharSet( pFontItem->GetCharSet() ); aTmpFont.SetPitch( pFontItem->GetPitch() ); SetCharFont( aTmpFont ); } else if ( pFontNameItem ) { vcl::Font aTmpFont( GetCharFont() ); aTmpFont.SetFamilyName( pFontNameItem->GetValue() ); SetCharFont( aTmpFont ); } m_xOutputSet.reset(new SfxAllItemSet(pSet ? *pSet->GetPool() : SfxGetpApp()->GetPool())); m_xShowSet->Show(); m_xSearchSet->Hide(); } void SvxCharacterMap::prepForRun() { if( SvxShowCharSet::getSelectedChar() == ' ') { m_xOKBtn->set_sensitive(false); setFavButtonState(u"", u""); } else { sal_UCS4 cChar = m_xShowSet->GetSelectCharacter(); // using the new UCS4 constructor OUString aOUStr( &cChar, 1 ); m_aShowChar.SetText(aOUStr); setFavButtonState(aOUStr, m_aShowChar.GetFont().GetFamilyName()); m_xOKBtn->set_sensitive(true); } } short SvxCharacterMap::run() { prepForRun(); return SfxDialogController::run(); } void SvxCharacterMap::SetChar( sal_UCS4 c ) { m_xShowSet->SelectCharacter( c ); setFavButtonState(OUString(&c, 1), aFont.GetFamilyName()); } sal_UCS4 SvxCharacterMap::GetChar() const { return m_aShowChar.GetText().iterateCodePoints(&o3tl::temporary(sal_Int32(0))); } void SvxCharacterMap::DisableFontSelection() { m_xFontText->set_sensitive(false); m_xFontLB->set_sensitive(false); } IMPL_LINK_NOARG(SvxCharacterMap, UpdateFavHdl, void*, void) { m_xShowSet->getFavCharacterList(); m_xSearchSet->getFavCharacterList(); // tdf#109214 - redraw highlight of the favorite characters m_xShowSet->Invalidate(); } void SvxCharacterMap::init() { aFont = m_xVirDev->GetFont(); aFont.SetTransparent( true ); aFont.SetFamily( FAMILY_DONTKNOW ); aFont.SetPitch( PITCH_DONTKNOW ); aFont.SetCharSet( RTL_TEXTENCODING_DONTKNOW ); OUString aDefStr( aFont.GetFamilyName() ); OUString aLastName; int nCount = m_xVirDev->GetFontFaceCollectionCount(); std::vector aEntries; aEntries.reserve(nCount); for (int i = 0; i < nCount; ++i) { OUString aFontName( m_xVirDev->GetFontMetricFromCollection( i ).GetFamilyName() ); if (aFontName != aLastName) { aLastName = aFontName; aEntries.emplace_back(aFontName, OUString::number(i)); } } m_xFontLB->insert_vector(aEntries, true); // the font may not be in the list => // try to find a font name token in list and select found font, // else select topmost entry bool bFound = (m_xFontLB->find_text(aDefStr) != -1); if (!bFound) { sal_Int32 nIndex = 0; do { OUString aToken = aDefStr.getToken(0, ';', nIndex); if (m_xFontLB->find_text(aToken) != -1) { aDefStr = aToken; bFound = true; break; } } while ( nIndex >= 0 ); } if (bFound) m_xFontLB->set_active_text(aDefStr); else if (m_xFontLB->get_count() ) m_xFontLB->set_active(0); FontSelectHdl(*m_xFontLB); if (m_xSubsetLB->get_count()) m_xSubsetLB->set_active(0); m_xFontLB->connect_changed(LINK( this, SvxCharacterMap, FontSelectHdl)); m_xSubsetLB->connect_changed(LINK( this, SvxCharacterMap, SubsetSelectHdl)); m_xOKBtn->connect_clicked(LINK(this, SvxCharacterMap, InsertClickHdl)); m_xOKBtn->show(); m_xShowSet->SetDoubleClickHdl( LINK( this, SvxCharacterMap, CharDoubleClickHdl ) ); m_xShowSet->SetReturnKeyPressHdl(LINK(this, SvxCharacterMap, ReturnKeypressOnCharHdl)); m_xShowSet->SetSelectHdl( LINK( this, SvxCharacterMap, CharSelectHdl ) ); m_xShowSet->SetHighlightHdl( LINK( this, SvxCharacterMap, CharHighlightHdl ) ); m_xShowSet->SetPreSelectHdl( LINK( this, SvxCharacterMap, CharPreSelectHdl ) ); m_xShowSet->SetFavClickHdl( LINK( this, SvxCharacterMap, FavClickHdl ) ); m_xSearchSet->SetDoubleClickHdl( LINK( this, SvxCharacterMap, CharDoubleClickHdl ) ); m_xSearchSet->SetReturnKeyPressHdl(LINK(this, SvxCharacterMap, ReturnKeypressOnCharHdl)); m_xSearchSet->SetSelectHdl( LINK( this, SvxCharacterMap, CharSelectHdl ) ); m_xSearchSet->SetHighlightHdl( LINK( this, SvxCharacterMap, SearchCharHighlightHdl ) ); m_xSearchSet->SetPreSelectHdl( LINK( this, SvxCharacterMap, CharPreSelectHdl ) ); m_xSearchSet->SetFavClickHdl( LINK( this, SvxCharacterMap, FavClickHdl ) ); m_xDecimalCodeText->connect_changed( LINK( this, SvxCharacterMap, DecimalCodeChangeHdl ) ); m_xHexCodeText->connect_changed( LINK( this, SvxCharacterMap, HexCodeChangeHdl ) ); m_xFavouritesBtn->connect_clicked( LINK(this, SvxCharacterMap, FavSelectHdl)); // tdf#117038 set the buttons width to its max possible width so it doesn't // make layout change when the label changes m_xFavouritesBtn->set_label(SvxResId(RID_SVXSTR_REMOVE_FAVORITES)); auto nMaxWidth = m_xFavouritesBtn->get_preferred_size().Width(); m_xFavouritesBtn->set_label(SvxResId(RID_SVXSTR_ADD_FAVORITES)); nMaxWidth = std::max(nMaxWidth, m_xFavouritesBtn->get_preferred_size().Width()); m_xFavouritesBtn->set_size_request(nMaxWidth, -1); if( SvxShowCharSet::getSelectedChar() == ' ') { m_xOKBtn->set_sensitive(false); } else { sal_UCS4 cChar = m_xShowSet->GetSelectCharacter(); // using the new UCS4 constructor OUString aOUStr( &cChar, 1 ); m_aShowChar.SetText(aOUStr); setFavButtonState(aOUStr, aDefStr); m_xOKBtn->set_sensitive(true); } m_aCharmapContents.init(m_xFrame.is(), LINK(this, SvxCharacterMap, CharClickHdl), LINK(this, SvxCharacterMap, UpdateFavHdl), Link()); setCharName(90); m_xSearchText->connect_focus_in(LINK( this, SvxCharacterMap, SearchFieldGetFocusHdl )); m_xSearchText->connect_changed(LINK(this, SvxCharacterMap, SearchUpdateHdl)); } void SvxCharacterMap::setFavButtonState(std::u16string_view sTitle, std::u16string_view rFont) { if(sTitle.empty() || rFont.empty()) { m_xFavouritesBtn->set_sensitive(false); return; } else m_xFavouritesBtn->set_sensitive(true); if (m_aCharmapContents.isFavChar(sTitle, rFont)) { m_xFavouritesBtn->set_label(SvxResId(RID_SVXSTR_REMOVE_FAVORITES)); } else { if (m_aCharmapContents.FavCharListIsFull()) m_xFavouritesBtn->set_sensitive(false); m_xFavouritesBtn->set_label(SvxResId(RID_SVXSTR_ADD_FAVORITES)); } } void SvxCharacterMap::SetCharFont( const vcl::Font& rFont ) { // first get the underlying info in order to get font names // like "Times New Roman;Times" resolved vcl::Font aTmp(m_xVirDev->GetFontMetric(rFont)); // tdf#56363 - search font family without the font feature after the colon OUString sFontFamilyName = aTmp.GetFamilyName(); if (const sal_Int32 nIndex = sFontFamilyName.indexOf(":"); nIndex != -1) sFontFamilyName = sFontFamilyName.copy(0, nIndex); if (sFontFamilyName == "StarSymbol" && m_xFontLB->find_text(sFontFamilyName) == -1) { //if for some reason, like font in an old document, StarSymbol is requested and it's not available, then //try OpenSymbol instead aTmp.SetFamilyName(u"OpenSymbol"_ustr); } if (m_xFontLB->find_text(sFontFamilyName) == -1) return; m_xFontLB->set_active_text(sFontFamilyName); aFont = std::move(aTmp); FontSelectHdl(*m_xFontLB); if (m_xSubsetLB->get_count()) m_xSubsetLB->set_active(0); } void SvxCharacterMap::fillAllSubsets(weld::ComboBox& rListBox) { SubsetMap aAll(nullptr); std::vector aEntries; for (auto & subset : aAll.GetSubsetMap()) aEntries.emplace_back(subset.GetName()); rListBox.insert_vector(aEntries, true); } void SvxCharacterMap::insertCharToDoc(const OUString& sGlyph) { if(sGlyph.isEmpty()) return; if (m_xFrame.is()) { uno::Sequence aArgs{ comphelper::makePropertyValue(u"Symbols"_ustr, sGlyph), comphelper::makePropertyValue(u"FontName"_ustr, aFont.GetFamilyName()) }; comphelper::dispatchCommand(u".uno:InsertSymbol"_ustr, m_xFrame, aArgs); m_aCharmapContents.updateRecentCharacterList(sGlyph, aFont.GetFamilyName()); } else { sal_UCS4 cChar = sGlyph.iterateCodePoints(&o3tl::temporary(sal_Int32(0))); const SfxItemPool* pPool = m_xOutputSet->GetPool(); m_xOutputSet->Put( SfxStringItem( SID_CHARMAP, sGlyph ) ); m_xOutputSet->Put( SvxFontItem( aFont.GetFamilyType(), aFont.GetFamilyName(), aFont.GetStyleName(), aFont.GetPitch(), aFont.GetCharSet(), pPool->GetWhichIDFromSlotID(SID_ATTR_CHAR_FONT) ) ); m_xOutputSet->Put( SfxStringItem( SID_FONT_NAME, aFont.GetFamilyName() ) ); m_xOutputSet->Put( SfxInt32Item( SID_ATTR_CHAR, cChar ) ); } } IMPL_LINK_NOARG(SvxCharacterMap, FontSelectHdl, weld::ComboBox&, void) { const sal_uInt32 nFont = m_xFontLB->get_active_id().toUInt32(); aFont = m_xVirDev->GetFontMetricFromCollection(nFont); aFont.SetWeight( WEIGHT_DONTKNOW ); aFont.SetItalic( ITALIC_NONE ); aFont.SetWidthType( WIDTH_DONTKNOW ); aFont.SetPitch( PITCH_DONTKNOW ); aFont.SetFamily( FAMILY_DONTKNOW ); // notify children using this font m_xShowSet->SetFont( aFont ); m_xSearchSet->SetFont( aFont ); m_aShowChar.SetFont( aFont ); // setup unicode subset listbar with font specific subsets, // hide unicode subset listbar for symbol fonts // TODO: get info from the Font once it provides it pSubsetMap.reset(); m_xSubsetLB->clear(); bool bNeedSubset = (aFont.GetCharSet() != RTL_TEXTENCODING_SYMBOL); if (bNeedSubset) { FontCharMapRef xFontCharMap = m_xShowSet->GetFontCharMap(); pSubsetMap.reset(new SubsetMap( xFontCharMap )); // update subset listbox for new font's unicode subsets for (auto const& subset : pSubsetMap->GetSubsetMap()) { m_xSubsetLB->append(weld::toId(&subset), subset.GetName()); // NOTE: subset must live at least as long as the selected font } if (m_xSubsetLB->get_count() <= 1) bNeedSubset = false; } m_xSubsetText->set_sensitive(bNeedSubset); m_xSubsetLB->set_sensitive(bNeedSubset); if (isSearchMode) { // tdf#137294 do this after modifying m_xSubsetLB sensitivity to // restore insensitive for the search case SearchUpdateHdl(*m_xSearchText); SearchCharHighlightHdl(m_xSearchSet.get()); } // tdf#118304 reselect current glyph to see if it's still there in new font selectCharByCode(Radix::hexadecimal); } void SvxCharacterMap::toggleSearchView(bool state) { isSearchMode = state; m_xHexCodeText->set_editable(!state); m_xDecimalCodeText->set_editable(!state); m_xSubsetLB->set_sensitive(!state); if(state) { m_xSearchSet->Show(); m_xShowSet->Hide(); } else { m_xSearchSet->Hide(); m_xShowSet->Show(); } } void SvxCharacterMap::setCharName(sal_UCS4 nDecimalValue) { /* get the character name */ UErrorCode errorCode = U_ZERO_ERROR; // icu has a private uprv_getMaxCharNameLength function which returns the max possible // length of this property. Unicode 3.2 max char name length was 83 char buffer[100]; u_charName(nDecimalValue, U_UNICODE_CHAR_NAME, buffer, sizeof(buffer), &errorCode); if (U_SUCCESS(errorCode)) m_xCharName->set_label(OUString::createFromAscii(buffer)); } IMPL_LINK_NOARG(SvxCharacterMap, SubsetSelectHdl, weld::ComboBox&, void) { const sal_Int32 nPos = m_xSubsetLB->get_active(); const Subset* pSubset = weld::fromId(m_xSubsetLB->get_active_id()); if( pSubset && !isSearchMode) { sal_UCS4 cFirst = pSubset->GetRangeMin(); m_xShowSet->SelectCharacter( cFirst ); setFavButtonState(OUString(&cFirst, 1), aFont.GetFamilyName()); m_xSubsetLB->set_active(nPos); } else if( pSubset && isSearchMode) { m_xSearchSet->SelectCharacter( pSubset ); const Subset* curSubset = nullptr; if( pSubsetMap ) curSubset = pSubsetMap->GetSubsetByUnicode( m_xSearchSet->GetSelectCharacter() ); if( curSubset ) m_xSubsetLB->set_active_text(curSubset->GetName()); else m_xSubsetLB->set_active(-1); sal_UCS4 sChar = m_xSearchSet->GetSelectCharacter(); setFavButtonState(OUString(&sChar, 1), aFont.GetFamilyName()); } } IMPL_LINK_NOARG(SvxCharacterMap, SearchFieldGetFocusHdl, weld::Widget&, void) { m_xOKBtn->set_sensitive(false); } IMPL_LINK_NOARG(SvxCharacterMap, SearchUpdateHdl, weld::Entry&, void) { if (!m_xSearchText->get_text().isEmpty()) { m_xSearchSet->ClearPreviousData(); OUString aKeyword = m_xSearchText->get_text().trim().toAsciiLowerCase(); OUString hex_code; if (std::u16string_view rest; aKeyword.startsWith("u+", &rest)) if (auto n = o3tl::toInt32(rest, 16)) hex_code = OUString::number(n, 16); // this removes leading zeroes toggleSearchView(true); FontCharMapRef xFontCharMap = m_xSearchSet->GetFontCharMap(); for (sal_UCS4 ucs4 = xFontCharMap->GetFirstChar();; ucs4 = xFontCharMap->GetNextChar(ucs4)) { bool bAdded = false; UErrorCode errorCode = U_ZERO_ERROR; char buffer[100]; u_charName(ucs4, U_UNICODE_CHAR_NAME, buffer, sizeof(buffer), &errorCode); if (U_SUCCESS(errorCode)) { OUString sName = OUString::createFromAscii(buffer); if (!sName.isEmpty() && sName.toAsciiLowerCase().indexOf(aKeyword) >= 0) { m_xSearchSet->AppendCharToList(ucs4); bAdded = true; } } if (!bAdded && !hex_code.isEmpty()) { OUString actual_number = OUString::number(ucs4, 16); if (actual_number.startsWith(hex_code)) m_xSearchSet->AppendCharToList(ucs4); } if (ucs4 == xFontCharMap->GetLastChar()) break; } m_xSearchSet->UpdateScrollRange(); } else { toggleSearchView(false); } } IMPL_LINK(SvxCharacterMap, CharClickHdl, SvxCharView*, rView, void) { rView->GrabFocus(); SetCharFont(rView->GetFont()); m_aShowChar.SetText( rView->GetText() ); m_aShowChar.SetFont(rView->GetFont()); m_aShowChar.Invalidate(); setFavButtonState(rView->GetText(), rView->GetFont().GetFamilyName());//check state // Get the hexadecimal code OUString charValue = rView->GetText(); sal_UCS4 cChar = charValue.iterateCodePoints(&o3tl::temporary(sal_Int32(1)), -1); OUString aHexText = OUString::number(cChar, 16).toAsciiUpperCase(); // Get the decimal code OUString aDecimalText = OUString::number(cChar); m_xHexCodeText->set_text(aHexText); m_xDecimalCodeText->set_text(aDecimalText); setCharName(cChar); rView->Invalidate(); m_xOKBtn->set_sensitive(true); } void SvxCharacterMap::insertSelectedCharacter(const SvxShowCharSet* pCharSet) { assert(pCharSet); sal_UCS4 cChar = pCharSet->GetSelectCharacter(); // using the new UCS4 constructor OUString aOUStr( &cChar, 1 ); setFavButtonState(aOUStr, aFont.GetFamilyName()); insertCharToDoc(aOUStr); } IMPL_LINK(SvxCharacterMap, CharDoubleClickHdl, SvxShowCharSet*, pCharSet, void) { insertSelectedCharacter(pCharSet); } IMPL_LINK_NOARG(SvxCharacterMap, CharSelectHdl, SvxShowCharSet*, void) { m_xOKBtn->set_sensitive(true); } IMPL_LINK(SvxCharacterMap, ReturnKeypressOnCharHdl, SvxShowCharSet*, pCharSet, void) { insertSelectedCharacter(pCharSet); m_xDialog->response(RET_OK); } IMPL_LINK_NOARG(SvxCharacterMap, InsertClickHdl, weld::Button&, void) { OUString sChar = m_aShowChar.GetText(); insertCharToDoc(sChar); // Need to update recent character list, when OK button does not insert if(!m_xFrame.is()) m_aCharmapContents.updateRecentCharacterList(sChar, aFont.GetFamilyName()); m_xDialog->response(RET_OK); } IMPL_LINK_NOARG(SvxCharacterMap, FavSelectHdl, weld::Button&, void) { if (m_xFavouritesBtn->get_label().match(SvxResId(RID_SVXSTR_ADD_FAVORITES))) { m_aCharmapContents.updateFavCharacterList(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName()); setFavButtonState(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName()); } else { m_aCharmapContents.deleteFavCharacterFromList(m_aShowChar.GetText(), m_aShowChar.GetFont().GetFamilyName()); m_xFavouritesBtn->set_label(SvxResId(RID_SVXSTR_ADD_FAVORITES)); m_xFavouritesBtn->set_sensitive(false); } m_aCharmapContents.updateFavCharControl(); } IMPL_LINK_NOARG(SvxCharacterMap, FavClickHdl, SvxShowCharSet*, void) { m_aCharmapContents.getFavCharacterList(); m_aCharmapContents.updateFavCharControl(); } IMPL_LINK_NOARG(SvxCharacterMap, CharHighlightHdl, SvxShowCharSet*, void) { OUString aText; sal_UCS4 cChar = m_xShowSet->GetSelectCharacter(); bool bSelect = (cChar > 0); // show char sample if ( bSelect ) { // using the new UCS4 constructor aText = OUString( &cChar, 1 ); // Get the hexadecimal code OUString aHexText = OUString::number(cChar, 16).toAsciiUpperCase(); // Get the decimal code OUString aDecimalText = OUString::number(cChar); setCharName(cChar); // Update the hex and decimal codes only if necessary if (!m_xHexCodeText->get_text().equalsIgnoreAsciiCase(aHexText)) m_xHexCodeText->set_text(aHexText); if (m_xDecimalCodeText->get_text() != aDecimalText) m_xDecimalCodeText->set_text( aDecimalText ); const Subset* pSubset = nullptr; if( pSubsetMap ) pSubset = pSubsetMap->GetSubsetByUnicode( cChar ); if( pSubset ) m_xSubsetLB->set_active_text(pSubset->GetName()); else m_xSubsetLB->set_active(-1); } m_aShowChar.SetText( aText ); m_aShowChar.SetFont( aFont ); m_aShowChar.Invalidate(); setFavButtonState(aText, aFont.GetFamilyName()); } IMPL_LINK_NOARG(SvxCharacterMap, SearchCharHighlightHdl, SvxShowCharSet*, void) { OUString aText; sal_UCS4 cChar = m_xSearchSet->GetSelectCharacter(); bool bSelect = (cChar > 0); // show char sample if ( bSelect ) { aText = OUString( &cChar, 1 ); // Get the hexadecimal code OUString aHexText = OUString::number(cChar, 16).toAsciiUpperCase(); // Get the decimal code OUString aDecimalText = OUString::number(cChar); setCharName(cChar); // Update the hex and decimal codes only if necessary if (!m_xHexCodeText->get_text().equalsIgnoreAsciiCase(aHexText)) m_xHexCodeText->set_text(aHexText); if (m_xDecimalCodeText->get_text() != aDecimalText) m_xDecimalCodeText->set_text( aDecimalText ); const Subset* pSubset = nullptr; if( pSubsetMap ) pSubset = pSubsetMap->GetSubsetByUnicode( cChar ); if( pSubset ) m_xSubsetLB->set_active_text(pSubset->GetName()); else m_xSubsetLB->set_active(-1); } if(m_xSearchSet->HasFocus()) { m_aShowChar.SetText( aText ); m_aShowChar.SetFont( aFont ); m_aShowChar.Invalidate(); setFavButtonState(aText, aFont.GetFamilyName()); } } void SvxCharacterMap::selectCharByCode(Radix radix) { OUString aCodeString; switch(radix) { case Radix::decimal: aCodeString = m_xDecimalCodeText->get_text(); break; case Radix::hexadecimal: aCodeString = m_xHexCodeText->get_text(); break; } // Convert the code back to a character using the appropriate radix sal_UCS4 cChar = aCodeString.toUInt32(static_cast (radix)); // Use FontCharMap::HasChar(sal_UCS4 cChar) to see if the desired character is in the font FontCharMapRef xFontCharMap = m_xShowSet->GetFontCharMap(); if (xFontCharMap->HasChar(cChar)) // Select the corresponding character SetChar(cChar); else { m_xCharName->set_label(SvxResId(RID_SVXSTR_MISSING_CHAR)); m_aShowChar.SetText(u" "_ustr); switch(radix) { case Radix::decimal: m_xHexCodeText->set_text(OUString::number(cChar, 16)); break; case Radix::hexadecimal: m_xDecimalCodeText->set_text(OUString::number(cChar)); break; } } } IMPL_LINK_NOARG(SvxCharacterMap, DecimalCodeChangeHdl, weld::Entry&, void) { selectCharByCode(Radix::decimal); } IMPL_LINK_NOARG(SvxCharacterMap, HexCodeChangeHdl, weld::Entry&, void) { selectCharByCode(Radix::hexadecimal); } IMPL_LINK(SvxCharacterMap, CharPreSelectHdl, SvxShowCharSet*, pCharSet, void) { assert(pCharSet); // adjust subset selection if( pSubsetMap ) { sal_UCS4 cChar = pCharSet->GetSelectCharacter(); setFavButtonState(OUString(&cChar, 1), aFont.GetFamilyName()); const Subset* pSubset = pSubsetMap->GetSubsetByUnicode( cChar ); if( pSubset ) m_xSubsetLB->set_active_text(pSubset->GetName()); } m_xOKBtn->set_sensitive(true); } // class SvxShowText ===================================================== SvxShowText::SvxShowText(const VclPtr& rVirDev) : m_xVirDev(rVirDev) , mnY(0) , mbCenter(false) { } void SvxShowText::SetDrawingArea(weld::DrawingArea* pDrawingArea) { CustomWidgetController::SetDrawingArea(pDrawingArea); vcl::Font aFont = m_xVirDev->GetFont(); Size aFontSize(aFont.GetFontSize().Width() * 5, aFont.GetFontSize().Height() * 5); aFont.SetFontSize(aFontSize); m_xVirDev->Push(PUSH_ALLFONT); m_xVirDev->SetFont(aFont); pDrawingArea->set_size_request(m_xVirDev->approximate_digit_width() + 2 * 12, m_xVirDev->LogicToPixel(aFontSize).Height() * 2); m_xVirDev->Pop(); } void SvxShowText::Paint(vcl::RenderContext& rRenderContext, const tools::Rectangle&) { rRenderContext.SetFont(m_aFont); Color aTextCol = rRenderContext.GetTextColor(); Color aFillCol = rRenderContext.GetFillColor(); Color aLineCol = rRenderContext.GetLineColor(); const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings(); const Color aWindowTextColor(rStyleSettings.GetDialogTextColor()); const Color aWindowColor(rStyleSettings.GetWindowColor()); const Color aShadowColor(rStyleSettings.GetShadowColor()); rRenderContext.SetTextColor(aWindowTextColor); rRenderContext.SetFillColor(aWindowColor); const OUString aText = GetText(); Size aSize(GetOutputSizePixel()); tools::Long nAvailWidth = aSize.Width(); tools::Long nWinHeight = aSize.Height(); bool bGotBoundary = true; bool bShrankFont = false; vcl::Font aOrigFont(rRenderContext.GetFont()); Size aFontSize(aOrigFont.GetFontSize()); ::tools::Rectangle aBoundRect; for (tools::Long nFontHeight = aFontSize.Height(); nFontHeight > 0; nFontHeight -= 5) { if (!rRenderContext.GetTextBoundRect( aBoundRect, aText ) || aBoundRect.IsEmpty()) { bGotBoundary = false; break; } if (!mbCenter) break; //only shrink in the single glyph large view mode tools::Long nTextWidth = aBoundRect.GetWidth(); if (nAvailWidth > nTextWidth) break; vcl::Font aFont(aOrigFont); aFontSize.setHeight( nFontHeight ); aFont.SetFontSize(aFontSize); rRenderContext.SetFont(aFont); mnY = (nWinHeight - rRenderContext.GetTextHeight()) / 2; bShrankFont = true; } Point aPoint(2, mnY); // adjust position using ink boundary if possible if (!bGotBoundary) aPoint.setX( (aSize.Width() - rRenderContext.GetTextWidth(aText)) / 2 ); else { // adjust position before it gets out of bounds aBoundRect += aPoint; // shift back vertically if needed int nYLDelta = aBoundRect.Top(); int nYHDelta = aSize.Height() - aBoundRect.Bottom(); if( nYLDelta <= 0 ) aPoint.AdjustY( -(nYLDelta - 1) ); else if( nYHDelta <= 0 ) aPoint.AdjustY(nYHDelta - 1 ); if (mbCenter) { // move glyph to middle of cell aPoint.setX( -aBoundRect.Left() + (aSize.Width() - aBoundRect.GetWidth()) / 2 ); } else { // shift back horizontally if needed int nXLDelta = aBoundRect.Left(); int nXHDelta = aSize.Width() - aBoundRect.Right(); if( nXLDelta <= 0 ) aPoint.AdjustX( -(nXLDelta - 1) ); else if( nXHDelta <= 0 ) aPoint.AdjustX(nXHDelta - 1 ); } } rRenderContext.SetLineColor(aShadowColor); rRenderContext.DrawRect(tools::Rectangle(Point(0, 0), aSize)); rRenderContext.DrawText(aPoint, aText); rRenderContext.SetTextColor(aTextCol); rRenderContext.SetFillColor(aFillCol); rRenderContext.SetLineColor(aLineCol); if (bShrankFont) rRenderContext.SetFont(aOrigFont); } void SvxShowText::SetFont( const vcl::Font& rFont ) { tools::Long nWinHeight = GetOutputSizePixel().Height(); m_aFont = rFont; m_aFont.SetWeight(WEIGHT_NORMAL); m_aFont.SetAlignment(ALIGN_TOP); m_aFont.SetFontSize(m_xVirDev->PixelToLogic(Size(0, nWinHeight / 2))); m_aFont.SetTransparent(true); m_xVirDev->Push(PUSH_ALLFONT); m_xVirDev->SetFont(m_aFont); mnY = (nWinHeight - m_xVirDev->GetTextHeight()) / 2; m_xVirDev->Pop(); Invalidate(); } void SvxShowText::Resize() { SetFont(GetFont()); //force recalculation of size } void SvxShowText::SetText(const OUString& rText) { m_sText = rText; Invalidate(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */