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 : * 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 <sfx2/thumbnailviewitem.hxx>
21 :
22 : #include <sfx2/thumbnailview.hxx>
23 : #include "thumbnailviewacc.hxx"
24 :
25 : #include <basegfx/matrix/b2dhommatrixtools.hxx>
26 : #include <basegfx/range/b2drectangle.hxx>
27 : #include <basegfx/vector/b2dsize.hxx>
28 : #include <basegfx/polygon/b2dpolygon.hxx>
29 : #include <drawinglayer/attribute/fillgraphicattribute.hxx>
30 : #include <drawinglayer/primitive2d/fillgraphicprimitive2d.hxx>
31 : #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
32 : #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
33 : #include <drawinglayer/primitive2d/textlayoutdevice.hxx>
34 : #include <drawinglayer/primitive2d/textprimitive2d.hxx>
35 : #include <drawinglayer/processor2d/baseprocessor2d.hxx>
36 : #include <vcl/button.hxx>
37 : #include <vcl/graph.hxx>
38 : #include <vcl/svapp.hxx>
39 : #include <vcl/texteng.hxx>
40 : #include <svtools/optionsdrawinglayer.hxx>
41 :
42 : using namespace basegfx;
43 : using namespace basegfx::tools;
44 : using namespace ::com::sun::star;
45 : using namespace drawinglayer::attribute;
46 : using namespace drawinglayer::primitive2d;
47 :
48 : class ResizableMultiLineEdit : public VclMultiLineEdit
49 : {
50 : private:
51 : ThumbnailViewItem* mpItem;
52 : bool mbIsInGrabFocus;
53 :
54 : public:
55 : ResizableMultiLineEdit (vcl::Window* pParent, ThumbnailViewItem* pItem);
56 : virtual ~ResizableMultiLineEdit ();
57 :
58 0 : void SetInGrabFocus(bool bInGrabFocus) { mbIsInGrabFocus = bInGrabFocus; }
59 :
60 : virtual bool PreNotify(NotifyEvent& rNEvt) SAL_OVERRIDE;
61 : virtual void Modify() SAL_OVERRIDE;
62 : };
63 :
64 8 : ResizableMultiLineEdit::ResizableMultiLineEdit (vcl::Window* pParent, ThumbnailViewItem* pItem) :
65 : VclMultiLineEdit (pParent, WB_CENTER | WB_BORDER),
66 : mpItem(pItem),
67 8 : mbIsInGrabFocus(false)
68 : {
69 8 : }
70 :
71 16 : ResizableMultiLineEdit::~ResizableMultiLineEdit ()
72 : {
73 16 : }
74 :
75 0 : bool ResizableMultiLineEdit::PreNotify(NotifyEvent& rNEvt)
76 : {
77 0 : bool nDone = false;
78 0 : if( rNEvt.GetType() == EVENT_KEYINPUT )
79 : {
80 0 : const KeyEvent& rKEvt = *rNEvt.GetKeyEvent();
81 0 : vcl::KeyCode aCode = rKEvt.GetKeyCode();
82 0 : switch (aCode.GetCode())
83 : {
84 : case KEY_RETURN:
85 0 : mpItem->setTitle( GetText() );
86 : //fall-through
87 : case KEY_ESCAPE:
88 0 : mpItem->setEditTitle(false);
89 0 : nDone = true;
90 0 : break;
91 : default:
92 0 : break;
93 : }
94 : }
95 0 : else if ( rNEvt.GetType() == EVENT_LOSEFOCUS && !mbIsInGrabFocus )
96 : {
97 0 : mpItem->setTitle( GetText() );
98 0 : mpItem->setEditTitle(false, false);
99 : }
100 0 : return nDone || VclMultiLineEdit::PreNotify(rNEvt);
101 : }
102 :
103 0 : void ResizableMultiLineEdit::Modify()
104 : {
105 0 : VclMultiLineEdit::Modify();
106 0 : mpItem->updateTitleEditSize();
107 0 : }
108 :
109 8 : ThumbnailViewItem::ThumbnailViewItem(ThumbnailView &rView, sal_uInt16 nId)
110 : : mrParent(rView)
111 : , mnId(nId)
112 : , mbVisible(true)
113 : , mbSelected(false)
114 : , mbHover(false)
115 : , mpxAcc(NULL)
116 : , mbEditTitle(false)
117 : , mpTitleED(NULL)
118 8 : , maTextEditMaxArea()
119 : {
120 8 : mpTitleED = new ResizableMultiLineEdit(&rView, this);
121 8 : }
122 :
123 16 : ThumbnailViewItem::~ThumbnailViewItem()
124 : {
125 8 : delete mpTitleED;
126 8 : if( mpxAcc )
127 : {
128 0 : static_cast< ThumbnailViewItemAcc* >( mpxAcc->get() )->ParentDestroyed();
129 0 : delete mpxAcc;
130 : }
131 8 : }
132 :
133 0 : void ThumbnailViewItem::show (bool bVisible)
134 : {
135 0 : mbVisible = bVisible;
136 0 : if (!mbVisible)
137 0 : mpTitleED->Show(false);
138 0 : }
139 :
140 0 : void ThumbnailViewItem::setSelection (bool state)
141 : {
142 0 : mbSelected = state;
143 0 : }
144 :
145 0 : void ThumbnailViewItem::setHighlight (bool state)
146 : {
147 0 : mbHover = state;
148 0 : }
149 :
150 0 : Rectangle ThumbnailViewItem::updateHighlight(bool bVisible, const Point& rPoint)
151 : {
152 0 : bool bNeedsPaint = false;
153 :
154 0 : if (bVisible && getDrawArea().IsInside(rPoint))
155 : {
156 0 : if (!isHighlighted())
157 0 : bNeedsPaint = true;
158 0 : setHighlight(true);
159 : }
160 : else
161 : {
162 0 : if (isHighlighted())
163 0 : bNeedsPaint = true;
164 0 : setHighlight(false);
165 : }
166 :
167 0 : if (bNeedsPaint)
168 0 : return getDrawArea();
169 :
170 0 : return Rectangle();
171 : }
172 :
173 0 : OUString ThumbnailViewItem::getHelpText() const
174 : {
175 0 : return maTitle;
176 : }
177 :
178 0 : void ThumbnailViewItem::setEditTitle (bool edit, bool bChangeFocus)
179 : {
180 0 : mbEditTitle = edit;
181 0 : mpTitleED->Show(edit);
182 0 : if (edit)
183 : {
184 0 : mpTitleED->SetText(maTitle);
185 0 : updateTitleEditSize();
186 0 : static_cast<ResizableMultiLineEdit*>(mpTitleED)->SetInGrabFocus(true);
187 0 : mpTitleED->GrabFocus();
188 0 : static_cast<ResizableMultiLineEdit*>(mpTitleED)->SetInGrabFocus(false);
189 : }
190 0 : else if (bChangeFocus)
191 : {
192 0 : mrParent.GrabFocus();
193 : }
194 0 : }
195 :
196 0 : Rectangle ThumbnailViewItem::getTextArea() const
197 : {
198 0 : Rectangle aTextArea(maTextEditMaxArea);
199 :
200 0 : TextEngine aTextEngine;
201 0 : aTextEngine.SetMaxTextWidth(maDrawArea.getWidth());
202 0 : aTextEngine.SetText(maTitle);
203 :
204 0 : long nTxtHeight = aTextEngine.GetTextHeight() + 6;
205 0 : if (nTxtHeight < aTextArea.GetHeight())
206 0 : aTextArea.SetSize(Size(aTextArea.GetWidth(), nTxtHeight));
207 :
208 0 : return aTextArea;
209 : }
210 :
211 0 : void ThumbnailViewItem::updateTitleEditSize()
212 : {
213 0 : Rectangle aTextArea = getTextArea();
214 0 : Point aPos = aTextArea.TopLeft();
215 0 : Size aSize = aTextArea.GetSize();
216 0 : mpTitleED->SetPosSizePixel(aPos, aSize);
217 0 : }
218 :
219 0 : void ThumbnailViewItem::setTitle (const OUString& rTitle)
220 : {
221 0 : if (mrParent.renameItem(this, rTitle))
222 0 : maTitle = rTitle;
223 0 : }
224 :
225 0 : uno::Reference< accessibility::XAccessible > ThumbnailViewItem::GetAccessible( bool bIsTransientChildrenDisabled )
226 : {
227 0 : if( !mpxAcc )
228 0 : mpxAcc = new uno::Reference< accessibility::XAccessible >( new ThumbnailViewItemAcc( this, bIsTransientChildrenDisabled ) );
229 :
230 0 : return *mpxAcc;
231 : }
232 :
233 8 : void ThumbnailViewItem::setDrawArea (const Rectangle &area)
234 : {
235 8 : maDrawArea = area;
236 8 : }
237 :
238 8 : void ThumbnailViewItem::calculateItemsPosition (const long nThumbnailHeight, const long,
239 : const long nPadding, sal_uInt32 nMaxTextLength,
240 : const ThumbnailItemAttributes *pAttrs)
241 : {
242 8 : drawinglayer::primitive2d::TextLayouterDevice aTextDev;
243 : aTextDev.setFontAttribute(pAttrs->aFontAttr,
244 : pAttrs->aFontSize.getX(), pAttrs->aFontSize.getY(),
245 8 : com::sun::star::lang::Locale() );
246 :
247 8 : Size aRectSize = maDrawArea.GetSize();
248 8 : Size aImageSize = maPreview1.GetSizePixel();
249 :
250 : // Calculate thumbnail position
251 8 : Point aPos = maDrawArea.TopLeft();
252 8 : aPos.X() = maDrawArea.getX() + (aRectSize.Width()-aImageSize.Width())/2;
253 8 : aPos.Y() = maDrawArea.getY() + nPadding + (nThumbnailHeight-aImageSize.Height())/2;
254 8 : maPrev1Pos = aPos;
255 :
256 : // Calculate text position
257 8 : aPos.Y() = maDrawArea.getY() + nThumbnailHeight + nPadding * 2;
258 8 : aPos.X() = maDrawArea.Left() + (aRectSize.Width() - aTextDev.getTextWidth(maTitle,0,nMaxTextLength))/2;
259 8 : maTextPos = aPos;
260 :
261 : // Calculate the text edit max area
262 8 : aPos = Point(maDrawArea.getX() + nPadding, maTextPos.getY());
263 8 : Size aEditSize(maDrawArea.GetWidth() - nPadding * 2,
264 16 : maDrawArea.Bottom() - maTextPos.Y());
265 8 : maTextEditMaxArea = Rectangle( aPos, aEditSize );
266 8 : }
267 :
268 8 : void ThumbnailViewItem::setSelectClickHdl (const Link &link)
269 : {
270 8 : maClickHdl = link;
271 8 : }
272 :
273 0 : void ThumbnailViewItem::Paint (drawinglayer::processor2d::BaseProcessor2D *pProcessor,
274 : const ThumbnailItemAttributes *pAttrs)
275 : {
276 0 : BColor aFillColor = pAttrs->aFillColor;
277 0 : drawinglayer::primitive2d::Primitive2DSequence aSeq(4);
278 0 : double fTransparence = 0.0;
279 :
280 : // Draw background
281 0 : if (mbSelected || mbHover)
282 0 : aFillColor = pAttrs->aHighlightColor;
283 :
284 0 : if (mbHover)
285 : {
286 0 : const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
287 0 : fTransparence = aSvtOptionsDrawinglayer.GetTransparentSelectionPercent() * 0.01;
288 : }
289 :
290 0 : sal_uInt32 nPrimitive = 0;
291 0 : aSeq[nPrimitive++] = drawinglayer::primitive2d::Primitive2DReference( new PolyPolygonSelectionPrimitive2D(
292 : B2DPolyPolygon(Polygon(maDrawArea, THUMBNAILVIEW_ITEM_CORNER, THUMBNAILVIEW_ITEM_CORNER).getB2DPolygon()),
293 : aFillColor,
294 : fTransparence,
295 : 0.0,
296 0 : true));
297 :
298 : // Draw thumbnail
299 0 : Point aPos = maPrev1Pos;
300 0 : Size aImageSize = maPreview1.GetSizePixel();
301 :
302 0 : aSeq[nPrimitive++] = drawinglayer::primitive2d::Primitive2DReference( new FillGraphicPrimitive2D(
303 0 : createTranslateB2DHomMatrix(aPos.X(),aPos.Y()),
304 : FillGraphicAttribute(Graphic(maPreview1),
305 : B2DRange(
306 : B2DPoint(0,0),
307 0 : B2DPoint(aImageSize.Width(),aImageSize.Height())),
308 : false)
309 0 : ));
310 :
311 : // draw thumbnail borders
312 0 : float fWidth = aImageSize.Width();
313 0 : float fHeight = aImageSize.Height();
314 0 : float fPosX = maPrev1Pos.getX();
315 0 : float fPosY = maPrev1Pos.getY();
316 :
317 0 : B2DPolygon aBounds;
318 0 : aBounds.append(B2DPoint(fPosX,fPosY));
319 0 : aBounds.append(B2DPoint(fPosX+fWidth,fPosY));
320 0 : aBounds.append(B2DPoint(fPosX+fWidth,fPosY+fHeight));
321 0 : aBounds.append(B2DPoint(fPosX,fPosY+fHeight));
322 0 : aBounds.setClosed(true);
323 :
324 0 : aSeq[nPrimitive++] = drawinglayer::primitive2d::Primitive2DReference(createBorderLine(aBounds));
325 :
326 : // Draw text below thumbnail
327 0 : aPos = maTextPos;
328 0 : addTextPrimitives( maTitle, pAttrs, aPos, aSeq );
329 :
330 0 : pProcessor->process(aSeq);
331 0 : }
332 :
333 0 : void ThumbnailViewItem::addTextPrimitives (const OUString& rText, const ThumbnailItemAttributes *pAttrs, Point aPos, drawinglayer::primitive2d::Primitive2DSequence& rSeq)
334 : {
335 0 : drawinglayer::primitive2d::TextLayouterDevice aTextDev;
336 :
337 0 : aPos.setY(aPos.getY() + aTextDev.getTextHeight());
338 :
339 0 : OUString aText (rText);
340 :
341 0 : TextEngine aTextEngine;
342 0 : aTextEngine.SetMaxTextWidth(maDrawArea.getWidth());
343 0 : aTextEngine.SetText(rText);
344 :
345 0 : sal_Int32 nPrimitives = rSeq.getLength();
346 0 : rSeq.realloc(nPrimitives + aTextEngine.GetLineCount(0));
347 :
348 : // Create the text primitives
349 0 : sal_uInt16 nLineStart = 0;
350 0 : for (sal_uInt16 i=0; i < aTextEngine.GetLineCount(0); ++i)
351 : {
352 0 : sal_uInt16 nLineLength = aTextEngine.GetLineLen(0, i);
353 0 : double nLineWidth = aTextDev.getTextWidth (aText, nLineStart, nLineLength);
354 :
355 0 : bool bTooLong = (aPos.getY() + aTextEngine.GetCharHeight()) > maDrawArea.Bottom();
356 0 : if (bTooLong && (nLineLength + nLineStart) < rText.getLength())
357 : {
358 : // Add the '...' to the last line to show, even though it may require to shorten the line
359 0 : double nDotsWidth = aTextDev.getTextWidth(OUString("..."),0,3);
360 :
361 0 : sal_uInt16 nLength = nLineLength - 1;
362 0 : while ( nDotsWidth + aTextDev.getTextWidth(aText, nLineStart, nLength) > maDrawArea.getWidth() && nLength > 0)
363 : {
364 0 : --nLength;
365 : }
366 :
367 0 : aText = aText.copy(0, nLineStart+nLength);
368 0 : aText += "...";
369 0 : nLineLength = nLength + 3;
370 : }
371 :
372 0 : double nLineX = maDrawArea.Left() + (maDrawArea.getWidth() - nLineWidth) / 2.0;
373 :
374 : basegfx::B2DHomMatrix aTextMatrix( createScaleTranslateB2DHomMatrix(
375 : pAttrs->aFontSize.getX(), pAttrs->aFontSize.getY(),
376 0 : nLineX, double( aPos.Y() ) ) );
377 :
378 0 : rSeq[nPrimitives++] = drawinglayer::primitive2d::Primitive2DReference(
379 : new TextSimplePortionPrimitive2D(aTextMatrix,
380 : aText,nLineStart,nLineLength,
381 : std::vector< double >( ),
382 : pAttrs->aFontAttr,
383 : com::sun::star::lang::Locale(),
384 0 : Color(COL_BLACK).getBColor() ) );
385 0 : nLineStart += nLineLength;
386 0 : aPos.setY(aPos.getY() + aTextEngine.GetCharHeight());
387 :
388 0 : if (bTooLong)
389 0 : break;
390 0 : }
391 0 : }
392 :
393 : drawinglayer::primitive2d::PolygonHairlinePrimitive2D*
394 0 : ThumbnailViewItem::createBorderLine (const basegfx::B2DPolygon& rPolygon)
395 : {
396 0 : return new PolygonHairlinePrimitive2D(rPolygon, Color(186,186,186).getBColor());
397 951 : }
398 :
399 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
400 :
401 :
|