Create dialog overlay that doesn't steal focus
#1
I'm trying to create a very simple score ticker display for my live scores service and have 2 questions:

Question 1:

If I create a simple xml file:
Code:
<window id="1141" type="dialog">
  <allowoverlay>yes</allowoverlay>
  <visible>Skin.HasSetting(ticker)</visible>
...etc... etc...
and then trigger its visibility by toggling the relevant skin setting then the ticker displays correctly while still allowing me to navigate the screens below. (Also, if I used "ActivateWindow(1141)" then the dialog would steal the focus so that's not really any good for me.)

However, I would like to include the ticker with the service, so adding a file to the skin folder isn't an option.

So the (very simple) question is, how can I recreate the same effect while including the xml file in my addon? The dialog needs to remain active until the setting is toggled again.

Question 2:

A related question: what's the best way to pass text to the dialog? I currently use "Skin.String" but don't know if this is best practice or not. The text needs to be updated regularly so this seems to work fairly well.

The only issue I've encountered is trying to pass text with a comma in it as the script thinks the comma delimits the string. I'm currently running the command as follows:
Code:
xbmc.executebuiltin(u"skin.setstring(tickertext,{})".format(ticker))

Any advice greatly appreciated.
BBC Live Football Scores: Football scores notifications service.
script.squeezeinfo: shows what's playing on your Logitech Media Server
Reply
#2
I'm still struggling with this. Using the WindowXMLDialog class lets me show the window from the Python script (which is a good start for me as I've not used WindowXML before) however it does steal the focus. The conditional visibility line in the XML file is ignored - although I'm not really surprised by this.

I've tried to activate another window immediately after displaying the dialog but that doesn't seem to work either.

Here's the code I've been using:
Code:
from time import sleep

import xbmc
import xbmcgui
import xbmcaddon

__addon__ = xbmcaddon.Addon()

class MyTicker(xbmcgui.WindowXMLDialog):
    def __init__(self,strXMLname, strFallbackPath, strDefaultName, forceFallback):
        # Changing the three varibles passed won't change, anything
        # Doing strXMLname = "bah.xml" will not change anything.
        # don't put GUI sensitive stuff here (as the xml hasn't been read yet
        # Idea to initialize your variables here
        pass

    def onInit(self):
        # Put your List Populating code/ and GUI startup stuff here
        pass

    def onAction(self, action):
        # Same as normal python Windows.
        pass

    def onClick(self, controlID):
        """
            Notice: onClick not onControl
            Notice: it gives the ID of the control not the control object
        """
        pass

    def onFocus(self, controlID):
        pass

ticker = MyTicker("customTickerDialog.xml", __addon__.getAddonInfo('path'), "Default", "720p")
ticker.show()
xbmc.executebuiltin("XBMC.ActivateWindow(home)")
sleep(5)
ticker.close()
It looks like I'm stuck in the dialog until the sleep expires and the dialog closes.

Does anyone have any ideas?
BBC Live Football Scores: Football scores notifications service.
script.squeezeinfo: shows what's playing on your Logitech Media Server
Reply
#3
Does anyone know if this is possible? I'm guessing it's not, but I'd love to hear if anyone has any thoughts.
BBC Live Football Scores: Football scores notifications service.
script.squeezeinfo: shows what's playing on your Logitech Media Server
Reply
#4
I would love to help but I find it difficult to understand what you're trying to do, when you want to present the dialog and what you mean by steal focus. Does this dialog include any buttons or listitems?

As for the second question I think .getcontrol + .setLabel is what you're trying to do. Find the id of the control you want to change from python (supose id=20) and setLabel afterwards:

self.getControl(20).setLabel("My Message", 'font14', '0xFFFFFFFF', '0xFFFF3300', '0xFF000000')

As for the sports stuff you probably want to check this:

http://forum.kodi.tv/showthread.php?tid=174789&page=6
Reply
#5
Thanks enen92. Apologies if my original post wasn't clear.

What I'm trying to do is create a ticker (i.e. a small scrolling text display) that is permanently visible regardless of the other active windows. If I create a custom xml file and put it in my skin folder and make the window visible only when a skin setting is set then, when I toggle the setting, the window appears and most importantly pressing controls (e.g. up down etc) still works on the menu screen.

However, if I create the same dialog window via my python script and make it visible then pressing up or down etc has no impact on the underlying menu. My assumption is that this happens because my dialog window has stolen the focus and is therefore receiving the key presses. This is the behaviour I want to change.

The dialog is one text label. No buttons.

Does that make it clearer?

Thanks for the the answer to the second question too.
BBC Live Football Scores: Football scores notifications service.
script.squeezeinfo: shows what's playing on your Logitech Media Server
Reply
#6
Ah I see what you mean now. I had a similar problem with p2p-streams addon because I wanted to show a dialog when the video osd was present and that did not steal focus of the window, which means, being able to use the player controls anyway. The dialog should present information (download/upload rates) that come from the p2p engine/backend.

