tdf#151001: Add support for EXPAND function
[LibreOffice.git] / svx / source / tbxctrls / fontworkgallery.cxx
blob41190e689abe4643253d1539cc5667196da290be
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 .
21 #include <com/sun/star/text/WritingMode.hpp>
23 #include <comphelper/lok.hxx>
24 #include <comphelper/propertyvalue.hxx>
25 #include <comphelper/servicehelper.hxx>
26 #include <comphelper/processfactory.hxx>
27 #include <com/sun/star/frame/ModuleManager.hpp>
29 #include <vcl/toolbox.hxx>
30 #include <vcl/virdev.hxx>
32 #include <sfx2/viewsh.hxx>
34 #include <svl/itempool.hxx>
36 #include <svtools/toolbarmenu.hxx>
37 #include <svtools/popupwindowcontroller.hxx>
39 #include <svx/fmmodel.hxx>
40 #include <svx/svdpage.hxx>
41 #include <svx/svdobj.hxx>
42 #include <svx/svdview.hxx>
44 #include <svx/gallery.hxx>
45 #include <svx/fontworkgallery.hxx>
47 #include <tools/UnitConversion.hxx>
49 #include <memory>
51 #include <svx/strings.hrc>
52 #include <svx/dialmgr.hxx>
54 using namespace ::com::sun::star::uno;
55 using namespace ::com::sun::star::beans;
57 namespace svx
60 FontWorkGalleryDialog::FontWorkGalleryDialog(weld::Window* pParent, SdrView& rSdrView,
61 Reference<css::frame::XFrame> xFrame)
62 : GenericDialogController(pParent, u"svx/ui/fontworkgallerydialog.ui"_ustr, u"FontworkGalleryDialog"_ustr)
63 , mnThemeId(0xffff)
64 , mrSdrView(rSdrView)
65 , mbInsertIntoPage(true)
66 , mpDestModel(nullptr)
67 , maCtlFavorites(m_xBuilder->weld_icon_view(u"ctlFavoriteswin"_ustr))
68 , mxOKButton(m_xBuilder->weld_button(u"ok"_ustr))
69 , mxFrame(std::move(xFrame))
71 Size aSize(530, 400);
72 maCtlFavorites->set_size_request(aSize.Width(), aSize.Height());
74 maCtlFavorites->connect_item_activated( LINK( this, FontWorkGalleryDialog, DoubleClickFavoriteHdl ) );
75 maCtlFavorites->connect_query_tooltip(LINK(this, FontWorkGalleryDialog, QueryTooltipHandler));
76 mxOKButton->connect_clicked(LINK(this, FontWorkGalleryDialog, ClickOKHdl));
78 initFavorites( GALLERY_THEME_FONTWORK );
79 fillFavorites( GALLERY_THEME_FONTWORK );
82 FontWorkGalleryDialog::~FontWorkGalleryDialog()
86 void FontWorkGalleryDialog::initFavorites(sal_uInt16 nThemeId)
88 // the favorites are read via the gallery
89 sal_uInt32 nFavCount = GalleryExplorer::GetSdrObjCount( nThemeId );
91 // lock gallery theme
92 GalleryExplorer::BeginLocking(nThemeId);
94 sal_uInt32 nModelPos;
95 FmFormModel *pModel = nullptr;
97 for( nModelPos = 0; nModelPos < nFavCount; nModelPos++ )
99 BitmapEx aThumb;
101 if (GalleryExplorer::GetSdrObj(nThemeId, nModelPos, pModel, &aThumb) && !aThumb.IsEmpty())
103 VclPtr< VirtualDevice > pVDev = VclPtr<VirtualDevice>::Create();
104 const Point aNull(0, 0);
106 if (pVDev->GetDPIScaleFactor() > 1)
107 aThumb.Scale(pVDev->GetDPIScaleFactor(), pVDev->GetDPIScaleFactor());
109 const Size aSize(aThumb.GetSizePixel());
111 pVDev->SetOutputSizePixel(aSize);
113 static const sal_uInt32 nLen(8);
114 static const Color aW(COL_WHITE);
115 static const Color aG(0xef, 0xef, 0xef);
117 pVDev->DrawCheckered(aNull, aSize, nLen, aW, aG);
119 pVDev->DrawBitmapEx(aNull, aThumb);
120 maFavoritesHorizontal.emplace_back(pVDev);
124 // release gallery theme
125 GalleryExplorer::EndLocking(nThemeId);
128 void FontWorkGalleryDialog::fillFavorites(sal_uInt16 nThemeId)
130 mnThemeId = nThemeId;
132 auto nFavCount = maFavoritesHorizontal.size();
134 maCtlFavorites->clear();
135 maIdToTitleMap.clear();
137 std::vector<OUString> aTitles;
138 (void)GalleryExplorer::FillObjListTitle(nThemeId, aTitles);
139 assert(aTitles.size() == nFavCount);
141 for( size_t nFavorite = 1; nFavorite <= nFavCount; nFavorite++ )
143 OUString sId = OUString::number(static_cast<sal_uInt16>(nFavorite));
144 maIdToTitleMap.emplace(sId, aTitles.at(nFavorite - 1));
145 maCtlFavorites->insert(-1, nullptr, &sId, maFavoritesHorizontal[nFavorite - 1], nullptr);
148 if (maCtlFavorites->n_children())
149 maCtlFavorites->select(0);
152 void FontWorkGalleryDialog::SetSdrObjectRef( SdrModel* pModel)
154 mbInsertIntoPage = false;
155 mpDestModel = pModel;
158 void FontWorkGalleryDialog::insertSelectedFontwork()
160 OUString sItemId = maCtlFavorites->get_selected_id();
161 if (sItemId.isEmpty())
162 return;
164 sal_Int32 nItemId = sItemId.toInt32();
166 if (nItemId == 0)
167 return;
169 FmFormModel aModel;
171 if( !GalleryExplorer::GetSdrObj( mnThemeId, nItemId-1, &aModel ) )
172 return;
174 SdrPage* pPage = aModel.GetPage(0);
175 if( !(pPage && pPage->GetObjCount()) )
176 return;
178 // tdf#116993 Calc uses a 'special' mode for this dialog in being the
179 // only caller of ::SetSdrObjectRef. Only in that case mpDestModel seems
180 // to be the correct target SdrModel.
181 // If this is not used, the correct SdrModel seems to be the one from
182 // the mrSdrView that is used to insert (InsertObjectAtView below) the
183 // cloned SdrObject.
184 const bool bUseSpecialCalcMode(!mbInsertIntoPage && nullptr != mpDestModel);
186 // center shape on current view
187 OutputDevice* pOutDev(mrSdrView.GetFirstOutputDevice());
189 if (!pOutDev)
190 return;
192 // Clone directly to target SdrModel (may be different due to user/caller (!))
193 rtl::Reference<SdrObject> xNewObject(
194 pPage->GetObj(0)->CloneSdrObject(
195 bUseSpecialCalcMode ? *mpDestModel : mrSdrView.getSdrModelFromSdrView()));
197 const Reference<XComponentContext>& xContext = comphelper::getProcessComponentContext();
198 css::uno::Reference<css::frame::XModuleManager> xModuleManager =
199 css::frame::ModuleManager::create(xContext);
200 OUString aModuleIdentifier = xModuleManager->identify(mxFrame);
202 if (aModuleIdentifier != "com.sun.star.drawing.DrawingDocument" &&
203 aModuleIdentifier != "com.sun.star.presentation.PresentationDocument" )
205 xNewObject->SetName(SvxResId(STR_ObjNameSingulFONTWORK) + u" 1");
206 xNewObject->MakeNameUnique();
208 else
209 xNewObject->SetName(OUString());
211 // tdf#117629
212 // Since the 'old' ::CloneSdrObject also copies the SdrPage* the
213 // SdrObject::getUnoShape() *will* create the wrong UNO API object
214 // early. This IS one of the reasons I do change these things - this
215 // error does not happen with my next change I am working on already
216 // ARGH! For now, reset the SdrPage* to nullptr.
217 // What sense does it have to copy the SdrPage* of the original SdrObject ?!?
218 // TTTT: This also *might* be the hidden reason for the strange code at the
219 // end of SdrObject::SetPage that tries to delete the SvxShape under some
220 // circumstances...
221 // xNewObject->SetPage(nullptr);
223 tools::Rectangle aObjRect( xNewObject->GetLogicRect() );
224 Point aPagePos;
225 Size aFontworkSize = aObjRect.GetSize();
227 SfxViewShell* pKitViewShell = comphelper::LibreOfficeKit::isActive() ?
228 SfxViewShell::Current() : nullptr;
229 if (pKitViewShell)
231 aPagePos = convertTwipToMm100(pKitViewShell->getLOKVisibleArea().Center());
233 sal_Int32 nLOKViewWidth = 0.8 * convertTwipToMm100(pKitViewShell->getLOKVisibleArea().getOpenWidth());
234 if (aFontworkSize.getWidth() > nLOKViewWidth)
236 double fScale = static_cast<double>(aFontworkSize.getWidth()) / nLOKViewWidth;
237 aFontworkSize.setWidth(aFontworkSize.getWidth() / fScale);
238 aFontworkSize.setHeight(aFontworkSize.getHeight() / fScale);
241 else
243 Size aSize = pOutDev->GetOutputSizePixel();
244 tools::Rectangle aPixelVisRect(Point(0,0), aSize);
245 tools::Rectangle aVisArea = pOutDev->PixelToLogic(aPixelVisRect);
247 aPagePos = aVisArea.Center();
250 if (aPagePos.getX() > aFontworkSize.getWidth() / 2)
251 aPagePos.AdjustX( -(aFontworkSize.getWidth() / 2) );
252 if (aPagePos.getY() > aFontworkSize.getHeight() / 2)
253 aPagePos.AdjustY( -(aFontworkSize.getHeight() / 2) );
255 tools::Rectangle aNewObjectRectangle(aPagePos, aFontworkSize);
256 xNewObject->SetLogicRect(aNewObjectRectangle);
258 if (bUseSpecialCalcMode)
260 mxSdrObject = std::move(xNewObject);
262 else
264 SdrPageView* pPV(mrSdrView.GetSdrPageView());
266 if (nullptr != pPV)
268 mrSdrView.InsertObjectAtView( xNewObject.get(), *pPV );
273 IMPL_LINK_NOARG(FontWorkGalleryDialog, ClickOKHdl, weld::Button&, void)
275 insertSelectedFontwork();
276 m_xDialog->response(RET_OK);
279 IMPL_LINK_NOARG(FontWorkGalleryDialog, DoubleClickFavoriteHdl, weld::IconView&, bool)
281 insertSelectedFontwork();
282 m_xDialog->response(RET_OK);
283 return true;
286 IMPL_LINK(FontWorkGalleryDialog, QueryTooltipHandler, const weld::TreeIter&, iter, OUString)
288 const OUString id = maCtlFavorites->get_id(iter);
289 auto it = maIdToTitleMap.find(id);
290 return it != maIdToTitleMap.end() ? it->second : OUString();
293 namespace {
295 class FontworkAlignmentWindow final : public WeldToolbarPopup
297 public:
298 FontworkAlignmentWindow(svt::PopupWindowController* pControl, weld::Widget* pParentWindow);
299 virtual void GrabFocus() override
301 mxLeft->grab_focus();
303 virtual void statusChanged( const css::frame::FeatureStateEvent& Event ) override;
305 private:
306 rtl::Reference<svt::PopupWindowController> mxControl;
307 std::unique_ptr<weld::RadioButton> mxLeft;
308 std::unique_ptr<weld::RadioButton> mxCenter;
309 std::unique_ptr<weld::RadioButton> mxRight;
310 std::unique_ptr<weld::RadioButton> mxStretch;
311 bool mbSettingValue;
313 DECL_LINK( SelectHdl, weld::Toggleable&, void );
315 void implSetAlignment( int nAlignmentMode, bool bEnabled );
320 constexpr OUString gsFontworkAlignment(u".uno:FontworkAlignment"_ustr);
322 FontworkAlignmentWindow::FontworkAlignmentWindow(svt::PopupWindowController* pControl, weld::Widget* pParent)
323 : WeldToolbarPopup(pControl->getFrameInterface(), pParent, u"svx/ui/fontworkalignmentcontrol.ui"_ustr, u"FontworkAlignmentControl"_ustr)
324 , mxControl(pControl)
325 , mxLeft(m_xBuilder->weld_radio_button(u"left"_ustr))
326 , mxCenter(m_xBuilder->weld_radio_button(u"center"_ustr))
327 , mxRight(m_xBuilder->weld_radio_button(u"right"_ustr))
328 , mxStretch(m_xBuilder->weld_radio_button(u"stretch"_ustr))
329 , mbSettingValue(false)
331 mxLeft->connect_toggled(LINK(this, FontworkAlignmentWindow, SelectHdl));
332 mxCenter->connect_toggled(LINK(this, FontworkAlignmentWindow, SelectHdl));
333 mxRight->connect_toggled(LINK(this, FontworkAlignmentWindow, SelectHdl));
334 mxStretch->connect_toggled(LINK(this, FontworkAlignmentWindow, SelectHdl));
336 AddStatusListener( gsFontworkAlignment );
339 void FontworkAlignmentWindow::implSetAlignment( int nSurface, bool bEnabled )
341 bool bSettingValue = mbSettingValue;
342 mbSettingValue = true;
343 mxLeft->set_active(nSurface == 0 && bEnabled);
344 mxLeft->set_sensitive(bEnabled);
345 mxCenter->set_active(nSurface == 1 && bEnabled);
346 mxCenter->set_sensitive(bEnabled);
347 mxRight->set_active(nSurface == 2 && bEnabled);
348 mxRight->set_sensitive(bEnabled);
349 //Refer https://bugs.documentfoundation.org/show_bug.cgi?id=145092 for why following lines are commented
350 //mxWord->set_active(nSurface == 3 && bEnabled);
351 //mxWord->set_sensitive(bEnabled);
352 mxStretch->set_active(nSurface == 4 && bEnabled);
353 mxStretch->set_sensitive(bEnabled);
354 mbSettingValue = bSettingValue;
357 void FontworkAlignmentWindow::statusChanged( const css::frame::FeatureStateEvent& Event )
359 if( Event.FeatureURL.Main != gsFontworkAlignment )
360 return;
362 if( !Event.IsEnabled )
364 implSetAlignment( 0, false );
366 else
368 sal_Int32 nValue = 0;
369 if( Event.State >>= nValue )
370 implSetAlignment( nValue, true );
374 IMPL_LINK(FontworkAlignmentWindow, SelectHdl, weld::Toggleable&, rButton, void)
376 if (mbSettingValue || !rButton.get_active())
377 return;
379 sal_Int32 nAlignment;
380 if (mxLeft->get_active())
381 nAlignment = 0;
382 else if (mxCenter->get_active())
383 nAlignment = 1;
384 else if (mxRight->get_active())
385 nAlignment = 2;
386 //Refer https://bugs.documentfoundation.org/show_bug.cgi?id=145092 for why following lines are commented
387 //else if (mxWord->get_active())
388 // nAlignment = 3;
389 else
390 nAlignment = 4;
392 Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
393 gsFontworkAlignment.copy(5), nAlignment) };
395 mxControl->dispatchCommand( gsFontworkAlignment, aArgs );
397 implSetAlignment( nAlignment, true );
399 mxControl->EndPopupMode();
402 namespace {
404 class FontworkAlignmentControl : public svt::PopupWindowController
406 public:
407 explicit FontworkAlignmentControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
409 virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
410 virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override;
412 // XInitialization
413 virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
415 // XServiceInfo
416 virtual OUString SAL_CALL getImplementationName() override;
417 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
422 FontworkAlignmentControl::FontworkAlignmentControl( const Reference< XComponentContext >& rxContext )
423 : svt::PopupWindowController( rxContext, Reference< css::frame::XFrame >(), u".uno:FontworkAlignment"_ustr )
427 std::unique_ptr<WeldToolbarPopup> FontworkAlignmentControl::weldPopupWindow()
429 return std::make_unique<FontworkAlignmentWindow>(this, m_pToolbar);
432 VclPtr<vcl::Window> FontworkAlignmentControl::createVclPopupWindow( vcl::Window* pParent )
434 mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
435 std::make_unique<FontworkAlignmentWindow>(this, pParent->GetFrameWeld()));
437 mxInterimPopover->Show();
439 return mxInterimPopover;
442 // XInitialization
443 void SAL_CALL FontworkAlignmentControl::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
445 svt::PopupWindowController::initialize( aArguments );
447 if (m_pToolbar)
449 mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
450 m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel());
453 ToolBox* pToolBox = nullptr;
454 ToolBoxItemId nId;
455 if ( getToolboxId( nId, &pToolBox ) )
456 pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
459 // XServiceInfo
462 OUString FontworkAlignmentControl::getImplementationName()
464 return u"com.sun.star.comp.svx.FontworkAlignmentController"_ustr;
468 Sequence< OUString > FontworkAlignmentControl::getSupportedServiceNames()
470 return { u"com.sun.star.frame.ToolbarController"_ustr };
474 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
475 com_sun_star_comp_svx_FontworkAlignmentControl_get_implementation(
476 css::uno::XComponentContext* xContext,
477 css::uno::Sequence<css::uno::Any> const &)
479 return cppu::acquire(new FontworkAlignmentControl(xContext));
482 namespace {
484 class FontworkCharacterSpacingWindow final : public WeldToolbarPopup
486 public:
487 FontworkCharacterSpacingWindow(svt::PopupWindowController* pControl, weld::Widget* pParentWindow);
488 virtual void GrabFocus() override;
490 virtual void statusChanged( const css::frame::FeatureStateEvent& Event ) override;
491 private:
492 rtl::Reference<svt::PopupWindowController> mxControl;
493 std::unique_ptr<weld::RadioButton> mxVeryTight;
494 std::unique_ptr<weld::RadioButton> mxTight;
495 std::unique_ptr<weld::RadioButton> mxNormal;
496 std::unique_ptr<weld::RadioButton> mxLoose;
497 std::unique_ptr<weld::RadioButton> mxVeryLoose;
498 std::unique_ptr<weld::RadioButton> mxCustom;
499 std::unique_ptr<weld::CheckButton> mxKernPairs;
500 sal_Int32 mnCharacterSpacing;
501 bool mbSettingValue;
502 bool mbCommandDispatched;
504 DECL_LINK( KernSelectHdl, weld::Toggleable&, void );
505 DECL_LINK( SelectHdl, weld::Toggleable&, void );
506 DECL_LINK( MouseReleaseHdl, const MouseEvent&, bool );
508 void implSetCharacterSpacing( sal_Int32 nCharacterSpacing, bool bEnabled );
509 void implSetKernCharacterPairs(bool bKernOnOff, bool bEnabled);
510 void DispatchSpacingDialog();
515 constexpr OUString gsFontworkCharacterSpacing(u".uno:FontworkCharacterSpacing"_ustr);
516 constexpr OUString gsFontworkKernCharacterPairs(u".uno:FontworkKernCharacterPairs"_ustr);
518 FontworkCharacterSpacingWindow::FontworkCharacterSpacingWindow(svt::PopupWindowController* pControl, weld::Widget* pParent)
519 : WeldToolbarPopup(pControl->getFrameInterface(), pParent, u"svx/ui/fontworkcharacterspacingcontrol.ui"_ustr, u"FontworkCharacterSpacingControl"_ustr)
520 , mxControl(pControl)
521 , mxVeryTight(m_xBuilder->weld_radio_button(u"verytight"_ustr))
522 , mxTight(m_xBuilder->weld_radio_button(u"tight"_ustr))
523 , mxNormal(m_xBuilder->weld_radio_button(u"normal"_ustr))
524 , mxLoose(m_xBuilder->weld_radio_button(u"loose"_ustr))
525 , mxVeryLoose(m_xBuilder->weld_radio_button(u"veryloose"_ustr))
526 , mxCustom(m_xBuilder->weld_radio_button(u"custom"_ustr))
527 , mxKernPairs(m_xBuilder->weld_check_button(u"kernpairs"_ustr))
528 , mnCharacterSpacing(0)
529 , mbSettingValue(false)
530 , mbCommandDispatched(false)
532 mxVeryTight->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
533 mxTight->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
534 mxNormal->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
535 mxLoose->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
536 mxVeryLoose->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
537 mxCustom->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, SelectHdl));
538 mxCustom->connect_mouse_release(LINK(this, FontworkCharacterSpacingWindow, MouseReleaseHdl));
540 mxKernPairs->connect_toggled(LINK(this, FontworkCharacterSpacingWindow, KernSelectHdl));
542 AddStatusListener( gsFontworkCharacterSpacing );
543 AddStatusListener( gsFontworkKernCharacterPairs );
545 // See TODO in svx/source/toolbars/fontworkbar.cxx for SID_FONTWORK_KERN_CHARACTER_PAIRS,
546 // the kernpairs setting is ignored, so hide the widget entirely
547 mxKernPairs->hide();
550 void FontworkCharacterSpacingWindow::GrabFocus()
552 mxVeryTight->grab_focus();
555 void FontworkCharacterSpacingWindow::implSetCharacterSpacing( sal_Int32 nCharacterSpacing, bool bEnabled )
557 bool bSettingValue = mbSettingValue;
558 mbSettingValue = true;
560 mxVeryTight->set_sensitive(bEnabled);
561 mxTight->set_sensitive(bEnabled);
562 mxNormal->set_sensitive(bEnabled);
563 mxLoose->set_sensitive(bEnabled);
564 mxVeryLoose->set_sensitive(bEnabled);
565 mxCustom->set_sensitive(bEnabled);
567 mxVeryTight->set_active(false);
568 mxTight->set_active(false);
569 mxNormal->set_active(false);
570 mxLoose->set_active(false);
571 mxVeryLoose->set_active(false);
572 mxCustom->set_active(true);
574 switch(nCharacterSpacing)
576 case 80:
577 mxVeryTight->set_active(true);
578 break;
579 case 90:
580 mxTight->set_active(true);
581 break;
582 case 100:
583 mxNormal->set_active(true);
584 break;
585 case 120:
586 mxLoose->set_active(true);
587 break;
588 case 150:
589 mxVeryLoose->set_active(true);
590 break;
593 mnCharacterSpacing = nCharacterSpacing;
595 mbSettingValue = bSettingValue;
598 void FontworkCharacterSpacingWindow::implSetKernCharacterPairs(bool bKernOnOff, bool bEnabled)
600 mxKernPairs->set_sensitive(bEnabled);
601 mxKernPairs->set_active(bKernOnOff);
604 void FontworkCharacterSpacingWindow::statusChanged( const css::frame::FeatureStateEvent& Event )
606 if( Event.FeatureURL.Main == gsFontworkCharacterSpacing )
608 if( !Event.IsEnabled )
610 implSetCharacterSpacing( 0, false );
612 else
614 sal_Int32 nValue = 0;
615 if( Event.State >>= nValue )
616 implSetCharacterSpacing( nValue, true );
619 else if( Event.FeatureURL.Main == gsFontworkKernCharacterPairs )
621 if( !Event.IsEnabled )
623 implSetKernCharacterPairs(false, false);
625 else
627 bool bValue = false;
628 if( Event.State >>= bValue )
629 implSetKernCharacterPairs(bValue, true);
634 IMPL_LINK_NOARG(FontworkCharacterSpacingWindow, KernSelectHdl, weld::Toggleable&, void)
636 if (mbSettingValue)
637 return;
639 bool bKernOnOff = mxKernPairs->get_active();
640 Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
641 gsFontworkKernCharacterPairs.copy(5), bKernOnOff) };
643 mxControl->dispatchCommand( gsFontworkKernCharacterPairs, aArgs );
644 mbCommandDispatched = true;
646 implSetKernCharacterPairs(bKernOnOff, true);
648 mxControl->EndPopupMode();
651 void FontworkCharacterSpacingWindow::DispatchSpacingDialog()
653 Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
654 gsFontworkCharacterSpacing.copy(5), mnCharacterSpacing) };
656 rtl::Reference<svt::PopupWindowController> xControl(mxControl);
657 xControl->EndPopupMode();
658 xControl->dispatchCommand(u".uno:FontworkCharacterSpacingDialog"_ustr, aArgs);
659 mbCommandDispatched = true;
662 IMPL_LINK(FontworkCharacterSpacingWindow, SelectHdl, weld::Toggleable&, rButton, void)
664 if (!rButton.get_active())
665 return;
667 if (mbSettingValue)
668 return;
670 // see MouseReleaseHdl for mbCommandDispatched check, there's no guarantee
671 // this toggle will happen before that mouse release though it does in
672 // practice for vcl and gtk
673 if (mbCommandDispatched)
674 return;
676 if (mxCustom->get_active())
677 DispatchSpacingDialog();
678 else
680 sal_Int32 nCharacterSpacing;
681 if (mxVeryTight->get_active())
682 nCharacterSpacing = 80;
683 else if (mxTight->get_active())
684 nCharacterSpacing = 90;
685 else if (mxLoose->get_active())
686 nCharacterSpacing = 120;
687 else if (mxVeryLoose->get_active())
688 nCharacterSpacing = 150;
689 else
690 nCharacterSpacing = 100;
692 Sequence< PropertyValue > aArgs{ comphelper::makePropertyValue(
693 gsFontworkCharacterSpacing.copy(5), nCharacterSpacing) };
695 mxControl->dispatchCommand( gsFontworkCharacterSpacing, aArgs );
696 mbCommandDispatched = true;
698 implSetCharacterSpacing( nCharacterSpacing, true );
701 mxControl->EndPopupMode();
704 IMPL_LINK_NOARG(FontworkCharacterSpacingWindow, MouseReleaseHdl, const MouseEvent&, bool)
707 tdf#145296 if the "custom" radiobutton was presented preselected as
708 toggled on and the user clicked on it then there's no toggled signal sent
709 because the item was already toggled on and didn't change state.
711 So if that happens launch the custom spacing dialog explicitly here on
712 mouse release.
714 if (mxCustom->get_active() && !mbCommandDispatched)
716 DispatchSpacingDialog();
717 return true;
719 return false;
722 namespace {
724 class FontworkCharacterSpacingControl : public svt::PopupWindowController
726 public:
727 explicit FontworkCharacterSpacingControl( const css::uno::Reference< css::uno::XComponentContext >& rxContext );
729 virtual std::unique_ptr<WeldToolbarPopup> weldPopupWindow() override;
730 virtual VclPtr<vcl::Window> createVclPopupWindow( vcl::Window* pParent ) override;
732 // XInitialization
733 virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
735 // XServiceInfo
736 virtual OUString SAL_CALL getImplementationName() override;
737 virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames() override;
742 FontworkCharacterSpacingControl::FontworkCharacterSpacingControl( const Reference< XComponentContext >& rxContext )
743 : svt::PopupWindowController( rxContext, Reference< css::frame::XFrame >(), u".uno:FontworkCharacterSpacingFloater"_ustr )
747 std::unique_ptr<WeldToolbarPopup> FontworkCharacterSpacingControl::weldPopupWindow()
749 return std::make_unique<FontworkCharacterSpacingWindow>(this, m_pToolbar);
752 VclPtr<vcl::Window> FontworkCharacterSpacingControl::createVclPopupWindow( vcl::Window* pParent )
754 mxInterimPopover = VclPtr<InterimToolbarPopup>::Create(getFrameInterface(), pParent,
755 std::make_unique<FontworkCharacterSpacingWindow>(this, pParent->GetFrameWeld()));
757 mxInterimPopover->Show();
759 return mxInterimPopover;
762 // XInitialization
763 void SAL_CALL FontworkCharacterSpacingControl::initialize( const css::uno::Sequence< css::uno::Any >& aArguments )
765 svt::PopupWindowController::initialize( aArguments );
767 if (m_pToolbar)
769 mxPopoverContainer.reset(new ToolbarPopupContainer(m_pToolbar));
770 m_pToolbar->set_item_popover(m_aCommandURL, mxPopoverContainer->getTopLevel());
773 ToolBox* pToolBox = nullptr;
774 ToolBoxItemId nId;
775 if ( getToolboxId( nId, &pToolBox ) )
776 pToolBox->SetItemBits( nId, pToolBox->GetItemBits( nId ) | ToolBoxItemBits::DROPDOWNONLY );
779 // XServiceInfo
782 OUString FontworkCharacterSpacingControl::getImplementationName()
784 return u"com.sun.star.comp.svx.FontworkCharacterSpacingController"_ustr;
788 Sequence< OUString > FontworkCharacterSpacingControl::getSupportedServiceNames()
790 Sequence<OUString> aSNS { u"com.sun.star.frame.ToolbarController"_ustr };
791 return aSNS;
795 extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
796 com_sun_star_comp_svx_FontworkCharacterSpacingControl_get_implementation(
797 css::uno::XComponentContext* xContext,
798 css::uno::Sequence<css::uno::Any> const &)
800 return cppu::acquire(new FontworkCharacterSpacingControl(xContext));
803 FontworkCharacterSpacingDialog::FontworkCharacterSpacingDialog(weld::Window* pParent, sal_Int32 nScale)
804 : GenericDialogController(pParent, u"svx/ui/fontworkspacingdialog.ui"_ustr, u"FontworkSpacingDialog"_ustr)
805 , m_xMtrScale(m_xBuilder->weld_metric_spin_button(u"entry"_ustr, FieldUnit::PERCENT))
807 m_xMtrScale->set_value(nScale, FieldUnit::PERCENT);
810 FontworkCharacterSpacingDialog::~FontworkCharacterSpacingDialog()
814 sal_Int32 FontworkCharacterSpacingDialog::getScale() const
816 return static_cast<sal_Int32>(m_xMtrScale->get_value(FieldUnit::PERCENT));
821 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */