Since the old thread probably won’t get any attention anymore, I will start a new one describing my current problems with Drag and Drop elements in detail.
First I have a custom Droppable which can store additional information. I use it to do actions when right-clicking on it:
[xml]
<controlDefinition name=“monsterDroppable” controller=“gui.MonsterDroppableControl”>
<panel childLayout=“center” id=“mainPanel” backgroundColor="#00000000" width=“49px” height=“49px”>
<control id="$droppableID" name=“droppable” width=“49px” height=“49px”>
<image filename=“Interface/ui/droppable.png”/>
</control>
<interact onSecondaryClick=“onRightClicked()” />
</panel>
</controlDefinition>
[/xml]
Its controller:
[java]
public class MonsterDroppableControl extends AbstractController implements MonsterDroppable {
/** The Draggable attached to this Droppable. /
private Element m_attachedDraggable;
/* The Monster currently dropped into this control. /
private Monster m_attachedMonster;
/* The underlying droppable */
private Droppable m_droppable;
private Nifty m_nifty;
private Screen m_screen;
@Override
public void bind(Nifty nifty, Screen screen, Element element, Properties parameter, Attributes controlDefinitionAttributes) {
super.bind(element);
element.setVisibleToMouseEvents(true);
m_nifty = nifty;
m_screen = screen;
m_droppable = element.findNiftyControl(controlDefinitionAttributes.get(“droppableID”), Droppable.class);
}
@Override
public void onStartScreen() {}
@Override
public boolean inputEvent(NiftyInputEvent inputEvent) {
return false;
}
@Override
public void addDraggable(final Monster monster) {
ControlBuilder buildDraggable = new ControlBuilder(“Draggable”) {{
childLayoutCenter();
width(“49px”);
height(“49px”);
control(new DraggableBuilder(“boxDraggable” + monster.getID()) {{
image(new ImageBuilder() {{
filename(Monster.MONSTERICON_PATH + monster.getID() + “.png”);
}});
}});
}};
if(m_attachedDraggable != null)
m_attachedDraggable.markForRemoval();
m_attachedMonster = monster;
m_attachedDraggable = buildDraggable.build(m_nifty, m_screen, m_droppable.getElement());
}
@Override
public Monster getMonster() {
return m_attachedMonster;
}
@Override
public void setMonster(Monster monster, Draggable draggable) {
if(m_attachedDraggable != null)
m_attachedDraggable.markForRemoval();
draggable.getElement().markForRemoval();
this.addDraggable(monster);
}
@Override
public void removeMonster() {
m_attachedMonster = null;
m_attachedDraggable = null;
}
/**
- Called when this draggable is right clicked on.
/
public void onRightClicked() {
if(m_attachedMonster != null)
GameClient.getInstance().showMonsterInformation(m_attachedMonster);
}
}
[/java]
I use this custom control in another custom control. The other one consists of 25 of these in a grid pattern.
[xml]
<controlDefinition name=“monsterBoxPage” controller=“evocri3Dclient.gui.MonsterBoxPageControl”>
<panel childLayout=“vertical” id=“mainPanel” backgroundColor="#00000000" width=“100%” height=“100%”>
<panel childLayout=“horizontal” backgroundColor="#00000000" width=“100%” height=“49px”>
<control id=“boxDroppable1” droppableID=“boxDroppable1” name=“monsterDroppable”/>
<control id=“boxDroppable2” droppableID=“boxDroppable2” name=“monsterDroppable”/>
<control id=“boxDroppable3” droppableID=“boxDroppable3” name=“monsterDroppable”/>
<control id=“boxDroppable4” droppableID=“boxDroppable4” name=“monsterDroppable”/>
<control id=“boxDroppable5” droppableID=“boxDroppable5” name=“monsterDroppable”/>
</panel>
<panel childLayout=“horizontal” backgroundColor="#00000000" width=“100%” height=“49px”>
<control id=“boxDroppable6” droppableID=“boxDroppable6” name=“monsterDroppable”/>
<control id=“boxDroppable7” droppableID=“boxDroppable7” name=“monsterDroppable”/>
<control id=“boxDroppable8” droppableID=“boxDroppable8” name=“monsterDroppable”/>
<control id=“boxDroppable9” droppableID=“boxDroppable9” name=“monsterDroppable”/>
<control id=“boxDroppable10” droppableID=“boxDroppable10” name=“monsterDroppable”/>
</panel>
<panel childLayout=“horizontal” backgroundColor="#00000000" width=“100%” height=“49px”>
<control id=“boxDroppable11” droppableID=“boxDroppable11” name=“monsterDroppable”/>
<control id=“boxDroppable12” droppableID=“boxDroppable12” name=“monsterDroppable”/>
<control id=“boxDroppable13” droppableID=“boxDroppable13” name=“monsterDroppable”/>
<control id=“boxDroppable14” droppableID=“boxDroppable14” name=“monsterDroppable”/>
<control id=“boxDroppable15” droppableID=“boxDroppable15” name=“monsterDroppable”/>
</panel>
<panel childLayout=“horizontal” backgroundColor="#00000000" width=“100%” height=“49px”>
<control id=“boxDroppable16” droppableID=“boxDroppable16” name=“monsterDroppable”/>
<control id=“boxDroppable17” droppableID=“boxDroppable17” name=“monsterDroppable”/>
<control id=“boxDroppable18” droppableID=“boxDroppable18” name=“monsterDroppable”/>
<control id=“boxDroppable19” droppableID=“boxDroppable19” name=“monsterDroppable”/>
<control id=“boxDroppable20” droppableID=“boxDroppable20” name=“monsterDroppable”/>
</panel>
<panel childLayout=“horizontal” backgroundColor="#00000000" width=“100%” height=“49px”>
<control id=“boxDroppable21” droppableID=“boxDroppable21” name=“monsterDroppable”/>
<control id=“boxDroppable22” droppableID=“boxDroppable22” name=“monsterDroppable”/>
<control id=“boxDroppable23” droppableID=“boxDroppable23” name=“monsterDroppable”/>
<control id=“boxDroppable24” droppableID=“boxDroppable24” name=“monsterDroppable”/>
<control id=“boxDroppable25” droppableID=“boxDroppable25” name=“monsterDroppable”/>
</panel>
</panel>
</controlDefinition>
[/xml]
Its controller is:
[java]
public class MonsterBoxPageControl extends AbstractController implements MonsterBoxPage {
/* The names of the Droppables where the monster icons are displayed in. /
private static final String DROPPABLE_NAMES = “boxDroppable”;
/* The Droppables where the monster icons are displayed in. */
private MonsterDroppable[] m_droppables;
private boolean m_firstSubscriberCall = true;
@Override
public void bind(Nifty nifty, Screen screen, Element element, Properties parameter, Attributes controlDefinitionAttributes) {
super.bind(element);
m_droppables = new MonsterDroppable[25];
for(int i = 0; i < 25; i++)
m_droppables = element.findNiftyControl(DROPPABLE_NAMES + (i + 1), MonsterDroppable.class);
}
@Override
public void onStartScreen() {}
@Override
public boolean inputEvent(NiftyInputEvent inputEvent) {
return false;
}
@Override
public void addMonster(final int position, final Monster monster) throws ArrayIndexOutOfBoundsException {
MonsterDroppable droppableToFill = m_droppables[position];
droppableToFill.addDraggable(monster);
}
@NiftyEventSubscriber(pattern=“boxDroppable[0-9]+”)
public void handleDragOperation(final String id, final DroppableDroppedEvent event) {
//This method gets called twice for each successful drag and drop operation. But I only need it once.
if(m_firstSubscriberCall) {
String sourceNumberString = event.getSource().getElement().getId().substring(12);
String targetNumberString = event.getTarget().getElement().getId().substring(12);
int sourceNumber = Integer.parseInt(sourceNumberString);
int targetNumber = Integer.parseInt(targetNumberString);
MonsterDroppable sourceDroppable = m_droppables[sourceNumber - 1];
MonsterDroppable targetDroppable = m_droppables[targetNumber - 1];
Monster sourceMonster = sourceDroppable.getMonster();
Monster targetMonster = targetDroppable.getMonster();
targetDroppable.setMonster(sourceMonster, event.getDraggable());
if(targetMonster != null) {
sourceDroppable.removeMonster();
sourceDroppable.addDraggable(targetMonster);
} else {
sourceDroppable.removeMonster();
}
}
m_firstSubscriberCall = !m_firstSubscriberCall;
}
}
[/java]
This control is being used in a simple window:
[xml]
<control title=“Monster Box” name=“window” id=“monsterBoxWindow” align=“left” valign=“top” hideOnClose=“true” revert=“false” height=“281px” width=“261px”>
<control name=“monsterBoxPage” id=“monsterBoxPage1”/>
</control>
[/xml]
I populate the box with 4 test monsters. A Monster is just a model class holding some information, like the icon name for the Draggable to display.
One Droppable should only hold a maximum of one monster. So when I drag a monster from one to the other and the other has one monster/icon it it already, they should switch. This is basically what I am trying to do with my code.
However there are a few problems: When a new Draggable is created and added to the Droppable, it is not initially rendered in the Droppable.
The Draggable switching code doesn’t work at all. It sometimes makes a Draggable disappear, it sometimes duplicates it and they are generally being placed in wrong positions.
Any idea what is wrong?