control center update

pull/15/head
DiMartinoXBMC 2016-11-26 11:56:53 +03:00
parent 791481214e
commit 4ff0f33bd2
25 changed files with 26 additions and 814 deletions

View File

@ -8,6 +8,7 @@
<import addon="script.module.torrent2http"/> <import addon="script.module.torrent2http"/>
<import addon="script.module.pyrrent2http"/> <import addon="script.module.pyrrent2http"/>
<import addon="script.module.chardet" /> <import addon="script.module.chardet" />
<import addon="script.module.pyxbmct" version="1.2.0"/>
</requires> </requires>
<extension point="xbmc.python.pluginsource" provides="video" library="default.py"> <extension point="xbmc.python.pluginsource" provides="video" library="default.py">
<provides>video</provides> <provides>video</provides>

View File

@ -24,7 +24,7 @@ import xbmcaddon
import xbmc import xbmc
import xbmcgui import xbmcgui
from functions import getParameters, HistoryDB, Searchers, log from functions import getParameters, HistoryDB, Searchers, log
from resources.pyxbmct.addonwindow import * import pyxbmct
__settings__ = xbmcaddon.Addon(id='plugin.video.torrenter') __settings__ = xbmcaddon.Addon(id='plugin.video.torrenter')
__language__ = __settings__.getLocalizedString __language__ = __settings__.getLocalizedString
@ -39,7 +39,7 @@ if len(sys.argv) > 1:
else: else:
params = {} params = {}
class ControlCenter(AddonDialogWindow): class ControlCenter(pyxbmct.AddonDialogWindow):
def __init__(self, title, addtime=None): def __init__(self, title, addtime=None):
super(ControlCenter, self).__init__(title) super(ControlCenter, self).__init__(title)
@ -57,18 +57,17 @@ class ControlCenter(AddonDialogWindow):
if not providers: if not providers:
self.db.set_providers(addtime, self.dic) self.db.set_providers(addtime, self.dic)
else: else:
for searcher in self.keys: for searcher in self.dic.keys():
self.dic[searcher] = False self.dic[searcher] = False
for searcher in providers: for searcher in providers:
try: try:
if searcher in self.keys: if searcher in self.dic.keys():
self.dic[searcher] = True self.dic[searcher] = True
except: except:
pass log('self.dic[searcher] except')
self.keys = self.dic.keys() self.keys = self.dic.keys()
self.placed, self.button_columns, self.last_column_row = self.place() self.placed, self.button_columns, self.last_column_row = self.place()
#print str((self.placed, self.button_columns, self.last_column_row))
else: else:
self.button_columns=0 self.button_columns=0
@ -78,7 +77,7 @@ class ControlCenter(AddonDialogWindow):
self.set_active_controls() self.set_active_controls()
self.set_navigation() self.set_navigation()
# Connect a key action (Backspace) to close the window. # Connect a key action (Backspace) to close the window.
self.connect(ACTION_NAV_BACK, self.close) self.connect(pyxbmct.ACTION_NAV_BACK, self.close)
def place(self): def place(self):
placed = {} placed = {}
@ -90,7 +89,6 @@ class ControlCenter(AddonDialogWindow):
else: else:
i += 1 i += 1
placed[item] = (j, i) placed[item] = (j, i)
#print item+str((j, i))
return placed, j, i return placed, j, i
def set_info_controls(self): def set_info_controls(self):
@ -103,7 +101,7 @@ class ControlCenter(AddonDialogWindow):
self.radiobutton_top, self.radiobutton_bottom = [None, None, None], [None, None, None] self.radiobutton_top, self.radiobutton_bottom = [None, None, None], [None, None, None]
for searcher in self.keys: for searcher in self.keys:
place = self.placed[searcher] place = self.placed[searcher]
self.radiobutton[searcher] = RadioButton(searcher) self.radiobutton[searcher] = pyxbmct.RadioButton(searcher)
self.placeControl(self.radiobutton[searcher], place[0], place[1]) self.placeControl(self.radiobutton[searcher], place[0], place[1])
self.radiobutton[searcher].setSelected(self.dic[searcher]) self.radiobutton[searcher].setSelected(self.dic[searcher])
self.connect(self.radiobutton[searcher], self.radio_update) self.connect(self.radiobutton[searcher], self.radio_update)
@ -112,32 +110,32 @@ class ControlCenter(AddonDialogWindow):
self.radiobutton_bottom[place[1]] = self.radiobutton[searcher] self.radiobutton_bottom[place[1]] = self.radiobutton[searcher]
# Button # Button
self.button_install = Button(__language__(30415)) self.button_install = pyxbmct.Button(__language__(30415))
self.placeControl(self.button_install, 2 + self.button_columns, 0) self.placeControl(self.button_install, 2 + self.button_columns, 0)
self.connect(self.button_install, self.installSearcher) self.connect(self.button_install, self.installSearcher)
# Button # Button
self.button_openserchset = Button(__language__(30416)) self.button_openserchset = pyxbmct.Button(__language__(30416))
self.placeControl(self.button_openserchset, 2 + self.button_columns, 1) self.placeControl(self.button_openserchset, 2 + self.button_columns, 1)
self.connect(self.button_openserchset, self.openSearcherSettings) self.connect(self.button_openserchset, self.openSearcherSettings)
# Button # Button
self.button_clearstor = Button(__language__(30417)) self.button_clearstor = pyxbmct.Button(__language__(30417))
self.placeControl(self.button_clearstor, 2 + self.button_columns, 2) self.placeControl(self.button_clearstor, 2 + self.button_columns, 2)
self.connect(self.button_clearstor, self.clearStorage) self.connect(self.button_clearstor, self.clearStorage)
# Button # Button
self.button_openset = Button(__language__(30413)) self.button_openset = pyxbmct.Button(__language__(30413))
self.placeControl(self.button_openset, 3 + self.button_columns, 0) self.placeControl(self.button_openset, 3 + self.button_columns, 0)
self.connect(self.button_openset, self.openSettings) self.connect(self.button_openset, self.openSettings)
# Button # Button
self.button_utorrent = Button(__language__(30414)) self.button_utorrent = pyxbmct.Button(__language__(30414))
self.placeControl(self.button_utorrent, 3 + self.button_columns, 1) self.placeControl(self.button_utorrent, 3 + self.button_columns, 1)
self.connect(self.button_utorrent, self.openUtorrent) self.connect(self.button_utorrent, self.openUtorrent)
# Button # Button
self.button_close = Button(__language__(30412)) self.button_close = pyxbmct.Button(__language__(30412))
self.placeControl(self.button_close, 3 + self.button_columns, 2) self.placeControl(self.button_close, 3 + self.button_columns, 2)
self.connect(self.button_close, self.close) self.connect(self.button_close, self.close)
@ -171,8 +169,6 @@ class ControlCenter(AddonDialogWindow):
ser = placed_keys[placed_values.index((place[0], place[1] - 1))] ser = placed_keys[placed_values.index((place[0], place[1] - 1))]
self.radiobutton[searcher].controlLeft(self.radiobutton[ser]) self.radiobutton[searcher].controlLeft(self.radiobutton[ser])
#print str((self.button_columns, self.last_column_row))
#print searcher
if self.more_two_searcher: if self.more_two_searcher:
if place == (self.button_columns, self.last_column_row) and self.last_column_row < 2: if place == (self.button_columns, self.last_column_row) and self.last_column_row < 2:
ser = placed_keys[placed_values.index((place[0] - 1, place[1] + 1))] ser = placed_keys[placed_values.index((place[0] - 1, place[1] + 1))]
@ -247,6 +243,9 @@ class ControlCenter(AddonDialogWindow):
def openSearcherSettings(self): def openSearcherSettings(self):
slist=Searchers().activeExternal() slist=Searchers().activeExternal()
if len(slist)>0: if len(slist)>0:
if len(slist) == 1:
ret = 0
else:
ret = xbmcgui.Dialog().select(__language__(30418), slist) ret = xbmcgui.Dialog().select(__language__(30418), slist)
if ret > -1 and ret < len(slist): if ret > -1 and ret < len(slist):
sid = slist[ret] sid = slist[ret]

