I am creating a file/folder browser with lemur.
If this already exists, please post a link.
Else, I will post code for it here.
I am creating a file/folder browser with lemur.
If this already exists, please post a link.
Else, I will post code for it here.
I donât know if anyone has created one yet. Writing one is on my to-do list but fairly low down. Today when I need file browsing I cheat and open a JFileChooser. (see SimArboreal Editor. )
Booya!
Itâs a bit crude but it works. Pictures will only show if they are inside the asset folder.
Hope you enjoy!
Usage:
Call this to open it:
FileBrowser.init(System.getProperty("user.dir"), new Callable<Object>() {
public Object call() {
return OnTextureChosen();
}
});
And have the method âOnTextureChosenâ look something like this:
public static Object OnTextureChosen() {
if(FileBrowser.isCanceled()) return null;
System.out.println(FileBrowser.getAssetPath());
Texture t = AssetManager.loadTexture(FileBrowser.getAssetPath());
return null;
}
The code:
package game.lemur;
import com.jme3.input.event.MouseButtonEvent;
import com.jme3.input.event.MouseMotionEvent;
import com.jme3.math.ColorRGBA;
import com.jme3.math.Vector3f;
import com.jme3.scene.Spatial;
import com.jme3.texture.Texture;
import com.simsilica.lemur.Button;
import com.simsilica.lemur.Command;
import com.simsilica.lemur.Container;
import com.simsilica.lemur.Label;
import com.simsilica.lemur.event.CursorEventControl;
import com.simsilica.lemur.event.DragHandler;
import com.simsilica.lemur.TextField;
import com.simsilica.lemur.component.TbtQuadBackgroundComponent;
import com.simsilica.lemur.event.MouseEventControl;
import com.simsilica.lemur.event.MouseListener;
import com.simsilica.lemur.geom.TbtQuad;
import game.Jme;
import java.io.File;
import java.util.concurrent.Callable;
/**
*
* @author Eric Bourque
*/
public class FileBrowser {
private static boolean canceled = false;
public static boolean isCanceled() {
return canceled;
}
private static boolean done = false;
public static boolean isDone() {
return done;
}
private static String selectedPath;
public static String getSelectedPath() {
return selectedPath;
}
private static String assetPath;
public static String getAssetPath() {
return assetPath;
}
private static Container window;
private static String currentFolder;
private static Label selected;
private static Callable<Object> endCall;
public FileBrowser(){
}
public static void show(){
Jme.guiNode().attachChild(window);
}
public static void hide(){
window.removeFromParent();
}
private static void gotoParentDir(){
File f = new File(currentFolder);
if(f.getParentFile() == null)return;
currentFolder = f.getParentFile().getPath()+"\\";
refresh();
}
private static void gotoChildDir(String child){
child = child.substring(2);
currentFolder = currentFolder +child+"\\";
System.out.println(currentFolder);
refresh();
}
private static void refresh(){
Vector3f pos = window.getLocalTranslation();
window.removeFromParent();
init(currentFolder, endCall);
window.setLocalTranslation(pos);
}
public static void init(String path, Callable<Object> func){
endCall = func;
currentFolder = path;
window = new Container();
CursorEventControl.addListenersToSpatial(window, new DragHandler());
Jme.guiNode().attachChild(window);
window.setLocalTranslation((int)(Jme.getScreenWidth()/2),(int)(Jme.getScreenHeight()/2),0);
Container c = window.addChild(new Container());
c.addChild(new Label("File Selector 1.0"));
TextField tf = c.addChild(new TextField(LemurConst.style));
tf.setText(path);
if(selectedPath != null){
try{
int i = selectedPath.indexOf("assets")+7;
assetPath = selectedPath.substring(i).replace("\\", "/");
if(selectedPath.endsWith(".png") || selectedPath.endsWith(".jpg") || selectedPath.endsWith(".bmp")){
Container imagePreview = c.addChild(new Container());
System.out.println("AssetPath: " + assetPath);
Texture t = Jme.assetManager().loadTexture(assetPath);
TbtQuadBackgroundComponent tbt = new TbtQuadBackgroundComponent(new TbtQuad(200, 200), t);
imagePreview.setBackground(tbt);
imagePreview.setPreferredSize(new Vector3f(200,200,0));
}
}catch(Exception e){}
}
Button b = c.addChild(new Button("Back"));
b.addClickCommands(new Command<Button>() {
@Override
public void execute( Button source ) {
gotoParentDir();
}
});
c = window.addChild(new Container());
File folder = new File(currentFolder);
String[] list = folder.list();
for (int i = 0; i < list.length; i++) {
File file = new File(path + list[i]);
if (file.isDirectory()) {
//Label l = ;
addClickListener(c.addChild(new Label("./" + list[i])), true);
//CursorEventControl.addListenersToSpatial(l, new CursorMotionEvent());
}
}
for (int i = 0; i < list.length; i++) {
File file = new File(path + list[i]);
if (!file.isDirectory()) {
Label l = c.addChild(new Label(list[i]));
if(selectedPath != null && selectedPath.equals(currentFolder + list[i])){
l.setColor(ColorRGBA.White);
if(selected != null)
selected.setColor(new ColorRGBA(0.5f, 0.75f, 0.75f, 0.85f)); //glass
selected = l;
}
addClickListener(l, false);
}
}
b = c.addChild(new Button("Ok"));
b.addClickCommands(new Command<Button>() {
@Override
public void execute( Button source ) {
done = true;
try{
endCall.call();
}catch(Exception e){}
hide();
}
});
b = c.addChild(new Button("Cancel"));
b.addClickCommands(new Command<Button>() {
@Override
public void execute( Button source ) {
canceled = true;
try{
endCall.call();
}catch(Exception e){}
hide();
}
});
}
private static void addClickListener(Spatial s, boolean isFolder) {
MouseEventControl.addListenersToSpatial(s,
new MouseListener() {
@Override
public void mouseButtonEvent(MouseButtonEvent mbe, Spatial target, Spatial capture) {
System.out.println("Button");
selectedPath = "";
if(target != capture)return;
if(isFolder){
gotoChildDir(((Label)capture).getText());
}else{
selectedPath = currentFolder +((Label)capture).getText();
System.out.println("Selected path: "+selectedPath);
refresh();
}
}
@Override
public void mouseEntered(MouseMotionEvent mme, Spatial target, Spatial capture) {
if((Label)target != selected)
((Label)target).setColor(ColorRGBA.Cyan);
}
@Override
public void mouseExited(MouseMotionEvent mme, Spatial target, Spatial capture) {
if((Label)target != selected)
((Label)target).setColor(new ColorRGBA(0.5f, 0.75f, 0.75f, 0.85f)); //glass
}
@Override
public void mouseMoved(MouseMotionEvent mme, Spatial target, Spatial capture) {
//System.out.println("Motion");
}
});
}
}
I would like to improve this with a scrolling window but I donât know how yetâŚ
Just finished! Really hope you like it, tell me what you think
Heheh⌠glad you got it working. Itâs very⌠âfunctionalâ.
I have to go but later tonight I may give some tips on neatening up your UI a bit if you are interested.
Sure! Did it in 3 hours so itâs bound to need a bit of that
If this is something many may want to use, what is the best way for me to make it publicly available?
I think it might be better to organize it as a series of subpanels.
So something like the following which Iâll do in a pseudo-notation that hopefully you can follow:
container(BorderLayout) {
north: container(SpringGridLayout(Axis.X, Axis.Y)) {
label(path), button(back)
}
center: container(SpringGridLayout(Axis.X, Axis.Y)) {
listBox(files), label(imagePrevies)
}
south: container(SpringGridLayout(Axis.X, Axis.Y)) {
button(ok), button(cancel)
}
}
Note the spring grid layouts that reverse the axis order so that by default children go into new columns instead of new rows.
Also, if you let the user specify their own Actions when creating the file selector then you can just use ActionButtons in the bottom panel and the caller can then 100% define what the Ok and Cancel (or any number of buttons) do. Though I guess thatâs tricky if you us âOkâ for drilling into directories, also.
Anyway, those are my random thoughts. If I ever do a real version then it will be quite a bit different as Iâll use a grid or table for the file list instead of a listbox, etc⌠Your approach is the easiest way to get the most functionality for the effort, though.
The OK button is for validating the final selection. Folders are entered by left clicking a directory. (dirs have a ./ infront)
Label color changes on mouse over and stay white if clicked.
I send a callable method to initialise the window so that the user can decide what the method the ok button does when clicked.
The downside of my browser is that there is a tiny gap inbetween labels where nothing gets selected but it should work better when the listbox is ready.
Thanks for the tips.
P.S. What timezone are you in? Iâm in GMT+1
GMT-5 but I sleep at odd times.
You can already use ListBox⌠didnât realize you werenât.
Ok, will check it outâŚ
I canât run SimArboreal in Jme3.1 because I am missing librairies.
The link for all the ressources is broken or private: http://hub.jmonkeyengine.org/forum/topic/simarboreal-formerly-tree-editor/
import com.simsilica.arboreal.mesh.BillboardedLeavesMeshGenerator;
import com.simsilica.arboreal.mesh.SkinnedTreeMeshGenerator;
import com.simsilica.arboreal.mesh.Vertex;
import com.simsilica.builder.Builder;
import com.simsilica.builder.BuilderReference;
import org.progeeks.json.JsonParser;
import org.progeeks.json.JsonPrinter;
And this:
I really want to check out how it works
You need to also check out SimArboreal and Pager. Probably SimFX also.
The jars for meta-jb-json should be in the tree somewhere.
Edit: note, Iâve never ported this to 3.1 yet. To run it, you might be better off downloading the full exe distro.
Just made it work on 3.1, minus the shadows, video recordings and a few other pixies
Now I can learn how to use Lemur properly. Thanks allot! Great job btw
P.S. how many trees do you think I can spawn if I make like 10 diff models and use instancing? Are we talking thousands or 10s of thousands? will the Wind cause lag?
I took a look at property panel. Love it, âŚbut still needs a bit of code to access public fields.
For example, I want slider to change color in a ColorRGBA.
This class has public floats a,r,g,b, but I guess the invoke only works for getters and setters right?
when I set this up:
properties.addFloatProperty("Amb_B", Player.currentSolarSystem.sun.amb.getColor(), "b", 0f, 2f, 0.1f);
I get:
Caused by: java.lang.RuntimeException: No suche property:b on:class com.jme3.math.ColorRGBA
So, anyway to do this without adding a bunch more floats to control color?
Try addFloatField() instead of addFloatProperty().
The wind wonât cause lag, really, as itâs down in the shader⌠shouldnât make any difference.
Instancing gives back performance but itâs not perfect. The driver still has to do per-object setup so itâs not as free as say batching, but it does use a lot less memory.
In the IsoSurface demo you can see how it performs with a lot of trees. Even with LOD there is a limit.