This is the dialog I'm talking about:

Image

Just like you I tried to start with a .xml window implementation but it revealed to be no go. The window always overlayed the osd buttons. So to be able to make it the way I wanted I had to make the dialog fully in python and do an inheritance of the videoosd dialog (id=12005).

Have a look here:

https://github.com/enen92/P2P-Streams-Ko...1004-L1007

This is the full dialog class:

the init function designs the class, the show function shows the dialog, the hide function hides the dialog and the setinformation sets information to the controllabels that were created on init:

https://github.com/enen92/P2P-Streams-Ko...1004-L1100

I guess this example is simple enough to understand how to solve your problem. In your case you probably need to get the active window id when creating your dialog. This can be done either from the python api or calling the json rpc and parsing the data later.

keep up the good work.
Reply
#7
Ah. Very interesting. So rather than create a new dialog window you just add a new control to the existing one.

Not quite what I had in mind as I would like the user to be able to navigate freely but this is still an improvement on where I was.

Many thanks.
BBC Live Football Scores: Football scores notifications service.
script.squeezeinfo: shows what's playing on your Logitech Media Server
Reply
#8
Something I forgot to mention is that you still need to grab the current active window id before showing the dialog. Assuming you want to do something similar for a service addon you can add this inside your service loop:

Code:
import xbmc,xbmcgui,json

while........

    current_window = xbmc.executeJSONRPC('{"jsonrpc":"2.0","id":1,"method":"GUI.GetProperties","params":{"properties":["currentwindow"]}}')
    window_id = json.loads(current_window)["result"]["currentwindow"]["id"]
    lat123 = OverlayText(window_id)
    try: lat123.show()
    except: pass
    xbmc.sleep(200)

The modified class is:

Code:
class OverlayText(object):
    def __init__(self,windowid):
        self.showing = False
        self.window = xbmcgui.Window(windowid)
        viewport_w, viewport_h = self._get_skin_resolution()
        font_max = 'font13'
        font_min = 'font10'
        origin_x = int(float(viewport_w)/1.3913)
        origin_y = int(float(viewport_h)/8.0)
        window_w = int(float(viewport_w)/3.7647)
        window_h = int(float(viewport_h)/2.5714)
        acelogo_w = int(float(window_w)/8.5)
        acelogo_h = int(float(window_w)/11.0)
        text_lat = int(float(window_w)/15)
        text_w = int(float(window_w)/1.7)
        text_h = int(float(window_h)/14)
        fst_setting = int(float(window_h)/3.5)
        fst_stat_setting = int(float(window_h)/1.4)

        #main window
        self._background = xbmcgui.ControlImage(origin_x, origin_y, window_w, window_h, "")
        self._acestreamlogo = xbmcgui.ControlImage(origin_x + int(float(window_w)/11.3), origin_y + int(float(window_h)/14), acelogo_w, acelogo_h, "")
        self._supseparator = xbmcgui.ControlImage(origin_x, origin_y + int(float(viewport_h)/12.176), window_w-10, 1, "")
        self._botseparator = xbmcgui.ControlImage(origin_x, origin_y + window_h - 30, window_w-10, 1, "")
        self._title = xbmcgui.ControlLabel(origin_x+int(float(window_w)/3.4), origin_y + text_h, window_w - 140, text_h, "teste", font=font_max, textColor='0xFFEB9E17')
        self._total_stats_label = xbmcgui.ControlLabel(origin_x+int(float(window_h)/1.72), origin_y + int(float(window_h)/1.6), int(float(window_w)/1.7), 20, "teste", font=font_min, textColor='0xFFEB9E17')
        #labels
        self._action = xbmcgui.ControlLabel(origin_x + text_lat, origin_y + fst_setting, int(float(text_w)*1.6), text_h, "teste" + '  N/A', font=font_min)
        self._download = xbmcgui.ControlLabel(origin_x + text_lat, origin_y + fst_setting + text_h, int(float(text_w)*1.6), text_h, "teste" + '  N/A', font=font_min)
        self._upload = xbmcgui.ControlLabel(origin_x + text_lat, origin_y + fst_setting + 2*text_h, text_w, text_h, "teste" + '  N/A', font=font_min)
        self._seeds = xbmcgui.ControlLabel(origin_x + text_lat, origin_y + fst_setting + 3*text_h, text_w, text_h, "teste" + '  N/A', font=font_min)
        self._total_download = xbmcgui.ControlLabel(origin_x + text_lat, origin_y + fst_stat_setting, text_w, text_h, "teste" + '  N/A', font=font_min)
        self._total_upload = xbmcgui.ControlLabel(origin_x + text_lat, origin_y + fst_stat_setting + text_h, text_w, text_h, "teste" + '  N/A', font=font_min)
        self._percent_value = xbmcgui.ControlLabel(origin_x+int(float(window_h)/1.05), origin_y + fst_setting, text_w, text_h,'N/A', font=font_min)

    def show(self):
        self.showing=True
        self.window.addControl(self._background)
        self.window.addControl(self._acestreamlogo)
        self.window.addControl(self._supseparator)
        self.window.addControl(self._botseparator)
        self.window.addControl(self._title)
        self.window.addControl(self._action)
        self.window.addControl(self._download)
        self.window.addControl(self._upload)
        self.window.addControl(self._seeds)
        self.window.addControl(self._total_stats_label)
        self.window.addControl(self._total_download)
        self.window.addControl(self._total_upload)
        self.window.addControl(self._percent_value)


    def hide(self):
        self.showing=False
        self.window.removeControl(self._total_download)
        self.window.removeControl(self._total_upload)
        self.window.removeControl(self._percent_value)
        self.window.removeControl(self._title)
        self.window.removeControl(self._action)
        self.window.removeControl(self._download)
        self.window.removeControl(self._upload)
        self.window.removeControl(self._seeds)
        self.window.removeControl(self._total_stats_label)
        self.window.removeControl(self._acestreamlogo)
        self.window.removeControl(self._supseparator)
        self.window.removeControl(self._botseparator)
        self.window.removeControl(self._background)

    def set_information(self,engine_data):
        if self.showing == True:
            self._action.setLabel(str(translate(50001)) + '  ' + engine_data["action"])
            self._percent_value.setLabel(engine_data["percent"])
            self._download.setLabel(str(translate(50002))+ '  ' + engine_data["download"])
            self._upload.setLabel(str(translate(50003)) + '  ' + engine_data["upload"])
            self._seeds.setLabel(str(translate(50004)) + '  ' + engine_data["seeds"])
            self._total_download.setLabel(str(translate(50006)) + '  ' + engine_data["total_download"])
            self._total_upload.setLabel(str(translate(50007)) + '  ' + engine_data["total_upload"])
        else: pass

    def _close(self):
        if self.showing:
            self.hide()
        else:
            pass
        try:
            self.window.clearProperties()
            print("OverlayText window closed")
        except: pass
                
    #Taken from xbmctorrent
    def _get_skin_resolution(self):
        import xml.etree.ElementTree as ET
        skin_path = xbmc.translatePath("special://skin/")
        tree = ET.parse(os.path.join(skin_path, "addon.xml"))
        try: res = tree.findall("./res")[0]
        except: res = tree.findall("./extension/res")[0]
        return int(res.attrib["width"]), int(res.attrib["height"])

