changed: Currently playing item's highlighting is now handled by the list control...
[xbmc:xbmc-antiquated.git] / guilib / GUIListItemLayout.cpp
1 #include "include.h"\r
2 #include "GUIListItemLayout.h"\r
3 #include "GUIListItem.h"\r
4 #include "GUIControlFactory.h"\r
5 #include "GUIFontManager.h"\r
6 #include "XMLUtils.h"\r
7 #include "../xbmc/utils/GUIInfoManager.h"\r
8 #include "../xbmc/utils/CharsetConverter.h"\r
9 #include "../xbmc/FileItem.h"\r
10 \r
11 CGUIListItemLayout::CListBase::CListBase(float posX, float posY, float width, float height)\r
12 {\r
13   m_posX = posX;\r
14   m_posY = posY;\r
15   m_width = width;\r
16   m_height = height;\r
17 }\r
18 \r
19 CGUIListItemLayout::CListBase::~CListBase()\r
20 {\r
21 }\r
22 \r
23 CGUIListItemLayout::CListLabel::CListLabel(float posX, float posY, float width, float height, const CLabelInfo &label, int info, const CStdString &content)\r
24 : CGUIListItemLayout::CListBase(posX, posY, width, height)\r
25 {\r
26   m_label = label;\r
27   m_info = info;\r
28   m_type = LIST_LABEL;\r
29   g_infoManager.ParseLabel(content, m_multiInfo);\r
30 }\r
31 \r
32 CGUIListItemLayout::CListLabel::~CListLabel()\r
33 {\r
34 }\r
35 \r
36 CGUIListItemLayout::CListTexture::CListTexture(float posX, float posY, float width, float height, const CImage &image)\r
37 : CGUIListItemLayout::CListBase(posX, posY, width, height),\r
38   m_image(0, 0, posX, posY, width, height, image)\r
39 {\r
40   m_type = LIST_TEXTURE;\r
41 }\r
42 \r
43 CGUIListItemLayout::CListTexture::~CListTexture()\r
44 {\r
45   m_image.FreeResources();\r
46 }\r
47 \r
48 CGUIListItemLayout::CListImage::CListImage(float posX, float posY, float width, float height, int info)\r
49 : CGUIListItemLayout::CListTexture(posX, posY, width, height, CImage(""))\r
50 {\r
51   m_info = info;\r
52   m_type = LIST_IMAGE;\r
53   m_image.SetAspectRatio(CGUIImage::ASPECT_RATIO_KEEP);\r
54 }\r
55 \r
56 CGUIListItemLayout::CListImage::~CListImage()\r
57 {\r
58 }\r
59 \r
60 CGUIListItemLayout::CGUIListItemLayout()\r
61 {\r
62   m_width = 0;\r
63   m_height = 0;\r
64   m_focused = false;\r
65   m_invalidated = true;\r
66   m_isPlaying = false;\r
67 }\r
68 \r
69 CGUIListItemLayout::CGUIListItemLayout(const CGUIListItemLayout &from)\r
70 {\r
71   m_width = from.m_width;\r
72   m_height = from.m_height;\r
73   m_focused = from.m_focused;\r
74   // copy across our controls\r
75   for (ciControls it = from.m_controls.begin(); it != from.m_controls.end(); ++it)\r
76   {\r
77     CListBase *item = *it;\r
78     if (item->m_type == CListBase::LIST_LABEL)\r
79       m_controls.push_back(new CListLabel(*(CListLabel *)item));\r
80     else if (item->m_type ==  CListBase::LIST_IMAGE)\r
81       m_controls.push_back(new CListImage(*(CListImage *)item));\r
82     else if (item->m_type ==  CListBase::LIST_TEXTURE)\r
83       m_controls.push_back(new CListTexture(*(CListTexture *)item));\r
84   }\r
85   m_invalidated = true;\r
86   m_isPlaying = false;\r
87 }\r
88 \r
89 CGUIListItemLayout::~CGUIListItemLayout()\r
90 {\r
91   for (iControls it = m_controls.begin(); it != m_controls.end(); ++it)\r
92     delete *it;\r
93 }\r
94 \r
95 float CGUIListItemLayout::Size(ORIENTATION orientation)\r
96 {\r
97   return (orientation == HORIZONTAL) ? m_width : m_height;\r
98 }\r
99 \r
100 void CGUIListItemLayout::Render(CGUIListItem *item)\r
101 {\r
102   if (m_invalidated)\r
103   {\r
104     // check for boolean conditions\r
105     m_isPlaying = g_infoManager.GetItemBool((CFileItem *)item, LISTITEM_ISPLAYING);\r
106 \r
107     for (iControls it = m_controls.begin(); it != m_controls.end(); it++)\r
108       UpdateItem(*it, item);\r
109     // now we have to check our overlapping label pairs\r
110     for (unsigned int i = 0; i < m_controls.size(); i++)\r
111     {\r
112       if (m_controls[i]->m_type == CListBase::LIST_LABEL)\r
113       {\r
114         CListLabel *label1 = (CListLabel *)m_controls[i];\r
115         for (unsigned int j = i + 1; j < m_controls.size(); j++)\r
116         {\r
117           if (m_controls[j]->m_type == CListBase::LIST_LABEL)\r
118           { // ok, now check if they overlap\r
119             CListLabel *label2 = (CListLabel *)m_controls[j];\r
120             if ((label1->m_renderY <= label2->m_renderY + label2->m_renderH*0.5f && label2->m_renderY + label2->m_renderH*0.5f <= label1->m_renderY + label1->m_renderH) ||\r
121                 (label2->m_renderY <= label1->m_renderY + label1->m_renderH*0.5f && label1->m_renderY + label1->m_renderH*0.5f <= label2->m_renderY + label2->m_renderH))\r
122             { // overlap vertically - check horizontal\r
123               CListLabel *left = label1->m_renderX < label2->m_renderX ? label1 : label2;\r
124               CListLabel *right = label1->m_renderX < label2->m_renderX ? label2 : label1;\r
125               if ((left->m_label.align & 3) == 0 && right->m_label.align & XBFONT_RIGHT)\r
126               { // left is aligned left, right is aligned right, and they overlap vertically\r
127                 if (left->m_renderX + left->m_renderW + 10 > right->m_renderX && left->m_renderX + left->m_renderW < right->m_renderX + right->m_renderW)\r
128                 { // overlap, so chop accordingly\r
129                   float chopPoint = (left->m_posX + left->m_width + right->m_posX - right->m_width) * 0.5f;\r
130 // [1       [2...[2  1].|..........1]         2]\r
131 // [1       [2.....[2   |      1]..1]         2]\r
132 // [1       [2..........|.[2   1]..1]         2]\r
133                   if (right->m_renderX > chopPoint)\r
134                     chopPoint = right->m_renderX - 5;\r
135                   else if (left->m_renderX + left->m_renderW < chopPoint)\r
136                     chopPoint = left->m_renderX + left->m_renderW + 5;\r
137                   left->m_renderW = chopPoint - 5 - left->m_renderX;\r
138                   right->m_renderW -= (chopPoint + 5 - right->m_renderX);\r
139                   right->m_renderX = chopPoint + 5;\r
140                 }\r
141               }\r
142             }\r
143           }\r
144         }\r
145       }\r
146     }\r
147     m_invalidated = false;\r
148   }\r
149 \r
150   // and render\r
151   for (iControls it = m_controls.begin(); it != m_controls.end(); it++)\r
152   {\r
153     CListBase *layoutItem = *it;\r
154     if (layoutItem->m_type == CListBase::LIST_LABEL)\r
155       RenderLabel((CListLabel *)layoutItem, item->IsSelected() || m_isPlaying, m_focused);\r
156     else\r
157       ((CListTexture *)layoutItem)->m_image.Render();\r
158   }\r
159 }\r
160 \r
161 void CGUIListItemLayout::UpdateItem(CGUIListItemLayout::CListBase *control, CGUIListItem *item)\r
162 {\r
163   if (control->m_type == CListBase::LIST_IMAGE)\r
164   {\r
165     CListImage *image = (CListImage *)control;\r
166     image->m_image.SetFileName(g_infoManager.GetItemImage((CFileItem *)item, image->m_info));\r
167   }\r
168   else if (control->m_type == CListBase::LIST_LABEL)\r
169   {\r
170     CListLabel *label = (CListLabel *)control;\r
171     if (label->m_info)\r
172       g_charsetConverter.utf8ToUTF16(g_infoManager.GetItemLabel((CFileItem *)item, label->m_info), label->m_text);\r
173     else\r
174       g_charsetConverter.utf8ToUTF16(g_infoManager.GetItemMultiLabel((CFileItem *)item, label->m_multiInfo), label->m_text);\r
175     if (label->m_label.font)\r
176     {\r
177       label->m_label.font->GetTextExtent(label->m_text, &label->m_textW, &label->m_renderH);\r
178       label->m_renderW = min(label->m_textW, label->m_width);\r
179       if (label->m_label.align & XBFONT_CENTER_Y)\r
180         label->m_renderY = label->m_posY + (label->m_height - label->m_renderH) * 0.5f;\r
181       else\r
182         label->m_renderY = label->m_posY;\r
183       if (label->m_label.align & XBFONT_RIGHT)\r
184         label->m_renderX = label->m_posX - label->m_renderW;\r
185       else if (label->m_label.align & XBFONT_CENTER_X)\r
186         label->m_renderX = label->m_posX - label->m_renderW * 0.5f;\r
187       else\r
188         label->m_renderX = label->m_posX;\r
189     }\r
190   }\r
191 }\r
192 \r
193 void CGUIListItemLayout::RenderLabel(CListLabel *label, bool selected, bool scroll)\r
194 {\r
195   if (label->m_label.font && !label->m_text.IsEmpty())\r
196   {\r
197     DWORD color = selected ? label->m_label.selectedColor : label->m_label.textColor;\r
198     if (scroll && label->m_renderW < label->m_textW)\r
199       label->m_label.font->DrawScrollingText(label->m_renderX, label->m_renderY, &color, 1,\r
200                                   label->m_label.shadowColor, label->m_text, label->m_renderW, label->m_scrollInfo);\r
201     else\r
202       label->m_label.font->DrawTextWidth(label->m_renderX, label->m_renderY, label->m_label.angle, color,\r
203                                   label->m_label.shadowColor, label->m_text, label->m_renderW);\r
204   }\r
205 }\r
206 \r
207 void CGUIListItemLayout::ResetScrolling()\r
208 {\r
209   for (iControls it = m_controls.begin(); it != m_controls.end(); it++)\r
210   {\r
211     CListBase *layoutItem = (*it);\r
212     if (layoutItem->m_type == CListBase::LIST_LABEL)\r
213       ((CListLabel *)layoutItem)->m_scrollInfo.Reset();\r
214   }\r
215 }\r
216 \r
217 \r
218 CGUIListItemLayout::CListBase *CGUIListItemLayout::CreateItem(TiXmlElement *child)\r
219 {\r
220   // grab the type...\r
221   CGUIControlFactory factory;\r
222   CStdString type = factory.GetType(child);\r
223   CGUIControl *control = factory.Create(0, NULL, child);\r
224   float posX = 0;\r
225   float posY = 0;\r
226   float width = 10;\r
227   float height = 10;\r
228   CStdString infoString;\r
229   CImage image;\r
230   CLabelInfo label;\r
231   XMLUtils::GetFloat(child, "posx", posX);\r
232   XMLUtils::GetFloat(child, "posy", posY);\r
233   XMLUtils::GetFloat(child, "width", width);\r
234   XMLUtils::GetFloat(child, "height", height);\r
235   XMLUtils::GetString(child, "info", infoString);\r
236   XMLUtils::GetHex(child, "textcolor", label.textColor);\r
237   XMLUtils::GetHex(child, "selectedcolor", label.selectedColor);\r
238   XMLUtils::GetHex(child, "shadowcolor", label.shadowColor);\r
239   CStdString fontName;\r
240   XMLUtils::GetString(child, "font", fontName);\r
241   label.font = g_fontManager.GetFont(fontName);\r
242   int info = g_infoManager.TranslateString(infoString);\r
243   if (info && (info < LISTITEM_START || info > LISTITEM_END))\r
244   {\r
245     CLog::Log(LOGERROR, __FUNCTION__" Invalid item info %s", infoString.c_str());\r
246     return NULL;\r
247   }\r
248   factory.GetTexture(child, "texture", image);\r
249   factory.GetAlignment(child, "align", label.align);\r
250   DWORD alignY = 0;\r
251   if (factory.GetAlignmentY(child, "aligny", alignY))\r
252     label.align |= alignY;\r
253   CStdString content;\r
254   XMLUtils::GetString(child, "label", content);\r
255   if (type == "label")\r
256   { // info label\r
257     return new CListLabel(posX, posY, width, height, label, info, content);\r
258   }\r
259   else if (type == "image")\r
260   {\r
261     if (info)\r
262     { // info image\r
263       return new CListImage(posX, posY, width, height, info);\r
264     }\r
265     else\r
266     { // texture\r
267       return new CListTexture(posX, posY, width, height, image);\r
268     }\r
269   }\r
270   return NULL;\r
271 }\r
272 \r
273 void CGUIListItemLayout::LoadLayout(TiXmlElement *layout, bool focused)\r
274 {\r
275   m_focused = focused;\r
276   layout->Attribute("width", &m_width);\r
277   layout->Attribute("height", &m_height);\r
278   TiXmlElement *child = layout->FirstChildElement("control");\r
279   while (child)\r
280   {\r
281     CListBase *item = CreateItem(child);\r
282     if (item)\r
283       m_controls.push_back(item);\r
284     child = child->NextSiblingElement("control");\r
285   }\r
286 }\r
287 \r
288 //#ifdef PRE_SKIN_VERSION_2_1_COMPATIBILITY\r
289 void CGUIListItemLayout::CreateListControlLayouts(float width, float height, bool focused, const CLabelInfo &labelInfo, const CLabelInfo &labelInfo2, const CImage &texture, float texHeight, float iconWidth, float iconHeight)\r
290 {\r
291   m_width = width;\r
292   m_height = height;\r
293   m_focused = focused;\r
294   CListTexture *tex = new CListTexture(0, 0, width, texHeight, texture);\r
295   m_controls.push_back(tex);\r
296   CListImage *image = new CListImage(8, 0, iconWidth, texHeight, LISTITEM_ICON);\r
297   m_controls.push_back(image);\r
298   float x = iconWidth + labelInfo.offsetX + 10;\r
299   CListLabel *label = new CListLabel(x, labelInfo.offsetY, width - x - 18, height, labelInfo, LISTITEM_LABEL, "");\r
300   m_controls.push_back(label);\r
301   x = labelInfo2.offsetX ? labelInfo2.offsetX : m_width - 16;\r
302   label = new CListLabel(x, labelInfo2.offsetY, x - iconWidth - 20, height, labelInfo2, LISTITEM_LABEL2, "");\r
303   m_controls.push_back(label);\r
304 }\r
305 //#endif