Files
addon/platformcode/xbmc_config_menu.py
2020-07-31 18:17:24 +02:00

883 lines
39 KiB
Python

# -*- coding: utf-8 -*-
# ------------------------------------------------------------
# XBMC Config Menu
# ------------------------------------------------------------
from __future__ import division
import sys, os, inspect, xbmcgui, xbmc
PY3 = False
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
from builtins import range
from past.utils import old_div
from core import channeltools, servertools, scrapertools
from platformcode import config, logger, platformtools
from core.support import log, dbg, match
class SettingsWindow(xbmcgui.WindowXMLDialog):
"""
Derived class that allows you to use custom configuration boxes.
This class is derived from xbmcgui.WindowXMLDialog and allows you to create a dialog box with controls of the type:
Radio Button (bool), Text Box (text), List (list) and Information Labels (label).
We can also customize the box by adding a title (title).
Construction method:
SettingWindow(list_controls, dict_values, title, callback, item)
Parameters:
list_controls: (list) List of controls to include in the window, according to the following scheme:
(opcional)list_controls= [
{'id': "nameControl1",
'type': "bool", # bool, text, list, label
'label': "Control 1: type RadioButton",
'color': '0xFFee66CC', # text color in hexadecimal ARGB format
'default': True,
'enabled': True,
'visible': True
},
{'id': "nameControl2",
'type': "text", # bool, text, list, label
'label': "Control 2: type text box",
'color': '0xFFee66CC',
'default': "Valor por defecto",
'hidden': False, # only for type = text Indicates whether to hide the text (for passwords)
'enabled': True,
'visible': True
},
{'id': "nameControl3",
'type': "list", # bool, text, list, label
'label': "Control 3: type List",
'color': '0xFFee66CC',
'default': 0, # Default value index in lvalues
'enabled': True,
'visible': True,
'lvalues':["item1", "item2", "item3", "item4"], # only for type = list
},
{'id': "nameControl4",
'type': "label", # bool, text, list, label
'label': "Control 4: tipo Etiqueta",
'color': '0xFFee66CC',
'enabled': True,
'visible': True
}]
If the controls list is not included, an attempt is made to obtain the json of the channel from which the call is made.
The format of the controls in the json is:
{
...
...
"settings": [
{
"id": "name_control_1",
"type": "bool",
"label": "Control 1: type RadioButton",
"default": false,
"enabled": true,
"visible": true,
"color": "0xFFee66CC"
},
{
"id": "name_control_2",
"type": "text",
"label": "Control 2: type text box",
"default": "Default value",
"hidden": true,
"enabled": true,
"visible": true,
"color": "0xFFee66CC"
},
{
"id": "name_control_3",
"type": "list",
"label": "Control 3: type List",
"default": 0,
"enabled": true,
"visible": true,
"color": "0xFFee66CC",
"lvalues": [
"item1",
"item2",
"item3",
"item4"
]
},
{
"id": "name_control_4",
"type": "label",
"label": "Control 4: tipo Etiqueta",
"enabled": true,
"visible": true,
"color": "0xFFee66CC"
},
]
}
The fields 'label', 'default', 'enabled' and 'lvalues' can be a number preceded by '@'. In which case
it will look for the literal in the string.xml file of the selected language.
The 'enabled' and 'visible' fields support the comparators eq (), gt () and it () and their operation is
described at: http://kodi.wiki/view/Add-on_settings#Different_types
(opcional) dict_values: (dict) Dictionary representing the pair (id: value) of the controls in the list.
If any control in the list is not included in this dictionary, it will be assigned the default value.
dict_values={"nameControl1": False,
"nameControl2": "Esto es un ejemplo"}
(opcional) caption: (str) Configuration window title. It can be located by a number preceded by '@'
(opcional) callback (str) Name of the function, of the channel from which the call is made, which will be
invoked when pressing the accept button in the window. This function will be passed as parameters the
object 'item' and the 'dict_values' dictionary. If this parameter does not exist, the channel is searched for
function called 'cb_validate_config' and if it exists it is used as a callback.
Retorno: If 'callback' is specified or the channel includes 'cb_validate_config' what that function returns will be returned. If not return none
Usage examples:
platformtools.show_channel_settings(): As such, without passing any argument, the window detects which channel the call has been made,
and read the json settings and load the controls, when you click OK, save them again.
return platformtools.show_channel_settings(list_controls=list_controls, dict_values=dict_values, callback='cb', item=item):
This opens the window with the passed controls and the dict_values values, if dict_values is not passed, it loads the default values of the controls,
when you accept, it calls the 'callback' function of the channel from where it was called, passing as parameters, item and dict_values
"""
def start(self, list_controls=None, dict_values=None, caption="", callback=None, item=None, custom_button=None, channelpath=None):
log()
# Media Path
self.mediapath = os.path.join(config.get_runtime_path(), 'resources', 'skins', 'Default', 'media')
# Params
self.list_controls = list_controls
self.values = dict_values
self.caption = caption
self.callback = callback
self.item = item
if isinstance(custom_button, dict):
self.custom_button = {}
self.custom_button["label"] = custom_button.get("label", "")
self.custom_button["function"] = custom_button.get("function", "")
self.custom_button["visible"] = bool(custom_button.get("visible", True))
self.custom_button["close"] = bool(custom_button.get("close", False))
else:
self.custom_button = None
# Load Channel Settings
if not channelpath:
channelpath = inspect.currentframe().f_back.f_back.f_code.co_filename
self.channel = os.path.basename(channelpath).replace(".py", "")
self.ch_type = os.path.basename(os.path.dirname(channelpath))
# If list_controls does not exist, it is removed from the channel json
if not self.list_controls:
# If the channel path is in the "channels" folder, we get the controls and values using chaneltools
if os.path.join(config.get_runtime_path(), "channels") in channelpath or os.path.join(config.get_runtime_path(), "specials") in channelpath:
# The call is made from a channel
self.list_controls, default_values = channeltools.get_channel_controls_settings(self.channel)
self.kwargs = {"channel": self.channel}
self.channelName = channeltools.get_channel_json(self.channel)['name']
# If the channel path is in the "servers" folder, we get the controls and values through servertools
elif os.path.join(config.get_runtime_path(), "servers") in channelpath:
# The call is made from a channel
self.list_controls, default_values = servertools.get_server_controls_settings(self.channel)
self.kwargs = {"server": self.channel}
self.channelName = servertools.get_server_parameters(self.channel)['name']
# Else Exit
else:
return None
# If dict_values are not passed, create a blank dict
if self.values is None:
self.values = {}
# Make title
if self.caption == "":
self.caption = str(config.get_localized_string(30100)) + ' - ' + self.channelName
matches = match(self.caption, patron=r'@(\d+)').matches
if matches:
for m in matches:
self.caption = self.caption.replace('@' + match, config.get_localized_string(int(m)))
# Show Window
self.return_value = None
self.doModal()
return self.return_value
@staticmethod
def set_enabled(c, val):
if c["type"] == "list":
c["control"].setEnabled(val)
c["label"].setEnabled(val)
else:
c["control"].setEnabled(val)
@staticmethod
def set_visible(c, val):
if c["type"] == "list":
c["control"].setVisible(val)
c["label"].setVisible(val)
else:
c["control"].setVisible(val)
def evaluate_conditions(self):
for c in self.list_controls:
c["active"] = self.evaluate(self.list_controls.index(c), c["enabled"])
self.set_enabled(c, c["active"])
c["show"] = self.evaluate(self.list_controls.index(c), c["visible"])
if not c["show"]:
self.set_visible(c, c["show"])
self.visible_controls = [c for c in self.list_controls if c["show"]]
def evaluate(self, index, cond):
import re
ok = False
# If the condition is True or False, there is nothing else to evaluate, that is the value
if isinstance(cond, bool):
return cond
# Get the conditions
conditions = re.compile(r'''(!?eq|!?gt|!?lt)?\s*\(\s*([^, ]+)\s*,\s*["']?([^"'\)]+)["']?\)([+|])?''').findall(cond)
for operator, id, value, next in conditions:
# The id must be a number, otherwise it is not valid and returns False
try:
id = int(id)
except:
return False
# The control to evaluate on has to be within range, otherwise it returns False
if index + id < 0 or index + id >= len(self.list_controls):
return False
else:
# Obtain the value of the control on which it is compared
c = self.list_controls[index + id]
if c["type"] == "bool": control_value = bool(c["control"].isSelected())
if c["type"] == "text": control_value = c["control"].getText()
if c["type"] == "list": control_value = c["label"].getLabel()
if c["type"] == "label": control_value = c["control"].getLabel()
matches = match(self.caption, patron=r'@(\d+)').matches
if matches:
for m in matches:
self.caption = self.caption.replace('@' + match, config.get_localized_string(int(m)))
# Operations lt "less than" and gt "greater than" require comparisons to be numbers, otherwise it returns
# False
if operator in ["lt", "!lt", "gt", "!gt"]:
try:
value = int(value)
except ValueError:
return False
# Operation eq "equal to"
if operator in ["eq", "!eq"]:
# int
try:
value = int(value)
except ValueError:
pass
# bool
if not isinstance(value, int) and value.lower() == "true":
value = True
elif not isinstance(value, int) and value.lower() == "false":
value = False
# Operation eq "equal to"
if operator == "eq":
if control_value == value:
ok = True
else:
ok = False
# Operation !eq "not equal to"
if operator == "!eq":
if not control_value == value:
ok = True
else:
ok = False
# operation "gt" "greater than"
if operator == "gt":
if control_value > value:
ok = True
else:
ok = False
# operation "!gt" "not greater than"
if operator == "!gt":
if not control_value > value:
ok = True
else:
ok = False
# operation "lt" "less than"
if operator == "lt":
if control_value < value:
ok = True
else:
ok = False
# operation "!lt" "not less than"
if operator == "!lt":
if not control_value < value:
ok = True
else:
ok = False
# Next operation, if it is "|" (or) and the result is True, there is no sense to follow, it is True
if next == "|" and ok is True:
break
# Next operation, if it is "+" (and) and the result is False, there is no sense to follow, it is False
if next == "+" and ok is False:
break
return ok
def add_control_label(self, c):
control = xbmcgui.ControlLabel(0, -100, self.controls_width + 20, 40, "", alignment=4, font=self.font, textColor=c["color"])
self.addControl(control)
control.setVisible(False)
control.setLabel(c["label"])
c["control"] = control
def add_control_list(self, c):
control = xbmcgui.ControlButton(0, -100, self.controls_width + 10, self.height_control, c["label"],
os.path.join(self.mediapath, 'Controls', 'MenuItemFO.png'),
os.path.join(self.mediapath, 'Controls', 'MenuItemNF.png'),
10, textColor=c["color"], font=self.font)
label = xbmcgui.ControlLabel(0, -100, self.controls_width, self.height_control, "", font=self.font, textColor=c["color"], alignment= 1 | 4)
self.addControl(control)
self.addControl(label)
control.setVisible(False)
label.setVisible(False)
label.setLabel(c["lvalues"][self.values[c["id"]]])
c["control"] = control
c["label"] = label
def add_control_text(self, c):
if xbmcgui.ControlEdit == ControlEdit:
control = xbmcgui.ControlEdit(0, -100, self.controls_width, self.height_control, c["label"],
os.path.join(self.mediapath, 'Controls', 'MenuItemFO.png'),
os.path.join(self.mediapath, 'Controls', 'MenuItemNF.png'), 0,
textColor=c["color"], font=self.font, isPassword=c["hidden"], window=self)
else:
control = xbmcgui.ControlEdit(0, -100, self.controls_width, self.height_control,
c["label"], self.font, c["color"], '', 1 | 4, isPassword=c["hidden"],
focusTexture=os.path.join(self.mediapath, 'Controls', 'MenuItemFO.png'),
noFocusTexture=os.path.join(self.mediapath, 'Controls', 'MenuItemNF.png'))
self.addControl(control)
control.setVisible(False)
control.setLabel(c["label"])
# frodo fix
s = self.values[c["id"]]
if s is None:
s = ''
control.setText(s)
# control.setText(self.values[c["id"]])
control.setWidth(self.controls_width + 10)
control.setHeight(self.height_control)
c["control"] = control
def add_control_bool(self, c):
# Old versions do not support some textures
if xbmcgui.__version__ in ["1.2", "2.0"]:
control = xbmcgui.ControlRadioButton(0, -100, self.controls_width + 20, self.height_control,
label=c["label"], font=self.font, textColor=c["color"],
focusTexture=os.path.join(self.mediapath, 'Controls', 'MenuItemFO.png'),
noFocusTexture=os.path.join(self.mediapath, 'Controls', 'MenuItemNF.png'))
else:
control = xbmcgui.ControlRadioButton(0, -100, self.controls_width + 20,
self.height_control, label=c["label"], font=self.font,
textColor=c["color"],
focusTexture=os.path.join(self.mediapath, 'Controls', 'MenuItemFO.png'),
noFocusTexture=os.path.join(self.mediapath, 'Controls', 'MenuItemNF.png'),
focusOnTexture=os.path.join(self.mediapath, 'Controls', 'radiobutton-focus.png'),
noFocusOnTexture=os.path.join(self.mediapath, 'Controls', 'radiobutton-focus.png'),
focusOffTexture=os.path.join(self.mediapath, 'Controls', 'radiobutton-nofocus.png'),
noFocusOffTexture=os.path.join(self.mediapath, 'Controls', 'radiobutton-nofocus.png'))
self.addControl(control)
control.setVisible(False)
control.setRadioDimension(x=self.controls_width - (self.height_control - 5), y=0, width=self.height_control - 5, height=self.height_control - 5)
control.setSelected(self.values[c["id"]])
c["control"] = control
def onInit(self):
self.getControl(10004).setEnabled(False)
self.getControl(10005).setEnabled(False)
self.getControl(10006).setEnabled(False)
self.ok_enabled = False
self.default_enabled = False
# Kodi 18 compatibility
if config.get_platform(True)['num_version'] < 18:
if xbmcgui.__version__ == "1.2":
self.setCoordinateResolution(1)
else:
self.setCoordinateResolution(5)
# Title
self.getControl(10002).setLabel(self.caption)
if self.custom_button is not None:
if self.custom_button['visible']:
self.getControl(10006).setLabel(self.custom_button['label'])
else:
self.getControl(10006).setVisible(False)
# self.getControl(10004).setPosition(self.getControl(10004).getPosition()[0], self.getControl(10004).getPosition()[1])
# self.getControl(10005).setPosition(self.getControl(10005).getPosition()[0], self.getControl(10005).getPosition()[1])
# Control Area Dimensions
self.controls_width = self.getControl(10007).getWidth() - 30
self.controls_height = self.getControl(10007).getHeight() -100
self.controls_pos_x = self.getControl(10007).getPosition()[0] + self.getControl(10001).getPosition()[0] + 10
self.controls_pos_y = self.getControl(10007).getPosition()[1] + self.getControl(10001).getPosition()[1]
self.height_control = 60
self.font = "font16"
# In old versions: we create 5 controls, from the contrary when clicking the second control,
# automatically change third party label to "Short By: Name" I don't know why ...
if xbmcgui.ControlEdit == ControlEdit:
for x in range(5):
control = xbmcgui.ControlRadioButton(-500, 0, 0, 0, "")
self.addControl(control)
for c in self.list_controls:
# Skip controls that do not have the appropriate values
if "type" not in c: continue
if "label" not in c: continue
if c["type"] != "label" and "id" not in c: continue
if c["type"] == "list" and "lvalues" not in c: continue
if c["type"] == "list" and not isinstance(c["lvalues"], list): continue
if c["type"] == "list" and not len(c["lvalues"]) > 0: continue
if c["type"] != "label" and len([control.get("id") for control in self.list_controls if c["id"] == control.get("id")]) > 1: continue
# Translation label and lvalues
if c['label'].startswith('@') and unicode(c['label'][1:]).isnumeric(): c['label'] = config.get_localized_string(int(c['label'][1:]))
if c['type'] == 'list':
lvalues = []
for li in c['lvalues']:
if li.startswith('@') and unicode(li[1:]).isnumeric(): lvalues.append(config.get_localized_string(int(li[1:])))
else: lvalues.append(li)
c['lvalues'] = lvalues
# Default values in case the control does not have them
if c["type"] == "bool": default = False
elif c["type"] == "list": default = 0
else: default = "" # label or text
c["default"] = c.get("default", default)
c["color"] = c.get("color", "0xFFFFFFFF")
c["visible"] = c.get("visible", True)
c["enabled"] = c.get("enabled", True)
if c["type"] == "label" and "id" not in c: c["id"] = None
if c["type"] == "text": c["hidden"] = c.get("hidden", False)
# Decide whether to use the default value or the saved value
if c["type"] in ["bool", "text", "list"]:
if c["id"] not in self.values:
if not self.callback: self.values[c["id"]] = config.get_setting(c["id"], **self.kwargs)
else: self.values[c["id"]] = c["default"]
if c["type"] == "bool": self.add_control_bool(c)
elif c["type"] == 'text': self.add_control_text(c)
elif c["type"] == 'list': self.add_control_list(c)
elif c["type"] == 'label': self.add_control_label(c)
self.list_controls = [c for c in self.list_controls if "control" in c]
self.evaluate_conditions()
self.index = -1
self.dispose_controls(0)
self.getControl(100010).setVisible(False)
self.getControl(10004).setEnabled(True)
self.getControl(10005).setEnabled(True)
self.getControl(10006).setEnabled(True)
self.ok_enabled = True
self.default_enabled = True
self.check_default()
self.check_ok(self.values)
def dispose_controls(self, index, focus=False, force=False):
show_controls = old_div(self.controls_height, self.height_control) - 1
visible_count = 0
if focus:
if not index >= self.index or not index <= self.index + show_controls:
if index < self.index: new_index = index
else: new_index = index - show_controls
else:new_index = self.index
else:
if index + show_controls >= len(self.visible_controls): index = len(self.visible_controls) - show_controls - 1
if index < 0: index = 0
new_index = index
if self.index != new_index or force:
for x, c in enumerate(self.visible_controls):
if x < new_index or visible_count > show_controls or not c["show"]:
self.set_visible(c, False)
else:
c["y"] = self.controls_pos_y + visible_count * self.height_control
visible_count += 1
if c["type"] != "list":
if c["type"] == "bool": c["control"].setPosition(self.controls_pos_x, c["y"])
else: c["control"].setPosition(self.controls_pos_x, c["y"])
else:
c["control"].setPosition(self.controls_pos_x, c["y"])
if xbmcgui.__version__ == "1.2": c["label"].setPosition(self.controls_pos_x + self.controls_width - 30, c["y"])
else: c["label"].setPosition(self.controls_pos_x, c["y"])
self.set_visible(c, True)
# Calculate the position and size of the ScrollBar
hidden_controls = len(self.visible_controls) - show_controls - 1
if hidden_controls < 0: hidden_controls = 0
scrollbar_height = self.getControl(10008).getHeight() - (hidden_controls * 3)
scrollbar_y = self.getControl(10008).getPosition()[1] + (new_index * 3)
self.getControl(10009).setPosition(self.getControl(10008).getPosition()[0], scrollbar_y)
self.getControl(10009).setHeight(scrollbar_height)
self.index = new_index
if focus:
self.setFocus(self.visible_controls[index]["control"])
def check_ok(self, dict_values=None):
if not self.callback:
if dict_values:
self.init_values = dict_values.copy()
self.getControl(10004).setEnabled(False)
self.ok_enabled = False
else:
if self.init_values == self.values:
self.getControl(10004).setEnabled(False)
self.ok_enabled = False
else:
self.getControl(10004).setEnabled(True)
self.ok_enabled = True
def check_default(self):
if self.custom_button is None:
def_values = dict([[c["id"], c.get("default")] for c in self.list_controls if not c["type"] == "label"])
if def_values == self.values:
self.getControl(10006).setEnabled(False)
self.default_enabled = False
else:
self.getControl(10006).setEnabled(True)
self.default_enabled = True
def onClick(self, id):
# Default values
if id == 10006:
if self.custom_button is not None:
if self.custom_button["close"]:
self.close()
if '.' in self.callback: package, self.callback = self.callback.rsplit('.', 1)
else: package = '%s.%s' % (self.ch_type, self.channel)
try: cb_channel = __import__(package, None, None, [package])
except ImportError: logger.error('Imposible importar %s' % package)
else:
self.return_value = getattr(cb_channel, self.custom_button['function'])(self.item, self.values)
if not self.custom_button["close"]:
if isinstance(self.return_value, dict) and "label" in self.return_value: self.getControl(10006).setLabel(self.return_value['label'])
for c in self.list_controls:
if c["type"] == "text": c["control"].setText(self.values[c["id"]])
if c["type"] == "bool": c["control"].setSelected(self.values[c["id"]])
if c["type"] == "list": c["label"].setLabel(c["lvalues"][self.values[c["id"]]])
self.evaluate_conditions()
self.dispose_controls(self.index, force=True)
else:
for c in self.list_controls:
if c["type"] == "text":
c["control"].setText(c["default"])
self.values[c["id"]] = c["default"]
if c["type"] == "bool":
c["control"].setSelected(c["default"])
self.values[c["id"]] = c["default"]
if c["type"] == "list":
c["label"].setLabel(c["lvalues"][c["default"]])
self.values[c["id"]] = c["default"]
self.evaluate_conditions()
self.dispose_controls(self.index, force=True)
self.check_default()
self.check_ok()
# Cancel button [X]
if id == 10003 or id == 10005:
self.close()
# OK button
if id == 10004:
self.close()
if self.callback and '.' in self.callback: package, self.callback = self.callback.rsplit('.', 1)
else: package = '%s.%s' % (self.ch_type, self.channel)
cb_channel = None
try: cb_channel = __import__(package, None, None, [package])
except ImportError:logger.error('Impossible to import %s' % package)
if self.callback:
# If there is a callback function we invoke it...
self.return_value = getattr(cb_channel, self.callback)(self.item, self.values)
else:
# if not, we test if there is a 'cb_validate_config' function in the channel...
try:
self.return_value = getattr(cb_channel, 'cb_validate_config')(self.item, self.values)
except AttributeError:
# if 'cb_validate_config' doesn't exist either ...
for v in self.values:
config.set_setting(v, self.values[v], **self.kwargs)
# Adjustment controls, if the value of an adjustment is changed, we change the value saved in the value dictionary
# Get the control that has been clicked
# control = self.getControl(id)
# We look it up in the list of controls
for cont in self.list_controls:
if cont['type'] == "list" and cont["control"].getId() == id:
select = platformtools.dialog_select(config.get_localized_string(30041), cont["lvalues"], self.values[cont["id"]])
if select >= 0:
cont["label"].setLabel(cont["lvalues"][select])
self.values[cont["id"]] = cont["lvalues"].index(cont["label"].getLabel())
# If the control is a "bool", we save the new value True / False
if cont["type"] == "bool" and cont["control"].getId() == id: self.values[cont["id"]] = bool(cont["control"].isSelected())
# If the control is a "text", we save the new value
if cont["type"] == "text" and cont["control"].getId() == id:
# Older versions require opening the keyboard manually
if xbmcgui.ControlEdit == ControlEdit:
keyboard = xbmc.Keyboard(cont["control"].getText(), cont["control"].getLabel(), cont["control"].isPassword)
keyboard.setHiddenInput(cont["control"].isPassword)
keyboard.doModal()
if keyboard.isConfirmed(): cont["control"].setText(keyboard.getText())
self.values[cont["id"]] = cont["control"].getText()
self.evaluate_conditions()
self.dispose_controls(self.index, force=True)
self.check_default()
self.check_ok()
# Older versions require this feature
def onFocus(self, a):
pass
def onAction(self, raw_action):
# Get Focus
focus = self.getFocusId()
action = raw_action.getId()
# On Left
if action == 1:
# if Focus is on close button
if focus == 10003:
self.dispose_controls(0, True)
self.setFocusId(3001)
# if focus is on List
else:
if self.ok_enabled:
self.setFocusId(10004)
else:
self.setFocusId(10005)
# On Right
elif action == 2:
# if Focus is on button
if focus in [10004, 10005, 10006]:
self.dispose_controls(0, True)
self.setFocusId(3001)
# if focus is on List
else:
self.setFocusId(10003)
# On Down
elif action == 4:
# if focus is on List
if focus not in [10004, 10005, 10006]:
try:
focus_control = [self.visible_controls.index(c) for c in self.visible_controls if c["control"].getId() == self.getFocus().getId()][0]
focus_control += 1
except:
focus_control = 0
while not focus_control == len(self.visible_controls) and (self.visible_controls[focus_control]["type"] == "label" or not self.visible_controls[focus_control]["active"]):
focus_control += 1
if focus_control >= len(self.visible_controls):
focus_control = 0
self.setFocusId(3001)
self.dispose_controls(focus_control, True)
# Else navigate on main buttons
elif focus in [10004]:
self.setFocusId(10005)
elif focus in [10005]:
if self.default_enabled: self.setFocusId(10006)
elif self.ok_enabled: self.setFocusId(10004)
elif focus in [10006]:
if self.ok_enabled: self.setFocusId(10004)
else: self.setFocusId(10005)
# On Up
elif action == 3:
# if focus is on List
if focus not in [10003, 10004, 10005, 10006]:
try:
focus_control = \
[self.visible_controls.index(c) for c in self.visible_controls if c["control"].getId() == self.getFocus().getId()][0]
focus_control -= 1
while not focus_control == -1 and (self.visible_controls[focus_control]["type"] == "label" or not
self.visible_controls[focus_control]["active"]):
focus_control -= 1
if focus_control < 0:
focus_control = len(self.visible_controls) - 1
except:
focus_control = 0
self.dispose_controls(focus_control, True)
# Else navigate on main buttons
elif focus in [10004]:
if self.default_enabled: self.setFocusId(10006)
else: self.setFocusId(10005)
elif focus in [10005]:
if self.ok_enabled: self.setFocusId(10004)
elif self.default_enabled: self.setFocusId(10006)
elif focus in [10006]:
self.setFocusId(10005)
# Accion 104: Scroll Down
elif action == 104:
self.dispose_controls(self.index - 1)
# Accion 105: Scroll Up
elif action == 105:
self.dispose_controls(self.index + 1)
# ACTION_PREVIOUS_MENU 10
# ACTION_NAV_BACK 92
elif action in [10, 92]:
self.close()
elif action == 501:
self.xx = int(raw_action.getAmount2())
elif action == 504:
if self.xx > raw_action.getAmount2():
if old_div((self.xx - int(raw_action.getAmount2())), self.height_control):
self.xx -= self.height_control
self.dispose_controls(self.index + 1)
else:
if old_div((int(raw_action.getAmount2()) - self.xx), self.height_control):
self.xx += self.height_control
self.dispose_controls(self.index - 1)
return
class ControlEdit(xbmcgui.ControlButton):
def __new__(cls, *args, **kwargs):
del kwargs["isPassword"]
del kwargs["window"]
args = list(args)
return xbmcgui.ControlButton.__new__(cls, *args, **kwargs)
def __init__(self, *args, **kwargs):
self.isPassword = kwargs["isPassword"]
self.window = kwargs["window"]
self.label = ""
self.text = ""
self.textControl = xbmcgui.ControlLabel(self.getX(), self.getY(), self.getWidth(), self.getHeight(), self.text,
font=kwargs["font"], textColor=kwargs["textColor"], alignment= 4 | 1)
self.window.addControl(self.textControl)
def setLabel(self, val):
self.label = val
xbmcgui.ControlButton.setLabel(self, val)
def getX(self):
return xbmcgui.ControlButton.getPosition(self)[0]
def getY(self):
return xbmcgui.ControlButton.getPosition(self)[1]
def setEnabled(self, e):
xbmcgui.ControlButton.setEnabled(self, e)
self.textControl.setEnabled(e)
def setWidth(self, w):
xbmcgui.ControlButton.setWidth(self, w)
self.textControl.setWidth(old_div(w, 2))
def setHeight(self, w):
xbmcgui.ControlButton.setHeight(self, w)
self.textControl.setHeight(w)
def setPosition(self, x, y):
xbmcgui.ControlButton.setPosition(self, x, y)
if xbmcgui.__version__ == "1.2":
self.textControl.setPosition(x + self.getWidth(), y)
else:
self.textControl.setPosition(x + old_div(self.getWidth(), 2), y)
def setText(self, text):
self.text = text
if self.isPassword:
self.textControl.setLabel("*" * len(self.text))
else:
self.textControl.setLabel(self.text)
def getText(self):
return self.text
if not hasattr(xbmcgui, "ControlEdit"):
xbmcgui.ControlEdit = ControlEdit