|
1 /* |
|
2 * Copyright (c) 2010 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: Easy dialing list box data. |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 // INCLUDE FILES |
|
20 |
|
21 #include "easydialinglistboxdata.h" |
|
22 #include "easydialinglistbox.h" |
|
23 #include "easydialinglistboxview.h" |
|
24 #include "easydialinglistboxitemdrawer.h" |
|
25 #include "easydialingpanics.h" |
|
26 |
|
27 #include "easydialingcontactdatamanager.h" |
|
28 #include <easydialing.mbg> |
|
29 #include <phonebook2.mbg> |
|
30 #include <phonebook2ece.mbg> |
|
31 |
|
32 // AvKON and drawing header files |
|
33 #include <aknlayoutscalable_avkon.cdl.h> |
|
34 #include <akniconconfig.h> |
|
35 #include <gulicon.h> |
|
36 #include <AknBidiTextUtils.h> |
|
37 #include <bidivisual.h> |
|
38 |
|
39 #include <aknlistloadertfx.h> |
|
40 #include <aknlistboxtfxinternal.h> |
|
41 #include <aknlistboxtfx.h> |
|
42 |
|
43 #include <akntransitionutils.h> |
|
44 #include <avkon.rsg> |
|
45 |
|
46 |
|
47 // EXTERNAL DATA STRUCTURES |
|
48 |
|
49 // EXTERNAL FUNCTION PROTOTYPES |
|
50 |
|
51 // CONSTANTS |
|
52 |
|
53 // KHighlightSeparatorChar is character used to separate matching and non-matching |
|
54 // portions of contact names. |
|
55 const TInt KHighlightSeparatorChar = 0x1F; |
|
56 _LIT( KHighlightSeparatorCharAsLit, "\x1F" ); |
|
57 |
|
58 |
|
59 // KContactNameFontHeightPercent is contact name font height relative to list item height. |
|
60 const TInt KContactNameFontHeightPercent = 35; |
|
61 |
|
62 // KCompanyNameFontHeightPercent is company name font height relative to list item height. |
|
63 const TInt KCompanyNameFontHeightPercent = 30; |
|
64 |
|
65 // KTextBoundingBoxHeightPercent gives the text bounding box height in percentages |
|
66 // relative to font height. This must be over 100, or part of the text cuts off. |
|
67 const TInt KTextBoundingBoxHeightPercent = 120; |
|
68 |
|
69 // KTextPlacementPercent controls how text is placed vertically within its bounding box. |
|
70 // The value is between 0 and 100. 0 means in top part, 50 mean in the middle, 100 means in the |
|
71 // bottom. |
|
72 const TInt KTextPlacementPercent = 70; |
|
73 |
|
74 // KMarginXPercent defines a width of horizontal margin used in many places. In relation to |
|
75 // the width of the item rectangle. |
|
76 const TInt KMarginXPercent = 2; |
|
77 |
|
78 // KMarginYPercent defines a height of vertical margin. In relation to |
|
79 // the height of the item rectangle. Currently used only with contact thumbnail. |
|
80 const TInt KMarginYPercent = 4; |
|
81 |
|
82 // KContacNameYOffsetPercent defines the vertical placement of contact name in relation to |
|
83 // item height. |
|
84 const TInt KContactNameYOffsetPercent = 10; |
|
85 |
|
86 // KCompanyNameYOffsetPercent defines the vertical placement of company name in relation to |
|
87 // item height. |
|
88 const TInt KCompanyNameYOffsetPercent = 60; |
|
89 |
|
90 // KArrowIconSizePercent defines the size of action menu icon relative to item height. |
|
91 const TInt KArrowIconSizePercent = 20; |
|
92 |
|
93 // KMatchingTextMarginInPixels the absolute pixel width of highlight margin. Highlight margin |
|
94 // is an extra space in highlight boundary to make the text look less crowded. |
|
95 const TInt KMatchingTextMarginInPixels = 3; |
|
96 |
|
97 // KMatchingTextMarginInPixels is the absolute pixel value for rounding used in highlight |
|
98 // rectangle. |
|
99 const TInt KHighligthRectangleRoundingYInPixels = 4; |
|
100 |
|
101 // KThumbnailAspectRatio is the aspect ratio of contact thumbnail in percents. 133 for instance |
|
102 // is 4:3 aspect ration. |
|
103 const TInt KThumbnailAspectRatio = 133; |
|
104 |
|
105 const TInt KCent = 100; |
|
106 |
|
107 const TInt KMaxRunInfoArrayCount = 20; |
|
108 |
|
109 // IMPLEMENTATION SPECIFIC CONSTANTS |
|
110 // The mif file from where you would like to show the |
|
111 // icon on the screen. |
|
112 _LIT( KFavouriteIconBitmapFile, "\\resource\\apps\\phonebook2.mif" ); |
|
113 _LIT( KEasyDialingBitmapFile, "\\resource\\apps\\easydialing.mif" ); |
|
114 _LIT( KPhonebook2EceBitmapFile, "\\resource\\apps\\phonebook2ece.mif" ); |
|
115 |
|
116 // MACROS |
|
117 |
|
118 // LOCAL CONSTANTS AND MACROS |
|
119 |
|
120 // MODULE DATA STRUCTURES |
|
121 |
|
122 // GLOBAL FUNCTION PROTOTYPES |
|
123 TRect ContactImageBoundingBox( const TRect& aItemRect ); |
|
124 TRect ArrowIconBoundingBox(const TRect& aItemRect); |
|
125 |
|
126 // LOCAL FUNCTION PROTOTYPES |
|
127 static TRect ContactNameBoundingBox( |
|
128 const TRect& aItemRect, |
|
129 const CFont* aContactNameFont, |
|
130 TBool aIsCurrentItem, |
|
131 TBool aIsFavourite, |
|
132 TBool aThumbnailsShown ); |
|
133 static TRect CompanyNameBoundingBox( |
|
134 const TRect& aItemRect, |
|
135 const CFont* aCompanyNameFont, |
|
136 TBool aIsCurrentItem, |
|
137 TBool aThumbnailsShown ); |
|
138 static TRect FavouriteIconBoundingBox( const TRect& aContactNameBoundingBox, TInt aTextWidth ); |
|
139 static TRect MirrorLayoutBoundingBox(const TRect& aSourceRect, TRect& aBoundingBoxRect); |
|
140 static TInt BaseLineOffset( const TRect& aTextBoundingBox, const CFont* aFont ); |
|
141 static TBool ContainsRightToLeftText( const TDesC& aDesc ); |
|
142 static TInt HighlightSeparatorCount( const TDesC& aText ); |
|
143 static HBufC* ConvertToVisualAndClipLC( const TDesC& aText, const CFont& aFont, const TRect& aBoundingBox ); |
|
144 |
|
145 static void ClipTextToWidth( |
|
146 TDes& aText, |
|
147 const CFont& aFont, |
|
148 TInt aMaxWidthInPixels, |
|
149 TBool& aMatch ); |
|
150 |
|
151 static TBool DrawPieceOfText( |
|
152 const TRect& aBoundingBox, |
|
153 TInt& aXOffset, |
|
154 CWindowGc &aGc, |
|
155 const TDesC& aText, |
|
156 TBool aMatch, |
|
157 const CFont* aFont, |
|
158 const CEasyDialingListBoxData::TExtendedColors& aColors, |
|
159 TBool aHighLight); |
|
160 |
|
161 static TInt DrawTextWithMatchHighlightL( |
|
162 const TRect& aBoundingBox, |
|
163 CWindowGc &aGc, |
|
164 const TDesC& aText, |
|
165 const CFont* aFont, |
|
166 const CEasyDialingListBoxData::TExtendedColors& aColors, |
|
167 TBool aHighLight ); |
|
168 |
|
169 static TInt CalculateTextWidth( |
|
170 const TRect& aBoundingBox, |
|
171 const TDesC& aText, |
|
172 const CFont* aFont ); |
|
173 |
|
174 static TBool CalculateTextPieceWidth( |
|
175 const TRect& aBoundingBox, |
|
176 TInt& aXOffset, |
|
177 const TDesC& aText, |
|
178 TBool aMatch, |
|
179 const CFont* aFont ); |
|
180 |
|
181 // FORWARD DECLARATIONS |
|
182 |
|
183 |
|
184 /* |
|
185 * ============================================================================== |
|
186 * |
|
187 * |
|
188 * class EasyDialingListBoxData::TExtendedColors |
|
189 * |
|
190 * |
|
191 * ============================================================================== |
|
192 */ |
|
193 |
|
194 |
|
195 // ----------------------------------------------------------------------------- |
|
196 // TExtendedColors |
|
197 // |
|
198 // ----------------------------------------------------------------------------- |
|
199 // |
|
200 CEasyDialingListBoxData::TExtendedColors::TExtendedColors() : |
|
201 CFormattedCellListBoxData::TColors(), |
|
202 iMatchingText(KRgbBlack), |
|
203 iMatchingBack(KRgbDarkYellow) |
|
204 { |
|
205 } |
|
206 |
|
207 |
|
208 /* |
|
209 * ============================================================================== |
|
210 * |
|
211 * |
|
212 * class CEasyDialingListBoxData |
|
213 * |
|
214 * |
|
215 * ============================================================================== |
|
216 */ |
|
217 |
|
218 |
|
219 // ----------------------------------------------------------------------------- |
|
220 // CEasyDialingListBoxData |
|
221 // |
|
222 // ----------------------------------------------------------------------------- |
|
223 // |
|
224 CEasyDialingListBoxData::CEasyDialingListBoxData() : |
|
225 CFormattedCellListBoxData() |
|
226 { |
|
227 } |
|
228 |
|
229 // ----------------------------------------------------------------------------- |
|
230 // Destructor |
|
231 // |
|
232 // ----------------------------------------------------------------------------- |
|
233 // |
|
234 CEasyDialingListBoxData::~CEasyDialingListBoxData() |
|
235 { |
|
236 // Release fonts. ReleaseFont function can cope with null pointer |
|
237 // so we don't need to null check them. |
|
238 CWsScreenDevice& screenDev = *( CEikonEnv::Static()->ScreenDevice() ); |
|
239 screenDev.ReleaseFont( iContactNameFont ); |
|
240 screenDev.ReleaseFont( iCompanyNameFont ); |
|
241 |
|
242 delete iArrowPointingRight; |
|
243 delete iArrowPointingLeft; |
|
244 delete iColorBitmap; |
|
245 delete iDummyThumbnail; |
|
246 |
|
247 iContactDataManager = NULL; |
|
248 } |
|
249 |
|
250 // ----------------------------------------------------------------------------- |
|
251 // NewL |
|
252 // |
|
253 // ----------------------------------------------------------------------------- |
|
254 // |
|
255 CEasyDialingListBoxData* CEasyDialingListBoxData::NewL() |
|
256 { |
|
257 CEasyDialingListBoxData* self = new (ELeave) CEasyDialingListBoxData(); |
|
258 |
|
259 CleanupStack::PushL( self ); |
|
260 self->ConstructLD(); |
|
261 CleanupStack::Pop( self ); |
|
262 |
|
263 return self; |
|
264 } |
|
265 |
|
266 |
|
267 // ----------------------------------------------------------------------------- |
|
268 // DrawData |
|
269 // |
|
270 // ----------------------------------------------------------------------------- |
|
271 // |
|
272 void CEasyDialingListBoxData::DrawData( |
|
273 const TListItemProperties& aProperties, |
|
274 CWindowGc& aGc, |
|
275 const TDesC* aText, |
|
276 const TRect& aRect, |
|
277 TBool aHighlight, |
|
278 const TExtendedColors& aColors ) const |
|
279 { |
|
280 const TRect &aItemRect = aRect; |
|
281 |
|
282 if ( aHighlight ) |
|
283 { |
|
284 DrawHighlight( aGc, aItemRect ); |
|
285 } |
|
286 |
|
287 // Draw the actual items. |
|
288 DrawDataFormatted( aProperties, aGc, aText, aItemRect, |
|
289 aHighlight, aColors ); |
|
290 } |
|
291 |
|
292 |
|
293 // ----------------------------------------------------------------------------- |
|
294 // ConstructLD |
|
295 // |
|
296 // ----------------------------------------------------------------------------- |
|
297 // |
|
298 void CEasyDialingListBoxData::ConstructLD() |
|
299 { |
|
300 CFormattedCellListBoxData::ConstructLD(); |
|
301 |
|
302 // EasyDialing bitmap file is attempted to be read from the same directory where the |
|
303 // executed binary is located |
|
304 TFileName dllFileName; |
|
305 Dll::FileName( dllFileName ); |
|
306 |
|
307 TParse parse; |
|
308 User::LeaveIfError(parse.Set(KEasyDialingBitmapFile, &dllFileName, NULL)); |
|
309 TFileName bitmapFileName(parse.FullName()); |
|
310 |
|
311 CFbsBitmap* bm; |
|
312 CFbsBitmap* mask; |
|
313 |
|
314 // iArrowPointingLeft is the icon displayed for the selected item in EasyDialingListBox |
|
315 AknIconUtils::CreateIconL( bm, mask, bitmapFileName, EMbmEasydialingQgn_indi_org_arrow_left, |
|
316 EMbmEasydialingQgn_indi_org_arrow_left_mask ); |
|
317 |
|
318 iArrowPointingLeft = CGulIcon::NewL( bm, mask ); |
|
319 |
|
320 AknIconUtils::CreateIconL( bm, mask, bitmapFileName, EMbmEasydialingQgn_indi_org_arrow_right, |
|
321 EMbmEasydialingQgn_indi_org_arrow_right_mask ); |
|
322 |
|
323 iArrowPointingRight = CGulIcon::NewL( bm, mask ); |
|
324 |
|
325 // Only mask for the icons are used. iColorBitmap is used for making the icon |
|
326 // to follow text color changes according to skin. |
|
327 iColorBitmap = new (ELeave) CFbsBitmap; |
|
328 |
|
329 // Contact default thumbnail is not available in themes. It is read from phonebook resource. |
|
330 AknIconUtils::CreateIconL( bm, mask, KPhonebook2EceBitmapFile, |
|
331 EMbmPhonebook2eceQgn_prop_pb_thumb_unknown, EMbmPhonebook2eceQgn_prop_pb_thumb_unknown_mask ); |
|
332 iDummyThumbnail = CGulIcon::NewL( bm, mask ); |
|
333 |
|
334 } |
|
335 |
|
336 |
|
337 // ----------------------------------------------------------------------------- |
|
338 // DrawHighlight |
|
339 // |
|
340 // ----------------------------------------------------------------------------- |
|
341 // |
|
342 void CEasyDialingListBoxData::DrawHighlight( CWindowGc &aGc, const TRect &aItemRect ) const |
|
343 { |
|
344 MAknListBoxTfxInternal* transApi = CAknListLoader::TfxApiInternal( &aGc ); |
|
345 if ( transApi ) |
|
346 { |
|
347 transApi->Invalidate(MAknListBoxTfxInternal::EListHighlight ); |
|
348 transApi->BeginRedraw( MAknListBoxTfxInternal::EListHighlight, aItemRect ); |
|
349 transApi->StartDrawing( MAknListBoxTfxInternal::EListHighlight ); |
|
350 aGc.SetClippingRect( iControl->Rect() ); |
|
351 } |
|
352 |
|
353 TAknLayoutRect outerRect; |
|
354 TAknLayoutRect innerRect; |
|
355 outerRect.LayoutRect( aItemRect, TAknWindowComponentLayout::Compose( |
|
356 AknLayoutScalable_Avkon::list_highlight_pane_cp1(), |
|
357 AknLayoutScalable_Avkon::list_highlight_pane_g10_cp1() ).LayoutLine() ); |
|
358 innerRect.LayoutRect( aItemRect, TAknWindowComponentLayout::Compose( |
|
359 AknLayoutScalable_Avkon::list_highlight_pane_cp1(), |
|
360 AknLayoutScalable_Avkon::list_highlight_pane_g1_cp1() ).LayoutLine() ); |
|
361 MAknsControlContext *cc = AknsDrawUtils::ControlContext( Control() ); |
|
362 |
|
363 if ( !cc ) |
|
364 { |
|
365 cc = SkinBackgroundContext(); |
|
366 } |
|
367 |
|
368 if ( cc ) |
|
369 { |
|
370 aGc.SetPenStyle( CGraphicsContext::ENullPen ); |
|
371 AknsDrawUtils::DrawFrame( |
|
372 AknsUtils::SkinInstance(), |
|
373 aGc, |
|
374 outerRect.Rect(), |
|
375 innerRect.Rect(), |
|
376 KAknsIIDQsnFrList, |
|
377 KAknsIIDQsnFrListCenter ); |
|
378 } |
|
379 |
|
380 if ( transApi ) |
|
381 { |
|
382 aGc.CancelClippingRect(); |
|
383 transApi->StopDrawing(); |
|
384 transApi->EndRedraw( MAknListBoxTfxInternal::EListHighlight ); |
|
385 } |
|
386 } |
|
387 |
|
388 |
|
389 // ----------------------------------------------------------------------------- |
|
390 // DrawDataFormatted |
|
391 // |
|
392 // ----------------------------------------------------------------------------- |
|
393 // |
|
394 // ToDo: SetSize function could be called once for all static data in SizeChanged. |
|
395 // Applies at least to icons. |
|
396 void CEasyDialingListBoxData::DrawDataFormatted( |
|
397 TListItemProperties /* aProperties */, |
|
398 CWindowGc& aGc, |
|
399 const TDesC* aText, |
|
400 const TRect& aItemRect, |
|
401 TBool aHighlight, |
|
402 const TExtendedColors& aColors ) const |
|
403 { |
|
404 TPtrC cellText; |
|
405 |
|
406 TInt error = TextUtils::ColumnText( cellText , 0, aText ); |
|
407 __ASSERT_DEBUG( error == KErrNone, EasyDialingPanic( EEasyDialingPanicInvalidListBoxModelString ) ); |
|
408 __ASSERT_DEBUG( iContactNameFont, EasyDialingPanic( EEasyDialingNoFontFound ) ); |
|
409 __ASSERT_DEBUG( iCompanyNameFont, EasyDialingPanic( EEasyDialingNoFontFound ) ); |
|
410 |
|
411 MAknListBoxTfxInternal *transApi = CAknListLoader::TfxApiInternal( &aGc ); |
|
412 if ( transApi ) |
|
413 { |
|
414 transApi->StartDrawing( MAknListBoxTfxInternal::EListItem ); |
|
415 if ( transApi->EffectsDisabled() ) |
|
416 { |
|
417 aGc.SetClippingRect( iControl->Rect() ); |
|
418 } |
|
419 } |
|
420 |
|
421 TRect boundingBox = ContactImageBoundingBox( aItemRect ); |
|
422 if ( AknLayoutUtils::LayoutMirrored() ) |
|
423 { |
|
424 boundingBox = MirrorLayoutBoundingBox( aItemRect, boundingBox ); |
|
425 } |
|
426 |
|
427 //Draws the Contact Thumbnail Icon if exists else draws the dummy contact thumbnail |
|
428 TBool fav = ContactThumbnailDrawing( aGc, boundingBox, cellText ); |
|
429 |
|
430 error = TextUtils::ColumnText( cellText , 1, aText ); |
|
431 __ASSERT_DEBUG( error == KErrNone, EasyDialingPanic( EEasyDialingPanicInvalidListBoxModelString ) ); |
|
432 |
|
433 boundingBox = ContactNameBoundingBox( aItemRect, |
|
434 iContactNameFont, |
|
435 aHighlight, |
|
436 fav, |
|
437 iContactDataManager->GetContactThumbnailSetting() ); |
|
438 TRect nameRectUnMirrored = boundingBox; // used for favourite star drawing |
|
439 |
|
440 if ( AknLayoutUtils::LayoutMirrored() ) |
|
441 { |
|
442 boundingBox = MirrorLayoutBoundingBox( aItemRect, boundingBox ); |
|
443 } |
|
444 |
|
445 // favourite icon size is set the same as contact name bounding box height. |
|
446 TInt favouriteIconSize = boundingBox.Height(); |
|
447 |
|
448 TRect arrowRect = ArrowIconBoundingBox( aItemRect ); |
|
449 if ( AknLayoutUtils::LayoutMirrored() ) |
|
450 { |
|
451 arrowRect = MirrorLayoutBoundingBox( aItemRect, arrowRect ); |
|
452 } |
|
453 |
|
454 // Draw arrow icon if the item is in focus. |
|
455 if ( aHighlight ) |
|
456 { |
|
457 DrawArrowIcon( aGc, arrowRect ); |
|
458 } |
|
459 |
|
460 TInt textWidth( 0 ); |
|
461 TInt err( KErrNone ); |
|
462 TRAP( err, textWidth = DrawTextWithMatchHighlightL( |
|
463 boundingBox, aGc, cellText, iContactNameFont, aColors, aHighlight ) ); |
|
464 |
|
465 if ( !err && TextUtils::ColumnText( cellText , 2, aText ) == KErrNone ) |
|
466 { |
|
467 TRect companyNameBoundingBox = CompanyNameBoundingBox( |
|
468 aItemRect, iCompanyNameFont, aHighlight, iContactDataManager->GetContactThumbnailSetting() ); |
|
469 if ( AknLayoutUtils::LayoutMirrored() ) |
|
470 { |
|
471 companyNameBoundingBox = MirrorLayoutBoundingBox( aItemRect, companyNameBoundingBox ); |
|
472 } |
|
473 TRAP( err, DrawTextWithMatchHighlightL( |
|
474 companyNameBoundingBox, aGc, cellText, iCompanyNameFont, aColors, aHighlight ) ); |
|
475 } |
|
476 |
|
477 if ( !err && fav ) |
|
478 { |
|
479 // Draws the Favourite Icon |
|
480 DrawFavouriteIcon( aGc, nameRectUnMirrored, textWidth, aItemRect ); |
|
481 } |
|
482 |
|
483 if ( transApi ) |
|
484 { |
|
485 aGc.CancelClippingRect(); |
|
486 transApi->StopDrawing(); |
|
487 } |
|
488 } |
|
489 |
|
490 // ----------------------------------------------------------------------------- |
|
491 // ContactThumbnailDrawing |
|
492 // |
|
493 // Draws the Contact Thumbnail Icon if any else draws the dummy contact thumbnail |
|
494 // ----------------------------------------------------------------------------- |
|
495 |
|
496 TBool CEasyDialingListBoxData::ContactThumbnailDrawing(CWindowGc& aGc, TRect aBoundingBox, TPtrC aCellText) const |
|
497 { |
|
498 TBool fav(EFalse); |
|
499 CFbsBitmap* thumbnail(NULL); |
|
500 TBool isLoaded = iContactDataManager->GetThumbnailAndFav(aCellText, thumbnail, fav); |
|
501 if ( isLoaded && thumbnail ) |
|
502 { |
|
503 // center the thumbnail in its rect |
|
504 TSize size(thumbnail->SizeInPixels()); |
|
505 TInt xOffset = (aBoundingBox.Width() - size.iWidth) / 2; |
|
506 TInt yOffset = (aBoundingBox.Height() - size.iHeight) / 2; |
|
507 TPoint tl(aBoundingBox.iTl.iX + xOffset, aBoundingBox.iTl.iY + yOffset); |
|
508 TRect sourceRect( TPoint(0,0),size); |
|
509 aGc.BitBlt(tl, thumbnail, sourceRect); |
|
510 } |
|
511 else if ( isLoaded && iContactDataManager->GetContactThumbnailSetting() ) |
|
512 { |
|
513 // draw dummy thumnbnail, but only if we know that the contact doesn't |
|
514 // have a thumbnail, and thumbnail drawing is enabled. |
|
515 AknIconUtils::SetSize(iDummyThumbnail->Bitmap(), aBoundingBox.Size()); |
|
516 AknIconUtils::SetSize(iDummyThumbnail->Mask(), aBoundingBox.Size()); |
|
517 aGc.BitBltMasked( aBoundingBox.iTl, iDummyThumbnail->Bitmap(), |
|
518 TRect( TPoint(0,0), aBoundingBox.Size() ), |
|
519 iDummyThumbnail->Mask(), ETrue ); |
|
520 } |
|
521 return fav; |
|
522 } |
|
523 |
|
524 |
|
525 // ----------------------------------------------------------------------------- |
|
526 // DrawArrowIcon |
|
527 // Draws the Action Menu |
|
528 // ----------------------------------------------------------------------------- |
|
529 void CEasyDialingListBoxData::DrawArrowIcon( |
|
530 CWindowGc& aGc, TRect aArrowRect) const |
|
531 { |
|
532 // Action Menu Arrow for opening the Action Menu |
|
533 if ( AknLayoutUtils::LayoutMirrored() ) |
|
534 { |
|
535 // For mirrored layout the UI logic is mirrored as well |
|
536 AknIconUtils::SetSize( iArrowPointingLeft->Mask(), aArrowRect.Size() ); |
|
537 aGc.BitBltMasked( aArrowRect.iTl, iColorBitmap, |
|
538 TRect( TPoint(0,0), aArrowRect.Size() ), |
|
539 iArrowPointingLeft->Mask(), ETrue ); |
|
540 |
|
541 } |
|
542 else |
|
543 { |
|
544 AknIconUtils::SetSize( iArrowPointingRight->Mask(), aArrowRect.Size() ); |
|
545 aGc.BitBltMasked( aArrowRect.iTl, iColorBitmap, |
|
546 TRect( TPoint(0,0), aArrowRect.Size() ), |
|
547 iArrowPointingRight->Mask(), ETrue ); |
|
548 } |
|
549 } |
|
550 |
|
551 // ----------------------------------------------------------------------------- |
|
552 // DrawFavouriteIcon |
|
553 // |
|
554 // Draws the Favourite Icon |
|
555 // ----------------------------------------------------------------------------- |
|
556 void CEasyDialingListBoxData::DrawFavouriteIcon( |
|
557 CWindowGc& aGc, |
|
558 TRect aNameRectUnMirrored, |
|
559 TInt aTextWidth, |
|
560 TRect aEffectiveRect) const |
|
561 { |
|
562 CFbsBitmap* favouriteIcon; |
|
563 CFbsBitmap* favouriteIconMask; |
|
564 TRect favouriteIconBoundingBox; |
|
565 |
|
566 favouriteIconBoundingBox = FavouriteIconBoundingBox( aNameRectUnMirrored, aTextWidth ); |
|
567 |
|
568 if ( AknLayoutUtils::LayoutMirrored() ) |
|
569 { |
|
570 favouriteIconBoundingBox = MirrorLayoutBoundingBox(aEffectiveRect, favouriteIconBoundingBox); |
|
571 } |
|
572 |
|
573 aGc.SetBrushStyle( CGraphicsContext::ENullBrush ); |
|
574 TRect sourceRect( TPoint(0,0), favouriteIconBoundingBox.Size() ); |
|
575 |
|
576 if( AknsUtils::SkinInstance()->GetCachedItemData(KAknsIIDQgnFsContactsFavorite) ) |
|
577 { |
|
578 AknsDrawUtils::DrawCachedImage( AknsUtils::SkinInstance(), aGc, sourceRect, |
|
579 KAknsIIDQgnFsContactsFavorite ); |
|
580 } |
|
581 else |
|
582 { |
|
583 // Create the bitmap and mask to draw. |
|
584 TRAP_IGNORE( AknIconUtils::CreateIconL(favouriteIcon, favouriteIconMask, KFavouriteIconBitmapFile, |
|
585 EMbmPhonebook2Qgn_prop_pb_topc, EMbmPhonebook2Qgn_prop_pb_topc_mask )); |
|
586 |
|
587 // Set size for the bitmap and mask |
|
588 AknIconUtils::SetSize(favouriteIcon, favouriteIconBoundingBox.Size()); |
|
589 AknIconUtils::SetSize(favouriteIconMask, favouriteIconBoundingBox.Size()); |
|
590 aGc.BitBltMasked( favouriteIconBoundingBox.iTl , favouriteIcon, sourceRect, favouriteIconMask, ETrue); |
|
591 } |
|
592 } |
|
593 // ----------------------------------------------------------------------------- |
|
594 // SetContactDataManager |
|
595 // |
|
596 // ----------------------------------------------------------------------------- |
|
597 // |
|
598 void CEasyDialingListBoxData::SetContactDataManager(CEasyDialingContactDataManager* aContactDataManager) |
|
599 { |
|
600 iContactDataManager = aContactDataManager; |
|
601 } |
|
602 |
|
603 // ----------------------------------------------------------------------------- |
|
604 // HandleItemSizeChange |
|
605 // |
|
606 // ----------------------------------------------------------------------------- |
|
607 // |
|
608 void CEasyDialingListBoxData::HandleItemSizeChange() |
|
609 { |
|
610 TInt height = iControl->ItemHeight(); |
|
611 TSize size( height, height ); |
|
612 TRAP_IGNORE( UpdateColorBitmapL( size ) ); |
|
613 |
|
614 // Obtain fonts. |
|
615 ObtainFonts( height ); |
|
616 |
|
617 // TODO: also bounding boxes could be updated and stored here |
|
618 } |
|
619 |
|
620 // ----------------------------------------------------------------------------- |
|
621 // ObtainFonts |
|
622 // |
|
623 // ----------------------------------------------------------------------------- |
|
624 // |
|
625 void CEasyDialingListBoxData::ObtainFonts( TInt aItemHeight ) |
|
626 { |
|
627 CWsScreenDevice& screenDev = *( CEikonEnv::Static()->ScreenDevice() ); |
|
628 |
|
629 // Release previous fonts. ReleaseFont function can cope with null pointers |
|
630 // so we don't need to null check them. |
|
631 screenDev.ReleaseFont( iContactNameFont ); |
|
632 screenDev.ReleaseFont( iCompanyNameFont ); |
|
633 |
|
634 // Get a logical font to a basis for our own fonts. |
|
635 const CFont* logicalFont = AknLayoutUtils::FontFromId( EAknLogicalFontSecondaryFont ); |
|
636 |
|
637 // Extract font information |
|
638 TFontSpec fontSpec = logicalFont->FontSpecInTwips(); |
|
639 |
|
640 // Calculate contact name font height in TWIPs. |
|
641 TInt fontHeightPixels = aItemHeight * KContactNameFontHeightPercent / KCent; |
|
642 TInt fontHeightTwips = screenDev.VerticalPixelsToTwips( fontHeightPixels ); |
|
643 |
|
644 // Set height, weight, and posture. |
|
645 fontSpec.iHeight = fontHeightTwips; |
|
646 fontSpec.iFontStyle.SetStrokeWeight( EStrokeWeightBold ); |
|
647 fontSpec.iFontStyle.SetPosture( EPostureUpright ); |
|
648 |
|
649 // Obtain contact name font |
|
650 TInt err = screenDev.GetNearestFontToDesignHeightInTwips( iContactNameFont, fontSpec ); |
|
651 __ASSERT_DEBUG( err == KErrNone, EasyDialingPanic( EEasyDialingNoFontFound ) ); |
|
652 |
|
653 // Calculate company name font height in TWIPs. |
|
654 fontHeightPixels = aItemHeight * KCompanyNameFontHeightPercent / KCent; |
|
655 fontHeightTwips = screenDev.VerticalPixelsToTwips( fontHeightPixels ); |
|
656 fontSpec.iHeight = fontHeightTwips; |
|
657 fontSpec.iFontStyle.SetStrokeWeight( EStrokeWeightNormal ); |
|
658 |
|
659 // Obtain company name font. |
|
660 err = screenDev.GetNearestFontToDesignHeightInTwips( iCompanyNameFont, fontSpec ); |
|
661 __ASSERT_DEBUG( err == KErrNone, EasyDialingPanic( EEasyDialingNoFontFound ) ); |
|
662 } |
|
663 |
|
664 |
|
665 // ----------------------------------------------------------------------------- |
|
666 // UpdateColorBitmapL |
|
667 // ColorBitmap is redrawn when UI layout or text color (Theme) changes |
|
668 // ----------------------------------------------------------------------------- |
|
669 // |
|
670 void CEasyDialingListBoxData::UpdateColorBitmapL( const TSize& aSize ) |
|
671 { |
|
672 TRgb color; |
|
673 // Get the HighLighted text color in ListBox from the Theme |
|
674 AknsUtils::GetCachedColor( AknsUtils::SkinInstance(), color, |
|
675 KAknsIIDQsnTextColors, EAknsCIQsnTextColorsCG10 ); |
|
676 |
|
677 // Create a bitmap with the similar display mode than what the device currently |
|
678 // uses for using it as an offscreen bitmap |
|
679 AknIconConfig::TPreferredDisplayMode mode; |
|
680 AknIconConfig::PreferredDisplayMode( mode, AknIconConfig::EImageTypeOffscreen ); |
|
681 User::LeaveIfError( iColorBitmap->Create( aSize, mode.iBitmapMode ) ); |
|
682 |
|
683 // Create a new drawing device and graphics context for enabling drawing to |
|
684 // the offscreen bitmap |
|
685 CFbsBitmapDevice* destinationDevice = CFbsBitmapDevice::NewL( iColorBitmap ); |
|
686 CleanupStack::PushL(destinationDevice); |
|
687 |
|
688 CFbsBitGc* destinationGc; |
|
689 User::LeaveIfError( destinationDevice->CreateContext( destinationGc ) ); |
|
690 |
|
691 // Set the color and style for pen and brush and draw a rectangle to the |
|
692 // bitmap graphics |
|
693 destinationGc->SetPenColor( color ); |
|
694 destinationGc->SetPenStyle( CGraphicsContext::ESolidPen ); |
|
695 destinationGc->SetBrushColor( color ); |
|
696 destinationGc->SetBrushStyle( CGraphicsContext::ESolidBrush ); |
|
697 destinationGc->DrawRect( TRect( TPoint( 0,0 ), aSize ) ); |
|
698 |
|
699 // Colorbitmap is ready, cleanup |
|
700 delete destinationGc; |
|
701 CleanupStack::PopAndDestroy(destinationDevice); |
|
702 } |
|
703 |
|
704 // ----------------------------------------------------------------------------- |
|
705 // SetEDLBXControl |
|
706 // |
|
707 // ----------------------------------------------------------------------------- |
|
708 // |
|
709 void CEasyDialingListBoxData::SetEDLBXControl(CEasyDialingListBox* aControl) |
|
710 { |
|
711 iControl = aControl; |
|
712 } |
|
713 |
|
714 |
|
715 /* |
|
716 * ============================================================================== |
|
717 * |
|
718 * Local functions |
|
719 * |
|
720 * ============================================================================== |
|
721 */ |
|
722 |
|
723 |
|
724 // ----------------------------------------------------------------------------- |
|
725 // ContactImageBoundingBox |
|
726 // Calculates the area where contact thumbnail is confined |
|
727 // ----------------------------------------------------------------------------- |
|
728 // |
|
729 TRect ContactImageBoundingBox(const TRect& aItemRect) |
|
730 { |
|
731 TInt leftMargin = aItemRect.Width() * KMarginXPercent / KCent; |
|
732 TInt topMargin = KMarginYPercent * aItemRect.Height() / KCent; |
|
733 TInt bottomMargin = topMargin; |
|
734 TInt width = ((aItemRect.Height() - topMargin - bottomMargin) * KThumbnailAspectRatio) / KCent; |
|
735 |
|
736 return TRect( |
|
737 aItemRect.iTl.iX + leftMargin, |
|
738 aItemRect.iTl.iY + topMargin, |
|
739 aItemRect.iTl.iX + leftMargin + width, |
|
740 aItemRect.iBr.iY - bottomMargin); |
|
741 } |
|
742 |
|
743 // ----------------------------------------------------------------------------- |
|
744 // ContactNameBoundingBox |
|
745 // Calculates the area to which the contact name and possible match highlights |
|
746 // are confined. |
|
747 // |
|
748 // ----------------------------------------------------------------------------- |
|
749 // |
|
750 static TRect ContactNameBoundingBox( |
|
751 const TRect& aItemRect, |
|
752 const CFont* aContactNameFont, |
|
753 TBool aIsCurrentItem, |
|
754 TBool aIsFavourite, |
|
755 TBool aThumbnailsShown ) |
|
756 { |
|
757 // Position X will contain the starting position of text from left side of item rect. |
|
758 TInt positionX = aItemRect.Width() * KMarginXPercent / KCent; |
|
759 |
|
760 if (aThumbnailsShown) |
|
761 { |
|
762 // If contact image is shown, text starts from right side of contact picture + margin. |
|
763 TRect contactImageBoundingBox = ContactImageBoundingBox( aItemRect ); |
|
764 positionX += contactImageBoundingBox.Width(); |
|
765 positionX += aItemRect.Width() * KMarginXPercent / KCent; |
|
766 } |
|
767 |
|
768 TInt topMargin = KContactNameYOffsetPercent * aItemRect.Height() / KCent; |
|
769 TInt height = KTextBoundingBoxHeightPercent * aContactNameFont->FontMaxHeight() / KCent; |
|
770 TInt rightMargin = KMarginXPercent * aItemRect.Width() / KCent; |
|
771 |
|
772 // Reserve space for communication launcher icon. |
|
773 // Communication launcher icon is shown only id item is highlighted. |
|
774 if ( aIsCurrentItem ) |
|
775 { |
|
776 rightMargin += KArrowIconSizePercent * aItemRect.Height() / KCent; |
|
777 } |
|
778 |
|
779 // If item is favourite, reserve space for favourite icon. Icon dimensions are the same as bounding box height. |
|
780 if ( aIsFavourite ) |
|
781 { |
|
782 rightMargin += height; |
|
783 } |
|
784 |
|
785 return TRect( |
|
786 aItemRect.iTl.iX + positionX, |
|
787 aItemRect.iTl.iY + topMargin, |
|
788 aItemRect.iTl.iX + aItemRect.Width() - rightMargin, |
|
789 aItemRect.iTl.iY + topMargin + height); |
|
790 } |
|
791 |
|
792 |
|
793 // ----------------------------------------------------------------------------- |
|
794 // CompanyNameBoundingBox |
|
795 // Calculates the area to which the company name and possible match highlights |
|
796 // are confined. |
|
797 // ----------------------------------------------------------------------------- |
|
798 // |
|
799 static TRect CompanyNameBoundingBox( |
|
800 const TRect& aItemRect, |
|
801 const CFont* aCompanyNameFont, |
|
802 TBool aIsCurrentItem, |
|
803 TBool aThumbnailsShown ) |
|
804 { |
|
805 // Position X will contain the starting position of text from left side of item rect. |
|
806 TInt positionX = aItemRect.Width() * KMarginXPercent / KCent; |
|
807 |
|
808 if (aThumbnailsShown) |
|
809 { |
|
810 // If contact image is show, text starts from right side of contact picture + margin. |
|
811 TRect contactImageBoundingBox = ContactImageBoundingBox( aItemRect ); |
|
812 positionX += contactImageBoundingBox.Width(); |
|
813 positionX += aItemRect.Width() * KMarginXPercent / KCent; |
|
814 } |
|
815 |
|
816 TInt topMargin = KCompanyNameYOffsetPercent * aItemRect.Height() / KCent; |
|
817 TInt height = KTextBoundingBoxHeightPercent * aCompanyNameFont->FontMaxHeight() / KCent; |
|
818 TInt rightMargin = KMarginXPercent * aItemRect.Width() / KCent; |
|
819 |
|
820 // Reserve space for communication launcher icon. |
|
821 // Communication launcher icon is shown only id item is highlighted. |
|
822 if ( aIsCurrentItem ) |
|
823 { |
|
824 rightMargin += KArrowIconSizePercent * aItemRect.Height() / KCent; |
|
825 } |
|
826 |
|
827 return TRect( |
|
828 aItemRect.iTl.iX + positionX, |
|
829 aItemRect.iTl.iY + topMargin, |
|
830 aItemRect.iTl.iX + aItemRect.Width() - rightMargin, |
|
831 aItemRect.iTl.iY + topMargin + height); |
|
832 } |
|
833 |
|
834 |
|
835 // ----------------------------------------------------------------------------- |
|
836 // ArrowIconBoundingBox |
|
837 // Calculates the area to which the action menu icon is drawn. |
|
838 // ----------------------------------------------------------------------------- |
|
839 // |
|
840 TRect ArrowIconBoundingBox(const TRect& aItemRect) |
|
841 { |
|
842 TInt iconSize = KArrowIconSizePercent * aItemRect.Height() / KCent; |
|
843 TInt rightMargin = KMarginXPercent * aItemRect.Width() / KCent; |
|
844 TInt positionX = aItemRect.iBr.iX - rightMargin - iconSize; |
|
845 TInt topMargin = ( aItemRect.Height() - iconSize ) / 2; // Icon is vertically centered. |
|
846 |
|
847 return TRect( |
|
848 positionX, |
|
849 aItemRect.iTl.iY + topMargin, |
|
850 positionX + iconSize, |
|
851 aItemRect.iTl.iY + topMargin + iconSize ); |
|
852 } |
|
853 |
|
854 |
|
855 // ----------------------------------------------------------------------------- |
|
856 // FavouriteIconBoundingBox |
|
857 // Calculates the area to which the favourite icon is drawn. |
|
858 // Because favourite icon is drawn in the same line with contact name, |
|
859 // this function takes contact name bounding box as the parameter, not |
|
860 // the whole item rect. |
|
861 // ----------------------------------------------------------------------------- |
|
862 // |
|
863 static TRect FavouriteIconBoundingBox( const TRect& aContactNameBoundingBox, TInt aTextWidth ) |
|
864 { |
|
865 return TRect( |
|
866 aContactNameBoundingBox.iTl.iX + aTextWidth, |
|
867 aContactNameBoundingBox.iTl.iY, |
|
868 aContactNameBoundingBox.iTl.iX + aTextWidth + aContactNameBoundingBox.Height(), |
|
869 aContactNameBoundingBox.iBr.iY); |
|
870 } |
|
871 |
|
872 |
|
873 |
|
874 // ----------------------------------------------------------------------------- |
|
875 // BaseLineOffset |
|
876 // |
|
877 // ----------------------------------------------------------------------------- |
|
878 // |
|
879 static TInt BaseLineOffset( const TRect& aTextBoundingBox, const CFont* aFont ) |
|
880 { |
|
881 TInt fontHeight = aFont->FontMaxHeight(); |
|
882 TInt topMargin = KTextPlacementPercent * (aTextBoundingBox.Height() - fontHeight) / KCent; |
|
883 return fontHeight + topMargin - aFont->FontMaxDescent(); |
|
884 } |
|
885 |
|
886 |
|
887 // ----------------------------------------------------------------------------- |
|
888 // MirrorLayoutBoundingBox |
|
889 // |
|
890 // ----------------------------------------------------------------------------- |
|
891 // |
|
892 static TRect MirrorLayoutBoundingBox(const TRect& aSourceRect, TRect& aBoundingBoxRect) |
|
893 { |
|
894 return TRect( |
|
895 aSourceRect.iTl.iX + aSourceRect.iBr.iX - aBoundingBoxRect.iBr.iX, |
|
896 aBoundingBoxRect.iTl.iY, |
|
897 aSourceRect.iTl.iX + aSourceRect.iBr.iX - aBoundingBoxRect.iTl.iX, |
|
898 aBoundingBoxRect.iBr.iY); |
|
899 } |
|
900 |
|
901 |
|
902 // ----------------------------------------------------------------------------- |
|
903 // ClipTextToWidth |
|
904 // Cuts the text in the given pixel width. Also considers match highlight |
|
905 // issues. |
|
906 // NOTE: Can change the aMatch parameter if considers that there is too little |
|
907 // width for matching highlight. |
|
908 // NOTE 2: This function cannot handle right-to-left or bidirectional text currently. |
|
909 // These cases must be handled elsewhere. |
|
910 // ----------------------------------------------------------------------------- |
|
911 // |
|
912 |
|
913 _LIT( KThreeDots, "..." ); |
|
914 |
|
915 static void ClipTextToWidth( |
|
916 TDes& aText, |
|
917 const CFont& aFont, |
|
918 TInt aMaxWidthInPixels, |
|
919 TBool& aMatch) |
|
920 { |
|
921 TInt minimumWidth = aFont.TextWidthInPixels( KThreeDots ); |
|
922 |
|
923 // If this is a matching piece of text, also match text marginals need to be counted. |
|
924 if ( aMatch ) |
|
925 { |
|
926 minimumWidth += 2 * KMatchingTextMarginInPixels; |
|
927 } |
|
928 |
|
929 if ( minimumWidth > aMaxWidthInPixels ) |
|
930 { |
|
931 |
|
932 // Not enough space for any text. |
|
933 aText.Zero(); |
|
934 aMatch = EFalse; // No match highlight shown. |
|
935 return; |
|
936 } |
|
937 |
|
938 if ( aMatch ) |
|
939 { |
|
940 aMaxWidthInPixels -= 2 * KMatchingTextMarginInPixels; |
|
941 } |
|
942 |
|
943 AknTextUtils::ClipToFit( aText, aFont, aMaxWidthInPixels ); |
|
944 } |
|
945 |
|
946 |
|
947 // ----------------------------------------------------------------------------- |
|
948 // DrawPieceOfText |
|
949 // Draws a piece of text of contact, either matching or not matching. |
|
950 // Updates aXOffset argument by adding drawn text width. |
|
951 // |
|
952 // @return: ETrue, if there was enough space for the text to draw. |
|
953 // NOTE: CWindowGc font must be set before calling this function. |
|
954 // ----------------------------------------------------------------------------- |
|
955 // |
|
956 static TBool DrawPieceOfText( |
|
957 const TRect& aBoundingBox, |
|
958 TInt& aXOffset, |
|
959 CWindowGc &aGc, |
|
960 const TDesC& aText, |
|
961 TBool aMatch, |
|
962 const CFont* aFont, |
|
963 const CEasyDialingListBoxData::TExtendedColors& aColors, |
|
964 TBool aHighLight ) |
|
965 { |
|
966 if (aText.Length() == 0) |
|
967 { |
|
968 return ETrue; |
|
969 } |
|
970 |
|
971 HBufC* newText = aText.Alloc(); |
|
972 if ( !newText ) |
|
973 { |
|
974 return EFalse; |
|
975 } |
|
976 |
|
977 TPtr textPtr = newText->Des(); |
|
978 |
|
979 // textWidth is the width needed for the text. |
|
980 TInt textWidth = AknBidiTextUtils::MeasureTextBoundsWidth( *aFont, textPtr, CFont::TMeasureTextInput::EFVisualOrder ); |
|
981 |
|
982 // whole width includes also possible highlight margins. |
|
983 TInt wholeWidth = textWidth + ( aMatch ? 2 * KMatchingTextMarginInPixels : 0); |
|
984 |
|
985 // availableWidth is the space left for drawing. |
|
986 TInt availableWidth = aBoundingBox.Width() - aXOffset; |
|
987 |
|
988 if ( availableWidth < wholeWidth ) |
|
989 { |
|
990 ClipTextToWidth( textPtr, *aFont, availableWidth, aMatch ); |
|
991 wholeWidth = availableWidth; |
|
992 if ( aMatch ) |
|
993 { |
|
994 textWidth = wholeWidth - (2 * KMatchingTextMarginInPixels); |
|
995 } |
|
996 else |
|
997 { |
|
998 textWidth = wholeWidth; |
|
999 } |
|
1000 } |
|
1001 |
|
1002 // textBox is rectangle for text without highlight. |
|
1003 TRect textBox( aBoundingBox ); |
|
1004 textBox.iTl.iX += aXOffset; |
|
1005 textBox.iBr.iX = textBox.iTl.iX + textWidth; |
|
1006 |
|
1007 TInt baseLineOffset = BaseLineOffset( textBox, aFont ); |
|
1008 |
|
1009 if ( aMatch ) |
|
1010 { |
|
1011 // highlightBox rectangle for text with highlight. |
|
1012 // Compared to no highlight, it has extra margins on both sides. |
|
1013 TRect highlightBox( textBox ); |
|
1014 highlightBox.iBr.iX = highlightBox.iTl.iX + wholeWidth; |
|
1015 |
|
1016 // Also boundingBox is shifted right for one margin width. |
|
1017 textBox.iTl.iX += KMatchingTextMarginInPixels; |
|
1018 textBox.iBr.iX += KMatchingTextMarginInPixels; |
|
1019 |
|
1020 // Outline of matching highlight is of same colour as text. |
|
1021 // This looks quite OK. |
|
1022 aGc.SetPenColor( aColors.iMatchingText ); |
|
1023 aGc.SetBrushStyle( CGraphicsContext::ESolidBrush ); |
|
1024 aGc.SetBrushColor( aColors.iMatchingBack ); |
|
1025 |
|
1026 aGc.DrawRoundRect( highlightBox, TSize( KMatchingTextMarginInPixels, KHighligthRectangleRoundingYInPixels ) ); |
|
1027 |
|
1028 aGc.SetBrushStyle( CGraphicsContext::ENullBrush ); |
|
1029 } |
|
1030 else |
|
1031 { |
|
1032 if ( aHighLight ) |
|
1033 { |
|
1034 aGc.SetPenColor( aColors.iHighlightedText ); |
|
1035 } |
|
1036 else |
|
1037 { |
|
1038 aGc.SetPenColor( aColors.iText ); |
|
1039 } |
|
1040 } |
|
1041 |
|
1042 aGc.DrawText( textPtr, textBox, baseLineOffset ); |
|
1043 delete newText; |
|
1044 aXOffset += wholeWidth; |
|
1045 return ETrue; |
|
1046 } |
|
1047 |
|
1048 |
|
1049 // ----------------------------------------------------------------------------- |
|
1050 // DrawTextWithMatchHighlight |
|
1051 // Draws a string with match highlight. Highlighted and non-highlighted |
|
1052 // parts are separated with KHighlightSeparatorChar. |
|
1053 // The first text part is not highlighted and from that on highlight |
|
1054 // is on on every other text piece. |
|
1055 // |
|
1056 // ----------------------------------------------------------------------------- |
|
1057 // |
|
1058 static TInt DrawTextWithMatchHighlightL( |
|
1059 const TRect& aBoundingBox, |
|
1060 CWindowGc &aGc, |
|
1061 const TDesC& aText, |
|
1062 const CFont* aFont, |
|
1063 const CEasyDialingListBoxData::TExtendedColors& aColors, |
|
1064 TBool aHighLight) |
|
1065 { |
|
1066 TInt xOffset = 0; |
|
1067 |
|
1068 HBufC* visualBuf = ConvertToVisualAndClipLC( aText, *aFont, aBoundingBox ); |
|
1069 |
|
1070 TInt calculatedTextWidth = CalculateTextWidth( aBoundingBox, *visualBuf, aFont ); |
|
1071 |
|
1072 if ( AknLayoutUtils::LayoutMirrored() ) |
|
1073 { |
|
1074 xOffset = aBoundingBox.Width() - calculatedTextWidth; |
|
1075 } |
|
1076 TPtrC textPiece; |
|
1077 TInt textPieceIndex = 0; |
|
1078 TBool match = EFalse; |
|
1079 |
|
1080 aGc.UseFont( aFont ); |
|
1081 aGc.SetBrushStyle( CGraphicsContext::ENullBrush ); |
|
1082 |
|
1083 while ( TextUtils::ColumnText( textPiece , textPieceIndex, visualBuf, KHighlightSeparatorChar) == KErrNone ) |
|
1084 { |
|
1085 if (! DrawPieceOfText( aBoundingBox, xOffset, aGc, textPiece, match, aFont, aColors, aHighLight )) |
|
1086 { |
|
1087 // If there was not enough space for this piece of text, exit the loop stop drawing further pieces. |
|
1088 break; |
|
1089 } |
|
1090 |
|
1091 // Toggle match |
|
1092 match = !match; |
|
1093 |
|
1094 ++textPieceIndex; |
|
1095 } |
|
1096 |
|
1097 CleanupStack::PopAndDestroy( visualBuf ); |
|
1098 |
|
1099 aGc.DiscardFont(); |
|
1100 |
|
1101 return calculatedTextWidth; |
|
1102 } |
|
1103 |
|
1104 // ----------------------------------------------------------------------------- |
|
1105 // CalculateTextWidth |
|
1106 // Calculates the width of the text and returns it |
|
1107 // ----------------------------------------------------------------------------- |
|
1108 // |
|
1109 static TInt CalculateTextWidth(const TRect& aBoundingBox, const TDesC& aText, const CFont* aFont ) |
|
1110 { |
|
1111 |
|
1112 TInt xOffset = 0; |
|
1113 TPtrC textPiece; |
|
1114 TInt textPieceIndex = 0; |
|
1115 TBool match = EFalse; |
|
1116 |
|
1117 while ( TextUtils::ColumnText( textPiece , textPieceIndex, &aText, KHighlightSeparatorChar) == KErrNone ) |
|
1118 { |
|
1119 if (! CalculateTextPieceWidth( aBoundingBox, xOffset, textPiece, match, aFont )) |
|
1120 { |
|
1121 // If there was not enough space for this piece of text, exit the loop stop drawing further pieces. |
|
1122 break; |
|
1123 } |
|
1124 |
|
1125 // Toggle match |
|
1126 match = !match; |
|
1127 |
|
1128 ++textPieceIndex; |
|
1129 } |
|
1130 |
|
1131 return xOffset; |
|
1132 } |
|
1133 |
|
1134 // ----------------------------------------------------------------------------- |
|
1135 // CalculateTextPieceWidth |
|
1136 // |
|
1137 // Calculates the width of the text piece of highlighted text. |
|
1138 // The function is aware of the available width for the text, and can take |
|
1139 // possible clippings into account. |
|
1140 // |
|
1141 // The available width is given by parameters aBoundingBox (space for all text |
|
1142 // pieces) and aXOffset (now much of that space has already been used). |
|
1143 // |
|
1144 // The function adds the text width to the aXOffset reference parameter. |
|
1145 // Returns EFalse, if there is no more space for new text pieces, otherwise |
|
1146 // ETrue. |
|
1147 // |
|
1148 // This function contains the same logic as function DrawPieceOfText. |
|
1149 // ----------------------------------------------------------------------------- |
|
1150 // |
|
1151 static TBool CalculateTextPieceWidth( |
|
1152 const TRect& aBoundingBox, |
|
1153 TInt& aXOffset, |
|
1154 const TDesC& aText, |
|
1155 TBool aMatch, |
|
1156 const CFont* aFont ) |
|
1157 { |
|
1158 if (aText.Length() == 0) |
|
1159 { |
|
1160 return ETrue; |
|
1161 } |
|
1162 |
|
1163 // textWidth is the width needed for the text. |
|
1164 TInt textWidth = AknBidiTextUtils::MeasureTextBoundsWidth( *aFont, aText, CFont::TMeasureTextInput::EFVisualOrder ); |
|
1165 |
|
1166 // whole width includes also possible highlight margins. |
|
1167 TInt wholeWidth = textWidth + ( aMatch ? 2 * KMatchingTextMarginInPixels : 0); |
|
1168 |
|
1169 // availableWidth is the space left for drawing. |
|
1170 TInt availableWidth = aBoundingBox.Width() - aXOffset; |
|
1171 |
|
1172 if ( availableWidth < wholeWidth ) |
|
1173 { |
|
1174 |
|
1175 // We get to this branch, if there is not enough space for the text piece. |
|
1176 HBufC* newText = aText.Alloc(); |
|
1177 if ( !newText ) |
|
1178 { |
|
1179 return EFalse; |
|
1180 } |
|
1181 |
|
1182 TPtr textPtr = newText->Des(); |
|
1183 |
|
1184 // Clip the text so that it fits the space. |
|
1185 ClipTextToWidth( textPtr, *aFont, availableWidth, aMatch ); |
|
1186 |
|
1187 if ( textPtr.Length() > 0 ) |
|
1188 { |
|
1189 wholeWidth = AknBidiTextUtils::MeasureTextBoundsWidth( *aFont, textPtr, CFont::TMeasureTextInput::EFVisualOrder ); |
|
1190 wholeWidth += (aMatch ? 2 * KMatchingTextMarginInPixels : 0); |
|
1191 |
|
1192 aXOffset += wholeWidth; |
|
1193 } |
|
1194 |
|
1195 delete newText; |
|
1196 |
|
1197 return EFalse; |
|
1198 } |
|
1199 |
|
1200 aXOffset += wholeWidth; |
|
1201 |
|
1202 return ETrue; |
|
1203 } |
|
1204 |
|
1205 // ----------------------------------------------------------------------------- |
|
1206 // ContainsRightToLeftText |
|
1207 // |
|
1208 // Returns true if argument descriptor contains right-to-left text. |
|
1209 // ----------------------------------------------------------------------------- |
|
1210 // |
|
1211 static TBool ContainsRightToLeftText( const TDesC& aDesc ) |
|
1212 { |
|
1213 TBool rtlFound = EFalse; |
|
1214 |
|
1215 // TRunInfoArray contains information of the directionalities of the different sections of the aText |
|
1216 TBidirectionalState::TRunInfo array[ KMaxRunInfoArrayCount ]; |
|
1217 |
|
1218 // Initialize the TBidiLogicalToVisual converter for making the conversion from logical to visual order |
|
1219 TBidiLogicalToVisual converter( aDesc, array, KMaxRunInfoArrayCount ); |
|
1220 |
|
1221 // Do the reordering. Amount of different directionality sections is returned. |
|
1222 TInt count( converter.Reorder() ); |
|
1223 // If there are more directionality blocks than we are prepared to handle, just ignore |
|
1224 // the rest. Those shouldn't fit the screen anyway. |
|
1225 count = Min( count, KMaxRunInfoArrayCount ); |
|
1226 |
|
1227 for ( TInt i = 0 ; i < count && !rtlFound ; i++ ) |
|
1228 { |
|
1229 // iDirection is 0 for left-to-right text. |
|
1230 if (array[i].iDirection) |
|
1231 { |
|
1232 rtlFound = ETrue; |
|
1233 } |
|
1234 } |
|
1235 |
|
1236 return rtlFound; |
|
1237 } |
|
1238 |
|
1239 // ----------------------------------------------------------------------------- |
|
1240 // ConvertToVisualAndClipL |
|
1241 // |
|
1242 // Clip bidirectional text to given box and convert it to visual order, ensuring |
|
1243 // that the match highlights don't get broken in the process. Result is given |
|
1244 // as new heap descriptor which is left to CleanupStack. |
|
1245 // NOTE1: No clipping happens here if given descriptor contains only |
|
1246 // left-to-right text. |
|
1247 // NOTE2: It's assumed that there can be highlights only in pure LTR and RTL |
|
1248 // texts. Highlights for mixed LTR-RTL text cannot be handled properly. |
|
1249 // ----------------------------------------------------------------------------- |
|
1250 // |
|
1251 static HBufC* ConvertToVisualAndClipLC( const TDesC& aText, |
|
1252 const CFont& aFont, |
|
1253 const TRect& aBoundingBox ) |
|
1254 { |
|
1255 HBufC* buf = HBufC::NewLC( aText.Length() + KAknBidiExtraSpacePerLine ); |
|
1256 TPtr ptr = buf->Des(); |
|
1257 ptr.Copy( aText ); |
|
1258 |
|
1259 // Calling AknBidiTextUtils::ConvertToVisualAndClip doesn't work correctly |
|
1260 // with the highlight separator characters (they are not considered to be |
|
1261 // zero-length). To minimise the problem, we call the function only when |
|
1262 // necessary, i.e. when given text really contains RTL text. This should be |
|
1263 // considered as temporary solutions because now the problem of excessive |
|
1264 // truncation still remains with RTL languages. |
|
1265 if ( ContainsRightToLeftText( ptr ) ) |
|
1266 { |
|
1267 AknBidiTextUtils::ConvertToVisualAndClipL( |
|
1268 ptr, aFont, aBoundingBox.Width(), |
|
1269 aBoundingBox.Width() ); |
|
1270 |
|
1271 // If there's an odd number of highlight separators in the RTL text, |
|
1272 // then the matching and and not-matching parts have gone |
|
1273 // off-sync in the visual conversion (because parts are drawn starting |
|
1274 // from left and first part is always interpreted as not-matching part). |
|
1275 // Fix this by adding one highlight separator. |
|
1276 TInt sepCount = HighlightSeparatorCount( ptr ); |
|
1277 if ( sepCount % 2 ) |
|
1278 { |
|
1279 if ( ptr.Length() == ptr.MaxLength() ) |
|
1280 { |
|
1281 // There's no more space available. We need to reallocate the |
|
1282 // buffer in order to fit the extra separator character. |
|
1283 HBufC* newBuf = buf->ReAllocL( buf->Length() + 1 ); |
|
1284 CleanupStack::Pop( buf ); // original buf deleted by ReAllocL |
|
1285 buf = newBuf; |
|
1286 CleanupStack::PushL( buf ); |
|
1287 ptr.Set( buf->Des() ); |
|
1288 } |
|
1289 ptr.Insert( 0, KHighlightSeparatorCharAsLit ); |
|
1290 } |
|
1291 } |
|
1292 |
|
1293 return buf; |
|
1294 } |
|
1295 |
|
1296 // ----------------------------------------------------------------------------- |
|
1297 // HighlightSeparatorCount |
|
1298 // |
|
1299 // Returns number of match highlight separator characters in the text |
|
1300 // ----------------------------------------------------------------------------- |
|
1301 // |
|
1302 static TInt HighlightSeparatorCount( const TDesC& aText ) |
|
1303 { |
|
1304 TInt len = aText.Length(); |
|
1305 TInt sepCount = 0; |
|
1306 |
|
1307 for ( TInt i = 0; i < len; i++ ) |
|
1308 { |
|
1309 if ( aText[i] == KHighlightSeparatorChar ) |
|
1310 { |
|
1311 sepCount++; |
|
1312 } |
|
1313 } |
|
1314 |
|
1315 return sepCount; |
|
1316 } |
|
1317 |
|
1318 // End of File. |
|
1319 |