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