1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sfx2/thumbnailviewitem.hxx>
22 #include <sfx2/thumbnailview.hxx>
23 #include "thumbnailviewacc.hxx"
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>
41 using namespace basegfx
;
42 using namespace basegfx::tools
;
43 using namespace ::com::sun::star
;
44 using namespace drawinglayer::attribute
;
45 using namespace drawinglayer::primitive2d
;
47 class ResizableMultiLineEdit
: public VclMultiLineEdit
50 ThumbnailViewItem
* mpItem
;
54 ResizableMultiLineEdit (vcl::Window
* pParent
, ThumbnailViewItem
* pItem
);
56 void SetInGrabFocus(bool bInGrabFocus
) { mbIsInGrabFocus
= bInGrabFocus
; }
58 virtual bool PreNotify(NotifyEvent
& rNEvt
) SAL_OVERRIDE
;
59 virtual void Modify() SAL_OVERRIDE
;
62 ResizableMultiLineEdit::ResizableMultiLineEdit (vcl::Window
* pParent
, ThumbnailViewItem
* pItem
) :
63 VclMultiLineEdit (pParent
, WB_CENTER
| WB_BORDER
),
65 mbIsInGrabFocus(false)
69 bool ResizableMultiLineEdit::PreNotify(NotifyEvent
& rNEvt
)
72 if( rNEvt
.GetType() == MouseNotifyEvent::KEYINPUT
)
74 const KeyEvent
& rKEvt
= *rNEvt
.GetKeyEvent();
75 vcl::KeyCode aCode
= rKEvt
.GetKeyCode();
76 switch (aCode
.GetCode())
79 mpItem
->setTitle( GetText() );
82 mpItem
->setEditTitle(false);
89 else if ( rNEvt
.GetType() == MouseNotifyEvent::LOSEFOCUS
&& !mbIsInGrabFocus
)
91 mpItem
->setTitle( GetText() );
92 mpItem
->setEditTitle(false, false);
94 return nDone
|| VclMultiLineEdit::PreNotify(rNEvt
);
97 void ResizableMultiLineEdit::Modify()
99 VclMultiLineEdit::Modify();
100 mpItem
->updateTitleEditSize();
103 ThumbnailViewItem::ThumbnailViewItem(ThumbnailView
&rView
, sal_uInt16 nId
)
112 , maTextEditMaxArea()
114 mpTitleED
= VclPtr
<ResizableMultiLineEdit
>::Create(&rView
, this);
117 ThumbnailViewItem::~ThumbnailViewItem()
119 mpTitleED
.disposeAndClear();
122 static_cast< ThumbnailViewItemAcc
* >( mpxAcc
->get() )->ParentDestroyed();
127 void ThumbnailViewItem::show (bool bVisible
)
129 mbVisible
= bVisible
;
131 mpTitleED
->Show(false);
134 void ThumbnailViewItem::setSelection (bool state
)
139 void ThumbnailViewItem::setHighlight (bool state
)
144 Rectangle
ThumbnailViewItem::updateHighlight(bool bVisible
, const Point
& rPoint
)
146 bool bNeedsPaint
= false;
148 if (bVisible
&& getDrawArea().IsInside(rPoint
))
150 if (!isHighlighted())
156 if (isHighlighted() || mpTitleED
->SupportsDoubleBuffering())
162 return getDrawArea();
167 OUString
ThumbnailViewItem::getHelpText() const
172 void ThumbnailViewItem::setEditTitle (bool edit
, bool bChangeFocus
)
175 mpTitleED
->Show(edit
);
178 mpTitleED
->SetText(maTitle
);
179 updateTitleEditSize();
180 static_cast<ResizableMultiLineEdit
*>(mpTitleED
.get())->SetInGrabFocus(true);
181 mpTitleED
->GrabFocus();
182 static_cast<ResizableMultiLineEdit
*>(mpTitleED
.get())->SetInGrabFocus(false);
184 else if (bChangeFocus
)
186 mrParent
.GrabFocus();
190 Rectangle
ThumbnailViewItem::getTextArea() const
192 Rectangle
aTextArea(maTextEditMaxArea
);
194 TextEngine aTextEngine
;
195 aTextEngine
.SetMaxTextWidth(maDrawArea
.getWidth());
196 aTextEngine
.SetText(maTitle
);
198 long nTxtHeight
= aTextEngine
.GetTextHeight() + 6;
199 if (nTxtHeight
< aTextArea
.GetHeight())
200 aTextArea
.SetSize(Size(aTextArea
.GetWidth(), nTxtHeight
));
205 void ThumbnailViewItem::updateTitleEditSize()
207 Rectangle aTextArea
= getTextArea();
208 Point aPos
= aTextArea
.TopLeft();
209 Size aSize
= aTextArea
.GetSize();
210 mpTitleED
->SetPosSizePixel(aPos
, aSize
);
213 void ThumbnailViewItem::setTitle (const OUString
& rTitle
)
215 if (mrParent
.renameItem(this, rTitle
))
219 uno::Reference
< accessibility::XAccessible
> ThumbnailViewItem::GetAccessible( bool bIsTransientChildrenDisabled
)
222 mpxAcc
= new uno::Reference
< accessibility::XAccessible
>( new ThumbnailViewItemAcc( this, bIsTransientChildrenDisabled
) );
227 void ThumbnailViewItem::setDrawArea (const Rectangle
&area
)
232 void ThumbnailViewItem::calculateItemsPosition (const long nThumbnailHeight
, const long,
233 const long nPadding
, sal_uInt32 nMaxTextLength
,
234 const ThumbnailItemAttributes
*pAttrs
)
236 drawinglayer::primitive2d::TextLayouterDevice aTextDev
;
237 aTextDev
.setFontAttribute(pAttrs
->aFontAttr
,
238 pAttrs
->aFontSize
.getX(), pAttrs
->aFontSize
.getY(),
239 com::sun::star::lang::Locale() );
241 Size aRectSize
= maDrawArea
.GetSize();
242 Size aImageSize
= maPreview1
.GetSizePixel();
244 // Calculate thumbnail position
245 Point aPos
= maDrawArea
.TopLeft();
246 aPos
.X() = maDrawArea
.getX() + (aRectSize
.Width()-aImageSize
.Width())/2;
247 aPos
.Y() = maDrawArea
.getY() + nPadding
+ (nThumbnailHeight
-aImageSize
.Height())/2;
250 // Calculate text position
251 aPos
.Y() = maDrawArea
.getY() + nThumbnailHeight
+ nPadding
* 2;
252 aPos
.X() = maDrawArea
.Left() + (aRectSize
.Width() - aTextDev
.getTextWidth(maTitle
,0,nMaxTextLength
))/2;
255 // Calculate the text edit max area
256 aPos
= Point(maDrawArea
.getX() + nPadding
, maTextPos
.getY());
257 Size
aEditSize(maDrawArea
.GetWidth() - nPadding
* 2,
258 maDrawArea
.Bottom() - maTextPos
.Y());
259 maTextEditMaxArea
= Rectangle( aPos
, aEditSize
);
262 void ThumbnailViewItem::setSelectClickHdl (const Link
<> &link
)
267 void ThumbnailViewItem::Paint (drawinglayer::processor2d::BaseProcessor2D
*pProcessor
,
268 const ThumbnailItemAttributes
*pAttrs
)
270 BColor aFillColor
= pAttrs
->aFillColor
;
271 drawinglayer::primitive2d::Primitive2DSequence
aSeq(4);
272 double fTransparence
= 0.0;
275 if (mbSelected
|| mbHover
)
276 aFillColor
= pAttrs
->aHighlightColor
;
279 fTransparence
= pAttrs
->fHighlightTransparence
;
281 sal_uInt32 nPrimitive
= 0;
282 aSeq
[nPrimitive
++] = drawinglayer::primitive2d::Primitive2DReference( new PolyPolygonSelectionPrimitive2D(
283 B2DPolyPolygon(Polygon(maDrawArea
, THUMBNAILVIEW_ITEM_CORNER
, THUMBNAILVIEW_ITEM_CORNER
).getB2DPolygon()),
290 Point aPos
= maPrev1Pos
;
291 Size aImageSize
= maPreview1
.GetSizePixel();
293 aSeq
[nPrimitive
++] = drawinglayer::primitive2d::Primitive2DReference( new FillGraphicPrimitive2D(
294 createTranslateB2DHomMatrix(aPos
.X(),aPos
.Y()),
295 FillGraphicAttribute(Graphic(maPreview1
),
298 B2DPoint(aImageSize
.Width(),aImageSize
.Height())),
302 // draw thumbnail borders
303 float fWidth
= aImageSize
.Width() - 1;
304 float fHeight
= aImageSize
.Height() - 1;
305 float fPosX
= maPrev1Pos
.getX();
306 float fPosY
= maPrev1Pos
.getY();
309 aBounds
.append(B2DPoint(fPosX
,fPosY
));
310 aBounds
.append(B2DPoint(fPosX
+fWidth
,fPosY
));
311 aBounds
.append(B2DPoint(fPosX
+fWidth
,fPosY
+fHeight
));
312 aBounds
.append(B2DPoint(fPosX
,fPosY
+fHeight
));
313 aBounds
.setClosed(true);
315 aSeq
[nPrimitive
++] = drawinglayer::primitive2d::Primitive2DReference(createBorderLine(aBounds
));
317 // Draw text below thumbnail
318 addTextPrimitives(maTitle
, pAttrs
, maTextPos
, aSeq
);
320 pProcessor
->process(aSeq
);
323 void ThumbnailViewItem::addTextPrimitives (const OUString
& rText
, const ThumbnailItemAttributes
*pAttrs
, Point aPos
, drawinglayer::primitive2d::Primitive2DSequence
& rSeq
)
325 drawinglayer::primitive2d::TextLayouterDevice aTextDev
;
327 aPos
.setY(aPos
.getY() + aTextDev
.getTextHeight());
329 OUString
aText (rText
);
331 TextEngine aTextEngine
;
332 aTextEngine
.SetMaxTextWidth(maDrawArea
.getWidth());
333 aTextEngine
.SetText(rText
);
335 sal_Int32 nPrimitives
= rSeq
.getLength();
336 rSeq
.realloc(nPrimitives
+ aTextEngine
.GetLineCount(0));
338 // Create the text primitives
339 sal_uInt16 nLineStart
= 0;
340 for (sal_uInt16 i
=0; i
< aTextEngine
.GetLineCount(0); ++i
)
342 sal_uInt16 nLineLength
= aTextEngine
.GetLineLen(0, i
);
343 double nLineWidth
= aTextDev
.getTextWidth (aText
, nLineStart
, nLineLength
);
345 bool bTooLong
= (aPos
.getY() + aTextEngine
.GetCharHeight()) > maDrawArea
.Bottom();
346 if (bTooLong
&& (nLineLength
+ nLineStart
) < rText
.getLength())
348 // Add the '...' to the last line to show, even though it may require to shorten the line
349 double nDotsWidth
= aTextDev
.getTextWidth(OUString("..."),0,3);
351 sal_uInt16 nLength
= nLineLength
- 1;
352 while ( nDotsWidth
+ aTextDev
.getTextWidth(aText
, nLineStart
, nLength
) > maDrawArea
.getWidth() && nLength
> 0)
357 aText
= aText
.copy(0, nLineStart
+nLength
);
359 nLineLength
= nLength
+ 3;
362 double nLineX
= maDrawArea
.Left() + (maDrawArea
.getWidth() - nLineWidth
) / 2.0;
364 basegfx::B2DHomMatrix
aTextMatrix( createScaleTranslateB2DHomMatrix(
365 pAttrs
->aFontSize
.getX(), pAttrs
->aFontSize
.getY(),
366 nLineX
, double( aPos
.Y() ) ) );
369 BColor aTextColor
= pAttrs
->aTextColor
;
370 if (mbSelected
|| mbHover
)
371 aTextColor
= pAttrs
->aHighlightTextColor
;
373 rSeq
[nPrimitives
++] = drawinglayer::primitive2d::Primitive2DReference(
374 new TextSimplePortionPrimitive2D(aTextMatrix
,
375 aText
, nLineStart
, nLineLength
,
376 std::vector
<double>(),
378 com::sun::star::lang::Locale(),
380 nLineStart
+= nLineLength
;
381 aPos
.setY(aPos
.getY() + aTextEngine
.GetCharHeight());
388 drawinglayer::primitive2d::PolygonHairlinePrimitive2D
*
389 ThumbnailViewItem::createBorderLine (const basegfx::B2DPolygon
& rPolygon
)
391 return new PolygonHairlinePrimitive2D(rPolygon
, Color(128, 128, 128).getBColor());
394 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */