this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

StarRodMain: add draggable panes and Dock

+380 -76
+2
src/main/java/app/Environment.java
··· 28 28 import javax.imageio.ImageIO; 29 29 import javax.swing.ImageIcon; 30 30 import javax.swing.SwingUtilities; 31 + import javax.swing.UIManager; 31 32 32 33 import org.apache.commons.io.FileExistsException; 33 34 import org.apache.commons.io.FileUtils; ··· 244 245 // UIManager.put("TabbedPane.tabWidthMode", "compact"); 245 246 // UIManager.put("TabbedPane.showTabSeparators", true); 246 247 // UIManager.put("TabbedPane.tabSeparatorsFullHeight", true); 248 + UIManager.put("SplitPaneDivider.style", "plain"); 247 249 248 250 if (fromJar && gitBuildTag != null && mainConfig.getBoolean(Options.CheckForUpdates)) 249 251 checkForUpdate();
+62 -74
src/main/java/app/StarRodMain.java
··· 28 28 import javax.swing.JProgressBar; 29 29 import javax.swing.JScrollBar; 30 30 import javax.swing.JScrollPane; 31 + import javax.swing.JSplitPane; 31 32 import javax.swing.JTextArea; 32 33 import javax.swing.ScrollPaneConstants; 33 34 import javax.swing.SwingConstants; 34 35 import javax.swing.SwingUtilities; 35 36 import javax.swing.SwingWorker; 37 + import javax.swing.UIManager; 36 38 import javax.swing.WindowConstants; 37 39 38 40 import org.apache.commons.io.FilenameUtils; ··· 44 46 import app.build.WslNixOsEnvironment; 45 47 import app.config.Options; 46 48 import app.input.InvalidInputException; 49 + import app.pane.Dock; 47 50 import assets.AssetHandle; 48 51 import assets.AssetManager; 49 52 import assets.ExpectedAsset; ··· 62 65 import game.worldmap.WorldMapEditor; 63 66 import net.miginfocom.swing.MigLayout; 64 67 import util.Logger; 65 - import util.Logger.Listener; 66 68 import util.Priority; 67 69 68 70 public class StarRodMain extends StarRodFrame 69 71 { 72 + // Layout constants 73 + private static final int MIN_PANE_WIDTH = 250; 74 + private static final int MIN_WINDOW_WIDTH = MIN_PANE_WIDTH * 3; 75 + private static final int MIN_WINDOW_HEIGHT = 600; 76 + private static final int MIN_DOCK_HEIGHT = 100; 77 + 70 78 public static void main(String[] args) throws InterruptedException 71 79 { 72 80 boolean isCommandLine = args.length > 0 || GraphicsEnvironment.isHeadless(); ··· 82 90 new StarRodMain(); 83 91 } 84 92 } 85 - 86 - private final JTextArea consoleTextArea; 87 - private final Listener consoleListener; 88 - 89 - private final JPanel progressPanel; 90 - private final JLabel progressLabel; 91 - private final JProgressBar progressBar; 92 93 93 94 private boolean taskRunning = false; 94 95 ··· 98 99 { 99 100 setTitle(Environment.decorateTitle("Star Rod")); 100 101 setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 102 + setMinimumSize(new Dimension(MIN_WINDOW_WIDTH, MIN_WINDOW_HEIGHT)); 101 103 102 - setMinimumSize(new Dimension(480, 32)); 103 - setLocationRelativeTo(null); 104 104 105 105 // Display current project path (read-only, restart app to change projects) 106 106 JLabel projectPathLabel = new JLabel(Environment.getProjectDirectory().getAbsolutePath()); ··· 136 136 globalsEditorButton.addActionListener((e) -> { 137 137 action_openGlobalsEditor(); 138 138 }); 139 - buttons.add(spriteEditorButton); 139 + buttons.add(globalsEditorButton); 140 140 141 141 JButton worldEditorButton = new JButton("World Map Editor"); 142 142 trySetIcon(worldEditorButton, ExpectedAsset.ICON_WORLD_EDITOR); ··· 162 162 }); 163 163 buttons.add(themesMenuButton); 164 164 165 + // Extract Data button 165 166 JButton extractDataButton = new JButton("Extract Map Data"); 166 167 trySetIcon(extractDataButton, ExpectedAsset.ICON_EXTRACT); 167 168 SwingUtils.setFontSize(extractDataButton, 12); ··· 170 171 }); 171 172 buttons.add(extractDataButton); 172 173 174 + // Build Project button 173 175 JButton buildProjectButton = new JButton("Build Project"); 174 176 trySetIcon(buildProjectButton, ExpectedAsset.ICON_GOLD); 175 177 SwingUtils.setFontSize(buildProjectButton, 12); ··· 178 180 }); 179 181 buttons.add(buildProjectButton); 180 182 181 - // not ready 182 - /* 183 - JButton captureThumbnailsButton = new JButton("Capture Thumbnails"); 184 - trySetIcon(captureThumbnailsButton, ExpectedAsset.ICON_THEMES); 185 - SwingUtils.setFontSize(captureThumbnailsButton, 12); 186 - captureThumbnailsButton.addActionListener((e) -> { 187 - action_captureThumbnails(); 188 - }); 189 - buttons.add(captureThumbnailsButton); 190 - */ 191 - 183 + // Open directories buttons 192 184 JButton openConfigDirButton = new JButton("Open Config Dir"); 193 185 trySetIcon(openConfigDirButton, ExpectedAsset.ICON_SILVER); 194 186 SwingUtils.setFontSize(openConfigDirButton, 12); ··· 205 197 }); 206 198 buttons.add(openProjectDirButton); 207 199 208 - consoleTextArea = new JTextArea(); 209 - consoleTextArea.setRows(8); 210 - consoleTextArea.setEditable(false); 211 - 212 - JScrollPane consoleScrollPane = new JScrollPane(consoleTextArea); 213 - consoleScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED); 214 - // consoleScrollPane.setVisible(false); 215 - 216 - consoleListener = (msg) -> { 217 - consoleTextArea.append(msg.text + System.lineSeparator()); 218 - JScrollBar vertical = consoleScrollPane.getVerticalScrollBar(); 219 - vertical.setValue(vertical.getMaximum()); 220 - }; 221 - 222 - JMenuItem copyText = new JMenuItem("Copy Text"); 223 - JPopupMenu copyTextMenu = new JPopupMenu(); 224 - copyTextMenu.add(copyText); 225 - consoleScrollPane.setComponentPopupMenu(copyTextMenu); 226 - copyText.addActionListener(e -> { 227 - StringSelection stringSelection = new StringSelection(consoleTextArea.getText()); 228 - Clipboard cb = Toolkit.getDefaultToolkit().getSystemClipboard(); 229 - cb.setContents(stringSelection, null); 230 - }); 231 - 232 - progressLabel = new JLabel("Waiting..."); 233 - progressBar = new JProgressBar(); 234 - progressBar.setIndeterminate(true); 235 - progressPanel = new JPanel(); 236 - progressPanel.setLayout(new MigLayout("fillx")); 237 - progressPanel.add(progressLabel, "wrap"); 238 - progressPanel.add(progressBar, "grow, wrap 8"); 239 - progressPanel.setVisible(false); 240 - 200 + // Window close handling 241 201 setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); 242 202 addWindowListener(new java.awt.event.WindowAdapter() { 243 203 @Override ··· 260 220 } 261 221 }); 262 222 263 - setLayout(new MigLayout("fillx, ins 16 16 16 16, wrap 2, hidemode 3", "[sg main, grow]8[sg main, grow]")); 223 + // Left pane - buttons panel 224 + JPanel leftPane = new JPanel(new MigLayout("fill, ins 8, wrap 1")); 225 + leftPane.add(new JLabel("Project:"), "split 2"); 226 + leftPane.add(projectPathLabel, "pushx, growx, gapbottom 8, wrap"); 264 227 265 - add(new JLabel("Project:"), "span, split 2"); 266 - add(projectPathLabel, "pushx, growx, wrap, gapbottom 8"); 228 + JPanel buttonsPanel = new JPanel(new MigLayout("fillx, wrap 1, hidemode 3")); 229 + buttonsPanel.add(mapEditorButton, "growx"); 230 + buttonsPanel.add(spriteEditorButton, "growx"); 231 + buttonsPanel.add(globalsEditorButton, "growx"); 232 + buttonsPanel.add(msgEditorButton, "growx"); 233 + buttonsPanel.add(worldEditorButton, "growx"); 234 + buttonsPanel.add(imageEditorButton, "growx"); 235 + buttonsPanel.add(themesMenuButton, "growx"); 236 + buttonsPanel.add(extractDataButton, "growx"); 237 + buttonsPanel.add(openConfigDirButton, "growx"); 238 + buttonsPanel.add(openProjectDirButton, "growx"); 239 + buttonsPanel.add(buildProjectButton, "growx, gaptop 8"); 267 240 268 - add(mapEditorButton, "grow"); 269 - add(spriteEditorButton, "grow"); 241 + leftPane.add(buttonsPanel, "growx"); 242 + leftPane.setMinimumSize(new Dimension(MIN_PANE_WIDTH, 0)); 270 243 271 - add(globalsEditorButton, "grow"); 272 - add(msgEditorButton, "grow"); 244 + // Middle pane - placeholder for now 245 + JPanel middlePane = new JPanel(new MigLayout("fill, ins 8")); 246 + middlePane.add(new JLabel("Middle Pane"), "center"); 247 + middlePane.setMinimumSize(new Dimension(MIN_PANE_WIDTH, 0)); 273 248 274 - add(worldEditorButton, "grow"); 275 - add(imageEditorButton, "grow"); 249 + // Right pane - placeholder for now 250 + JPanel rightPane = new JPanel(new MigLayout("fill, ins 8")); 251 + rightPane.add(new JLabel("Right Pane"), "center"); 252 + rightPane.setMinimumSize(new Dimension(MIN_PANE_WIDTH, 0)); 276 253 277 - add(themesMenuButton, "grow"); 278 - add(extractDataButton, "grow"); 254 + // Create horizontal split panes (left | middle | right) 255 + JSplitPane leftMiddleSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftPane, middlePane); 256 + leftMiddleSplit.setOneTouchExpandable(false); 257 + leftMiddleSplit.setDividerSize(1); 258 + leftMiddleSplit.setResizeWeight(0.0); // Left pane stays fixed, middle gets extra space 279 259 280 - add(openConfigDirButton, "grow"); 281 - add(openProjectDirButton, "grow"); 260 + JSplitPane mainHorizontalSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftMiddleSplit, rightPane); 261 + mainHorizontalSplit.setOneTouchExpandable(false); 262 + mainHorizontalSplit.setDividerSize(1); 263 + mainHorizontalSplit.setResizeWeight(1.0); // Middle gets priority, right stays fixed 282 264 283 - add(buildProjectButton, "grow, span, gaptop 8"); 265 + // Dock (bottom panel) 266 + Dock dock = new Dock(); 267 + dock.setMinimumSize(new Dimension(0, MIN_DOCK_HEIGHT)); 268 + 269 + // Create vertical split pane (middlePane | dock) 270 + JSplitPane verticalSplit = new JSplitPane(JSplitPane.VERTICAL_SPLIT, mainHorizontalSplit, dock); 271 + verticalSplit.setOneTouchExpandable(false); 272 + verticalSplit.setDividerSize(4); 273 + verticalSplit.setResizeWeight(1.0); // Give most space to top pane 284 274 285 - add(progressPanel, "grow, span, wrap, gap top 8"); 286 - add(consoleScrollPane, "grow, span"); 275 + // Layout 276 + setLayout(new MigLayout("fill, ins 0")); 277 + add(verticalSplit, "grow, push"); 287 278 288 279 pack(); 289 - setResizable(false); 290 280 setLocationRelativeTo(null); 291 281 setVisible(true); 292 - 293 - Logger.addListener(consoleListener); 294 282 } 295 283 296 284 public interface EditorWork
+69
src/main/java/app/pane/Dock.java
··· 1 + package app.pane; 2 + 3 + import java.awt.BorderLayout; 4 + 5 + import javax.swing.BorderFactory; 6 + import javax.swing.JPanel; 7 + import javax.swing.JScrollPane; 8 + import javax.swing.JTabbedPane; 9 + import javax.swing.JTextArea; 10 + 11 + import util.Logger; 12 + import util.ui.AssetsPanel; 13 + import util.ui.ThemedIcon; 14 + 15 + public class Dock extends JPanel 16 + { 17 + private JTabbedPane tabbedPane; 18 + private JTextArea logTextArea; 19 + 20 + public Dock() 21 + { 22 + // Create vertical tabbed pane with dock styling 23 + tabbedPane = new JTabbedPane(JTabbedPane.LEFT); 24 + tabbedPane.putClientProperty("JTabbedPane.tabType", "card"); 25 + tabbedPane.putClientProperty("JTabbedPane.hasFullBorder", true); 26 + 27 + // Add File Explorer tab with AssetsPanel 28 + AssetsPanel assetsPanel = new AssetsPanel(); 29 + tabbedPane.addTab(null, ThemedIcon.FOLDER_OPEN_16, assetsPanel); 30 + 31 + // Add Logs tab with text area 32 + logTextArea = createLogTextArea(); 33 + JScrollPane logScrollPane = new JScrollPane(logTextArea); 34 + logScrollPane.setBorder(null); 35 + tabbedPane.addTab(null, ThemedIcon.TERMINAL_16, logScrollPane); 36 + Logger.addListener(new LogListener(logTextArea)); 37 + 38 + // Layout 39 + setLayout(new BorderLayout()); 40 + add(tabbedPane, BorderLayout.CENTER); 41 + } 42 + 43 + private JTextArea createLogTextArea() 44 + { 45 + JTextArea textArea = new JTextArea(); 46 + textArea.setEditable(false); 47 + // Add horizontal padding using EmptyBorder 48 + textArea.setBorder(BorderFactory.createEmptyBorder(4, 8, 4, 8)); 49 + return textArea; 50 + } 51 + 52 + private static class LogListener implements Logger.Listener 53 + { 54 + private final JTextArea textArea; 55 + 56 + public LogListener(JTextArea textArea) 57 + { 58 + this.textArea = textArea; 59 + } 60 + 61 + @Override 62 + public void post(Logger.Message msg) 63 + { 64 + textArea.append(msg.text + System.lineSeparator()); 65 + // Auto-scroll to bottom 66 + textArea.setCaretPosition(textArea.getDocument().getLength()); 67 + } 68 + } 69 + }
-1
src/main/java/app/project/ui/ProjectSwitcherDialog.java
··· 105 105 { 106 106 super("Star Rod Launcher"); 107 107 setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); 108 - setIconImage(Environment.getDefaultIconImage()); 109 108 110 109 addWindowListener(new WindowAdapter() { 111 110 @Override
+13
src/main/java/assets/AssetHandle.java
··· 19 19 this.assetDir = assetDir; 20 20 assetPath = path.replaceAll("\\\\", "/"); // resolve all paths with '/' as separator 21 21 } 22 + 23 + public String getAssetName() { 24 + int slash = assetPath.lastIndexOf('/'); 25 + if (slash >= 0) { 26 + return assetPath.substring(slash + 1); 27 + } else { 28 + return assetPath; 29 + } 30 + } 31 + 32 + public String getAssetDescription() { 33 + return null; 34 + } 22 35 }
+11
src/main/java/assets/ui/MapAsset.java
··· 9 9 import app.Environment; 10 10 import assets.AssetHandle; 11 11 import assets.AssetManager; 12 + import game.map.Map; 12 13 import util.Logger; 13 14 14 15 public class MapAsset extends AssetHandle ··· 62 63 Logger.logError(e.getMessage()); 63 64 desc = "READ ERROR"; 64 65 } 66 + } 67 + 68 + @Override 69 + public String getAssetName() { 70 + return Map.deriveName(this); 71 + } 72 + 73 + @Override 74 + public String getAssetDescription() { 75 + return desc; 65 76 } 66 77 }
+16 -1
src/main/java/game/map/editor/MapEditor.java
··· 25 25 import java.util.IdentityHashMap; 26 26 import java.util.LinkedList; 27 27 import java.util.List; 28 + import java.util.concurrent.CountDownLatch; 28 29 import java.util.concurrent.LinkedBlockingQueue; 29 30 30 31 import javax.imageio.ImageIO; ··· 3708 3709 3709 3710 /** 3710 3711 * Shows dialog to select alternate texture archive. 3712 + * Must be called outside runInContext to avoid deadlock with EDT. 3711 3713 * @return the selected texture name, or null if user cancelled 3712 3714 */ 3713 3715 private String promptForTextureArchive() ··· 3960 3962 if (newMap == null) 3961 3963 return; 3962 3964 3965 + final CountDownLatch edtLatch = thumbnailMode ? null : new CountDownLatch(1); 3966 + final Map guiMap = newMap; 3963 3967 final boolean[] texturesLoaded = { false }; 3964 3968 final boolean[] reloadTexturesFlag = { false }; 3965 3969 ··· 4009 4013 if (!thumbnailMode) { 4010 4014 SwingUtilities.invokeLater(() -> { 4011 4015 updateWindowTitle(); 4012 - gui.setMap(map); 4016 + gui.setMap(guiMap); 4017 + edtLatch.countDown(); 4013 4018 }); 4014 4019 4015 4020 if (map.editorData != null) { ··· 4028 4033 } 4029 4034 } 4030 4035 }); 4036 + 4037 + // Wait for invokeLater above to complete 4038 + if (edtLatch != null) { 4039 + try { 4040 + edtLatch.await(); 4041 + } 4042 + catch (InterruptedException e) { 4043 + Thread.currentThread().interrupt(); 4044 + } 4045 + } 4031 4046 4032 4047 loading = false; 4033 4048 }
+97
src/main/java/util/ui/AssetsPanel.java
··· 1 + package util.ui; 2 + 3 + import java.awt.Dimension; 4 + import java.awt.FlowLayout; 5 + import java.awt.Graphics; 6 + import java.awt.Graphics2D; 7 + import java.awt.event.MouseAdapter; 8 + import java.awt.event.MouseEvent; 9 + import java.util.ArrayList; 10 + import java.util.Collection; 11 + 12 + import javax.swing.JLabel; 13 + import javax.swing.JPanel; 14 + import javax.swing.JScrollPane; 15 + import javax.swing.UIManager; 16 + 17 + import assets.AssetManager; 18 + import assets.ui.MapAsset; 19 + import assets.AssetHandle; 20 + import net.miginfocom.swing.MigLayout; 21 + import util.Logger; 22 + 23 + public class AssetsPanel extends JPanel { 24 + private Collection<? extends AssetHandle> results; 25 + 26 + private JPanel resultsPanel; 27 + 28 + public AssetsPanel() { 29 + super(); 30 + 31 + try { 32 + results = AssetManager.getMapSources().stream().map(asset -> new MapAsset(asset)).toList(); 33 + } catch (Exception e) { 34 + Logger.logError("Failed to load assets: " + e.getMessage()); 35 + results = new ArrayList<>(); 36 + } 37 + 38 + setLayout(new MigLayout("ins 4")); 39 + 40 + resultsPanel = new JPanel(new WrapLayout(FlowLayout.LEFT, 0, 0)); 41 + for (AssetHandle asset : results) { 42 + //resultsPanel.add(createAssetItem(asset)); 43 + } 44 + 45 + JScrollPane scrollPane = new JScrollPane(resultsPanel); 46 + scrollPane.setBorder(null); 47 + 48 + add(scrollPane, "grow, push"); 49 + } 50 + 51 + private JPanel createAssetItem(AssetHandle asset) { 52 + JPanel panel = new JPanel(new MigLayout("ins 0, fill")); 53 + 54 + panel.setPreferredSize(new Dimension(80, 80)); 55 + panel.setOpaque(true); 56 + 57 + JLabel icon = new JLabel(ThemedIcon.PACKAGE_24); 58 + // TODO: worker to load thumbnail with an asset method (e.g. MapAsset can return the thumbnail made by action_captureThumbnails) 59 + 60 + JLabel name = new JLabel(asset.getAssetName()); 61 + name.setPreferredSize(new Dimension(80, 20)); 62 + 63 + panel.add(icon, "wrap"); 64 + panel.add(name, "align center, wmax 80"); 65 + 66 + String desc = asset.getAssetDescription(); 67 + if (desc != null && !desc.isEmpty()) { 68 + panel.setToolTipText(desc); 69 + } 70 + 71 + panel.addMouseListener(new MouseAdapter() { 72 + @Override 73 + public void mouseEntered(MouseEvent e) { 74 + panel.setBackground(UIManager.getColor("Table.selectionBackground")); 75 + } 76 + 77 + @Override 78 + public void mouseExited(MouseEvent e) { 79 + panel.setBackground(null); 80 + } 81 + 82 + @Override 83 + public void mouseClicked(MouseEvent e) { 84 + if (e.getClickCount() == 2) { 85 + // Double-click to open 86 + openAsset(asset); 87 + } 88 + } 89 + }); 90 + 91 + return panel; 92 + } 93 + 94 + private void openAsset(AssetHandle asset) { 95 + // TODO 96 + } 97 + }
+9
src/main/java/util/ui/ThemedIcon.java
··· 71 71 72 72 public static final FlatSVGIcon REFRESH_24 = getIcon("refresh_24"); 73 73 public static final FlatSVGIcon REFRESH_16 = REFRESH_24.derive(16, 16); 74 + 75 + public static final FlatSVGIcon TERMINAL_24 = getIcon("terminal"); 76 + public static final FlatSVGIcon TERMINAL_16 = TERMINAL_24.derive(16, 16); 77 + 78 + public static final FlatSVGIcon FOLDER_OPEN_24 = getIcon("folder-open"); 79 + public static final FlatSVGIcon FOLDER_OPEN_16 = FOLDER_OPEN_24.derive(16, 16); 80 + 81 + public static final FlatSVGIcon PACKAGE_24 = getIcon("package"); 82 + public static final FlatSVGIcon PACKAGE_16 = PACKAGE_24.derive(16, 16); 74 83 }
+98
src/main/java/util/ui/WrapLayout.java
··· 1 + package util.ui; 2 + 3 + import java.awt.*; 4 + import javax.swing.*; 5 + 6 + /** 7 + * A FlowLayout that supports wrapping of components to new lines. 8 + * TODO: make not terrible and slow 9 + */ 10 + public class WrapLayout extends FlowLayout { 11 + public WrapLayout() { 12 + super(); 13 + } 14 + 15 + public WrapLayout(int align) { 16 + super(align); 17 + } 18 + 19 + public WrapLayout(int align, int hgap, int vgap) { 20 + super(align, hgap, vgap); 21 + } 22 + 23 + @Override 24 + public Dimension preferredLayoutSize(Container target) { 25 + return layoutSize(target, true); 26 + } 27 + 28 + @Override 29 + public Dimension minimumLayoutSize(Container target) { 30 + Dimension minimum = layoutSize(target, false); 31 + minimum.width -= (getHgap() + 1); 32 + return minimum; 33 + } 34 + 35 + private Dimension layoutSize(Container target, boolean preferred) { 36 + synchronized (target.getTreeLock()) { 37 + int targetWidth = target.getSize().width; 38 + if (targetWidth == 0) { 39 + targetWidth = Integer.MAX_VALUE; 40 + } 41 + 42 + int hgap = getHgap(); 43 + int vgap = getVgap(); 44 + Insets insets = target.getInsets(); 45 + int horizontalInsetsAndGap = insets.left + insets.right + (hgap * 2); 46 + int maxWidth = targetWidth - horizontalInsetsAndGap; 47 + 48 + Dimension dim = new Dimension(0, 0); 49 + int rowWidth = 0; 50 + int rowHeight = 0; 51 + 52 + int nmembers = target.getComponentCount(); 53 + 54 + for (int i = 0; i < nmembers; i++) { 55 + Component m = target.getComponent(i); 56 + 57 + if (m.isVisible()) { 58 + Dimension d = preferred ? m.getPreferredSize() : m.getMinimumSize(); 59 + 60 + if (rowWidth + d.width > maxWidth && rowWidth > 0) { 61 + addRow(dim, rowWidth, rowHeight); 62 + rowWidth = 0; 63 + rowHeight = 0; 64 + } 65 + 66 + if (rowWidth != 0) { 67 + rowWidth += hgap; 68 + } 69 + 70 + rowWidth += d.width; 71 + rowHeight = Math.max(rowHeight, d.height); 72 + } 73 + } 74 + 75 + addRow(dim, rowWidth, rowHeight); 76 + 77 + dim.width += horizontalInsetsAndGap; 78 + dim.height += insets.top + insets.bottom + vgap * 2; 79 + 80 + Container scrollPane = SwingUtilities.getAncestorOfClass(JScrollPane.class, target); 81 + if (scrollPane != null && target.isValid()) { 82 + dim.width -= (hgap + 1); 83 + } 84 + 85 + return dim; 86 + } 87 + } 88 + 89 + private void addRow(Dimension dim, int rowWidth, int rowHeight) { 90 + dim.width = Math.max(dim.width, rowWidth); 91 + 92 + if (dim.height > 0) { 93 + dim.height += getVgap(); 94 + } 95 + 96 + dim.height += rowHeight; 97 + } 98 + }
+1
src/main/resources/icon/folder-open.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-folder-open-icon lucide-folder-open"><path d="m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2"/></svg>
+1
src/main/resources/icon/package.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-package-icon lucide-package"><path d="M11 21.73a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73z"/><path d="M12 22V12"/><polyline points="3.29 7 12 12 20.71 7"/><path d="m7.5 4.27 9 5.15"/></svg>
+1
src/main/resources/icon/terminal.svg
··· 1 + <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="lucide lucide-terminal-icon lucide-terminal"><path d="M12 19h8"/><path d="m4 17 6-6-6-6"/></svg>