View File

@ -917,7 +917,6 @@ class HistoryDB:
self.cur.execute('select providers from history where addtime="' + addtime + '"') self.cur.execute('select providers from history where addtime="' + addtime + '"')
x = self.cur.fetchone() x = self.cur.fetchone()
self._close() self._close()
# print 'get_providers: '+str(x[0].split(',') if x and x[0]!='' else None)
return x[0].split(',') if x and x[0] != '' else None return x[0].split(',') if x and x[0] != '' else None
def set_providers(self, addtime, providers): def set_providers(self, addtime, providers):
@ -934,7 +933,7 @@ class HistoryDB:
self._close() self._close()
def change_providers(self, addtime, searcher): def change_providers(self, addtime, searcher):
self._connect() #self._connect()
providers = self.get_providers(addtime) providers = self.get_providers(addtime)
keys = Searchers().dic().keys() keys = Searchers().dic().keys()
if providers and len(providers) > 0: if providers and len(providers) > 0:
@ -946,8 +945,8 @@ class HistoryDB:
if i not in keys: if i not in keys:
providers.remove(i) providers.remove(i)
self.set_providers(addtime, providers) self.set_providers(addtime, providers)
self.db.commit() #self.db.commit()
self._close() #self._close()
def add(self, url): def add(self, url):
self._connect() self._connect()

