Your Universal Remote Control Center
RemoteCentral.com
Philips Pronto Professional Forum - View Post
Previous section Next section Previous page Next page Up level
Up level
The following page was printed from RemoteCentral.com:

Login:
Pass:
 
 

Page 1 of 2
Topic:
Is there a free ProntoScript dialog box implementation?
This thread has 16 replies. Displaying posts 1 through 15.
Post 1 made on Wednesday May 22, 2019 at 05:52
sebastian
Long Time Member
Joined:
Posts:
September 2003
93
Hi,

in my setup, I have some buttons to start activities like "Watch TV", "Watch Blu-ray" etc.
I would like to extend some of those to offer a choice for an output device, eg. watch a Blu-ray on the TV screen or the projector.
I'm thinking along the lines of a pop-up dialog box or a kind of menu that pops up when pressing the activity button.
This could be done with hidden pages or un/hiding buttons and panels.
But I think it would be much more versatile to generate these dynamically using ProntoScript.

Unfortunately, by default we only get GUI.alert(), which is kinda useless in that context.
I've checked some of the ancient wisdom postings and it seems that the only way is to code the functionality myself.

Before I start reinventing the wheel: is there already an implementation of a dialog box of some sort available out there?
For now, the only thing I'm looking for would be a popup that offers two choices, so nothing too fancy...

Sebastian
Post 2 made on Wednesday May 22, 2019 at 17:35
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,992
Not to my knowledge. Also, you want the ability to control "modality" as well as having timed dismissal with defaults.

It is funny you are asking about this because I was just thinking last night about how to break an image apart such that you could have say 10x10 pixel pieces for a frame around the dialog and a single color background.

Create a dynamic panel on screen setting background color, etc.

Next, assuming you want a 10 pixel border, you'd need 4 resource images at 10x10 representing all 4 corners. 1 resource image for the vertical edge, 1 resource image for the horizontal edge, and 1 resource panel from which you'd read background background color.

Create a dynamic panel onscreen and install the background color from your resource widget (be sure to set transparent=false).

Next, using the 'stretchImage' functionality of a panel you could assemble pieces and parts by positioning the 4 new panels for the corners, size according to your image and install the corner images.

Finally, create panels for the horizontal bars and the vertical bars. Install the images into these pieces with 'stretchImage=true" for the bars.

If you want to take a crack at the ProntoScript and want to share with the community, I'd be happy to review/suggest changes or improvements.

Just don't have time to write it up myself as I'm working on a NodeJS project for Raspberry Pi at this time.

Lyndel
Lyndel McGee
Philips Pronto Addict/Beta Tester
OP | Post 3 made on Thursday May 23, 2019 at 05:13
sebastian
Long Time Member
Joined:
Posts:
September 2003
93
Thanks, Lyndel! I think I will give it a shot, then.
It'll probably take some time though - I'm not very familiar with scripting the GUI stuff, yet, but I'll figure it out.
Now I only need to find some spare time... ;)

I'll keep you updated.

Sebastian
Post 4 made on Saturday May 25, 2019 at 16:43
Barry Gordon
Founding Member
Joined:
Posts:
August 2001
2,157
I built such a dialog box for my CommandFusion based systems. Command fusion is a system very similar to the Pronto Professional system. There are two parts; the System designer (think Pep2) and a run time package that runs on IOS devices and Android devices. I run mine on iPads and iPhones.

The Dialog system is in two parts, a screen that is a subscreen of every page screen and is simply a nice box with places where the second part can place things like text and buttons. The second part is a Javascript function that does all the work. It is called whenever the dialog box needs to go up on a page. It makes the dialog box visible on the page (centering it), dynamically fills in the text, and sets up to 3 buttons with a limited set of names

If you PM me I will send you the two parts.  The javascrip[t code will give you some idea on what is involved.  I will answer questions, or read it over and call me and I'll walk you through the code
OP | Post 5 made on Tuesday May 28, 2019 at 12:53
sebastian
Long Time Member
Joined:
Posts:
September 2003
93
One question:
I end up doing a lot of attribute assignments like:

btn = GUI.addButton();
btn.visible = false;
btn.font = "verdana.ttf";
btn.fontSize = 10;
btn.color = 0xFFFFFF;
[...]


I suppose there isn't a more efficient way, like e.g.
var properties = {visible:false, font:"verdana.ttf", fontSize:10, color:0xFFFFFF, ... };
btn = GUI.addButton(properties);


The only other solution I found was to loop over the properties object and use the keys as attributes for "btn" and assign the corresponding value.

Sebastian
Post 6 made on Wednesday May 29, 2019 at 20:38
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,992
Sebastian,

I got your mail but don't have a github userid.

WRT your question, the only solution is the loop as the version of javascript in pronto does not support Object.assign() which would copy properties IIRC, from another object.

var btn = GUI.addButton();
for (var key in properties) {
btn[key] = properties[key];
}


Note that doing color via a property on a button will only work until said button is pressed onscreen. I think you have to call setColor() or setBgColor() on a button.

However, using color and bgColor for panels works just as you would expect.

Another tidbit - The 'transparent' property if used on a panel is like 'no Fill' from the editor. However, if you set a button's 'transparent' property to true, the button cannot be pressed. I often use this undocumented 'feature' to enable/disable buttons without having to hide them.
Lyndel McGee
Philips Pronto Addict/Beta Tester
OP | Post 7 made on Thursday May 30, 2019 at 03:01
sebastian
Long Time Member
Joined:
Posts:
September 2003
93
Hi Lyndel,

ok, I'll post a link to my code as soon as it's halfway presentable ;)

Regarding the property assignment, I already suspected that there's no "cleaner" way.
I've already seen the "for-loop solution" and I think I'll will do it this way then.

Thanks a lot for pointing out the .color()/.setColor() behavior!
One of the currently unresolved issues indeed was that the button labels change color as soon as a button is pressed!

The button transparency thing is also great to know as I was looking for a way to prevent multple button presses on a button that e.g. triggers a .scheduleActions() call!

Sebastian
OP | Post 8 made on Thursday May 30, 2019 at 05:26
sebastian
Long Time Member
Joined:
Posts:
September 2003
93
So this is what I'm currently working on:
[Link: github.com]

It's far from being finished; use at your own risk ;)

There's instructions on how to use it in the top comment section of the file.
I'll write up a proper README when it's all done. Probably ;)

I'm using Noel Blackman's Aleera theme for my UI, so I took one of the graphics and cut it up into 10x10 pixel pieces and reduced their transparency a bit.
This is what it looks like in PEP3:



And that's an example how it looks with 3 buttons (without a message text):
var buttons = [ ["B1", "GUI.alert('1')"], ["B2", "GUI.alert('xyz')"], ["Close", "close();"] ];
​dbox(400, 200, 'Three Buttons','', buttons);




Sebastian
Post 9 made on Saturday June 1, 2019 at 01:15
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,992
Code looks good. Now, on to your TODO's.

To define colors/fonts etc for text, I recommend the following:

In your RESOURCES page where you put all your corner and other images, define some panels with appropriate ProntoScript names like 'Message_Template', and buttons with prontoscript names 'Button_Template' etc..

Next, write a function that simply 'lifts' the values of properties from your RESOURCE widget(s) into the on-screen GUI.addPanel() or GUI.addButton() results.

For example:
var source = myResourceWidget;
var target = myGUIPanel;
var propertiesToCopy = ['color','font','width','label','transparent','visible'];

propertiesToCopy.forEach(function (key){
target[key] = source[key];
});

With this approach, you can visually see how text will appear, etc and design that on your resource page.

If you want different styles of dialogs, can simply create an activity with ProntoScript name 'DIALOG_TEMPLATES'. Inside this activity, you can put pages with ProntoScript names like 'DIALOG_STYLE_1'. Each of these pages has the same number of widgets with expected ProntoScript names.


Then, in your constructor for the dialog box, you could simply specify which 'Template' you wanted to use and then lookup your resource widgets as:

