xref: /core/sc/source/ui/cctrl/dpcontrol.cxx (revision ce76f924)
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 
30 ScDPFieldButton::ScDPFieldButton(OutputDevice* pOutDev, const StyleSettings* pStyle, const Fraction* pZoomY, ScDocument* pDoc) :
31     mpDoc(pDoc),
32     mpOutDev(pOutDev),
33     mpStyle(pStyle),
34     mbBaseButton(true),
35     mbPopupButton(false),
36     mbHasHiddenMember(false),
37     mbPopupPressed(false),
38     mbPopupLeft(false)
39 {
40     if (pZoomY)
41         maZoomY = *pZoomY;
42     else
43         maZoomY = Fraction(1, 1);
44 }
45 
46 ScDPFieldButton::~ScDPFieldButton()
47 {
48 }
49 
50 void ScDPFieldButton::setText(const OUString& rText)
51 {
52     maText = rText;
53 }
54 
55 void ScDPFieldButton::setBoundingBox(const Point& rPos, const Size& rSize, bool bLayoutRTL)
56 {
57     maPos = rPos;
58     maSize = rSize;
59     if (bLayoutRTL)
60     {
61         // rPos is the logical-left position, adjust maPos to visual-left (inside the cell border)
62         maPos.AdjustX( -(maSize.Width() - 1) );
63     }
64 }
65 
66 void ScDPFieldButton::setDrawBaseButton(bool b)
67 {
68     mbBaseButton = b;
69 }
70 
71 void ScDPFieldButton::setDrawPopupButton(bool b)
72 {
73     mbPopupButton = b;
74 }
75 
76 void ScDPFieldButton::setHasHiddenMember(bool b)
77 {
78     mbHasHiddenMember = b;
79 }
80 
81 void ScDPFieldButton::setPopupPressed(bool b)
82 {
83     mbPopupPressed = b;
84 }
85 
86 void ScDPFieldButton::setPopupLeft(bool b)
87 {
88     mbPopupLeft = b;
89 }
90 
91 void ScDPFieldButton::draw()
92 {
93     bool bOldMapEnabled = mpOutDev->IsMapModeEnabled();
94 
95     if (mpOutDev->GetMapMode().GetMapUnit() != MapUnit::MapPixel)
96         mpOutDev->EnableMapMode(false);
97 
98     if (mbBaseButton)
99     {
100         // Background
101         tools::Rectangle aRect(maPos, maSize);
102         mpOutDev->SetLineColor(mpStyle->GetFaceColor());
103         mpOutDev->SetFillColor(mpStyle->GetFaceColor());
104         mpOutDev->DrawRect(aRect);
105 
106         // Border lines
107         mpOutDev->SetLineColor(mpStyle->GetLightColor());
108         mpOutDev->DrawLine(maPos, Point(maPos.X(), maPos.Y()+maSize.Height()-1));
109         mpOutDev->DrawLine(maPos, Point(maPos.X()+maSize.Width()-1, maPos.Y()));
110 
111         mpOutDev->SetLineColor(mpStyle->GetShadowColor());
112         mpOutDev->DrawLine(Point(maPos.X(), maPos.Y()+maSize.Height()-1),
113                            Point(maPos.X()+maSize.Width()-1, maPos.Y()+maSize.Height()-1));
114         mpOutDev->DrawLine(Point(maPos.X()+maSize.Width()-1, maPos.Y()),
115                            Point(maPos.X()+maSize.Width()-1, maPos.Y()+maSize.Height()-1));
116 
117         // Field name.
118         // Get the font and size the same way as in scenario selection (lcl_DrawOneFrame in gridwin4.cxx)
119         vcl::Font aTextFont( mpStyle->GetAppFont() );
120         if ( mpDoc )
121         {
122             //  use ScPatternAttr::GetFont only for font size
123             vcl::Font aAttrFont;
124             mpDoc->GetPool()->GetDefaultItem(ATTR_PATTERN).
125                 GetFont( aAttrFont, SC_AUTOCOL_BLACK, mpOutDev, &maZoomY );
126             aTextFont.SetFontSize( aAttrFont.GetFontSize() );
127         }
128         mpOutDev->SetFont(aTextFont);
129         mpOutDev->SetTextColor(mpStyle->GetButtonTextColor());
130 
131         Point aTextPos = maPos;
132         tools::Long nTHeight = mpOutDev->GetTextHeight();
133         aTextPos.setX(maPos.getX() + 2); // 2 = Margin
134         aTextPos.setY(maPos.getY() + (maSize.Height()-nTHeight)/2);
135 
136         mpOutDev->Push(vcl::PushFlags::CLIPREGION);
137         mpOutDev->IntersectClipRegion(aRect);
138         mpOutDev->DrawText(aTextPos, maText);
139         mpOutDev->Pop();
140     }
141 
142     if (mbPopupButton)
143         drawPopupButton();
144 
145     mpOutDev->EnableMapMode(bOldMapEnabled);
146 }
147 
148 void ScDPFieldButton::getPopupBoundingBox(Point& rPos, Size& rSize) const
149 {
150     float fScaleFactor = mpOutDev->GetDPIScaleFactor();
151 
152     tools::Long nMaxSize = 18 * fScaleFactor; // Button max size in either dimension
153 
154     tools::Long nW = std::min(maSize.getWidth() / 2, nMaxSize);
155     tools::Long nH = std::min(maSize.getHeight(),    nMaxSize);
156 
157     double fZoom = static_cast<double>(maZoomY) > 1.0 ? static_cast<double>(maZoomY) : 1.0;
158     if (fZoom > 1.0)
159     {
160         nW = fZoom * (nW - 1);
161         nH = fZoom * (nH - 1);
162     }
163 
164     // #i114944# AutoFilter button is left-aligned in RTL.
165     // DataPilot button is always right-aligned for now, so text output isn't affected.
166     if (mbPopupLeft)
167         rPos.setX(maPos.getX());
168     else
169         rPos.setX(maPos.getX() + maSize.getWidth() - nW);
170 
171     rPos.setY(maPos.getY() + maSize.getHeight() - nH);
172     rSize.setWidth(nW);
173     rSize.setHeight(nH);
174 }
175 
176 void ScDPFieldButton::drawPopupButton()
177 {
178     Point aPos;
179     Size aSize;
180     getPopupBoundingBox(aPos, aSize);
181 
182     float fScaleFactor = mpOutDev->GetDPIScaleFactor();
183 
184     // Background & outer black border
185     mpOutDev->SetLineColor(COL_BLACK);
186     Color aBackgroundColor
187         = mbHasHiddenMember ? mpStyle->GetHighlightColor()
188                             : mbPopupPressed ? mpStyle->GetShadowColor() : mpStyle->GetFaceColor();
189     mpOutDev->SetFillColor(aBackgroundColor);
190     mpOutDev->DrawRect(tools::Rectangle(aPos, aSize));
191 
192     // the arrowhead
193     Color aArrowColor = mbHasHiddenMember ? mpStyle->GetHighlightTextColor() : mpStyle->GetButtonTextColor();
194     // FIXME: HACK: The following DrawPolygon draws twice in lok rtl mode for some reason.
195     // => one at the correct location with fill (possibly no outline)
196     // => and the other at an x offset with outline and without fill
197     // eg. Replacing this with a DrawRect() does not have any such problems.
198     comphelper::LibreOfficeKit::isActive() ? mpOutDev->SetLineColor() : mpOutDev->SetLineColor(aArrowColor);
199     mpOutDev->SetFillColor(aArrowColor);
200 
201     Point aCenter(aPos.X() + (aSize.Width() / 2), aPos.Y() + (aSize.Height() / 2));
202 
203     Size aArrowSize(4 * fScaleFactor, 2 * fScaleFactor);
204 
205     tools::Polygon aPoly(3);
206     aPoly.SetPoint(Point(aCenter.X() - aArrowSize.Width(), aCenter.Y() - aArrowSize.Height()), 0);
207     aPoly.SetPoint(Point(aCenter.X() + aArrowSize.Width(), aCenter.Y() - aArrowSize.Height()), 1);
208     aPoly.SetPoint(Point(aCenter.X(),                      aCenter.Y() + aArrowSize.Height()), 2);
209     mpOutDev->DrawPolygon(aPoly);
210 
211     if (mbHasHiddenMember)
212     {
213         // tiny little box to display in presence of hidden member(s).
214         Point aBoxPos(aPos.X() + aSize.Width() - 5 * fScaleFactor, aPos.Y() + aSize.Height() - 5 * fScaleFactor);
215         Size aBoxSize(3 * fScaleFactor, 3 * fScaleFactor);
216         mpOutDev->DrawRect(tools::Rectangle(aBoxPos, aBoxSize));
217     }
218 }
219 
220 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
221