Ideas to improve GUI - discussion
#1
Currently skinners need to do complex and not always obvious workarounds to achieve some goals and this add unnecessary complexity to skin's xml and therefore slowing down GUI. Those are just ideas and I'd like to start discussion what could be done to ease process of skinning and extend skins potential.

Improving GUI handling

1. Loading XML files:

  1. CGUIWindow::Load could save copy of loaded window to (let's call it) CachedWindows, next time it would just create copy of cached window instead of reading and parsing same .xml again.

    ReloadSkin would clear CachedWindows. Feature could be toggled in AdvancedSettings.

    pros: less I/O operations -> faster UI processing -> better user experience
    cons: memory consumption (don't think would be a problem)

    posible issues: handling conditional includes

2. Extending controls functionality:

  1. Add <onaction action="action" [override="false"]>DoSmth</action> to focusable controls

    Example: on some button control: <onaction action="ACTION_SHOW_INFO">ActivateWindow(movieinformation,ListItem.Property(path_to_file))</onaction> - this could bring info window for movies listed in RecentlyAdded block on home window.

    Override parameter would specify if we call core's handling of action or not
  2. Making static content item to act like focusable control - add onfocus/onunfocus and onaction mentioned above (just idea - didn't think about it too much yet)
  3. Adding Expressions to skin:
    There are situations when skinner create two identical ontrols that differs only by <onfocus>/<onclick>/<label> and <visible> attribute

    Expressions could be something like:
    Code:
    <expressions>
        <expression name="RunRecentlyAdded">
            <value condition="Skin.HasSetting(homepageShowRecentlyAdded)">XBMC.RunScript(script.recentlyadded,limit=4)</value>
            <value>-</value>
        </expression>
    </expressions>

    [...]

    <control type="button">
        <onfocus>$VAR[RunRecentlyAdded]</onfocus>
    </control>

    And for labels:

    Code:
    <expressions>
        <expression name="TodayTemp">
            <value condition="IsEmpty(Window.Property(Day0.HighTemp)) | IsEmpty(Window.Property(Day0.LowTemp))">$INFO[Window.Property(Day1.LowTemp)]$INFO[System.TemperatureUnits] - $INFO[Window.Property(Day1.HighTemp)]$INFO[System.TemperatureUnits]</value>
            <value>$INFO[Window.Property(Current.Temperature)]$INFO[System.TemperatureUnits]</value>
        </expression>
    </expressions>

    [...]

    <control type="label">
        <label>$VAR[TodayTemp]</label>
    </control>

3. Python modules:
  1. xbmcgui - containers:
    • Allow scripts to retrieve, insert, remove, modify items that aren't created by python script

      Possible usage:
      • filtering items on the fly (not only by labels - also genres, years etc)
      • Having letter seperated lists - example:
        Code:
        [A] [American Psycho] [Apocalypse Now] [b] [Batman] [Black Hawk Down] ...
        where [A], could have special layout prepared to stand out from rest of list items
      Those are just examples - such features could be used by 5% of users so adding them into xbmc core would be waste - altering list by scripts would allow of further customisations by skins
  2. Add ContextMenu class to xbmcgui to allow easy way of showing it filled with items defined in python script

4. Builtin functions:

  1. Adding 'Container(id).Select([b]n[,type,behaviour])' builtin function - type could be: filtered, all, id
    • filtered - select nth item from that left after filtering list
    • all - select nth item from all items (if item is filtered out it it would select item based on behaviour parameter (no_action, prev, next, select_0):
      • no_action - no action
      • prev / next - it would select previous / next available item
      • select_0 - would select first item in list
    • id - would select item with id equal to n

    I found basic workaround for this: I used this python script placed in skin's extras dir:
    Code:
    import xbmcgui

    try:
        wnd = xbmcgui.Window(xbmcgui.getCurrentWindowId())
        
        c = len(sys.argv)
        
        id = -1
        item = -1
        
        if ile == 2:
            id = wnd.getFocusId()
        elif ile == 3:
            id = int(sys.argv[1])
        
        if ile > 1:
            item = int(sys.argv[ile - 1])
        
        if id > 0 and item > 0:
            wnd.getControl(id).selectItem(item)
    except:
        pass
And runned by <onfocus>RunScript(special://skin/extras/ContainerSelect.py)</onfocus>

Other ideas (outside of GUI scope)

5. Python modules:
  1. playlist:
    • allow callbacks for onNextItem, onPrevItem and allow overriding GetNextItem, etc

      would make posible to create playlist script for advanced playlist operations: such as "play after current", smart shuffle/random - random could be based on inner rating if user skips song it decrease inner rating of the song - again this could be used just by 5% of users

      alternative idea is to move playlist outside of xbmc core to chose from different playlist engines as addons

Of course I would offer contribution in form of patches if people would be excited about any of this features.

What do You think?
Reply
#2
grajen3,

I would personally be thankful for anything that made smart playlists, smarter. There are currently quite a few shortcomings in the playlist features of XBMC that I hope will be looked at in the future and possibly improved.

Mark
Reply
#3
@mwkurt
I started topic with hopes for detailed discussion - not just 'What could be changed' - let's talk how would You like it to be. What would You like to have changed/added in smartplaylist?

And just sidenote: I'm no XBMC developer, but I really enjoy tinkering inside source code to make my custom xbmc build suit to my needs and desires - That's why I wanted to start discussion about what could be improved and how it could be done.
Reply
#4
Regarding 2c. Something like this would be really nice, I would call it an expression instead of a variable though, that way it would be ok (by definition) to have it allow commands and multiple expressions.

For example:
expression1: XBMC.HasSettings(foo) + strcmp(expression2, Item.Artist)
expression2: somecommand(item.something, item.somethingelse)

I think this is how many skinners almost uses the skin setting but this is a more powerful version of it I agree.

I think many of the cases where the controls share a similar expression they should be grouped though, but I'm sure there exist cases where you do not want that. Especially if grouping will get a caching method (store the rendered output of a group)
If you have problems please read this before posting

Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.

Image

"Well Im gonna download the code and look at it a bit but I'm certainly not a really good C/C++ programer but I'd help as much as I can, I mostly write in C#."
Reply
#5
Sure, "expression" is better name for it. The idea behind is to allow dynamic assigning values based on conditions. Conditional includes are great in skinning but they're assigned once - at window init.

Those are just ideas - and thing about ideas is that they can changed, improved or abandomed.

I really like to hear thoughts on idea #1 from devs, cause other ideas are meant to improve flexibility of skinning and first one would impact on performance.
Reply
#6
Nice initiative.

1a - yup, you've identified the only issue: Conditional includes. We could always cache the (pre-include-resolving) xml file, though I suspect that wouldn't save all that much - maybe a bit on win32 (notoriously slow i/o)? Get rid of conditional includes and you could save the resolved xml or the complete window/control structure. A possible avenue for investigation is to construct a vector<int,bool> of condition,value pairs and compare that before using the saved structure. Ofcourse, getting some decent timing values for the various stages (i/o, include resolving, control creation) should be the first point of call.

One thing that might improve things is moving the xml -> control conversion to be based on the control. In fact, you could probably put the XML resolving directly in the control constructors - afterall, the vast majority of the Set* functions in CGUI*Control* are for creation and are otherwise unused. This is likely to be a significant saving, as you're only looking searching for the appropriate values per control.

2a. Not sure I like the idea, and in most cases it won't actually give what you want (eg your example won't work) as just activating the movie info window with a given path won't do anything. I'm not sure what override would do - perhaps give an example?

2b. This kinda defeats the purpose of using a list container - you'd be better to use a grouplist.

2c. I've mentioned this several times, but it's basically having a <variable> rather than <constant>. These would be evaluated once per frame and then referenced from the various controls in a similar way that infocolor stuff is. We'd probably need to use a variant class for it, or specify the type of the output (the infocolor works by casting to color_t). No need for the $VAR IMO. Take a look at how the infocolor stuff is if you want to look at hacking something up.

topfs2 is referring to the condition portion of the variable rather than the value of the variable I think? Not quite sure how easy it would be to feed variables into the condition side of things. IMO starting with strings (labels, actions etc.) and floats (position, size etc.) would be a reasonable starting point. Many animations could be done in a more consistent manner if the float variables had a way to "change with animation" (everything except rotate basically).

3a. Personally I think this should (if anything) be done at the directory listing layer - after all, you really need it done BEFORE sorting and filtering takes place (and/or to do the sorting/filtering). We have the issue in the new "files in library" view that the retrieval of metadata has to be done before sorting/filtering for instance. I'm not sure of the usage cases you really give. Personally any services like this IMO belong in XBMC itself primarily, though I don't have a problem with it being an extension point. I suspect most uses are rather specific to the listing at hand though.

4. This appears purely a workaround for problems associated with a certain persons patches :p. Again, XBMC should take care of this IMO.

5. Playlists need overhauling in general. I'm hoping that topfs2 and Montellese come up with a great system for jsonrpc that we can then poach. IMO the biggest issue we have is with manual playlist generation - the user doesn't know what the current playlist contains as it's not shown anywhere unless they switch to it. Having the playlist appear on screen as a modal/modeless combination dialog might be a way of alleviating this.

Cheers,
Jonathan
Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.


Image
Reply
#7
I have actually somewhat been playing with the whole info situation since it is a needed step for event based processing / rendering.

The idea I'm evaluating is that infomanager is essentially just a statemachine, it keep tracks of what 'foo' has as a value, the value is a variant for flexibility. Any time anything pushes something which changes the state an event is fired to the windowmanager which relays this out to the controls, any control affected by this state change will trigger an processing event. The processing event can then (as in my gsoc branch) trigger a rendering event.

To make this all somewhat simpler I am evaluating moving the info conditions from the infomanager and into each control, so each control have a boolexpression for its visibility tag. This expression is a class and when you receive the state change event you can send in that event into that expression which returns true if said statechange affected the expression. Each of these expressions have a value, which can only be changed during some statechange. What I am getting to is that expression could could follow any interpreted language really and have functions, variables or other expressions. This expression could be built (as now really) from the xml, and as you said jmarshall that the xml should be in the control I have a feeling it would make it look somewhat prettier Smile

Currently I am working on extending the variant to handle stuff like variant1 + variant2 no matter what types each of these variants are. It would be very easy to extend this so that each skin can store anything in here, since the statemachine is really general. That way a skinner could do $Expression(mine) := $Expression(another) + $INFO(something). Another nice feature of this is that it would be real simple to add functions, strcmp, substring even if $Expression(mine) then foo else bar fi would work. The nice part about expressions is since they are built up by variables and variables can only change during a statechange, strcmp etc only ever needs to be evaluated once, and each control knows when it is time for a reprocess of the info condition.

This is all rather similar to how we do it already but IMO somewhat cleaner, still somewhat unsure how much more memory it may consume. Have a feeling it may be negligible though.
If you have problems please read this before posting

Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.

Image

"Well Im gonna download the code and look at it a bit but I'm certainly not a really good C/C++ programer but I'd help as much as I can, I mostly write in C#."
Reply
#8
This is going somewhat offtopic I guess (maybe we should start another thread targetting dev ideas specifically for infomanager?) but the idea I had was to keep the manager as the holder of the state machine, and the controls register that they hold expressions.

That way notifications of state changes don't need to filter through the control heirarchy (which in some skins can be rather large - 10^3), and instead get sent to the manager which then "simply" looks in it's map for expressions affected by the state change.

The manager then reevaluates those expressions (how this is done might need some thinking, due to potential recursions in dependencies - we don't have that problem with our current stuff) and if changed pushes the notification to just those controls that have registered for them.

This puts the notifications to controls at the expression level (expressions are often shared between controls) - not sure if that's better than at the state_id level or not. Key is to minimize the amount of running through expression lists and control lists.

Note that you'd have to be quite careful with differentiating between notification events and processing events - for example, you don't want your processing events to immediately process notification events (or vice-versa) else you can end up in a nice infinite loop. A simple way to avoid this is having the processing events be handled after all notifications have been performed, and have processing events simply queue up further notifications that aren't executed until some suitable delay (this is where processing once a frame is nice).

Cheers,
Jonathan
Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.


Image
Reply
#9
grajen3 Wrote:@mwkurt
I started topic with hopes for detailed discussion - not just 'What could be changed' - let's talk how would You like it to be. What would You like to have changed/added in smartplaylist?

Hello again,

Sorry I didn't give any specifics. I will now:

I would hope that the behavior of playlists within a playlist could be changed. As it presently stands, the main playlist overrules any rules that were set in the added playlist.

There should be a way to mix episodes and movies into a single playlist.

There should be a few more rules..i.e. sort on rating, sort on date added to the library.

Those are just a few off the top of my head. Not in front of my XBMC computer presently. I see if I can come up with some others.

And while I have your attention, :o), I would like to ask...is there any way of changing the way that XBMC gets the video stream attributes, more specifically, the durationinseconds tag? My understanding is that XBMC will get this information either when the video file starts to play or when the file is included in a playlist that is opened. Shouldn't it get this information when the file is scraped into the library? Would make life much easier for plugin developers.

Thanks,
Mark
Reply
#10
grajen3 Wrote:Improving GUI handling

1. Loading XML files:

  1. CGUIWindow::Load could save copy of loaded window to (let's call it) CachedWindows, next time it would just create copy of cached window instead of reading and parsing same .xml again.

    ReloadSkin would clear CachedWindows. Feature could be toggled in AdvancedSettings.

    pros: less I/O operations -> faster UI processing -> better user experience
    cons: memory consumption (don't think would be a problem)

    posible issues: handling conditional includes

I have to say this is something I have thought about as well, and defiantly excites me. Even a fraction of a second improvement in GUI rendering would be an added benefit.
Reply
#11
jmarshall Wrote:Nice initiative.

1a - yup, you've identified the only issue: Conditional includes. We could always cache the (pre-include-resolving) xml file, though I suspect that wouldn't save all that much - maybe a bit on win32 (notoriously slow i/o)? Get rid of conditional includes and you could save the resolved xml or the complete window/control structure. A possible avenue for investigation is to construct a vector<int,bool> of condition,value pairs and compare that before using the saved structure. Ofcourse, getting some decent timing values for the various stages (i/o, include resolving, control creation) should be the first point of call.

One thing that might improve things is moving the xml -> control conversion to be based on the control. In fact, you could probably put the XML resolving directly in the control constructors - afterall, the vast majority of the Set* functions in CGUI*Control* are for creation and are otherwise unused. This is likely to be a significant saving, as you're only looking searching for the appropriate values per control.
I guess I could start with moving parsing xml to control to control specific classes. Also current engine is searching XMLelement for specified child (by using XMLUtils::GetFloat method). I'm wondering what if we enumarate child XMLelements instead and based on tagname of child elements assign values to appropiate control members?

After that I will take a look at constructing vector<int,bool> conditions -> bool values and comparing it next time window will be created.

Of course I'll start at getting statistics of time needed of execution seperate parts of creating window. I have hunch that caching window for future use will have significant impact on time needed to init window - sometimes when I navigate through xbmc I hear my hard drive starting to spin to load xml file.
Reply
#12
My guess (and it is just a guess) is that there'll basically be no signficant difference between iterating over XML elements or iterating over what the control wants, once you're at the point of just getting what the particular control wants (as number of things the control wants >= number of XML elements typically, once include resolving and defaults are in there).

I'd start by just splitting CGUIControlFactory::Create based on the type for a start - while this will cause some duplicate code at first (put all the common stuff on top ofcourse), you could then consider constructing gui elements directly from XML, which means the baseclasses could take in some of that dupe.

Your plan sounds fine - make sure you try a range of skins (things like Aeon used to contain over a thousand controls in a window - they're probably less now though!) to get a good picture of speed across the board.

Cheers,
Jonathan
Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.


Image
Reply
#13
jmarshall Wrote:My guess (and it is just a guess) is that there'll basically be no signficant difference between iterating over XML elements or iterating over what the control wants, once you're at the point of just getting what the particular control wants (as number of things the control wants >= number of XML elements typically, once include resolving and defaults are in there).
Well I didn't think it through.

jmarshall Wrote:I'd start by just splitting CGUIControlFactory::Create based on the type for a start - while this will cause some duplicate code at first (put all the common stuff on top ofcourse), you could then consider constructing gui elements directly from XML, which means the baseclasses could take in some of that dupe.
I'm in progess of doing it - it's a lot of code shuffling and I have to figure out what properties apply to what controls: splitting controls to focusable / not focusable, what text attributes are needed to what controls, etc.

jmarshall Wrote:Your plan sounds fine - make sure you try a range of skins (things like Aeon used to contain over a thousand controls in a window - they're probably less now though!) to get a good picture of speed across the board.
Did some tests (15 times measured loading of video window - I think this is most important/complex in xbmc and took average value) on these skins:
  • Night
  • Aeon65
  • Alaska Rev
  • Back-row
  • Confluence
  • Elipsis
  • Foundation
  • Shade
  • SLik

Results:
Controls creation is longest in Aeon65 and Elipsis. (both 5 times longer than in confluence)
Include resolving is longest in Night, next are Aeon65 and Shade (Night 18 / Aeon and Shade 17 times longer than in confluence)

Jezz_X's skins (Confluence and SLik) are fastest (except for Foundation - Hitcher's template skin - it's around 20 times faster than Confluence <- this one is really fast ;])


---
edit:

I have another idea to evaluate: currently MultiImage control only accepts directories as container for images - could we add new <textures> element that could hold paths to image files (remote ones too - it would be cached using xbmc cache mechanism)?
Reply
#14
It'd be good if you could list the times in ms (even just for the "fastest" and "slowest") so we know the relative ones.

Regarding MultiImage - the <imagepath> argument can take a single texture or a directory of textures. This is enough IMO.
Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.


Image
Reply
#15
@grajen3

Could you ad PM3.HD to tested skins. I think it's best performing one.
My skins:

Amber
Quartz

Reply

Logout Mark Read Team Forum Stats Members Help
Ideas to improve GUI - discussion0