Line data Source code
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 : // FIX fdo#38246 https://bugs.libreoffice.org/show_bug.cgi?id=38246
11 : // Design proposal: https://wiki.documentfoundation.org/Design/Whiteboards/Comments_Ruler_Control
12 : // TODO Alpha blend border when it doesn't fit in window
13 :
14 : #include "swruler.hxx"
15 :
16 : #include "viewsh.hxx"
17 : #include "edtwin.hxx"
18 : #include "PostItMgr.hxx"
19 : #include "viewopt.hxx"
20 : #include <view.hxx>
21 : #include "cmdid.h"
22 : #include <sfx2/request.hxx>
23 : #include <vcl/svapp.hxx>
24 : #include <vcl/window.hxx>
25 : #include <vcl/settings.hxx>
26 : #include "misc.hrc"
27 :
28 : #define CONTROL_BORDER_WIDTH 1
29 :
30 : #define CONTROL_LEFT_OFFSET 6
31 : #define CONTROL_RIGHT_OFFSET 3
32 : #define CONTROL_TOP_OFFSET 4
33 :
34 : #define CONTROL_TRIANGLE_WIDTH 4
35 : #define CONTROL_TRIANGLE_PAD 3
36 :
37 : // Constructor
38 0 : SwCommentRuler::SwCommentRuler( SwViewShell* pViewSh, Window* pParent, SwEditWin* pWin, sal_uInt16 nRulerFlags, SfxBindings& rBindings, WinBits nWinStyle)
39 : : SvxRuler(pParent, pWin, nRulerFlags, rBindings, nWinStyle | WB_HSCROLL)
40 : , mpViewShell(pViewSh)
41 : , mpSwWin(pWin)
42 : , mbIsHighlighted(false)
43 : , mnFadeRate(0)
44 0 : , maVirDev( *this )
45 : {
46 : // Set fading timeout: 5 x 40ms = 200ms
47 0 : maFadeTimer.SetTimeout(40);
48 0 : maFadeTimer.SetTimeoutHdl( LINK( this, SwCommentRuler, FadeHandler ) );
49 0 : }
50 :
51 : // Destructor
52 0 : SwCommentRuler::~SwCommentRuler()
53 : {
54 0 : }
55 :
56 0 : void SwCommentRuler::Paint( const Rectangle& rRect )
57 : {
58 0 : SvxRuler::Paint( rRect );
59 : // Don't draw if there is not any note
60 0 : if ( mpViewShell->GetPostItMgr()
61 0 : && mpViewShell->GetPostItMgr()->HasNotes() )
62 0 : DrawCommentControl();
63 0 : }
64 :
65 0 : void SwCommentRuler::DrawCommentControl()
66 : {
67 0 : const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
68 0 : bool bIsCollapsed = ! mpViewShell->GetPostItMgr()->ShowNotes();
69 :
70 0 : Rectangle aControlRect = GetCommentControlRegion();
71 0 : maVirDev.SetOutputSizePixel( aControlRect.GetSize() );
72 :
73 : // Paint comment control background
74 : // TODO Check if these are best colors to be used
75 0 : Color aBgColor = GetFadedColor( rStyleSettings.GetDarkShadowColor(), rStyleSettings.GetWorkspaceColor() );
76 0 : maVirDev.SetFillColor( aBgColor );
77 :
78 0 : if ( mbIsHighlighted || !bIsCollapsed )
79 : {
80 : // Draw borders
81 0 : maVirDev.SetLineColor( rStyleSettings.GetShadowColor() );
82 : }
83 : else
84 : {
85 : // No borders
86 0 : maVirDev.SetLineColor();
87 : }
88 :
89 0 : maVirDev.DrawRect( Rectangle( Point(), aControlRect.GetSize() ) );
90 :
91 : // Label and arrow tip
92 0 : OUString aLabel( SW_RESSTR ( STR_COMMENTS_LABEL ) );
93 : // Get label and arrow coordinates
94 0 : Point aLabelPos;
95 0 : Point aArrowPos;
96 : bool bArrowToRight;
97 : // TODO Discover why it should be 0 instead of CONTROL_BORDER_WIDTH + CONTROL_TOP_OFFSET
98 0 : aLabelPos.Y() = 0;
99 0 : aArrowPos.Y() = CONTROL_BORDER_WIDTH + CONTROL_TOP_OFFSET;
100 0 : if ( !Application::GetSettings().GetLayoutRTL() )
101 : {
102 : // LTR
103 0 : if ( bIsCollapsed )
104 : {
105 : // It should draw something like | > Comments |
106 0 : aLabelPos.X() = CONTROL_LEFT_OFFSET + CONTROL_TRIANGLE_WIDTH + CONTROL_TRIANGLE_PAD;
107 0 : aArrowPos.X() = CONTROL_LEFT_OFFSET;
108 : }
109 : else
110 : {
111 : // It should draw something like | Comments < |
112 0 : aLabelPos.X() = CONTROL_LEFT_OFFSET;
113 0 : aArrowPos.X() = aControlRect.GetSize().Width() - 1 - CONTROL_RIGHT_OFFSET - CONTROL_BORDER_WIDTH - CONTROL_TRIANGLE_WIDTH;
114 : }
115 0 : bArrowToRight = bIsCollapsed;
116 : }
117 : else
118 : {
119 : // RTL
120 0 : long nLabelWidth = GetTextWidth( aLabel );
121 0 : if ( bIsCollapsed )
122 : {
123 : // It should draw something like | Comments < |
124 0 : aArrowPos.X() = aControlRect.GetSize().Width() - 1 - CONTROL_RIGHT_OFFSET - CONTROL_BORDER_WIDTH - CONTROL_TRIANGLE_WIDTH;
125 0 : aLabelPos.X() = aArrowPos.X() - CONTROL_TRIANGLE_PAD - nLabelWidth;
126 : }
127 : else
128 : {
129 : // It should draw something like | > Comments |
130 0 : aLabelPos.X() = aControlRect.GetSize().Width() - 1 - CONTROL_RIGHT_OFFSET - CONTROL_BORDER_WIDTH - nLabelWidth;
131 0 : aArrowPos.X() = CONTROL_LEFT_OFFSET;
132 : }
133 0 : bArrowToRight = !bIsCollapsed;
134 : }
135 :
136 : // Draw label
137 0 : Color aTextColor = GetFadedColor( rStyleSettings.GetButtonTextColor(), rStyleSettings.GetDarkShadowColor() );
138 0 : maVirDev.SetTextColor( aTextColor );
139 : // FIXME Expected font size?
140 0 : maVirDev.DrawText( aLabelPos, aLabel );
141 :
142 : // Draw arrow
143 : // FIXME consistence of button colors. http://opengrok.libreoffice.org/xref/core/vcl/source/control/button.cxx#785
144 0 : Color aArrowColor = GetFadedColor( Color( COL_BLACK ), rStyleSettings.GetShadowColor() );
145 0 : ImplDrawArrow ( aArrowPos.X(), aArrowPos.Y(), aArrowColor, bArrowToRight );
146 :
147 : // Blit comment control
148 0 : DrawOutDev( aControlRect.TopLeft(), aControlRect.GetSize(), Point(), aControlRect.GetSize(), maVirDev );
149 0 : }
150 :
151 0 : void SwCommentRuler::ImplDrawArrow(long nX, long nY, const Color& rColor, bool bPointRight)
152 : {
153 0 : maVirDev.SetLineColor();
154 0 : maVirDev.SetFillColor( rColor );
155 0 : if ( bPointRight )
156 : {
157 0 : maVirDev.DrawRect( Rectangle( nX+0, nY+0, nX+0, nY+6 ) );
158 0 : maVirDev.DrawRect( Rectangle( nX+1, nY+1, nX+1, nY+5 ) );
159 0 : maVirDev.DrawRect( Rectangle( nX+2, nY+2, nX+2, nY+4 ) );
160 0 : maVirDev.DrawRect( Rectangle( nX+3, nY+3, nX+3, nY+3 ) );
161 : }
162 : else
163 : {
164 0 : maVirDev.DrawRect( Rectangle( nX+0, nY+3, nX+0, nY+3 ) );
165 0 : maVirDev.DrawRect( Rectangle( nX+1, nY+2, nX+1, nY+4 ) );
166 0 : maVirDev.DrawRect( Rectangle( nX+2, nY+1, nX+2, nY+5 ) );
167 0 : maVirDev.DrawRect( Rectangle( nX+3, nY+0, nX+3, nY+6 ) );
168 : }
169 0 : }
170 :
171 : // Just accept double-click outside comment control
172 0 : void SwCommentRuler::Command( const CommandEvent& rCEvt )
173 : {
174 0 : Point aMousePos = rCEvt.GetMousePosPixel();
175 : // Ignore command request if it is inside Comment Control
176 0 : if ( !mpViewShell->GetPostItMgr()
177 0 : || !mpViewShell->GetPostItMgr()->HasNotes()
178 0 : || !GetCommentControlRegion().IsInside( aMousePos ) )
179 0 : SvxRuler::Command( rCEvt );
180 0 : }
181 :
182 0 : void SwCommentRuler::MouseMove(const MouseEvent& rMEvt)
183 : {
184 0 : SvxRuler::MouseMove(rMEvt);
185 0 : if ( ! mpViewShell->GetPostItMgr() || ! mpViewShell->GetPostItMgr()->HasNotes() )
186 0 : return;
187 :
188 0 : Point aMousePos = rMEvt.GetPosPixel();
189 0 : bool bWasHighlighted = mbIsHighlighted;
190 0 : mbIsHighlighted = GetCommentControlRegion().IsInside( aMousePos );
191 0 : if ( mbIsHighlighted != bWasHighlighted )
192 : {
193 : // Set proper help text
194 0 : if ( mbIsHighlighted )
195 : {
196 : // Mouse over comment control
197 0 : UpdateCommentHelpText();
198 : }
199 : else
200 : {
201 : // Mouse out of comment control
202 : // FIXME Should remember previous tooltip text?
203 0 : SetQuickHelpText( OUString() );
204 : }
205 : // Do start fading
206 0 : maFadeTimer.Start();
207 : }
208 : }
209 :
210 0 : void SwCommentRuler::MouseButtonDown( const MouseEvent& rMEvt )
211 : {
212 0 : Point aMousePos = rMEvt.GetPosPixel();
213 0 : if ( !rMEvt.IsLeft() || IsTracking() || !GetCommentControlRegion().IsInside( aMousePos ) )
214 : {
215 0 : SvxRuler::MouseButtonDown(rMEvt);
216 0 : return;
217 : }
218 :
219 : // Toggle notes visibility
220 0 : SwView &rView = mpSwWin->GetView();
221 0 : SfxRequest aRequest( rView.GetViewFrame(), FN_VIEW_NOTES );
222 0 : rView.ExecViewOptions( aRequest );
223 :
224 : // It is inside comment control, so update help text
225 0 : UpdateCommentHelpText();
226 :
227 0 : Invalidate();
228 : }
229 :
230 0 : void SwCommentRuler::Update()
231 : {
232 0 : Rectangle aPreviousControlRect = GetCommentControlRegion();
233 0 : SvxRuler::Update();
234 0 : if (aPreviousControlRect != GetCommentControlRegion())
235 0 : Invalidate();
236 0 : }
237 :
238 0 : void SwCommentRuler::UpdateCommentHelpText()
239 : {
240 : int nTooltipResId;
241 0 : if ( mpViewShell->GetPostItMgr()->ShowNotes() )
242 0 : nTooltipResId = STR_HIDE_COMMENTS;
243 : else
244 0 : nTooltipResId = STR_SHOW_COMMENTS;
245 0 : SetQuickHelpText( OUString( SW_RESSTR( nTooltipResId ) ) );
246 0 : }
247 :
248 : // TODO Make Ruler return its central rectangle instead of margins.
249 0 : Rectangle SwCommentRuler::GetCommentControlRegion()
250 : {
251 0 : long nLeft = 0;
252 0 : SwPostItMgr *pPostItMgr = mpViewShell->GetPostItMgr();
253 :
254 : //rhbz#1006850 When the SwPostItMgr ctor is called from SwView::SwView it
255 : //triggers an update of the uiview, but the result of the ctor hasn't been
256 : //set into the mpViewShell yet, so GetPostItMgr is temporarily still NULL
257 0 : if (!pPostItMgr)
258 0 : return Rectangle();
259 :
260 0 : unsigned long nSidebarWidth = pPostItMgr->GetSidebarWidth(true);
261 : //FIXME When the page width is larger then screen, the ruler is misplaced by one pixel
262 0 : if (GetTextRTL())
263 0 : nLeft = GetPageOffset() - nSidebarWidth + GetBorderOffset();
264 : else
265 0 : nLeft = GetWinOffset() + GetPageOffset() + mpSwWin->LogicToPixel(Size(GetPageWidth(), 0)).Width();
266 0 : long nTop = 0 + 4; // Ruler::ImplDraw uses RULER_OFF (value: 3px) as offset, and Ruler::ImplFormat adds one extra pixel
267 : // Somehow pPostItMgr->GetSidebarBorderWidth() returns border width already doubled
268 0 : long nRight = nLeft + nSidebarWidth + pPostItMgr->GetSidebarBorderWidth(true);
269 0 : long nBottom = nTop + GetRulerVirHeight() - 3;
270 :
271 0 : Rectangle aRect(nLeft, nTop, nRight, nBottom);
272 0 : return aRect;
273 : }
274 :
275 0 : Color SwCommentRuler::GetFadedColor(const Color &rHighColor, const Color &rLowColor)
276 : {
277 0 : if ( ! maFadeTimer.IsActive() )
278 0 : return mbIsHighlighted ? rHighColor : rLowColor;
279 :
280 0 : Color aColor = rHighColor;
281 0 : aColor.Merge( rLowColor, mnFadeRate * 255/100.f );
282 0 : return aColor;
283 : }
284 :
285 0 : IMPL_LINK_NOARG(SwCommentRuler, FadeHandler)
286 : {
287 0 : const int nStep = 25;
288 0 : if ( mbIsHighlighted && mnFadeRate < 100 )
289 0 : mnFadeRate += nStep;
290 0 : else if ( !mbIsHighlighted && mnFadeRate > 0 )
291 0 : mnFadeRate -= nStep;
292 : else
293 0 : return 0;
294 :
295 0 : Invalidate();
296 :
297 0 : if ( mnFadeRate != 0 && mnFadeRate != 100)
298 0 : maFadeTimer.Start();
299 0 : return 0;
300 : }
301 :
302 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|