diff --git a/src/gui/ListGUI.java b/src/gui/ListGUI.java index 2a14e5b..52df156 100644 --- a/src/gui/ListGUI.java +++ b/src/gui/ListGUI.java @@ -44,7 +44,6 @@ public class ListGUI extends JPanel { JButton addListElementEntity; JButton removeListElementEntity; JButton addPicEntity; - String pathImage; JList list; JScrollPane scroll; ActionListener removeEntity; @@ -92,9 +91,9 @@ public class ListGUI extends JPanel { return (String) list.getSelectedValue(); } - - //ТУТ МОЖЕТ БЫТЬ ТРАБЛ Т,К, СОЗДАНИЕ ХИТБОКСА - ХАРДКОД. Он может быть не только Rectangle - public void addListElement(String name,String solid) throws DuplicateEntryException { + + public void addListElement(String name, String solid) throws DuplicateEntryException { + // плейсхолдеры для новых хитбоксов и дроубоксов, иначе всё валится с NPE Hitbox hitbox = new Hitbox(); Drawbox drawbox = new Drawbox(); @@ -108,13 +107,15 @@ public class ListGUI extends JPanel { } public void updateList() { - String[] nameList = createNameList(); testModel.removeAllElements(); - for (String name : nameList) - testModel.addElement(name); + + for (Entity e: Project.getInstance()) { + testModel.addElement(e.getName()); - pathImage = Project.getInstance().getXMLPath(); - createImageMap(nameList); + // Create and store JList items icons in a map to prevent their unneccessary re-creation + iconMap.put(e.getName(), createListIconFromSprite( e.getImage() )); + } + list.updateUI(); } @@ -137,7 +138,7 @@ public class ListGUI extends JPanel { } private final float iconMaxWidth = 40, iconMaxHeight = 40; - public Icon imageScaling(BufferedImage image) { + private Icon createListIconFromSprite(BufferedImage image) { CustomIcon icon = null; try { int imageWidth = image.getWidth(), imageHeight = image.getHeight(); @@ -185,14 +186,6 @@ public class ListGUI extends JPanel { } } - private void createImageMap(String[] nameList) { - for (int i = 0; i < nameList.length; i++) { - String name = nameList[i]; - BufferedImage image = Project.getInstance().loadImageByName(name); - iconMap.put(name, imageScaling(image)); - } - } - private JButton createButton(int width,int height,ActionListener listener,String pathImage) { JButton button = new JButton(new ImageIcon(pathImage)); button.setSize(110, 46); diff --git a/src/model/Entity.java b/src/model/Entity.java index 4914c41..b596c48 100644 --- a/src/model/Entity.java +++ b/src/model/Entity.java @@ -8,11 +8,14 @@ public class Entity { private Hitbox thisHitbox; private String type; private BufferedImage thisImage; - //private + private int width = 0; + private int height = 0; + - public Entity(String name,String drawbox,String hitbox) { + public Entity(String name, String drawbox, String hitbox, BufferedImage sprite) { thisName = new String(name); thisDrawbox = new Drawbox(drawbox); + setImage(sprite); // updates entity width and height, should be called before creating hitbox thisHitbox = new Hitbox(hitbox); thisHitbox.setOwnerEntity(this); } @@ -44,10 +47,6 @@ public class Entity { thisHitbox = outHitbox; }; - public void setImage(BufferedImage outImage) { - thisImage = outImage; - }; - public String getName() { return thisName; }; @@ -60,9 +59,19 @@ public class Entity { return thisHitbox; }; + /** @return BufferedImage object or null if an image is not set */ public BufferedImage getImage() { return thisImage; - }; + } + + /** NOTE: Image setter updates entity width and height */ + public void setImage(BufferedImage sprite) { + this.thisImage = sprite; + if(sprite != null) { + width = sprite.getHeight(); + height = sprite.getHeight(); + } + } public void PrintEntity() { System.out.println("---------------------"); @@ -71,4 +80,20 @@ public class Entity { this.thisHitbox.printToConsole(); System.out.println("---------------------"); } + + public int getWidth() { + return width; + } + + public void setWidth(int width) { + this.width = width; + } + + public int getHeight() { + return height; + } + + public void setHeight(int height) { + this.height = height; + } } diff --git a/src/repository/Project.java b/src/repository/Project.java index e163b65..9ceeee3 100644 --- a/src/repository/Project.java +++ b/src/repository/Project.java @@ -132,6 +132,7 @@ public class Project implements Iterable, EntityDrawboxChangedListener { factory = DocumentBuilderFactory.newInstance(); builder = factory.newDocumentBuilder(); document = builder.parse(new File(path+fileName)); + // TODO: remove this from Project, it should not know SHIT about MainGUI if(Launcher.getMainGUI() != null) // at the first program launch, main gui creates list gui before static link to main gui is set Launcher.getMainGUI().setTitle("Hitbox/Drawbox Editor: " + path + fileName); // Получение списка всех элементов objecttype внутри корневого элемента (getDocumentElement возвращает ROOT элемент XML файла). @@ -144,14 +145,18 @@ public class Project implements Iterable, EntityDrawboxChangedListener { } } - // эта колбаса парсит сущности из XML в программные объекты внутри модели, является частью внутренней кухни так что обычно её не нужно трогать - private void parsingElementXMLtoElementList(String entityName,Node objecttype) { + private void parsingElementXMLtoElementList(String entityName, Node objecttype) { String newDrawbox = null; String newHitbox = null; - String type = null; + String type = null; + BufferedImage sprite = null; Element element = (Element)objecttype; NodeList propertyElements = element.getElementsByTagName("property"); - if(propertyElements!=null) { + if(propertyElements != null) { + + // do not lazy load images here - Hitbox parser needs real image sizes + sprite = loadImageByName(entityName); + for(int i = 0; i < propertyElements.getLength(); i++) { Element property = (Element)propertyElements.item(i); String propertyName = property.getAttribute("name"); @@ -168,7 +173,8 @@ public class Project implements Iterable, EntityDrawboxChangedListener { break; } } - Entity e = new Entity(entityName,newDrawbox,newHitbox); + + Entity e = new Entity(entityName, newDrawbox, newHitbox, sprite); e.setType(type); listEntity.add(e); } @@ -179,9 +185,6 @@ public class Project implements Iterable, EntityDrawboxChangedListener { * XML-файл. Возвращает null если изображение не найдено. * */ public BufferedImage loadImageByName(String name) { - //TODO: сделать кеширование - не дело подгружать одну и ту же картинку по десять раз! - - String path = Project.getInstance().getXMLPath(); String extension = "png"; // TODO: изображения следует подгружать в отдельном потоке! @@ -210,6 +213,9 @@ public class Project implements Iterable, EntityDrawboxChangedListener { if(getEntityByName(e.getName()) != null) throw new DuplicateEntryException("The entity with the name '" + e.getName() + "' already exists!"); + //TODO: move image loading to AddListElementEntityListener and make it lazy + e.setImage(loadImageByName(e.getName())); + listEntity.add(e); Element objecttypeElement = document.createElement("objecttype"); @@ -366,8 +372,9 @@ public class Project implements Iterable, EntityDrawboxChangedListener { return null; } - //https://stackoverflow.com/a/64659614/6929164 - public static void stripEmptyElements(Node node) + // https://stackoverflow.com/a/64659614/6929164 + // new empty lines will appear on every XML save without this function + private static void stripEmptyElements(Node node) { NodeList children = node.getChildNodes(); for(int i = 0; i < children.getLength(); ++i) {