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