Can I add a control to an existing window (Home)?
#1
Hi, I've been building a skin/script combination that mostly just uses the home window (Home.xml) and occasionally uses a custom dialog. I've been using python scripts to gather data from an internet data source and setting window properties extensively to build lists, control views, and so forth. So far, so good.

Now I'm trying to build a login screen. Currently, the login view is just another custom view of the home window. I added some edit controls and then realized that python cannot read edit controls when they are instantiated from the window's xml files. So I got started on a small python script that runs when the view is selected to add the edit controls, in hopes of being able to read the username and password fields.

So here's my actual question: I see plenty of examples of how to add controls to a custom window that is entirely instantiated and controlled by python:

Code:
class MyClass(xbmcgui.Window):
      self.list = xbmcgui.ControlList(200, 150, 300, 400)
      self.addControl(self.list)

and I see plenty of examples of how to control lists and other attributes of an existing window

Code:
win = xbmcgui.Window(10000)
win.setProperty(mykey,myvalue)
category = win.getProperty(mykey)

But I can't find an answer either way about if it's possible for python to add controls to an existing window.

I've tried this and it doesn't work, because the already instantiated and active window, 'win', doesn't already have an 'inputbox_username' attribute to assign anything to.

Code:
win = xbmcgui.Window(10000)
win.inputbox_username = xbmcgui.ControlEdit(100, 250, 125, 75, 'Status', 'font16')
win.addControl(inputbox_username)
win.setFocus(inputbox_username)

So, I'm guessing that once an xbmcgui window object has been instantiated (such as the Home.xml), then new controls cannot be added to that object. Is that right?

