TextBox control alignment
#1
Hi,

for my addon XBMC File Cleaner I am currently writing a log viewer that is activated through the addon's settings. In the Artwork Downloader addon I have found something very similar, which I've tailored to my needs. I do however have one issue with the alignment of the text. I'm logging the filenames of any files that get cleaned up and these filenames can be quite long. When using scene names with XBMC, filenames tend to have periods instead of spaces, causing the (default?) justification alignment to mess up the text.

I use the method below in order to set the text in the TextBoxControl. I looked in the documentation but cannot find methods named "setAlign()" or "setProperty('align', 'left')". As you can see in the attached screenshots, alignment is definitely needed. I added some long lines from the XBMC logfile to better show the issue.

PHP Code:
__title__ "XBMC File Cleaner"
__logfile__ "/abs/path/to/cleaner.log"
self.CONTROL_LABEL 1
self
.CONTROL_TEXTBOX 5

def populate_window
(self):
    
heading "Cleaning log"
    
try:
        
open(__logfile__)
    
except (IOErrorOSError) as error:
        
xbmc.log("%s: %s" % (__title__error), xbmc.LOGERROR)
    else:    
        
self.window.getControl(self.CONTROL_LABEL).setLabel("%s - %s" % (heading__title__,))
        
self.window.getControl(self.CONTROL_TEXTBOX).setText(f.read())
        
f.close() 

Since I know very little about skinning, I don't know how to align the text differently. I noticed from the log files that DialogTextViewer.xml is loaded once the window is activated. I then tried modifying it as below, but it appears to be skin-dependent.

PHP Code:
<control type="textbox" id="5">
  <
posx>432</posx>
  <
posy>180</posy>
  <
width>1344</width>
  <
height>789</height>
  <
label>-</label>
  <
align>left</align> <!-- Not in Aeon Nox 4. Added for testing -->
  <
font>Font_Reg20</font>
  <
shadowcolor>black</shadowcolor>
  <
pagecontrol>61</pagecontrol>
</
control

Could someone please help me find a universal way to left-align the text in this particular TextBox only? I don't want to mess up other people's skins just to print one simple log file nicely. On the other hand, if I could tell XBMC to allow wrapping on other characters like dashes, semicolons, colons, periods or comma's that would also be a big help.

watch gallery
Reply
#2
I would say your best bet is to create your own dialog skin and display it using that.
Reply
#3
There is no option to set extra characters to allow hyphenation for? If not, how would I go about making my own textbox? Do I need to follow the skinning manuals?
Reply
#4
(2014-03-23, 11:23)Anthirian Wrote: There is no option to set extra characters to allow hyphenation for? If not, how would I go about making my own textbox? Do I need to follow the skinning manuals?
No there is not an option like that. The skinning manual has what you need to design the skin. You will also need to display it with the xbmcgui module. When I'm not on my phone at work though, I can post some instructions and an example.
Reply
#5
Here's the basic xml for a simple dialog with a textbox. I haven't tested it so some of the positioning may need some tweaking.

Code:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<window>
    <defaultcontrol>201</defaultcontrol>
    <coordinates>
        <system>1</system>
        <posx>100</posx>
        <posy>50</posy>
    </coordinates>
    <controls>
        <control type="image">
            <description>Dialog Background</description>
            <posx>0</posx>
            <posy>0</posy>
            <width>1080</width>
            <height>620</height>
            <texture>dialog_background.png</texture>
        </control>
        <control type="label" id="100">
            <description>Caption</description>
            <posx>0</posx>
            <posy>0</posy>
            <width>1080</width>
            <height>50</height>
            <font>font13</font>
            <textcolor>FFFFFFFF</textcolor>
            <aligny>center</aligny>
            <align>center</align>
        </control>
        <control type="textbox" id="200">
            <posx>20</posx>
            <posy>70</posy>
            <width>1030</width>
            <height>530</height>
            <pagecontrol>201</pagecontrol>
            <font>font13</font>
            <textcolor>FFFFFFFF</textcolor>
        </control>
        <control type="scrollbar" id="201">
            <description>Message Scrollbar</description>
            <posx>1036</posx>
            <posy>70</posy>
            <width>4</width>
            <height>530</height>
            <texturesliderbackground>-</texturesliderbackground>
            <texturesliderbar>slider_bar.png</texturesliderbar>
            <texturesliderbarfocus>slider_bar_focus.png</texturesliderbarfocus>
            <textureslidernib>-</textureslidernib>
            <textureslidernibfocus>-</textureslidernibfocus>
            <orientation>vertical</orientation>
        </control>
    </controls>
