Skip to content

Commit

Permalink
feat: animate the filler widgets
Browse files Browse the repository at this point in the history
  • Loading branch information
atennert committed Mar 15, 2021
1 parent f7b70e2 commit 30b2e5e
Show file tree
Hide file tree
Showing 4 changed files with 136 additions and 12 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
21.3
* add widget for displaying memory (RAM) status
* randomly hide filler widgets
* animate filler widgets

21.2
* add linking for systems with /usr/lib64 instead of /usr/lib
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package de.atennert.lcarsde.statusbar

import de.atennert.lcarsde.statusbar.widgets.StatusFillerWidget
import kotlinx.coroutines.*
import kotlin.random.Random

/**
* Controls the update/animation lifecycle for all filler widgets.
*/
class FillerAnimation {

private val fillerWidgets = mutableListOf<StatusFillerWidget>()

private var updateJob: Job? = null

private val minimalSwitchDelay = 2_000L // ms
private val maximalSwitchDelay = 10_000L // ms

fun addFillerWidget(fillerWidget: StatusFillerWidget) {
fillerWidgets.add(fillerWidget)
}

fun clearWidgets() {
fillerWidgets.clear()
}

private fun animateFiller() {
val widget = fillerWidgets.randomOrNull() ?: return

widget.update()
}

fun startAnimation() {
fillerWidgets.forEach(StatusFillerWidget::start)
updateJob = GlobalScope.launch(Dispatchers.Unconfined) {
while (true) {
delay(Random.nextLong(minimalSwitchDelay, maximalSwitchDelay))
animateFiller()
}
}
}

fun stopAnimation() {
updateJob?.cancel()
updateJob = null
fillerWidgets.forEach(StatusFillerWidget::stop)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class StatusBar {
private val widgetFactory = WidgetFactory(cssProvider)

private var widgets = emptyList<StatusWidget>()
private val fillerAnimation = FillerAnimation()

private var currentWidth = 40 // px
private var initialized = false
Expand Down Expand Up @@ -70,6 +71,7 @@ class StatusBar {
val (horizontalCells, leftOverPixels) = getCellsAndOverflow()
if (initialized) {
stop()
fillerAnimation.clearWidgets()

for (i in 1..3) {
gtk_grid_remove_row(grid.reinterpret(), 0)
Expand Down Expand Up @@ -153,6 +155,7 @@ class StatusBar {
val configuration = WidgetConfiguration("", 0, 0, 2, 1)
.withAddedPx(addedPixelsPerFiller[col])
val filler = StatusFillerWidget(configuration, cssProvider)
fillerAnimation.addFillerWidget(filler)
gtk_grid_attach(grid.reinterpret(), filler.widget, col * 2, row, 2, 1)
}
}
Expand All @@ -171,9 +174,11 @@ class StatusBar {

private fun start() {
widgets.forEach(StatusWidget::start)
fillerAnimation.startAnimation()
}

fun stop() {
fillerAnimation.stopAnimation()
widgets.forEach(StatusWidget::stop)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,33 +1,104 @@
package de.atennert.lcarsde.statusbar.widgets

import de.atennert.lcarsde.statusbar.configuration.WidgetConfiguration
import de.atennert.lcarsde.statusbar.extensions.setStyling
import kotlinx.cinterop.CPointer
import kotlinx.cinterop.reinterpret
import de.atennert.lcarsde.statusbar.extensions.gSignalConnect
import kotlinx.cinterop.*
import statusbar.*
import kotlin.math.PI
import kotlin.random.Random

class StatusFillerWidget(widgetConfiguration: WidgetConfiguration, cssProvider: CPointer<GtkCssProvider>)
: StatusWidget(widgetConfiguration, cssProvider, null) {

private var ref: StableRef<StatusFillerWidget>? = null

private var lastColor = "123"

init {
val text = "${Random.nextInt(10000)}".padStart(4, '0')
widget = gtk_label_new(text)!!
widget = gtk_drawing_area_new()!!
gtk_widget_set_size_request(widget, widthPx, heightPx)
gtk_label_set_xalign(widget.reinterpret(), 1f)
gtk_label_set_yalign(widget.reinterpret(), 1f)
}

override fun start() {
ref = StableRef.create(this)

gSignalConnect(widget, "draw",
staticCFunction { _: CPointer<GtkWidget>, c: CPointer<cairo_t>, p: COpaquePointer -> draw(c, p) },
ref!!.asCPointer())

val colorIdx = Random.nextInt(colors.size)
val color = colors[colorIdx]
super.start()

widget.setStyling(cssProvider, "button--$color", "button--long")
update()
}

override fun stop() {
super.stop()

ref!!.dispose()
}

override fun update() {
// Nothing to do
gtk_widget_queue_draw(widget)
}

companion object {
private val colors = arrayOf("c9c", "99c", "f96", "000")

private fun draw(context: CPointer<cairo_t>, ref: COpaquePointer) {
val widget = ref.asStableRef<StatusFillerWidget>().get()

val availableColors = colors.filterNot { it == widget.lastColor }
val colorIdx = Random.nextInt(availableColors.size)
val newColor = availableColors[colorIdx]
val text = "${Random.nextInt(10000)}".padStart(4, '0')
widget.lastColor = newColor

cairo_set_source_rgb(context, convertColor(newColor[0]), convertColor(newColor[1]), convertColor(newColor[2]))
createBorderPath(context, widget)
cairo_fill(context)

drawText(context, widget, text)
}

private fun convertColor(char: Char): Double {
return when(char) {
'f' -> 1.0
'c' -> 0.8
'9' -> 0.6
'6' -> 0.4
else -> 0.0
}
}

private fun createBorderPath(context: CPointer<cairo_t>, widget: StatusFillerWidget) {
cairo_arc(context, 20.0, 20.0, 20.0, 1.0 * PI, 1.5 * PI)
cairo_line_to(context, widget.widthPx - 20.0, 0.0)
cairo_arc(context, widget.widthPx - 20.0, 20.0, 20.0, 1.5 * PI, 2.0 * PI)
cairo_line_to(context, widget.widthPx.toDouble(), widget.heightPx - 20.0)
cairo_arc(context, widget.widthPx - 20.0, widget.heightPx - 20.0, 20.0, 0.0 * PI, 0.5 * PI)
cairo_line_to(context, 20.0, widget.heightPx.toDouble())
cairo_arc(context, 20.0, widget.heightPx - 20.0, 20.0, 0.5 * PI, 1.0 * PI)
cairo_close_path(context)
}

private fun drawText(context: CPointer<cairo_t>, widget: StatusFillerWidget, text: String) {
cairo_set_source_rgb(context, 0.0, 0.0, 0.0)
val layout = pango_cairo_create_layout(context)!!

val fontDescription = pango_font_description_from_string("Ubuntu Condensed, 12")
pango_layout_set_font_description(layout, fontDescription)
pango_layout_set_text(layout, text, text.length)

val layoutSize = IntArray(2)
pango_layout_get_size(layout, layoutSize.refTo(0), layoutSize.refTo(1))
cairo_move_to(context,
widget.widthPx - (layoutSize[0].toFloat() / 1024.0) - 16,
widget.heightPx - (layoutSize[1].toFloat() / 1024.0)
)

pango_cairo_show_layout(context, layout)
pango_font_description_free(fontDescription)
g_object_unref(layout)
}
}
}

0 comments on commit 30b2e5e

Please sign in to comment.