Nifty - keyboard event handling on text element

Hi!

So I have a screen, some Nifty controls on there like Sliders, TextFields etc and also, at the very bottom, a simple Nifty text element which is basically serving as a button for me, which means it is clickable and calls a method that changes the screen. I also made sure to enable its “focusable” attribute.

Now when the screen starts, the keyboard focus is on one of the Nifty controls as it should be, and as expected, by pressing the TAB button, the focus moves to the next control and so on. Once my text element gets the focus though, pressing TAB has no effect anymore, although the focus should actually move to the first element again. Also, pressing Enter has no effect (like it has on e.g. a CheckBox)

I’ve looked at the Nifty control definitions and don’t find any special code which deals with keyboard input, so how come keyboard handling (at least of the pre-defined default keys) works fine with Nifty Controls but not with my text element?

What do I have to do that my text element reacts to keyboard input, in particular the pre-defined default keys like TAB, Enter etc.?

Thanks in advance!
KB

Does it behave differently if you use a Button control? If there’s a specific reason you’re not using a Button control have you tried using a Label control and making it focusable?

It works just fine with a Button control.
I’m not using a Button or a Label control because I wanna have a particular design (font, font size etc.) and use as few Nifty Controls as possible. For example Controls won’t allow me to change the font and stuff like that. That’s why I’m using text elements.

You can change the font on both a button and a label. Both buttons and labels use the text element as a sub-element in their control structure. I’m not positive, but I think I remember reading that the text element was generally less functional than a label control so it might be that it was never meant to work with focus traversal, but I certainly don’t know.

You’re actually right. Still, I can’t modify the existing controls exactly as I need them (JUST the text, no visible panel in the background).

I’ve considered creating a custom control and took the ButtonControl definition as a reference but finally end up with the same issue - it just won’t react on keyboard input.

First I thought I found the solution to my problem, namely including the attribute inputMapping=“de.lessvoid.nifty.input.mapping.MenuInputMapping” to my controlDefinition, just like it’s also the case in the ButtonControl definition, but turns out it doesn’t change a thing.

You can set the background color/image of both a label and button.

Here’s an example label style with a background image:

<?xml version="1.0" encoding="UTF-8"?>
<nifty-styles>
  <style id="listlabel-highlight" base="base-font">
    <attributes backgroundImage="Interface/UI/SelectionBox_Blue.png" imageMode="resize:5,6,5,5,5,6,5,6,5,6,5,5" align="center" textLineHeight="14px" textMinHeight="14px" /> 
  </style>
</nifty-styles>

Here’s an example button style that modifies the font, background image and hover/click effects:

<?xml version="1.0" encoding="UTF-8"?>
<nifty-styles>
  <!-- +++++++++++++++++++++++++++++++++++++ -->
  <!-- style for the button background panel -->
  <!-- +++++++++++++++++++++++++++++++++++++ -->
  <style id="whitebuttonHD#panel">
    <attributes backgroundImage="Interface/UI/Buttons/Button_WhiteHD.png" imageMode="sprite-resize:64,30,0,23,18,23,12,23,18,23,6,23,18,23,12" paddingLeft="8px" paddingRight="8px" paddingTop="7px" paddingBottom="8px" childLayout="center" visibleToMouse="true" focusable="false"/>
    <effect>
      <onHover name="imageOverlay" filename="Interface/UI/Buttons/Button_WhiteHD.png" imageMode="sprite-resize:64,30,1,23,18,23,12,23,18,23,6,23,18,23,12" post="true" />
      <onClick name="imageOverlay" filename="Interface/UI/Buttons/Button_WhiteHD.png" imageMode="sprite-resize:64,30,2,23,18,23,12,23,18,23,6,23,18,23,12" post="true" />
    </effect>
  </style>

  <!-- +++++++++++++++++++++++++++++++++++++ -->
  <!-- style for the button text -->
  <!-- +++++++++++++++++++++++++++++++++++++ -->
  <style id="whitebuttonHD#text">
    <attributes font="Interface/Fonts/SpaceAge_18.fnt" align="center" valign="center" textHAlign="center" textVAlign="center" visibleToMouse="false" color="#555555"/>
  </style>
</nifty-styles>

Thanks a lot! It nearly works now. Here’s my style definition:

<?xml version="1.0" encoding="UTF-8"?>
<nifty-styles>
    <!-- +++++++++++++++++++++++++++++++++++++ -->
    <!-- style for the button background panel -->
    <!-- +++++++++++++++++++++++++++++++++++++ -->
    <style id="menubutton#panel">
        <attributes childLayout="center" visibleToMouse="true" focusable="false" />
    </style>

    <!-- +++++++++++++++++++++++++++++++++++++ -->
    <!-- style for the button text -->
    <!-- +++++++++++++++++++++++++++++++++++++ -->
    <style id="menubutton#text">
        <attributes font="Images.GUI/prisma60.fnt" align="center"
          valign="center" textHAlign="center" textVAlign="center"
          visibleToMouse="false" color="#ffff" base="button-font"/>
        <effect>
            <onHover name="textColor" color="#999f" />
            <onFocus name="textColor" color="#f00f" />
        </effect>
    </style>
</nifty-styles>

The problem is now: Due to the onHover effect on the text, the “visibleToMouse” attribute is automatically set to true, no matter what I specify for it. Now when I give my button an id, say “menubutton” and click it, the actual id that’s submitted to the eventbus is “menubutton#text”. Any way around that? This clashes with how I implemented the interaction, I basically need the unaltered id to be submitted.

Yeah an element needs to be visible to the mouse in order for any effects associated with the mouse to work. What you can do is change the effects on the text element to onCustom effects and in the panel element add in an onHover and onFocus effect that activates the respective custom effect on the text element:

<?xml version="1.0" encoding="UTF-8"?>
<nifty-styles>
    <!-- +++++++++++++++++++++++++++++++++++++ -->
    <!-- style for the button background panel -->
    <!-- +++++++++++++++++++++++++++++++++++++ -->
    <style id="menubutton#panel">
        <attributes childLayout="center" visibleToMouse="true" focusable="true" />
        <effect>
            <onHover name="hover" targetElement="#text" />
            <onFocus name="focus" targetElement="#text" />
        </effect>
    </style>

    <!-- +++++++++++++++++++++++++++++++++++++ -->
    <!-- style for the button text -->
    <!-- +++++++++++++++++++++++++++++++++++++ -->
    <style id="menubutton#text">
        <attributes font="Images.GUI/prisma60.fnt" align="center"
          valign="center" textHAlign="center" textVAlign="center"
          visibleToMouse="false" color="#ffff" base="button-font"/>
        <effect>
            <onCustom customKey="hover" name="textColor" color="#999f" />
            <onCustom customKey="focus" name="textColor" color="#f00f" />
        </effect>
    </style>
</nifty-styles>

I’m not 100% positive on the value for targetElement since I haven’t really used this type of effect myself. At any rate I changed the focusable=“false” value in the panel element attributes to focusable=“true” since you’re using an onFocus effect I assume you want this control to be able to receive keyboard focus, but if not then just change it back to false.

As for the id that’s submitted to the eventbus, if it’s still giving you trouble you could:

int index = id.indexOf("#");
id = (index >= 0) ? id.substring(0, index) : id;