Nifty chat control not wrapping

I’m trying to integrate the nifty-chat control (from nifty-default-controls → nifty-controls → nifty-chat-control.xml) but am having a problem with wrapping. The nifty-chat-line control definition has a label with wrap=“true”:



[xml]<controlDefinition name=“nifty-chat-line”>

<panel childLayout=“horizontal” width=“100%” align=“center” style="">

<image id="#chat-line-icon" width="$chatLineIconWidth" height="$chatLineIconHeight" />

<control id="#chat-line-text" name=“label” align=“left” textHAlign=“left” height="$chatLineHeight" width="" wrap=“true” />

</panel>

</controlDefinition>[/xml]

(I’ve also added the width="
" while testing, though without success)



The problems is, if I write a chat line that is longer than the listbox is wide, it doesn’t wrap the text, instead it displays a horizontal scrollbar (which is disabled in the xml with horizontal=“off”) and just displays the text in one line.



Has anyone seen this behaviour before or does anyone know what could be the problem?

I’m using nifty 1.3 as part of JME3.

Has anyone been able to get wrapping to work in the chat-control?

The label does not support wrap if i read code correctly. The text standard control does.

I suggest you override this control definition using a standard text element with the same id (i see they use the TextRenderer of the Element without using any Label interface function, so this should work).

I also suggest you file a bug report in nifty project.

I mean the text standard element <text id="mytext’’ text=“Text” />

Thank you for the suggestion.

Replacing the label with a text element worked well, but unfortunately it made no difference with regards to the wrapping.

Maybe because of the height of the chat field? You already have it as a variable, what happens when you make it larger?

Thank you. Unfortunately that makes the chat lines higher (making the chat box higher) but still displays the text in the middle of the text/label element (I’ve tested both) unwrapped (cut off).

but you set the “wrap” attribute still?

Maybe you should set a fixed width for the text element for wrapping to work, I remember such condition was needed for wrapping in Button for instance. You can setup the widht in the element control definition or, better, in its controller upon binding (element.setConstraintWidth(new SizeValue(width+“px”)); where width is the width of the chat area minus icon width).



Anyway, have you filled a bug report because it soes not work in examples either and that is definitely a bug. It should work correctly. Those are new user-contributed controls that might need reviewing.

Yes, it has been set to true all the time.

Perhaps it has got something to do with the label/text being updated dynamically by the chat-control?

Does dynamically added text wrap itself currently or is it just for static text?

I guess I’ll have to look into that.

it is not updated dynamically. A new chatline control is created when a new line is about to be displayed.

You can also try to remove the height constraint of the text element, allowing it to grow if needed.

Thanks. I tried removing the height constraint of the text, but then the chatlines disappeared entirely, even if I explicitly set height vales for all the parent elements. I guess I’ll have to take a closer look at the source for the controllers and converter to see if I can find where the wrapping is ignored/failing. Perhaps it needs to wrap, check the new height and resize the chatline control before adding it to the listbox.

I’ve filled the bug report, it should proably be fixed in next versions.



You can read the nifty manual (complete manual with pdf, can be downlaoded from the nifty blog) there is some example with wrapping working in there.

1 Like

I solved it with a ScrollPanel instead of a ListBox in the nifty chat control, only requiring a few modifications.

Here’s my solution for anyone who’s interested:



The modified control definition:

[xml]<controlDefinition name=“chat-control” style=“chat-control” controller=“com.limewoodGames.holicity.client.gui.controllers.NiftyChatControl” lines=“10” sendLabel=“Send” chatLineIconWidth=“25px” chatLineIconHeight=“25px” chatLineHeight=“27px”>

<panel style="#mainPanel">

<panel style="#chatPanel">

<panel style="#chatArea">

<control id="#chatBox" name=“scrollPanel” style=“nifty-listbox” vertical=“true” horizontal=“false” autoScroll=“bottom” width=“100%” height=“100%”>

</control>

</panel>

<panel style="#playerArea">

<control id="#playerList" name=“listBox” vertical=“on” horizontal=“off” selection=“Disabled” displayItems="$lines" viewConverterClass=“de.lessvoid.nifty.controls.chatcontrol.ChatBoxViewConverter”>

<control name=“nifty-chat-line” chatLineIconWidth="$chatLineIconWidth" chatLineIconHeight="$chatLineIconHeight" chatLineHeight="$chatLineHeight" />

</control>

</panel>

</panel>

<panel style="#spacer"/>

<panel style="#chatTextArea">

<control id="#chat-text-input" name=“textfield” />

<control id="#chat-text-button" name=“button” width="" label="$sendLabel">

<interact onClick=“sendText()” />

</control>

</panel>

</panel>

</controlDefinition>[/xml]



The modified controller:

[java]

[…]



private ScrollPanel scrollPanel;

private List<ChatEntryModelClass> chatLines = new ArrayList<ChatEntryModelClass>();



/**

  • Default constructor.

    */

    public NiftyChatControl() {

    }



    /**
  • {@inheritDoc}

    */

    @Override

    public final void bind(final Nifty niftyParam, final Screen screenParam, final Element newElement, final Properties properties, final Attributes controlDefinitionAttributes) {

    super.bind(newElement);

    LOGGER.fine("binding chat control");

    nifty = niftyParam;



    PanelBuilder panel = new PanelBuilder() {{

    childLayout(ChildLayoutType.Vertical);

    width(percentage(100));

    x("0px");

    y("0px");

    align(Align.Left);

    valign(VAlign.Bottom);

    padding("2px");

    paddingRight("15px");

    }};

    scrollPanel = getScrollPanel(CHAT_BOX);

    panel.build(niftyParam, nifty.getCurrentScreen(), scrollPanel.getElement().findElementByName("#nifty-scrollpanel-child-root"));



    // this buffer is needed because in some cases the entry is added to either list before the emelent is bound.

    final ListBox<ChatEntryModelClass> playerList = getListBox(PLAYER_LIST);

    while (!playerBuffer.isEmpty()) {

    ChatEntryModelClass player = playerBuffer.remove(0);

    LOGGER.log(Level.FINE, "adding player {0}", (playerList.itemCount() + 1));

    playerList.addItem(player);

    playerList.sortAllItems(playerComparator);

    playerList.showItem(player);

    }

    while (!linesBuffer.isEmpty()) {

    ChatEntryModelClass line = linesBuffer.remove(0);

    receivedChatLine(line.getLabel(), line.getIcon(), line.getStyle());

    }

    }



    […]



    /**
  • {@inheritDoc}

    */

    @Override

    public void receivedChatLine(final String text, NiftyImage icon, String style) {

    if (linesBuffer.isEmpty()) {

    try {

    final Element chatBox = scrollPanel.getElement();

    LOGGER.log(Level.FINE, "adding message {0}", (chatBox.getElements().size() + 1));

    PanelBuilder pb = new PanelBuilder() {{

    width(percentage(100));

    childLayout(ChildLayoutType.Horizontal);

    paddingTop("2px");

    image(new ImageBuilder() {{

    width("25px");

    height("25px");

    filename("Interface/player_icon.png");

    }});

    text(new TextBuilder() {{

    text(text);

    font("Interface/Fonts/freesans-12.fnt");

    textHAlign(Align.Left);

    wrap(true);

    width(percentage(100));

    }});

    }};

    Element contents = chatBox.findElementByName("#nifty-scrollpanel-child-root").getElements().get(0);

    Element panel = pb.build(nifty, nifty.getCurrentScreen(), contents);

    if(icon != null) {

    panel.getElements().get(0).getRenderer(ImageRenderer.class).setImage(icon);

    }

    // Autoscroll to bottom

    scrollPanel.getElement().layoutElements();

    scrollPanel.setUp(0, 5, 0, 50, AutoScroll.OFF);

    scrollPanel.setVerticalPos(contents.getHeight());

    // Add line to lines list

    chatLines.add(new ChatEntryModelClass(text, icon, style));

    } catch (NullPointerException npe) {

    linesBuffer.add(new ChatEntryModelClass(text, icon, style));

    }

    } else {

    linesBuffer.add(new ChatEntryModelClass(text, icon, style));

    }

    }



    […]



    /**
  • {@inheritDoc}

    */

    @Override

    public List<ChatEntryModelClass> getLines() {

    return chatLines;

    }



    […]



    @SuppressWarnings(“unchecked”)

    private ListBox<ChatEntryModelClass> getListBox(final String name) {

    return (ListBox<ChatEntryModelClass>) getElement().findNiftyControl(name, ListBox.class);

    }



    private ScrollPanel getScrollPanel(final String name) {

    return (ScrollPanel) getElement().findNiftyControl(name, ScrollPanel.class);

    }



    […][/java]



    It’s not the most flexible solution, but it works for now for my purposes and perhaps it might be of help to someone else too.
2 Likes