View File

@ -82,21 +82,21 @@ class KickAssSo(Content.Content):
return False return False
def get_contentList(self, category, subcategory=None, apps_property=None): def get_contentList(self, category, subcategory=None, apps_property=None):
self.debug = self.log
contentList = [] contentList = []
url = self.get_url(category, subcategory, apps_property) url = self.get_url(category, subcategory, apps_property)
response = self.makeRequest(url, headers=self.headers) response = self.makeRequest(url, headers=self.headers)
if None != response and 0 < len(response): if None != response and 0 < len(response):
# print response self.debug(response)
if category: if category:
contentList = self.mode(response) contentList = self.mode(response)
# print str(contentList) self.debug(str(contentList))
return contentList return contentList
def mode(self, response): def mode(self, response):
contentList = [] contentList = []
# print str(result)
num = 51 num = 51
good_forums = ['TV', 'Anime', 'Movies'] good_forums = ['TV', 'Anime', 'Movies']
regex = '''<tr class=".+?" id=.+?</tr>''' regex = '''<tr class=".+?" id=.+?</tr>'''
@ -129,6 +129,7 @@ class KickAssSo(Content.Content):
return contentList return contentList
def get_info(self, url): def get_info(self, url):
self.debug = self.log
movieInfo = {} movieInfo = {}
color = '[COLOR blue]%s:[/COLOR] %s\r\n' color = '[COLOR blue]%s:[/COLOR] %s\r\n'
response = self.makeRequest(url, headers=self.headers) response = self.makeRequest(url, headers=self.headers)
@ -190,7 +191,5 @@ class KickAssSo(Content.Content):
if i == 'IMDb link': if i == 'IMDb link':
movieInfo['kinopoisk'] = 'http://imdb.snick.ru/ratefor/02/tt%s.png' % info.get(i) movieInfo['kinopoisk'] = 'http://imdb.snick.ru/ratefor/02/tt%s.png' % info.get(i)
self.debug(str(movieInfo))
# print str(info)
return movieInfo return movieInfo

View File

