Initial commit
This commit is contained in:
commit
3776e85bc0
40
.gitignore
vendored
Normal file
40
.gitignore
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
*.kt.old
|
||||
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
!**/src/main/**/target/
|
||||
!**/src/test/**/target/
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea/modules.xml
|
||||
.idea/jarRepositories.xml
|
||||
.idea/compiler.xml
|
||||
.idea/libraries/
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### Eclipse ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
.sts4-cache
|
||||
|
||||
### NetBeans ###
|
||||
/nbproject/private/
|
||||
/nbbuild/
|
||||
/dist/
|
||||
/nbdist/
|
||||
/.nb-gradle/
|
||||
build/
|
||||
!**/src/main/**/build/
|
||||
!**/src/test/**/build/
|
||||
|
||||
### VS Code ###
|
||||
.vscode/
|
||||
|
||||
### Mac OS ###
|
||||
.DS_Store
|
7
.idea/encodings.xml
Normal file
7
.idea/encodings.xml
Normal file
@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="Encoding">
|
||||
<file url="file://$PROJECT_DIR$/src/main/kotlin" charset="UTF-8" />
|
||||
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
|
||||
</component>
|
||||
</project>
|
6
.idea/kotlinc.xml
Normal file
6
.idea/kotlinc.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="1.7.10" />
|
||||
</component>
|
||||
</project>
|
13
.idea/misc.xml
Normal file
13
.idea/misc.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MavenProjectsManager">
|
||||
<option name="originalFiles">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/pom.xml" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||
<output url="file://$PROJECT_DIR$/out" />
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
Normal file
6
.idea/vcs.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
115
.idea/workspace.xml
Normal file
115
.idea/workspace.xml
Normal file
@ -0,0 +1,115 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="AutoImportSettings">
|
||||
<option name="autoReloadType" value="SELECTIVE" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="7c866fd4-dd39-4ede-9dcf-e623b1d0f46d" name="Changes" comment="">
|
||||
<change afterPath="$PROJECT_DIR$/.gitignore" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/.idea/encodings.xml" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/.idea/kotlinc.xml" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/.idea/misc.xml" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/.idea/vcs.xml" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/pom.xml" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/kotlin/AppModel.kt" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/kotlin/AppView.kt" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/kotlin/ButtonArt.kt" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/kotlin/ImageButton.kt" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/kotlin/Main.kt" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/kotlin/TodoView.kt.old" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/kotlin/Util.kt" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/resources/Main.kt.old" afterDir="false" />
|
||||
<change afterPath="$PROJECT_DIR$/src/main/resources/demoIcon.png" afterDir="false" />
|
||||
</list>
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="FileTemplateManagerImpl">
|
||||
<option name="RECENT_TEMPLATES">
|
||||
<list>
|
||||
<option value="Kotlin File" />
|
||||
<option value="Class" />
|
||||
<option value="Kotlin Class" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="MarkdownSettingsMigration">
|
||||
<option name="stateVersion" value="1" />
|
||||
</component>
|
||||
<component name="ProjectId" id="2Rx2CD5ArGjpQZZIPM7XNqEj2yY" />
|
||||
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
|
||||
<component name="ProjectViewState">
|
||||
<option name="hideEmptyMiddlePackages" value="true" />
|
||||
<option name="showLibraryContents" value="true" />
|
||||
</component>
|
||||
<component name="PropertiesComponent">{
|
||||
"keyToString": {
|
||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||
"last_opened_file_path": "C:/Nyeogit/taskzap/taskzap/src/main/resources"
|
||||
}
|
||||
}</component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="C:\Nyeogit\taskzap\taskzap\src\main\resources" />
|
||||
<recent name="C:\Nyeogit\taskzap\taskzap\src\main\kotlin" />
|
||||
</key>
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="C:\Nyeogit\taskzap\taskzap\src\main\resources" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunManager">
|
||||
<configuration name="MainKt" type="JetRunConfigurationType" temporary="true" nameIsGenerated="true">
|
||||
<option name="MAIN_CLASS_NAME" value="MainKt" />
|
||||
<module name="taskzap" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="true" type="JetRunConfigurationType">
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<configuration default="true" type="KotlinStandaloneScriptRunConfigurationType">
|
||||
<option name="filePath" />
|
||||
<method v="2">
|
||||
<option name="Make" enabled="true" />
|
||||
</method>
|
||||
</configuration>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="Kotlin.MainKt" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
</component>
|
||||
<component name="SpellCheckerSettings" RuntimeDictionaries="0" Folders="0" CustomDictionaries="0" DefaultDictionary="application-level" UseSingleDictionary="true" transferred="true" />
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="7c866fd4-dd39-4ede-9dcf-e623b1d0f46d" name="Changes" comment="" />
|
||||
<created>1688177283964</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1688177283964</updated>
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="Vcs.Log.Tabs.Properties">
|
||||
<option name="TAB_STATES">
|
||||
<map>
|
||||
<entry key="MAIN">
|
||||
<value>
|
||||
<State />
|
||||
</value>
|
||||
</entry>
|
||||
</map>
|
||||
</option>
|
||||
</component>
|
||||
</project>
|
104
pom.xml
Normal file
104
pom.xml
Normal file
@ -0,0 +1,104 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>taskzap</artifactId>
|
||||
<groupId>app.chromaticdragon</groupId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>consoleApp</name>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
<kotlin.code.style>official</kotlin.code.style>
|
||||
<kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget>
|
||||
</properties>
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>mavenCentral</id>
|
||||
<url>https://repo1.maven.org/maven2/</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>src/main/kotlin</sourceDirectory>
|
||||
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<version>1.7.10</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>compile</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>test-compile</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-failsafe-plugin</artifactId>
|
||||
<version>2.22.2</version>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>exec-maven-plugin</artifactId>
|
||||
<version>1.6.0</version>
|
||||
<configuration>
|
||||
<mainClass>MainKt</mainClass>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<source>6</source>
|
||||
<target>6</target>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-test-junit5</artifactId>
|
||||
<version>1.7.10</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.8.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||
<version>1.7.10</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlinx</groupId>
|
||||
<artifactId>kotlinx-datetime-jvm</artifactId>
|
||||
<version>0.4.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
53
src/main/kotlin/AppModel.kt
Normal file
53
src/main/kotlin/AppModel.kt
Normal file
@ -0,0 +1,53 @@
|
||||
import kotlinx.datetime.LocalDateTime
|
||||
import java.awt.image.BufferedImage
|
||||
import java.util.*
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
class AppModel {
|
||||
var version: Long = 0
|
||||
private set
|
||||
private var tasks: HashMap<UUID, TaskRecord> = HashMap()
|
||||
|
||||
fun updateTask(task: TaskRecord): TaskRecord? { // returns the old version
|
||||
version += 1
|
||||
val old = tasks[task.uuid]
|
||||
tasks[task.uuid] = task
|
||||
return old
|
||||
}
|
||||
|
||||
fun getTask(uuid: UUID): TaskRecord? {
|
||||
return tasks[uuid]
|
||||
}
|
||||
|
||||
fun removeTask(uuid: UUID): TaskRecord? {
|
||||
version += 1
|
||||
return tasks.remove(uuid)
|
||||
}
|
||||
|
||||
fun getTasksByBlinkAt(): ArrayList<TaskRecord> {
|
||||
val list = ArrayList<TaskRecord>()
|
||||
for (t in tasks) { list.add(t.value) }
|
||||
list.sortBy { t -> t.blinkAt }
|
||||
return list
|
||||
}
|
||||
}
|
||||
|
||||
class TaskRecord(
|
||||
val uuid: UUID,
|
||||
val icon: IconRecord,
|
||||
val task: String,
|
||||
val link: LinkRecord?,
|
||||
val createdAt: LocalDateTime,
|
||||
val blinkAt: LocalDateTime,
|
||||
)
|
||||
|
||||
class LinkRecord(
|
||||
val icon: IconRecord,
|
||||
val window: Int,
|
||||
val pid: Int,
|
||||
val filename: String,
|
||||
)
|
||||
|
||||
class IconRecord(val image: BufferedImage) {
|
||||
val cachedButtonArt = ButtonArt.fromArbitraryImage(image) // don't persist this, just have it always ready
|
||||
}
|
125
src/main/kotlin/AppView.kt
Normal file
125
src/main/kotlin/AppView.kt
Normal file
@ -0,0 +1,125 @@
|
||||
import java.awt.*
|
||||
import javax.swing.BoxLayout
|
||||
import javax.swing.JDialog
|
||||
import javax.swing.JPanel
|
||||
import javax.swing.border.EmptyBorder
|
||||
|
||||
private val GRID_SIZE = 64;
|
||||
private val GRID_SIZE_INNER = 56;
|
||||
private val GRID_INSET = (GRID_SIZE - GRID_SIZE_INNER) / 2
|
||||
|
||||
class AppView(model: AppModel): JDialog() {
|
||||
private val viewModel = AppViewModel(model)
|
||||
|
||||
private val controlPanel = buildControlPanel()
|
||||
private val iconPanel = JPanel()
|
||||
// TODO: Replace these with icons that have clear meaning
|
||||
|
||||
init {
|
||||
isAlwaysOnTop = true
|
||||
isUndecorated = true
|
||||
background = TRANSPARENT
|
||||
bounds = Rectangle(0, 0, Toolkit.getDefaultToolkit().screenSize.width, 64)
|
||||
|
||||
contentPane.layout = BorderLayout()
|
||||
contentPane.add(controlPanel, BorderLayout.WEST)
|
||||
contentPane.add(iconPanel, BorderLayout.CENTER)
|
||||
|
||||
iconPanel.layout = FlowLayout(FlowLayout.LEFT, 0, 0)
|
||||
|
||||
controlPanel.background = TRANSPARENT;
|
||||
iconPanel.background = TRANSPARENT;
|
||||
}
|
||||
|
||||
fun touch() {
|
||||
viewModel.ifDirty(contentPane) {
|
||||
val ipHeight = iconPanel.height
|
||||
val iconSize = ipHeight * 3/4;
|
||||
val meterHeight = ipHeight - iconSize;
|
||||
|
||||
iconPanel.removeAll()
|
||||
|
||||
val tasks = viewModel.model.getTasksByBlinkAt()
|
||||
for (task in tasks) {
|
||||
iconPanel.add(TaskView(task))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildControlPanel(): JPanel {
|
||||
val moveButton = ImageButton(
|
||||
ButtonArt(
|
||||
getImage("/move_unlit.png")!!,
|
||||
getImage("/move_lit.png")!!,
|
||||
getImage("/move_pressed.png")!!,
|
||||
),
|
||||
null
|
||||
)
|
||||
// TODO: Do something
|
||||
moveButton.preferredSize = Dimension(GRID_SIZE, GRID_SIZE)
|
||||
moveButton.border = EmptyBorder(GRID_INSET, GRID_INSET, GRID_INSET, GRID_INSET)
|
||||
moveButton.callback = { print("test") }
|
||||
|
||||
val controlPanel = JPanel()
|
||||
controlPanel.layout = BoxLayout(controlPanel, BoxLayout.PAGE_AXIS)
|
||||
|
||||
controlPanel.add(moveButton)
|
||||
|
||||
return controlPanel
|
||||
}
|
||||
}
|
||||
|
||||
// for now: just reexpose the underlying model
|
||||
// we don't have a layer of state beyond what can be kept in the UI
|
||||
class AppViewModel(val model: AppModel) {
|
||||
private var cpHeight: Int = -1
|
||||
private var version: Long = -1
|
||||
|
||||
fun ifDirty(contentPane: Container, body: () -> Unit) {
|
||||
if (version != model.version || contentPane.height != cpHeight) {
|
||||
body()
|
||||
cpHeight = contentPane.height
|
||||
version = model.version
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class TaskView(
|
||||
private val task: TaskRecord,
|
||||
): JPanel() {
|
||||
private var button: ImageButton
|
||||
init {
|
||||
layout = BorderLayout()
|
||||
preferredSize = Dimension(GRID_SIZE, GRID_SIZE)
|
||||
border = EmptyBorder(GRID_INSET, GRID_INSET, GRID_INSET, GRID_INSET)
|
||||
background = TRANSPARENT
|
||||
|
||||
button = ImageButton(
|
||||
task.icon.cachedButtonArt,
|
||||
null
|
||||
)
|
||||
|
||||
add(button)
|
||||
}
|
||||
|
||||
/*
|
||||
override fun paintComponent(gnull: Graphics?) {
|
||||
super.paintComponent(gnull)
|
||||
|
||||
val g = gnull!!
|
||||
|
||||
// icon occupies top of space
|
||||
g.drawImage(task.icon.image, 0, 0, iconSize, iconSize, Color(0, 0, 0, 0)) { _, _, _, _, _, _ -> false }
|
||||
|
||||
// bar occupies middle 1/2 of space
|
||||
val realBarHeight = meterHeight / 2
|
||||
val barY = iconSize + (meterHeight - realBarHeight)/2
|
||||
val arcSize = realBarHeight / 2
|
||||
val barX = arcSize
|
||||
val realBarWidth = iconSize - arcSize * 2
|
||||
|
||||
g.color = Color(0, 255, 0, 255)
|
||||
g.fillRoundRect(barX, barY, realBarWidth, realBarHeight, arcSize, arcSize)
|
||||
}
|
||||
*/
|
||||
}
|
42
src/main/kotlin/ButtonArt.kt
Normal file
42
src/main/kotlin/ButtonArt.kt
Normal file
@ -0,0 +1,42 @@
|
||||
import java.awt.Graphics2D
|
||||
import java.awt.image.BufferedImage
|
||||
import java.awt.image.RescaleOp
|
||||
|
||||
// val MAX_SIZE: Int = 256
|
||||
|
||||
// TODO: Enforce MAX_SIZE
|
||||
// TODO: Cookie cutter out a roundrect
|
||||
|
||||
class ButtonArt(
|
||||
val base: BufferedImage,
|
||||
val highlighted: BufferedImage,
|
||||
val pressed: BufferedImage
|
||||
) {
|
||||
companion object {
|
||||
fun fromArbitraryImage(base: BufferedImage): ButtonArt {
|
||||
return ButtonArt(
|
||||
base,
|
||||
base.toHighlighted(),
|
||||
base.toPressed(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun BufferedImage.toHighlighted(): BufferedImage {
|
||||
val highlighted = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
|
||||
val g = highlighted.graphics as Graphics2D
|
||||
val op = RescaleOp(0.75f, 128f, null)
|
||||
g.drawImage(this, 0, 0, width, height, 0, 0, width, height, null)
|
||||
op.filter(highlighted, highlighted)
|
||||
return highlighted
|
||||
}
|
||||
|
||||
private fun BufferedImage.toPressed(): BufferedImage {
|
||||
val pressed = BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB)
|
||||
val g = pressed.graphics as Graphics2D
|
||||
val op = RescaleOp(2.0f, 0.0f, null)
|
||||
g.drawImage(this, 0, 0, width, height, 0, 0, width, height, null)
|
||||
op.filter(pressed, pressed)
|
||||
return pressed
|
||||
}
|
63
src/main/kotlin/ImageButton.kt
Normal file
63
src/main/kotlin/ImageButton.kt
Normal file
@ -0,0 +1,63 @@
|
||||
import java.awt.Dimension
|
||||
import java.awt.Graphics
|
||||
import java.awt.event.MouseAdapter
|
||||
import java.awt.event.MouseEvent
|
||||
import java.awt.event.MouseListener
|
||||
import java.awt.image.BufferedImage
|
||||
import javax.swing.JPanel
|
||||
|
||||
class ImageButton(
|
||||
private val art: ButtonArt,
|
||||
var callback: (() -> Unit)?,
|
||||
): JPanel() {
|
||||
private var mouseOver = false
|
||||
private var mouseDown = false
|
||||
|
||||
init {
|
||||
background = TRANSPARENT
|
||||
preferredSize = Dimension(art.base.width, art.base.height)
|
||||
this.addMouseListener(object: MouseAdapter() {
|
||||
override fun mouseEntered(e: MouseEvent?) {
|
||||
super.mouseEntered(e)
|
||||
mouseOver = true
|
||||
repaint()
|
||||
}
|
||||
|
||||
override fun mouseExited(e: MouseEvent?) {
|
||||
super.mouseExited(e)
|
||||
mouseOver = false
|
||||
repaint()
|
||||
}
|
||||
|
||||
override fun mousePressed(e: MouseEvent?) {
|
||||
super.mousePressed(e)
|
||||
mouseDown = true
|
||||
repaint()
|
||||
}
|
||||
|
||||
override fun mouseReleased(e: MouseEvent?) {
|
||||
super.mouseReleased(e)
|
||||
mouseDown = false
|
||||
repaint()
|
||||
}
|
||||
|
||||
override fun mouseClicked(e: MouseEvent?) {
|
||||
super.mouseClicked(e)
|
||||
callback?.invoke()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
override fun paintComponent(gnull: Graphics?) {
|
||||
super.paintComponent(gnull)
|
||||
|
||||
val g = gnull!!
|
||||
val img = if (mouseDown) { art.pressed } else if (mouseOver) { art.highlighted } else { art.base }
|
||||
|
||||
val insets = insets
|
||||
val dx = width - (insets.left + insets.right)
|
||||
val dy = height - (insets.top + insets.bottom)
|
||||
|
||||
g.drawImage(img, insets.left, insets.top, dx, dy, null)
|
||||
}
|
||||
}
|
71
src/main/kotlin/Main.kt
Normal file
71
src/main/kotlin/Main.kt
Normal file
@ -0,0 +1,71 @@
|
||||
import java.awt.event.WindowAdapter
|
||||
import java.awt.event.WindowEvent
|
||||
import java.awt.image.BufferedImage
|
||||
import javax.swing.JFrame
|
||||
import javax.swing.Timer
|
||||
import kotlin.system.exitProcess
|
||||
import kotlinx.datetime.*
|
||||
import kotlinx.datetime.TimeZone
|
||||
import java.awt.*
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.util.*
|
||||
import javax.imageio.ImageIO
|
||||
import javax.swing.JButton
|
||||
import javax.swing.JLabel
|
||||
import javax.swing.JPanel
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val app = App()
|
||||
|
||||
app.start()
|
||||
}
|
||||
|
||||
class App {
|
||||
private var model = AppModel()
|
||||
|
||||
private var running: Boolean = false
|
||||
private val worker = createWorker()
|
||||
private val appView = createAppView()
|
||||
|
||||
fun start() {
|
||||
running = true
|
||||
worker.start()
|
||||
|
||||
val demoIcon = getImage("/demoIcon.png")!!
|
||||
|
||||
for (i in 0..2) {
|
||||
model.updateTask(
|
||||
TaskRecord(
|
||||
uuid = UUID.randomUUID(),
|
||||
icon = IconRecord(demoIcon),
|
||||
task = "FIX THE DOG",
|
||||
link = null,
|
||||
createdAt = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault()),
|
||||
blinkAt = Clock.System.now().toLocalDateTime(TimeZone.currentSystemDefault())
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createWorker(): Timer {
|
||||
return Timer(33) { onFrame() }
|
||||
}
|
||||
|
||||
private fun createAppView(): AppView {
|
||||
val av = AppView(model)
|
||||
av.addWindowListener(object: WindowAdapter() {
|
||||
override fun windowClosing(e: WindowEvent?) {
|
||||
running = false
|
||||
}
|
||||
})
|
||||
|
||||
return av
|
||||
}
|
||||
|
||||
private fun onFrame() {
|
||||
if (!running) { exitProcess(0) }
|
||||
|
||||
if (running) appView.isVisible = true
|
||||
appView.touch()
|
||||
}
|
||||
}
|
16
src/main/kotlin/Util.kt
Normal file
16
src/main/kotlin/Util.kt
Normal file
@ -0,0 +1,16 @@
|
||||
import java.awt.AlphaComposite
|
||||
import java.awt.Color
|
||||
import java.awt.Composite
|
||||
import java.awt.Graphics2D
|
||||
import java.awt.image.BufferedImage
|
||||
import java.awt.image.RescaleOp
|
||||
import java.io.ByteArrayInputStream
|
||||
import java.net.URL
|
||||
import javax.imageio.ImageIO
|
||||
|
||||
val TRANSPARENT: Color = Color(0, 0, 0, 0)
|
||||
|
||||
fun ByteArray.toImage(): BufferedImage = ImageIO.read(ByteArrayInputStream(this))
|
||||
fun getImage(name: String): BufferedImage? = getResource(name)?.readBytes()?.toImage()
|
||||
fun getResource(name: String): URL? = App::class.java.getResource(name)
|
||||
|
BIN
src/main/resources/demoIcon.png
Normal file
BIN
src/main/resources/demoIcon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 22 KiB |
BIN
src/main/resources/move_lit.png
Normal file
BIN
src/main/resources/move_lit.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
BIN
src/main/resources/move_pressed.png
Normal file
BIN
src/main/resources/move_pressed.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
BIN
src/main/resources/move_unlit.png
Normal file
BIN
src/main/resources/move_unlit.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
Loading…
Reference in New Issue
Block a user