|
1 /* |
|
2 * Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include "HgDrawUtils.h" |
|
20 |
|
21 #include "HgMarquee.h" |
|
22 |
|
23 #include <gdi.h> |
|
24 #include <gulicon.h> |
|
25 #include <AknUtils.h> |
|
26 #include <AknsUtils.h> |
|
27 #include <AknsControlContext.h> |
|
28 #include <AknsDrawUtils.h> |
|
29 #include <AknsListBoxBackgroundControlContext.h> |
|
30 #include <aknlayoutscalable_avkon.cdl.h> |
|
31 #include <AknBidiTextUtils.h> |
|
32 |
|
33 const TInt KHgDrawUtilsGranularity(10); |
|
34 const TInt KHgDrawUtilsMaxNumberOfLines(4); |
|
35 |
|
36 CHgDrawUtils* CHgDrawUtils::NewL( TCallBack& aMarqueeCallback ) |
|
37 { |
|
38 CHgDrawUtils* self = new (ELeave) CHgDrawUtils(); |
|
39 CleanupStack::PushL( self ); |
|
40 self->ConstructL( aMarqueeCallback ); |
|
41 CleanupStack::Pop(self); |
|
42 return self; |
|
43 } |
|
44 |
|
45 CHgDrawUtils::~CHgDrawUtils() |
|
46 { |
|
47 delete iMarquee; |
|
48 } |
|
49 |
|
50 |
|
51 void DrawEmptyListImpl_real_DrawUpToTwoLines( CGraphicsContext &aGc, |
|
52 TPtrC aText, |
|
53 TAknLayoutText &aLine1, |
|
54 TAknLayoutText &aLine2, |
|
55 TInt aLine1length, |
|
56 TInt aLine2length, |
|
57 const CFont* aFont, |
|
58 TRgb aColor, |
|
59 TDes& aBuffer ) |
|
60 { |
|
61 TRAPD( error, |
|
62 { |
|
63 CArrayFix<TInt>* wrapWidthArray = new( ELeave ) CArrayFixFlat<TInt>(KHgDrawUtilsGranularity); |
|
64 CleanupStack::PushL( wrapWidthArray ); |
|
65 |
|
66 wrapWidthArray->AppendL( aLine1length ); |
|
67 wrapWidthArray->AppendL( aLine2length ); |
|
68 |
|
69 AknBidiTextUtils::ConvertToVisualAndWrapToStringL( |
|
70 aText, *wrapWidthArray, *aFont, aBuffer, ETrue ); |
|
71 |
|
72 CleanupStack::PopAndDestroy( wrapWidthArray ); // wrapWidthArray |
|
73 } ); // TRAP end |
|
74 |
|
75 if ( error != KErrNone ) |
|
76 { |
|
77 aBuffer = aText; |
|
78 } |
|
79 |
|
80 // Drawing text |
|
81 aGc.Reset(); |
|
82 TBool oneline( EFalse ); |
|
83 TPtrC ptr = aBuffer; |
|
84 TPtrC top = ptr; |
|
85 TInt off = ptr.Locate('\n'); |
|
86 if ( off >= 0 ) |
|
87 { |
|
88 top.Set(ptr.Left(off)); |
|
89 ptr.Set(ptr.Mid(off+1)); |
|
90 |
|
91 TInt off1 = ptr.Locate('\n'); |
|
92 if ( off1 >= 0 ) |
|
93 { |
|
94 ptr.Set(ptr.Left(off1)); |
|
95 } |
|
96 else |
|
97 { |
|
98 oneline = ETrue; |
|
99 } |
|
100 } |
|
101 |
|
102 aGc.SetBrushStyle(CGraphicsContext::ENullBrush); |
|
103 |
|
104 // no layout exist for popup list - mainpane layout is ok for X |
|
105 // coords, center vertically. Also need to calculate vertical |
|
106 // position for mainpane lists, since laf is broken as designed. |
|
107 // If you don't believe this, try using laf values in phonebook. |
|
108 aGc.UseFont( aFont ); |
|
109 aGc.SetPenColor( aColor ); |
|
110 |
|
111 aLine1.DrawText(aGc, top, EFalse, aColor ); |
|
112 if ( !oneline ) |
|
113 { |
|
114 aLine2.DrawText( aGc, ptr, EFalse, aColor ); |
|
115 } |
|
116 aGc.DiscardFont(); |
|
117 } |
|
118 |
|
119 void DrawEmptyListImpl_real_DrawMoreThanTwoLines( const TRect &aParentRect, |
|
120 CGraphicsContext &aGc, |
|
121 TPtrC aText, |
|
122 TRgb aColor, |
|
123 TDes& buffer ) |
|
124 |
|
125 { |
|
126 // fetch layouts |
|
127 TAknLayoutText line[KHgDrawUtilsMaxNumberOfLines]; |
|
128 |
|
129 line[0].LayoutText( aParentRect, AknLayoutScalable_Avkon::main_pane_empty_t1(2) ); |
|
130 line[1].LayoutText( aParentRect, AknLayoutScalable_Avkon::main_pane_empty_t3(0) ); |
|
131 line[2].LayoutText( aParentRect, AknLayoutScalable_Avkon::main_pane_empty_t4(0) ); |
|
132 line[3].LayoutText( aParentRect, AknLayoutScalable_Avkon::main_pane_empty_t5(0) ); |
|
133 |
|
134 TInt lineLength[KHgDrawUtilsMaxNumberOfLines]; |
|
135 TInt i; |
|
136 for ( i = 0; i < KHgDrawUtilsMaxNumberOfLines; i++ ) |
|
137 { |
|
138 lineLength[i] = line[i].TextRect().Width(); |
|
139 } |
|
140 |
|
141 const CFont *bigFont = line[0].Font(); |
|
142 const CFont *smallFont = line[1].Font(); |
|
143 |
|
144 // wrap text |
|
145 TInt off = aText.Locate('\n'); |
|
146 TPtrC rest( aText ); |
|
147 rest.Set( aText.Right(aText.Length() - off - 1 )); |
|
148 |
|
149 HBufC* firstLine = NULL; |
|
150 |
|
151 TRAPD( error1, |
|
152 { |
|
153 firstLine = HBufC::NewL( |
|
154 aText.Left(off).Length() + KAknBidiExtraSpacePerLine ); |
|
155 }); |
|
156 |
|
157 if (error1 == KErrNone) |
|
158 { |
|
159 TPtr firstLinePtr = firstLine->Des(); |
|
160 AknBidiTextUtils::ConvertToVisualAndClip( |
|
161 aText.Left(off), |
|
162 firstLinePtr, |
|
163 *bigFont, |
|
164 lineLength[0], |
|
165 lineLength[0] ); |
|
166 } |
|
167 |
|
168 TRAPD( error2, |
|
169 { |
|
170 CArrayFix<TInt>* wrapWidthArray = new( ELeave ) CArrayFixFlat<TInt>(KHgDrawUtilsGranularity); |
|
171 CleanupStack::PushL( wrapWidthArray ); |
|
172 |
|
173 // wrap small font lines |
|
174 wrapWidthArray->Reset(); |
|
175 for ( i = 1; i < KHgDrawUtilsMaxNumberOfLines; i++ ) |
|
176 { |
|
177 wrapWidthArray->AppendL( lineLength[i] ); |
|
178 } |
|
179 |
|
180 AknBidiTextUtils::ConvertToVisualAndWrapToStringL( |
|
181 rest, *wrapWidthArray, *smallFont, buffer, ETrue ); |
|
182 |
|
183 CleanupStack::PopAndDestroy( wrapWidthArray ); // wrapWidthArray |
|
184 } ); // TRAP end |
|
185 |
|
186 |
|
187 TPtrC ptr[KHgDrawUtilsMaxNumberOfLines]; |
|
188 TInt n = 0; |
|
189 |
|
190 if (error1 == KErrNone) |
|
191 { |
|
192 ptr[0].Set( firstLine->Des() ); |
|
193 } |
|
194 if ( error1 != KErrNone || error2 != KErrNone ) |
|
195 { |
|
196 ptr[0].Set(aText.Left(off)); |
|
197 } |
|
198 else |
|
199 { |
|
200 TInt newlines[3]; |
|
201 n = 0; |
|
202 for ( i = 0; i < buffer.Length(); i++ ) |
|
203 { |
|
204 if ( buffer[i] != '\n' ) |
|
205 { |
|
206 continue; |
|
207 } |
|
208 newlines[n] = i; |
|
209 |
|
210 n++; |
|
211 if ( n >= 3 ) |
|
212 { |
|
213 break; |
|
214 } |
|
215 } |
|
216 |
|
217 if ( n >= 1 ) |
|
218 { |
|
219 ptr[1].Set( buffer.Left( newlines[0] ) ); |
|
220 } |
|
221 if ( n >= 2 ) |
|
222 { |
|
223 ptr[2].Set( buffer.Mid( newlines[0] + 1, newlines[1] - newlines[0] - 1 ) ); |
|
224 } |
|
225 if ( n >= 3 ) |
|
226 { |
|
227 ptr[3].Set( buffer.Mid( newlines[1] + 1, newlines[2] - newlines[1] - 1 ) ); |
|
228 } |
|
229 } |
|
230 |
|
231 // draw texts |
|
232 aGc.SetBrushStyle(CGraphicsContext::ENullBrush); |
|
233 |
|
234 for ( i = 0; i < KHgDrawUtilsMaxNumberOfLines; i++ ) |
|
235 { |
|
236 line[i].DrawText( aGc, ptr[i], EFalse, aColor ); |
|
237 } |
|
238 |
|
239 delete firstLine; |
|
240 } |
|
241 |
|
242 void DrawEmptyListImpl_real( const TRect &aClientRect, |
|
243 CGraphicsContext &aGc, |
|
244 TPtrC aText, |
|
245 const TRgb& aColor ) |
|
246 { |
|
247 if ( !aText.Length() ) |
|
248 { |
|
249 return; |
|
250 } |
|
251 |
|
252 HBufC* hbuf = HBufC::New( aText.Size() + 3 * ( KAknBidiExtraSpacePerLine +1 ) |
|
253 + 10 ); // reserve space for newlines |
|
254 if ( !hbuf ) |
|
255 { // can't really do anything |
|
256 return; |
|
257 } |
|
258 |
|
259 TPtr buffer(hbuf->Des()); |
|
260 |
|
261 /* |
|
262 * input text can be either |
|
263 * - "line1" |
|
264 * - "line1 which will be wrapped to 2 lines and truncated with..." |
|
265 * - "line1\nline2" |
|
266 * - "line1\nMany other lines which will be wrapped to several lines" |
|
267 * |
|
268 * there are 3 layouts |
|
269 * - 1 line with big font, |
|
270 * - 2 lines with big font |
|
271 * - 1 line with big font + 1..3 lines with small font (not for popup lists) |
|
272 * |
|
273 * so first we need to check if given text has a newline, |
|
274 * if so, then we need to check if given text fits to 2 lines or |
|
275 * should it be split to several small font lines |
|
276 */ |
|
277 |
|
278 TInt i, n; |
|
279 n = 0; |
|
280 for (i = 0; i < aText.Length(); i ++) |
|
281 { |
|
282 if ( aText[i] == '\n' ) |
|
283 { |
|
284 n++; |
|
285 } |
|
286 } |
|
287 |
|
288 |
|
289 TAknTextComponentLayout layout1( AknLayoutScalable_Avkon::main_pane_empty_t1( 0 ) ); |
|
290 TAknTextComponentLayout layout2( AknLayoutScalable_Avkon::main_pane_empty_t2( 0 ) ); |
|
291 TAknLayoutText line1; |
|
292 TAknLayoutText line2; |
|
293 |
|
294 line1.LayoutText( aClientRect, layout1 ); |
|
295 TInt line1length = line1.TextRect().Size().iWidth; |
|
296 |
|
297 line2.LayoutText( aClientRect, layout2 ); |
|
298 TInt line2length = line2.TextRect().Size().iWidth; |
|
299 |
|
300 const CFont *font = line1.Font(); |
|
301 |
|
302 if ( n == 0 ) |
|
303 { // one line, or one line which will be wrapped to two |
|
304 DrawEmptyListImpl_real_DrawUpToTwoLines( aGc, aText, line1, line2, |
|
305 line1length, line2length, |
|
306 font, aColor, buffer ); |
|
307 delete hbuf; |
|
308 return; |
|
309 } |
|
310 |
|
311 TRAPD( error, |
|
312 { |
|
313 CArrayFix<TInt>* wrapWidthArray = new( ELeave ) CArrayFixFlat<TInt>(KHgDrawUtilsGranularity); |
|
314 CleanupStack::PushL( wrapWidthArray ); |
|
315 |
|
316 wrapWidthArray->AppendL( line1length ); |
|
317 wrapWidthArray->AppendL( line2length ); |
|
318 wrapWidthArray->AppendL( line2length ); // allow wrap to 3 lines |
|
319 |
|
320 AknBidiTextUtils::ConvertToVisualAndWrapToStringL( |
|
321 aText, *wrapWidthArray, *font, buffer, ETrue ); |
|
322 |
|
323 CleanupStack::PopAndDestroy( wrapWidthArray ); // wrapWidthArray |
|
324 } ); // TRAP end |
|
325 |
|
326 |
|
327 n = 0; |
|
328 for ( i = 0; i < buffer.Length(); i ++) |
|
329 { |
|
330 if (buffer[i] == '\n') |
|
331 { |
|
332 n++; |
|
333 } |
|
334 } |
|
335 |
|
336 // wrapping adds a \n to end of each line --> n < 3 |
|
337 // there is no layout for empty popuplist |
|
338 if ( error != KErrNone || n < 3 ) |
|
339 { // 2 lines which fit to 2 line space |
|
340 DrawEmptyListImpl_real_DrawUpToTwoLines( aGc, aText, line1, line2, |
|
341 line1length, line2length, |
|
342 font, aColor, buffer ); |
|
343 } |
|
344 else |
|
345 { // 1 line with big font + 1..3 lines with small font |
|
346 DrawEmptyListImpl_real_DrawMoreThanTwoLines( aClientRect, aGc, aText, aColor, buffer ); |
|
347 } |
|
348 |
|
349 delete hbuf; |
|
350 } |
|
351 |
|
352 void CHgDrawUtils::DrawEmptyText( |
|
353 CWindowGc& aGc, |
|
354 const TRect& aRect, |
|
355 const TDesC& aText, |
|
356 const TRgb& aColor |
|
357 ) const |
|
358 { |
|
359 DrawEmptyListImpl_real(aRect, aGc, aText, aColor); |
|
360 } |
|
361 |
|
362 // ----------------------------------------------------------------------------- |
|
363 // CHgScroller::DrawImage() |
|
364 // ----------------------------------------------------------------------------- |
|
365 // |
|
366 void CHgDrawUtils::DrawImage( |
|
367 CWindowGc& aGc, |
|
368 const TRect& aRect, |
|
369 const TAknWindowComponentLayout& aLayout, |
|
370 const CGulIcon& aIcon |
|
371 ) const |
|
372 { |
|
373 TAknLayoutRect image; |
|
374 image.LayoutRect(aRect, aLayout); |
|
375 // image.DrawImage(aGc, aIcon.Bitmap(), aIcon.Mask()); |
|
376 TSize slotSize(image.Rect().Size()); |
|
377 TPoint cropPoint(0,0); |
|
378 TPoint toTl(image.Rect().iTl); |
|
379 if( aIcon.Bitmap() && aIcon.Bitmap()->SizeInPixels() != slotSize ) |
|
380 { |
|
381 TSize bitmapSize( aIcon.Bitmap()->SizeInPixels() ); |
|
382 if( bitmapSize.iWidth != slotSize.iWidth ) |
|
383 { |
|
384 if( bitmapSize.iWidth < slotSize.iWidth ) |
|
385 { |
|
386 // Bitmap smaller than slot -> move draw position |
|
387 toTl.iX += ( slotSize.iWidth - bitmapSize.iWidth )/2; |
|
388 } |
|
389 else |
|
390 { |
|
391 // Slot smaller than bitmap -> move crop rect position |
|
392 cropPoint.iX += ( bitmapSize.iWidth - slotSize.iWidth )/2; |
|
393 } |
|
394 } |
|
395 |
|
396 if( bitmapSize.iHeight != slotSize.iHeight ) |
|
397 { |
|
398 if( bitmapSize.iHeight < slotSize.iHeight ) |
|
399 { |
|
400 // Bitmap smaller than slot -> move draw position |
|
401 toTl.iY += ( slotSize.iHeight - bitmapSize.iHeight )/2; |
|
402 } |
|
403 else |
|
404 { |
|
405 // Slot smaller than bitmap -> move crop rect position |
|
406 cropPoint.iY += ( bitmapSize.iHeight - slotSize.iHeight )/2; |
|
407 } |
|
408 } |
|
409 } |
|
410 |
|
411 TRect cropRect(cropPoint, slotSize); |
|
412 |
|
413 if (aIcon.Mask()) |
|
414 { |
|
415 aGc.BitBltMasked(toTl, aIcon.Bitmap(), cropRect, aIcon.Mask(), ETrue); |
|
416 } |
|
417 else |
|
418 { |
|
419 aGc.BitBlt(toTl, aIcon.Bitmap(), cropRect); |
|
420 } |
|
421 } |
|
422 |
|
423 // ----------------------------------------------------------------------------- |
|
424 // CHgScroller::DrawText() |
|
425 // ----------------------------------------------------------------------------- |
|
426 // |
|
427 void CHgDrawUtils::DrawText( |
|
428 CWindowGc& aGc, |
|
429 const TRect& aRect, |
|
430 const TAknTextComponentLayout& aLayout, |
|
431 const TDesC& aText, |
|
432 const TRgb& aColor |
|
433 ) const |
|
434 { |
|
435 TAknLayoutText textLayout; |
|
436 textLayout.LayoutText(aRect, aLayout.LayoutLine()); |
|
437 textLayout.DrawText(aGc, aText, ETrue, aColor ); |
|
438 } |
|
439 |
|
440 // ----------------------------------------------------------------------------- |
|
441 // CHgScroller::DrawTextMarquee() |
|
442 // ----------------------------------------------------------------------------- |
|
443 // |
|
444 void CHgDrawUtils::DrawTextMarquee( |
|
445 CWindowGc& aGc, |
|
446 const TRect& aRect, |
|
447 const TAknTextComponentLayout& aLayout, |
|
448 const TDesC& aText, |
|
449 const TRgb& aColor, |
|
450 const TInt& aMarqueeLine |
|
451 ) |
|
452 { |
|
453 TBool drawn = EFalse; |
|
454 |
|
455 if( iMarqueeLine == aMarqueeLine) |
|
456 |
|
457 { |
|
458 if( iMarquee->DrawText( |
|
459 aGc, |
|
460 aRect, |
|
461 aLayout.LayoutLine(), |
|
462 aText, |
|
463 aColor)) |
|
464 { |
|
465 iMarquee->Reset(); |
|
466 iMarqueeLine++; |
|
467 } |
|
468 else |
|
469 { |
|
470 drawn = ETrue; |
|
471 } |
|
472 } |
|
473 |
|
474 if(!drawn) |
|
475 { |
|
476 DrawText(aGc, aRect, aLayout, aText, aColor); |
|
477 } |
|
478 } |
|
479 |
|
480 |
|
481 CHgDrawUtils::CHgDrawUtils() |
|
482 { |
|
483 |
|
484 } |
|
485 |
|
486 void CHgDrawUtils::ConstructL( TCallBack& aMarqueeCallback ) |
|
487 { |
|
488 iMarquee = CHgMarquee::NewL(); |
|
489 iMarquee->SetRedrawCallBack( aMarqueeCallback ); |
|
490 } |
|
491 |
|
492 void CHgDrawUtils::ResetMarquee() |
|
493 { |
|
494 if(iMarquee) |
|
495 { |
|
496 iMarquee->Reset(); |
|
497 iMarqueeLine = 0; |
|
498 } |
|
499 } |
|
500 |
|
501 void CHgDrawUtils::EnableMarquee( TBool aEnable ) |
|
502 { |
|
503 iMarquee->EnableMarquee(aEnable); |
|
504 } |