reorganize

This commit is contained in:
downthecrop 2025-09-08 04:00:39 -07:00
parent 529f0c22b0
commit cf6bb51d2c
20 changed files with 815 additions and 411 deletions

View file

@ -0,0 +1,45 @@
package KondoKit.components
import KondoKit.plugin.Companion.TITLE_BAR_COLOR
import KondoKit.plugin.Companion.WIDGET_COLOR
import KondoKit.plugin.Companion.secondaryColor
import java.awt.*
import javax.swing.*
class ButtonPanel(
private val alignment: Int = FlowLayout.CENTER,
private val hgap: Int = 5,
private val vgap: Int = 0
) : JPanel() {
init {
layout = FlowLayout(alignment, hgap, vgap)
background = WIDGET_COLOR
}
fun addButton(text: String, action: () -> Unit): JButton {
val button = JButton(text).apply {
background = TITLE_BAR_COLOR
foreground = secondaryColor
font = Font("RuneScape Small", Font.PLAIN, 14)
addActionListener {
action()
}
}
add(button)
return button
}
fun addIcon(icon: Icon, action: () -> Unit): JButton {
val button = JButton(icon).apply {
background = TITLE_BAR_COLOR
foreground = secondaryColor
font = Font("RuneScape Small", Font.PLAIN, 14)
addActionListener {
action()
}
}
add(button)
return button
}
}

View file

@ -0,0 +1,60 @@
package KondoKit.components
import KondoKit.ImageCanvas
import KondoKit.SpriteToBufferedImage
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
class IconComponent(
spriteId: Int,
private val iconWidth: Int = 25,
private val iconHeight: Int = 23,
private val useThemeColors: Boolean = true,
private val tint: Color? = null,
private val grayscale: Boolean = false,
private val brightnessBoost: Float = 1.0f
) : JPanel() {
private val imageCanvas: ImageCanvas
init {
layout = BorderLayout()
background = if (useThemeColors) WIDGET_COLOR else Color.WHITE
val bufferedImageSprite = SpriteToBufferedImage.getBufferedImageFromSprite(
API.GetSprite(spriteId),
tint,
grayscale,
brightnessBoost
)
imageCanvas = ImageCanvas(bufferedImageSprite).apply {
val size = Dimension(iconWidth, iconHeight)
preferredSize = size
maximumSize = size
minimumSize = size
background = if (useThemeColors) WIDGET_COLOR else Color.WHITE
}
add(imageCanvas, BorderLayout.CENTER)
border = BorderFactory.createEmptyBorder(2, 2, 2, 2)
}
fun updateFillColor(color: Color) {
imageCanvas.fillColor = color
background = color
imageCanvas.repaint()
repaint()
}
fun applyThemeColors() {
updateFillColor(WIDGET_COLOR)
}
}

View file

@ -0,0 +1,35 @@
package KondoKit.components
import KondoKit.Helpers.formatHtmlLabelText
import KondoKit.plugin.Companion.primaryColor
import KondoKit.plugin.Companion.secondaryColor
import java.awt.Font
import java.awt.Color
import javax.swing.JLabel
import javax.swing.SwingConstants
class LabelComponent(
text: String = "",
private val isHtml: Boolean = false,
private val alignment: Int = SwingConstants.LEFT
) : JLabel() {
init {
this.text = text
this.horizontalAlignment = alignment
this.font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16)
}
fun updateText(plainText: String, color: Color = secondaryColor) {
this.text = plainText
this.foreground = color
}
fun updateHtmlText(text1: String, color1: Color = primaryColor, text2: String = "", color2: Color = secondaryColor) {
this.text = formatHtmlLabelText(text1, color1, text2, color2)
}
fun setAsHeader() {
font = Font("RuneScape Small", Font.BOLD, 16)
}
}

View file

@ -0,0 +1,27 @@
package KondoKit.components
import KondoKit.plugin.Companion.POPUP_BACKGROUND
import KondoKit.plugin.Companion.POPUP_FOREGROUND
import java.awt.Font
import javax.swing.JMenuItem
import javax.swing.JPopupMenu
class PopupMenuComponent : JPopupMenu() {
init {
background = POPUP_BACKGROUND
}
fun addMenuItem(text: String, action: () -> Unit): JMenuItem {
val menuItem = JMenuItem(text).apply {
font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16)
background = POPUP_BACKGROUND
foreground = POPUP_FOREGROUND
addActionListener {
action()
}
}
add(menuItem)
return menuItem
}
}

View file

@ -1,4 +1,4 @@
package KondoKit
package KondoKit.components
import KondoKit.plugin.Companion.PROGRESS_BAR_FILL
import KondoKit.plugin.Companion.secondaryColor

View file

@ -1,4 +1,4 @@
package KondoKit.ReflectiveEditorComponents
package KondoKit.components.ReflectiveEditorComponents
import KondoKit.ImageCanvas
import KondoKit.plugin

View file

@ -1,4 +1,4 @@
package KondoKit.ReflectiveEditorComponents
package KondoKit.components.ReflectiveEditorComponents
data class GitLabPlugin(
val id: String,

View file

@ -1,6 +1,6 @@
package KondoKit.ReflectiveEditorComponents
package KondoKit.components.ReflectiveEditorComponents
import KondoKit.ReflectiveEditorView
import KondoKit.views.ReflectiveEditorView
import com.google.gson.Gson
import com.google.gson.JsonObject
import java.awt.EventQueue

View file

@ -1,4 +1,4 @@
package KondoKit
package KondoKit.components
import KondoKit.plugin.Companion.SCROLL_BAR_COLOR
import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR

View file

@ -0,0 +1,155 @@
package KondoKit.components
import KondoKit.ImageCanvas
import KondoKit.SpriteToBufferedImage
import KondoKit.plugin.Companion.WIDGET_COLOR
import KondoKit.plugin.Companion.secondaryColor
import plugin.api.API
import java.awt.*
import java.awt.datatransfer.DataFlavor
import java.awt.event.*
import javax.swing.*
open class SearchField(
private val onSearch: (String) -> Unit,
private val placeholderText: String = "Search...",
private val fieldWidth: Int = 230,
private val fieldHeight: Int = 30
) : Canvas() {
private var cursorVisible: Boolean = true
private var text: String = ""
private val bufferedImageSprite = SpriteToBufferedImage.getBufferedImageFromSprite(API.GetSprite(1423)) // MAG_SPRITE
private val imageCanvas = bufferedImageSprite.let {
ImageCanvas(it).apply {
preferredSize = Dimension(12, 12)
size = preferredSize
minimumSize = preferredSize
maximumSize = preferredSize
fillColor = WIDGET_COLOR
}
}
init {
val dimension = Dimension(fieldWidth, fieldHeight)
preferredSize = dimension
background = WIDGET_COLOR
foreground = secondaryColor
font = Font("Arial", Font.PLAIN, 14)
minimumSize = dimension
maximumSize = dimension
addKeyListener(object : KeyAdapter() {
override fun keyTyped(e: KeyEvent) {
// Prevent null character from being typed on Ctrl+A & Ctrl+V
if (e.isControlDown && (e.keyChar == '\u0001' || e.keyChar == '\u0016')) {
e.consume()
return
}
if (e.keyChar == '\b') {
if (text.isNotEmpty()) {
text = text.dropLast(1)
}
} else if (e.keyChar == '\n') {
onSearch(text)
} else {
text += e.keyChar
}
SwingUtilities.invokeLater {
repaint()
}
}
override fun keyPressed(e: KeyEvent) {
if (e.isControlDown) {
when (e.keyCode) {
KeyEvent.VK_A -> {
text = ""
SwingUtilities.invokeLater {
repaint()
}
}
KeyEvent.VK_V -> {
try {
val clipboard = Toolkit.getDefaultToolkit().systemClipboard
val pasteText = clipboard.getData(DataFlavor.stringFlavor) as String
text += pasteText
SwingUtilities.invokeLater {
repaint()
}
} catch (ex: Exception) {
// Ignore clipboard errors
}
}
}
}
}
})
addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
if (e.x > width - 20 && e.y < 20) {
text = ""
onSearch(text)
SwingUtilities.invokeLater {
repaint()
}
}
}
})
Timer(500) { _ ->
cursorVisible = !cursorVisible
SwingUtilities.invokeLater {
repaint()
}
}.start()
}
override fun paint(g: Graphics) {
super.paint(g)
g.color = foreground
g.font = font
val fm = g.fontMetrics
val cursorX = fm.stringWidth(text) + 30
// Draw magnifying glass icon
imageCanvas.let { canvas ->
val imgG = g.create(5, 5, canvas.width, canvas.height)
canvas.paint(imgG)
imgG.dispose()
}
// Use a local copy of the text to avoid threading issues
val currentText = text
// Draw placeholder text if field is empty, otherwise draw actual text
if (currentText.isEmpty()) {
g.color = Color.GRAY // Use a lighter color for placeholder text
g.drawString(placeholderText, 30, 20)
} else {
g.color = foreground // Use normal color for actual text
g.drawString(currentText, 30, 20)
}
if (cursorVisible && hasFocus()) {
g.color = foreground
g.drawLine(cursorX, 5, cursorX, 25)
}
// Only draw the "x" button if there's text
if (currentText.isNotEmpty()) {
g.color = Color.RED
g.drawString("x", width - 20, 20)
}
}
fun setText(newText: String) {
text = newText
repaint()
}
fun getText(): String = text
}

View file

@ -0,0 +1,231 @@
package KondoKit.components
import KondoKit.Helpers
import KondoKit.Helpers.FieldNotifier
import KondoKit.plugin.Companion.WIDGET_COLOR
import KondoKit.plugin.Companion.primaryColor
import KondoKit.plugin.Companion.secondaryColor
import plugin.Plugin
import java.awt.*
import java.awt.event.MouseAdapter
import java.awt.event.MouseEvent
import java.util.*
import java.util.Timer
import javax.swing.*
class SettingsPanel(private val plugin: Plugin) : JPanel() {
init {
layout = BoxLayout(this, BoxLayout.Y_AXIS)
background = WIDGET_COLOR
border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
}
fun addSettingsFromPlugin() {
val fieldNotifier = FieldNotifier(plugin)
val exposedFields = plugin.javaClass.declaredFields.filter { field ->
field.annotations.any { annotation ->
annotation.annotationClass.simpleName == "Exposed"
}
}
if (exposedFields.isNotEmpty()) {
for (field in exposedFields) {
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 fieldPanel = JPanel().apply {
layout = GridBagLayout()
background = WIDGET_COLOR
foreground = secondaryColor
border = BorderFactory.createEmptyBorder(5, 0, 5, 0)
maximumSize = Dimension(Int.MAX_VALUE, 50)
}
val gbc = GridBagConstraints().apply {
insets = Insets(0, 5, 0, 5)
}
val label = JLabel(field.name.capitalize()).apply {
foreground = secondaryColor
font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16)
}
gbc.gridx = 0
gbc.gridy = 0
gbc.weightx = 0.0
gbc.anchor = GridBagConstraints.WEST
fieldPanel.add(label, gbc)
// Create appropriate input component based on field type
val inputComponent: JComponent = when {
field.type == Boolean::class.javaPrimitiveType || field.type == java.lang.Boolean::class.java ->
JCheckBox().apply {
isSelected = field.get(plugin) as Boolean
}
field.type.isEnum ->
JComboBox((field.type.enumConstants as Array<Enum<*>>)).apply {
selectedItem = field.get(plugin)
}
field.type == Int::class.javaPrimitiveType || field.type == Integer::class.java ->
JSpinner(SpinnerNumberModel(field.get(plugin) as Int, Int.MIN_VALUE, Int.MAX_VALUE, 1))
field.type == Float::class.javaPrimitiveType ||
field.type == Double::class.javaPrimitiveType ||
field.type == java.lang.Float::class.java ||
field.type == java.lang.Double::class.java ->
JSpinner(SpinnerNumberModel((field.get(plugin) as Number).toDouble(), -Double.MAX_VALUE, Double.MAX_VALUE, 0.1))
else ->
JTextField(field.get(plugin)?.toString() ?: "")
}
// Add mouse listener to the label only if a description is available
if (description.isNotBlank()) {
label.cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)
label.addMouseListener(object : MouseAdapter() {
override fun mouseEntered(e: MouseEvent) {
showCustomToolTip(description, label)
}
override fun mouseExited(e: MouseEvent) {
customToolTipWindow?.isVisible = false
}
})
}
gbc.gridx = 1
gbc.gridy = 0
gbc.weightx = 1.0
gbc.fill = GridBagConstraints.HORIZONTAL
fieldPanel.add(inputComponent, gbc)
val applyButton = JButton("\u2714").apply {
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
var previousValue = field.get(plugin)?.toString()
val timer = Timer()
timer.schedule(object : TimerTask() {
override fun run() {
val currentValue = field.get(plugin)?.toString()
if (currentValue != previousValue) {
previousValue = currentValue
SwingUtilities.invokeLater {
// Update the inputComponent based on the new value
when (inputComponent) {
is JCheckBox -> inputComponent.isSelected = field.get(plugin) as Boolean
is JComboBox<*> -> inputComponent.selectedItem = field.get(plugin)
is JSpinner -> inputComponent.value = field.get(plugin)
is JTextField -> inputComponent.text = field.get(plugin)?.toString() ?: ""
}
}
}
}
}, 0, 1000) // Poll every 1000 milliseconds (1 second)
}
if (exposedFields.isNotEmpty()) {
add(Box.createVerticalStrut(5))
}
}
}
companion object {
var customToolTipWindow: JWindow? = null
fun showCustomToolTip(text: String, component: JComponent) {
val _font = Font("RuneScape Small", Font.PLAIN, 16)
val maxWidth = 150
val lineHeight = 16
// Create a dummy JLabel to get FontMetrics for the font used in the tooltip
val dummyLabel = JLabel()
dummyLabel.font = _font
val fontMetrics = dummyLabel.getFontMetrics(_font)
// Calculate the approximate width of the text
val textWidth = fontMetrics.stringWidth(text)
// Calculate the number of lines required based on the text width and max tooltip width
val numberOfLines = Math.ceil(textWidth.toDouble() / maxWidth).toInt()
// Calculate the required height of the tooltip
val requiredHeight = numberOfLines * lineHeight + 6 // Adding some padding
if (customToolTipWindow == null) {
customToolTipWindow = JWindow().apply {
val bgColor = Helpers.colorToHex(KondoKit.plugin.Companion.TOOLTIP_BACKGROUND)
val textColor = Helpers.colorToHex(KondoKit.plugin.Companion.secondaryColor)
contentPane = JLabel("<html><div style='color: $textColor; background-color: $bgColor; padding: 3px; word-break: break-all;'>$text</div></html>").apply {
border = BorderFactory.createLineBorder(Color.BLACK)
isOpaque = true
background = KondoKit.plugin.Companion.TOOLTIP_BACKGROUND
foreground = Color.WHITE
font = _font
maximumSize = Dimension(maxWidth, Int.MAX_VALUE)
preferredSize = Dimension(maxWidth, requiredHeight)
}
pack()
}
} else {
// Update the tooltip text
val label = customToolTipWindow!!.contentPane as JLabel
val bgColor = Helpers.colorToHex(KondoKit.plugin.Companion.TOOLTIP_BACKGROUND)
val textColor = Helpers.colorToHex(KondoKit.plugin.Companion.secondaryColor)
label.text = "<html><div style='color: $textColor; background-color: $bgColor; padding: 3px; word-break: break-all;'>$text</div></html>"
label.preferredSize = Dimension(maxWidth, requiredHeight)
customToolTipWindow!!.pack()
}
// Position the tooltip near the component
val locationOnScreen = component.locationOnScreen
customToolTipWindow!!.setLocation(locationOnScreen.x, locationOnScreen.y + 15)
customToolTipWindow!!.isVisible = true
}
}
}

View file

@ -1,4 +1,4 @@
package KondoKit
package KondoKit.components
import java.awt.*
import java.awt.event.MouseAdapter

View file

@ -0,0 +1,31 @@
package KondoKit.components
import KondoKit.plugin.Companion.TITLE_BAR_COLOR
import KondoKit.plugin.Companion.secondaryColor
import java.awt.*
import javax.swing.*
class ViewHeader(
title: String,
private val headerHeight: Int = 40
) : JPanel() {
private val titleLabel = JLabel(title)
init {
background = TITLE_BAR_COLOR
preferredSize = Dimension(Int.MAX_VALUE, headerHeight)
border = BorderFactory.createEmptyBorder(5, 10, 5, 10)
layout = BorderLayout()
titleLabel.foreground = secondaryColor
titleLabel.font = Font("RuneScape Small", Font.PLAIN, 16)
titleLabel.horizontalAlignment = SwingConstants.CENTER
add(titleLabel, BorderLayout.CENTER)
}
fun setTitle(title: String) {
titleLabel.text = title
}
}

View file

@ -0,0 +1,35 @@
package KondoKit.components
import KondoKit.plugin.Companion.WIDGET_COLOR
import java.awt.BorderLayout
import java.awt.Dimension
import javax.swing.BorderFactory
import javax.swing.JPanel
class WidgetPanel(
private val widgetWidth: Int = 220,
private val widgetHeight: Int = 50,
private val addDefaultPadding: Boolean = true
) : JPanel() {
init {
layout = BorderLayout(5, 5)
background = WIDGET_COLOR
val size = Dimension(widgetWidth, widgetHeight)
preferredSize = size
maximumSize = size
minimumSize = size
if (addDefaultPadding) {
border = BorderFactory.createEmptyBorder(5, 5, 5, 5)
}
}
fun setFixedSize(width: Int, height: Int) {
val size = Dimension(width, height)
preferredSize = size
maximumSize = size
minimumSize = size
}
}

View file

@ -1,35 +1,43 @@
package KondoKit
import KondoKit.Constants.COMBAT_LVL_SPRITE
import KondoKit.Helpers.formatHtmlLabelText
import KondoKit.Helpers.formatNumber
import KondoKit.Helpers.getSpriteId
import KondoKit.Helpers.showAlert
import KondoKit.HiscoresView.createHiscoreSearchView
import KondoKit.HiscoresView.hiScoreView
import KondoKit.LootTrackerView.BAG_ICON
import KondoKit.LootTrackerView.createLootTrackerView
import KondoKit.LootTrackerView.lootTrackerView
import KondoKit.LootTrackerView.npcDeathSnapshots
import KondoKit.LootTrackerView.onPostClientTick
import KondoKit.LootTrackerView.takeGroundSnapshot
import KondoKit.ReflectiveEditorView.addPlugins
import KondoKit.ReflectiveEditorView.createReflectiveEditorView
import KondoKit.ReflectiveEditorView.reflectiveEditorView
import KondoKit.views.HiscoresView
import KondoKit.views.LootTrackerView
import KondoKit.views.ReflectiveEditorView
import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite
import KondoKit.Themes.Theme
import KondoKit.Themes.ThemeType
import KondoKit.Themes.getTheme
import KondoKit.XPTrackerView.createXPTrackerView
import KondoKit.XPTrackerView.createXPWidget
import KondoKit.XPTrackerView.initialXP
import KondoKit.XPTrackerView.resetXPTracker
import KondoKit.XPTrackerView.totalXPWidget
import KondoKit.XPTrackerView.updateWidget
import KondoKit.XPTrackerView.wrappedWidget
import KondoKit.XPTrackerView.xpTrackerView
import KondoKit.XPTrackerView.xpWidgets
import KondoKit.components.ProgressBar
import KondoKit.components.ScrollablePanel
import KondoKit.components.ToggleSwitch
import KondoKit.components.*
import KondoKit.views.XPTrackerView
import KondoKit.plugin.StateManager.focusedView
import KondoKit.views.Constants.COMBAT_LVL_SPRITE
import KondoKit.views.HiscoresView.createHiscoreSearchView
import KondoKit.views.HiscoresView.hiScoreView
import KondoKit.views.LootTrackerView.BAG_ICON
import KondoKit.views.LootTrackerView.createLootTrackerView
import KondoKit.views.LootTrackerView.lootTrackerView
import KondoKit.views.LootTrackerView.npcDeathSnapshots
import KondoKit.views.LootTrackerView.onPostClientTick
import KondoKit.views.LootTrackerView.takeGroundSnapshot
import KondoKit.views.ReflectiveEditorView.addPlugins
import KondoKit.views.ReflectiveEditorView.createReflectiveEditorView
import KondoKit.views.ReflectiveEditorView.reflectiveEditorView
import KondoKit.views.XPTrackerView.createXPTrackerView
import KondoKit.views.XPTrackerView.createXPWidget
import KondoKit.views.XPTrackerView.initialXP
import KondoKit.views.XPTrackerView.resetXPTracker
import KondoKit.views.XPTrackerView.totalXPWidget
import KondoKit.views.XPTrackerView.updateWidget
import KondoKit.views.XPTrackerView.wrappedWidget
import KondoKit.views.XPTrackerView.xpTrackerView
import KondoKit.views.XPTrackerView.xpWidgets
import plugin.Plugin
import plugin.api.*
import plugin.api.API.*

View file

@ -0,0 +1,33 @@
package KondoKit.views
import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR
import java.awt.Dimension
import javax.swing.BorderFactory
import javax.swing.Box
import javax.swing.BoxLayout
import javax.swing.JPanel
open class BaseView(
private val viewName: String,
private val preferredWidth: Int = 242,
private val addDefaultSpacing: Boolean = true
) : JPanel() {
init {
layout = BoxLayout(this, BoxLayout.Y_AXIS)
name = viewName
background = VIEW_BACKGROUND_COLOR
border = BorderFactory.createEmptyBorder(0, 0, 0, 0)
if (addDefaultSpacing) {
add(Box.createVerticalStrut(5))
}
}
fun setViewSize(height: Int) {
val dimension = Dimension(preferredWidth, height)
preferredSize = dimension
maximumSize = dimension
minimumSize = dimension
}
}

View file

@ -1,19 +1,17 @@
package KondoKit
package KondoKit.views
import KondoKit.Constants.COLOR_BACKGROUND_DARK
import KondoKit.Constants.SKILL_DISPLAY_ORDER
import KondoKit.Constants.SKILL_SPRITE_DIMENSION
import KondoKit.Helpers.formatHtmlLabelText
import KondoKit.Helpers.getSpriteId
import KondoKit.Helpers.showToast
import KondoKit.ImageCanvas
import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite
import KondoKit.plugin.Companion.POPUP_FOREGROUND
import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND
import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR
import KondoKit.components.LabelComponent
import KondoKit.components.SearchField
import KondoKit.plugin.Companion.WIDGET_COLOR
import KondoKit.plugin.Companion.primaryColor
import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR
import KondoKit.plugin.Companion.POPUP_FOREGROUND
import KondoKit.plugin.Companion.secondaryColor
import KondoKit.plugin.StateManager.focusedView
import KondoKit.plugin.Companion.primaryColor
import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND
import com.google.gson.Gson
import plugin.api.API
import rt4.Sprites
@ -68,120 +66,17 @@ object HiscoresView {
const val VIEW_NAME = "HISCORE_SEARCH_VIEW"
var hiScoreView: JPanel? = null
class CustomSearchField(private val hiscoresPanel: JPanel) : Canvas() {
class CustomSearchField(private val hiscoresPanel: JPanel) : SearchField({ username ->
// Handle search action
(this as CustomSearchField).searchPlayer(username)
}) {
private var cursorVisible: Boolean = true
private var text: String = ""
private val gson = Gson()
private val bufferedImageSprite = getBufferedImageFromSprite(API.GetSprite(Constants.MAG_SPRITE))
private val imageCanvas = bufferedImageSprite.let {
ImageCanvas(it).apply {
preferredSize = Constants.ICON_DIMENSION_SMALL
size = preferredSize
minimumSize = preferredSize
maximumSize = preferredSize
fillColor = COLOR_BACKGROUND_DARK
}
}
init {
preferredSize = Constants.SEARCH_FIELD_DIMENSION
background = Constants.COLOR_BACKGROUND_DARK
foreground = Constants.COLOR_FOREGROUND_LIGHT
font = Constants.FONT_ARIAL_PLAIN_14
minimumSize = preferredSize
maximumSize = preferredSize
addKeyListener(object : KeyAdapter() {
override fun keyTyped(e: KeyEvent) {
// Prevent null character from being typed on Ctrl+A & Ctrl+V
if (e.isControlDown && (e.keyChar == '\u0001' || e.keyChar == '\u0016')) {
e.consume()
return
}
if (e.keyChar == '\b') {
if (text.isNotEmpty()) {
text = text.dropLast(1)
}
} else if (e.keyChar == '\n') {
searchPlayer(text)
} else {
text += e.keyChar
}
SwingUtilities.invokeLater {
repaint()
}
}
override fun keyPressed(e: KeyEvent) {
if (e.isControlDown) {
when (e.keyCode) {
KeyEvent.VK_A -> {
text = ""
repaint()
}
KeyEvent.VK_V -> {
val clipboard = Toolkit.getDefaultToolkit().systemClipboard
val pasteText = clipboard.getData(DataFlavor.stringFlavor) as String
text += pasteText
SwingUtilities.invokeLater {
repaint()
}
}
}
}
}
})
addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
if (e.x > width - 20 && e.y < 20) {
text = ""
SwingUtilities.invokeLater {
repaint()
}
}
}
})
Timer(500) {
cursorVisible = !cursorVisible
if(focusedView == VIEW_NAME)
SwingUtilities.invokeLater {
repaint()
}
}.start()
}
override fun paint(g: Graphics) {
super.paint(g)
g.color = foreground
g.font = font
val fm = g.fontMetrics
val cursorX = fm.stringWidth(text) + 30
imageCanvas.let { canvas ->
val imgG = g.create(5, 5, canvas.width, canvas.height)
canvas.paint(imgG)
imgG.dispose()
}
g.drawString(text, 30, 20)
if (cursorVisible && hasFocus()) {
g.drawLine(cursorX, 5, cursorX, 25)
}
if (text.isNotEmpty()) {
g.color = Color.RED
g.drawString("x", width - 20, 20)
}
}
fun searchPlayer(username: String) {
text = username.replace(" ", "_")
val apiUrl = "http://api.2009scape.org:3000/hiscores/playerSkills/1/${text.toLowerCase()}"
val cleanUsername = username.replace(" ", "_")
setText(cleanUsername)
val apiUrl = "http://api.2009scape.org:3000/hiscores/playerSkills/1/${cleanUsername.toLowerCase()}"
updateHiscoresView(null, "Searching...")
@ -222,7 +117,6 @@ object HiscoresView {
}.start()
}
private fun updatePlayerData(jsonResponse: String, username: String) {
val hiscoresResponse = gson.fromJson(jsonResponse, HiscoresResponse::class.java)
updateHiscoresView(hiscoresResponse, username)
@ -231,10 +125,12 @@ object HiscoresView {
private fun updateHiscoresView(data: HiscoresResponse?, username: String) {
val playerNameLabel = findComponentByName(hiscoresPanel, "playerNameLabel") as? JPanel
playerNameLabel?.removeAll() // Clear previous components
var nameLabel = JLabel(formatHtmlLabelText(username, secondaryColor, "", primaryColor), JLabel.CENTER).apply {
var nameLabel = LabelComponent().apply {
updateHtmlText(username, secondaryColor, "", primaryColor)
font = Constants.FONT_ARIAL_BOLD_12
foreground = Constants.COLOR_FOREGROUND_LIGHT
border = BorderFactory.createEmptyBorder(0, 6, 0, 0) // Top, Left, Bottom, Right padding
horizontalAlignment = JLabel.CENTER
}
playerNameLabel?.add(nameLabel)
playerNameLabel?.revalidate()
@ -259,10 +155,12 @@ object HiscoresView {
}
val exp_multiplier = data.info.exp_multiplier
nameLabel = JLabel(formatHtmlLabelText(username, secondaryColor, " (${exp_multiplier}x)", primaryColor), JLabel.CENTER).apply {
nameLabel = LabelComponent().apply {
updateHtmlText(username, secondaryColor, " (${exp_multiplier}x)", primaryColor)
font = Constants.FONT_ARIAL_BOLD_12
foreground = Constants.COLOR_FOREGROUND_LIGHT
border = BorderFactory.createEmptyBorder(0, 6, 0, 0) // Top, Left, Bottom, Right padding
horizontalAlignment = JLabel.CENTER
}
@ -341,13 +239,9 @@ object HiscoresView {
}
fun createHiscoreSearchView() {
val hiscorePanel = JPanel().apply {
layout = BoxLayout(this, BoxLayout.Y_AXIS)
name = VIEW_NAME
val hiscorePanel = BaseView(VIEW_NAME, Constants.HISCORE_PANEL_DIMENSION.width).apply {
background = Constants.COLOR_BACKGROUND_MEDIUM
preferredSize = Constants.HISCORE_PANEL_DIMENSION
maximumSize = preferredSize
minimumSize = preferredSize
setViewSize(Constants.HISCORE_PANEL_DIMENSION.height)
}
val customSearchField = CustomSearchField(hiscorePanel)
@ -391,23 +285,23 @@ object HiscoresView {
minimumSize = preferredSize
}
for (i in SKILL_DISPLAY_ORDER) {
for (i in Constants.SKILL_DISPLAY_ORDER) {
val skillPanel = JPanel().apply {
layout = BorderLayout()
background = COLOR_BACKGROUND_DARK
background = Constants.COLOR_BACKGROUND_DARK
preferredSize = Constants.SKILL_PANEL_DIMENSION
maximumSize = preferredSize
minimumSize = preferredSize
border = MatteBorder(5, 0, 0, 0, COLOR_BACKGROUND_DARK)
border = MatteBorder(5, 0, 0, 0, Constants.COLOR_BACKGROUND_DARK)
}
val bufferedImageSprite = getBufferedImageFromSprite(API.GetSprite(getSpriteId(i)))
val imageCanvas = bufferedImageSprite.let {
ImageCanvas(it).apply {
preferredSize = SKILL_SPRITE_DIMENSION
size = SKILL_SPRITE_DIMENSION
fillColor = COLOR_BACKGROUND_DARK
preferredSize = Constants.SKILL_SPRITE_DIMENSION
size = Constants.SKILL_SPRITE_DIMENSION
fillColor = Constants.COLOR_BACKGROUND_DARK
}
}
@ -420,7 +314,7 @@ object HiscoresView {
}
val imageContainer = JPanel(FlowLayout(FlowLayout.CENTER, 5, 0)).apply {
background = COLOR_BACKGROUND_DARK
background = Constants.COLOR_BACKGROUND_DARK
add(imageCanvas)
add(numberLabel)
}
@ -432,7 +326,7 @@ object HiscoresView {
hiscorePanel.add(skillsPanel)
val totalCombatPanel = JPanel(FlowLayout(FlowLayout.CENTER, 0, 0)).apply {
background = COLOR_BACKGROUND_DARK
background = Constants.COLOR_BACKGROUND_DARK
preferredSize = Constants.TOTAL_COMBAT_PANEL_DIMENSION
maximumSize = preferredSize
minimumSize = preferredSize
@ -441,7 +335,7 @@ object HiscoresView {
val bufferedImageSprite = getBufferedImageFromSprite(API.GetSprite(Constants.LVL_BAR_SPRITE))
val totalLevelIcon = ImageCanvas(bufferedImageSprite).apply {
fillColor = COLOR_BACKGROUND_DARK
fillColor = Constants.COLOR_BACKGROUND_DARK
preferredSize = Constants.ICON_DIMENSION_LARGE
size = Constants.ICON_DIMENSION_LARGE
}
@ -463,7 +357,7 @@ object HiscoresView {
val bufferedImageSprite2 = getBufferedImageFromSprite(API.GetSprite(Constants.COMBAT_LVL_SPRITE))
val combatLevelIcon = ImageCanvas(bufferedImageSprite2).apply {
fillColor = COLOR_BACKGROUND_DARK
fillColor = Constants.COLOR_BACKGROUND_DARK
preferredSize = Constants.ICON_DIMENSION_LARGE
size = Constants.ICON_DIMENSION_LARGE
}
@ -477,7 +371,7 @@ object HiscoresView {
}
val combatLevelPanel = JPanel(FlowLayout(FlowLayout.LEFT)).apply {
background = COLOR_BACKGROUND_DARK
background = Constants.COLOR_BACKGROUND_DARK
add(combatLevelIcon)
add(combatLevelLabel)
}

View file

@ -1,19 +1,26 @@
package KondoKit
package KondoKit.views
import KondoKit.Helpers
import KondoKit.Helpers.addMouseListenerToAll
import KondoKit.Helpers.formatHtmlLabelText
import KondoKit.ImageCanvas
import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite
import KondoKit.XPTrackerView.wrappedWidget
import KondoKit.views.XPTrackerView.wrappedWidget
import KondoKit.components.PopupMenuComponent
import KondoKit.components.ProgressBar
import KondoKit.plugin.Companion.useLiveGEPrices
import KondoKit.plugin.Companion.WIDGET_COLOR
import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR
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
import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR
import KondoKit.plugin.Companion.WIDGET_COLOR
import KondoKit.plugin.Companion.primaryColor
import KondoKit.plugin.Companion.registerDrawAction
import KondoKit.plugin.Companion.secondaryColor
import KondoKit.plugin.StateManager.focusedView
import KondoKit.views.BaseView
import plugin.api.API
import rt4.*
import java.awt.*
@ -44,7 +51,7 @@ object LootTrackerView {
var lootTrackerView: JPanel? = null
fun loadGEPrices(): Map<String, String> {
return if (plugin.useLiveGEPrices) {
return if (useLiveGEPrices) {
try {
println("LootTracker: Loading Remote GE Prices")
val url = URL("https://cdn.2009scape.org/gedata/latest.json")
@ -103,9 +110,7 @@ object LootTrackerView {
fun createLootTrackerView() {
lootTrackerView = JPanel().apply {
layout = BoxLayout(this, BoxLayout.Y_AXIS) // Use BoxLayout on Y axis to stack widgets vertically
background = VIEW_BACKGROUND_COLOR
lootTrackerView = BaseView(VIEW_NAME, addDefaultSpacing = false).apply {
add(Box.createVerticalStrut(5))
totalTrackerWidget = createTotalLootWidget()
@ -425,7 +430,7 @@ object LootTrackerView {
newDrops.forEach { drop ->
val geValue = (gePriceMap[drop.id.toString()]?.toInt() ?: 0) * drop.quantity
updateValueLabel(lootTrackerView, geValue.toString(), npcName)
plugin.registerDrawAction { addItemToLootPanel(lootTrackerView, drop, npcName) }
registerDrawAction { addItemToLootPanel(lootTrackerView, drop, npcName) }
updateTotalValue(geValue)
}
}
@ -501,16 +506,16 @@ object LootTrackerView {
private fun removeLootFrameMenu(toRemove: JPanel, npcName: String): JPopupMenu {
// Create a popup menu
val popupMenu = JPopupMenu()
val popupMenu = PopupMenuComponent()
val rFont = Font("RuneScape Small", Font.TRUETYPE_FONT, 16)
popupMenu.background = POPUP_BACKGROUND
popupMenu.background = KondoKit.plugin.Companion.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
background = KondoKit.plugin.Companion.POPUP_BACKGROUND // Dark background for item
foreground = KondoKit.plugin.Companion.POPUP_FOREGROUND // Light text color for item
}
popupMenu.add(menuItem1)
menuItem1.addActionListener {
@ -538,20 +543,17 @@ object LootTrackerView {
private fun resetLootTrackerMenu(): JPopupMenu {
// Create a popup menu
val popupMenu = JPopupMenu()
val rFont = Font("RuneScape Small", Font.TRUETYPE_FONT, 16)
popupMenu.background = POPUP_BACKGROUND
val popupMenu = PopupMenuComponent()
// Create menu items with custom font and colors
val menuItem1 = JMenuItem("Reset Loot Tracker").apply {
font = rFont // Set custom font
background = POPUP_BACKGROUND // Dark background for item
foreground = POPUP_FOREGROUND // Light text color for item
font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16)
background = KondoKit.plugin.Companion.POPUP_BACKGROUND
foreground = KondoKit.plugin.Companion.POPUP_FOREGROUND
}
popupMenu.add(menuItem1)
menuItem1.addActionListener {
plugin.registerDrawAction {
registerDrawAction {
resetLootTracker()
}
}

View file

@ -1,15 +1,16 @@
package KondoKit
package KondoKit.views
import KondoKit.Helpers.convertValue
import KondoKit.Helpers
import KondoKit.components.*
import KondoKit.components.ReflectiveEditorComponents.CustomSearchField
import KondoKit.components.ReflectiveEditorComponents.GitLabPlugin
import KondoKit.components.ReflectiveEditorComponents.GitLabPluginFetcher
import KondoKit.components.ReflectiveEditorComponents.PluginProperties
import KondoKit.views.Constants
import KondoKit.Helpers.showToast
import KondoKit.ReflectiveEditorComponents.CustomSearchField
import KondoKit.ReflectiveEditorComponents.GitLabPlugin
import KondoKit.ReflectiveEditorComponents.GitLabPluginFetcher
import KondoKit.ReflectiveEditorComponents.PluginProperties
import KondoKit.plugin.Companion.TITLE_BAR_COLOR
import KondoKit.plugin
import KondoKit.plugin.Companion.TOOLTIP_BACKGROUND
import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR
import KondoKit.plugin.Companion.WIDGET_COLOR
import KondoKit.plugin.Companion.secondaryColor
import plugin.Plugin
import plugin.PluginInfo
@ -94,9 +95,10 @@ object ReflectiveEditorView {
mainPanel.add(pluginListView, PLUGIN_LIST_VIEW)
// Create a placeholder for the plugin detail view
val pluginDetailView = JPanel(BorderLayout())
pluginDetailView.name = PLUGIN_DETAIL_VIEW
pluginDetailView.background = VIEW_BACKGROUND_COLOR
val pluginDetailView = BaseView(PLUGIN_DETAIL_VIEW).apply {
layout = BorderLayout()
background = VIEW_BACKGROUND_COLOR
}
mainPanel.add(pluginDetailView, PLUGIN_DETAIL_VIEW)
// Set the reflectiveEditorView to our main panel
@ -237,7 +239,7 @@ object ReflectiveEditorView {
val headerPanel = JPanel(FlowLayout(FlowLayout.LEFT))
headerPanel.background = VIEW_BACKGROUND_COLOR
val headerLabel = JLabel("Available Plugins")
headerLabel.foreground = secondaryColor
headerLabel.foreground = plugin.Companion.secondaryColor
headerLabel.font = Font("RuneScape Small", Font.BOLD, 16)
headerPanel.add(headerLabel)
panel.add(headerPanel)
@ -270,14 +272,14 @@ object ReflectiveEditorView {
private fun createPluginItemPanel(pluginInfo: PluginInfo, plugin: Plugin): JPanel {
val panel = JPanel(BorderLayout())
panel.background = WIDGET_COLOR
panel.background = KondoKit.plugin.Companion.WIDGET_COLOR
panel.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
panel.maximumSize = Dimension(220, 60)
// Plugin name and version (using package name as in original implementation)
val packageName = plugin.javaClass.`package`.name
val nameLabel = JLabel(packageName)
nameLabel.foreground = secondaryColor
nameLabel.foreground = KondoKit.plugin.Companion.secondaryColor
nameLabel.font = Font("RuneScape Small", Font.PLAIN, 16)
// Check if plugin has exposed attributes
@ -295,8 +297,8 @@ object ReflectiveEditorView {
} else {
button.text = "Edit"
}
button.background = TITLE_BAR_COLOR
button.foreground = secondaryColor
button.background = KondoKit.plugin.Companion.TITLE_BAR_COLOR
button.foreground = KondoKit.plugin.Companion.secondaryColor
button.font = Font("RuneScape Small", Font.PLAIN, 14)
button.addActionListener {
showPluginDetails(pluginInfo, plugin)
@ -311,11 +313,11 @@ object ReflectiveEditorView {
// Layout
val infoPanel = JPanel(BorderLayout())
infoPanel.background = WIDGET_COLOR
infoPanel.background = KondoKit.plugin.Companion.WIDGET_COLOR
infoPanel.add(nameLabel, BorderLayout.WEST)
val controlsPanel = JPanel(FlowLayout(FlowLayout.RIGHT, 5, 0))
controlsPanel.background = WIDGET_COLOR
controlsPanel.background = KondoKit.plugin.Companion.WIDGET_COLOR
// Add edit button first (left side of controls)
editButton?.let { controlsPanel.add(it) }
@ -331,13 +333,13 @@ object ReflectiveEditorView {
private fun createDisabledPluginItemPanel(pluginName: String): JPanel {
val panel = JPanel(BorderLayout())
panel.background = WIDGET_COLOR
panel.background = plugin.Companion.WIDGET_COLOR
panel.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
panel.maximumSize = Dimension(220, 60)
// Plugin name
val nameLabel = JLabel(pluginName)
nameLabel.foreground = secondaryColor
nameLabel.foreground = plugin.Companion.secondaryColor
nameLabel.font = Font("RuneScape Small", Font.PLAIN, 16)
// Plugin toggle switch (iOS style) - initially off for disabled plugins
@ -355,11 +357,11 @@ object ReflectiveEditorView {
// Layout
val infoPanel = JPanel(BorderLayout())
infoPanel.background = WIDGET_COLOR
infoPanel.background = plugin.Companion.WIDGET_COLOR
infoPanel.add(nameLabel, BorderLayout.WEST)
val controlsPanel = JPanel(FlowLayout(FlowLayout.RIGHT, 5, 0))
controlsPanel.background = WIDGET_COLOR
controlsPanel.background = plugin.Companion.WIDGET_COLOR
controlsPanel.add(toggleSwitch)
panel.add(infoPanel, BorderLayout.CENTER)
@ -370,19 +372,19 @@ object ReflectiveEditorView {
private fun createGitLabPluginItemPanel(gitLabPlugin: GitLabPlugin): JPanel {
val panel = JPanel(BorderLayout())
panel.background = WIDGET_COLOR
panel.background = plugin.Companion.WIDGET_COLOR
panel.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
panel.maximumSize = Dimension(220, 60)
// Plugin name
val nameLabel = JLabel(gitLabPlugin.path)
nameLabel.foreground = secondaryColor
nameLabel.foreground = plugin.Companion.secondaryColor
nameLabel.font = Font("RuneScape Small", Font.PLAIN, 16)
// Download button (placeholder for now)
val downloadButton = JButton("Download")
downloadButton.background = TITLE_BAR_COLOR
downloadButton.foreground = secondaryColor
downloadButton.background = plugin.Companion.TITLE_BAR_COLOR
downloadButton.foreground = plugin.Companion.secondaryColor
downloadButton.font = Font("RuneScape Small", Font.PLAIN, 14)
downloadButton.addActionListener {
// TODO: Implement download functionality
@ -396,11 +398,11 @@ object ReflectiveEditorView {
// Layout
val infoPanel = JPanel(BorderLayout())
infoPanel.background = WIDGET_COLOR
infoPanel.background = plugin.Companion.WIDGET_COLOR
infoPanel.add(nameLabel, BorderLayout.WEST)
val controlsPanel = JPanel(FlowLayout(FlowLayout.RIGHT, 5, 0))
controlsPanel.background = WIDGET_COLOR
controlsPanel.background = plugin.Companion.WIDGET_COLOR
controlsPanel.add(downloadButton)
controlsPanel.add(toggleSwitch)
@ -540,21 +542,17 @@ object ReflectiveEditorView {
}
// Create a new detail view
val detailView = JPanel(BorderLayout())
detailView.name = PLUGIN_DETAIL_VIEW
val detailView = BaseView(PLUGIN_DETAIL_VIEW)
detailView.layout = BorderLayout()
detailView.background = VIEW_BACKGROUND_COLOR
// Header with back button
val headerPanel = JPanel(BorderLayout())
headerPanel.background = TITLE_BAR_COLOR
headerPanel.preferredSize = Dimension(Int.MAX_VALUE, 40)
headerPanel.border = BorderFactory.createEmptyBorder(5, 10, 5, 10)
//$packageName v${pluginInfo.version} should be
val headerPanel = ViewHeader(" v${pluginInfo.version}", 40).apply {
border = BorderFactory.createEmptyBorder(5, 10, 5, 10)
}
val backButton = JButton("Back")
backButton.background = TITLE_BAR_COLOR
backButton.foreground = secondaryColor
backButton.font = Font("RuneScape Small", Font.PLAIN, 14)
backButton.addActionListener {
val backButton = ButtonPanel(FlowLayout.LEFT).addButton("Back") {
// Reset scroll position to top when returning to the list view
SwingUtilities.invokeLater {
// Find the ScrollablePanel in the plugin list view and reset its scroll position
@ -567,13 +565,8 @@ object ReflectiveEditorView {
}
val packageName = plugin.javaClass.`package`.name
val titleLabel = JLabel("$packageName v${pluginInfo.version}")
titleLabel.foreground = secondaryColor
titleLabel.font = Font("RuneScape Small", Font.PLAIN, 16)
titleLabel.horizontalAlignment = SwingConstants.CENTER
headerPanel.add(backButton, BorderLayout.WEST)
headerPanel.add(titleLabel, BorderLayout.CENTER)
// Content panel for settings
val contentPanel = JPanel()
@ -583,7 +576,7 @@ object ReflectiveEditorView {
// Add plugin info
val infoPanel = JPanel(BorderLayout())
infoPanel.background = WIDGET_COLOR
infoPanel.background = KondoKit.plugin.Companion.WIDGET_COLOR
infoPanel.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
infoPanel.maximumSize = Dimension(Int.MAX_VALUE, 80)
@ -593,9 +586,9 @@ object ReflectiveEditorView {
Description: ${pluginInfo.description}
""".trimIndent()
val infoLabel = JLabel("<html>$infoText</html>")
infoLabel.foreground = secondaryColor
infoLabel.font = Font("RuneScape Small", Font.PLAIN, 14)
val infoLabel = LabelComponent(infoText).apply {
font = Font("RuneScape Small", Font.PLAIN, 14)
}
infoPanel.add(infoLabel, BorderLayout.CENTER)
contentPanel.add(infoPanel)
@ -627,144 +620,9 @@ object ReflectiveEditorView {
}
private fun addPluginSettings(contentPanel: JPanel, plugin: Plugin) {
val fieldNotifier = Helpers.FieldNotifier(plugin)
val exposedFields = plugin.javaClass.declaredFields.filter { field ->
field.annotations.any { annotation ->
annotation.annotationClass.simpleName == "Exposed"
}
}
if (exposedFields.isNotEmpty()) {
for (field in exposedFields) {
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 fieldPanel = JPanel()
fieldPanel.layout = GridBagLayout()
fieldPanel.background = WIDGET_COLOR
fieldPanel.foreground = secondaryColor
fieldPanel.border = BorderFactory.createEmptyBorder(5, 0, 5, 0)
fieldPanel.maximumSize = Dimension(Int.MAX_VALUE, 50)
val gbc = GridBagConstraints()
gbc.insets = Insets(0, 5, 0, 5)
val label = JLabel(field.name.capitalize())
label.foreground = secondaryColor
gbc.gridx = 0
gbc.gridy = 0
gbc.weightx = 0.0
label.font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16)
gbc.anchor = GridBagConstraints.WEST
fieldPanel.add(label, gbc)
// Create appropriate input component based on field type
val inputComponent: JComponent = when {
field.type == Boolean::class.javaPrimitiveType || field.type == java.lang.Boolean::class.java -> JCheckBox().apply {
isSelected = field.get(plugin) as Boolean
}
field.type.isEnum -> JComboBox((field.type.enumConstants as Array<Enum<*>>)).apply {
selectedItem = field.get(plugin)
}
field.type == Int::class.javaPrimitiveType || field.type == Integer::class.java -> JSpinner(SpinnerNumberModel(field.get(plugin) as Int, Int.MIN_VALUE, Int.MAX_VALUE, 1))
field.type == Float::class.javaPrimitiveType || field.type == Double::class.javaPrimitiveType || field.type == java.lang.Float::class.java || field.type == java.lang.Double::class.java -> JSpinner(SpinnerNumberModel((field.get(plugin) as Number).toDouble(), -Double.MAX_VALUE, Double.MAX_VALUE, 0.1))
else -> JTextField(field.get(plugin)?.toString() ?: "")
}
// Add mouse listener to the label only if a description is available
if (description.isNotBlank()) {
label.cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)
label.addMouseListener(object : MouseAdapter() {
override fun mouseEntered(e: MouseEvent) {
showCustomToolTip(description, label)
}
override fun mouseExited(e: MouseEvent) {
customToolTipWindow?.isVisible = false
}
})
}
gbc.gridx = 1
gbc.gridy = 0
gbc.weightx = 1.0
gbc.fill = GridBagConstraints.HORIZONTAL
fieldPanel.add(inputComponent, gbc)
val applyButton = JButton("\u2714").apply {
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 -> convertValue(field.type, field.genericType, inputComponent.text)
else -> throw IllegalArgumentException("Unsupported input component type")
}
fieldNotifier.setFieldValue(field, newValue)
showToast(
mainPanel,
"${field.name} updated successfully!"
)
} catch (e: Exception) {
showToast(
mainPanel,
"Failed to update ${field.name}: ${e.message}",
JOptionPane.ERROR_MESSAGE
)
}
}
fieldPanel.add(applyButton, gbc)
contentPanel.add(fieldPanel)
// Track field changes in real-time and update UI
var previousValue = field.get(plugin)?.toString()
val timer = Timer()
timer.schedule(object : TimerTask() {
override fun run() {
val currentValue = field.get(plugin)?.toString()
if (currentValue != previousValue) {
previousValue = currentValue
SwingUtilities.invokeLater {
// Update the inputComponent based on the new value
when (inputComponent) {
is JCheckBox -> inputComponent.isSelected = field.get(plugin) as Boolean
is JComboBox<*> -> inputComponent.selectedItem = field.get(plugin)
is JSpinner -> inputComponent.value = field.get(plugin)
is JTextField -> inputComponent.text = field.get(plugin)?.toString() ?: ""
}
}
}
}
}, 0, 1000) // Poll every 1000 milliseconds (1 second)
}
if (exposedFields.isNotEmpty()) {
contentPanel.add(Box.createVerticalStrut(5))
}
}
val settingsPanel = SettingsPanel(plugin)
settingsPanel.addSettingsFromPlugin()
contentPanel.add(settingsPanel)
}
fun addPlugins(reflectiveEditorView: JPanel) {

View file

@ -1,23 +1,29 @@
package KondoKit
package KondoKit.views
import KondoKit.Helpers
import KondoKit.Helpers.addMouseListenerToAll
import KondoKit.Helpers.formatHtmlLabelText
import KondoKit.Helpers.formatNumber
import KondoKit.Helpers.getProgressBarColor
import KondoKit.Helpers.getSpriteId
import KondoKit.ImageCanvas
import KondoKit.SpriteToBufferedImage.getBufferedImageFromSprite
import KondoKit.XPTable
import KondoKit.components.PopupMenuComponent
import KondoKit.components.ProgressBar
import KondoKit.components.WidgetPanel
import KondoKit.plugin.Companion.IMAGE_SIZE
import KondoKit.plugin.Companion.LVL_ICON
import KondoKit.plugin.Companion.POPUP_BACKGROUND
import KondoKit.plugin.Companion.POPUP_FOREGROUND
import KondoKit.plugin.Companion.TOTAL_XP_WIDGET_SIZE
import KondoKit.plugin.Companion.VIEW_BACKGROUND_COLOR
import KondoKit.plugin.Companion.WIDGET_COLOR
import KondoKit.plugin.Companion.WIDGET_SIZE
import KondoKit.plugin
import KondoKit.plugin.Companion.playerXPMultiplier
import KondoKit.plugin.Companion.primaryColor
import KondoKit.plugin.Companion.secondaryColor
import KondoKit.plugin.StateManager.focusedView
import KondoKit.views.BaseView
import plugin.api.API
import java.awt.*
import java.awt.event.MouseAdapter
@ -155,12 +161,8 @@ object XPTrackerView {
}
fun createTotalXPWidget(): XPWidget {
val widgetPanel = Panel().apply {
layout = BorderLayout(5, 5)
background = WIDGET_COLOR
preferredSize = TOTAL_XP_WIDGET_SIZE
maximumSize = TOTAL_XP_WIDGET_SIZE
minimumSize = TOTAL_XP_WIDGET_SIZE
val widgetPanel = WidgetPanel(TOTAL_XP_WIDGET_SIZE.width, TOTAL_XP_WIDGET_SIZE.height).apply {
border = BorderFactory.createEmptyBorder(5, 5, 5, 5)
}
val bufferedImageSprite = getBufferedImageFromSprite(API.GetSprite(LVL_ICON))
@ -233,9 +235,8 @@ object XPTrackerView {
fun createXPTrackerView(){
val widgetViewPanel = JPanel().apply {
layout = BoxLayout(this, BoxLayout.Y_AXIS)
background = VIEW_BACKGROUND_COLOR
val widgetViewPanel = BaseView(VIEW_NAME, addDefaultSpacing = false).apply {
add(Box.createVerticalStrut(5))
}
val popupMenu = createResetMenu()
@ -260,7 +261,6 @@ object XPTrackerView {
val wrapped = wrappedWidget(totalXPWidget!!.container)
addMouseListenerToAll(wrapped,rightClickListener)
wrapped.addMouseListener(rightClickListener)
widgetViewPanel.add(Box.createVerticalStrut(5))
widgetViewPanel.add(wrapped)
widgetViewPanel.add(Box.createVerticalStrut(5))
@ -282,17 +282,13 @@ object XPTrackerView {
fun createResetMenu(): JPopupMenu {
// Create a popup menu
val popupMenu = JPopupMenu()
val rFont = Font("RuneScape Small", Font.TRUETYPE_FONT, 16)
popupMenu.background = POPUP_BACKGROUND
val popupMenu = PopupMenuComponent()
// Create menu items with custom font and colors
val menuItem1 = JMenuItem("Reset Tracker").apply {
font = rFont // Set custom font
background = POPUP_BACKGROUND // Dark background for item
foreground = POPUP_FOREGROUND // Light text color for item
font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16)
background = KondoKit.plugin.Companion.POPUP_BACKGROUND
foreground = KondoKit.plugin.Companion.POPUP_FOREGROUND
}
// Add menu items to the popup menu
@ -304,21 +300,19 @@ object XPTrackerView {
}
fun removeXPWidgetMenu(toRemove: Container, skillId: Int): JPopupMenu {
val popupMenu = JPopupMenu()
val rFont = Font("RuneScape Small", Font.TRUETYPE_FONT, 16)
popupMenu.background = POPUP_BACKGROUND
val popupMenu = PopupMenuComponent()
val resetItem = JMenuItem("Reset").apply {
font = rFont
background = POPUP_BACKGROUND
foreground = POPUP_FOREGROUND
font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16)
background = KondoKit.plugin.Companion.POPUP_BACKGROUND
foreground = KondoKit.plugin.Companion.POPUP_FOREGROUND
}
popupMenu.add(resetItem)
val removeItem = JMenuItem("Remove").apply {
font = rFont
background = POPUP_BACKGROUND
foreground = POPUP_FOREGROUND
font = Font("RuneScape Small", Font.TRUETYPE_FONT, 16)
background = KondoKit.plugin.Companion.POPUP_BACKGROUND
foreground = KondoKit.plugin.Companion.POPUP_FOREGROUND
}
popupMenu.add(removeItem)
@ -360,12 +354,8 @@ object XPTrackerView {
fun createXPWidget(skillId: Int, previousXp: Int): XPWidget {
val widgetPanel = Panel().apply {
layout = BorderLayout(5, 5)
background = WIDGET_COLOR
preferredSize = WIDGET_SIZE
maximumSize = WIDGET_SIZE
minimumSize = WIDGET_SIZE
val widgetPanel = WidgetPanel(WIDGET_SIZE.width, WIDGET_SIZE.height).apply {
border = BorderFactory.createEmptyBorder(5, 5, 5, 5)
}
val bufferedImageSprite = skillIconCache[skillId]