This will enable the "dialog" no matter the window id of the current active window. See screenshots below:

Image

Image

Image

If you are willing to follow this route probably a good idea to store the current window in an hidden setting (or something similar) and delete the window if the current active window id differs from the previous one otherwise you'll have a few copies of the same window depending on the window id you're on. This will make browsing kodi slow.

Hope I could help somehow,

Cheers
Reply
#9
Thank you. Extremely helpful.
BBC Live Football Scores: Football scores notifications service.
script.squeezeinfo: shows what's playing on your Logitech Media Server
Reply
#10
Have had some success with this now - thanks to enen92...
Image
Image
I have to activate it for each window but that's fine for now.
BBC Live Football Scores: Football scores notifications service.
script.squeezeinfo: shows what's playing on your Logitech Media Server
Reply
#11
Could you share your code to fork it?

Thanks a lot!!
Reply
#12
All my code is on github. The ticker has taken a backseat for the moment as I'm working on a few core issues.
BBC Live Football Scores: Football scores notifications service.
script.squeezeinfo: shows what's playing on your Logitech Media Server
Reply
#13
I need to show a panel over the DVDPlayer when a film is playing.
The idea is integrate an app like shazam (music recognition) with the film is playing. Recognize the song and show information about it in the panel.

In your understasding, it could be possible?

Thanks again.
Reply
#14
Show an overlay while film is playing? Yes, that should work.

Recognition of music in film? No idea!
BBC Live Football Scores: Football scores notifications service.
script.squeezeinfo: shows what's playing on your Logitech Media Server
Reply
#15
(2015-01-19, 15:05)ysilvela Wrote: The idea is integrate an app like shazam (music recognition) with the film is playing. Recognize the song and show information about it in the panel.

In your understasding, it could be possible
For that please see this other thread with discussion here:

http://forum.kodi.tv/showthread.php?tid=37230

http://acousticbrainz.org

http://acousticbrainz.org/data

Sorry if off-topic, do not mean to high-jack your thread.
Reply

Logout Mark Read Team Forum Stats Members Help
Create dialog overlay that doesn't steal focus0