</window>

You put this in <addon_dir>/resources/skins/<skin_name>/720p/

So if we call this skin 'Example' we could save it as <addon_dir>/resources/skins/Example/720p/example-text-dialog.xml

For this example you would also need to save the following to <addon_dir>/resources/skins/Example/skin.xml

Code:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<skin>
  <defaultresolution>720p</defaultresolution>
  <defaultresolutionwide>720p</defaultresolutionwide>
  <version>1.0</version>
  
  <zoom>0</zoom>
  
  <credits>
    <skinname>Example</skinname>
    <name>Anthirian</name>
  </credits>
</skin>

In this example there are three images. One for the background and two for the scrollbar.
Put those in <addon_dir>/resources/skins/Example/media/

And that covers the skin itself.

To display this you could use the following code:

Code:
import xbmcgui, xbmcaddon

class ExampleDialog(xbmcgui.WindowXMLDialog):
    def __init__(self,*args,**kwargs):
        self.caption = kwargs.get('caption','')
        self.text = kwargs.get('text','')
        xbmcgui.WindowXMLDialog.__init__(self)

    def onInit(self):
        self.getControl(100).setLabel(self.caption)
        self.getControl(200).setText(self.text)

def showTextDialog(caption,text):
    path = xbmcaddon.Addon().getAddonInfo('path')
    win = ExampleDialog('example-text-dialog.xml',path,'Example',caption=caption,text=text)
    win.doModal()
    del win

#The following will actually display the dialog
showTextDialog('Test Caption','Some text to display')

And I think that about covers the basics.
Reply
#6
Thank you very much for this detailed explanation. I'll give it a try this week.
Reply
#7
I followed your instructions to the letter, but it looks like I'm having some issues getting the window to actually focus. I'm calling it via the settings using the following XML:

PHP Code:
<setting label="32602" type="action" action="RunScript($CWD/viewer.py)" /> 

Using this, the window seems to be created, because only after I hit the back button can I select other settings. What am I doing wrong? The log is below. The only thing out of the ordinary seems the fact that the list of ParentPaths is empty. Is that normal?

Code:
20:10:51 T:11252   DEBUG: XBPyThread::Process - The source file to load is C:\Users\Geert\AppData\Roaming\XBMC\addons\script.filecleaner/viewer.py
20:10:51 T:11252   DEBUG: XBPyThread::Process - Setting the Python path to <long list of paths here>
20:10:51 T:11252   DEBUG: XBPyThread::Process - Entering source directory C:\Users\Geert\AppData\Roaming\XBMC\addons\script.filecleaner
20:10:51 T:9992   DEBUG: ------ Window Init (C:\Users\Geert\AppData\Roaming\XBMC\addons\script.filecleaner\resources\skins\Example\720p\example-text-dialog.xml) ------
20:10:51 T:9992    INFO: Loading skin file: C:\Users\Geert\AppData\Roaming\XBMC\addons\script.filecleaner\resources\skins\Example\720p\example-text-dialog.xml, load type: LOAD_ON_GUI_INIT
20:10:51 T:9992   DEBUG: LocalizeStrings: no strings.po file exist at C:\Users\Geert\AppData\Roaming\XBMC\addons\script.filecleaner\resources\language\English, fallback to strings.xml
20:10:51 T:9992   DEBUG: CGUIMediaWindow::GetDirectory ()
20:10:51 T:9992   DEBUG:   ParentPath = []
20:10:51 T:9992   ERROR: Control 201 in window 13000 has been asked to focus, but it can't
20:10:53 T:9992   DEBUG: Keyboard: scancode: 0e, sym: 0008, unicode: 0008, modifier: 0
20:10:53 T:9992   DEBUG: CApplication::OnKey: backspace (f008) pressed, action is Back
20:10:53 T:9992   ERROR: Control 201 in window 13000 has been asked to focus, but it can't
20:10:53 T:9992   DEBUG: ------ Window Deinit (C:\Users\Geert\AppData\Roaming\XBMC\addons\script.filecleaner\resources\skins\Example\720p\example-text-dialog.xml) ------
20:10:53 T:11252    INFO: Scriptresult: Success
20:10:53 T:11252    INFO: Python script stopped
20:10:53 T:11252   DEBUG: Thread XBPyThread 11252 terminating
20:10:53 T:9992   DEBUG: waiting for python thread 10 (C:\Users\Geert\AppData\Roaming\XBMC\addons\script.filecleaner/viewer.py) to stop
20:10:53 T:9992   DEBUG: python thread 10 (C:\Users\Geert\AppData\Roaming\XBMC\addons\script.filecleaner/viewer.py) destructed
Reply
#8
(2014-03-24, 21:17)Anthirian Wrote: I followed your instructions to the letter, but it looks like I'm having some issues getting the window to actually focus. I'm calling it via the settings using the following XML:

PHP Code:
<setting label="32602" type="action" action="RunScript($CWD/viewer.py)" /> 

Using this, the window seems to be created, because only after I hit the back button can I select other settings. What am I doing wrong? The log is below. The only thing out of the ordinary seems the fact that the list of ParentPaths is empty. Is that normal?

It sounds like the window is displaying under the settings window.

Try inserting <zorder>2</zorder> in the windows xml file like below:
Code:
<window>
    <defaultcontrol>123</defaultcontrol>
    <zorder>2</zorder>
    <coordinates>
Reply
#9
Yes, that solved the issue. Thank you once again. I can now start skinning Smile
Reply
#10
Okay, I've spent a few days getting a nice window with a caption, a textbox, a scrollbar and a few buttons in it. In the textbox I am showing the contents of a text file (log) and I allow the user to either clear or trim the log using the two buttons in the window. As such, I currently call the same script that shows the window but with a different argument, as below.

Code:
<onclick>XBMC.RunScript(special://home/addons/script.filecleaner/viewer.py, trim)</onclick>

Now, this all works quite well, but it always creates a new window over the existing one. I prefer reusing the existing window, but since it's not a built-in window I'm having trouble with it. I have tried setting <id> tags in my WindowXML file, e.g. 13000 (outside the reserved IDs), but I can't seem to use that instead of creating a new window. How do I make viewer.py use the already opened window that the button is pressed in?
Reply
#11
Give the buttons id attributes and add this to your window class and use it and instead:
Code:
def onClick(self,controlID):
    if controlID == <TRIM BUTTON ID>:
        self.doTrim()

In doTrim() you would modify the text and re-display it just as you did in onInit()
Reply
#12
Aha, so it's the other way around. Don't do the callback in the XML file but in the Python script. I changed it and it works like a charm, thanks! One last question though: I would like to increase the caption's font size, but does that really require me to include my own font files and Font.xml? I would simply like to use existing fonts, but larger. Is this possible?
Reply
#13
You can't include your own font files, even if you want to (other than modifying the XBMC skin). You can use a larger font from the skin, but if the skin the person is using is different, it may just use the default font size. One method to deal with this is to create different xml files for different skins and detect the skin and change xml based on that. But that only works for skins you include specific files for. The other way I have used is to read in the current skins Font.xml file and attempt to find the closest match in font size and then modify your skin file on the fly with those font names. Both of these methods are overly complex for one dialog, so I would just make do with the default font size.
Reply
#14
I must have missed your response since it was so quick. Thanks for the explanation, I have indeed decided to just use the default font size. Instead of increasing the size I just changed the text color. Thanks for all the help!
Reply
#15
I forgot to mention. For creating line breaks at other characters than spaces, you could try inserting an empty formatting tag after the character. For instance replace
Code:
'filename-1x01.mp4'
with
Code:
'filename-[B][/B]1x01.mp4'
The tags won't be displayed. I'm not sure if this will work but it might.
Reply

Logout Mark Read Team Forum Stats Members Help
TextBox control alignment0