merged: Linuxport revisions 14057-14059
[xbmc:xbmc-antiquated.git] / xbmc / lib / libPython / xbmcmodule / controllist.cpp
1 /*
2  *      Copyright (C) 2005-2008 Team XBMC
3  *      http://www.xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, write to
17  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18  *  http://www.gnu.org/copyleft/gpl.html
19  *
20  */
21  
22 #include "stdafx.h"
23 #include "lib/libPython/python/Python.h"
24 #include "GUIListContainer.h"
25 #include "GUIFontManager.h"
26 #include "control.h"
27 #include "pyutil.h"
28
29 using namespace std;
30
31 #ifndef __GNUC__
32 #pragma code_seg("PY_TEXT")
33 #pragma data_seg("PY_DATA")
34 #pragma bss_seg("PY_BSS")
35 #pragma const_seg("PY_RDATA")
36 #endif
37
38 #ifdef __cplusplus
39 extern "C" {
40 #endif
41
42 namespace PYXBMC
43 {
44   extern PyObject* ControlSpin_New(void);
45
46   PyObject* ControlList_New(PyTypeObject *type, PyObject *args, PyObject *kwds)
47   {
48     static char *keywords[] = {
49       "x", "y", "width", "height", "font",
50       "textColor", "buttonTexture", "buttonFocusTexture",
51       // maintain order of above items for backward compatibility
52       "selectedColor",
53       "imageWidth", "imageHeight",
54       "itemTextXOffset", "itemTextYOffset",
55       "itemHeight", "space", "alignmentY", NULL };//"shadowColor", NULL };
56     ControlList *self;
57     char *cFont = NULL;
58     char *cTextColor = NULL;
59     char *cSelectedColor = NULL;
60     char *cTextureButton = NULL;
61     char *cTextureButtonFocus = NULL;
62     //char* cShadowColor = NULL;
63     self = (ControlList*)type->tp_alloc(type, 0);
64     if (!self) return NULL;
65     new(&self->strFont) string();    
66     new(&self->strTextureButton) string();    
67     new(&self->strTextureButtonFocus) string();
68     new(&self->vecItems) std::vector<PYXBMC::ListItem*>();
69
70     // create a python spin control
71     self->pControlSpin = (ControlSpin*)ControlSpin_New();
72     if (!self->pControlSpin)
73     {
74       Py_DECREF( self );
75       return NULL;
76     }
77
78     // initialize default values
79     self->strFont = "font13";
80     self->dwTextColor = 0xe0f0f0f0;
81     self->dwSelectedColor = 0xffffffff;
82     self->dwImageHeight = 10;
83     self->dwImageWidth = 10;
84     self->dwItemHeight = 27;
85     self->dwSpace = 2;
86     self->dwItemTextXOffset = CONTROL_TEXT_OFFSET_X;
87     self->dwItemTextYOffset = CONTROL_TEXT_OFFSET_Y;
88     self->dwAlignmentY = XBFONT_CENTER_Y;
89     //self->dwShadowColor = NULL;
90
91     if (!PyArg_ParseTupleAndKeywords(
92       args,
93       kwds,
94       "llll|ssssslllllll",//s",
95       keywords,
96       &self->dwPosX,
97       &self->dwPosY,
98       &self->dwWidth,
99       &self->dwHeight,
100       &cFont,
101       &cTextColor,
102       &cTextureButton,
103       &cTextureButtonFocus,
104       &cSelectedColor,
105       &self->dwImageWidth,
106       &self->dwImageHeight,
107       &self->dwItemTextXOffset,
108       &self->dwItemTextYOffset,
109       &self->dwItemHeight,
110       &self->dwSpace,
111       &self->dwAlignmentY//,
112       ))//&cShadowColor))
113     {
114       Py_DECREF( self );
115       return NULL;
116     }
117
118     // set specified values
119     if (cFont) self->strFont = cFont;
120     if (cTextColor)
121     {
122       sscanf( cTextColor, "%lx", &self->dwTextColor );
123     }
124     if (cSelectedColor)
125     {
126       sscanf( cSelectedColor, "%lx", &self->dwSelectedColor );
127     }
128     //if (cShadowColor) sscanf( cShadowColor, "%x", &self->dwShadowColor );
129
130     self->strTextureButton = cTextureButton ? cTextureButton :
131       PyGetDefaultImage("listcontrol", "texturenofocus", "list-nofocus.png");
132     self->strTextureButtonFocus = cTextureButtonFocus ? cTextureButtonFocus :
133       PyGetDefaultImage("listcontrol", "texturefocus", "list-focus.png");
134
135     // default values for spin control
136     self->pControlSpin->dwPosX = self->dwWidth - 35;
137     self->pControlSpin->dwPosY = self->dwHeight - 15;
138
139     return (PyObject*)self;
140   }
141
142   void ControlList_Dealloc(ControlList* self)
143   {
144     // conditionally delete spincontrol
145     Py_XDECREF(self->pControlSpin);
146
147     // delete all ListItem from vector
148     vector<ListItem*>::iterator it = self->vecItems.begin();
149     while (it != self->vecItems.end())
150     {
151       ListItem* pListItem = *it;
152       Py_DECREF(pListItem);
153       ++it;
154     }
155     self->vecItems.clear();
156     self->vecItems.~vector();
157     
158     self->strFont.~string();
159     self->strTextureButton.~string();
160     self->strTextureButtonFocus.~string();
161     
162     self->ob_type->tp_free((PyObject*)self);
163   }
164
165   CGUIControl* ControlList_Create(ControlList* pControl)
166   {
167     CLabelInfo label;
168     label.align = pControl->dwAlignmentY;
169     label.font = g_fontManager.GetFont(pControl->strFont);
170     label.textColor = label.focusedColor = pControl->dwTextColor;
171     //label.shadowColor = pControl->dwShadowColor;
172     label.selectedColor = pControl->dwSelectedColor;
173     label.offsetX = (float)pControl->dwItemTextXOffset;
174     label.offsetY = (float)pControl->dwItemTextYOffset;
175     // Second label should have the same font, alignment, and colours as the first, but
176     // the offsets should be 0.
177     CLabelInfo label2 = label;
178     label2.offsetX = label2.offsetY = 0;
179     label2.align |= XBFONT_RIGHT;
180
181     pControl->pGUIControl = new CGUIListContainer(
182       pControl->iParentId,
183       pControl->iControlId,
184       (float)pControl->dwPosX,
185       (float)pControl->dwPosY,
186       (float)pControl->dwWidth,
187       (float)pControl->dwHeight - pControl->pControlSpin->dwHeight - 5,
188       label, label2,
189       (CStdString)pControl->strTextureButton,
190       (CStdString)pControl->strTextureButtonFocus,
191       (float)pControl->dwItemHeight,
192       (float)pControl->dwImageWidth, (float)pControl->dwImageHeight,
193       (float)pControl->dwSpace, NULL);
194
195     return pControl->pGUIControl;
196   }
197
198   /*
199    * ControlList_AddItem
200    * (string label) / (ListItem)
201    * ListItem is added to vector
202    * For a string we create a new ListItem and add it to the vector
203    */
204 PyDoc_STRVAR(addItem__doc__,
205     "addItem(item) -- Add a new item to this control list.\n"
206     "\n"
207     "item               : string, unicode or ListItem - item to add.\n"
208     "\n"
209     "example:\n"
210     "  - cList.addItem('Reboot XBMC')\n");
211
212   PyObject* ControlList_AddItem(ControlList *self, PyObject *args)
213   {
214     PyObject *pObject;
215     string strText;
216
217     ListItem* pListItem = NULL;
218
219     if (!PyArg_ParseTuple(args, "O", &pObject))  return NULL;
220     if (ListItem_CheckExact(pObject))
221     {
222       // object is a listitem
223       pListItem = (ListItem*)pObject;
224       Py_INCREF(pListItem);
225     }
226     else
227     {
228       // object is probably a text item
229       if (!PyGetUnicodeString(strText, pObject, 1)) return NULL;
230       // object is a unicode string now, create a new ListItem
231       pListItem = ListItem_FromString(strText);
232     }
233
234     // add item to objects vector
235     self->vecItems.push_back(pListItem);
236
237     // create message
238     CGUIMessage msg(GUI_MSG_LABEL_ADD, self->iParentId, self->iControlId, 0, 0, pListItem->item);
239
240     // send message
241     PyGUILock();
242     if (self->pGUIControl) self->pGUIControl->OnMessage(msg);
243     PyGUIUnlock();
244
245     Py_INCREF(Py_None);
246     return Py_None;
247   }
248
249   /*
250   * ControlList_SelectItem(int item)
251   * Select an item by index
252   */
253   PyDoc_STRVAR(selectItem,
254     "selectItem(item) -- Select an item by index number.\n"
255     "\n"
256     "item               : integer - index number of the item to select.\n"
257     "\n"
258     "example:\n"
259     "  - cList.selectItem(12)\n");
260
261   PyObject* ControlList_SelectItem(ControlList *self, PyObject *args)
262   {
263     long itemIndex;
264
265     if (!PyArg_ParseTuple(args, "l", &itemIndex)) return NULL;
266
267     // create message
268     CGUIMessage msg(GUI_MSG_ITEM_SELECT, self->iParentId, self->iControlId, itemIndex);
269
270     // send message
271     PyGUILock();
272     if (self->pGUIControl) self->pGUIControl->OnMessage(msg);
273     PyGUIUnlock();
274
275     Py_INCREF(Py_None);
276     return Py_None;
277   }
278
279   // reset() method
280   PyDoc_STRVAR(reset__doc__,
281     "reset() -- Clear all ListItems in this control list.\n"
282     "\n"
283     "example:\n"
284     "  - cList.reset()\n");
285
286   PyObject* ControlList_Reset(ControlList *self, PyObject *args)
287   {
288     // create message
289     ControlList *pControl = (ControlList*)self;
290     CGUIMessage msg(GUI_MSG_LABEL_RESET, pControl->iParentId, pControl->iControlId);
291
292     // send message
293     PyGUILock();
294     if (pControl->pGUIControl) pControl->pGUIControl->OnMessage(msg);
295     PyGUIUnlock();
296
297     // delete all items from vector
298     // delete all ListItem from vector
299     vector<ListItem*>::iterator it = self->vecItems.begin();
300     while (it != self->vecItems.end())
301     {
302       ListItem* pListItem = *it;
303       Py_DECREF(pListItem);
304       ++it;
305     }
306     self->vecItems.clear();
307
308     Py_INCREF(Py_None);
309     return Py_None;
310   }
311
312   // getSpinControl() method
313   PyDoc_STRVAR(getSpinControl__doc__,
314     "getSpinControl() -- returns the associated ControlSpin object.\n"
315     "\n"
316     "*Note, Not working completely yet -\n"
317     "       After adding this control list to a window it is not possible to change\n"
318     "       the settings of this spin control.\n"
319     "\n"
320     "example:\n"
321     "  - ctl = cList.getSpinControl()\n");
322
323   PyObject* ControlList_GetSpinControl(ControlTextBox *self, PyObject *args)
324   {
325     Py_INCREF(self->pControlSpin);
326     return (PyObject*)self->pControlSpin;
327   }
328
329   // setImageDimensions() method
330   PyDoc_STRVAR(setImageDimensions__doc__,
331     "setImageDimensions(imageWidth, imageHeight) -- Sets the width/height of items icon or thumbnail.\n"
332     "\n"
333     "imageWidth         : [opt] integer - width of items icon or thumbnail.\n"
334     "imageHeight        : [opt] integer - height of items icon or thumbnail.\n"
335     "\n"
336     "example:\n"
337     "  - cList.setImageDimensions(18, 18)\n");
338
339   PyObject* ControlList_SetImageDimensions(ControlList *self, PyObject *args)
340   {
341     if (!PyArg_ParseTuple(args, "ll", &self->dwImageWidth, &self->dwImageHeight))
342     {
343       return NULL;
344     }
345
346     /*
347     PyGUILock();
348     if (self->pGUIControl)
349     {
350       CGUIListControl* pListControl = (CGUIListControl*) self->pGUIControl;
351       pListControl->SetImageDimensions((float)self->dwImageWidth, (float)self->dwImageHeight );
352     }
353     PyGUIUnlock();
354     */
355     Py_INCREF(Py_None);
356     return Py_None;
357   }
358
359   // setItemHeight() method
360   PyDoc_STRVAR(setItemHeight__doc__,
361     "setItemHeight(itemHeight) -- Sets the height of items.\n"
362     "\n"
363     "itemHeight         : integer - height of items.\n"
364     "\n"
365     "example:\n"
366     "  - cList.setItemHeight(25)\n");
367
368   PyObject* ControlList_SetItemHeight(ControlList *self, PyObject *args)
369   {
370     if (!PyArg_ParseTuple(args, "l", &self->dwItemHeight)) return NULL;
371
372     /*
373     PyGUILock();
374     if (self->pGUIControl)
375     {
376       CGUIListControl* pListControl = (CGUIListControl*) self->pGUIControl;
377       pListControl->SetItemHeight((float)self->dwItemHeight);
378     }
379     PyGUIUnlock();
380     */
381     Py_INCREF(Py_None);
382     return Py_None;
383   }
384
385
386   // setPageControlVisible() method
387   PyDoc_STRVAR(setPageControlVisible__doc__,
388     "setPageControlVisible(visible) -- Sets the spin control's visible/hidden state.\n"
389     "\n"
390     "visible            : boolean - True=visible / False=hidden.\n"
391     "\n"
392     "example:\n"
393     "  - cList.setPageControlVisible(True)\n");
394
395   PyObject* ControlList_SetPageControlVisible(ControlList *self, PyObject *args)
396   {
397     bool isOn = true;
398
399     if (!PyArg_ParseTuple(args, "b", &isOn)) return NULL;
400
401     /*
402     PyGUILock();
403     if (self->pGUIControl)
404     {
405       ((CGUIListControl*)self->pGUIControl)->SetPageControlVisible( isOn );
406     }
407     PyGUIUnlock();
408     */
409
410     Py_INCREF(Py_None);
411     return Py_None;
412   }
413
414   // setSpace() method
415   PyDoc_STRVAR(setSpace__doc__,
416     "setSpace(space) -- Set's the space between items.\n"
417     "\n"
418     "space              : [opt] integer - space between items.\n"
419     "\n"
420     "example:\n"
421     "  - cList.setSpace(5)\n");
422
423   PyObject* ControlList_SetSpace(ControlList *self, PyObject *args)
424   {
425     if (!PyArg_ParseTuple(args, "l", &self->dwSpace)) return NULL;
426
427     /*
428     PyGUILock();
429     if (self->pGUIControl)
430     {
431       CGUIListControl* pListControl = (CGUIListControl*) self->pGUIControl;
432       pListControl->SetSpaceBetweenItems((float)self->dwSpace);
433     }
434     PyGUIUnlock();
435     */
436
437     Py_INCREF(Py_None);
438     return Py_None;
439   }
440
441   // getSelectedPosition() method
442   PyDoc_STRVAR(getSelectedPosition__doc__,
443     "getSelectedPosition() -- Returns the position of the selected item as an integer.\n"
444     "\n"
445     "*Note, Returns -1 for empty lists.\n"
446     "\n"
447     "example:\n"
448     "  - pos = cList.getSelectedPosition()\n");
449
450   PyObject* ControlList_GetSelectedPosition(ControlList *self, PyObject *args)
451   {
452     // create message
453     ControlList *pControl = (ControlList*)self;
454     CGUIMessage msg(GUI_MSG_ITEM_SELECTED, pControl->iParentId, pControl->iControlId);
455     long pos = -1;
456
457     // send message
458     PyGUILock();
459     if ((self->vecItems.size() > 0) && pControl->pGUIControl)
460     {
461       pControl->pGUIControl->OnMessage(msg);
462       pos = msg.GetParam1();
463     }
464     PyGUIUnlock();
465
466     return Py_BuildValue("l", pos);
467   }
468
469   // getSelectedItem() method
470   PyDoc_STRVAR(getSelectedItem__doc__,
471     "getSelectedItem() -- Returns the selected item as a ListItem object.\n"
472     "\n"
473     "*Note, Same as getSelectedPosition(), but instead of an integer a ListItem object\n"
474     "       is returned. Returns None for empty lists.\n"
475     "       See windowexample.py on how to use this.\n"
476     "\n"
477     "example:\n"
478     "  - item = cList.getSelectedItem()\n");
479
480   PyObject* ControlList_GetSelectedItem(ControlList *self, PyObject *args)
481   {
482     // create message
483     ControlList *pControl = (ControlList*)self;
484     CGUIMessage msg(GUI_MSG_ITEM_SELECTED, pControl->iParentId, pControl->iControlId);
485     PyObject* pListItem = Py_None;
486
487     // send message
488     PyGUILock();
489     if ((self->vecItems.size() > 0) && pControl->pGUIControl)
490     {
491       pControl->pGUIControl->OnMessage(msg);
492       pListItem = (PyObject*)self->vecItems[msg.GetParam1()];
493     }
494     PyGUIUnlock();
495
496     Py_INCREF(pListItem);
497     return pListItem;
498   }
499
500   // size() method
501   PyDoc_STRVAR(size__doc__,
502     "size() -- Returns the total number of items in this list control as an integer.\n"
503     "\n"
504     "example:\n"
505     "  - cnt = cList.size()\n");
506
507   PyObject* ControlList_Size(ControlList *self)
508   {
509     return Py_BuildValue("l", self->vecItems.size());
510   }
511
512   // getListItem() method
513   PyDoc_STRVAR(getListItem__doc__,
514     "getListItem(index) -- Returns a given ListItem in this List.\n"
515     "\n"
516     "index           : integer - index number of item to return.\n"
517     "\n"
518     "*Note, throws a ValueError if index is out of range.\n"
519     "\n"
520     "example:\n"
521     "  - listitem = cList.getListItem(6)\n");
522
523   PyObject* ControlList_GetListItem(ControlList *self, PyObject *args)
524   {
525     int iPos = -1;
526     if (!PyArg_ParseTuple(args, "i", &iPos)) return NULL;
527
528     if (iPos < 0 || iPos >= (int)self->vecItems.size())
529     {
530       PyErr_SetString(PyExc_ValueError, "Index out of range");
531       return NULL;
532     }
533
534     PyObject* pListItem = (PyObject*)self->vecItems[iPos];
535
536     Py_INCREF(pListItem);
537     return pListItem;
538   }
539
540   // getItemHeight() Method
541         PyDoc_STRVAR(getItemHeight__doc__,
542                 "getItemHeight() -- Returns the control's current item height as an integer.\n"
543                 "\n"
544                 "example:\n"
545                 "  - item_height = self.cList.getItemHeight()\n");
546
547   PyObject* ControlList_GetItemHeight(ControlList *self)
548         {
549                 return Py_BuildValue("l", self->dwItemHeight);
550         }
551
552   // getSpace() Method
553         PyDoc_STRVAR(getSpace__doc__,
554                 "getSpace() -- Returns the control's space between items as an integer.\n"
555                 "\n"
556                 "example:\n"
557                 "  - gap = self.cList.getSpace()\n");
558
559   PyObject* ControlList_GetSpace(ControlList *self)
560         {
561                 return Py_BuildValue("l", self->dwSpace);
562         }
563
564   PyMethodDef ControlList_methods[] = {
565     {"addItem", (PyCFunction)ControlList_AddItem, METH_VARARGS, addItem__doc__},
566     {"selectItem", (PyCFunction)ControlList_SelectItem, METH_VARARGS,  selectItem},
567     {"reset", (PyCFunction)ControlList_Reset, METH_VARARGS, reset__doc__},
568     {"getSpinControl", (PyCFunction)ControlList_GetSpinControl, METH_VARARGS, getSpinControl__doc__},
569     {"getSelectedPosition", (PyCFunction)ControlList_GetSelectedPosition, METH_VARARGS, getSelectedPosition__doc__},
570     {"getSelectedItem", (PyCFunction)ControlList_GetSelectedItem, METH_VARARGS, getSelectedItem__doc__},
571     {"setImageDimensions", (PyCFunction)ControlList_SetImageDimensions, METH_VARARGS, setImageDimensions__doc__},
572     {"setItemHeight", (PyCFunction)ControlList_SetItemHeight, METH_VARARGS, setItemHeight__doc__},
573     {"setSpace", (PyCFunction)ControlList_SetSpace, METH_VARARGS, setSpace__doc__},
574     {"setPageControlVisible", (PyCFunction)ControlList_SetPageControlVisible, METH_VARARGS, setPageControlVisible__doc__},
575     {"size", (PyCFunction)ControlList_Size, METH_VARARGS, size__doc__},
576     {"getItemHeight", (PyCFunction)ControlList_GetItemHeight, METH_VARARGS, getItemHeight__doc__},
577     {"getSpace", (PyCFunction)ControlList_GetSpace, METH_VARARGS, getSpace__doc__},
578     {"getListItem", (PyCFunction)ControlList_GetListItem, METH_VARARGS, getListItem__doc__},
579     {NULL, NULL, 0, NULL}
580   };
581
582   PyDoc_STRVAR(controlList__doc__,
583     "ControlList class.\n"
584     "\n"
585     "ControlList(x, y, width, height[, font, textColor, buttonTexture, buttonFocusTexture,\n"
586     "            selectedColor, imageWidth, imageHeight, itemTextXOffset, itemTextYOffset,\n"
587     "            itemHeight, space, alignmentY])\n"//, shadowColor])\n"
588     "\n"
589     "x                  : integer - x coordinate of control.\n"
590     "y                  : integer - y coordinate of control.\n"
591     "width              : integer - width of control.\n"
592     "height             : integer - height of control.\n"
593     "font               : [opt] string - font used for items label. (e.g. 'font13')\n"
594     "textColor          : [opt] hexstring - color of items label. (e.g. '0xFFFFFFFF')\n"
595     "buttonTexture      : [opt] string - filename for focus texture.\n"
596     "buttonFocusTexture : [opt] string - filename for no focus texture.\n"
597     "selectedColor      : [opt] integer - x offset of label.\n"
598     "imageWidth         : [opt] integer - width of items icon or thumbnail.\n"
599     "imageHeight        : [opt] integer - height of items icon or thumbnail.\n"
600     "itemTextXOffset    : [opt] integer - x offset of items label.\n"
601     "itemTextYOffset    : [opt] integer - y offset of items label.\n"
602     "itemHeight         : [opt] integer - height of items.\n"
603     "space              : [opt] integer - space between items.\n"
604     "alignmentY         : [opt] integer - Y-axis alignment of items label - *Note, see xbfont.h\n"
605     //"shadowColor        : [opt] hexstring - color of items label's shadow. (e.g. '0xFF000000')\n"
606     "\n"
607     "*Note, You can use the above as keywords for arguments and skip certain optional arguments.\n"
608     "       Once you use a keyword, all following arguments require the keyword.\n"
609     "       After you create the control, you need to add it to the window with addControl().\n"
610     "\n"
611     "example:\n"
612     "  - self.cList = xbmcgui.ControlList(100, 250, 200, 250, 'font14', space=5)\n"
613   );
614
615 // Restore code and data sections to normal.
616 #ifndef __GNUC__
617 #pragma code_seg()
618 #pragma data_seg()
619 #pragma bss_seg()
620 #pragma const_seg()
621 #endif
622
623   PyTypeObject ControlList_Type;
624
625   void initControlList_Type()
626   {
627     PyInitializeTypeObject(&ControlList_Type);
628
629     ControlList_Type.tp_name = "xbmcgui.ControlList";
630     ControlList_Type.tp_basicsize = sizeof(ControlList);
631     ControlList_Type.tp_dealloc = (destructor)ControlList_Dealloc;
632     ControlList_Type.tp_compare = 0;
633     ControlList_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE;
634     ControlList_Type.tp_doc = controlList__doc__;
635     ControlList_Type.tp_methods = ControlList_methods;
636     ControlList_Type.tp_base = &Control_Type;
637     ControlList_Type.tp_new = ControlList_New;
638   }
639 }
640
641 #ifdef __cplusplus
642 }
643 #endif