If there is some clever way to add controls to an existing xbmcgui window instance, I would love to hear it. Otherwise, I will probaby just draw a custom transparent dialog over the existing home window to contain and process the edit controls (or some other solution that I don't know about yet ;-)

Thanks!
Reply
#2
I never tried altering* an already existing (and pure c code defined) window, and I don't think that this is a good idea.
But if you want to have custom dialog or window, why not just do it? Wink

You could change (via XML) the current in use skin - or even create your own "mod" - to have a new button or something which calls a script add-on which defines and opens a WindowDialog (or WindowXMLDialog) with all your needed controls (and design/look). In this script you have access to all control's values and can do whatever you want to do.

(*= With "altering" I mean adding additional controls)
My GitHub. My Add-ons:
Image
Reply
#3
Okay, that's what I thought. Just wanted to make sure I wasn't missing something. Thanks sphere!

My transparent dialog with the edit / submit controls has shaped up nicely. The only step I have left is figuring out how to implement the equivalent of <onclick> for the button I made in the dialog, so the button will close the window - thus passing the edit control's contents into my script so I can use the data for the login routine. :-)

If you happen to know how to do that off the top of your head, feel free to let me know. Right now I'm thinking I have to trap the Enter key when it's pressed somehow. Ahh, puzzles...

-Jerimiah
Reply
#4
The edit control is meant for a "live search suggestion like functionality", the window receives the value on every action (e.g. h, he, hel, hell, hello) via its onAction()-method (which you need to override in python). If you want to implement something like a log-in screen you should create a dialog-window (not full screen sized, x and y center positioned) with multiple edit-controls (one with isPassword=True), ignoring the edit-control's input event but reacting on your submit controlbutton selected action. In this case you should read the control's values via control.getText(), do your business logic and finally calling .close() on your modal window.

I don't know your plan, but it should also be said that if you just need a way to get something like username and password from the user, you could also use the add-on settings for the input method (create an add-on with settings.xml). You can simply implement a loop like "get credentials, if credentials empty: show settings dialog, repeat", maybe even in an auto started service add-on.
My GitHub. My Add-ons:
Image
Reply
#5
(2013-09-22, 23:55)jerimiah797 Wrote: O The only step I have left is figuring out how to implement the equivalent of <onclick> for the button I made in the dialog, so the button will close the window - thus passing the edit control's contents into my script so I can use the data for the login routine. :-)

-Jerimiah

onControl method of xbmcgui.Window and xbmcgui.WindowDialog classes catches controls that have been clicked or pressed Enter on. For a button you need to do something like this:

Code:
self.button = xbmcgui.ControlButton(500, 500, 100, 50, 'My Button')
...
def onControl(self, control):
    if control == self.button:
        (do something)
Reply
#6
(2013-09-23, 00:18)Roman_V_M Wrote:
Code:
self.button = xbmcgui.ControlButton(500, 500, 100, 50, 'My Button')
...
def onControl(self, control):
    if control == self.button:
        (do something)

Should be
Code:
self.button = xbmcgui.ControlButton(500, 500, 100, 50, 'My Button')
...
def onClick(self, control):
    if control == self.button:
        (do something)
onControl -> onClick Wink
My GitHub. My Add-ons:
Image
Reply
#7
(2013-09-23, 00:29)sphere Wrote:
(2013-09-23, 00:18)Roman_V_M Wrote:
Code:
self.button = xbmcgui.ControlButton(500, 500, 100, 50, 'My Button')
...
def onControl(self, control):
    if control == self.button:
        (do something)

Should be
Code:
self.button = xbmcgui.ControlButton(500, 500, 100, 50, 'My Button')
...
def onClick(self, control):
    if control == self.button:
        (do something)
onControl -> onClick Wink

onClick does not work, at least in Gotham, while onControl works perfectly both in Frodo and Gotham.
Reply
#8
Great, thanks for the info, guys. I am not running Gotham, but future-proofing seems like a good idea. I'll try on Control with Frodo and see how it works.
Reply
#9
Just wanted to follow up on this topic. Someone PM'd me about what I ended up doing so I figured I would share it with everyone. I ended up moving all my code into a proper addon folder and it's working like a charm.

I used the transparent window to draw a few text controls and display the text input fields I needed for my login screen, which is a regular WindowXML that pretty much just has a background and logo. The transparent dialog is a hybrid of some controls defined in the xml and some controls defined in python. Doing it this way let me put in a while loop that would reset the fields (destroy and then re-open the transparent dialog) if the credentials were wrong. Here's my code.

Login event loop, dialog create/destroy:

Code:
class LoginWin(WinBase):                  #WinBase is a passthrough subclass of WindowXML I made so that I can handle additional custom keyword arguments
    def __init__(self, *args, **kwargs):
        WinBase.__init__(self, *args)
        self.app = kwargs.get('app')
        self.mem = self.app.mem

    def onInit(self):
        print "Starting onInit Loop"
        while not self.app.get_var('logged_in'):
            if self.app.get_var('bad_creds'):
                self.getControl(10).setLabel('Login failed! Try again...')
                print "Set fail label message"
            self.inputwin = InputDialog("input.xml", self.app.__addon_path__, 'Default', '720p')
            self.inputwin.doModal()
            data = self.mem.login_member(self.inputwin.name_txt, self.inputwin.pswd_txt)
            self.app.set_var('logged_in', data['logged_in'])
            self.app.set_var('bad_creds', data['bad_creds'])
            del self.inputwin
            print "Logged_in value: " + str(self.app.get_var('logged_in'))
            print "Bad Creds value: " + str(self.app.get_var('bad_creds'))

        print "Exited the while loop! Calling the del function"
        self.close()

Python portion of the transparent dialog:
Code:
class InputDialog(xbmcgui.WindowXMLDialog):

    def __init__(self, xmlFilename, scriptPath, defaultSkin, defaultRes):
        self.name = xbmcgui.ControlEdit(530, 320, 400, 120, '', 'rhapsody_font16', '0xDD171717', focusTexture="none.png")
        self.pswd = xbmcgui.ControlEdit(530, 320, 400, 120, '', font='rhapsody_font16', textColor='0xDD171717', focusTexture="none.png", isPassword=1)
        self.butn = None
        self.name_txt = ""
        self.pswd_txt = ""

    def onInit(self):
        self.name_select = self.getControl(10)
        self.pswd_select = self.getControl(11)
        self.pswd_select.setVisible(False)
        self.addControl(self.name)
        self.addControl(self.pswd)
        self.butn = self.getControl(22)
        self.name.setPosition(600, 320)
        self.name.setWidth(400)
        self.name.controlDown(self.pswd)
        self.pswd.setPosition(600, 410)
        self.pswd.setWidth(400)
        self.pswd.controlUp(self.name)
        self.pswd.controlDown(self.butn)
        self.butn.controlUp(self.pswd)
        self.setFocus(self.name)


    def onAction(self, action):
        #print str(action.getId())
        #print type(action)
        if action.getId() == 7:                              #Move to next field on Enter, or submit if button is focused
            if self.getFocus() == self.name:
                self.setFocus(self.pswd)
            elif self.getFocus() == self.pswd:
                self.setFocus(self.butn)
            elif self.getFocusId() == 22:            
                self.close()
                self.name_txt = self.name.getText()
                self.pswd_txt = self.pswd.getText()
            else: pass
        elif action.getId() == 18:                         #Tab between fields
            if self.getFocus() == self.name:
                self.setFocus(self.pswd)
            elif self.getFocus() == self.pswd:
                self.setFocus(self.butn)
            elif self.getFocus() == self.butn:
                self.setFocus(self.name)
            else: pass
        else:
            pass

    def onFocus(self, control):                           #Highlight active field / button by turning highlight images on or off
        if control == 3001:
            self.name_select.setVisible(True)
            self.pswd_select.setVisible(False)
        elif control == 3002:
            self.name_select.setVisible(False)
            self.pswd_select.setVisible(True)
        elif control == 22:
            self.name_select.setVisible(False)
            self.pswd_select.setVisible(False)
        else: pass

XML portion of transparent dialog:
Code:
<window type="dialog">
    <controls>
        <control type="group">
            <posx>590</posx>
            <posy>200</posy>
            <control type="label">
                <posx>-30</posx>
                <posy>0</posy>
                <align>left</align>
                <aligny>top</aligny>
                <label>Sign in to start listening</label>
                <font>rhapsody_font45caps_title</font>
                <textcolor>DD171717</textcolor>
                        <!-- darkgrey -->
            </control>
            <control type="label">
                <posx>0</posx>
                <posy>80</posy>
                <label>Username (usually your email address)</label>
                <align>left</align>
                <aligny>top</aligny>
                <font>rhapsody_font16</font>
                <textcolor>DD171717</textcolor>
                        <!-- darkgrey -->
            </control>
            <control type="image">
                <width>420</width>
                <height>40</height>
                <posx>0</posx>
                <posy>120</posy>
                <texture>white.png</texture>
            </control>
            <control type="label">
                <posx>0</posx>
                <posy>170</posy>
                <label>Password</label>
                <align>left</align>
                <aligny>top</aligny>
                <font>rhapsody_font16</font>
                <textcolor>DD171717</textcolor>
                        <!-- darkgrey -->
            </control>
            <control type="image">
                <width>420</width>
                <height>40</height>
                <posx>0</posx>
                <posy>210</posy>
                <texture>white.png</texture>
            </control>
            <control type="image">
                <posx>290</posx>
                <posy>280</posy>
                <width>130</width>
                <height>50</height>
                <texture>white.png</texture>
            </control>
            <control type="image" id="10">
                <description>Highlight for username</description>
                <width>422</width>
                <height>42</height>
                <posx>-1</posx>
                <posy>119</posy>
                <texture border="8">selectoutline.png</texture>
            </control>
            <control type="image" id="11">
                <description>Highlight for password</description>
                <width>422</width>
                <height>42</height>
                <posx>-1</posx>
                <posy>209</posy>
                <texture border="8">selectoutline.png</texture>
            </control>
            <control type="button" id="22">
                <posx>310</posx>
                <posy>280</posy>
                <width>130</width>
                <height>50</height>
                <label>Sign In</label>
                <font>rhapsody_font24_title</font>
                <textcolor>DD171717</textcolor>
                <focusedcolor>DD171717</focusedcolor>
                <texturefocus>none.jpg</texturefocus>
            </control>
            <control type="image" id="12">
                <description>Highlight for submit button</description>
                <visible>Control.HasFocus(22)</visible>
                <posx>288</posx>
                <posy>278</posy>
                <width>134</width>
                <height>54</height>
                <texture border="8">selectoutline.png</texture>
            </control>
        </control>
    </controls>
</window>

Here's the WinBase passsthough class mentioned in the LoginWin class:
Code:
class WinBase(xbmcgui.WindowXML):
    def __init__(self, xmlName, thescriptPath, defaultname, forceFallback):
        #print "I'm the MainWin base dialog class"
        pass

And here's a screenshot of how it looks. For some reason the blue highlight around the active field didn't show up in the screenshot:
Image
Reply

Logout Mark Read Team Forum Stats Members Help
Can I add a control to an existing window (Home)?0