Unverified Commit cc4e47fc authored by Nikolay Igotti's avatar Nikolay Igotti Committed by GitHub

Cursor control API (#500)

Let's keep as is for know, and just mention minSdk in README.
parent a73e8750
...@@ -11,6 +11,7 @@ import kotlin.math.sin ...@@ -11,6 +11,7 @@ import kotlin.math.sin
import kotlin.math.PI import kotlin.math.PI
class Clocks(private val layer: SkiaLayer): SkikoView { class Clocks(private val layer: SkiaLayer): SkikoView {
private val cursorManager = CursorManager()
private val withFps = true private val withFps = true
private val fpsCounter = FPSCounter() private val fpsCounter = FPSCounter()
private val platformYOffset = if (hostOs == OS.Ios) 50f else 5f private val platformYOffset = if (hostOs == OS.Ios) 50f else 5f
...@@ -128,6 +129,11 @@ class Clocks(private val layer: SkiaLayer): SkikoView { ...@@ -128,6 +129,11 @@ class Clocks(private val layer: SkiaLayer): SkikoView {
when (event.kind) { when (event.kind) {
SkikoPointerEventKind.DOWN, SkikoPointerEventKind.DOWN,
SkikoPointerEventKind.MOVE -> { SkikoPointerEventKind.MOVE -> {
if (event.x > 200) {
cursorManager.setCursor(layer.component, PredefinedCursors.HAND)
} else {
cursorManager.setCursor(layer.component, PredefinedCursors.DEFAULT)
}
xpos = event.x xpos = event.x
ypos = event.y ypos = event.y
} }
......
...@@ -4,9 +4,10 @@ import android.content.* ...@@ -4,9 +4,10 @@ import android.content.*
import android.content.ClipboardManager import android.content.ClipboardManager
import android.content.res.Configuration import android.content.res.Configuration
import android.net.Uri import android.net.Uri
import android.view.PointerIcon.*
import android.view.View
import org.jetbrains.skiko.redrawer.Redrawer import org.jetbrains.skiko.redrawer.Redrawer
actual fun setSystemLookAndFeel(): Unit = TODO() actual fun setSystemLookAndFeel(): Unit = TODO()
internal class AndroidOpenGLRedrawer( internal class AndroidOpenGLRedrawer(
...@@ -65,3 +66,27 @@ internal actual fun ClipboardManager_getText(): String? { ...@@ -65,3 +66,27 @@ internal actual fun ClipboardManager_getText(): String? {
val clip = clipboard.primaryClip ?: return null val clip = clipboard.primaryClip ?: return null
return clip.getItemAt(0)?.text?.toString() return clip.getItemAt(0)?.text?.toString()
} }
actual typealias Cursor = android.view.PointerIcon
// TODO: not sure if correct.
internal actual fun CursorManager_setCursor(component: Any, cursor: Cursor) {
if (component is View) {
component.pointerIcon = cursor
}
}
internal actual fun CursorManager_getCursor(component: Any): Cursor? =
if (component is View) {
component.pointerIcon
} else {
null
}
internal actual fun getCursorById(id: PredefinedCursorsId): Cursor =
when (id) {
PredefinedCursorsId.DEFAULT -> getSystemIcon(defaultContext!!, TYPE_DEFAULT)
PredefinedCursorsId.CROSSHAIR -> getSystemIcon(defaultContext!!, TYPE_CROSSHAIR)
PredefinedCursorsId.HAND -> getSystemIcon(defaultContext!!, TYPE_HAND)
PredefinedCursorsId.TEXT -> getSystemIcon(defaultContext!!, TYPE_TEXT)
}
\ No newline at end of file
...@@ -109,5 +109,8 @@ actual open class SkiaLayer { ...@@ -109,5 +109,8 @@ actual open class SkiaLayer {
} }
} }
actual val component: Any?
get() = this.container
internal actual fun draw(canvas: Canvas): Unit = TODO() internal actual fun draw(canvas: Canvas): Unit = TODO()
} }
\ No newline at end of file
package org.jetbrains.skiko package org.jetbrains.skiko
import org.jetbrains.skiko.redrawer.* import org.jetbrains.skiko.redrawer.*
import java.awt.Component
import java.awt.Desktop import java.awt.Desktop
import java.awt.Toolkit import java.awt.Toolkit
import java.awt.datatransfer.DataFlavor import java.awt.datatransfer.DataFlavor
...@@ -63,3 +64,27 @@ internal actual fun ClipboardManager_getText(): String? { ...@@ -63,3 +64,27 @@ internal actual fun ClipboardManager_getText(): String? {
null null
} }
} }
actual typealias Cursor = java.awt.Cursor
internal actual fun CursorManager_setCursor(component: Any, cursor: Cursor) {
if (component is Component) {
component.cursor = cursor
}
}
internal actual fun CursorManager_getCursor(component: Any): Cursor? {
return if (component is Component) {
component.cursor
} else {
null
}
}
internal actual fun getCursorById(id: PredefinedCursorsId): Cursor =
when (id) {
PredefinedCursorsId.DEFAULT -> Cursor(Cursor.DEFAULT_CURSOR)
PredefinedCursorsId.CROSSHAIR -> Cursor(Cursor.CROSSHAIR_CURSOR)
PredefinedCursorsId.HAND -> Cursor(Cursor.HAND_CURSOR)
PredefinedCursorsId.TEXT -> Cursor(Cursor.TEXT_CURSOR)
}
\ No newline at end of file
...@@ -147,6 +147,9 @@ actual open class SkiaLayer internal constructor( ...@@ -147,6 +147,9 @@ actual open class SkiaLayer internal constructor(
fullscreenAdapter.fullscreen = value fullscreenAdapter.fullscreen = value
} }
actual val component: Any?
get() = backedLayer
actual var skikoView: SkikoView? = null actual var skikoView: SkikoView? = null
actual fun attachTo(container: Any) { actual fun attachTo(container: Any) {
......
package org.jetbrains.skiko
/**
* Identifiers of predefined cursors.
*/
enum class PredefinedCursorsId {
DEFAULT,
CROSSHAIR,
TEXT,
HAND
}
/**
* Predefined platform cursors.
*/
object PredefinedCursors {
val DEFAULT: Cursor = getCursorById(PredefinedCursorsId.DEFAULT)
val CROSSHAIR: Cursor = getCursorById(PredefinedCursorsId.CROSSHAIR)
val TEXT: Cursor = getCursorById(PredefinedCursorsId.TEXT)
val HAND: Cursor = getCursorById(PredefinedCursorsId.HAND)
}
/**
* Pointer device cursor abstraction.
*/
expect class Cursor
internal expect fun getCursorById(id: PredefinedCursorsId): Cursor
...@@ -18,10 +18,43 @@ internal expect fun URIHandler_openUri(uri: String) ...@@ -18,10 +18,43 @@ internal expect fun URIHandler_openUri(uri: String)
* Manager for controlling system clipboard. Is open so that platform could provide an override if default doesn't fit. * Manager for controlling system clipboard. Is open so that platform could provide an override if default doesn't fit.
*/ */
open class ClipboardManager { open class ClipboardManager {
/**
* Set current system clipboard content as text.
*/
open fun setText(text: String) = ClipboardManager_setText(text) open fun setText(text: String) = ClipboardManager_setText(text)
/**
* Get current system clipboard content as text.
*/
open fun getText(): String? = ClipboardManager_getText() open fun getText(): String? = ClipboardManager_getText()
} }
internal expect fun ClipboardManager_setText(text: String) internal expect fun ClipboardManager_setText(text: String)
internal expect fun ClipboardManager_getText(): String? internal expect fun ClipboardManager_getText(): String?
/**
* Manager to control cursor per native component.
*/
open class CursorManager {
/**
* Set cursor for the given component.
*/
open fun setCursor(component: Any?, cursor: Cursor) {
if (component != null) CursorManager_setCursor(component, cursor)
}
/**
* Get cursor for the given component.
*/
open fun getCursor(component: Any?): Cursor? = if (component != null) {
CursorManager_getCursor(component)
} else { null }
}
/**
* Sets cursor for the platform component.
*/
internal expect fun CursorManager_setCursor(component: Any, cursor: Cursor)
/**
* Gets current cursor for the platform component, or null if not defined or known.
*/
internal expect fun CursorManager_getCursor(component: Any): Cursor?
...@@ -3,20 +3,58 @@ package org.jetbrains.skiko ...@@ -3,20 +3,58 @@ package org.jetbrains.skiko
import org.jetbrains.skia.Canvas import org.jetbrains.skia.Canvas
import org.jetbrains.skia.Picture import org.jetbrains.skia.Picture
/**
* Generic layer for Skiko rendering.
*/
expect open class SkiaLayer { expect open class SkiaLayer {
/**
* Current graphics API used for rendering.
*/
var renderApi: GraphicsApi var renderApi: GraphicsApi
/**
* Current content scale.
*/
val contentScale: Float val contentScale: Float
/**
* If rendering is full screen.
*/
var fullscreen: Boolean var fullscreen: Boolean
/**
* If transparency is enabled.
*/
var transparency: Boolean var transparency: Boolean
/**
* Underlying platform component.
*/
val component: Any?
/**
* Current view used for rendering.
*/
var skikoView: SkikoView? var skikoView: SkikoView?
// Actual type of attach container is platform-specific. /**
* Attach this SkikoView to platform container.
* Actual type of attach container is platform-specific.
*/
fun attachTo(container: Any) fun attachTo(container: Any)
/**
* Detach this SkikoView from platform container.
*/
fun detach() fun detach()
/**
* Force redraw.
*/
fun needRedraw() fun needRedraw()
/**
* Drawing function.
*/
internal fun draw(canvas: Canvas) internal fun draw(canvas: Canvas)
} }
......
...@@ -14,3 +14,18 @@ internal actual fun ClipboardManager_setText(text: String) { ...@@ -14,3 +14,18 @@ internal actual fun ClipboardManager_setText(text: String) {
internal actual fun ClipboardManager_getText(): String? { internal actual fun ClipboardManager_getText(): String? {
return UIPasteboard.generalPasteboard.string return UIPasteboard.generalPasteboard.string
} }
// TODO: not sure if correct.
actual typealias Cursor = Any
internal actual fun CursorManager_setCursor(component: Any, cursor: Cursor) {}
internal actual fun CursorManager_getCursor(component: Any): Cursor? = null
internal actual fun getCursorById(id: PredefinedCursorsId): Cursor =
when (id) {
PredefinedCursorsId.DEFAULT -> Any()
PredefinedCursorsId.CROSSHAIR -> Any()
PredefinedCursorsId.HAND -> Any()
PredefinedCursorsId.TEXT -> Any()
}
\ No newline at end of file
...@@ -42,6 +42,9 @@ actual open class SkiaLayer { ...@@ -42,6 +42,9 @@ actual open class SkiaLayer {
redrawer?.needRedraw() redrawer?.needRedraw()
} }
actual val component: Any?
get() = this.view
val width: Float val width: Float
get() = view!!.frame.useContents { get() = view!!.frame.useContents {
return@useContents size.width.toFloat() return@useContents size.width.toFloat()
......
package org.jetbrains.skiko package org.jetbrains.skiko
import kotlinx.coroutines.await import org.w3c.dom.HTMLElement
internal actual inline fun <R> maybeSynchronized(lock: Any, block: () -> R): R = internal actual inline fun <R> maybeSynchronized(lock: Any, block: () -> R): R =
block() block()
...@@ -16,6 +16,31 @@ internal actual fun ClipboardManager_setText(text: String) { ...@@ -16,6 +16,31 @@ internal actual fun ClipboardManager_setText(text: String) {
} }
internal actual fun ClipboardManager_getText(): String? { internal actual fun ClipboardManager_getText(): String? {
TODO("implement ClipboardManager_getText") // TODO("implement ClipboardManager_getText")
// kotlinx.browser.window.navigator.clipboard.readText() // kotlinx.browser.window.navigator.clipboard.readText()
return null
} }
actual typealias Cursor = String
internal actual fun CursorManager_setCursor(component: Any, cursor: Cursor) {
if (component is HTMLElement) {
component.style.cursor = cursor
}
}
internal actual fun CursorManager_getCursor(component: Any): Cursor? {
return if (component is HTMLElement) {
component.style.cursor
} else {
null
}
}
internal actual fun getCursorById(id: PredefinedCursorsId): Cursor =
when (id) {
PredefinedCursorsId.DEFAULT -> "default"
PredefinedCursorsId.CROSSHAIR -> "crosshair"
PredefinedCursorsId.HAND -> "pointer"
PredefinedCursorsId.TEXT -> "text"
}
\ No newline at end of file
...@@ -76,11 +76,18 @@ actual open class SkiaLayer { ...@@ -76,11 +76,18 @@ actual open class SkiaLayer {
private var desiredWidth = 0 private var desiredWidth = 0
private var desiredHeight = 0 private var desiredHeight = 0
actual val component: Any?
get() = this.htmlCanvas
private var htmlCanvas: HTMLCanvasElement? = null
/** /**
* Initializes the [CanvasRenderer] and events listeners. * Initializes the [CanvasRenderer] and events listeners.
* Delegates rendering and events processing to [skikoView]. * Delegates rendering and events processing to [skikoView].
*/ */
fun attachTo(htmlCanvas: HTMLCanvasElement, autoDetach: Boolean = true) { fun attachTo(htmlCanvas: HTMLCanvasElement, autoDetach: Boolean = true) {
this.htmlCanvas = htmlCanvas
// Scale canvas to allow high DPI rendering as suggested in // Scale canvas to allow high DPI rendering as suggested in
// https://www.khronos.org/webgl/wiki/HandlingHighDPI. // https://www.khronos.org/webgl/wiki/HandlingHighDPI.
desiredWidth = htmlCanvas.width desiredWidth = htmlCanvas.width
......
...@@ -11,3 +11,21 @@ internal actual fun ClipboardManager_setText(text: String) { ...@@ -11,3 +11,21 @@ internal actual fun ClipboardManager_setText(text: String) {
internal actual fun ClipboardManager_getText(): String? { internal actual fun ClipboardManager_getText(): String? {
TODO("Implement ClipboardManager_getText() on Linux") TODO("Implement ClipboardManager_getText() on Linux")
} }
actual typealias Cursor = Any
internal actual fun CursorManager_setCursor(component: Any, cursor: Cursor) {
TODO("Implement CursorManager_setCursor on Linux")
}
internal actual fun CursorManager_getCursor(component: Any): Cursor? {
TODO("Implement CursorManager_getCursor on Linux")
}
internal actual fun getCursorById(id: PredefinedCursorsId): Cursor =
when (id) {
PredefinedCursorsId.DEFAULT -> Any()
PredefinedCursorsId.CROSSHAIR -> Any()
PredefinedCursorsId.HAND -> Any()
PredefinedCursorsId.TEXT -> Any()
}
\ No newline at end of file
...@@ -14,6 +14,8 @@ actual open class SkiaLayer { ...@@ -14,6 +14,8 @@ actual open class SkiaLayer {
actual var transparency: Boolean actual var transparency: Boolean
get() = TODO("Not yet implemented") get() = TODO("Not yet implemented")
set(value) {} set(value) {}
actual val component: Any?
get() = TODO("Not yet implemented")
actual fun needRedraw() { actual fun needRedraw() {
TODO("unimplemented") TODO("unimplemented")
} }
......
package org.jetbrains.skiko package org.jetbrains.skiko
import platform.AppKit.NSPasteboard import platform.AppKit.*
import platform.AppKit.NSPasteboardTypeString
import platform.AppKit.NSWorkspace
import platform.Foundation.NSURL import platform.Foundation.NSURL
internal actual fun URIHandler_openUri(uri: String) { internal actual fun URIHandler_openUri(uri: String) {
...@@ -16,3 +14,30 @@ internal actual fun ClipboardManager_setText(text: String) { ...@@ -16,3 +14,30 @@ internal actual fun ClipboardManager_setText(text: String) {
internal actual fun ClipboardManager_getText(): String? { internal actual fun ClipboardManager_getText(): String? {
return NSPasteboard.generalPasteboard.stringForType(dataType = NSPasteboardTypeString) return NSPasteboard.generalPasteboard.stringForType(dataType = NSPasteboardTypeString)
} }
actual typealias Cursor = NSCursor
// TODO: not sure if it is correct.
internal actual fun CursorManager_setCursor(component: Any, cursor: Cursor) {
if (component is NSView) {
component.resetCursorRects()
component.addCursorRect(component.bounds(), cursor)
}
}
internal actual fun CursorManager_getCursor(component: Any): Cursor? {
return if (component is NSView) {
// TODO: likely incorrect.
NSCursor.currentCursor
} else {
null
}
}
internal actual fun getCursorById(id: PredefinedCursorsId): Cursor =
when (id) {
PredefinedCursorsId.DEFAULT -> NSCursor.arrowCursor
PredefinedCursorsId.CROSSHAIR -> NSCursor.crosshairCursor
PredefinedCursorsId.HAND -> NSCursor.pointingHandCursor
PredefinedCursorsId.TEXT -> NSCursor.IBeamCursor
}
\ No newline at end of file
...@@ -76,6 +76,9 @@ actual open class SkiaLayer { ...@@ -76,6 +76,9 @@ actual open class SkiaLayer {
*/ */
lateinit var nsView: NSView lateinit var nsView: NSView
actual val component: Any?
get() = this.nsView
/** /**
* Implements rendering logic and events processing. * Implements rendering logic and events processing.
*/ */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment