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