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