@ -1,786 +0,0 @@
# -*- coding: utf-8 -*-
# This is a "local" version of PyXBMCt to be used in standalone addons.
#
# PyXBMCt is a mini-framework for creating XBMC Python addons with arbitrary UI
# made of controls - decendants of xbmcgui.Control class.
# The framework uses image textures from XBMC Confluence skin.
#
# Licence: GPL v.3 http://www.gnu.org/licenses/gpl.html
#
## @package addonwindow
# PyXBMCt framework module
import os
import xbmc
import xbmcgui
# _addon = xbmcaddon.Addon()
_images = os.path.join(os.path.dirname(__file__), 'textures', 'default')
# Text alighnment constants. Mixed variants are obtained by bit OR (|)
ALIGN_LEFT = 0
ALIGN_RIGHT = 1
ALIGN_CENTER_X = 2
ALIGN_CENTER_Y = 4
ALIGN_CENTER = 6
ALIGN_TRUNCATED = 8
ALIGN_JUSTIFY = 10
# XBMC key action codes.
# More codes at https://github.com/xbmc/xbmc/blob/master/xbmc/guilib/Key.h
## ESC action
ACTION_PREVIOUS_MENU = 10
## Backspace action
ACTION_NAV_BACK = 92
## Left arrow key
ACTION_MOVE_LEFT = 1
## Right arrow key
ACTION_MOVE_RIGHT = 2
## Up arrow key
ACTION_MOVE_UP = 3
## Down arrow key
ACTION_MOVE_DOWN = 4
## Mouse wheel up
ACTION_MOUSE_WHEEL_UP = 104
## Mouse wheel down
ACTION_MOUSE_WHEEL_DOWN = 105
## Mouse drag
ACTION_MOUSE_DRAG = 106
## Mouse move
ACTION_MOUSE_MOVE = 107
def _set_textures(textures={}, kwargs={}):
"""Set texture arguments for controls."""
for texture in textures.keys():
try:
kwargs[texture]
except KeyError:
kwargs[texture] = textures[texture]
class AddonWindowError(Exception):
"""Custom exception."""
pass
class Label(xbmcgui.ControlLabel):
"""ControlLabel class.
Parameters:
label: string or unicode - text string.
font: string - font used for label text. (e.g. 'font13')
textColor: hexstring - color of enabled label's label. (e.g. '0xFFFFFFFF')
disabledColor: hexstring - color of disabled label's label. (e.g. '0xFFFF3300')
alignment: integer - alignment of label - *Note, see xbfont.h
hasPath: bool - True=stores a path / False=no path.
angle: integer - angle of control. (+ rotates CCW, - rotates CW)"
Note:
After you create the control, you need to add it to the window with placeControl().
Example:
self.label = Label('Status', angle=45)
"""
def __new__(cls, *args, **kwargs):
return super(Label, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class FadeLabel(xbmcgui.ControlFadeLabel):
"""Control that scrolls label text.
Parameters:
font: string - font used for label text. (e.g. 'font13')
textColor: hexstring - color of fadelabel's labels. (e.g. '0xFFFFFFFF')
_alignment: integer - alignment of label - *Note, see xbfont.h
Note:
After you create the control, you need to add it to the window with placeControl().
Example:
self.fadelabel = FadeLabel(textColor='0xFFFFFFFF')
"""
def __new__(cls, *args, **kwargs):
return super(FadeLabel, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class TextBox(xbmcgui.ControlTextBox):
"""ControlTextBox class.
Parameters:
font: string - font used for text. (e.g. 'font13')
textColor: hexstring - color of textbox's text. (e.g. '0xFFFFFFFF')
Note:
After you create the control, you need to add it to the window with placeControl().
Example:
self.textbox = TextBox(textColor='0xFFFFFFFF')
"""
def __new__(cls, *args, **kwargs):
return super(TextBox, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class Image(xbmcgui.ControlImage):
"""ControlImage class.
Parameters:
filename: string - image filename.
colorKey: hexString - (example, '0xFFFF3300')
aspectRatio: integer - (values 0 = stretch (default), 1 = scale up (crops), 2 = scale down (black bars)
colorDiffuse: hexString - (example, '0xC0FF0000' (red tint)).
Note:
After you create the control, you need to add it to the window with placeControl().
Example:
self.image = Image('d:\images\picture.jpg', aspectRatio=2)
"""
def __new__(cls, *args, **kwargs):
return super(Image, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class Button(xbmcgui.ControlButton):
"""ControlButton class.
Parameters:
label: string or unicode - text string.
focusTexture: string - filename for focus texture.
noFocusTexture: string - filename for no focus texture.
textOffsetX: integer - x offset of label.
textOffsetY: integer - y offset of label.
alignment: integer - alignment of label - *Note, see xbfont.h
font: string - font used for label text. (e.g. 'font13')
textColor: hexstring - color of enabled button's label. (e.g. '0xFFFFFFFF')
disabledColor: hexstring - color of disabled button's label. (e.g. '0xFFFF3300')
angle: integer - angle of control. (+ rotates CCW, - rotates CW)
shadowColor: hexstring - color of button's label's shadow. (e.g. '0xFF000000')
focusedColor: hexstring - color of focused button's label. (e.g. '0xFF00FFFF')
Note:
After you create the control, you need to add it to the window with placeControl().
Example:
self.button = Button('Status', font='font14')
"""
def __new__(cls, *args, **kwargs):
textures = {'focusTexture': os.path.join(_images, 'Button', 'KeyboardKey.png'),
'noFocusTexture': os.path.join(_images, 'Button', 'KeyboardKeyNF.png')}
_set_textures(textures, kwargs)
try:
kwargs['alignment']
except KeyError:
kwargs['alignment'] = ALIGN_CENTER
return super(Button, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class RadioButton(xbmcgui.ControlRadioButton):
"""ControlRadioButton class.
Parameters:
label: string or unicode - text string.
focusTexture: string - filename for focus texture.
noFocusTexture: string - filename for no focus texture.
textOffsetX: integer - x offset of label.
textOffsetY: integer - y offset of label.
_alignment: integer - alignment of label - *Note, see xbfont.h
font: string - font used for label text. (e.g. 'font13')
textColor: hexstring - color of enabled radio button's label. (e.g. '0xFFFFFFFF')
disabledColor: hexstring - color of disabled radio button's label. (e.g. '0xFFFF3300')
angle: integer - angle of control. (+ rotates CCW, - rotates CW)
shadowColor: hexstring - color of radio button's label's shadow. (e.g. '0xFF000000')
focusedColor: hexstring - color of focused radio button's label. (e.g. '0xFF00FFFF')
focusOnTexture: string - filename for radio focused/checked texture.
noFocusOnTexture: string - filename for radio not focused/checked texture.
focusOffTexture: string - filename for radio focused/unchecked texture.
noFocusOffTexture: string - filename for radio not focused/unchecked texture.
Note: To customize RadioButton all 4 abovementioned textures need to be provided.
Note:
After you create the control, you need to add it to the window with placeControl().
Example:
self.radiobutton = RadioButton('Status', font='font14')
"""
def __new__(cls, *args, **kwargs):
if int(xbmc.getInfoLabel('System.BuildVersion')[:2]) >= 13:
textures = {'focusTexture': os.path.join(_images, 'RadioButton', 'MenuItemFO.png'),
'noFocusTexture': os.path.join(_images, 'RadioButton', 'MenuItemNF.png'),
'focusOnTexture': os.path.join(_images, 'RadioButton', 'radiobutton-focus.png'),
'noFocusOnTexture': os.path.join(_images, 'RadioButton', 'radiobutton-focus.png'),
'focusOffTexture': os.path.join(_images, 'RadioButton', 'radiobutton-nofocus.png'),
'noFocusOffTexture': os.path.join(_images, 'RadioButton', 'radiobutton-nofocus.png')}
else: # This is for compatibility with Frodo and earlier versions.
textures = {'focusTexture': os.path.join(_images, 'RadioButton', 'MenuItemFO.png'),
'noFocusTexture': os.path.join(_images, 'RadioButton', 'MenuItemNF.png'),
'TextureRadioFocus': os.path.join(_images, 'RadioButton', 'radiobutton-focus.png'),
'TextureRadioNoFocus': os.path.join(_images, 'RadioButton', 'radiobutton-nofocus.png')}
_set_textures(textures, kwargs)
return super(RadioButton, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class Edit(xbmcgui.ControlEdit):
"""
ControlEdit class.
Edit(label[, font, textColor, disabledColor, alignment, focusTexture, noFocusTexture])
Parameters:
label : string or unicode - text string.
font : [opt] string - font used for label text. (e.g. 'font13')
textColor : [opt] hexstring - color of enabled label's label. (e.g. '0xFFFFFFFF')
disabledColor : [opt] hexstring - color of disabled label's label. (e.g. '0xFFFF3300')
_alignment : [opt] integer - alignment of label - *Note, see xbfont.h
focusTexture : [opt] string - filename for focus texture.
noFocusTexture : [opt] string - filename for no focus texture.
isPassword : [opt] bool - if true, mask text value.
*Note, You can use the above as keywords for arguments and skip certain optional arguments.
Once you use a keyword, all following arguments require the keyword.
After you create the control, you need to add it to the window with palceControl().
example:
- self.edit = Edit('Status')
"""
def __new__(cls, *args, **kwargs):
textures = {'focusTexture': os.path.join(_images, 'Edit', 'button-focus.png'),
'noFocusTexture': os.path.join(_images, 'Edit', 'black-back2.png')}
_set_textures(textures, kwargs)
return super(Edit, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class List(xbmcgui.ControlList):
"""ControlList class.
Parameters:
font: string - font used for items label. (e.g. 'font13')
textColor: hexstring - color of items label. (e.g. '0xFFFFFFFF')
buttonTexture: string - filename for no focus texture.
buttonFocusTexture: string - filename for focus texture.
selectedColor: integer - x offset of label.
_imageWidth: integer - width of items icon or thumbnail.
_imageHeight: integer - height of items icon or thumbnail.
_itemTextXOffset: integer - x offset of items label.
_itemTextYOffset: integer - y offset of items label.
_itemHeight: integer - height of items.
_space: integer - space between items.
_alignmentY: integer - Y-axis alignment of items label - *Note, see xbfont.h
Note:
After you create the control, you need to add it to the window with placeControl().
Example:
self.cList = List('font14', space=5)
"""
def __new__(cls, *args, **kwargs):
textures = {'buttonTexture': os.path.join(_images, 'List', 'MenuItemNF.png'),
'buttonFocusTexture': os.path.join(_images, 'List', 'MenuItemFO.png')}
_set_textures(textures, kwargs)
return super(List, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class Slider(xbmcgui.ControlSlider):
"""ControlSlider class.
Parameters:
textureback: string - image filename.
texture: string - image filename.
texturefocus: string - image filename.
Note:
After you create the control, you need to add it to the window with placeControl().
Example:
self.slider = Slider()
"""
def __new__(cls, *args, **kwargs):
textures = {'textureback': os.path.join(_images, 'Slider', 'osd_slider_bg.png'),
'texture': os.path.join(_images, 'Slider', 'osd_slider_nibNF.png'),
'texturefocus': os.path.join(_images, 'Slider', 'osd_slider_nib.png')}
_set_textures(textures, kwargs)
return super(Slider, cls).__new__(cls, -10, -10, 1, 1, *args, **kwargs)
class _AbstractWindow(object):
"""
Top-level control window.
The control windows serves as a parent widget for other XBMC UI controls
much like Tkinter.Tk or PyQt QWidget class.
This is an abstract class which is not supposed to be instantiated directly
and will raise exeptions.
This class is a basic "skeleton" for a control window.
"""
def __init__(self):
"""Constructor method."""
self.actions_connected = []
self.controls_connected = []
def setGeometry(self, width_, height_, rows_, columns_, pos_x=-1, pos_y=-1):
"""
Set width, height, Grid layout, and coordinates (optional) for a new control window.
Parameters:
width_, height_: widgh and height of the created window.
rows_, columns_: rows and colums of the Grid layout to place controls on.
pos_x, pos_y (optional): coordinates of the top left corner of the window.
If pos_x and pos_y are not privided, the window will be placed
at the center of the screen.
Example:
self.setGeometry(400, 500, 5, 4)
"""
self.width = width_
self.height = height_
self.rows = rows_
self.columns = columns_
if pos_x > 0 and pos_y > 0:
self.x = pos_x
self.y = pos_y
else:
self.x = 640 - self.width / 2
self.y = 360 - self.height / 2
self.setGrid()
def setGrid(self):
"""
Set window grid layout of rows * columns.
This is a helper method not to be called directly.
"""
self.grid_x = self.x
self.grid_y = self.y
self.tile_width = self.width / self.columns
self.tile_height = self.height / self.rows
def placeControl(self, control, row, column, rowspan=1, columnspan=1, pad_x=5, pad_y=5):
"""
Place a control within the window grid layout.
pad_x, pad_y: horisontal and vertical padding for control's
size and aspect adjustments. Negative values can be used
to make a control overlap with grid cells next to it, if necessary.
Raises AddonWindowError if a grid has not yet been set.
Example:
self.placeControl(self.label, 0, 1)
"""
try:
control_x = (self.grid_x + self.tile_width * column) + pad_x
control_y = (self.grid_y + self.tile_height * row) + pad_y
control_width = self.tile_width * columnspan - 2 * pad_x
control_height = self.tile_height * rowspan - 2 * pad_y
except AttributeError:
raise AddonWindowError('Window geometry is not defined! Call setGeometry first.')
control.setPosition(control_x, control_y)
control.setWidth(control_width)
control.setHeight(control_height)
self.addControl(control)
self.setAnimation(control)
def getX(self):
"""Get X coordinate of the top-left corner of the window."""
try:
return self.x
except AttributeError:
raise AddonWindowError('Window geometry is not defined! Call setGeometry first.')
def getY(self):
"""Get Y coordinate of the top-left corner of the window."""
try:
return self.y
except AttributeError:
raise AddonWindowError('Window geometry is not defined! Call setGeometry first.')
def getWindowWidth(self):
"""Get window width."""
try:
return self.width
except AttributeError:
raise AddonWindowError('Window geometry is not defined! Call setGeometry first.')
def getWindowHeight(self):
"""Get window height."""
try:
return self.height
except AttributeError:
raise AddonWindowError('Window geometry is not defined! Call setGeometry first.')
def getRows(self):
"""
Get grid rows count.
Raises AddonWindowError if a grid has not yet been set.
"""
try:
return self.rows
except AttributeError:
raise AddonWindowError('Grid layot is not set! Call setGeometry first.')
def getColumns(self):
"""
Get grid columns count.
Raises AddonWindowError if a grid has not yet been set.
"""
try:
return self.columns
except AttributeError:
raise AddonWindowError('Grid layout is not set! Call setGeometry first.')
def connect(self, event, function):
"""
Connect an event to a function.
An event can be an inctance of a Control object or an integer key action code.
Several basic key action codes are provided by PyXBMCT. More action codes can be found at
https://github.com/xbmc/xbmc/blob/master/xbmc/guilib/Key.h
You can connect the following Controls: Button, RadioButton and List. Other Controls do not
generate any control events when activated so their connections won't work.
To catch Slider events you need to connect the following key actions:
ACTION_MOVE_LEFT, ACTION_MOVE_RIGHT and ACTION_MOUSE_DRAG, and do a check
whether the Slider is focused.
"function" parameter is a function or a method to be executed. Note that you must provide
a function object [without brackets ()], not a function call!
lambda can be used as a function to call another function or method with parameters.
Examples:
self.connect(self.exit_button, self.close)
or
self.connect(ACTION_NAV_BACK, self.close)
"""
try:
self.disconnect(event)
except AddonWindowError:
if type(event) == int:
self.actions_connected.append([event, function])
else:
self.controls_connected.append([event, function])
def connectEventList(self, events, function):
"""
Connect a list of controls/action codes to a function.
See connect docstring for more info.
"""
[self.connect(event, function) for event in events]
def disconnect(self, event):
"""
Disconnect an event from a function.
An event can be an inctance of a Control object or an integer key action code
which has previously been connected to a function or a method.
Raises AddonWindowError if an event is not connected to any function.
Examples:
self.disconnect(self.exit_button)
or
self.disconnect(ACTION_NAV_BACK)
"""
if type(event) == int:
event_list = self.actions_connected
else:
event_list = self.controls_connected
for index in range(len(event_list)):
if event == event_list[index][0]:
event_list.pop(index)
break
else:
raise AddonWindowError('The action or control %s is not connected!' % event)
def disconnectEventList(self, events):
"""
Disconnect a list of controls/action codes from functions.
See disconnect docstring for more info.
Raises AddonWindowError if at least one event in the list
is not connected to any function.
"""
[self.disconnect(event) for event in events]
def executeConnected(self, event, connected_list):
"""
Execute a connected event (an action or a control).
This is a helper method not to be called directly.
"""
for item in connected_list:
if event == item[0]:
item[1]()
break
def setAnimation(self, control):
"""
This method is called to set animation properties for all controls
added to the current addon window instance - both built-in controls
(window background, title bar etc.) and controls added with placeControl().
It receives a control instance as the 2nd positional argument (besides self).
By default the method does nothing, i.e. no animation is set for controls.
To add animation you need to re-implement this menthod in your child class.
E.g:
def setAnimation(self, control):
control.setAnimations([('WindowOpen', 'effect=fade start=0 end=100 time=1000',),
('WindowClose', 'effect=fade start=100 end=0 time=1000',)])
"""
pass
class _AddonWindow(_AbstractWindow):
"""
Top-level control window.
The control windows serves as a parent widget for other XBMC UI controls
much like Tkinter.Tk or PyQt QWidget class.
This is an abstract class which is not supposed to be instantiated directly
and will raise exeptions. It is designed to be implemented in a grand-child class
with the second inheritance from xbmcgui.Window or xbmcgui.WindowDialog
in a direct child class.
This class provides a control window with a background and a header
similar to top-level widgets of desktop UI frameworks.
"""
def __init__(self, title=''):
"""Constructor method."""
super(_AddonWindow, self).__init__()
self.setFrame(title)
def setFrame(self, title):
"""
Define paths to images for window background and title background textures,
and set control position adjustment constants used in setGrid.
This is a helper method not to be called directly.
"""
# Window background image
self.background_img = os.path.join(_images, 'AddonWindow', 'ContentPanel.png')
# Background for a window header
self.title_background_img = os.path.join(_images, 'AddonWindow', 'dialogheader.png')
# Horisontal adjustment for a header background if the main background has transparent edges.
self.X_MARGIN = 5
# Vertical adjustment for a header background if the main background has transparent edges
self.Y_MARGIN = 5
# Header position adjustment if the main backround has visible borders.
self.Y_SHIFT = 4
# The height of a window header (for the title background and the title label).
self.HEADER_HEIGHT = 35
self.background = xbmcgui.ControlImage(-10, -10, 1, 1, self.background_img)
self.addControl(self.background)
self.setAnimation(self.background)
self.title_background = xbmcgui.ControlImage(-10, -10, 1, 1, self.title_background_img)
self.addControl(self.title_background)
self.setAnimation(self.title_background)
self.title_bar = xbmcgui.ControlLabel(-10, -10, 1, 1, title, alignment=ALIGN_CENTER, textColor='0xFFFFA500',
font='font13_title')
self.addControl(self.title_bar)
self.setAnimation(self.title_bar)
self.window_close_button = xbmcgui.ControlButton(-100, -100, 60, 30, '',
focusTexture=os.path.join(_images, 'AddonWindow',
'DialogCloseButton-focus.png'),
noFocusTexture=os.path.join(_images, 'AddonWindow',
'DialogCloseButton.png'))
self.addControl(self.window_close_button)
self.setAnimation(self.window_close_button)
def setGeometry(self, width_, height_, rows_, columns_, pos_x=-1, pos_y=-1, padding=5):
"""
Set width, height, Grid layout, and coordinates (optional) for a new control window.
Parameters:
width_, height_: widgh and height of the created window.
rows_, columns_: rows and colums of the Grid layout to place controls on.
pos_x, pos_y (optional): coordinates of the top left corner of the window.
If pos_x and pos_y are not privided, the window will be placed
at the center of the screen.
padding (optional): padding between outer edges of the window and
controls placed on it.
Example:
self.setGeometry(400, 500, 5, 4)
"""
self.win_padding = padding
super(_AddonWindow, self).setGeometry(width_, height_, rows_, columns_, pos_x, pos_y)
self.background.setPosition(self.x, self.y)
self.background.setWidth(self.width)
self.background.setHeight(self.height)
self.title_background.setPosition(self.x + self.X_MARGIN, self.y + self.Y_MARGIN + self.Y_SHIFT)
self.title_background.setWidth(self.width - 2 * self.X_MARGIN)
self.title_background.setHeight(self.HEADER_HEIGHT)
self.title_bar.setPosition(self.x + self.X_MARGIN, self.y + self.Y_MARGIN + self.Y_SHIFT)
self.title_bar.setWidth(self.width - 2 * self.X_MARGIN)
self.title_bar.setHeight(self.HEADER_HEIGHT)
self.window_close_button.setPosition(self.x + self.width - 70, self.y + self.Y_MARGIN + self.Y_SHIFT)
def setGrid(self):
"""
Set window grid layout of rows * columns.
This is a helper method not to be called directly.
"""
self.grid_x = self.x + self.X_MARGIN + self.win_padding
self.grid_y = self.y + self.Y_MARGIN + self.Y_SHIFT + self.HEADER_HEIGHT + self.win_padding
self.tile_width = (self.width - 2 * (self.X_MARGIN + self.win_padding)) / self.columns
self.tile_height = (
self.height - self.HEADER_HEIGHT - self.Y_SHIFT - 2 * (
self.Y_MARGIN + self.win_padding)) / self.rows
def setWindowTitle(self, title=''):
"""
Set window title.
This method must be called AFTER (!!!) setGeometry(),
otherwise there is some werid bug with all skin text labels set to the 'title' text.
Example:
self.setWindowTitle('My Cool Addon')
"""
self.title_bar.setLabel(title)
def getWindowTitle(self):
"""Get window title."""
return self.title_bar.getLabel()
class _FullWindow(xbmcgui.Window):
"""An abstract class to define window event processing."""
def onAction(self, action):
"""
Catch button actions.
Note that, despite being compared to an integer,
action is an instance of xbmcgui.Action class.
"""
if action == ACTION_PREVIOUS_MENU:
self.close()
else:
self.executeConnected(action, self.actions_connected)
def onControl(self, control):
"""
Catch activated controls.
Control is an instance of xbmcgui.Control class.
"""
if control == self.window_close_button:
self.close()
else:
self.executeConnected(control, self.controls_connected)
class _DialogWindow(xbmcgui.WindowDialog):
"""An abstract class to define window event processing."""
def onAction(self, action):
"""
Catch button actions.
Note that, despite being compared to an integer,
action is an instance of xbmcgui.Action class.
"""
if action == ACTION_PREVIOUS_MENU:
self.close()
else:
self.executeConnected(action, self.actions_connected)
def onControl(self, control):
"""
Catch activated controls.
Control is an instance of xbmcgui.Control class.
"""
if control == self.window_close_button:
self.close()
else:
self.executeConnected(control, self.controls_connected)
class BlankFullWindow(_FullWindow, _AbstractWindow):
"""
Addon UI container with a solid background.
This is a blank window with a black background and without any elements whatsoever.
The decoration and layout are completely up to an addon developer.
The window controls can hide under video or music visualization.
Window ID can be passed on class instantiation an agrument
but __init__ must have the 2nd fake argument, e.g:
def __init__(self, *args)
Minimal example:
addon = MyAddon('My Cool Addon')
addon.setGeometry(400, 300, 4, 3)
addon.doModal()
"""
pass
class BlankDialogWindow(_DialogWindow, _AbstractWindow):
"""
Addon UI container with a transparent background.
This is a blank window with a transparent background and without any elements whatsoever.
The decoration and layout are completely up to an addon developer.
The window controls are always displayed over video or music visualization.
Minimal example:
addon = MyAddon('My Cool Addon')
addon.setGeometry(400, 300, 4, 3)
addon.doModal()
"""
pass
class AddonFullWindow(_FullWindow, _AddonWindow):
"""
Addon UI container with a solid background.
Control window is displayed on top of the main background image - self.main_bg.
Video and music visualization are displayed unhindered.
Window ID can be passed on class instantiation as the 2nd positional agrument
but __init__ must have the 3rd fake argument, e.g:
def __init__(self, title='', *args)
Minimal example:
addon = MyAddon('My Cool Addon')
addon.setGeometry(400, 300, 4, 3)
addon.doModal()
"""
def __new__(cls, title='', *args, **kwargs):
return super(AddonFullWindow, cls).__new__(cls, *args, **kwargs)
def setFrame(self, title):
"""
Set the image for for the fullscreen background.
"""
# Image for the fullscreen background.
self.main_bg_img = os.path.join(_images, 'AddonWindow', 'SKINDEFAULT.jpg')
# Fullscreen background image control.
self.main_bg = xbmcgui.ControlImage(1, 1, 1280, 720, self.main_bg_img)
self.addControl(self.main_bg)
super(AddonFullWindow, self).setFrame(title)
def setBackground(self, image=''):
"""
Set the main bacground to an image file.
image: path to an image file as str.
Example:
self.setBackground('d:\images\bacground.png')
"""
self.main_bg.setImage(image)
class AddonDialogWindow(_DialogWindow, _AddonWindow):
"""
Addon UI container with a transparent background.
Control window is displayed on top of XBMC UI,
including video an music visualization!
Minimal example:
addon = MyAddon('My Cool Addon')
addon.setGeometry(400, 300, 4, 3)
addon.doModal()
"""
pass

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB