# Resolutions



## wmcbrine

Some things I've found about the little-documented area of changing resolutions...

First, the lists of resolutions returned by EVT_RESOLUTION_INFO -- an asterisk indicates the default resolution (always 640x480):



Code:


Series 2, not affected by Aspect Ratio setting:

*  640x480 1:1
   704x480 11:10

Series 3, 16:9, 720p:

  1280x720 1:1
   704x480 40:33
*  640x480 1:1

Series 3, 4:3, 720p:

  1280x720 3:4
   704x480 10:11
*  640x480 1:1

Series 3, 4:3, 480i:

   704x480 10:11
  1280x720 3:4
*  640x480 1:1

Series 3, 16:9, 480i:

   704x480 40:33
  1280x720 1:1
*  640x480 1:1

The second pair of numbers is meant to be the pixel aspect ratio -- note that this is always shown as 1:1 for 640:480, which is wrong when the TiVo is set to 16:9. Also, the Series 2 (running 9.1) has 11:10 where the S3 (running 9.2) has 10:11.

The first listed resolution in each group appears to be the "optimal" resolution for the given output mode and aspect ratio.

In the default 640x480 mode, there's a kind of posterization of images that doesn't occur in 704x480 mode. However, in 704x480 mode, transparency no longer works correctly. (You can see both of these effects in the "test" app in HME for Python.)*

In 1280x720 mode, setting a view to a color resource doesn't fill the whole view with the color -- only an area up to 704x480 or so, centered in the view. But images can fill the whole view.

* Edit: That was all on the S3. On the S2, attempting to change the resolution doesn't work, and in fact, seems to cause a reboot.


----------



## perrce

Has anyone else been experimenting with changing resolution? The documentation on this is really horrible. According to the hme-protocol doc, you need to send an event to change resolution. But just as I was about to experiment with that, I noticed that BScreen has a new constructor that isn't in the javadocs. This new constructor takes a Resolution object (also not in the javadocs) as an arguement. 

I thought that they may have set up BScreen to automatically change the resolution for you. My experiments don't show that though. The passed Resolution object is used internally to set a local targetResolution variable (which doesn't seem to do anything), but I can't find that the constructor (or any other method) causes an event to be sent based on the received Resolution. So now I'm back to playing with manually sending the event to the receiver. 

Has anyone else made any progress?


----------



## s2kdave

Yes, I've done a ton of resolution stuff. You can look for an example using the experimental HME in my not yet announced or released version of bananas-plus:

http://code.google.com/p/bananas-plus

Just look at the code for BApplicationPlus. It auto changes the resolution for you to the preferred resolution.


----------



## wmcbrine

perrce said:


> Has anyone else made any progress?


Well, if you're at all interested in Python...



Code:


    def handle_resolution(self):
        """ Choose the 'optimal' resolution. """
        return self.resolutions[0]

So, yeah.


----------



## perrce

Here's one. Despite having my Series 3 TiVo video output set to 1080i Fixed, 1920x1080 doesn't appear as one of the available resolutions when I getAvailableRenderingResolutions(). The only resolutions returned are:



Code:


com.tivo.hme.sdk.Resolution[1280x720-PAR=1/1]
com.tivo.hme.sdk.Resolution[704x480-PAR=40/33]
com.tivo.hme.sdk.Resolution[640x480-PAR=1/1]

Any idea why 1080i isn't showing up? Code follows:



Code:


System.out.println("#   All Available Resolutions");
for(Resolution res : this.getReceiverResolutionInfo().getAvailableRenderingResolutions()) {
        System.out.println(res.toString());
}


----------



## s2kdave

perrce said:


> Any idea why 1080i isn't showing up? Code follows:


It never has and won't (at least as of now). I think the tivo is restricting it to 720 or smaller. Probably for performance or memory reasons I'm sure.


----------



## perrce

s2kdave,

I've been looking at resolution issues, and although it's easy enough to scale fonts and layout, whisper arrows and keyboard images are more than I really want to deal with.

How stable is bananas-plus? Is it ready for beta testing yet? How close is it to being ready for general audiences?


----------



## s2kdave

perrce said:


> s2kdave,
> 
> I've been looking at resolution issues, and although it's easy enough to scale fonts and layout, whisper arrows and keyboard images are more than I really want to deal with.
> 
> How stable is bananas-plus? Is it ready for beta testing yet? How close is it to being ready for general audiences?


Bananas-plus is stable enough for a beta for sure. I've already started converting my movie rentals app to start using it. The reason I haven't made a release yet is I want to make sure I'm not missing any big holes in the api. The LayoutManager stuff needs to be tested a little more, but it works pretty well. You don't need to use the LayoutManager though. There are constructors for the regular hardcode it way, plus a couple more that predefine certain things (like the row height in a list) and another constructor for when you use the LayoutManager. I also haven't built the scripts to build the zip that contains all the jar, documentation and license files in it. But feel free to use it and make comments on it. The samples cover a lot of the api, but there are still traces of hardcoding dimensions in it.


----------



## s2kdave

BTW, the keyboard in regular bananas is pretty much unusable on resolutions higher than 480 (ie, you can't increase the size of it). I did a lot of work on the keyboard to provide a similar api, yet make it scalable to multiple resolutions via the skin.


----------



## wmcbrine

Yeah, the keyboard in Bananas is weird -- they pre-rendered the letters as a PNG. Why do that? I figure it was to ensure the letters were aligned, but I achieved the same effect just with views. Perhaps they wanted to keep down the number of views used, but you only need one per column.


----------



## perrce

Looking more closely at bananas-plus, it's package is com.tivo.hme.bananas. Is that right? Or should it have it's own package? Btw, do you have a *.jar of it?


----------



## s2kdave

perrce said:


> Looking more closely at bananas-plus, it's package is com.tivo.hme.bananas. Is that right? Or should it have it's own package? Btw, do you have a *.jar of it?


Yes, that's right and the only reason for it was so it could access package level stuff in bananas. They did a real poor job of making bananas extendable. So while doing it I tried as best as I could to make it extendable outside the package using protected everywhere.

I don't have a jar of it yet. I mentioned I haven't made a release yet. Maybe I'll do that soon.


----------



## s2kdave

wmcbrine said:


> Yeah, the keyboard in Bananas is weird -- they pre-rendered the letters as a PNG. Why do that? I figure it was to ensure the letters were aligned, but I achieved the same effect just with views. Perhaps they wanted to keep down the number of views used, but you only need one per column.


Yeah, I thought that was weird too. I think they were trying to keep the number of views down as there is a max limit to them. And I bet a single image performs better than 30 or so of them with transparency.


----------



## wmcbrine

s2kdave said:


> And I bet a single image performs better than 30 or so of them with transparency.


Probably -- but, like I say, you only need as many views as you have columns (four, seven, whatever). I wonder if they missed that insight? I know the first thing I thought of was one view per character, and that would indeed seem like too many...


----------



## perrce

I've been playing with bananas-plus, and I think I need some help. Right now, I'm just trying to create a ListPlus object. To do that, I took a working Bananas sample app, and "patched in" the bananas-plus classes: my application extends BApplicationPlus, my screen extends BScreenPlus, and my list extends BListPlus. Those were really the only changes I made.

When I run the new bananas-plus app on my Series 3 (set to 1080i Fixed) I get a ClassCastException, although when I run it in the version 1.4 simulator (resolution obviously 480i), it works ok. (I have never been able to get the 1.4.1e simulator to work.)

Any idea what I'm missing? I'm including below the contents of the class that holds the screen causing the error, and output from the console.

MainMenuScreen.java:


Code:


/**
 * 
 */
package org.dazeend.bplustest;

import com.tivo.hme.bananas.*;
import java.awt.Color;

/**
 * @author Charles Perry ([email protected])
 *
 */
public class MainMenuScreen extends BScreenPlus {
	
	private MainMenuList mainMenuList;	// The list that contains the main menu
	private int screenWidth 	= getApp().getReceiverResolutionInfo().getRenderingResolution().getWidth();
	private int screenHeight 	= getApp().getReceiverResolutionInfo().getRenderingResolution().getHeight();
	private int safeTitleH		= getApp().getReceiverResolutionInfo().getRenderingResolution().getSafeTitleHorizontal();
	private int safeTitleV		= getApp().getReceiverResolutionInfo().getRenderingResolution().getSafeTitleVertical();
	
	/**
	 * Constructor.
	 * 
	 * @param app	This instance of the application.
	 */
	public MainMenuScreen(BApplicationPlus app) {
		super(app);
	
		if(BPlusTest.DEBUG){
			System.out.println("### MainMenuScreen.MainMenuScreen");
			System.out.println("Screen Width:  " + screenWidth);
			System.out.println("Screen Height: " + screenHeight);
			System.out.println("SafeTitleH:    " + safeTitleH);
			System.out.println("SafeTitleV:    " + safeTitleV);
			System.out.flush();
		}
		// Define all dimensions in terms of percentage of the screen height and width. This make it
		// resolution-safe.
		BText titleText = new BText(	this.getNormal(),
										safeTitleH,
										safeTitleV,
										screenWidth - (2 * safeTitleH),
										(int)((0.24 * screenHeight) - safeTitleV)
										);
		titleText.setColor( Color.yellow );
		titleText.setFont( ( (BPlusTest)getBApp() ).getTitleFont() );
		titleText.setShadow(true);
		titleText.setFlags(RSRC_HALIGN_CENTER + RSRC_VALIGN_TOP);
		titleText.setValue("BPlusTest");
		
		mainMenuList = new MainMenuList(	this.getNormal(), 									// Put list on "normal" level
											safeTitleH , 										// x coord. of list origin
											(int)(screenHeight * 0.25), 						// y coord. of list origin
											(screenWidth - (2 * safeTitleH)), 					// width of list (full screen)
											((int)(((0.75 * screenHeight) - safeTitleV)/8))*8,	// height of list (full screen). Defined in terms of row height to ensure that height is an even multiple or rowheight.
											(int)(((0.75 * screenHeight) - safeTitleV)/8)		// row height for 8 rows
											);
		
		// Add menu items
		mainMenuList.add("This is a test");
		mainMenuList.add("Only a test");
		mainMenuList.add("Do not panic");
		mainMenuList.add("It will all be over soon");
		setFocusDefault(mainMenuList);
	}
	
	/**
	 * The list that contains the main menu. This class was modified from the Bananas sample source code.
	 * 
	 * @author Charles Perry ([email protected])
	 *
	 */
	static class MainMenuList extends BListPlus
    {
       
		/**
		 * Main menu constructor.
		 * 
		 * @param parent	The BView that contains this list
		 * @param x			The x coordinate of the top left corner of the list.
		 * @param y			The y coordinate of the top left corner of the list.
		 * @param width		The width of the list
		 * @param height	The height of the list
		 * @param rowHeight	The height of each row in the list
		 */
        public MainMenuList(BView parent, int x, int y, int width, int height, int rowHeight)
        {
            super(parent, x, y, width, height, rowHeight);
            
            // Configure list.
            this.setBarAndArrows(BAR_HANG, BAR_DEFAULT, null, "push");
        }

        /**
         * Creates each row of the list. Uses
         */
        protected void createRow(BView parent, int index)
        {   

            BText text = new BText( parent, 0, 0, parent.getWidth(), parent.getHeight() );
            text.setShadow(false);
            text.setFlags(RSRC_HALIGN_LEFT);
            text.setFont( ( (BPlusTest)getBApp() ).getBodyFont() );
            text.setColor( ( (BPlusTest)getBApp() ).NTSC_WHITE );
            text.setValue(get(index).toString());
        }
    }
}

Here's the output on the console (including some debugging messages):


Code:


Instance ID = 0000002530d15b62
hme-host-sample version: 1.4.1 threadsafe-experimental
debug: Loaded factory: org.dazeend.bplustest.BPlusTest
debug: Class loader for org.dazeend.bplustest.BPlusTest: sun.misc.Launcher$AppClassLoader
debug: Context class loader: sun.misc.Launcher$AppClassLoader
added factory
MDNS ADD: http://192.168.1.5:7288/bplustest/
Contacting mDNS localhost daemon at 127.0.0.1:5354
Connection to mDNS localhost daemon failed: java.net.ConnectException: Connection refused
mDNS localhost daemon: service not found.
        > java.net.ConnectException: Connection refused
jmdns library: register [start]: http://192.168.1.5:7288/bplustest/
192.168.1.6 icon.png HTTP GET - to factory /bplustest/
jmdns library: register [done]:  http://192.168.1.5:7288/bplustest/
SDK debug level = 1. Will log: errors,warnings
To control HME SDK debugging, set the property com.tivo.hme.sdk.debug.level
The integer debug level is interpreted as follows:
    0: Only errors logged (default, recommended for installed apps)
    1: Level 0 + errors and warnings logged (recommended for development)
    2: Level 1 + events from receiver logged
    3: Level 2 + commands to receiver logged
Using vStrings!
### Harmonium.init
#   Preferred Resolution
com.tivo.hme.sdk.Resolution[1280x720-PAR=1/1]
#   All Available Resolutions
com.tivo.hme.sdk.Resolution[1280x720-PAR=1/1]
com.tivo.hme.sdk.Resolution[704x480-PAR=40/33]
com.tivo.hme.sdk.Resolution[640x480-PAR=1/1]
### Harmonium.handleEvent
#   Current Resolution
screenHeight: 480.0
screenWidth: 640.0
aspectratio: 1.3333333333333333
# Preferred Resolution: com.tivo.hme.sdk.Resolution[1280x720-PAR=1/1]
# Current Resolution: com.tivo.hme.sdk.Resolution[640x480-PAR=1/1]
# Finished setting resolution
### Harmonium.handleEvent
#   Current Resolution
screenHeight: 720.0
screenWidth: 1280.0
aspectratio: 1.7777777777777777
# Preferred Resolution: com.tivo.hme.sdk.Resolution[1280x720-PAR=1/1]
# Current Resolution: com.tivo.hme.sdk.Resolution[1280x720-PAR=1/1]
## Resolution set to preferred. Pushing main menu.
### MainMenuScreen.MainMenuScreen
Screen Width:  1280
Screen Height: 720
SafeTitleH:    128
SafeTitleV:    54
connection to receiver closed
Unexpected error: java.lang.ClassCastException: com.tivo.hme.bananas.BSkin$Element cannot be cast to com.tivo.hme.bananas.BSkinPlus$Element
Thread HttpConnection(192.168.1.6:4416): java.lang.ClassCastException: com.tivo.hme.bananas.BSkin$Element cannot be cast to com.tivo.hme.bananas.BSkinPlus$Element
    com.tivo.hme.bananas.BSkinPlus.get(BSkinPlus.java:101)
    com.tivo.hme.bananas.BSkinPlus.get(BSkinPlus.java:1)
    com.tivo.hme.bananas.BHighlightsPlus.setBarAndArrows(BHighlightsPlus.java:238)
    com.tivo.hme.bananas.BHighlightsPlus.setBarAndArrows(BHighlightsPlus.java:207)
    com.tivo.hme.bananas.BHighlightsPlus.setBarAndArrows(BHighlightsPlus.java:200)
    com.tivo.hme.bananas.BList.setBarAndArrows(BList.java:157)
    com.tivo.hme.bananas.BListPlus.setBarAndArrows(BListPlus.java:211)
    org.dazeend.bplustest.MainMenuScreen$MainMenuList.<init>(MainMenuScreen.java:91)
    org.dazeend.bplustest.MainMenuScreen.<init>(MainMenuScreen.java:56)
    org.dazeend.bplustest.BPlusTest.displayMainMenu(BPlusTest.java:69)
    org.dazeend.bplustest.BPlusTest.handleEvent(BPlusTest.java:157)
    com.tivo.hme.sdk.HmeObject.postEvent(HmeObject.java:145)
    com.tivo.hme.sdk.Resource.postEvent(Resource.java:132)
    com.tivo.hme.sdk.Application.dispatchEvent(Application.java:1889)
    com.tivo.hme.bananas.BApplication.dispatchEvent(BApplication.java:278)
    com.tivo.hme.sdk.Application.handleChunk(Application.java:1606)
    com.tivo.hme.host.sample.Listener.readEvents(Listener.java:359)
    com.tivo.hme.host.sample.Listener.handleHME(Listener.java:310)
    com.tivo.hme.host.sample.Listener.handle(Listener.java:446)
    com.tivo.hme.host.http.server.HttpConnection.handleRequest(HttpConnection.java:321)
    com.tivo.hme.host.http.server.HttpConnection.run(HttpConnection.java:266)
    java.lang.Thread.run(Thread.java:619)
debug: stack[6]: java.lang.Thread.run(Thread.java:619)
debug: stack[5]: com.tivo.hme.host.http.server.HttpConnection.run(HttpConnection.java:272)
debug: stack[4]: com.tivo.core.ds.ThrowableUtils.createThrowable(ThrowableUtils.java:75)
192.168.1.6 icon.png HTTP GET - to factory /bplustest/


----------



## s2kdave

perrce said:


> I've been playing with bananas-plus, and I think I need some help. Right now, I'm just trying to create a ListPlus object. To do that, I took a working Bananas sample app, and "patched in" the bananas-plus classes: my application extends BApplicationPlus, my screen extends BScreenPlus, and my list extends BListPlus. Those were really the only changes I made.
> 
> When I run the new bananas-plus app on my Series 3 (set to 1080i Fixed) I get a ClassCastException, although when I run it in the version 1.4 simulator (resolution obviously 480i), it works ok. (I have never been able to get the 1.4.1e simulator to work.)
> 
> Any idea what I'm missing? I'm including below the contents of the class that holds the screen causing the error, and output from the console.


Most likely your BApplicationPlus extended class is overriding one of the init methods and not calling super so it's not setting the skin to be a BSkinPlus instance and configured to that. I was tempted to make that init method final and provide an alternate init method, but decided a programmer should already be calling super anyway.


----------



## s2kdave

s2kdave said:


> Most likely your BApplicationPlus extended class is overriding one of the init methods and not calling super so it's not setting the skin to be a BSkinPlus instance and configured to that. I was tempted to make that init method final and provide an alternate init method, but decided a programmer should already be calling super anyway.


Actually, that's not it. Not sure what to do about it. It looks like maybe you're adding BSkin.Element objects to the skin rather than BSkinPlus.Element objects and it doesn't like that. I didn't think that was a requirement. Can I see your skin initialization code?

Edit: Yep that looks like it's the issue. It's actually a typo on my part inside BSkinPlus. It should reference BSkin.Element not BSkinPlus.Element so that you can use either. A fix on your side you can just use BSkinPlus.Elements instead and it should work.


----------



## perrce

s2kdave said:


> It looks like maybe you're adding BSkin.Element objects to the skin rather than BSkinPlus.Element objects and it doesn't like that. I didn't think that was a requirement. Can I see your skin initialization code?


That's the thing: I'm not using Skins -- at least not directly. I stripped my test app down to the basics. All I do start up the application, change the resolution (probably in an odd way, since I'm learning as I go), and then push the MainMenuScreen. I'm not using any Skins other than anything used behind the scenes. So I was a little confused when I got that Exception dealing with the Skin.

For your reference, I'm including the only other file in the app: the BPlusTest.java file that starts the app and pushes the MainMenuScreen. Any light you can shed would be appreciated.

BPlusTest.java:


Code:


/**
 * 
 */
package org.dazeend.bplustest;

import com.tivo.hme.bananas.*;
import com.tivo.hme.sdk.*;
import com.tivo.hme.interfaces.*;
import java.io.*;


/**
 * @author Charles Perry ([email protected])
 *
 */
public class BPlusTest extends BApplicationPlus {
	
	// Static variable used for debugging
	public static boolean DEBUG = true;
	
	// Define colors
	public static String NTSC_WHITE = "0xEBEBEB";
	public static String NTSC_BLACK = "0x101010";
	
	// fonts scaled to resolution
	private String titleFont;
	private String bodyFont;
	private double scaleFactor;
 	
	/**
	 * Application initialization. Run when application is started from TiVo.
	 */
	public void init(IContext context) throws Exception {
		// Initialization from superclass.
		super.init(context);

		// Check if our resolution is set to the preferred resolution
		Resolution resolution = this.getReceiverResolutionInfo().getPreferredRenderingResolution();
		if(DEBUG) {
			System.out.println("### Harmonium.init");
			System.out.println("#   Preferred Resolution");
			System.out.println(resolution.toString());
			System.out.println("#   All Available Resolutions");
			for(Resolution res : this.getReceiverResolutionInfo().getAvailableRenderingResolutions()) {
				System.out.println(res.toString());
			}
			System.out.flush();
		}
		if( resolution.equals( this.getReceiverResolutionInfo().getRenderingResolution() ) ){
			// It's already set, so push the main menu screen
			this.displayMainMenu();
		}
		else {
			// It's not set yet, so set it.
			setReceiverResolution(resolution);
		}
	}
	
	/**
	 * Initializes font information and displays the main menu
	 */
	private void displayMainMenu() {
		// Define a scaling factor between a standard definition screen (640x480) and the current resolution
		scaleFactor = (double)this.getReceiverResolutionInfo().getRenderingResolution().getHeight()/480;
		int titleFontSize = (int)(48 * scaleFactor);
		int bodyFontSize =  (int)(24 * scaleFactor);
		titleFont = "default-" + titleFontSize + ".font";
		bodyFont = "default-" + bodyFontSize + ".font";
		MainMenuScreen mainMenuScreen = new MainMenuScreen(this);
		push(mainMenuScreen, TRANSITION_NONE);	
	}
	
	/**
	 * Gets the name and size of the font used for titles.
	 * 
	 * @return	a string containing the title font name and size
	 */
	public String getTitleFont() {
		return this.titleFont;
	}
	
	/**
	 * Gets the name and size of the font used for body text.
	 * 
	 * @return	a string containing the body font name and size
	 */
	public String getBodyFont() {
		return this.bodyFont;
	}
	
	/**
	 * Gets scale factor to convert to our resolution from standard definition.
	 * 
	 * @return
	 */
	public double getScaleFactor() {
		return this.scaleFactor;
	}
	
	/**
	 * Handles key presses from TiVo remote control.
	 */
	@Override
	public boolean handleKeyPress(int key, long rawcode) {
		
		switch(key) {
		case KEY_LEFT:
			this.setActive(false);
			return true;
		}
		
		return super.handleKeyPress(key, rawcode);

	}

	/**
	 * Handles TiVo events
	 */
	@Override
	public boolean handleEvent(HmeEvent event) {
		// Check to see if this event is of a type that we want to handle
		if(event.getClass() == HmeEvent.ResolutionInfo.class ) {
			// This is a ResolutionInfo event that gives information about display resolutions that are available
			// on the TiVo. This event is sent at application start up and whenever the display resolution changes.
			
			// Cast the event as a ResolutionInfo object, and get information about it.
			HmeEvent.ResolutionInfo resolutionInfo = (HmeEvent.ResolutionInfo) event;
			double screenHeight = resolutionInfo.getRenderingResolution().getHeight();
			double screenWidth = resolutionInfo.getRenderingResolution().getWidth();
			double aspectRatio = screenWidth / screenHeight;
			
			// DEBUG: print resolution info
			if(DEBUG) {
				
				System.out.println("### Harmonium.handleEvent");
				System.out.println("#   Current Resolution");
				System.out.println("screenHeight: " + screenHeight);
				System.out.println("screenWidth: " + screenWidth);
				System.out.println("aspectratio: " + aspectRatio);
				
				
				System.out.flush();
			}
			
			if(DEBUG) {
				System.out.println("# Preferred Resolution: " + resolutionInfo.getPreferredRenderingResolution().toString());
				System.out.println("# Current Resolution: " + resolutionInfo.getRenderingResolution().toString());
				System.out.flush();
			}
			if( resolutionInfo.getPreferredRenderingResolution().equals( resolutionInfo.getRenderingResolution() ) ) {
				// The preferred resolution has been set, so push the main menu and display it
				if(DEBUG){
					System.out.println("## Resolution set to preferred. Pushing main menu.");
					System.out.flush();
				}
				
				this.displayMainMenu();
			}
			if(DEBUG) {
				System.out.println("# Finished setting resolution");
				System.out.flush();
			}
			return true;
		}
		else {
			// The event was something that we didn't catch, so pass it to the superclass
			return super.handleEvent(event);
		}
	}
}


----------



## s2kdave

perrce said:


> That's the thing: I'm not using Skins -- at least not directly.


Ok, I found the problem. It's because you aren't calling super.handleEvent when it receives the resolution so it's never configuring the skin based on the resolution. I need to put some better logging/errors in place if that happens I suppose. Use this handleEvent method instead:



Code:


    public boolean handleEvent(HmeEvent event) {
        boolean result = super.handleEvent(event);
        // Check to see if this event is of a type that we want to handle
        if(event.getClass() == HmeEvent.ResolutionInfo.class ) {
            // This is a ResolutionInfo event that gives information about display resolutions that are available
            // on the TiVo. This event is sent at application start up and whenever the display resolution changes.
            
            // Cast the event as a ResolutionInfo object, and get information about it.
            HmeEvent.ResolutionInfo resolutionInfo = (HmeEvent.ResolutionInfo) event;
            double screenHeight = resolutionInfo.getRenderingResolution().getHeight();
            double screenWidth = resolutionInfo.getRenderingResolution().getWidth();
            double aspectRatio = screenWidth / screenHeight;
            
            // DEBUG: print resolution info
            if(DEBUG) {
                
                System.out.println("### Harmonium.handleEvent");
                System.out.println("#   Current Resolution");
                System.out.println("screenHeight: " + screenHeight);
                System.out.println("screenWidth: " + screenWidth);
                System.out.println("aspectratio: " + aspectRatio);
                
                
                System.out.flush();
            }
            
            if(DEBUG) {
                System.out.println("# Preferred Resolution: " + resolutionInfo.getPreferredRenderingResolution().toString());
                System.out.println("# Current Resolution: " + resolutionInfo.getRenderingResolution().toString());
                System.out.flush();
            }
            if( resolutionInfo.getPreferredRenderingResolution().equals( resolutionInfo.getRenderingResolution() ) ) {
                // The preferred resolution has been set, so push the main menu and display it
                if(DEBUG){
                    System.out.println("## Resolution set to preferred. Pushing main menu.");
                    System.out.flush();
                }
                
                this.displayMainMenu();
            }
            if(DEBUG) {
                System.out.println("# Finished setting resolution");
                System.out.flush();
            }
        }
        return result;
    }


----------



## s2kdave

Ok, if you update the code, it shouldn't get that exception any more plus it will print out a warning message if the skin is not configured (like in your case by not calling super.handleEvent). The UI won't behave properly until it is configured. So either you need to call super.handleEvent or do essential what it does and configure the skin for the resolution.


----------



## s2kdave

BTW, the spot where you do this in the MainMenuList would be better done another way. Basically the font and color resources are better stored in the skin. Also you can override the color for a single list by calling setColor/setFont on the BListPlus itself. You don't need to override createRow at all. As a matter of fact you don't even need the MainMenuList class at all, just create a BListPlus directly.



Code:


protected void createRow(BView parent, int index)
        {   

            BText text = new BText( parent, 0, 0, parent.getWidth(), parent.getHeight() );
            text.setShadow(false);
            text.setFlags(RSRC_HALIGN_LEFT);
            text.setFont( ( (BPlusTest)getBApp() ).getBodyFont() );
            text.setColor( ( (BPlusTest)getBApp() ).NTSC_WHITE );
            text.setValue(get(index).toString());
        }

To override font/color for all lists and buttons, override initSkin() in BApplicationPlus (call super), then override those particular values. Take into consideration the getCurrentResolution() of course for the font size. You can see the SkinUtils class where it inits everything.

This will override for all future created lists


Code:


        new BSkinPlus.Element(skin, IBananasPlus.H_BAR_FONT, 0, 0, getBodyFont());
        new BSkinPlus.Element(skin, IBananasPlus.H_BAR_TEXT_COLOR, 0, 0, NTSC_WHITE);

This will override for a single list:


Code:


mainMenuList = new BListPlus(	this.getNormal(), 									// Put list on "normal" level
											safeTitleH , 										// x coord. of list origin
											(int)(screenHeight * 0.25), 						// y coord. of list origin
											(screenWidth - (2 * safeTitleH)), 					// width of list (full screen)
											((int)(((0.75 * screenHeight) - safeTitleV)/8))*8,	// height of list (full screen). Defined in terms of row height to ensure that height is an even multiple or rowheight.
											(int)(((0.75 * screenHeight) - safeTitleV)/8)		// row height for 8 rows
											);
		
		// Add menu items
		mainMenuList.add("This is a test");
		mainMenuList.add("Only a test");
		mainMenuList.add("Do not panic");
		mainMenuList.add("It will all be over soon");
		mainMenuList.setColor(Color.red);
		mainMenuList.setFont("default-24.font");
		mainMenuList.setBarAndArrows(BAR_HANG, BAR_DEFAULT, null, "push");


----------



## perrce

s2kdave said:


> BTW, the spot where you do this in the MainMenuList would be better done another way.


Thanks for the help. I'll download the new bplus code and try it out. And thanks for the tips. This is my first time writing an HME app and I feel like I'm still wandering around in the dark. But, hey -- the only way to learn is to try!


----------



## s2kdave

perrce said:


> Thanks for the help. I'll download the new bplus code and try it out. And thanks for the tips. This is my first time writing an HME app and I feel like I'm still wandering around in the dark. But, hey -- the only way to learn is to try!


The way you were doing it IS the way you're supposed to in regular bananas, but those are part of the flaws I was aiming to fix with bananas-plus. It's not a real good design to hardcode the UI aspects especially now that there can be more resolutions than 640x480.


----------



## perrce

s2kdave said:


> Basically the font and color resources are better stored in the skin.


Can you give me the nickel tour on how you intended skins to work in Bananas-plus? How do I get/set title fonts? colors? etc? Do I need to init something first, or is that all taken care of in the BApplicationsPlus init? I'm getting a little lost in the code and can't figure out what the intended entry point was. Thanks.


----------



## s2kdave

There are certain predefined colors and fonts such as H_BAR_FONT and H_BAR_COLOR for the font/color of the text on bars. You can find the names in IBananasPlus.

The way you would make your own custom ones would be like this:

in your extended BApplicationPlus class:


Code:


public void initSkin() {
    super.initSkin();

    Resolution resolution = getCurrentResolution();
    String fontBaseOnResolution = ...;
    new BSkinPlus.Element(skin, "myCustomFont", 0, 0, fontBasedOnResolution);
}

Then in your own custom UI element or screen where you need the font:


Code:


Element e = getSkin().get("myCustomFont");
btext.setFont(e.getResource());

The idea is that you loosely couple your views and screens to the resolution and it will render appropriately based on the resolution without you having to do anything outside your BApplicationPlus class. And for images it's the same thing.


Code:


Element e = getSkin().get("myCustomImage");
icon = new BViewPlus(getNormal(), 0, 0, e.getWidth, e.getHeight());
icon.setResource(e.getResource());

Now I've made a couple extra tools that help in calculating the sizes based on the resolution by doing scaling. The idea is you make your images to a specific resolution, in this case 720p. Then you scale that image/font to all other resolutions. Here's the example of the initSkin() method:


Code:


public void initSkin() {
    super.initSkin();

    Scale s = new Scale(720, getCurrentResolution().getHeight());

    //24 is the size of the font at 720p resolution
    new Element(skin, "myCustomFont", 0, 0, "default-" + s.dx(24) + "-bold.font");

   //use an image scale utility to save a scaled copy to disk when needed
   //40x40 is the size of the image at 720p resolution
   SkinUtils.createImage(skin, s, "myCustomIcon", 40, 40, "resources/myIcon.png");
}

I've also found that scaling down the font size a little lighter than 1:1 makes for better results. So I create a separate Scale instance just for fonts


Code:


        Scale f;
        if (res.getHeight() < 720) {
            //do a lighter scale for fonts when it's a smaller resolution
            f = new Scale(720, res.getHeight()*9/8);
        } else {
            f = s;
        }


----------



## s2kdave

Oh, and to override the title font/color globally, just create a new Element in initSkin() with one or more of these:

IBananasPlus.H_TITLE_FONT
IBananasPlus.H_TITLE_TEXT_COLOR
IBananasPlus.H_TITLE_SHADOW_COLOR


----------

