/src/libreoffice/sw/source/uibase/docvw/HeaderFooterWin.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 | | |
10 | | #include <strings.hrc> |
11 | | |
12 | | #include <doc.hxx> |
13 | | #include <drawdoc.hxx> |
14 | | #include <cmdid.h> |
15 | | #include <DashedLine.hxx> |
16 | | #include <docsh.hxx> |
17 | | #include <edtwin.hxx> |
18 | | #include <fmthdft.hxx> |
19 | | #include <HeaderFooterWin.hxx> |
20 | | #include <pagedesc.hxx> |
21 | | #include <pagefrm.hxx> |
22 | | #include <view.hxx> |
23 | | #include <viewopt.hxx> |
24 | | #include <wrtsh.hxx> |
25 | | #include <IDocumentDrawModelAccess.hxx> |
26 | | |
27 | | #include <basegfx/color/bcolortools.hxx> |
28 | | #include <basegfx/matrix/b2dhommatrixtools.hxx> |
29 | | #include <basegfx/polygon/b2dpolygon.hxx> |
30 | | #include <basegfx/range/b2drectangle.hxx> |
31 | | #include <basegfx/vector/b2dsize.hxx> |
32 | | #include <basegfx/utils/gradienttools.hxx> |
33 | | #include <drawinglayer/attribute/fillgradientattribute.hxx> |
34 | | #include <drawinglayer/attribute/fontattribute.hxx> |
35 | | #include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx> |
36 | | #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> |
37 | | #include <drawinglayer/primitive2d/PolygonHairlinePrimitive2D.hxx> |
38 | | #include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx> |
39 | | #include <drawinglayer/primitive2d/textlayoutdevice.hxx> |
40 | | #include <drawinglayer/primitive2d/textprimitive2d.hxx> |
41 | | #include <editeng/boxitem.hxx> |
42 | | #include <svx/hdft.hxx> |
43 | | #include <sfx2/bindings.hxx> |
44 | | #include <sfx2/viewfrm.hxx> |
45 | | #include <drawinglayer/processor2d/baseprocessor2d.hxx> |
46 | | #include <drawinglayer/processor2d/processor2dtools.hxx> |
47 | | #include <vcl/canvastools.hxx> |
48 | | #include <vcl/metric.hxx> |
49 | | #include <vcl/svapp.hxx> |
50 | | #include <vcl/settings.hxx> |
51 | | #include <vcl/virdev.hxx> |
52 | | #include <vcl/weld/Builder.hxx> |
53 | | #include <vcl/weld/MenuButton.hxx> |
54 | | #include <memory> |
55 | | |
56 | 0 | #define TEXT_PADDING 5 |
57 | 0 | #define BOX_DISTANCE 10 |
58 | 0 | #define BUTTON_WIDTH 18 |
59 | | |
60 | | using namespace basegfx; |
61 | | using namespace basegfx::utils; |
62 | | using namespace drawinglayer::attribute; |
63 | | |
64 | | namespace |
65 | | { |
66 | | basegfx::BColor lcl_GetFillColor(const basegfx::BColor& rLineColor) |
67 | 0 | { |
68 | 0 | basegfx::BColor aHslLine = basegfx::utils::rgb2hsl(rLineColor); |
69 | 0 | double nLuminance = aHslLine.getZ() * 2.5; |
70 | 0 | if ( nLuminance == 0 ) |
71 | 0 | nLuminance = 0.5; |
72 | 0 | else if ( nLuminance >= 1.0 ) |
73 | 0 | nLuminance = aHslLine.getZ() * 0.4; |
74 | 0 | aHslLine.setZ( nLuminance ); |
75 | 0 | return basegfx::utils::hsl2rgb( aHslLine ); |
76 | 0 | } |
77 | | |
78 | | basegfx::BColor lcl_GetLighterGradientColor(const basegfx::BColor& rDarkColor) |
79 | 0 | { |
80 | 0 | basegfx::BColor aHslDark = basegfx::utils::rgb2hsl(rDarkColor); |
81 | 0 | double nLuminance = aHslDark.getZ() * 255 + 20; |
82 | 0 | aHslDark.setZ( nLuminance / 255.0 ); |
83 | 0 | return basegfx::utils::hsl2rgb( aHslDark ); |
84 | 0 | } |
85 | | |
86 | | B2DPolygon lcl_GetPolygon( const ::tools::Rectangle& rRect, bool bOnTop ) |
87 | 0 | { |
88 | 0 | const double nRadius = 3; |
89 | 0 | const double nKappa((M_SQRT2 - 1.0) * 4.0 / 3.0); |
90 | |
|
91 | 0 | B2DPolygon aPolygon; |
92 | 0 | aPolygon.append( B2DPoint( rRect.Left(), rRect.Top() ) ); |
93 | |
|
94 | 0 | { |
95 | 0 | B2DPoint aCorner( rRect.Left(), rRect.Bottom() ); |
96 | 0 | B2DPoint aStart( rRect.Left(), rRect.Bottom() - nRadius ); |
97 | 0 | B2DPoint aEnd( rRect.Left() + nRadius, rRect.Bottom() ); |
98 | 0 | aPolygon.append( aStart ); |
99 | 0 | aPolygon.appendBezierSegment( |
100 | 0 | interpolate( aStart, aCorner, nKappa ), |
101 | 0 | interpolate( aEnd, aCorner, nKappa ), |
102 | 0 | aEnd ); |
103 | 0 | } |
104 | |
|
105 | 0 | { |
106 | 0 | B2DPoint aCorner( rRect.Right(), rRect.Bottom() ); |
107 | 0 | B2DPoint aStart( rRect.Right() - nRadius, rRect.Bottom() ); |
108 | 0 | B2DPoint aEnd( rRect.Right(), rRect.Bottom() - nRadius ); |
109 | 0 | aPolygon.append( aStart ); |
110 | 0 | aPolygon.appendBezierSegment( |
111 | 0 | interpolate( aStart, aCorner, nKappa ), |
112 | 0 | interpolate( aEnd, aCorner, nKappa ), |
113 | 0 | aEnd ); |
114 | 0 | } |
115 | |
|
116 | 0 | aPolygon.append( B2DPoint( rRect.Right(), rRect.Top() ) ); |
117 | |
|
118 | 0 | if ( !bOnTop ) |
119 | 0 | { |
120 | 0 | B2DRectangle aBRect = vcl::unotools::b2DRectangleFromRectangle(rRect); |
121 | 0 | B2DHomMatrix aRotation = createRotateAroundPoint( |
122 | 0 | aBRect.getCenterX(), aBRect.getCenterY(), M_PI ); |
123 | 0 | aPolygon.transform( aRotation ); |
124 | 0 | } |
125 | |
|
126 | 0 | return aPolygon; |
127 | 0 | } |
128 | | } |
129 | | |
130 | | void SwFrameButtonPainter::PaintButton(drawinglayer::primitive2d::Primitive2DContainer& rSeq, |
131 | | const tools::Rectangle& rRect, bool bOnTop) |
132 | 0 | { |
133 | 0 | rSeq.clear(); |
134 | 0 | B2DPolygon aPolygon = lcl_GetPolygon(rRect, bOnTop); |
135 | | |
136 | | // Colors |
137 | 0 | basegfx::BColor aLineColor = SwViewOption::GetCurrentViewOptions().GetHeaderFooterMarkColor().getBColor(); |
138 | 0 | basegfx::BColor aFillColor = lcl_GetFillColor(aLineColor); |
139 | 0 | basegfx::BColor aLighterColor = lcl_GetLighterGradientColor(aFillColor); |
140 | |
|
141 | 0 | const StyleSettings& rSettings = Application::GetSettings().GetStyleSettings(); |
142 | 0 | if (rSettings.GetHighContrastMode()) |
143 | 0 | { |
144 | 0 | aFillColor = rSettings.GetDialogColor().getBColor(); |
145 | 0 | aLineColor = rSettings.GetDialogTextColor().getBColor(); |
146 | |
|
147 | 0 | rSeq.push_back(new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(B2DPolyPolygon(aPolygon), aFillColor)); |
148 | 0 | } |
149 | 0 | else |
150 | 0 | { |
151 | 0 | B2DRectangle aGradientRect = vcl::unotools::b2DRectangleFromRectangle(rRect); |
152 | 0 | double nAngle = M_PI; |
153 | 0 | if (bOnTop) |
154 | 0 | nAngle = 0; |
155 | |
|
156 | 0 | FillGradientAttribute aFillAttrs(css::awt::GradientStyle_LINEAR, 0.0, 0.0, 0.0, nAngle, |
157 | 0 | basegfx::BColorStops(aLighterColor, aFillColor)); |
158 | 0 | rSeq.push_back(new drawinglayer::primitive2d::FillGradientPrimitive2D(aGradientRect, std::move(aFillAttrs))); |
159 | 0 | } |
160 | | |
161 | | // Create the border lines primitive |
162 | 0 | rSeq.push_back(new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(std::move(aPolygon), aLineColor)); |
163 | 0 | } |
164 | | |
165 | | SwHeaderFooterDashedLine::SwHeaderFooterDashedLine(SwEditWin* pEditWin, const SwFrame *pFrame, bool bHeader) |
166 | 0 | : SwDashedLine(pEditWin, &SwViewOption::GetHeaderFooterMarkColor) |
167 | 0 | , m_pEditWin(pEditWin) |
168 | 0 | , m_pFrame(pFrame) |
169 | 0 | , m_bIsHeader(bHeader) |
170 | 0 | { |
171 | 0 | } Unexecuted instantiation: SwHeaderFooterDashedLine::SwHeaderFooterDashedLine(SwEditWin*, SwFrame const*, bool) Unexecuted instantiation: SwHeaderFooterDashedLine::SwHeaderFooterDashedLine(SwEditWin*, SwFrame const*, bool) |
172 | | |
173 | | bool SwHeaderFooterDashedLine::IsOnScreen() |
174 | 0 | { |
175 | 0 | tools::Rectangle aBounds(GetPosPixel(), GetSizePixel()); |
176 | 0 | tools::Rectangle aVisArea = GetEditWin()->LogicToPixel(GetEditWin()->GetView().GetVisArea()); |
177 | 0 | return aBounds.Overlaps(aVisArea); |
178 | 0 | } |
179 | | |
180 | | void SwHeaderFooterDashedLine::EnsureWin() |
181 | 0 | { |
182 | 0 | if (!m_pWin) |
183 | 0 | { |
184 | 0 | m_pWin = VclPtr<SwHeaderFooterWin>::Create(m_pEditWin, m_pFrame, m_bIsHeader); |
185 | 0 | m_pWin->SetZOrder(this, ZOrderFlags::Before); |
186 | 0 | } |
187 | 0 | } |
188 | | |
189 | | void SwHeaderFooterDashedLine::ShowAll(bool bShow) |
190 | 0 | { |
191 | 0 | Show(bShow); |
192 | 0 | if (!m_pWin && IsOnScreen()) |
193 | 0 | EnsureWin(); |
194 | 0 | if (m_pWin) |
195 | 0 | m_pWin->ShowAll(bShow); |
196 | 0 | } |
197 | | |
198 | | void SwHeaderFooterDashedLine::SetReadonly(bool bReadonly) |
199 | 0 | { |
200 | 0 | ShowAll(!bReadonly); |
201 | 0 | } |
202 | | |
203 | | bool SwHeaderFooterDashedLine::Contains(const Point &rDocPt) const |
204 | 0 | { |
205 | 0 | if (m_pWin && m_pWin->Contains(rDocPt)) |
206 | 0 | return true; |
207 | | |
208 | 0 | ::tools::Rectangle aLineRect(GetPosPixel(), GetSizePixel()); |
209 | 0 | return aLineRect.Contains(rDocPt); |
210 | 0 | } |
211 | | |
212 | | void SwHeaderFooterDashedLine::SetOffset(Point aOffset, tools::Long nXLineStart, tools::Long nXLineEnd) |
213 | 0 | { |
214 | 0 | Point aLinePos(nXLineStart, aOffset.Y()); |
215 | 0 | Size aLineSize(nXLineEnd - nXLineStart, 1); |
216 | 0 | SetPosSizePixel(aLinePos, aLineSize); |
217 | |
|
218 | 0 | bool bOnScreen = IsOnScreen(); |
219 | 0 | if (!m_pWin && bOnScreen) |
220 | 0 | { |
221 | 0 | EnsureWin(); |
222 | 0 | m_pWin->ShowAll(true); |
223 | 0 | } |
224 | 0 | else if (m_pWin && !bOnScreen) |
225 | 0 | m_pWin.disposeAndClear(); |
226 | |
|
227 | 0 | if (m_pWin) |
228 | 0 | m_pWin->SetOffset(aOffset); |
229 | 0 | } |
230 | | |
231 | | SwHeaderFooterWin::SwHeaderFooterWin(SwEditWin* pEditWin, const SwFrame *pFrame, bool bHeader ) : |
232 | 0 | InterimItemWindow(pEditWin, u"modules/swriter/ui/hfmenubutton.ui"_ustr, u"HFMenuButton"_ustr), |
233 | 0 | m_xMenuButton(m_xBuilder->weld_menu_button(u"menubutton"_ustr)), |
234 | 0 | m_xPushButton(m_xBuilder->weld_button(u"button"_ustr)), |
235 | 0 | m_pEditWin(pEditWin), |
236 | 0 | m_pFrame(pFrame), |
237 | 0 | m_bIsHeader( bHeader ), |
238 | 0 | m_bIsAppearing( false ), |
239 | 0 | m_nFadeRate( 100 ), |
240 | 0 | m_aFadeTimer("SwHeaderFooterWin m_aFadeTimer") |
241 | 0 | { |
242 | 0 | m_xVirDev = m_xMenuButton->create_virtual_device(); |
243 | 0 | SwFrameMenuButtonBase::SetVirDevFont(*m_xVirDev); |
244 | |
|
245 | 0 | m_xPushButton->connect_clicked(LINK(this, SwHeaderFooterWin, ClickHdl)); |
246 | 0 | m_xMenuButton->connect_selected(LINK(this, SwHeaderFooterWin, SelectHdl)); |
247 | | |
248 | | // set the PopupMenu |
249 | | // Rewrite the menu entries' text |
250 | 0 | if (m_bIsHeader) |
251 | 0 | { |
252 | 0 | m_xMenuButton->set_item_label(u"edit"_ustr, SwResId(STR_FORMAT_HEADER)); |
253 | 0 | m_xMenuButton->set_item_label(u"delete"_ustr, SwResId(STR_DELETE_HEADER)); |
254 | 0 | } |
255 | 0 | else |
256 | 0 | { |
257 | 0 | m_xMenuButton->set_item_label(u"edit"_ustr, SwResId(STR_FORMAT_FOOTER)); |
258 | 0 | m_xMenuButton->set_item_label(u"delete"_ustr, SwResId(STR_DELETE_FOOTER)); |
259 | 0 | } |
260 | |
|
261 | 0 | m_aFadeTimer.SetTimeout(50); |
262 | 0 | m_aFadeTimer.SetInvokeHandler(LINK(this, SwHeaderFooterWin, FadeHandler)); |
263 | 0 | } Unexecuted instantiation: SwHeaderFooterWin::SwHeaderFooterWin(SwEditWin*, SwFrame const*, bool) Unexecuted instantiation: SwHeaderFooterWin::SwHeaderFooterWin(SwEditWin*, SwFrame const*, bool) |
264 | | |
265 | | SwHeaderFooterWin::~SwHeaderFooterWin( ) |
266 | 0 | { |
267 | 0 | disposeOnce(); |
268 | 0 | } |
269 | | |
270 | | void SwHeaderFooterWin::dispose() |
271 | 0 | { |
272 | 0 | m_xPushButton.reset(); |
273 | 0 | m_xMenuButton.reset(); |
274 | 0 | m_pEditWin.reset(); |
275 | 0 | m_xVirDev.disposeAndClear(); |
276 | 0 | InterimItemWindow::dispose(); |
277 | 0 | } |
278 | | |
279 | | void SwHeaderFooterWin::SetOffset(Point aOffset) |
280 | 0 | { |
281 | | // Compute the text to show |
282 | 0 | const SwPageFrame* pPageFrame = SwFrameMenuButtonBase::GetPageFrame(m_pFrame); |
283 | 0 | const SwPageDesc* pDesc = pPageFrame->GetPageDesc(); |
284 | 0 | bool bIsFirst = !pDesc->IsFirstShared() && pPageFrame->OnFirstPage(); |
285 | 0 | bool bIsLeft = !pDesc->IsHeaderShared() && !pPageFrame->OnRightPage(); |
286 | 0 | bool bIsRight = !pDesc->IsHeaderShared() && pPageFrame->OnRightPage(); |
287 | 0 | m_sLabel = SwResId(STR_HEADER_TITLE); |
288 | 0 | if (!m_bIsHeader) |
289 | 0 | m_sLabel = bIsFirst ? SwResId(STR_FIRST_FOOTER_TITLE) |
290 | 0 | : bIsLeft ? SwResId(STR_LEFT_FOOTER_TITLE) |
291 | 0 | : bIsRight ? SwResId(STR_RIGHT_FOOTER_TITLE) |
292 | 0 | : SwResId(STR_FOOTER_TITLE ); |
293 | 0 | else |
294 | 0 | m_sLabel = bIsFirst ? SwResId(STR_FIRST_HEADER_TITLE) |
295 | 0 | : bIsLeft ? SwResId(STR_LEFT_HEADER_TITLE) |
296 | 0 | : bIsRight ? SwResId(STR_RIGHT_HEADER_TITLE) |
297 | 0 | : SwResId(STR_HEADER_TITLE); |
298 | |
|
299 | 0 | sal_Int32 nPos = m_sLabel.lastIndexOf("%1"); |
300 | 0 | m_sLabel = m_sLabel.replaceAt(nPos, 2, pDesc->GetName().toString()); |
301 | 0 | m_xMenuButton->set_accessible_name(m_sLabel); |
302 | | |
303 | | // Compute the text size and get the box position & size from it |
304 | 0 | ::tools::Rectangle aTextRect; |
305 | 0 | m_xVirDev->GetTextBoundRect(aTextRect, m_sLabel); |
306 | 0 | ::tools::Rectangle aTextPxRect = m_xVirDev->LogicToPixel(aTextRect); |
307 | 0 | FontMetric aFontMetric = m_xVirDev->GetFontMetric(m_xVirDev->GetFont()); |
308 | 0 | Size aBoxSize (aTextPxRect.GetWidth() + BUTTON_WIDTH + TEXT_PADDING * 2, |
309 | 0 | aFontMetric.GetLineHeight() + TEXT_PADDING * 2 ); |
310 | |
|
311 | 0 | tools::Long nYFooterOff = 0; |
312 | 0 | if (!m_bIsHeader) |
313 | 0 | nYFooterOff = aBoxSize.Height(); |
314 | |
|
315 | 0 | Point aBoxPos(aOffset.X() - aBoxSize.Width() - BOX_DISTANCE, |
316 | 0 | aOffset.Y() - nYFooterOff); |
317 | |
|
318 | 0 | if (AllSettings::GetLayoutRTL()) |
319 | 0 | { |
320 | 0 | aBoxPos.setX( aOffset.X() + BOX_DISTANCE ); |
321 | 0 | } |
322 | | |
323 | | // Set the position & Size of the window |
324 | 0 | SetPosSizePixel(aBoxPos, aBoxSize); |
325 | |
|
326 | 0 | m_xVirDev->SetOutputSizePixel(aBoxSize); |
327 | 0 | PaintButton(); |
328 | 0 | } |
329 | | |
330 | | void SwHeaderFooterWin::ShowAll(bool bShow) |
331 | 0 | { |
332 | 0 | bool bIsEmptyHeaderFooter = IsEmptyHeaderFooter(); |
333 | 0 | m_xMenuButton->set_visible(!bIsEmptyHeaderFooter); |
334 | 0 | m_xPushButton->set_visible(bIsEmptyHeaderFooter); |
335 | |
|
336 | 0 | m_bIsAppearing = bShow; |
337 | |
|
338 | 0 | if (m_aFadeTimer.IsActive()) |
339 | 0 | m_aFadeTimer.Stop(); |
340 | 0 | m_aFadeTimer.Start(); |
341 | 0 | } |
342 | | |
343 | | bool SwHeaderFooterWin::Contains( const Point &rDocPt ) const |
344 | 0 | { |
345 | 0 | ::tools::Rectangle aRect(GetPosPixel(), GetSizePixel()); |
346 | 0 | return aRect.Contains(rDocPt); |
347 | 0 | } |
348 | | |
349 | | void SwHeaderFooterWin::PaintButton() |
350 | 0 | { |
351 | 0 | if (!m_xVirDev) |
352 | 0 | return; |
353 | | |
354 | | // Use pixels for the rest of the drawing |
355 | 0 | SetMapMode(MapMode(MapUnit::MapPixel)); |
356 | 0 | drawinglayer::primitive2d::Primitive2DContainer aSeq; |
357 | 0 | const ::tools::Rectangle aRect(::tools::Rectangle(Point(0, 0), m_xVirDev->PixelToLogic(GetSizePixel()))); |
358 | |
|
359 | 0 | SwFrameButtonPainter::PaintButton(aSeq, aRect, m_bIsHeader); |
360 | | |
361 | | // Create the text primitive |
362 | 0 | basegfx::BColor aLineColor = SwViewOption::GetCurrentViewOptions().GetHeaderFooterMarkColor().getBColor(); |
363 | 0 | B2DVector aFontSize; |
364 | 0 | FontAttribute aFontAttr = drawinglayer::primitive2d::getFontAttributeFromVclFont(aFontSize, m_xVirDev->GetFont(), false, false); |
365 | |
|
366 | 0 | FontMetric aFontMetric = m_xVirDev->GetFontMetric(m_xVirDev->GetFont()); |
367 | 0 | double nTextOffsetY = aFontMetric.GetAscent() + TEXT_PADDING; |
368 | 0 | Point aTextPos(TEXT_PADDING, nTextOffsetY); |
369 | |
|
370 | 0 | basegfx::B2DHomMatrix aTextMatrix(createScaleTranslateB2DHomMatrix( |
371 | 0 | aFontSize.getX(), aFontSize.getY(), |
372 | 0 | double(aTextPos.X()), double(aTextPos.Y()))); |
373 | |
|
374 | 0 | aSeq.push_back(new drawinglayer::primitive2d::TextSimplePortionPrimitive2D( |
375 | 0 | aTextMatrix, m_sLabel, 0, m_sLabel.getLength(), |
376 | 0 | std::vector<double>(), {}, std::move(aFontAttr), css::lang::Locale(), aLineColor)); |
377 | | |
378 | | // Create the 'plus' or 'arrow' primitive |
379 | 0 | B2DRectangle aSignArea(B2DPoint(aRect.Right() - BUTTON_WIDTH, 0.0), |
380 | 0 | B2DVector(aRect.Right(), aRect.getOpenHeight())); |
381 | |
|
382 | 0 | B2DPolygon aSign; |
383 | 0 | bool bIsEmptyHeaderFooter = IsEmptyHeaderFooter(); |
384 | 0 | if (bIsEmptyHeaderFooter) |
385 | 0 | { |
386 | | // Create the + polygon |
387 | 0 | double nLeft = aSignArea.getMinX() + TEXT_PADDING; |
388 | 0 | double nRight = aSignArea.getMaxX() - TEXT_PADDING; |
389 | 0 | double nHalfW = ( nRight - nLeft ) / 2.0; |
390 | |
|
391 | 0 | double nTop = aSignArea.getCenterY() - nHalfW; |
392 | 0 | double nBottom = aSignArea.getCenterY() + nHalfW; |
393 | |
|
394 | 0 | aSign.append(B2DPoint(nLeft, aSignArea.getCenterY() - 1.0)); |
395 | 0 | aSign.append(B2DPoint(aSignArea.getCenterX() - 1.0, aSignArea.getCenterY() - 1.0)); |
396 | 0 | aSign.append(B2DPoint(aSignArea.getCenterX() - 1.0, nTop)); |
397 | 0 | aSign.append(B2DPoint(aSignArea.getCenterX() + 1.0, nTop)); |
398 | 0 | aSign.append(B2DPoint(aSignArea.getCenterX() + 1.0, aSignArea.getCenterY() - 1.0)); |
399 | 0 | aSign.append(B2DPoint(nRight, aSignArea.getCenterY() - 1.0)); |
400 | 0 | aSign.append(B2DPoint(nRight, aSignArea.getCenterY() + 1.0)); |
401 | 0 | aSign.append(B2DPoint(aSignArea.getCenterX() + 1.0, aSignArea.getCenterY() + 1.0)); |
402 | 0 | aSign.append(B2DPoint(aSignArea.getCenterX() + 1.0, nBottom)); |
403 | 0 | aSign.append(B2DPoint(aSignArea.getCenterX() - 1.0, nBottom)); |
404 | 0 | aSign.append(B2DPoint(aSignArea.getCenterX() - 1.0, aSignArea.getCenterY() + 1.0)); |
405 | 0 | aSign.append(B2DPoint(nLeft, aSignArea.getCenterY() + 1.0)); |
406 | 0 | aSign.setClosed(true); |
407 | 0 | } |
408 | 0 | else |
409 | 0 | { |
410 | | // Create the v polygon |
411 | 0 | B2DPoint aLeft(aSignArea.getMinX() + TEXT_PADDING, aSignArea.getCenterY()); |
412 | 0 | B2DPoint aRight(aSignArea.getMaxX() - TEXT_PADDING, aSignArea.getCenterY()); |
413 | 0 | B2DPoint aBottom((aLeft.getX() + aRight.getX()) / 2.0, aLeft.getY() + 4.0); |
414 | 0 | aSign.append(aLeft); |
415 | 0 | aSign.append(aRight); |
416 | 0 | aSign.append(aBottom); |
417 | 0 | aSign.setClosed(true); |
418 | 0 | } |
419 | |
|
420 | 0 | BColor aSignColor = COL_BLACK.getBColor(); |
421 | 0 | if (Application::GetSettings().GetStyleSettings().GetHighContrastMode()) |
422 | 0 | aSignColor = COL_WHITE.getBColor(); |
423 | |
|
424 | 0 | aSeq.push_back(new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D( |
425 | 0 | B2DPolyPolygon(aSign), aSignColor) ); |
426 | | |
427 | | // Create the processor and process the primitives |
428 | 0 | const drawinglayer::geometry::ViewInformation2D aNewViewInfos; |
429 | 0 | std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor( |
430 | 0 | drawinglayer::processor2d::createProcessor2DFromOutputDevice(*m_xVirDev, aNewViewInfos)); |
431 | | |
432 | | // TODO Ghost it all if needed |
433 | 0 | drawinglayer::primitive2d::Primitive2DContainer aGhostedSeq; |
434 | 0 | double nFadeRate = double(m_nFadeRate) / 100.0; |
435 | |
|
436 | 0 | basegfx::BColorModifierSharedPtr aBColorModifier = |
437 | 0 | std::make_shared<basegfx::BColorModifier_interpolate>(COL_WHITE.getBColor(), |
438 | 0 | 1.0 - nFadeRate); |
439 | |
|
440 | 0 | aGhostedSeq.push_back(new drawinglayer::primitive2d::ModifiedColorPrimitive2D(std::move(aSeq), std::move(aBColorModifier))); |
441 | |
|
442 | 0 | pProcessor->process(aGhostedSeq); |
443 | |
|
444 | 0 | if (bIsEmptyHeaderFooter) |
445 | 0 | m_xPushButton->set_custom_button(m_xVirDev.get()); |
446 | 0 | else |
447 | 0 | m_xMenuButton->set_custom_button(m_xVirDev.get()); |
448 | 0 | } |
449 | | |
450 | | bool SwHeaderFooterWin::IsEmptyHeaderFooter( ) const |
451 | 0 | { |
452 | 0 | bool bResult = true; |
453 | |
|
454 | 0 | const SwPageFrame* pPageFrame = SwFrameMenuButtonBase::GetPageFrame(m_pFrame); |
455 | 0 | if (!pPageFrame) |
456 | 0 | { |
457 | 0 | return bResult; |
458 | 0 | } |
459 | | |
460 | | // Actually check it |
461 | 0 | const SwPageDesc* pDesc = pPageFrame->GetPageDesc(); |
462 | |
|
463 | 0 | bool const bFirst(pPageFrame->OnFirstPage()); |
464 | 0 | const SwFrameFormat *const pFormat = (pPageFrame->OnRightPage()) |
465 | 0 | ? pDesc->GetRightFormat(bFirst) |
466 | 0 | : pDesc->GetLeftFormat(bFirst); |
467 | |
|
468 | 0 | if ( pFormat ) |
469 | 0 | { |
470 | 0 | if ( m_bIsHeader ) |
471 | 0 | bResult = !pFormat->GetHeader().IsActive(); |
472 | 0 | else |
473 | 0 | bResult = !pFormat->GetFooter().IsActive(); |
474 | 0 | } |
475 | |
|
476 | 0 | return bResult; |
477 | 0 | } |
478 | | |
479 | | void SwHeaderFooterWin::ExecuteCommand(std::u16string_view rIdent) |
480 | 0 | { |
481 | 0 | SwView& rView = m_pEditWin->GetView(); |
482 | 0 | SwWrtShell& rSh = rView.GetWrtShell(); |
483 | |
|
484 | 0 | const SwPageFrame* pPageFrame = SwFrameMenuButtonBase::GetPageFrame(m_pFrame); |
485 | 0 | const UIName& rStyleName = pPageFrame->GetPageDesc()->GetName(); |
486 | 0 | if (rIdent == u"edit") |
487 | 0 | { |
488 | 0 | OUString sPageId = m_bIsHeader ? u"header"_ustr : u"footer"_ustr; |
489 | 0 | rView.GetDocShell()->FormatPage(rView.GetFrameWeld(), rStyleName, sPageId, rSh); |
490 | 0 | } |
491 | 0 | else if (rIdent == u"borderback") |
492 | 0 | { |
493 | 0 | SwPageDesc& rPageDesc = const_cast<SwPageDesc&>(*pPageFrame->GetPageDesc()); |
494 | 0 | SwFrameFormat& rMaster = rPageDesc.GetMaster(); |
495 | 0 | SwFrameFormat* pHFFormat = const_cast< SwFrameFormat* >( rMaster.GetFooter().GetFooterFormat() ); |
496 | 0 | if ( m_bIsHeader ) |
497 | 0 | pHFFormat = const_cast< SwFrameFormat* >( rMaster.GetHeader().GetHeaderFormat() ); |
498 | 0 | SfxItemSet aSet( pHFFormat->GetAttrSet() ); |
499 | | |
500 | | // Items to hand over XPropertyList things like XColorList, |
501 | | // XHatchList, XGradientList, and XBitmapList to the Area TabPage: |
502 | 0 | aSet.MergeRange( SID_COLOR_TABLE, SID_PATTERN_LIST ); |
503 | | // create needed items for XPropertyList entries from the DrawModel so that |
504 | | // the Area TabPage can access them |
505 | 0 | rSh.GetDoc()->getIDocumentDrawModelAccess().GetDrawModel()->PutAreaListItems( aSet ); |
506 | |
|
507 | 0 | aSet.MergeRange(SID_ATTR_BORDER_INNER, SID_ATTR_BORDER_INNER); |
508 | | // Create a box info item... needed by the dialog |
509 | 0 | std::shared_ptr<SvxBoxInfoItem> aBoxInfo(std::make_shared<SvxBoxInfoItem>(SID_ATTR_BORDER_INNER)); |
510 | 0 | if (const SvxBoxInfoItem *pBoxInfo = pHFFormat->GetAttrSet().GetItemIfSet(SID_ATTR_BORDER_INNER)) |
511 | 0 | aBoxInfo.reset(pBoxInfo->Clone()); |
512 | |
|
513 | 0 | aBoxInfo->SetTable(false); |
514 | 0 | aBoxInfo->SetDist(true); |
515 | 0 | aBoxInfo->SetMinDist(false); |
516 | 0 | aBoxInfo->SetDefDist(MIN_BORDER_DIST); |
517 | 0 | aBoxInfo->SetValid(SvxBoxInfoItemValidFlags::DISABLE); |
518 | 0 | aSet.Put(*aBoxInfo); |
519 | |
|
520 | 0 | if (svx::ShowBorderBackgroundDlg( GetFrameWeld(), &aSet ) ) |
521 | 0 | { |
522 | | // Apply the modified format to all (first, even, odd) of the page style's FrameFormats |
523 | 0 | aSet.DisableItem(RES_CNTNT); // don't duplicate the content though... |
524 | 0 | rPageDesc.SetFormatAttrOnAll(aSet, m_bIsHeader); |
525 | 0 | rView.GetDocShell()->SetModified(); |
526 | 0 | } |
527 | 0 | } |
528 | 0 | else if (rIdent == u"delete") |
529 | 0 | { |
530 | 0 | rSh.ChangeHeaderOrFooter( rStyleName, m_bIsHeader, false, true ); |
531 | | // warning: "this" may be disposed now |
532 | 0 | rSh.GetWin()->GrabFocusToDocument(); |
533 | 0 | } |
534 | 0 | else if (rIdent == u"insert_pagenumber") |
535 | 0 | { |
536 | 0 | SfxViewFrame& rVFrame = rSh.GetView().GetViewFrame(); |
537 | 0 | rVFrame.GetBindings().Execute(FN_INSERT_FLD_PGNUMBER); |
538 | 0 | } |
539 | 0 | else if (rIdent == u"insert_pagecount") |
540 | 0 | { |
541 | 0 | SfxViewFrame& rVFrame = rSh.GetView().GetViewFrame(); |
542 | 0 | rVFrame.GetBindings().Execute(FN_INSERT_FLD_PGCOUNT); |
543 | 0 | } |
544 | 0 | else if (rIdent == u"insert_pagecount_in_range") |
545 | 0 | { |
546 | 0 | SfxViewFrame& rVFrame = rSh.GetView().GetViewFrame(); |
547 | 0 | rVFrame.GetBindings().Execute(FN_INSERT_FLD_RANGE_PGCOUNT); |
548 | 0 | } |
549 | 0 | } |
550 | | |
551 | | IMPL_LINK_NOARG(SwHeaderFooterWin, ClickHdl, weld::Button&, void) |
552 | 0 | { |
553 | 0 | SwView& rView = m_pEditWin->GetView(); |
554 | 0 | SwWrtShell& rSh = rView.GetWrtShell(); |
555 | |
|
556 | 0 | const SwPageFrame* pPageFrame = SwFrameMenuButtonBase::GetPageFrame(m_pFrame); |
557 | 0 | const UIName& rStyleName = pPageFrame->GetPageDesc()->GetName(); |
558 | 0 | { |
559 | 0 | VclPtr<SwHeaderFooterWin> xThis(this); |
560 | 0 | rSh.ChangeHeaderOrFooter( rStyleName, m_bIsHeader, true, false ); |
561 | | //tdf#153059 after ChangeHeaderOrFooter is it possible that "this" is disposed |
562 | 0 | if (xThis->isDisposed()) |
563 | 0 | return; |
564 | 0 | } |
565 | 0 | m_xPushButton->hide(); |
566 | 0 | m_xMenuButton->show(); |
567 | 0 | PaintButton(); |
568 | 0 | } |
569 | | |
570 | | IMPL_LINK(SwHeaderFooterWin, SelectHdl, const OUString&, rIdent, void) |
571 | 0 | { |
572 | 0 | ExecuteCommand(rIdent); |
573 | 0 | } |
574 | | |
575 | | IMPL_LINK_NOARG(SwHeaderFooterWin, FadeHandler, Timer *, void) |
576 | 0 | { |
577 | 0 | if (m_bIsAppearing && m_nFadeRate > 0) |
578 | 0 | m_nFadeRate -= 25; |
579 | 0 | else if (!m_bIsAppearing && m_nFadeRate < 100) |
580 | 0 | m_nFadeRate += 25; |
581 | |
|
582 | 0 | if (m_nFadeRate != 100 && !IsVisible()) |
583 | 0 | { |
584 | 0 | Show(); |
585 | 0 | } |
586 | 0 | else if (m_nFadeRate == 100 && IsVisible()) |
587 | 0 | { |
588 | 0 | Show(false); |
589 | 0 | } |
590 | 0 | else |
591 | 0 | PaintButton(); |
592 | |
|
593 | 0 | if (IsVisible() && m_nFadeRate > 0 && m_nFadeRate < 100) |
594 | 0 | m_aFadeTimer.Start(); |
595 | 0 | } |
596 | | |
597 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |