/src/libreoffice/sfx2/source/view/lokstarmathhelper.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */ |
2 | | /* |
3 | | * This file is part of the LibreOffice project. |
4 | | * |
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/. |
8 | | */ |
9 | | |
10 | | #include <sal/config.h> |
11 | | |
12 | | #include <sfx2/ipclient.hxx> |
13 | | #include <sfx2/lokcomponenthelpers.hxx> |
14 | | #include <sfx2/lokhelper.hxx> |
15 | | #include <sfx2/objsh.hxx> |
16 | | |
17 | | #include <comphelper/dispatchcommand.hxx> |
18 | | #include <comphelper/lok.hxx> |
19 | | #include <toolkit/helper/vclunohelper.hxx> |
20 | | #include <tools/fract.hxx> |
21 | | #include <tools/mapunit.hxx> |
22 | | #include <tools/UnitConversion.hxx> |
23 | | #include <vcl/layout.hxx> |
24 | | #include <vcl/virdev.hxx> |
25 | | #include <vcl/window.hxx> |
26 | | |
27 | | #include <com/sun/star/embed/XEmbeddedObject.hpp> |
28 | | #include <com/sun/star/frame/XModel.hpp> |
29 | | #include <com/sun/star/lang/XServiceInfo.hpp> |
30 | | |
31 | | LokStarMathHelper::LokStarMathHelper(const SfxViewShell* pViewShell) |
32 | 0 | : mpViewShell(pViewShell) |
33 | 0 | { |
34 | 0 | if (mpViewShell) |
35 | 0 | { |
36 | 0 | if (const SfxInPlaceClient* pIPClient = mpViewShell->GetIPClient()) |
37 | 0 | { |
38 | 0 | if (const auto& xEmbObj = pIPClient->GetObject()) |
39 | 0 | { |
40 | 0 | css::uno::Reference<css::lang::XServiceInfo> xComp(xEmbObj->getComponent(), |
41 | 0 | css::uno::UNO_QUERY); |
42 | 0 | if (xComp && xComp->supportsService(u"com.sun.star.formula.FormulaProperties"_ustr)) |
43 | 0 | { |
44 | 0 | if (css::uno::Reference<css::frame::XModel> xModel{ xComp, |
45 | 0 | css::uno::UNO_QUERY }) |
46 | 0 | { |
47 | 0 | if (auto xController = xModel->getCurrentController()) |
48 | 0 | { |
49 | 0 | mpIPClient = pIPClient; |
50 | 0 | mxFrame = xController->getFrame(); |
51 | 0 | } |
52 | 0 | } |
53 | 0 | } |
54 | 0 | } |
55 | 0 | } |
56 | 0 | } |
57 | 0 | } |
58 | | |
59 | | void LokStarMathHelper::Dispatch( |
60 | | const OUString& cmd, const css::uno::Sequence<css::beans::PropertyValue>& rArguments) const |
61 | 0 | { |
62 | 0 | if (mxFrame) |
63 | 0 | comphelper::dispatchCommand(cmd, mxFrame, rArguments); |
64 | 0 | } |
65 | | |
66 | | namespace |
67 | | { |
68 | | // Find a child SmGraphicWindow* |
69 | | vcl::Window* FindSmGraphicWindow(vcl::Window* pWin) |
70 | 0 | { |
71 | 0 | if (!pWin) |
72 | 0 | return nullptr; |
73 | | |
74 | 0 | if (pWin->IsStarMath()) |
75 | 0 | return pWin; |
76 | | |
77 | 0 | pWin = pWin->GetWindow(GetWindowType::FirstChild); |
78 | 0 | while (pWin) |
79 | 0 | { |
80 | 0 | if (vcl::Window* pSmGraphicWindow = FindSmGraphicWindow(pWin)) |
81 | 0 | return pSmGraphicWindow; |
82 | 0 | pWin = pWin->GetWindow(GetWindowType::Next); |
83 | 0 | } |
84 | 0 | return nullptr; |
85 | 0 | } |
86 | | |
87 | | // Find a child window that corresponds to SmGraphicWidget |
88 | | vcl::Window* FindChildSmGraphicWidgetWindow(vcl::Window* pWin) |
89 | 0 | { |
90 | 0 | if (!pWin) |
91 | 0 | return nullptr; |
92 | | |
93 | | // The needed window is a VclDrawingArea |
94 | 0 | if (dynamic_cast<VclDrawingArea*>(pWin)) |
95 | 0 | return pWin; |
96 | | |
97 | 0 | pWin = pWin->GetWindow(GetWindowType::FirstChild); |
98 | 0 | while (pWin) |
99 | 0 | { |
100 | 0 | if (vcl::Window* pSmGraphicWidgetWindow = FindChildSmGraphicWidgetWindow(pWin)) |
101 | 0 | return pSmGraphicWidgetWindow; |
102 | 0 | pWin = pWin->GetWindow(GetWindowType::Next); |
103 | 0 | } |
104 | 0 | return nullptr; |
105 | 0 | } |
106 | | } |
107 | | |
108 | | vcl::Window* LokStarMathHelper::GetGraphicWindow() |
109 | 0 | { |
110 | 0 | if (!mpGraphicWindow) |
111 | 0 | { |
112 | 0 | if (mxFrame) |
113 | 0 | { |
114 | 0 | css::uno::Reference<css::awt::XWindow> xDockerWin = mxFrame->getContainerWindow(); |
115 | 0 | mpGraphicWindow.reset(FindSmGraphicWindow(VCLUnoHelper::GetWindow(xDockerWin))); |
116 | 0 | } |
117 | 0 | } |
118 | |
|
119 | 0 | return mpGraphicWindow.get(); |
120 | 0 | } |
121 | | |
122 | | vcl::Window* LokStarMathHelper::GetWidgetWindow() |
123 | 0 | { |
124 | 0 | if (!mpWidgetWindow) |
125 | 0 | mpWidgetWindow.reset(FindChildSmGraphicWidgetWindow(GetGraphicWindow())); |
126 | |
|
127 | 0 | return mpWidgetWindow.get(); |
128 | 0 | } |
129 | | |
130 | | const SfxViewShell* LokStarMathHelper::GetSmViewShell() |
131 | 0 | { |
132 | 0 | if (vcl::Window* pGraphWindow = GetGraphicWindow()) |
133 | 0 | { |
134 | 0 | return SfxViewShell::GetFirst(false, [pGraphWindow](const SfxViewShell& shell) { |
135 | 0 | return shell.GetWindow() && shell.GetWindow()->IsChild(pGraphWindow); |
136 | 0 | }); |
137 | 0 | } |
138 | 0 | return nullptr; |
139 | 0 | } |
140 | | |
141 | | tools::Rectangle LokStarMathHelper::GetBoundingBox() const |
142 | 0 | { |
143 | 0 | if (mpIPClient) |
144 | 0 | { |
145 | 0 | tools::Rectangle r(mpIPClient->GetObjArea()); |
146 | 0 | if (SfxObjectShell* pObjShell = const_cast<SfxViewShell*>(mpViewShell)->GetObjectShell()) |
147 | 0 | { |
148 | 0 | const o3tl::Length unit = MapToO3tlLength(pObjShell->GetMapUnit()); |
149 | 0 | if (unit != o3tl::Length::twip && unit != o3tl::Length::invalid) |
150 | 0 | r = o3tl::convert(r, unit, o3tl::Length::twip); |
151 | 0 | } |
152 | 0 | return r; |
153 | 0 | } |
154 | 0 | return {}; |
155 | 0 | } |
156 | | |
157 | | bool LokStarMathHelper::postMouseEvent(int nType, int nX, int nY, int nCount, int nButtons, |
158 | | int nModifier, double fPPTScaleX, double fPPTScaleY) |
159 | 0 | { |
160 | 0 | const tools::Rectangle rBBox = GetBoundingBox(); |
161 | 0 | if (Point aMousePos(nX, nY); rBBox.Contains(aMousePos)) |
162 | 0 | { |
163 | 0 | if (vcl::Window* pWindow = GetWidgetWindow()) |
164 | 0 | { |
165 | 0 | aMousePos -= rBBox.TopLeft(); |
166 | | |
167 | | // In lok, Math does not convert coordinates (see SmGraphicWidget::SetDrawingArea, |
168 | | // which disables MapMode), and uses twips internally (see SmDocShell ctor and |
169 | | // SmMapUnit), but the conversion factor can depend on the client zoom. |
170 | | // 1. Remove the twip->pixel factor in the passed scales |
171 | 0 | double fScaleX = o3tl::convert(fPPTScaleX, o3tl::Length::px, o3tl::Length::twip); |
172 | 0 | double fScaleY = o3tl::convert(fPPTScaleY, o3tl::Length::px, o3tl::Length::twip); |
173 | | // 2. Adjust the position according to the scales |
174 | 0 | aMousePos |
175 | 0 | = Point(std::round(aMousePos.X() * fScaleX), std::round(aMousePos.Y() * fScaleY)); |
176 | | // 3. Take window own scaling into account (reverses the conversion done in |
177 | | // SmGraphicWidget::MouseButtonDown, albeit incompletely - it does not handle |
178 | | // GetFormulaDrawPos; hopefully, in lok/in-place case, it's always [ 0, 0 ]?) |
179 | 0 | aMousePos = pWindow->LogicToPixel(aMousePos); |
180 | |
|
181 | 0 | LokMouseEventData aMouseEventData( |
182 | 0 | nType, aMousePos, nCount, MouseEventModifiers::SIMPLECLICK, nButtons, nModifier); |
183 | 0 | SfxLokHelper::postMouseEventAsync(pWindow, aMouseEventData); |
184 | |
|
185 | 0 | return true; |
186 | 0 | } |
187 | 0 | } |
188 | 0 | return false; |
189 | 0 | } |
190 | | |
191 | | void LokStarMathHelper::PaintTile(VirtualDevice& rDevice, const tools::Rectangle& rTileRect) |
192 | 0 | { |
193 | 0 | const tools::Rectangle aMathRect = GetBoundingBox(); |
194 | 0 | if (rTileRect.GetIntersection(aMathRect).IsEmpty()) |
195 | 0 | return; |
196 | | |
197 | 0 | vcl::Window* pWidgetWindow = GetWidgetWindow(); |
198 | 0 | if (!pWidgetWindow) |
199 | 0 | return; |
200 | | |
201 | 0 | Point aOffset(aMathRect.Left() - rTileRect.Left(), aMathRect.Top() - rTileRect.Top()); |
202 | |
|
203 | 0 | MapMode newMode = rDevice.GetMapMode(); |
204 | 0 | newMode.SetOrigin(aOffset); |
205 | 0 | rDevice.SetMapMode(newMode); // Push/Pop is done in PaintAllInPlaceOnTile |
206 | |
|
207 | 0 | pWidgetWindow->Paint(rDevice, {}); // SmGraphicWidget::Paint does not use the passed rectangle |
208 | 0 | } |
209 | | |
210 | | void LokStarMathHelper::PaintAllInPlaceOnTile(VirtualDevice& rDevice, int nOutputWidth, |
211 | | int nOutputHeight, int nTilePosX, int nTilePosY, |
212 | | tools::Long nTileWidth, tools::Long nTileHeight) |
213 | 0 | { |
214 | 0 | if (comphelper::LibreOfficeKit::isTiledAnnotations()) |
215 | 0 | return; |
216 | | |
217 | 0 | SfxViewShell* pCurView = SfxViewShell::Current(); |
218 | 0 | if (!pCurView) |
219 | 0 | return; |
220 | 0 | const ViewShellDocId nDocId = pCurView->GetDocId(); |
221 | 0 | const int nPartForCurView = pCurView->getPart(); |
222 | | |
223 | | // Resizes the virtual device to contain the entries context |
224 | 0 | rDevice.SetOutputSizePixel({ nOutputWidth, nOutputHeight }, /*bErase*/ false); |
225 | |
|
226 | 0 | auto popIt = rDevice.ScopedPush(vcl::PushFlags::MAPMODE); |
227 | 0 | MapMode aMapMode(rDevice.GetMapMode()); |
228 | | |
229 | | // Scaling. Must convert from pixels to twips. We know that VirtualDevices use a DPI of 96. |
230 | 0 | const double scale = conversionFract(o3tl::Length::px, o3tl::Length::twip); |
231 | 0 | const double scaleX = double(nOutputWidth) / nTileWidth * scale; |
232 | 0 | const double scaleY = double(nOutputHeight) / nTileHeight * scale; |
233 | 0 | aMapMode.SetScaleX(scaleX); |
234 | 0 | aMapMode.SetScaleY(scaleY); |
235 | 0 | aMapMode.SetMapUnit(MapUnit::MapTwip); |
236 | 0 | rDevice.SetMapMode(aMapMode); |
237 | |
|
238 | 0 | const tools::Rectangle aTileRect(Point(nTilePosX, nTilePosY), Size(nTileWidth, nTileHeight)); |
239 | |
|
240 | 0 | for (SfxViewShell* pViewShell = SfxViewShell::GetFirst(); pViewShell; |
241 | 0 | pViewShell = SfxViewShell::GetNext(*pViewShell)) |
242 | 0 | if (pViewShell->GetDocId() == nDocId && pViewShell->getPart() == nPartForCurView) |
243 | 0 | LokStarMathHelper(pViewShell).PaintTile(rDevice, aTileRect); |
244 | 0 | } |
245 | | |
246 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ |