More helpers/DRY

This commit is contained in:
downthecrop 2025-10-24 18:43:16 -07:00
parent 573e579643
commit 47e545cbc7
17 changed files with 264 additions and 289 deletions

View file

@ -0,0 +1,14 @@
package KondoKit
import java.awt.Component
import java.awt.Dimension
fun <T : Component> T.setFixedSize(width: Int, height: Int): T =
setFixedSize(Dimension(width, height))
fun <T : Component> T.setFixedSize(size: Dimension): T {
preferredSize = size
minimumSize = size
maximumSize = size
return this
}

View file

@ -12,6 +12,7 @@ import java.lang.reflect.Type
import java.util.* import java.util.*
import java.util.Timer import java.util.Timer
import javax.swing.* import javax.swing.*
import KondoKit.setFixedSize
object Helpers { object Helpers {
// Convenience helper for loading resources relative to the KondoKit plugin class // Convenience helper for loading resources relative to the KondoKit plugin class
@ -35,9 +36,7 @@ object Helpers {
componentPosition: String = BorderLayout.NORTH componentPosition: String = BorderLayout.NORTH
): ImageCanvasComponents { ): ImageCanvasComponents {
val imageCanvas = ImageCanvas(bufferedImage).apply { val imageCanvas = ImageCanvas(bufferedImage).apply {
preferredSize = size setFixedSize(size)
minimumSize = size
maximumSize = size
this.size = size this.size = size
this.background = background this.background = background
} }

View file

@ -4,6 +4,8 @@ import KondoKit.ViewConstants
import KondoKit.plugin.Companion.TITLE_BAR_COLOR import KondoKit.plugin.Companion.TITLE_BAR_COLOR
import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.WIDGET_COLOR
import KondoKit.plugin.Companion.secondaryColor import KondoKit.plugin.Companion.secondaryColor
import KondoKit.components.UiStyler.button
import KondoKit.components.UiStyler.ButtonDefaults
import java.awt.* import java.awt.*
import javax.swing.* import javax.swing.*
@ -18,29 +20,25 @@ class ButtonPanel(
background = WIDGET_COLOR background = WIDGET_COLOR
} }
fun addButton(text: String, action: () -> Unit): JButton { fun addButton(text: String, action: () -> Unit): JButton =
val button = JButton(text).apply { createAndAddButton(text = text, action = action)
background = TITLE_BAR_COLOR
foreground = secondaryColor
font = ViewConstants.FONT_RUNESCAPE_SMALL_14
addActionListener {
action()
}
}
add(button)
return button
}
fun addIcon(icon: Icon, action: () -> Unit): JButton { fun addIcon(icon: Icon, action: () -> Unit): JButton =
val button = JButton(icon).apply { createAndAddButton(icon = icon, action = action)
background = TITLE_BAR_COLOR
foreground = secondaryColor 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 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
}
} }

View file

@ -2,13 +2,13 @@ package KondoKit.components
import KondoKit.ImageCanvas import KondoKit.ImageCanvas
import KondoKit.SpriteToBufferedImage import KondoKit.SpriteToBufferedImage
import KondoKit.setFixedSize
import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.WIDGET_COLOR
import KondoKit.plugin.Companion.primaryColor import KondoKit.plugin.Companion.primaryColor
import KondoKit.plugin.Companion.secondaryColor import KondoKit.plugin.Companion.secondaryColor
import plugin.api.API import plugin.api.API
import java.awt.BorderLayout import java.awt.BorderLayout
import java.awt.Color import java.awt.Color
import java.awt.Dimension
import javax.swing.BorderFactory import javax.swing.BorderFactory
import javax.swing.JPanel import javax.swing.JPanel
@ -36,10 +36,7 @@ class IconComponent(
) )
imageCanvas = ImageCanvas(bufferedImageSprite).apply { imageCanvas = ImageCanvas(bufferedImageSprite).apply {
val size = Dimension(iconWidth, iconHeight) setFixedSize(iconWidth, iconHeight)
preferredSize = size
maximumSize = size
minimumSize = size
background = if (useThemeColors) WIDGET_COLOR else Color.WHITE background = if (useThemeColors) WIDGET_COLOR else Color.WHITE
} }

View file

@ -1,8 +1,7 @@
package KondoKit.components package KondoKit.components
import KondoKit.ViewConstants import KondoKit.components.UiStyler.menuItem
import KondoKit.plugin.Companion.POPUP_BACKGROUND import KondoKit.plugin.Companion.POPUP_BACKGROUND
import KondoKit.plugin.Companion.POPUP_FOREGROUND
import javax.swing.JMenuItem import javax.swing.JMenuItem
import javax.swing.JPopupMenu import javax.swing.JPopupMenu
@ -13,15 +12,8 @@ class PopupMenuComponent : JPopupMenu() {
} }
fun addMenuItem(text: String, action: () -> Unit): JMenuItem { fun addMenuItem(text: String, action: () -> Unit): JMenuItem {
val menuItem = JMenuItem(text).apply { val item = menuItem(text = text, onClick = action)
font = ViewConstants.FONT_RUNESCAPE_SMALL_16 add(item)
background = POPUP_BACKGROUND return item
foreground = POPUP_FOREGROUND
addActionListener {
action()
}
}
add(menuItem)
return menuItem
} }
} }

View file

@ -3,6 +3,7 @@ package KondoKit.components
import KondoKit.ImageCanvas import KondoKit.ImageCanvas
import KondoKit.ViewConstants import KondoKit.ViewConstants
import KondoKit.SpriteToBufferedImage import KondoKit.SpriteToBufferedImage
import KondoKit.setFixedSize
import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.WIDGET_COLOR
import KondoKit.plugin.Companion.secondaryColor import KondoKit.plugin.Companion.secondaryColor
import KondoKit.plugin.StateManager.focusedView import KondoKit.plugin.StateManager.focusedView
@ -27,22 +28,18 @@ class SearchField(
private val bufferedImageSprite = SpriteToBufferedImage.getBufferedImageFromSprite(API.GetSprite(1423)) // MAG_SPRITE private val bufferedImageSprite = SpriteToBufferedImage.getBufferedImageFromSprite(API.GetSprite(1423)) // MAG_SPRITE
private val imageCanvas = bufferedImageSprite.let { private val imageCanvas = bufferedImageSprite.let {
ImageCanvas(it).apply { ImageCanvas(it).apply {
preferredSize = ViewConstants.DIMENSION_SMALL_ICON setFixedSize(ViewConstants.DIMENSION_SMALL_ICON)
size = preferredSize size = preferredSize
minimumSize = preferredSize
maximumSize = preferredSize
fillColor = WIDGET_COLOR fillColor = WIDGET_COLOR
} }
} }
init { init {
val dimension = Dimension(fieldWidth, fieldHeight) val dimension = Dimension(fieldWidth, fieldHeight)
preferredSize = dimension setFixedSize(dimension)
background = WIDGET_COLOR background = WIDGET_COLOR
foreground = secondaryColor foreground = secondaryColor
font = ViewConstants.FONT_ARIAL_PLAIN_14 font = ViewConstants.FONT_ARIAL_PLAIN_14
minimumSize = dimension
maximumSize = dimension
isFocusable = true isFocusable = true
focusTraversalKeysEnabled = false focusTraversalKeysEnabled = false

View file

@ -3,6 +3,8 @@ package KondoKit.components
import KondoKit.Helpers import KondoKit.Helpers
import KondoKit.Helpers.FieldNotifier import KondoKit.Helpers.FieldNotifier
import KondoKit.ViewConstants import KondoKit.ViewConstants
import KondoKit.components.UiStyler
import KondoKit.setFixedSize
import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.WIDGET_COLOR
import KondoKit.plugin.Companion.primaryColor import KondoKit.plugin.Companion.primaryColor
import KondoKit.plugin.Companion.secondaryColor import KondoKit.plugin.Companion.secondaryColor
@ -10,6 +12,7 @@ import plugin.Plugin
import java.awt.* import java.awt.*
import java.awt.event.MouseAdapter import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent import java.awt.event.MouseEvent
import java.lang.reflect.Field
import java.util.* import java.util.*
import java.util.Timer import java.util.Timer
import javax.swing.* import javax.swing.*
@ -36,18 +39,7 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
field.isAccessible = true field.isAccessible = true
// Get the "Exposed" annotation specifically and retrieve its description, if available // Get the "Exposed" annotation specifically and retrieve its description, if available
val exposedAnnotation = field.annotations.firstOrNull { annotation -> val description = field.exposedDescription()
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 fieldPanel = JPanel().apply { val fieldPanel = JPanel().apply {
layout = GridBagLayout() layout = GridBagLayout()
@ -104,7 +96,7 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
} }
// Check if the field is a HashMap // Check if the field is a HashMap
field.type == HashMap::class.java || field.type.simpleName == "HashMap" -> { field.isHashMapType() -> {
inputComponent = createHashMapEditor(field, plugin, fieldNotifier) inputComponent = createHashMapEditor(field, plugin, fieldNotifier)
isHashMapEditor = true isHashMapEditor = true
} }
@ -141,14 +133,9 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
fieldPanel.add(inputComponent, gbc) fieldPanel.add(inputComponent, gbc)
// Add apply button for non-HashMap editors // Add apply button for non-HashMap editors
val applyButton = JButton("\u2714").apply { val applyButton = UiStyler.button(
maximumSize = Dimension(Int.MAX_VALUE, 8) text = "\u2714",
} onClick = {
gbc.gridx = 2
gbc.gridy = 0
gbc.weightx = 0.0
gbc.fill = GridBagConstraints.NONE
applyButton.addActionListener {
try { try {
val newValue = when (inputComponent) { val newValue = when (inputComponent) {
is JCheckBox -> inputComponent.isSelected is JCheckBox -> inputComponent.isSelected
@ -170,13 +157,21 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
) )
} }
} }
).also {
it.maximumSize = Dimension(Int.MAX_VALUE, 8)
}
gbc.gridx = 2
gbc.gridy = 0
gbc.weightx = 0.0
gbc.fill = GridBagConstraints.NONE
fieldPanel.add(applyButton, gbc) fieldPanel.add(applyButton, gbc)
add(fieldPanel) add(fieldPanel)
} }
// Track field changes in real-time and update UI (skip HashMap fields) // 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() var previousValue = field.get(plugin)?.toString()
val timer = Timer() val timer = Timer()
timer.schedule(object : TimerTask() { 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 // Create a panel to hold the table and buttons
val editorPanel = JPanel() val editorPanel = JPanel()
editorPanel.layout = BoxLayout(editorPanel, BoxLayout.Y_AXIS) 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.border = BorderFactory.createEmptyBorder(5, 0, 5, 0)
editorPanel.maximumSize = Dimension(Int.MAX_VALUE, 250) editorPanel.maximumSize = Dimension(Int.MAX_VALUE, 250)
// Get the "Exposed" annotation specifically and retrieve its description, if available val description = field.exposedDescription()
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
}
} ?: ""
// Create title label // Create title label
val titleLabel = JLabel("${field.name} (Key-Value Pairs)").apply { 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 // Create a scroll pane for the table with fixed size
val scrollPane = JScrollPane(table).apply { val scrollPane = JScrollPane(table).apply {
preferredSize = Dimension(Int.MAX_VALUE, 150) setFixedSize(Dimension(Int.MAX_VALUE, 150))
maximumSize = preferredSize
minimumSize = preferredSize
background = WIDGET_COLOR background = WIDGET_COLOR
verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED verticalScrollBarPolicy = JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED
horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_NEVER horizontalScrollBarPolicy = JScrollPane.HORIZONTAL_SCROLLBAR_NEVER
@ -304,9 +285,9 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
} }
// Add button // Add button
val addButton = JButton("+").apply { val addButton = UiStyler.button(
maximumSize = Dimension(40, 30) text = "+",
addActionListener { onClick = {
val vector = java.util.Vector<Any>() val vector = java.util.Vector<Any>()
vector.add("") vector.add("")
vector.add("") vector.add("")
@ -317,12 +298,14 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
table.editCellAt(newRow, 0) table.editCellAt(newRow, 0)
table.editorComponent?.requestFocus() table.editorComponent?.requestFocus()
} }
).apply {
setFixedSize(40, 30)
} }
// Remove button // Remove button
val removeButton = JButton("-").apply { val removeButton = UiStyler.button(
maximumSize = Dimension(40, 30) text = "-",
addActionListener { onClick = {
val selectedRow = table.selectedRow val selectedRow = table.selectedRow
if (selectedRow >= 0) { if (selectedRow >= 0) {
tableModel.removeRow(selectedRow) tableModel.removeRow(selectedRow)
@ -334,12 +317,14 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
) )
} }
} }
).apply {
setFixedSize(40, 30)
} }
// Apply button // Apply button
val applyButton = JButton("Apply Changes").apply { val applyButton = UiStyler.button(
maximumSize = Dimension(120, 30) text = "Apply Changes",
addActionListener { onClick = {
try { try {
// Commit any active cell editing before reading values // Commit any active cell editing before reading values
if (table.isEditing) { if (table.isEditing) {
@ -356,9 +341,11 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
for (i in 0 until tableModel.rowCount) { for (i in 0 until tableModel.rowCount) {
val key = tableModel.getValueAt(i, 0).toString() val key = tableModel.getValueAt(i, 0).toString()
val value = tableModel.getValueAt(i, 1).toString() val value = tableModel.getValueAt(i, 1).toString()
// Only add non-empty keys
if (key.isNotBlank()) { if (key.isBlank()) {
// Skip empty values continue
}
if (value.isBlank()) { if (value.isBlank()) {
Helpers.showToast( Helpers.showToast(
this@SettingsPanel, this@SettingsPanel,
@ -368,17 +355,15 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
continue continue
} }
// Try to convert the value to the appropriate type based on the field's generic type
val convertedValue = try { val convertedValue = try {
// For HashMap<String, Int> - treat all HashMap<String, Int> fields the same way regardless of plugin
val fieldTypeName = field.genericType.toString() val fieldTypeName = field.genericType.toString()
if (fieldTypeName.contains("java.util.HashMap<java.lang.String, java.lang.Integer>") || when {
fieldTypeName.contains("java.util.HashMap<java.lang.String, java.lang.Integer>") ||
fieldTypeName.contains("HashMap<String, Int>") || fieldTypeName.contains("HashMap<String, Int>") ||
fieldTypeName.contains("HashMap<String, Integer>")) { fieldTypeName.contains("HashMap<String, Integer>") -> {
try { try {
val intValue = value.toInt() value.toInt()
intValue } catch (numberFormat: NumberFormatException) {
} catch (e: NumberFormatException) {
Helpers.showToast( Helpers.showToast(
this@SettingsPanel, this@SettingsPanel,
"Invalid number format for key '$key': '$value'. Using 0 as default.", "Invalid number format for key '$key': '$value'. Using 0 as default.",
@ -387,37 +372,19 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
0 0
} }
} }
// For other numeric types fieldTypeName.contains("java.lang.Integer") || fieldTypeName.contains("int") -> value.toInt()
else if (fieldTypeName.contains("java.lang.Integer") || fieldTypeName.contains("java.lang.Double") || fieldTypeName.contains("double") -> value.toDouble()
fieldTypeName.contains("int")) { fieldTypeName.contains("java.lang.Float") || fieldTypeName.contains("float") -> value.toFloat()
value.toInt() fieldTypeName.contains("java.lang.Boolean") || fieldTypeName.contains("boolean") -> value.toBoolean()
} else -> value
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) { } catch (e: Exception) {
// If conversion fails, keep as string
value value
} }
currentHashMap[key] = convertedValue 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) fieldNotifier.setFieldValue(field, currentHashMap)
Helpers.showToast( Helpers.showToast(
this@SettingsPanel, this@SettingsPanel,
@ -431,6 +398,8 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
) )
} }
} }
).apply {
setFixedSize(120, 30)
} }
buttonsPanel.add(addButton) buttonsPanel.add(addButton)
@ -448,6 +417,23 @@ class SettingsPanel(private val plugin: Plugin) : JPanel() {
return editorPanel 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 { companion object {
var customToolTipWindow: JWindow? = null var customToolTipWindow: JWindow? = null

View file

@ -5,6 +5,7 @@ import KondoKit.plugin.Companion.PROGRESS_BAR_FILL
import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.WIDGET_COLOR
import KondoKit.plugin.Companion.primaryColor import KondoKit.plugin.Companion.primaryColor
import KondoKit.plugin.Companion.secondaryColor import KondoKit.plugin.Companion.secondaryColor
import KondoKit.setFixedSize
import java.awt.* import java.awt.*
import java.awt.event.MouseAdapter import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent import java.awt.event.MouseEvent
@ -32,9 +33,7 @@ class ToggleSwitch : JPanel() {
} }
}) })
cursor = Cursor(Cursor.HAND_CURSOR) cursor = Cursor(Cursor.HAND_CURSOR)
preferredSize = ViewConstants.TOGGLE_SWITCH_SIZE setFixedSize(ViewConstants.TOGGLE_SWITCH_SIZE)
maximumSize = ViewConstants.TOGGLE_SWITCH_SIZE
minimumSize = ViewConstants.TOGGLE_SWITCH_SIZE
isOpaque = false // Make the panel background transparent isOpaque = false // Make the panel background transparent
} }

View file

@ -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 : AbstractButton> 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() } }
}
}
}

View file

@ -1,6 +1,7 @@
package KondoKit.components package KondoKit.components
import KondoKit.ViewConstants import KondoKit.ViewConstants
import KondoKit.setFixedSize
import KondoKit.plugin.Companion.TITLE_BAR_COLOR import KondoKit.plugin.Companion.TITLE_BAR_COLOR
import KondoKit.plugin.Companion.secondaryColor import KondoKit.plugin.Companion.secondaryColor
import java.awt.* import java.awt.*
@ -15,7 +16,7 @@ class ViewHeader(
init { init {
background = TITLE_BAR_COLOR background = TITLE_BAR_COLOR
preferredSize = Dimension(Int.MAX_VALUE, headerHeight) setFixedSize(Int.MAX_VALUE, headerHeight)
border = BorderFactory.createEmptyBorder(5, 10, 5, 10) border = BorderFactory.createEmptyBorder(5, 10, 5, 10)
layout = BorderLayout() layout = BorderLayout()

View file

@ -2,6 +2,7 @@ package KondoKit.components
import KondoKit.ViewConstants import KondoKit.ViewConstants
import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.WIDGET_COLOR
import KondoKit.setFixedSize
import java.awt.BorderLayout import java.awt.BorderLayout
import java.awt.Dimension import java.awt.Dimension
import javax.swing.BorderFactory import javax.swing.BorderFactory
@ -25,9 +26,7 @@ class WidgetPanel(
background = WIDGET_COLOR background = WIDGET_COLOR
val size = Dimension(widgetWidth, widgetHeight) val size = Dimension(widgetWidth, widgetHeight)
preferredSize = size setFixedSize(size)
maximumSize = size
minimumSize = size
val top = paddingTop ?: if (addDefaultPadding) 5 else 0 val top = paddingTop ?: if (addDefaultPadding) 5 else 0
val left = paddingLeft ?: 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) { fun setFixedSize(width: Int, height: Int) {
val size = Dimension(width, height) val size = Dimension(width, height)
preferredSize = size this@WidgetPanel.setFixedSize(size)
maximumSize = size
minimumSize = size
} }
} }

View file

@ -608,26 +608,20 @@ class plugin : Plugin() {
// ImageCanvas with forced size // ImageCanvas with forced size
val imageCanvas = ImageCanvas(bufferedImageSprite).apply { val imageCanvas = ImageCanvas(bufferedImageSprite).apply {
background = WIDGET_COLOR background = WIDGET_COLOR
preferredSize = imageSize setFixedSize(imageSize)
maximumSize = imageSize
minimumSize = imageSize
} }
// Wrapping the ImageCanvas in another JPanel to prevent stretching // Wrapping the ImageCanvas in another JPanel to prevent stretching
val imageCanvasWrapper = JPanel().apply { val imageCanvasWrapper = JPanel().apply {
layout = GridBagLayout() // Keeps the layout of the wrapped panel minimal layout = GridBagLayout() // Keeps the layout of the wrapped panel minimal
preferredSize = imageSize setFixedSize(imageSize)
maximumSize = imageSize
minimumSize = imageSize
isOpaque = false // No background for the wrapper isOpaque = false // No background for the wrapper
add(imageCanvas) // Adding ImageCanvas directly, layout won't stretch it add(imageCanvas) // Adding ImageCanvas directly, layout won't stretch it
} }
val panelButton = JPanel().apply { val panelButton = JPanel().apply {
layout = GridBagLayout() layout = GridBagLayout()
preferredSize = buttonSize setFixedSize(buttonSize)
maximumSize = buttonSize
minimumSize = buttonSize
background = WIDGET_COLOR background = WIDGET_COLOR
isOpaque = true isOpaque = true

View file

@ -2,7 +2,7 @@ package KondoKit.views
import KondoKit.ViewConstants import KondoKit.ViewConstants
import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR
import java.awt.Dimension import KondoKit.setFixedSize
import javax.swing.BorderFactory import javax.swing.BorderFactory
import javax.swing.Box import javax.swing.Box
import javax.swing.BoxLayout import javax.swing.BoxLayout
@ -26,9 +26,6 @@ open class BaseView(
} }
fun setViewSize(height: Int) { fun setViewSize(height: Int) {
val dimension = Dimension(preferredWidth, height) setFixedSize(preferredWidth, height)
preferredSize = dimension
maximumSize = dimension
minimumSize = dimension
} }
} }

View file

@ -6,12 +6,11 @@ import KondoKit.Helpers.formatHtmlLabelText
import KondoKit.ImageCanvas import KondoKit.ImageCanvas
import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite
import KondoKit.ViewConstants import KondoKit.ViewConstants
import KondoKit.setFixedSize
import KondoKit.views.XPTrackerView.wrappedWidget import KondoKit.views.XPTrackerView.wrappedWidget
import KondoKit.components.PopupMenuComponent import KondoKit.components.PopupMenuComponent
import KondoKit.components.ProgressBar import KondoKit.components.ProgressBar
import KondoKit.components.WidgetPanel 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.TITLE_BAR_COLOR
import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND
import KondoKit.plugin.Companion.TOTAL_XP_WIDGET_SIZE import KondoKit.plugin.Companion.TOTAL_XP_WIDGET_SIZE
@ -24,6 +23,7 @@ import KondoKit.plugin.StateManager.focusedView
import plugin.api.API import plugin.api.API
import rt4.* import rt4.*
import java.awt.* import java.awt.*
import java.awt.Component
import java.awt.Font import java.awt.Font
import java.awt.event.MouseAdapter import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent import java.awt.event.MouseEvent
@ -252,10 +252,8 @@ object LootTrackerView : View, OnPostClientTickCallback, OnKillingBlowNPCCallbac
val rowsNeeded = ceil(totalItems / 6.0).toInt() val rowsNeeded = ceil(totalItems / 6.0).toInt()
val lootPanelHeight = rowsNeeded * (40) val lootPanelHeight = rowsNeeded * (40)
val size = Dimension(lootPanel.width,lootPanelHeight+32) val size = Dimension(lootPanel.width, lootPanelHeight + 32)
lootPanel.parent.preferredSize = size (lootPanel.parent as? Component)?.setFixedSize(size)
lootPanel.parent.minimumSize = size
lootPanel.parent.maximumSize = size
lootPanel.parent.revalidate() lootPanel.parent.revalidate()
lootPanel.parent.repaint() lootPanel.parent.repaint()
lootPanel.revalidate() lootPanel.revalidate()
@ -275,16 +273,11 @@ object LootTrackerView : View, OnPostClientTickCallback, OnKillingBlowNPCCallbac
// Create the panel for the item // Create the panel for the item
val itemPanel = FixedSizePanel(Dimension(36, 32)).apply { val itemPanel = FixedSizePanel(Dimension(36, 32)).apply {
preferredSize = Dimension(36, 32)
background = WIDGET_COLOR background = WIDGET_COLOR
minimumSize = preferredSize
maximumSize = preferredSize
val imageCanvas = ImageCanvas(bufferedImageSprite).apply { val imageCanvas = ImageCanvas(bufferedImageSprite).apply {
preferredSize = Dimension(36, 32) setFixedSize(36, 32)
background = WIDGET_COLOR background = WIDGET_COLOR
minimumSize = preferredSize
maximumSize = preferredSize
} }
// Add the imageCanvas to the panel // Add the imageCanvas to the panel
@ -476,9 +469,7 @@ object LootTrackerView : View, OnPostClientTickCallback, OnKillingBlowNPCCallbac
val labelPanel = JPanel(BorderLayout()).apply { val labelPanel = JPanel(BorderLayout()).apply {
background = TITLE_BAR_COLOR background = TITLE_BAR_COLOR
border = BorderFactory.createEmptyBorder(5, 5, 5, 5) border = BorderFactory.createEmptyBorder(5, 5, 5, 5)
maximumSize = Dimension(ViewConstants.DEFAULT_WIDGET_SIZE.width, 24) setFixedSize(ViewConstants.DEFAULT_WIDGET_SIZE.width, 24)
minimumSize = maximumSize
preferredSize = maximumSize
} }
val killCount = npcKillCounts.getOrPut(npcName) { 0 } val killCount = npcKillCounts.getOrPut(npcName) { 0 }
@ -536,18 +527,7 @@ object LootTrackerView : View, OnPostClientTickCallback, OnKillingBlowNPCCallbac
private fun removeLootFrameMenu(toRemove: JPanel, npcName: String): JPopupMenu { private fun removeLootFrameMenu(toRemove: JPanel, npcName: String): JPopupMenu {
// Create a popup menu // Create a popup menu
val popupMenu = PopupMenuComponent() val popupMenu = PopupMenuComponent()
val rFont = ViewConstants.FONT_RUNESCAPE_SMALL_16 popupMenu.addMenuItem("Remove") {
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 {
lootItemPanels[npcName]?.clear() lootItemPanels[npcName]?.clear()
npcKillCounts[npcName] = 0 npcKillCounts[npcName] = 0
lootTrackerView?.let { parent -> lootTrackerView?.let { parent ->
@ -574,14 +554,7 @@ object LootTrackerView : View, OnPostClientTickCallback, OnKillingBlowNPCCallbac
// Create a popup menu // Create a popup menu
val popupMenu = PopupMenuComponent() val popupMenu = PopupMenuComponent()
// Create menu items with custom font and colors popupMenu.addMenuItem("Reset Loot Tracker") {
val menuItem1 = JMenuItem("Reset Loot Tracker").apply {
font = ViewConstants.FONT_RUNESCAPE_SMALL_16
background = POPUP_BACKGROUND
foreground = POPUP_FOREGROUND
}
popupMenu.add(menuItem1)
menuItem1.addActionListener {
registerDrawAction { registerDrawAction {
resetLootTracker() resetLootTracker()
} }

View file

@ -4,13 +4,13 @@ import KondoKit.Helpers
import KondoKit.components.* import KondoKit.components.*
import KondoKit.ViewConstants import KondoKit.ViewConstants
import KondoKit.views.ViewLayoutHelpers.createSearchFieldSection import KondoKit.views.ViewLayoutHelpers.createSearchFieldSection
import KondoKit.setFixedSize
import KondoKit.pluginmanager.GitLabPlugin import KondoKit.pluginmanager.GitLabPlugin
import KondoKit.pluginmanager.GitLabPluginFetcher import KondoKit.pluginmanager.GitLabPluginFetcher
import KondoKit.pluginmanager.PluginDownloadManager import KondoKit.pluginmanager.PluginDownloadManager
import KondoKit.pluginmanager.PluginProperties import KondoKit.pluginmanager.PluginProperties
import KondoKit.pluginmanager.PluginInfoWithStatus import KondoKit.pluginmanager.PluginInfoWithStatus
import KondoKit.Helpers.showToast import KondoKit.Helpers.showToast
import KondoKit.plugin.Companion.TITLE_BAR_COLOR
import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND
import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR
import KondoKit.plugin.Companion.WIDGET_COLOR import KondoKit.plugin.Companion.WIDGET_COLOR
@ -304,17 +304,10 @@ object ReflectiveEditorView : View {
} }
// Edit button (only show if plugin has exposed attributes) // Edit button (only show if plugin has exposed attributes)
val editButton = if (exposedFields.isNotEmpty()) { val editButton = exposedFields.takeIf { it.isNotEmpty() }?.let {
val button = JButton("Edit") UiStyler.button(text = "Edit") {
button.background = TITLE_BAR_COLOR
button.foreground = secondaryColor
button.font = ViewConstants.FONT_RUNESCAPE_SMALL_14
button.addActionListener {
showPluginDetails(pluginInfo, plugin) showPluginDetails(pluginInfo, plugin)
} }
button
} else {
null
} }
// Plugin toggle switch (iOS style) - skip for KondoKit since it should always be on // 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 // Create a placeholder component that takes the same space but is invisible
val placeholder = JPanel() val placeholder = JPanel()
placeholder.background = WIDGET_COLOR placeholder.background = WIDGET_COLOR
placeholder.preferredSize = ViewConstants.TOGGLE_PLACEHOLDER_SIZE placeholder.setFixedSize(ViewConstants.TOGGLE_PLACEHOLDER_SIZE)
placeholder.maximumSize = ViewConstants.TOGGLE_PLACEHOLDER_SIZE
placeholder.isVisible = false placeholder.isVisible = false
placeholder placeholder
} }
@ -417,10 +409,7 @@ object ReflectiveEditorView : View {
nameLabel.font = ViewConstants.FONT_RUNESCAPE_SMALL_PLAIN_16 nameLabel.font = ViewConstants.FONT_RUNESCAPE_SMALL_PLAIN_16
// Action button based on plugin status // Action button based on plugin status
val actionButton = JButton() val actionButton = UiStyler.button()
actionButton.background = TITLE_BAR_COLOR
actionButton.foreground = secondaryColor
actionButton.font = ViewConstants.FONT_RUNESCAPE_SMALL_14
// Progress bar for downloads // Progress bar for downloads
val progressBar = JProgressBar(0, 100) val progressBar = JProgressBar(0, 100)

View file

@ -77,14 +77,3 @@ object ViewLayoutHelpers {
fun Container.addVerticalSpacing(pixels: Int) { fun Container.addVerticalSpacing(pixels: Int) {
add(Box.createVerticalStrut(pixels)) add(Box.createVerticalStrut(pixels))
} }
fun <T : Component> T.setFixedSize(width: Int, height: Int): T {
return setFixedSize(Dimension(width, height))
}
fun <T : Component> T.setFixedSize(size: Dimension): T {
preferredSize = size
minimumSize = size
maximumSize = size
return this
}

View file

@ -8,6 +8,7 @@ import KondoKit.Helpers.getProgressBarColor
import KondoKit.Helpers.getSpriteId import KondoKit.Helpers.getSpriteId
import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite
import KondoKit.ViewConstants import KondoKit.ViewConstants
import KondoKit.setFixedSize
import KondoKit.XPTable import KondoKit.XPTable
import KondoKit.components.PopupMenuComponent import KondoKit.components.PopupMenuComponent
import KondoKit.components.ProgressBar 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_COLOR
import KondoKit.plugin.Companion.WIDGET_SIZE import KondoKit.plugin.Companion.WIDGET_SIZE
import KondoKit.plugin import KondoKit.plugin
import KondoKit.plugin.Companion.POPUP_BACKGROUND
import KondoKit.plugin.Companion.POPUP_FOREGROUND
import KondoKit.plugin.Companion.playerXPMultiplier import KondoKit.plugin.Companion.playerXPMultiplier
import KondoKit.plugin.Companion.primaryColor import KondoKit.plugin.Companion.primaryColor
import KondoKit.plugin.Companion.secondaryColor 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 { private fun getSkillIcon(skillId: Int): BufferedImage {
return skillIconCache[skillId] ?: getBufferedImageFromSprite(API.GetSprite(getSpriteId(skillId))).also { return skillIconCache[skillId] ?: getBufferedImageFromSprite(API.GetSprite(getSpriteId(skillId))).also {
skillIconCache[skillId] = it skillIconCache[skillId] = it
@ -366,24 +359,16 @@ object XPTrackerView : View, OnUpdateCallback, OnXPUpdateCallback {
fun createResetMenu(): JPopupMenu { fun createResetMenu(): JPopupMenu {
val popupMenu = PopupMenuComponent() val popupMenu = PopupMenuComponent()
popupMenu.addMenuItem("Reset Tracker") {
val resetItem = createMenuItem("Reset Tracker") plugin.registerDrawAction { resetXPTracker(xpTrackerView!!) }
popupMenu.add(resetItem) }
resetItem.addActionListener { plugin.registerDrawAction { resetXPTracker(xpTrackerView!!) } }
return popupMenu return popupMenu
} }
fun removeXPWidgetMenu(toRemove: Container, skillId: Int): JPopupMenu { fun removeXPWidgetMenu(toRemove: Container, skillId: Int): JPopupMenu {
val popupMenu = PopupMenuComponent() val popupMenu = PopupMenuComponent()
val resetItem = createMenuItem("Reset") popupMenu.addMenuItem("Reset") {
popupMenu.add(resetItem)
val removeItem = createMenuItem("Remove")
popupMenu.add(removeItem)
resetItem.addActionListener {
xpWidgets[skillId]?.let { widget -> xpWidgets[skillId]?.let { widget ->
// Baseline at current XP and clear per-widget counters // Baseline at current XP and clear per-widget counters
initialXP[skillId] = widget.previousXp 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 // Reset the per-skill baseline to the current XP so next widget starts fresh
xpWidgets[skillId]?.let { widget -> xpWidgets[skillId]?.let { widget ->
initialXP[skillId] = widget.previousXp initialXP[skillId] = widget.previousXp
@ -440,9 +425,7 @@ object XPTrackerView : View, OnUpdateCallback, OnXPUpdateCallback {
val actionsLabel = createMetricLabel(actionsTitle) val actionsLabel = createMetricLabel(actionsTitle)
val progressBar = ProgressBar(0.0, getProgressBarColor(skillId)).apply { val progressBar = ProgressBar(0.0, getProgressBarColor(skillId)).apply {
preferredSize = Dimension(160, 22) setFixedSize(160, 22)
minimumSize = preferredSize
maximumSize = preferredSize
} }
val progressPanel = JPanel(BorderLayout()).apply { val progressPanel = JPanel(BorderLayout()).apply {
@ -484,15 +467,11 @@ object XPTrackerView : View, OnUpdateCallback, OnXPUpdateCallback {
) )
val outerPanel = JPanel(GridBagLayout()).apply { val outerPanel = JPanel(GridBagLayout()).apply {
background = WIDGET_COLOR background = WIDGET_COLOR
preferredSize = outerPanelSize setFixedSize(outerPanelSize)
maximumSize = outerPanelSize
minimumSize = outerPanelSize
} }
val innerPanel = JPanel(BorderLayout()).apply { val innerPanel = JPanel(BorderLayout()).apply {
background = WIDGET_COLOR background = WIDGET_COLOR
preferredSize = component.preferredSize setFixedSize(component.preferredSize)
maximumSize = component.preferredSize
minimumSize = component.preferredSize
add(component, BorderLayout.CENTER) add(component, BorderLayout.CENTER)
} }
val gbc = GridBagConstraints().apply { val gbc = GridBagConstraints().apply {