/src/libreoffice/sc/source/ui/cctrl/dpcontrol.cxx
Line | Count | Source |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
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 | | * This file incorporates work covered by the following license notice: |
10 | | * |
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 . |
18 | | */ |
19 | | |
20 | | #include <dpcontrol.hxx> |
21 | | |
22 | | #include <vcl/outdev.hxx> |
23 | | #include <vcl/settings.hxx> |
24 | | #include <comphelper/lok.hxx> |
25 | | #include <scitems.hxx> |
26 | | #include <document.hxx> |
27 | | #include <docpool.hxx> |
28 | | #include <patattr.hxx> |
29 | | #include <svtools/colorcfg.hxx> |
30 | | #include <tools/mapunit.hxx> |
31 | | |
32 | | ScDPFieldButton::ScDPFieldButton(OutputDevice* pOutDev, const StyleSettings& rStyle, double fZoomY, ScDocument& rDoc): |
33 | 0 | mfZoomY(fZoomY), |
34 | 0 | mrDoc(rDoc), |
35 | 0 | mpOutDev(pOutDev), |
36 | 0 | mrStyle(rStyle), |
37 | 0 | mnToggleIndent(0), |
38 | 0 | mbBaseButton(true), |
39 | 0 | mbPopupButton(false), |
40 | 0 | mbPopupButtonMulti(false), |
41 | 0 | mbToggleButton(false), |
42 | 0 | mbToggleCollapse(false), |
43 | 0 | mbHasHiddenMember(false), |
44 | 0 | mbPopupPressed(false), |
45 | 0 | mbPopupLeft(false) |
46 | 0 | { |
47 | 0 | } |
48 | | |
49 | | ScDPFieldButton::~ScDPFieldButton() |
50 | 0 | { |
51 | 0 | } |
52 | | |
53 | | void ScDPFieldButton::setText(const OUString& rText) |
54 | 0 | { |
55 | 0 | maText = rText; |
56 | 0 | } |
57 | | |
58 | | void ScDPFieldButton::setBoundingBox(const Point& rPos, const Size& rSize, bool bLayoutRTL) |
59 | 0 | { |
60 | 0 | maPos = rPos; |
61 | 0 | maSize = rSize; |
62 | 0 | if (bLayoutRTL) |
63 | 0 | { |
64 | | // rPos is the logical-left position, adjust maPos to visual-left (inside the cell border) |
65 | 0 | maPos.AdjustX( -(maSize.Width() - 1) ); |
66 | 0 | } |
67 | 0 | } |
68 | | |
69 | | void ScDPFieldButton::setDrawBaseButton(bool b) |
70 | 0 | { |
71 | 0 | mbBaseButton = b; |
72 | 0 | } |
73 | | |
74 | | void ScDPFieldButton::setDrawPopupButton(bool b) |
75 | 0 | { |
76 | 0 | mbPopupButton = b; |
77 | 0 | } |
78 | | |
79 | | void ScDPFieldButton::setDrawPopupButtonMulti(bool b) |
80 | 0 | { |
81 | 0 | mbPopupButtonMulti = b; |
82 | 0 | } |
83 | | |
84 | | void ScDPFieldButton::setDrawToggleButton(bool b, bool bCollapse, sal_Int32 nIndent) |
85 | 0 | { |
86 | 0 | mbToggleButton = b; |
87 | 0 | mbToggleCollapse = bCollapse; |
88 | 0 | mnToggleIndent = nIndent; |
89 | 0 | } |
90 | | |
91 | | void ScDPFieldButton::setHasHiddenMember(bool b) |
92 | 0 | { |
93 | 0 | mbHasHiddenMember = b; |
94 | 0 | } |
95 | | |
96 | | void ScDPFieldButton::setPopupPressed(bool b) |
97 | 0 | { |
98 | 0 | mbPopupPressed = b; |
99 | 0 | } |
100 | | |
101 | | void ScDPFieldButton::setPopupLeft(bool b) |
102 | 0 | { |
103 | 0 | mbPopupLeft = b; |
104 | 0 | } |
105 | | |
106 | | void ScDPFieldButton::draw() |
107 | 0 | { |
108 | 0 | bool bOldMapEnabled = mpOutDev->IsMapModeEnabled(); |
109 | |
|
110 | 0 | if (mpOutDev->GetMapMode().GetMapUnit() != MapUnit::MapPixel) |
111 | 0 | mpOutDev->EnableMapMode(false); |
112 | |
|
113 | 0 | if (mbBaseButton) |
114 | 0 | { |
115 | | // Background |
116 | 0 | tools::Rectangle aRect(maPos, maSize); |
117 | 0 | mpOutDev->SetLineColor(mrStyle.GetFaceColor()); |
118 | 0 | mpOutDev->SetFillColor(mrStyle.GetFaceColor()); |
119 | 0 | mpOutDev->DrawRect(aRect); |
120 | | |
121 | | // Border lines |
122 | 0 | mpOutDev->SetLineColor(mrStyle.GetLightColor()); |
123 | 0 | mpOutDev->DrawLine(maPos, Point(maPos.X(), maPos.Y()+maSize.Height()-1)); |
124 | 0 | mpOutDev->DrawLine(maPos, Point(maPos.X()+maSize.Width()-1, maPos.Y())); |
125 | |
|
126 | 0 | mpOutDev->SetLineColor(mrStyle.GetShadowColor()); |
127 | 0 | mpOutDev->DrawLine(Point(maPos.X(), maPos.Y()+maSize.Height()-1), |
128 | 0 | Point(maPos.X()+maSize.Width()-1, maPos.Y()+maSize.Height()-1)); |
129 | 0 | mpOutDev->DrawLine(Point(maPos.X()+maSize.Width()-1, maPos.Y()), |
130 | 0 | Point(maPos.X()+maSize.Width()-1, maPos.Y()+maSize.Height()-1)); |
131 | | |
132 | | // Field name. |
133 | | // Get the font and size the same way as in scenario selection (lcl_DrawOneFrame in gridwin4.cxx) |
134 | 0 | vcl::Font aTextFont( mrStyle.GetAppFont() ); |
135 | | // use ScPatternAttr::GetFont only for font size |
136 | 0 | vcl::Font aAttrFont; |
137 | 0 | mrDoc.getCellAttributeHelper().getDefaultCellAttribute().fillFontOnly(aAttrFont, mpOutDev, &mfZoomY); |
138 | 0 | aTextFont.SetFontSize(aAttrFont.GetFontSize()); |
139 | 0 | mpOutDev->SetFont(aTextFont); |
140 | 0 | mpOutDev->SetTextColor(mrStyle.GetButtonTextColor()); |
141 | |
|
142 | 0 | Point aTextPos = maPos; |
143 | 0 | tools::Long nTHeight = mpOutDev->GetTextHeight(); |
144 | 0 | aTextPos.setX(maPos.getX() + 2); // 2 = Margin |
145 | 0 | aTextPos.setY(maPos.getY() + (maSize.Height()-nTHeight)/2); |
146 | |
|
147 | 0 | auto popIt = mpOutDev->ScopedPush(vcl::PushFlags::CLIPREGION); |
148 | 0 | mpOutDev->IntersectClipRegion(aRect); |
149 | 0 | mpOutDev->DrawText(aTextPos, maText); |
150 | 0 | } |
151 | |
|
152 | 0 | if (mbPopupButton || mbPopupButtonMulti) |
153 | 0 | drawPopupButton(); |
154 | |
|
155 | 0 | if (mbToggleButton) |
156 | 0 | drawToggleButton(); |
157 | |
|
158 | 0 | mpOutDev->EnableMapMode(bOldMapEnabled); |
159 | 0 | } |
160 | | |
161 | | void ScDPFieldButton::getPopupBoundingBox(Point& rPos, Size& rSize) const |
162 | 0 | { |
163 | 0 | float fScaleFactor = mpOutDev->GetDPIScaleFactor(); |
164 | |
|
165 | 0 | tools::Long nMaxSize = 18 * fScaleFactor; // Button max size in either dimension |
166 | |
|
167 | 0 | tools::Long nW = std::min(maSize.getWidth() / 2, nMaxSize); |
168 | 0 | tools::Long nH = std::min(maSize.getHeight(), nMaxSize); |
169 | |
|
170 | 0 | double fZoom = mfZoomY > 1.0 ? mfZoomY : 1.0; |
171 | 0 | if (fZoom > 1.0) |
172 | 0 | { |
173 | 0 | nW = fZoom * (nW - 1); |
174 | 0 | nH = fZoom * (nH - 1); |
175 | 0 | } |
176 | | |
177 | | // #i114944# AutoFilter button is left-aligned in RTL. |
178 | | // DataPilot button is always right-aligned for now, so text output isn't affected. |
179 | 0 | if (mbPopupLeft) |
180 | 0 | rPos.setX(maPos.getX()); |
181 | 0 | else |
182 | 0 | rPos.setX(maPos.getX() + maSize.getWidth() - nW); |
183 | |
|
184 | 0 | rPos.setY(maPos.getY() + maSize.getHeight() - nH); |
185 | 0 | rSize.setWidth(nW); |
186 | 0 | rSize.setHeight(nH); |
187 | 0 | } |
188 | | |
189 | | void ScDPFieldButton::getToggleBoundingBox(Point& rPos, Size& rSize) const |
190 | 0 | { |
191 | 0 | const float fScaleFactor = mpOutDev->GetDPIScaleFactor(); |
192 | |
|
193 | 0 | tools::Long nMaxSize = 13 * fScaleFactor; // Button max size in either dimension |
194 | 0 | tools::Long nMargin = 3 * fScaleFactor; |
195 | |
|
196 | 0 | tools::Long nIndent = fScaleFactor * o3tl::convert(mnToggleIndent, o3tl::Length::twip, o3tl::Length::px); |
197 | 0 | tools::Long nW = std::min(maSize.getWidth() / 2, nMaxSize); |
198 | 0 | tools::Long nH = std::min(maSize.getHeight(), nMaxSize); |
199 | 0 | nIndent = std::min(nIndent, maSize.getWidth()); |
200 | |
|
201 | 0 | double fZoom = mfZoomY > 1.0 ? mfZoomY : 1.0; |
202 | 0 | if (fZoom > 1.0) |
203 | 0 | { |
204 | 0 | nW = fZoom * (nW - 1); |
205 | 0 | nH = fZoom * (nH - 1); |
206 | 0 | nIndent = fZoom * (nIndent -1); |
207 | 0 | nMargin = fZoom * (nMargin - 1); |
208 | 0 | } |
209 | | |
210 | | // FIXME: RTL case ? |
211 | 0 | rPos.setX(maPos.getX() + nIndent - nW + nMargin); |
212 | 0 | rPos.setY(maPos.getY() + maSize.getHeight() / 2 - nH / 2 + nMargin); |
213 | 0 | rSize.setWidth(nW - nMargin - 1); |
214 | 0 | rSize.setHeight(nH - nMargin - 1); |
215 | 0 | } |
216 | | |
217 | | void ScDPFieldButton::drawPopupButton() |
218 | 0 | { |
219 | 0 | Point aPos; |
220 | 0 | Size aSize; |
221 | 0 | getPopupBoundingBox(aPos, aSize); |
222 | |
|
223 | 0 | float fScaleFactor = mpOutDev->GetDPIScaleFactor(); |
224 | | |
225 | | // Button background color |
226 | 0 | Color aFaceColor = mrStyle.GetFaceColor(); |
227 | 0 | Color aBackgroundColor |
228 | 0 | = mbHasHiddenMember ? mrStyle.GetHighlightColor() |
229 | 0 | : mbPopupPressed ? mrStyle.GetShadowColor() : aFaceColor; |
230 | | |
231 | | // Button line color |
232 | 0 | mpOutDev->SetLineColor(mrStyle.GetLabelTextColor()); |
233 | | // If the document background is light and face color is dark, use ShadowColor instead |
234 | 0 | Color aDocColor = svtools::ColorConfig().GetColorValue(svtools::DOCCOLOR).nColor; |
235 | 0 | if (aDocColor.IsBright() && aFaceColor.IsDark()) |
236 | 0 | mpOutDev->SetLineColor(mrStyle.GetShadowColor()); |
237 | |
|
238 | 0 | mpOutDev->SetFillColor(aBackgroundColor); |
239 | 0 | mpOutDev->DrawRect(tools::Rectangle(aPos, aSize)); |
240 | | |
241 | | // the arrowhead |
242 | 0 | Color aArrowColor = mbHasHiddenMember ? mrStyle.GetHighlightTextColor() : mrStyle.GetButtonTextColor(); |
243 | | // FIXME: HACK: The following DrawPolygon draws twice in lok rtl mode for some reason. |
244 | | // => one at the correct location with fill (possibly no outline) |
245 | | // => and the other at an x offset with outline and without fill |
246 | | // eg. Replacing this with a DrawRect() does not have any such problems. |
247 | 0 | comphelper::LibreOfficeKit::isActive() ? mpOutDev->SetLineColor() : mpOutDev->SetLineColor(aArrowColor); |
248 | 0 | mpOutDev->SetFillColor(aArrowColor); |
249 | |
|
250 | 0 | Point aCenter(aPos.X() + (aSize.Width() / 2), aPos.Y() + (aSize.Height() / 2)); |
251 | |
|
252 | 0 | Size aArrowSize(4 * fScaleFactor, 2 * fScaleFactor); |
253 | |
|
254 | 0 | tools::Polygon aPoly(3); |
255 | 0 | aPoly.SetPoint(Point(aCenter.X() - aArrowSize.Width(), aCenter.Y() - aArrowSize.Height()), 0); |
256 | 0 | aPoly.SetPoint(Point(aCenter.X() + aArrowSize.Width(), aCenter.Y() - aArrowSize.Height()), 1); |
257 | 0 | aPoly.SetPoint(Point(aCenter.X(), aCenter.Y() + aArrowSize.Height()), 2); |
258 | 0 | mpOutDev->DrawPolygon(aPoly); |
259 | |
|
260 | 0 | if (mbHasHiddenMember) |
261 | 0 | { |
262 | | // tiny little box to display in presence of hidden member(s). |
263 | 0 | Point aBoxPos(aPos.X() + aSize.Width() - 5 * fScaleFactor, aPos.Y() + aSize.Height() - 5 * fScaleFactor); |
264 | 0 | Size aBoxSize(3 * fScaleFactor, 3 * fScaleFactor); |
265 | 0 | mpOutDev->DrawRect(tools::Rectangle(aBoxPos, aBoxSize)); |
266 | 0 | } |
267 | 0 | } |
268 | | |
269 | | void ScDPFieldButton::drawToggleButton() |
270 | 0 | { |
271 | 0 | Point aPos; |
272 | 0 | Size aSize; |
273 | 0 | getToggleBoundingBox(aPos, aSize); |
274 | | |
275 | | // Background & outer black border |
276 | 0 | mpOutDev->SetLineColor(COL_BLACK); |
277 | 0 | mpOutDev->SetFillColor(); |
278 | 0 | mpOutDev->DrawRect(tools::Rectangle(aPos, aSize)); |
279 | |
|
280 | 0 | Point aCenter(aPos.X() + aSize.getWidth() / 2, aPos.Y() + aSize.getHeight() / 2); |
281 | |
|
282 | 0 | mpOutDev->DrawLine( |
283 | 0 | Point(aPos.X() + 2, aCenter.Y()), |
284 | 0 | Point(aPos.X() + aSize.getWidth() - 2, aCenter.Y())); |
285 | |
|
286 | 0 | if (!mbToggleCollapse) |
287 | 0 | { |
288 | 0 | mpOutDev->DrawLine( |
289 | 0 | Point(aCenter.X(), aPos.Y() + 2), |
290 | 0 | Point(aCenter.X(), aPos.Y() + aSize.getHeight() - 2)); |
291 | 0 | } |
292 | 0 | } |
293 | | |
294 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |