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.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
}

View file

@ -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
}
}
}

View file

@ -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)
}
}
}

View file

@ -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
}
}
}

View file

@ -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

View file

@ -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<Any>()
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<Any, Any> ?: HashMap<Any, Any>()
// 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<String, Int> - treat all HashMap<String, Int> fields the same way regardless of plugin
val fieldTypeName = field.genericType.toString()
if (fieldTypeName.contains("java.util.HashMap<java.lang.String, java.lang.Integer>") ||
fieldTypeName.contains("HashMap<String, Int>") ||
fieldTypeName.contains("HashMap<String, Integer>")) {
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<java.lang.String, java.lang.Integer>") ||
fieldTypeName.contains("HashMap<String, Int>") ||
fieldTypeName.contains("HashMap<String, Integer>") -> {
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

View file

@ -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
}
}
}

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
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()

View file

@ -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)
}
}

View file

@ -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

View file

@ -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)
}
}

View file

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

View file

@ -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)

View file

@ -77,14 +77,3 @@ object ViewLayoutHelpers {
fun Container.addVerticalSpacing(pixels: Int) {
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.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 {