@@ -60,6 +60,7 @@ class TextListComponent : public IList<TextListData, T>
6060 inline void setAlignment (Alignment align) { mAlignment = align; }
6161
6262 inline void setCursorChangedCallback (const std::function<void (CursorState state)>& func) { mCursorChangedCallback = func; }
63+ inline void setFavoriteIndicatorCallback (const std::function<bool (const T&)>& func) { mFavoriteIndicatorCallback = func; }
6364
6465 inline void setFont (const std::shared_ptr<Font>& font)
6566 {
@@ -109,17 +110,20 @@ class TextListComponent : public IList<TextListData, T>
109110 bool mSelectorColorGradientHorizontal = true ;
110111 unsigned int mSelectedColor ;
111112 std::string mScrollSound ;
113+ std::function<bool (const T&)> mFavoriteIndicatorCallback ;
112114 static const unsigned int COLOR_ID_COUNT = 2 ;
113115 unsigned int mColors [COLOR_ID_COUNT];
114116 int mViewportHeight ;
115117 int mCursorPrev = -1 ;
116118
117119 ImageComponent mSelectorImage ;
120+ ImageComponent mFavoriteIcon ;
121+ bool mFavoriteIconVisible ;
118122};
119123
120124template <typename T>
121125TextListComponent<T>::TextListComponent(Window* window) :
122- IList<TextListData, T>(window), mSelectorImage (window)
126+ IList<TextListData, T>(window), mSelectorImage (window), mFavoriteIcon (window)
123127{
124128 mMarqueeOffset = 0 ;
125129 mMarqueeOffset2 = 0 ;
@@ -139,6 +143,9 @@ TextListComponent<T>::TextListComponent(Window* window) :
139143 mSelectedColor = 0 ;
140144 mColors [0 ] = 0x0000FFFF ;
141145 mColors [1 ] = 0x00FF00FF ;
146+
147+ mFavoriteIcon .setImage (" :/heart_filled.svg" );
148+ mFavoriteIconVisible = true ;
142149}
143150
144151template <typename T>
@@ -204,6 +211,12 @@ void TextListComponent<T>::render(const Transform4x4f& parentTrans)
204211
205212 entry.data .textCache ->setColor (color);
206213
214+ const bool showFavorite = mFavoriteIconVisible && (mFavoriteIndicatorCallback ? mFavoriteIndicatorCallback (entry.object ) : false );
215+ const float iconSize = entrySize * 0 .60f ;
216+ const float iconGap = showFavorite ? (iconSize * 0 .35f ) : 0 .0f ;
217+ const float textWidth = entry.data .textCache ->metrics .size .x ();
218+ const float lineWidth = showFavorite ? (iconSize + iconGap + textWidth) : textWidth;
219+
207220 Vector3f offset (0 , y, 0 );
208221
209222 switch (mAlignment )
@@ -212,26 +225,41 @@ void TextListComponent<T>::render(const Transform4x4f& parentTrans)
212225 offset[0 ] = mHorizontalMargin ;
213226 break ;
214227 case ALIGN_CENTER:
215- offset[0 ] = (int )((mSize .x () - entry. data . textCache -> metrics . size . x () ) / 2 );
228+ offset[0 ] = (int )((mSize .x () - lineWidth ) / 2 );
216229 if (offset[0 ] < mHorizontalMargin )
217230 offset[0 ] = mHorizontalMargin ;
218231 break ;
219232 case ALIGN_RIGHT:
220- offset[0 ] = (mSize .x () - entry. data . textCache -> metrics . size . x () );
233+ offset[0 ] = (mSize .x () - lineWidth );
221234 offset[0 ] -= mHorizontalMargin ;
222235 if (offset[0 ] < mHorizontalMargin )
223236 offset[0 ] = mHorizontalMargin ;
224237 break ;
225238 }
226239
240+ float rowScrollOffset = 0 .0f ;
241+ if ((mCursor == i) && (mMarqueeOffset > 0 ))
242+ rowScrollOffset = (float )mMarqueeOffset ;
243+
244+ if (showFavorite)
245+ {
246+ Transform4x4f iconTrans = trans;
247+ iconTrans.translate (offset - Vector3f (rowScrollOffset, 0 , 0 ));
248+ mFavoriteIcon .setPosition (0 , (entrySize - iconSize) * 0 .5f , 0 );
249+ mFavoriteIcon .setResize (iconSize, iconSize);
250+ mFavoriteIcon .render (iconTrans);
251+ }
252+
253+ Vector3f textOffset = offset + Vector3f (showFavorite ? (iconSize + iconGap) : 0 .0f , 0 , 0 );
254+
227255 // render text
228256 Transform4x4f drawTrans = trans;
229257
230258 // currently selected item text might be scrolling
231259 if ((mCursor == i) && (mMarqueeOffset > 0 ))
232- drawTrans.translate (offset - Vector3f ((float )mMarqueeOffset , 0 , 0 ));
260+ drawTrans.translate (textOffset - Vector3f ((float )mMarqueeOffset , 0 , 0 ));
233261 else
234- drawTrans.translate (offset );
262+ drawTrans.translate (textOffset );
235263
236264 Renderer::setMatrix (drawTrans);
237265 font->renderTextCache (entry.data .textCache .get ());
@@ -240,8 +268,16 @@ void TextListComponent<T>::render(const Transform4x4f& parentTrans)
240268 // marquee is scrolled far enough for it to repeat
241269 if ((mCursor == i) && (mMarqueeOffset2 < 0 ))
242270 {
271+ // also render the favorite icon alongside the wrap-around copy of the text
272+ if (showFavorite)
273+ {
274+ Transform4x4f iconTrans2 = trans;
275+ iconTrans2.translate (offset - Vector3f ((float )mMarqueeOffset2 , 0 , 0 ));
276+ mFavoriteIcon .render (iconTrans2);
277+ }
278+
243279 drawTrans = trans;
244- drawTrans.translate (offset - Vector3f ((float )mMarqueeOffset2 , 0 , 0 ));
280+ drawTrans.translate (textOffset - Vector3f ((float )mMarqueeOffset2 , 0 , 0 ));
245281 Renderer::setMatrix (drawTrans);
246282 font->renderTextCache (entry.data .textCache .get ());
247283 }
@@ -481,6 +517,21 @@ void TextListComponent<T>::applyTheme(const std::shared_ptr<ThemeData>& theme, c
481517 } else {
482518 mSelectorImage .setImage (" " );
483519 }
520+
521+ if (elem->has (" favoriteIconPath" ))
522+ mFavoriteIcon .setImage (elem->get <std::string>(" favoriteIconPath" ));
523+ else
524+ mFavoriteIcon .setImage (" :/heart_filled.svg" );
525+
526+ if (elem->has (" favoriteIconColor" ))
527+ mFavoriteIcon .setColorShift (elem->get <unsigned int >(" favoriteIconColor" ));
528+ else
529+ mFavoriteIcon .setColorShift (0xFFFFFFFF );
530+
531+ if (elem->has (" favoriteIconVisible" ))
532+ mFavoriteIconVisible = elem->get <bool >(" favoriteIconVisible" );
533+ else
534+ mFavoriteIconVisible = true ;
484535}
485536
486537#endif // ES_APP_COMPONENTS_TEXT_LIST_COMPONENT_H
0 commit comments