From 47e545cbc7603fa0407986bc925b2db341bd75de Mon Sep 17 00:00:00 2001 From: downthecrop Date: Fri, 24 Oct 2025 18:43:16 -0700 Subject: [PATCH] More helpers/DRY --- .../kotlin/KondoKit/ComponentExtensions.kt | 14 ++ .../src/main/kotlin/KondoKit/Helpers.kt | 5 +- .../kotlin/KondoKit/components/ButtonPanel.kt | 44 ++-- .../KondoKit/components/IconComponent.kt | 9 +- .../KondoKit/components/PopupMenuComponent.kt | 18 +- .../kotlin/KondoKit/components/SearchField.kt | 9 +- .../KondoKit/components/SettingsPanel.kt | 228 ++++++++---------- .../KondoKit/components/ToggleSwitch.kt | 7 +- .../kotlin/KondoKit/components/UiStyler.kt | 74 ++++++ .../kotlin/KondoKit/components/ViewHeader.kt | 3 +- .../kotlin/KondoKit/components/WidgetPanel.kt | 9 +- .../src/main/kotlin/KondoKit/plugin.kt | 12 +- .../main/kotlin/KondoKit/views/BaseView.kt | 7 +- .../kotlin/KondoKit/views/LootTrackerView.kt | 43 +--- .../KondoKit/views/ReflectiveEditorView.kt | 21 +- .../KondoKit/views/ViewLayoutHelpers.kt | 11 - .../kotlin/KondoKit/views/XPTrackerView.kt | 39 +-- 17 files changed, 264 insertions(+), 289 deletions(-) create mode 100644 plugin-playground/src/main/kotlin/KondoKit/ComponentExtensions.kt create mode 100644 plugin-playground/src/main/kotlin/KondoKit/components/UiStyler.kt diff --git a/plugin-playground/src/main/kotlin/KondoKit/ComponentExtensions.kt b/plugin-playground/src/main/kotlin/KondoKit/ComponentExtensions.kt new file mode 100644 index 0000000..ecb57ce --- /dev/null +++ b/plugin-playground/src/main/kotlin/KondoKit/ComponentExtensions.kt @@ -0,0 +1,14 @@ +package KondoKit + +import java.awt.Component +import java.awt.Dimension + +fun T.setFixedSize(width: Int, height: Int): T = + setFixedSize(Dimension(width, height)) + +fun T.setFixedSize(size: Dimension): T { + preferredSize = size + minimumSize = size + maximumSize = size + return this +} diff --git a/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt b/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt index ab31c94..dfca49f 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/Helpers.kt @@ -12,6 +12,7 @@ import java.lang.reflect.Type import java.util.* import java.util.Timer import javax.swing.* +import KondoKit.setFixedSize object Helpers { // Convenience helper for loading resources relative to the KondoKit plugin class @@ -35,9 +36,7 @@ object Helpers { componentPosition: String = BorderLayout.NORTH ): ImageCanvasComponents { val imageCanvas = ImageCanvas(bufferedImage).apply { - preferredSize = size - minimumSize = size - maximumSize = size + setFixedSize(size) this.size = size this.background = background } diff --git a/plugin-playground/src/main/kotlin/KondoKit/components/ButtonPanel.kt b/plugin-playground/src/main/kotlin/KondoKit/components/ButtonPanel.kt index 716ac67..b397fc7 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/components/ButtonPanel.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/components/ButtonPanel.kt @@ -4,6 +4,8 @@ import KondoKit.ViewConstants import KondoKit.plugin.Companion.TITLE_BAR_COLOR import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.secondaryColor +import KondoKit.components.UiStyler.button +import KondoKit.components.UiStyler.ButtonDefaults import java.awt.* import javax.swing.* @@ -18,29 +20,25 @@ class ButtonPanel( background = WIDGET_COLOR } - fun addButton(text: String, action: () -> Unit): JButton { - val button = JButton(text).apply { - background = TITLE_BAR_COLOR - foreground = secondaryColor + fun addButton(text: String, action: () -> Unit): JButton = + createAndAddButton(text = text, action = action) + + fun addIcon(icon: Icon, action: () -> Unit): JButton = + createAndAddButton(icon = icon, action = action) + + private fun createAndAddButton( + text: String? = null, + icon: Icon? = null, + action: () -> Unit + ): JButton { + val defaults = ButtonDefaults( + background = TITLE_BAR_COLOR, + foreground = secondaryColor, font = ViewConstants.FONT_RUNESCAPE_SMALL_14 - addActionListener { - action() - } + ) + + return button(text = text, icon = icon, defaults = defaults, onClick = action).also { + add(it) } - add(button) - return button } - - fun addIcon(icon: Icon, action: () -> Unit): JButton { - val button = JButton(icon).apply { - background = TITLE_BAR_COLOR - foreground = secondaryColor - font = ViewConstants.FONT_RUNESCAPE_SMALL_14 - addActionListener { - action() - } - } - add(button) - return button - } -} \ No newline at end of file +} diff --git a/plugin-playground/src/main/kotlin/KondoKit/components/IconComponent.kt b/plugin-playground/src/main/kotlin/KondoKit/components/IconComponent.kt index 3b57304..c695976 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/components/IconComponent.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/components/IconComponent.kt @@ -2,13 +2,13 @@ package KondoKit.components import KondoKit.ImageCanvas import KondoKit.SpriteToBufferedImage +import KondoKit.setFixedSize import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.primaryColor import KondoKit.plugin.Companion.secondaryColor import plugin.api.API import java.awt.BorderLayout import java.awt.Color -import java.awt.Dimension import javax.swing.BorderFactory import javax.swing.JPanel @@ -36,10 +36,7 @@ class IconComponent( ) imageCanvas = ImageCanvas(bufferedImageSprite).apply { - val size = Dimension(iconWidth, iconHeight) - preferredSize = size - maximumSize = size - minimumSize = size + setFixedSize(iconWidth, iconHeight) background = if (useThemeColors) WIDGET_COLOR else Color.WHITE } @@ -57,4 +54,4 @@ class IconComponent( fun applyThemeColors() { updateFillColor(WIDGET_COLOR) } -} \ No newline at end of file +} diff --git a/plugin-playground/src/main/kotlin/KondoKit/components/PopupMenuComponent.kt b/plugin-playground/src/main/kotlin/KondoKit/components/PopupMenuComponent.kt index 56d543f..4126898 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/components/PopupMenuComponent.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/components/PopupMenuComponent.kt @@ -1,8 +1,7 @@ package KondoKit.components -import KondoKit.ViewConstants +import KondoKit.components.UiStyler.menuItem import KondoKit.plugin.Companion.POPUP_BACKGROUND -import KondoKit.plugin.Companion.POPUP_FOREGROUND import javax.swing.JMenuItem import javax.swing.JPopupMenu @@ -13,15 +12,8 @@ class PopupMenuComponent : JPopupMenu() { } fun addMenuItem(text: String, action: () -> Unit): JMenuItem { - val menuItem = JMenuItem(text).apply { - font = ViewConstants.FONT_RUNESCAPE_SMALL_16 - background = POPUP_BACKGROUND - foreground = POPUP_FOREGROUND - addActionListener { - action() - } - } - add(menuItem) - return menuItem + val item = menuItem(text = text, onClick = action) + add(item) + return item } -} \ No newline at end of file +} diff --git a/plugin-playground/src/main/kotlin/KondoKit/components/SearchField.kt b/plugin-playground/src/main/kotlin/KondoKit/components/SearchField.kt index 4f7ddda..be21524 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/components/SearchField.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/components/SearchField.kt @@ -3,6 +3,7 @@ package KondoKit.components import KondoKit.ImageCanvas import KondoKit.ViewConstants import KondoKit.SpriteToBufferedImage +import KondoKit.setFixedSize import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.secondaryColor import KondoKit.plugin.StateManager.focusedView @@ -27,22 +28,18 @@ class SearchField( private val bufferedImageSprite = SpriteToBufferedImage.getBufferedImageFromSprite(API.GetSprite(1423)) // MAG_SPRITE private val imageCanvas = bufferedImageSprite.let { ImageCanvas(it).apply { - preferredSize = ViewConstants.DIMENSION_SMALL_ICON + setFixedSize(ViewConstants.DIMENSION_SMALL_ICON) size = preferredSize - minimumSize = preferredSize - maximumSize = preferredSize fillColor = WIDGET_COLOR } } init { val dimension = Dimension(fieldWidth, fieldHeight) - preferredSize = dimension + setFixedSize(dimension) background = WIDGET_COLOR foreground = secondaryColor font = ViewConstants.FONT_ARIAL_PLAIN_14 - minimumSize = dimension - maximumSize = dimension isFocusable = true focusTraversalKeysEnabled = false diff --git a/plugin-playground/src/main/kotlin/KondoKit/components/SettingsPanel.kt b/plugin-playground/src/main/kotlin/KondoKit/components/SettingsPanel.kt index d803b92..6fe212e 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/components/SettingsPanel.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/components/SettingsPanel.kt @@ -3,6 +3,8 @@ package KondoKit.components import KondoKit.Helpers import KondoKit.Helpers.FieldNotifier import KondoKit.ViewConstants +import KondoKit.components.UiStyler +import KondoKit.setFixedSize import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.primaryColor import KondoKit.plugin.Companion.secondaryColor @@ -10,6 +12,7 @@ import plugin.Plugin import java.awt.* import java.awt.event.MouseAdapter import java.awt.event.MouseEvent +import java.lang.reflect.Field import java.util.* import java.util.Timer import javax.swing.* @@ -36,18 +39,7 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() { field.isAccessible = true // Get the "Exposed" annotation specifically and retrieve its description, if available - val exposedAnnotation = field.annotations.firstOrNull { annotation -> - annotation.annotationClass.simpleName == "Exposed" - } - - val description = exposedAnnotation?.let { annotation -> - try { - val descriptionField = annotation.annotationClass.java.getMethod("description") - descriptionField.invoke(annotation) as String - } catch (e: NoSuchMethodException) { - "" // No description method, return empty string - } - } ?: "" + val description = field.exposedDescription() val fieldPanel = JPanel().apply { layout = GridBagLayout() @@ -104,7 +96,7 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() { } // Check if the field is a HashMap - field.type == HashMap::class.java || field.type.simpleName == "HashMap" -> { + field.isHashMapType() -> { inputComponent = createHashMapEditor(field, plugin, fieldNotifier) isHashMapEditor = true } @@ -141,42 +133,45 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() { fieldPanel.add(inputComponent, gbc) // Add apply button for non-HashMap editors - val applyButton = JButton("\u2714").apply { - maximumSize = Dimension(Int.MAX_VALUE, 8) + val applyButton = UiStyler.button( + text = "\u2714", + onClick = { + try { + val newValue = when (inputComponent) { + is JCheckBox -> inputComponent.isSelected + is JComboBox<*> -> inputComponent.selectedItem + is JSpinner -> inputComponent.value + is JTextField -> Helpers.convertValue(field.type, field.genericType, inputComponent.text) + else -> throw IllegalArgumentException("Unsupported input component type") + } + fieldNotifier.setFieldValue(field, newValue) + Helpers.showToast( + this@SettingsPanel, + "${field.name} updated successfully!" + ) + } catch (e: Exception) { + Helpers.showToast( + this@SettingsPanel, + "Failed to update ${field.name}: ${e.message}", + JOptionPane.ERROR_MESSAGE + ) + } + } + ).also { + it.maximumSize = Dimension(Int.MAX_VALUE, 8) } + gbc.gridx = 2 gbc.gridy = 0 gbc.weightx = 0.0 gbc.fill = GridBagConstraints.NONE - applyButton.addActionListener { - try { - val newValue = when (inputComponent) { - is JCheckBox -> inputComponent.isSelected - is JComboBox<*> -> inputComponent.selectedItem - is JSpinner -> inputComponent.value - is JTextField -> Helpers.convertValue(field.type, field.genericType, inputComponent.text) - else -> throw IllegalArgumentException("Unsupported input component type") - } - fieldNotifier.setFieldValue(field, newValue) - Helpers.showToast( - this@SettingsPanel, - "${field.name} updated successfully!" - ) - } catch (e: Exception) { - Helpers.showToast( - this@SettingsPanel, - "Failed to update ${field.name}: ${e.message}", - JOptionPane.ERROR_MESSAGE - ) - } - } - + fieldPanel.add(applyButton, gbc) add(fieldPanel) } // Track field changes in real-time and update UI (skip HashMap fields) - if (field.type != HashMap::class.java && field.type.simpleName != "HashMap") { + if (!field.isHashMapType()) { var previousValue = field.get(plugin)?.toString() val timer = Timer() timer.schedule(object : TimerTask() { @@ -205,7 +200,7 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() { } } - private fun createHashMapEditor(field: java.lang.reflect.Field, plugin: Plugin, fieldNotifier: FieldNotifier): JComponent { + private fun createHashMapEditor(field: Field, plugin: Plugin, fieldNotifier: FieldNotifier): JComponent { // Create a panel to hold the table and buttons val editorPanel = JPanel() editorPanel.layout = BoxLayout(editorPanel, BoxLayout.Y_AXIS) @@ -213,19 +208,7 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() { editorPanel.border = BorderFactory.createEmptyBorder(5, 0, 5, 0) editorPanel.maximumSize = Dimension(Int.MAX_VALUE, 250) - // Get the "Exposed" annotation specifically and retrieve its description, if available - val exposedAnnotation = field.annotations.firstOrNull { annotation -> - annotation.annotationClass.simpleName == "Exposed" - } - - val description = exposedAnnotation?.let { annotation -> - try { - val descriptionField = annotation.annotationClass.java.getMethod("description") - descriptionField.invoke(annotation) as String - } catch (e: NoSuchMethodException) { - "" // No description method, return empty string - } - } ?: "" + val description = field.exposedDescription() // Create title label val titleLabel = JLabel("${field.name} (Key-Value Pairs)").apply { @@ -288,9 +271,7 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() { // Create a scroll pane for the table with fixed size val scrollPane = JScrollPane(table).apply { - preferredSize = Dimension(Int.MAX_VALUE, 150) - maximumSize = preferredSize - minimumSize = preferredSize + setFixedSize(Dimension(Int.MAX_VALUE, 150)) background = WIDGET_COLOR verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_NEVER @@ -304,9 +285,9 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() { } // Add button - val addButton = JButton("+").apply { - maximumSize = Dimension(40, 30) - addActionListener { + val addButton = UiStyler.button( + text = "+", + onClick = { val vector = java.util.Vector() vector.add("") vector.add("") @@ -317,12 +298,14 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() { table.editCellAt(newRow, 0) table.editorComponent?.requestFocus() } + ).apply { + setFixedSize(40, 30) } - + // Remove button - val removeButton = JButton("-").apply { - maximumSize = Dimension(40, 30) - addActionListener { + val removeButton = UiStyler.button( + text = "-", + onClick = { val selectedRow = table.selectedRow if (selectedRow >= 0) { tableModel.removeRow(selectedRow) @@ -334,51 +317,53 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() { ) } } + ).apply { + setFixedSize(40, 30) } - + // Apply button - val applyButton = JButton("Apply Changes").apply { - maximumSize = Dimension(120, 30) - addActionListener { + val applyButton = UiStyler.button( + text = "Apply Changes", + onClick = { try { // Commit any active cell editing before reading values if (table.isEditing) { table.cellEditor.stopCellEditing() } - + // Get the current HashMap from the field and modify it in place val currentHashMap = field.get(plugin) as? HashMap ?: HashMap() - + // Clear the current HashMap currentHashMap.clear() - + // Add the new entries from the table to the existing HashMap for (i in 0 until tableModel.rowCount) { val key = tableModel.getValueAt(i, 0).toString() val value = tableModel.getValueAt(i, 1).toString() - // Only add non-empty keys - if (key.isNotBlank()) { - // Skip empty values - if (value.isBlank()) { - Helpers.showToast( - this@SettingsPanel, - "Skipping entry with empty value for key '$key'", - JOptionPane.WARNING_MESSAGE - ) - continue - } - - // Try to convert the value to the appropriate type based on the field's generic type - val convertedValue = try { - // For HashMap - treat all HashMap fields the same way regardless of plugin - val fieldTypeName = field.genericType.toString() - if (fieldTypeName.contains("java.util.HashMap") || - fieldTypeName.contains("HashMap") || - fieldTypeName.contains("HashMap")) { + + if (key.isBlank()) { + continue + } + + if (value.isBlank()) { + Helpers.showToast( + this@SettingsPanel, + "Skipping entry with empty value for key '$key'", + JOptionPane.WARNING_MESSAGE + ) + continue + } + + val convertedValue = try { + val fieldTypeName = field.genericType.toString() + when { + fieldTypeName.contains("java.util.HashMap") || + fieldTypeName.contains("HashMap") || + fieldTypeName.contains("HashMap") -> { try { - val intValue = value.toInt() - intValue - } catch (e: NumberFormatException) { + value.toInt() + } catch (numberFormat: NumberFormatException) { Helpers.showToast( this@SettingsPanel, "Invalid number format for key '$key': '$value'. Using 0 as default.", @@ -386,38 +371,20 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() { ) 0 } - } - // For other numeric types - else if (fieldTypeName.contains("java.lang.Integer") || - fieldTypeName.contains("int")) { - value.toInt() - } - else if (fieldTypeName.contains("java.lang.Double") || - fieldTypeName.contains("double")) { - value.toDouble() - } - else if (fieldTypeName.contains("java.lang.Float") || - fieldTypeName.contains("float")) { - value.toFloat() - } - else if (fieldTypeName.contains("java.lang.Boolean") || - fieldTypeName.contains("boolean")) { - value.toBoolean() - } - // Default to string for other types - else { - value } - } catch (e: Exception) { - // If conversion fails, keep as string - value + fieldTypeName.contains("java.lang.Integer") || fieldTypeName.contains("int") -> value.toInt() + fieldTypeName.contains("java.lang.Double") || fieldTypeName.contains("double") -> value.toDouble() + fieldTypeName.contains("java.lang.Float") || fieldTypeName.contains("float") -> value.toFloat() + fieldTypeName.contains("java.lang.Boolean") || fieldTypeName.contains("boolean") -> value.toBoolean() + else -> value } - currentHashMap[key] = convertedValue + } catch (e: Exception) { + value } + + currentHashMap[key] = convertedValue } - - // Update the field to trigger notifications (even though the reference is the same) - // This ensures OnKondoValueUpdated() gets called if it exists + fieldNotifier.setFieldValue(field, currentHashMap) Helpers.showToast( this@SettingsPanel, @@ -431,6 +398,8 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() { ) } } + ).apply { + setFixedSize(120, 30) } buttonsPanel.add(addButton) @@ -447,7 +416,24 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() { return editorPanel } - + + private fun Field.exposedDescription(): String { + val exposedAnnotation = annotations.firstOrNull { + it.annotationClass.simpleName == "Exposed" + } ?: return "" + + return try { + val descriptionMethod = exposedAnnotation.annotationClass.java.getMethod("description") + descriptionMethod.invoke(exposedAnnotation) as? String ?: "" + } catch (_: Exception) { + "" + } + } + + private fun Field.isHashMapType(): Boolean { + return type == HashMap::class.java || type.simpleName == "HashMap" + } + companion object { var customToolTipWindow: JWindow? = null diff --git a/plugin-playground/src/main/kotlin/KondoKit/components/ToggleSwitch.kt b/plugin-playground/src/main/kotlin/KondoKit/components/ToggleSwitch.kt index 901f45d..3a53bd7 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/components/ToggleSwitch.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/components/ToggleSwitch.kt @@ -5,6 +5,7 @@ import KondoKit.plugin.Companion.PROGRESS_BAR_FILL import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.primaryColor import KondoKit.plugin.Companion.secondaryColor +import KondoKit.setFixedSize import java.awt.* import java.awt.event.MouseAdapter import java.awt.event.MouseEvent @@ -32,9 +33,7 @@ class ToggleSwitch : JPanel() { } }) cursor = Cursor(Cursor.HAND_CURSOR) - preferredSize = ViewConstants.TOGGLE_SWITCH_SIZE - maximumSize = ViewConstants.TOGGLE_SWITCH_SIZE - minimumSize = ViewConstants.TOGGLE_SWITCH_SIZE + setFixedSize(ViewConstants.TOGGLE_SWITCH_SIZE) isOpaque = false // Make the panel background transparent } @@ -129,4 +128,4 @@ class ToggleSwitch : JPanel() { fun setActiveSwitch(activeSwitch: Color) { this.activeSwitch = activeSwitch } -} \ No newline at end of file +} diff --git a/plugin-playground/src/main/kotlin/KondoKit/components/UiStyler.kt b/plugin-playground/src/main/kotlin/KondoKit/components/UiStyler.kt new file mode 100644 index 0000000..dd9fadc --- /dev/null +++ b/plugin-playground/src/main/kotlin/KondoKit/components/UiStyler.kt @@ -0,0 +1,74 @@ +package KondoKit.components + +import KondoKit.ViewConstants +import KondoKit.plugin.Companion.POPUP_BACKGROUND +import KondoKit.plugin.Companion.POPUP_FOREGROUND +import KondoKit.plugin.Companion.TITLE_BAR_COLOR +import KondoKit.plugin.Companion.secondaryColor +import java.awt.Color +import java.awt.Font +import java.awt.Insets +import javax.swing.AbstractButton +import javax.swing.Icon +import javax.swing.JButton +import javax.swing.JMenuItem + +/** + * Centralises common Swing styling so buttons and menu items share a + * consistent look and the setup code remains in one place. + */ +object UiStyler { + + data class ButtonDefaults( + val background: Color = TITLE_BAR_COLOR, + val foreground: Color = secondaryColor, + val font: Font = ViewConstants.FONT_RUNESCAPE_SMALL_14, + val margin: Insets? = null + ) + + data class MenuItemDefaults( + val background: Color = POPUP_BACKGROUND, + val foreground: Color = POPUP_FOREGROUND, + val font: Font = ViewConstants.FONT_RUNESCAPE_SMALL_16 + ) + + fun T.applyDefaults( + defaults: ButtonDefaults = ButtonDefaults(), + onClick: (() -> Unit)? = null + ): T { + background = defaults.background + foreground = defaults.foreground + font = defaults.font + defaults.margin?.let { margin = it } + onClick?.let { addActionListener { _ -> it() } } + return this + } + + fun button( + text: String? = null, + icon: Icon? = null, + defaults: ButtonDefaults = ButtonDefaults(), + onClick: (() -> Unit)? = null + ): JButton { + return JButton().apply { + text?.let { this.text = it } + icon?.let { this.icon = it } + isOpaque = true + applyDefaults(defaults, onClick) + } + } + + fun menuItem( + text: String, + defaults: MenuItemDefaults = MenuItemDefaults(), + onClick: (() -> Unit)? = null + ): JMenuItem { + return JMenuItem(text).apply { + background = defaults.background + foreground = defaults.foreground + font = defaults.font + onClick?.let { addActionListener { _ -> it() } } + } + } + +} diff --git a/plugin-playground/src/main/kotlin/KondoKit/components/ViewHeader.kt b/plugin-playground/src/main/kotlin/KondoKit/components/ViewHeader.kt index fd0e505..ced0a75 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/components/ViewHeader.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/components/ViewHeader.kt @@ -1,6 +1,7 @@ package KondoKit.components import KondoKit.ViewConstants +import KondoKit.setFixedSize import KondoKit.plugin.Companion.TITLE_BAR_COLOR import KondoKit.plugin.Companion.secondaryColor import java.awt.* @@ -15,7 +16,7 @@ class ViewHeader( init { background = TITLE_BAR_COLOR - preferredSize = Dimension(Int.MAX_VALUE, headerHeight) + setFixedSize(Int.MAX_VALUE, headerHeight) border = BorderFactory.createEmptyBorder(5, 10, 5, 10) layout = BorderLayout() diff --git a/plugin-playground/src/main/kotlin/KondoKit/components/WidgetPanel.kt b/plugin-playground/src/main/kotlin/KondoKit/components/WidgetPanel.kt index 1348500..99b0e0d 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/components/WidgetPanel.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/components/WidgetPanel.kt @@ -2,6 +2,7 @@ package KondoKit.components import KondoKit.ViewConstants import KondoKit.plugin.Companion.WIDGET_COLOR +import KondoKit.setFixedSize import java.awt.BorderLayout import java.awt.Dimension import javax.swing.BorderFactory @@ -25,9 +26,7 @@ class WidgetPanel( background = WIDGET_COLOR val size = Dimension(widgetWidth, widgetHeight) - preferredSize = size - maximumSize = size - minimumSize = size + setFixedSize(size) val top = paddingTop ?: if (addDefaultPadding) 5 else 0 val left = paddingLeft ?: if (addDefaultPadding) 5 else 0 @@ -39,8 +38,6 @@ class WidgetPanel( fun setFixedSize(width: Int, height: Int) { val size = Dimension(width, height) - preferredSize = size - maximumSize = size - minimumSize = size + this@WidgetPanel.setFixedSize(size) } } diff --git a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt index db4f3cf..e2cf637 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/plugin.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/plugin.kt @@ -608,26 +608,20 @@ class plugin : Plugin() { // ImageCanvas with forced size val imageCanvas = ImageCanvas(bufferedImageSprite).apply { background = WIDGET_COLOR - preferredSize = imageSize - maximumSize = imageSize - minimumSize = imageSize + setFixedSize(imageSize) } // Wrapping the ImageCanvas in another JPanel to prevent stretching val imageCanvasWrapper = JPanel().apply { layout = GridBagLayout() // Keeps the layout of the wrapped panel minimal - preferredSize = imageSize - maximumSize = imageSize - minimumSize = imageSize + setFixedSize(imageSize) isOpaque = false // No background for the wrapper add(imageCanvas) // Adding ImageCanvas directly, layout won't stretch it } val panelButton = JPanel().apply { layout = GridBagLayout() - preferredSize = buttonSize - maximumSize = buttonSize - minimumSize = buttonSize + setFixedSize(buttonSize) background = WIDGET_COLOR isOpaque = true diff --git a/plugin-playground/src/main/kotlin/KondoKit/views/BaseView.kt b/plugin-playground/src/main/kotlin/KondoKit/views/BaseView.kt index 9e2aaf1..4479f1b 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/views/BaseView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/views/BaseView.kt @@ -2,7 +2,7 @@ package KondoKit.views import KondoKit.ViewConstants import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR -import java.awt.Dimension +import KondoKit.setFixedSize import javax.swing.BorderFactory import javax.swing.Box import javax.swing.BoxLayout @@ -26,9 +26,6 @@ open class BaseView( } fun setViewSize(height: Int) { - val dimension = Dimension(preferredWidth, height) - preferredSize = dimension - maximumSize = dimension - minimumSize = dimension + setFixedSize(preferredWidth, height) } } diff --git a/plugin-playground/src/main/kotlin/KondoKit/views/LootTrackerView.kt b/plugin-playground/src/main/kotlin/KondoKit/views/LootTrackerView.kt index 782e24b..f085307 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/views/LootTrackerView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/views/LootTrackerView.kt @@ -6,12 +6,11 @@ import KondoKit.Helpers.formatHtmlLabelText import KondoKit.ImageCanvas import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite import KondoKit.ViewConstants +import KondoKit.setFixedSize import KondoKit.views.XPTrackerView.wrappedWidget import KondoKit.components.PopupMenuComponent import KondoKit.components.ProgressBar import KondoKit.components.WidgetPanel -import KondoKit.plugin.Companion.POPUP_BACKGROUND -import KondoKit.plugin.Companion.POPUP_FOREGROUND import KondoKit.plugin.Companion.TITLE_BAR_COLOR import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND import KondoKit.plugin.Companion.TOTAL_XP_WIDGET_SIZE @@ -24,6 +23,7 @@ import KondoKit.plugin.StateManager.focusedView import plugin.api.API import rt4.* import java.awt.* +import java.awt.Component import java.awt.Font import java.awt.event.MouseAdapter import java.awt.event.MouseEvent @@ -252,10 +252,8 @@ object LootTrackerView : View, OnPostClientTickCallback, OnKillingBlowNPCCallbac val rowsNeeded = ceil(totalItems / 6.0).toInt() val lootPanelHeight = rowsNeeded * (40) - val size = Dimension(lootPanel.width,lootPanelHeight+32) - lootPanel.parent.preferredSize = size - lootPanel.parent.minimumSize = size - lootPanel.parent.maximumSize = size + val size = Dimension(lootPanel.width, lootPanelHeight + 32) + (lootPanel.parent as? Component)?.setFixedSize(size) lootPanel.parent.revalidate() lootPanel.parent.repaint() lootPanel.revalidate() @@ -275,16 +273,11 @@ object LootTrackerView : View, OnPostClientTickCallback, OnKillingBlowNPCCallbac // Create the panel for the item val itemPanel = FixedSizePanel(Dimension(36, 32)).apply { - preferredSize = Dimension(36, 32) background = WIDGET_COLOR - minimumSize = preferredSize - maximumSize = preferredSize val imageCanvas = ImageCanvas(bufferedImageSprite).apply { - preferredSize = Dimension(36, 32) + setFixedSize(36, 32) background = WIDGET_COLOR - minimumSize = preferredSize - maximumSize = preferredSize } // Add the imageCanvas to the panel @@ -476,9 +469,7 @@ object LootTrackerView : View, OnPostClientTickCallback, OnKillingBlowNPCCallbac val labelPanel = JPanel(BorderLayout()).apply { background = TITLE_BAR_COLOR border = BorderFactory.createEmptyBorder(5, 5, 5, 5) - maximumSize = Dimension(ViewConstants.DEFAULT_WIDGET_SIZE.width, 24) - minimumSize = maximumSize - preferredSize = maximumSize + setFixedSize(ViewConstants.DEFAULT_WIDGET_SIZE.width, 24) } val killCount = npcKillCounts.getOrPut(npcName) { 0 } @@ -536,18 +527,7 @@ object LootTrackerView : View, OnPostClientTickCallback, OnKillingBlowNPCCallbac private fun removeLootFrameMenu(toRemove: JPanel, npcName: String): JPopupMenu { // Create a popup menu val popupMenu = PopupMenuComponent() - val rFont = ViewConstants.FONT_RUNESCAPE_SMALL_16 - - popupMenu.background = POPUP_BACKGROUND - - // Create menu items with custom font and colors - val menuItem1 = JMenuItem("Remove").apply { - font = rFont // Set custom font - background = POPUP_BACKGROUND // Dark background for item - foreground = POPUP_FOREGROUND // Light text color for item - } - popupMenu.add(menuItem1) - menuItem1.addActionListener { + popupMenu.addMenuItem("Remove") { lootItemPanels[npcName]?.clear() npcKillCounts[npcName] = 0 lootTrackerView?.let { parent -> @@ -574,14 +554,7 @@ object LootTrackerView : View, OnPostClientTickCallback, OnKillingBlowNPCCallbac // Create a popup menu val popupMenu = PopupMenuComponent() - // Create menu items with custom font and colors - val menuItem1 = JMenuItem("Reset Loot Tracker").apply { - font = ViewConstants.FONT_RUNESCAPE_SMALL_16 - background = POPUP_BACKGROUND - foreground = POPUP_FOREGROUND - } - popupMenu.add(menuItem1) - menuItem1.addActionListener { + popupMenu.addMenuItem("Reset Loot Tracker") { registerDrawAction { resetLootTracker() } diff --git a/plugin-playground/src/main/kotlin/KondoKit/views/ReflectiveEditorView.kt b/plugin-playground/src/main/kotlin/KondoKit/views/ReflectiveEditorView.kt index f468515..72d9f4d 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/views/ReflectiveEditorView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/views/ReflectiveEditorView.kt @@ -4,13 +4,13 @@ import KondoKit.Helpers import KondoKit.components.* import KondoKit.ViewConstants import KondoKit.views.ViewLayoutHelpers.createSearchFieldSection +import KondoKit.setFixedSize import KondoKit.pluginmanager.GitLabPlugin import KondoKit.pluginmanager.GitLabPluginFetcher import KondoKit.pluginmanager.PluginDownloadManager import KondoKit.pluginmanager.PluginProperties import KondoKit.pluginmanager.PluginInfoWithStatus import KondoKit.Helpers.showToast -import KondoKit.plugin.Companion.TITLE_BAR_COLOR import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR import KondoKit.plugin.Companion.WIDGET_COLOR @@ -304,17 +304,10 @@ object ReflectiveEditorView : View { } // Edit button (only show if plugin has exposed attributes) - val editButton = if (exposedFields.isNotEmpty()) { - val button = JButton("Edit") - button.background = TITLE_BAR_COLOR - button.foreground = secondaryColor - button.font = ViewConstants.FONT_RUNESCAPE_SMALL_14 - button.addActionListener { + val editButton = exposedFields.takeIf { it.isNotEmpty() }?.let { + UiStyler.button(text = "Edit") { showPluginDetails(pluginInfo, plugin) } - button - } else { - null } // Plugin toggle switch (iOS style) - skip for KondoKit since it should always be on @@ -324,8 +317,7 @@ object ReflectiveEditorView : View { // Create a placeholder component that takes the same space but is invisible val placeholder = JPanel() placeholder.background = WIDGET_COLOR - placeholder.preferredSize = ViewConstants.TOGGLE_PLACEHOLDER_SIZE - placeholder.maximumSize = ViewConstants.TOGGLE_PLACEHOLDER_SIZE + placeholder.setFixedSize(ViewConstants.TOGGLE_PLACEHOLDER_SIZE) placeholder.isVisible = false placeholder } @@ -417,10 +409,7 @@ object ReflectiveEditorView : View { nameLabel.font = ViewConstants.FONT_RUNESCAPE_SMALL_PLAIN_16 // Action button based on plugin status - val actionButton = JButton() - actionButton.background = TITLE_BAR_COLOR - actionButton.foreground = secondaryColor - actionButton.font = ViewConstants.FONT_RUNESCAPE_SMALL_14 + val actionButton = UiStyler.button() // Progress bar for downloads val progressBar = JProgressBar(0, 100) diff --git a/plugin-playground/src/main/kotlin/KondoKit/views/ViewLayoutHelpers.kt b/plugin-playground/src/main/kotlin/KondoKit/views/ViewLayoutHelpers.kt index 3a1f375..47b7f0a 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/views/ViewLayoutHelpers.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/views/ViewLayoutHelpers.kt @@ -77,14 +77,3 @@ object ViewLayoutHelpers { fun Container.addVerticalSpacing(pixels: Int) { add(Box.createVerticalStrut(pixels)) } - -fun T.setFixedSize(width: Int, height: Int): T { - return setFixedSize(Dimension(width, height)) -} - -fun T.setFixedSize(size: Dimension): T { - preferredSize = size - minimumSize = size - maximumSize = size - return this -} diff --git a/plugin-playground/src/main/kotlin/KondoKit/views/XPTrackerView.kt b/plugin-playground/src/main/kotlin/KondoKit/views/XPTrackerView.kt index 4d9cbf9..498647a 100644 --- a/plugin-playground/src/main/kotlin/KondoKit/views/XPTrackerView.kt +++ b/plugin-playground/src/main/kotlin/KondoKit/views/XPTrackerView.kt @@ -8,6 +8,7 @@ import KondoKit.Helpers.getProgressBarColor import KondoKit.Helpers.getSpriteId import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite import KondoKit.ViewConstants +import KondoKit.setFixedSize import KondoKit.XPTable import KondoKit.components.PopupMenuComponent import KondoKit.components.ProgressBar @@ -18,8 +19,6 @@ import KondoKit.plugin.Companion.TOTAL_XP_WIDGET_SIZE import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.WIDGET_SIZE import KondoKit.plugin -import KondoKit.plugin.Companion.POPUP_BACKGROUND -import KondoKit.plugin.Companion.POPUP_FOREGROUND import KondoKit.plugin.Companion.playerXPMultiplier import KondoKit.plugin.Companion.primaryColor import KondoKit.plugin.Companion.secondaryColor @@ -126,12 +125,6 @@ object XPTrackerView : View, OnUpdateCallback, OnXPUpdateCallback { } } - private fun createMenuItem(text: String): JMenuItem = JMenuItem(text).apply { - font = widgetFont - background = POPUP_BACKGROUND - foreground = POPUP_FOREGROUND - } - private fun getSkillIcon(skillId: Int): BufferedImage { return skillIconCache[skillId] ?: getBufferedImageFromSprite(API.GetSprite(getSpriteId(skillId))).also { skillIconCache[skillId] = it @@ -366,24 +359,16 @@ object XPTrackerView : View, OnUpdateCallback, OnXPUpdateCallback { fun createResetMenu(): JPopupMenu { val popupMenu = PopupMenuComponent() - - val resetItem = createMenuItem("Reset Tracker") - popupMenu.add(resetItem) - - resetItem.addActionListener { plugin.registerDrawAction { resetXPTracker(xpTrackerView!!) } } + popupMenu.addMenuItem("Reset Tracker") { + plugin.registerDrawAction { resetXPTracker(xpTrackerView!!) } + } return popupMenu } fun removeXPWidgetMenu(toRemove: Container, skillId: Int): JPopupMenu { val popupMenu = PopupMenuComponent() - val resetItem = createMenuItem("Reset") - popupMenu.add(resetItem) - - val removeItem = createMenuItem("Remove") - popupMenu.add(removeItem) - - resetItem.addActionListener { + popupMenu.addMenuItem("Reset") { xpWidgets[skillId]?.let { widget -> // Baseline at current XP and clear per-widget counters initialXP[skillId] = widget.previousXp @@ -395,7 +380,7 @@ object XPTrackerView : View, OnUpdateCallback, OnXPUpdateCallback { } } - removeItem.addActionListener { + popupMenu.addMenuItem("Remove") { // Reset the per-skill baseline to the current XP so next widget starts fresh xpWidgets[skillId]?.let { widget -> initialXP[skillId] = widget.previousXp @@ -440,9 +425,7 @@ object XPTrackerView : View, OnUpdateCallback, OnXPUpdateCallback { val actionsLabel = createMetricLabel(actionsTitle) val progressBar = ProgressBar(0.0, getProgressBarColor(skillId)).apply { - preferredSize = Dimension(160, 22) - minimumSize = preferredSize - maximumSize = preferredSize + setFixedSize(160, 22) } val progressPanel = JPanel(BorderLayout()).apply { @@ -484,15 +467,11 @@ object XPTrackerView : View, OnUpdateCallback, OnXPUpdateCallback { ) val outerPanel = JPanel(GridBagLayout()).apply { background = WIDGET_COLOR - preferredSize = outerPanelSize - maximumSize = outerPanelSize - minimumSize = outerPanelSize + setFixedSize(outerPanelSize) } val innerPanel = JPanel(BorderLayout()).apply { background = WIDGET_COLOR - preferredSize = component.preferredSize - maximumSize = component.preferredSize - minimumSize = component.preferredSize + setFixedSize(component.preferredSize) add(component, BorderLayout.CENTER) } val gbc = GridBagConstraints().apply {