New GUI library available

There’s no need to worry about if the gui uses AWT/Swing or not. If you want to use it, use it. This doesn’t add AWT/Swing dependance to jME. Just your GUI. Remember, I’m splitting out all non-core functionality into their own libs.

^

/

|

|

|



If it wasn’t already apparent… that was me.

Excellent. I just wasn’t seeing what you were trying to do. Got it now. Thanks.

See next post.

I think I found a bug in UIWindow in createWindowNodeFromCoordSet where you have just one quad. After line 334 you should add:



quad.setRenderState( quadAlpha);



Works like a charm now.



The only minor general concern I have about the nui so far is that sometimes I’ve noticed that buttons close together get their states a little stuck. In other words, if I lose focus on my exit button and mouse over my options button, the exit button will sometimes remain in the over state. Only seems to happen if I move the mouse very quickly. I’m a little tired atm, so when I’m more awake, I’ll check to insure that the buttons aren’t overlapping, which is possible since they are very close together.

I haven’t seen any problem with them being too close together. The relation to screen coordinates is pixel grained. So your windows are probably overlapping.



Thanks for the bug note!

The old widget code had working scrollbars and had the clipping working.

Guurk,



I went back and double checked all the positioning and nothing is overlapping. The closest button is 6 pixels from the next. What is happening is that if I move the mouse very rapidly across three of the buttons, not always, but maybe after 5 or 6 tries, I can get them all to stick in the on state.



Don’t know if it’s worth pursuing, but just thought I’d mention it. I think I can live with it personally, but would be interesting if you found anything on this.

I’ll take a look at it. It might have something to do with the mouse movement event being tagged by just one button. Try commenting out the ‘event.setProcessed();’ line in the onMouseMove method of UIButton. You’ll notice that I allowed button up events to propagate to all consumers, it sounds like the same needs to happen with mouse move.

And now that I take a closer look it seems also that we’ll need to remove the hit test in some instances.



Bottom line, the code that effects that is in this method.



Thanks for the debug work!

Ok. I’ll take a look at the code tomorrow. A little more testing revealed that it’s only a problem when moving the mouse over the buttons (they are aligned vertically) from top to bottom. If I move the mouse over them from the bottom up, it’s fine. Strange.

Sounds like it’s my new gamestate stuff that screws things up. Guurk, do you want me to update things for you? I think I can do it fairly fast as I know exactly what’s changed, but if you have already done it there’s no point.

It’s debateable wether I’m going to get to it in the next couple of days. I wish to but my real work is very demanding right now. So, Per, feel free! Thanks.

Sure, I’m on it. Will probably do it tonight or tomorrow.

Gah! I picked the wrong time to do a complete CVS update. Dead in the water now. :frowning: I started to work on updating the NUI to work with the new gamestate stuff, but I’d rather wait for you, Per, since you really know what is going on in gamestate now.



Could we get NUI into CVS at this point? It shouldn’t hurt anything since the jmex branching.

No problem Slowdive, work done, took about 5 mins :slight_smile:



The test seems to run fine, though I hadn’t seen it before so I don’t know if it differs.



Changelog:


StandardUIGameState
- constructors takes a gameStateName
- since the InputHandler of StandardGameState has been removed, StandardUIGameState now maintains one
- changed update(float) to stateUpdate(float), removed call to super.update
- removed render(float) as it does the exact same thing as BasicGameState.render(float)
- stateNode is now known as rootNode

XMLUIGameState
- constructor now takes a gameStateName
- removed dead imports

NewUITest
- because each GameState now maintains its own scene tree, there's no longer a need for a rootNode to be passed to the GameStateManager on create()
- GameStateManager.addGameState = GameStateManager.attachChild
- GameStateManager.switchTo = GameStateManager.activateChildNamed
- removed dead imports

NewUITestState & NewUITestState1
- constructors now take a gameStateName
- constructors update the rootNode
- switchTo() is now onActivate()


Download

Coolness. Thanks for the fast turnaround!

I’ve made Per’s change file available on the file galleries now too. So, yes, you can pick it up at that url noio.

Guurk,



Would it be possible to add an onMouseOver method to UIButton? I’m using this to trigger a sound event when the cursor rolls over a button in the UI. Code included below:


/*
 * Created on Jan 31, 2005
 */

package com.jme.nui;

import com.jme.math.Vector2f;
import com.jme.scene.Node;
import com.jme.scene.state.AlphaState;
import com.jme.scene.state.TextureState;
import com.jme.system.DisplaySystem;
import com.jme.util.LoggingSystem;
import com.sun.org.apache.xpath.internal.XPathAPI;
import java.util.ArrayList;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import org.w3c.dom.traversal.NodeIterator;
/**
 * A button can be one of the following: <br>
 * <ul>
 * <li>Made from 3 different states, each with 9 section definitions </li>
 * <li>Made from 3 different states, each with 1 section definition </li>
 * <li>Made from 1 state, with 9 section definitions </li>
 * <li>Made from 1 state, with 1 section definiton </li>
 * </ul>
 * The default _quad from UIWindow is the midmid area if we are using the 9
 * section method. Otherwise it's the one quad needed.
 *
 * @author schustej
 */
public class UIButton extends UIWindow {

    /**
     * The default _quad is the midmid area if we are using the 9 area button
     * method. Otherwise it's the one quad needed used for other states.
     */
    protected Node             _upNode;
    protected Node             _overNode;
    protected Node             _downNode;
    protected static final int UI_STATE_BUTTON_NONE = 1;
    protected static final int UI_STATE_BUTTON_OVER = 2;
    protected static final int UI_STATE_BUTTON_DOWN = 3;
    protected int              _state               = UI_STATE_BUTTON_NONE;

    protected ArrayList _callbacks = new ArrayList();
   
    /**
     * Standard constructor. The parent MUST be a frame window. Just like all
     * components.
     *
     * @param parent
     * @param typeName
     * @param textureSetName
     * @param text
     * @param x
     * @param y
     * @param width
     * @param height
     */
    public UIButton( UIFrameWindow parent, String typeName, String textureSetName, String text,
            Float x, Float y, Float width, Float height) {
        super( parent, text, x, y, width, height, typeName, textureSetName);
        _msgInterestFlags = UI_MOUSEMOVE | UI_MOUSELEFTUP | UI_MOUSELEFTDOWN;
    }

    protected void initGeometry() {
        AlphaState quadAlpha = DisplaySystem.getDisplaySystem().getRenderer().createAlphaState();
        quadAlpha.setBlendEnabled( true);
        quadAlpha.setSrcFunction( AlphaState.SB_SRC_ALPHA);
        quadAlpha.setDstFunction( AlphaState.DB_ONE_MINUS_SRC_ALPHA);
        quadAlpha.setTestEnabled( true);
        quadAlpha.setTestFunction( AlphaState.TF_GREATER);
        quadAlpha.setEnabled( true);
        // Get the coordinate set from the laf
        // JAVA50
//        UIButtonCoordSet coordSet = getControlFrame().getDefaultScheme()._uiButtonCoordSetsByName
//                .get( _typeName);
        UIButtonCoordSet coordSet = (UIButtonCoordSet) getControlFrame().getDefaultScheme()._uiButtonCoordSetsByName
                    .get( _typeName);
        LoggingSystem.getLogger().fine(
                "Button Info: " + _text + " : " + _typeName + " : " + _textureSetName);
        // Get the texture state from the laf
        // JAVA50
//        TextureState textureState = getControlFrame().getDefaultScheme()._uiTextureStatesByName
//                .get( _textureSetName);
        TextureState textureState = (TextureState) getControlFrame().getDefaultScheme()._uiTextureStatesByName
                    .get( _textureSetName);
        // textureState.getTexture().setWrap( Texture.WM_WRAP_S_WRAP_T);
        textureState.setEnabled( true);
        if( coordSet == null || textureState == null) {
            // we are going to build our button with no textures... just draw it
            // instead.
            LoggingSystem.getLogger().fine( "Creating non-textured button");
            // create 3 quads, 1 for each state, plus all the lines for the
            // borders.
            _upNode = createWindowNode( "UIButton._upNode.up." + _text + "." + System.currentTimeMillis(),
                    quadAlpha, getControlFrame().getDefaultScheme()._3dbackground,
                    getControlFrame().getDefaultScheme()._3dbackground, getControlFrame()
                            .getDefaultScheme()._3dbackground);
            _overNode = createWindowNode( "UIButton._overNode.over." + _text + "."
                    + System.currentTimeMillis(), quadAlpha,
                    getControlFrame().getDefaultScheme()._3dbackground, getControlFrame()
                            .getDefaultScheme()._border_dark,
                    getControlFrame().getDefaultScheme()._border_light);
            _downNode = createWindowNode( "UIButton._downNode.down." + _text + "."
                    + System.currentTimeMillis(), quadAlpha,
                    getControlFrame().getDefaultScheme()._3dbackground, getControlFrame()
                            .getDefaultScheme()._border_light,
                    getControlFrame().getDefaultScheme()._border_dark);
            _uiNode.attachChild( _upNode);
            _uiNode.attachChild( _overNode);
            _overNode.setForceCull( true);
            _uiNode.attachChild( _downNode);
            _downNode.setForceCull( true);
        } else {
            // build our button with textures and quads
            if( coordSet._default == null) {
                // multiple states
                LoggingSystem.getLogger().fine( "Creating multi state textured button");
                _upNode = createWindowNodeFromCoordSet( "UIButton._upNode.up." + _text + "."
                        + System.currentTimeMillis(), coordSet._up, quadAlpha, textureState);
                _overNode = createWindowNodeFromCoordSet( "UIButton._overNode.over." + _text + "."
                        + System.currentTimeMillis(), coordSet._over, quadAlpha, textureState);
                _downNode = createWindowNodeFromCoordSet( "UIButton._downNode.down." + _text + "."
                        + System.currentTimeMillis(), coordSet._down, quadAlpha, textureState);
                _uiNode.attachChild( _upNode);
                _uiNode.attachChild( _overNode);
                _overNode.setForceCull( true);
                _uiNode.attachChild( _downNode);
                _downNode.setForceCull( true);
            } else {
                // one state
                LoggingSystem.getLogger().fine( "Creating single state textured button");
                _upNode = createWindowNodeFromCoordSet( "UIButton._upNode.default." + _text + "."
                        + System.currentTimeMillis(), coordSet._default, quadAlpha, textureState);
                _uiNode.attachChild( _upNode);
            }
        }
        _textNode = createStdTextNode( _text, "default_black", 0, 0, true);
        _uiNode.attachChild( _textNode);
    }

    // JAVA50
//    protected void onMouseMove( UIEvent<Vector2f> event) {
    protected void onMouseMove( UIEvent event) {
        LoggingSystem.getLogger().finest( "UIFrameWindow.onMouseMove()");
        // JAVA50
        //if( hitTest( event.getInfo())) {
        if( hitTest( (Vector2f) event.getInfo())) {
            event.setProcessed();
            if( _state != UI_STATE_BUTTON_DOWN) {
                if( _state != UI_STATE_BUTTON_OVER) {
                    setStateOver();
                }
            }
        } else {
            if( _state == UI_STATE_BUTTON_OVER) {
                // JAVA50
                //if( hitTest( event.getInfo())) {
                if( hitTest( (Vector2f) event.getInfo())) {
                    setStateOver();
                } else {
                    setStateNone();
                }
            }
        }
    }

   
   
    // JAVA50
    //protected void onMouseLeftUp( UIEvent<Vector2f> event) {
    protected void onMouseLeftUp( UIEvent event) {
        LoggingSystem.getLogger().finest( "UIButton.onMouseLeftUp()");
        if( _state == UI_STATE_BUTTON_DOWN) {
            event.setProcessed();
            // JAVA50
            //if( hitTest( event.getInfo())) {
            if( hitTest( (Vector2f) event.getInfo())) {
                setStateOver();
            } else {
                setStateNone();
            }
        }
    }

    // JAVA50
    //protected void onMouseLeftDown( UIEvent<Vector2f> event) {
    protected void onMouseLeftDown( UIEvent event) {
        LoggingSystem.getLogger().finest( "UIButton.onMouseLeftDown()");
        // JAVA50
        //if( this.hitTest( event.getInfo())) {
        if( this.hitTest( (Vector2f) event.getInfo())) {
            event.setProcessed();
            if( _state != UI_STATE_BUTTON_DOWN) {
                onClick();
                setStateDown();
            }
        }
    }