CF.widget('FRAME_TOP_LEFT', myTemplate, 'DIALOG_TEMPLATES'.

Also, I noted that your script uses Verdana or some other font. For the font to be available in your XCF for use by script, you must have this font defined on some widget in the config. Voila, you just created Templates with resource widgets so you've got that covered. Finally, you mentioned about sizing your text. To do this, you require a widget with the font you want to use installed. Again, your Template comes to the rescue as it holds the font you want in the size you want.

All you have to work out is how to do line breaks, etc...

Here is some code you may want to try out. It was written before Philips provided the ability to determine text size. It is based on max characters per line and the base code was originally in the Philips RSS Feed example module.

Hoping it will provide some assistance.


//********************************************************************************
// JavaScript String Extensions
//********************************************************************************
// String extensions for wordwrap + trimming
//String.wordWrap(maxLength: Integer, [breakWith: String = "\n"], [cutWords: Boolean = false]): String
//Returns an string with the extra characters/words "broken".
//maxLengthmaximum amount of characters per line
//breakWithstring that will be added whenever it's needed to break the line
//cutWordsif true, the words will be cut, so the line will have exactly "maxLength" characters, otherwise the words won't be cut
//
if (!String.prototype.wordWrap) {
String.prototype.wordWrap = function wordWrap(m, b, c) {
var i, j, s, r = this.split("\n");
if (m > 0) {
for (i in r) {
for (s = r[i], r[i] = ""; s.length > m; j = c ? m : (j = s.substr(0, m).match(/\S*$/)).input.length - j[0].length || m, r[i] += s.substr(0, j) + ((s = s.substr(j)).length ? b : "")) {};
r[i] += s;
}
}
return r.join("\n");
};
}
if (!String.prototype.wordWrapIntoArray) {
String.prototype.wordWrapIntoArray = function wordWrapIntoArray(m, b, c) {
var i, j, s, r = this.split("\n");
if (m > 0) {
for (i in r) {
for (s = r[i], r[i] = ""; s.length > m; j = c ? m : (j = s.substr(0, m).match(/\S*$/)).input.length - j[0].length || m, r[i] += s.substr(0, j) + ((s = s.substr(j)).length ? b : "")) {};
r[i] += s;
}
}
return r;
};
}
if (!String.prototype.trim) String.prototype.trim = function() {
return this.replace(/^\s+|\s+$/g, "");
};
if (!String.prototype.ltrim) String.prototype.ltrim = function() {
return this.replace(/^\s+/, "");
};
if (!String.prototype.rtrim) String.prototype.rtrim = function() {
return this.replace(/\s+$/, "");
};
//********************************************************************************
// JavaScript String Extensions
//********************************************************************************

Lyndel McGee
Philips Pronto Addict/Beta Tester
Post 10 made on Saturday June 1, 2019 at 01:21
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,992
If you are in the states and want to bounce ideas around via telephone, send me an email to addy on my profile and we can exchange contact info.

I used to have a skype account but not sure if it is still active.

Lyndel
Lyndel McGee
Philips Pronto Addict/Beta Tester
OP | Post 11 made on Saturday June 1, 2019 at 07:40
sebastian
Long Time Member
Joined:
Posts:
September 2003
93
Thanks a lot for your input!
Of course, using the resources from PEP as templates would be the natural thing to do - for
some reason that hasn't occured to me #-)

I've now set it up exactly like that and I also split the dialog title from the message, so you could configure different text styles for each.
You could also set some title bar background for the dialog window, if you wanted.

I'll have a closer look at the word wrapping code. I'm currently not sure if I'm going to implement text wrapping at all, but I will give it a try.
I'm not planning to use these dialogs excessively and currently all the text displayed is static anyway, so it might just be easier to do the formatting in PEP - also considering the likelihood that the result might look more pleasing when done manually.

Thanks for the phone call offer - I'm currently ok using the forum, but maybe I'll take you up on it one day.
I'm located in Germany, so there's also the time zone issue...

Sebastian
Post 12 made on Saturday June 1, 2019 at 13:40
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,992
Wow, I just realized that the post above was the longest I've written here in over 5 years. I used to write novellas.

I included the kitchen sink on code above as at the time there was no string.trim(), string.rtrim(), string.ltrim(). So, inside the pronto, I decided I'd just add them to the string prototype so you could use them naturally such as:

var trimmed = " Hello World! ".trim();

According to Philips, widgets created GUI.addPanel() and GUI.addButton() should be cleaned up with 'remove' as you have done otherwise you get memory leaks. But, how could such leaks occur. If you jump between activities, I would presume that all memory would be cleared. If you leave to 'Diagnostics' or 'Setup', I would expect the same.

However, I always try to bulletproof my code. Therefore, in your dialog upon startup, you might consider creating a Page onExit callback that is added upon construction such that if user pages up/down within the same activity, you clean up the widgets that might be open using your 'close'. method.


Finally,

My stepson, wife, and grandkids are in Stockholm so I know about the TZ issue.

I facetime with them on weekends, so there are options. ;-)
Lyndel McGee
Philips Pronto Addict/Beta Tester
OP | Post 13 made on Sunday June 2, 2019 at 11:36
sebastian
Long Time Member
Joined:
Posts:
September 2003
93
I didn't know that you could extend the builtin JS classes so easily - that's useful :)

I have now added some code that checks if the number of buttons fits into the specified width and if not, increases the dialog's width accordingly.
Then the message text is wrapped (using your code example - thanks again for that) to fit the message panel width, increasing its height, if necessary.

So basically, specifying a width and height of "1" should still get you a decent-sized dialog.

All within limits, of course - an "auto-sized" single button dialog will be pretty narrow, so it won't fit much text.
And there's no "plan B" if you specify too many buttons or too much text to fit the screen.
(maybe I should marry the word wrap code to the button placement, so one could have multiple lines of buttons.... just kidding ;-)

I'm also calling the close() function from onExit() now, as you suggested.

Sebastian
Post 14 made on Sunday June 2, 2019 at 21:29
Lyndel McGee
RC Moderator
Joined:
Posts:
August 2001
12,992
You don't need to worry about activity exit, you need to worry about page exit.

If you PageUp/Down to non-hidden pages within the activity, you should call the close at that time.

This means that when your dialog is shown, it should register a callback function.

function onPageExit() {
// you may run into issues calling close() directly. If you do, ping me
// via email as you may need to install your dialog as a member field in the
// current page.
// in your onShow, do something like CF.page()['___myDialog'] = this;
// then instead of close(), call
// this['___myDialog'].close();
// delete this['___myDialog'];

close();
this.onExit = null;
}
CF.page().onExit = onPageExit;
Lyndel McGee
Philips Pronto Addict/Beta Tester
OP | Post 15 made on Monday June 3, 2019 at 04:33
sebastian
Long Time Member
Joined:
Posts:
September 2003
93
Ah, I see - so I can remove the CF.activity().onExit line again?
I've now put

CF.page().onExit = function() { close(); }

after all the ".visible = true" lines instead, which doesn't seem to not work - at least in the simulator.
Reading your function's comments, I'm wondering what kind of issues I should expect with calling close() directly?
I am assuming it's because objects are already being dereferenced by the system while the onExit callback function is being executed?
So should I generally use something like "CF.page()['___myDialog'] = this; ..." or only in case when issues become noticeable?

Also I noticed that you're often putting something like "this.onExit = null;" at the end to remove the callback - is this just to help the garbage collector along?

Sebastian
Page 1 of 2


Jump to


Protected Feature Before you can reply to a message...
You must first register for a Remote Central user account - it's fast and free! Or, if you already have an account, please login now.

Please read the following: Unsolicited commercial advertisements are absolutely not permitted on this forum. Other private buy & sell messages should be posted to our Marketplace. For information on how to advertise your service or product click here. Remote Central reserves the right to remove or modify any post that is deemed inappropriate.

Hosting Services by ipHouse