1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
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/.
10 #include <sal/config.h>
12 #include <sfx2/ipclient.hxx>
13 #include <sfx2/lokcomponenthelpers.hxx>
14 #include <sfx2/lokhelper.hxx>
15 #include <sfx2/objsh.hxx>
17 #include <comphelper/dispatchcommand.hxx>
18 #include <comphelper/lok.hxx>
19 #include <toolkit/helper/vclunohelper.hxx>
20 #include <tools/fract.hxx>
21 #include <tools/UnitConversion.hxx>
22 #include <vcl/layout.hxx>
23 #include <vcl/virdev.hxx>
24 #include <vcl/window.hxx>
26 #include <com/sun/star/embed/XEmbeddedObject.hpp>
27 #include <com/sun/star/frame/XModel.hpp>
28 #include <com/sun/star/lang/XServiceInfo.hpp>
30 LokStarMathHelper::LokStarMathHelper(const SfxViewShell
* pViewShell
)
31 : mpViewShell(pViewShell
)
35 if (const SfxInPlaceClient
* pIPClient
= mpViewShell
->GetIPClient())
37 if (const auto& xEmbObj
= pIPClient
->GetObject())
39 css::uno::Reference
<css::lang::XServiceInfo
> xComp(xEmbObj
->getComponent(),
41 if (xComp
&& xComp
->supportsService("com.sun.star.formula.FormulaProperties"))
43 if (css::uno::Reference
<css::frame::XModel
> xModel
{ xComp
,
44 css::uno::UNO_QUERY
})
46 if (auto xController
= xModel
->getCurrentController())
48 mpIPClient
= pIPClient
;
49 mxFrame
= xController
->getFrame();
58 void LokStarMathHelper::Dispatch(
59 const OUString
& cmd
, const css::uno::Sequence
<css::beans::PropertyValue
>& rArguments
) const
62 comphelper::dispatchCommand(cmd
, mxFrame
, rArguments
);
67 // Find a child SmGraphicWindow*
68 vcl::Window
* FindSmGraphicWindow(vcl::Window
* pWin
)
73 if (pWin
->IsStarMath())
76 pWin
= pWin
->GetWindow(GetWindowType::FirstChild
);
79 if (vcl::Window
* pSmGraphicWindow
= FindSmGraphicWindow(pWin
))
80 return pSmGraphicWindow
;
81 pWin
= pWin
->GetWindow(GetWindowType::Next
);
86 // Find a child window that corresponds to SmGraphicWidget
87 vcl::Window
* FindChildSmGraphicWidgetWindow(vcl::Window
* pWin
)
92 // The needed window is a VclDrawingArea
93 if (dynamic_cast<VclDrawingArea
*>(pWin
))
96 pWin
= pWin
->GetWindow(GetWindowType::FirstChild
);
99 if (vcl::Window
* pSmGraphicWidgetWindow
= FindChildSmGraphicWidgetWindow(pWin
))
100 return pSmGraphicWidgetWindow
;
101 pWin
= pWin
->GetWindow(GetWindowType::Next
);
107 vcl::Window
* LokStarMathHelper::GetGraphicWindow()
109 if (!mpGraphicWindow
)
113 css::uno::Reference
<css::awt::XWindow
> xDockerWin
= mxFrame
->getContainerWindow();
114 mpGraphicWindow
.set(FindSmGraphicWindow(VCLUnoHelper::GetWindow(xDockerWin
)));
118 return mpGraphicWindow
.get();
121 vcl::Window
* LokStarMathHelper::GetWidgetWindow()
124 mpWidgetWindow
.set(FindChildSmGraphicWidgetWindow(GetGraphicWindow()));
126 return mpWidgetWindow
.get();
129 const SfxViewShell
* LokStarMathHelper::GetSmViewShell()
131 if (vcl::Window
* pGraphWindow
= GetGraphicWindow())
133 return SfxViewShell::GetFirst(false, [pGraphWindow
](const SfxViewShell
* shell
) {
134 return shell
->GetWindow() && shell
->GetWindow()->IsChild(pGraphWindow
);
140 tools::Rectangle
LokStarMathHelper::GetBoundingBox() const
144 tools::Rectangle
r(mpIPClient
->GetObjArea());
145 if (SfxObjectShell
* pObjShell
= const_cast<SfxViewShell
*>(mpViewShell
)->GetObjectShell())
147 const o3tl::Length unit
= MapToO3tlLength(pObjShell
->GetMapUnit());
148 if (unit
!= o3tl::Length::twip
&& unit
!= o3tl::Length::invalid
)
149 r
= o3tl::convert(r
, unit
, o3tl::Length::twip
);
156 bool LokStarMathHelper::postMouseEvent(int nType
, int nX
, int nY
, int nCount
, int nButtons
,
157 int nModifier
, double fPPTScaleX
, double fPPTScaleY
)
159 const tools::Rectangle rBBox
= GetBoundingBox();
160 if (Point
aMousePos(nX
, nY
); rBBox
.Contains(aMousePos
))
162 if (vcl::Window
* pWindow
= GetWidgetWindow())
164 aMousePos
-= rBBox
.TopLeft();
166 // In lok, Math does not convert coordinates (see SmGraphicWidget::SetDrawingArea,
167 // which disables MapMode), and uses twips internally (see SmDocShell ctor and
168 // SmMapUnit), but the conversion factor can depend on the client zoom.
169 // 1. Remove the twip->pixel factor in the passed scales
170 double fScaleX
= o3tl::convert(fPPTScaleX
, o3tl::Length::px
, o3tl::Length::twip
);
171 double fScaleY
= o3tl::convert(fPPTScaleY
, o3tl::Length::px
, o3tl::Length::twip
);
172 // 2. Adjust the position according to the scales
174 = Point(std::round(aMousePos
.X() * fScaleX
), std::round(aMousePos
.Y() * fScaleY
));
175 // 3. Take window own scaling into account (reverses the conversion done in
176 // SmGraphicWidget::MouseButtonDown, albeit incompletely - it does not handle
177 // GetFormulaDrawPos; hopefully, in lok/in-place case, it's always [ 0, 0 ]?)
178 aMousePos
= pWindow
->LogicToPixel(aMousePos
);
180 LokMouseEventData
aMouseEventData(
181 nType
, aMousePos
, nCount
, MouseEventModifiers::SIMPLECLICK
, nButtons
, nModifier
);
182 SfxLokHelper::postMouseEventAsync(pWindow
, aMouseEventData
);
190 void LokStarMathHelper::PaintTile(VirtualDevice
& rDevice
, const tools::Rectangle
& rTileRect
)
192 const tools::Rectangle aMathRect
= GetBoundingBox();
193 if (rTileRect
.GetIntersection(aMathRect
).IsEmpty())
196 vcl::Window
* pWidgetWindow
= GetWidgetWindow();
200 Point
aOffset(aMathRect
.Left() - rTileRect
.Left(), aMathRect
.Top() - rTileRect
.Top());
202 MapMode newMode
= rDevice
.GetMapMode();
203 newMode
.SetOrigin(aOffset
);
204 rDevice
.SetMapMode(newMode
); // Push/Pop is done in PaintAllInPlaceOnTile
206 pWidgetWindow
->Paint(rDevice
, {}); // SmGraphicWidget::Paint does not use the passed rectangle
209 void LokStarMathHelper::PaintAllInPlaceOnTile(VirtualDevice
& rDevice
, int nOutputWidth
,
210 int nOutputHeight
, int nTilePosX
, int nTilePosY
,
211 tools::Long nTileWidth
, tools::Long nTileHeight
)
213 if (comphelper::LibreOfficeKit::isTiledAnnotations())
216 SfxViewShell
* pCurView
= SfxViewShell::Current();
219 const ViewShellDocId nDocId
= pCurView
->GetDocId();
220 const int nPartForCurView
= pCurView
->getPart();
222 // Resizes the virtual device to contain the entries context
223 rDevice
.SetOutputSizePixel({ nOutputWidth
, nOutputHeight
});
225 rDevice
.Push(vcl::PushFlags::MAPMODE
);
226 MapMode
aMapMode(rDevice
.GetMapMode());
228 // Scaling. Must convert from pixels to twips. We know that VirtualDevices use a DPI of 96.
229 const Fraction scale
= conversionFract(o3tl::Length::px
, o3tl::Length::twip
);
230 const Fraction scaleX
= Fraction(nOutputWidth
, nTileWidth
) * scale
;
231 const Fraction scaleY
= Fraction(nOutputHeight
, nTileHeight
) * scale
;
232 aMapMode
.SetScaleX(scaleX
);
233 aMapMode
.SetScaleY(scaleY
);
234 aMapMode
.SetMapUnit(MapUnit::MapTwip
);
235 rDevice
.SetMapMode(aMapMode
);
237 const tools::Rectangle
aTileRect(Point(nTilePosX
, nTilePosY
), Size(nTileWidth
, nTileHeight
));
239 for (SfxViewShell
* pViewShell
= SfxViewShell::GetFirst(); pViewShell
;
240 pViewShell
= SfxViewShell::GetNext(*pViewShell
))
241 if (pViewShell
->GetDocId() == nDocId
&& pViewShell
->getPart() == nPartForCurView
)
242 LokStarMathHelper(pViewShell
).PaintTile(rDevice
, aTileRect
);
247 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */