mattblovell / kodi_panel

Front panel LCD display for Kodi (via JSON-RPC)
MIT License
12 stars 5 forks source link

format_str option with shared element require specific name to work #30

Closed nico1080 closed 3 years ago

nico1080 commented 3 years ago

When using the format_str to display a "special treatment" if the name match the special treatment the format_str will not be used eg:

[shared_element.acodec]
name = "acodec"   # special treatment in audio_screens()
posx = 375
posy = 220
font = "font_tiny"
fill = "color_7S"
format_str = " {acodec} test "

will display the acodec result --> format_str not work

But if I change the name to any info label:

[shared_element.acodec]
name = "VideoPlayer.Title"   # special treatment in audio_screens()
posx = 375
posy = 220
font = "font_tiny"
fill = "color_7S"
format_str = " {acodec} test "

It will display acodec result + test --> format_str works

mattblovell commented 3 years ago

What you describe is the natural consequence of the procedural flow the code must go through following the addition of callback functions (to replace the previous "special treatment"). It really has nothing to do with sharing of elements across layouts.

If the name of the entry matches that for a callback function, then the callback function has full responsibility for what then happens.

If this post explains things adequately, please feel free to close the issue.

mattblovell commented 3 years ago

For concreteness, here's the structure that now exists within text_fields():

    # Check for any defined callback functions.  If an entry
    # exists in the lookup table, invoke the specified function
    # with all of the arguments discussed in earlier comments.

    if field_info["name"] in ELEMENT_CB:
        #  ... invoke ELEMENT_CB function ...

    elif field_info["name"] in STRING_CB:
        # ... invoke STRING_CB function ...

    else:
        if (field_info["name"] in info.keys() and
            info[field_info["name"]] != ""):

            # Use format_str or prefix/suffic approach, in that order
            if field_info.get("format_str", ""):
                display_string = format_InfoLabels(
                    field_info["format_str"], info, screen_mode, layout_name)
            else:
                display_string = (field_info.get("prefix", "") +
                                  info[field_info["name"]] +
                                  field_info.get("suffix", ""))

Only the final else makes use of format_str or prefix and suffix.

mattblovell commented 3 years ago

One change I can make is to change the conditional that is used within that final else above...

Right now, an element's name has to either match some existing InfoLabel key or be the name identifying a callback function to use. That test against the InfoLabel keys could be dropped when a format_str is present. That would permit more generic names for entries within the fields array for every layout.

mattblovell commented 3 years ago

Right now, an element's name has to either match some existing InfoLabel key or be the name identifying a callback function to use.

See if commit b970a648350a20b288f41f56cfb580cc4f911534 helps at all...

Entries within the fields array for a layout that specify a format_str can now have any name, so long as it doesn't collide with an entry in the callback tables. Non-colliding entries with a format_str always get that string evaluated and, if that results in something non-empty, the result gets displayed.

Entries that have a name corresponding to an InfoLabel still get processed only if that InfoLabel is non-empty. (I have plans to add an exclude option for handling things like the "00" ChannelNumber you mentioned in discussions.)

Even with the above change, it is still the case that using a name that matches a callback function leaves that callback function "fully in charge" of what happens next. (For element callbacks that want to draw or render something directly, it made no sense even to attempt using them for string interpolation. For string callbacks, one can now have the field array entry named anything you like and just invoke the string callback via format_str.)

mattblovell commented 3 years ago

Commit 50bce995b2ab3c891df3bc423e78242855bcf74c updates all of the example setup files to explain the available 'name' options for entries in the fields array of each layout, as well as the restriction that exists on the use of format_str.

Here is the new text that starts out the Audio Screens comment block:

#   Entries within the "fields" array generally correspond to text
#   fields, but the introduction of the ELEMENT_CB lookup table (if
#   customized) does permit for additional graphical elements.  Such
#   customization does require a bit of Python programming.
#
#   Note that the available InfoLabels can be augmented via use of
#   the AUDIO_LABELS list (see earlier in this file).
#
#   Each entry must have a 'name' key that corresponds to ONE of
#   the following:
#
#     - Exactly matching one of the InfoLabels retrieved from Kodi.
#       Such entries are only rendered if the corresponding InfoLabel
#       is non-empty.
#
#     - One of the callback functions named in either the ELEMENT_CB
#       table or the STRING_CB table.  That string matching triggers
#       execution of the corresponding callback function.
#
#     - An arbitrary string, not matching an InfoLabel or any callback
#       function names, provided that the entry ALSO specifies a
#       'format_str' key.
#
#   The execution path followed by any of the above naming choices is
#   typically expected to yield a text string to display.  Remaining
#   keys that control the rendering of that text are as follows:

The format_str description now reads:

#      format_str Alternatively, rather than using prefix and suffix,
#                 and if one is NOT triggering a callback function, a
#                 formatting string can be specified.  The string
#                 should contain one or more InfoLabels to substitute,
#                 enclosed within curly braces.  See the status layout
#                 screen text fields for examples.
#
#                 Terms to be substituted can also make use of any
#                 entries defined within the string-manipulation
#                 callback table (see the STRING_CB dictionary in
#                 kodi_panel_display.py)

Hopefully those changes clarify things a little. If not, please respond. I'll close this issue if I don't hear from you in a few days.

mattblovell commented 3 years ago

I realized that I left out the option of using a newly-introduced shared element. So, the "each entry must ..." text is being updated to read

#   Unless making use of a shared element, each entry must have a
#   'name' key that corresponds to ONE of the following:
nico1080 commented 3 years ago

Commit 50bce99 updates all of the example setup files to explain the available 'name' options for entries in the fields array of each layout, as well as the restriction that exists on the use of format_str.

Here is the new text that starts out the Audio Screens comment block:

#   Entries within the "fields" array generally correspond to text
#   fields, but the introduction of the ELEMENT_CB lookup table (if
#   customized) does permit for additional graphical elements.  Such
#   customization does require a bit of Python programming.
#
#   Note that the available InfoLabels can be augmented via use of
#   the AUDIO_LABELS list (see earlier in this file).
#
#   Each entry must have a 'name' key that corresponds to ONE of
#   the following:
#
#     - Exactly matching one of the InfoLabels retrieved from Kodi.
#       Such entries are only rendered if the corresponding InfoLabel
#       is non-empty.
#
#     - One of the callback functions named in either the ELEMENT_CB
#       table or the STRING_CB table.  That string matching triggers
#       execution of the corresponding callback function.
#
#     - An arbitrary string, not matching an InfoLabel or any callback
#       function names, provided that the entry ALSO specifies a
#       'format_str' key.
#
#   The execution path followed by any of the above naming choices is
#   typically expected to yield a text string to display.  Remaining
#   keys that control the rendering of that text are as follows:

The format_str description now reads:

#      format_str Alternatively, rather than using prefix and suffix,
#                 and if one is NOT triggering a callback function, a
#                 formatting string can be specified.  The string
#                 should contain one or more InfoLabels to substitute,
#                 enclosed within curly braces.  See the status layout
#                 screen text fields for examples.
#
#                 Terms to be substituted can also make use of any
#                 entries defined within the string-manipulation
#                 callback table (see the STRING_CB dictionary in
#                 kodi_panel_display.py)

Hopefully those changes clarify things a little. If not, please respond. I'll close this issue if I don't hear from you in a few days.

To be sure to understand: Shared elements don't need a name field if they have a format_str field If a shared element have a name field, matching a callback function it will display the callback function ( format_str , preffix/suffix ignored) like any field

fields within layout (= not Shared elements) need to have a name. depending of the names:

It is a bit difficult to follow of the possibilities :)

mattblovell commented 3 years ago

Shared elements don't need a name field if they have a format_str field

Not quite. The new documentation was meant to provide guidance solely on the contents with a layout's fields array.

The definition of entries within the shared_element table is exactly what an earlier comment block dictates. Shared elements get dropped into a layout table exactly as they are written. So, if a shared element is supposed to be dropped into the fields array for a layout, then that shared element must have a name, because every entry within fields must have a name.

In contrast if the shared element is, say, a progress bar, then no name is needed for that (since the prog entry at the top-level of a layout never needs a name).

(As an aside, there are presently just 3 "top-level" entries possible for a layout:

Everything else is an entry within the fields array. There likely is little need to continue having thumb and prog be top-level entries. They could likely be folded into the fields array as well, but doing so might break existing setup.toml files. There likely aren't that many users at present, but it's nice not to surprise people.)

If a shared element have a name field, matching a callback function it will display the callback function ( format_str , preffix/suffix ignored) like any field

Entries within the fields array always need a name. If that name matches a callback function, then that function is what gets invoked.

Per my first statements above, shared elements might or might not need a name -- it depends upon where the end-user intends on making use of them.

fields within layout (= not Shared elements) need to have a name. depending of the names:

if name match an infolabel (and that infolabel is not empty) it will display prefix/infolabel/suffix+label or format_str+label

Correct.

if name match callback function it will display callback function+label (format_str ignored)

Correct. The label is suppressed if the callback function returns an empty string.

If name match nothing (custom name) it will display format_str+label( prefix/suffix ignored)

Correct.

Design History

Originally, a name had to exactly match an InfoLabel (aside from the hard-coded special treatment names). The resulting string was then exactly that InfoLabel, provided it was non-empty. That was the extent of the original functionality.

Then the prefix and suffix functionality got added. The InfoLabel still had to be non-empty in order for the prefix and suffix to be employed.

Subsequent to that, I figured out how to make format_str work. With format strings, prefix and suffix already get ignored (why use those, when the user can just specify that text as part of the format_str itself).

Even though a format_str could make use of any InfoLabel for substitution, having the entry still carry a name was still useful -- the specified InfoLabel could be checked to see if it was non-empty.

The most recent change to the code just permits an entry that has a format_str to use any name it wants. That might be useful if you have a format_str that contains multiple distinct InfoLabels and always want it rendered.

Summary Attempt

It is a bit difficult to follow of the possibilities :)

I think things can be distilled to the following points:

The main use cases for the fields array are still

  1. InfoLabels or
  2. callback functions.
mattblovell commented 3 years ago

Commit e078b4d4836a600dbc977104879bcb1d4c663d1e has another update to the example setup files.

The documentation now reads:

#   All entries in the "fields" array" MUST have a name (either
#   specified explicitly or inherited from a shared element
#   reference).  The 'name' key corresponds to ONE of the following:
#
#     - An exact match for one of the InfoLabels retrieved from Kodi.
#       The entry is only rendered if the corresponding InfoLabel is
#       non-empty.
#
#     - An exact match for one of the callback functions named in the
#       ELEMENT_CB table or the STRING_CB table.  That match triggers
#       execution of the corresponding callback function.
#
#     - An arbitrary string (not matching an InfoLabel or any callback
#       function names), provided that the entry ALSO specifies a
#       'format_str' key.  The interpolated format_str always gets
#       rendered.
nico1080 commented 3 years ago

Very clear, I am closing this issue as it is just a mis understanding of the functions.