    protected void setStateDown() {
        _upNode.setForceCull( true);
        if( _overNode != null)
            _overNode.setForceCull( true);
        if( _downNode != null)
            _downNode.setForceCull( false);
        this._uiNode.updateRenderState();
        _state = UI_STATE_BUTTON_DOWN;
    }

    protected void setStateOver() {
        LoggingSystem.getLogger().fine( "Setting state Over");
        _upNode.setForceCull( true);
        if( _overNode != null)
            _overNode.setForceCull( false);
        if( _downNode != null)
            _downNode.setForceCull( true);
        this._uiNode.updateRenderState();

        //Added to support mouse over events
        if (_state != UI_STATE_BUTTON_DOWN){
           onMouseOver();
        }
        _state = UI_STATE_BUTTON_OVER;       
    }

    protected void setStateNone() {
        _upNode.setForceCull( false);
        if( _overNode != null)
            _overNode.setForceCull( true);
        if( _downNode != null)
            _downNode.setForceCull( true);
        this._uiNode.updateRenderState();
        _state = UI_STATE_BUTTON_NONE;
    }

    /**
     * If you wish to use this method to get notification off the onClick
     * method then do not override the onClick method. Unless you know what
     * you are doing.
     * @param callback
     */   
    public void registerCallback( UIEventReceiver callback) {
        _callbacks.add( callback);
    }
   
    /**
     * Override this method to recieve callback notification of button
     * activation.<br>
     * Usage Example: <code>
     * button = new UIButton( window, "standard", "default", "Textured Button", 10.0f, 50.0f,
     *           200.0f, 40.0f) {
     *       public void onClick() {
     *           System.out.println( "Click!");
     *      }
     *  };
     * </code>
     */
    public void onClick() {
        for( int i =0 ; i < _callbacks.size(); i++) {       
            UIEventReceiver rec = (UIEventReceiver) _callbacks.get( i);
            rec.call( new UIEvent( 0, this));
        }
    }
   
    protected void onMouseOver(){
        for( int i =0 ; i < _callbacks.size(); i++) {       
            UIEventReceiver rec = (UIEventReceiver) _callbacks.get( i);
            rec.call( new UIEvent( 0, this));
        }
    };
   
    public static UIWindow createFromXML( UIFrameWindow parent, org.w3c.dom.Node winNode, UIEventReceiver receiver) throws Exception {
       
        String texset = XPathAPI.selectSingleNode( winNode, "textureset").getChildNodes().item( 0).getTextContent();
       
        String type = "alternate_non_type";
        try {
            type = XPathAPI.selectSingleNode( winNode, "type").getChildNodes().item( 0).getTextContent();
        } catch( Exception e) {
            // no error since this is not a required field
        }
        String text = "";
        try {
            text = XPathAPI.selectSingleNode( winNode, "text").getChildNodes().item( 0).getTextContent();
        } catch( Exception e) {
            // no error since this is not a required field
        }
        Float locx = Float.valueOf( XPathAPI.selectSingleNode( winNode, "locx").getChildNodes().item( 0).getTextContent());
        Float locy = Float.valueOf( XPathAPI.selectSingleNode( winNode, "locy").getChildNodes().item( 0).getTextContent());
        Float width = Float.valueOf( XPathAPI.selectSingleNode( winNode, "sizew").getChildNodes().item( 0).getTextContent());
        Float height = Float.valueOf( XPathAPI.selectSingleNode( winNode, "sizeh").getChildNodes().item( 0).getTextContent());
   
        UIButton button = new UIButton(  parent,
                type, texset, text, locx, locy, width, height);
       
        NodeIterator linkIter = XPathAPI.selectNodeIterator( winNode, "methodlink");
        org.w3c.dom.Node linkNode = linkIter.nextNode();
       
        while( linkNode != null) {
            String methodlinkname = linkNode.getChildNodes().item( 0).getTextContent();
           
            if( methodlinkname.equals( "onClick")) {
                button.registerCallback( receiver);
            }
           
            linkNode = linkIter.nextNode();
        }
       
        return button;
    }
}



I did it very quick and dirty, so maybe there's something I haven't considered, but this works for me. ;)

hi



just one little question :smiley:



is there some kind of tutorial

or example for using nui ??



thx a lot

cu gerch

There’s an example bundled with the source download.