diff --git a/lib/src/main/kotlin/com/github/mnemotechnician/mkui/windows/Window.kt b/lib/src/main/kotlin/com/github/mnemotechnician/mkui/windows/Window.kt index 101a3f2..f2efe5d 100644 --- a/lib/src/main/kotlin/com/github/mnemotechnician/mkui/windows/Window.kt +++ b/lib/src/main/kotlin/com/github/mnemotechnician/mkui/windows/Window.kt @@ -21,22 +21,29 @@ abstract class Window { var isDragging = false internal set - /** Name of this window, displayed in the top bar */ - open var name = "unnamed window" + /** Name of this window, displayed in the top bar. Should be overriden. */ + abstract var name: String + + /** Whether this window can be closed by the user. Should be overriden. */ + abstract var closeable: Boolean /** Called when the window is being created. At this point the window has a Table assigned to it, which should be inflated by this function. */ abstract fun onCreate() /** The window has already been created, this function is called on every tick. You should avoid modifying the table from this function: that can cause a performance loss. */ - fun onUpdate() { + open fun onUpdate() { } /** Called whenever the window is being dragged by the user */ - fun onDrag() { + open fun onDrag() { } /** Called whenever this window is being toggled by the user */ - fun onToggle(collapsed: Boolean) { + open fun onToggle(collapsed: Boolean) { + } + + /** Called whenever the window is being destroyed */ + open fun onDestroy() { } } \ No newline at end of file diff --git a/lib/src/main/kotlin/com/github/mnemotechnician/mkui/windows/WindowManager.kt b/lib/src/main/kotlin/com/github/mnemotechnician/mkui/windows/WindowManager.kt index 4a97b16..55b63c7 100644 --- a/lib/src/main/kotlin/com/github/mnemotechnician/mkui/windows/WindowManager.kt +++ b/lib/src/main/kotlin/com/github/mnemotechnician/mkui/windows/WindowManager.kt @@ -5,6 +5,8 @@ import arc.math.* import arc.util.* import arc.struct.* import arc.input.* +import arc.scene.* +import arc.scene.actions.* import arc.scene.event.* import arc.scene.ui.* import arc.scene.ui.layout.* @@ -19,12 +21,19 @@ object WindowManager { internal val windowGroup = WidgetGroup() internal val windows = Seq() + /** Windows that were requested to be created before the window manager was initialized are placed into this queue */ + internal val windowQueue = Queue(10) + internal var initialized = false + init { Events.run(EventType.ClientLoadEvent::class.java) { windowGroup.setFillParent(true) windowGroup.touchable = Touchable.childrenOnly; Core.scene.add(windowGroup) + initialized = true + repeat(windowQueue.size) { constructWindow(windowQueue.removeFirst()) } + Log.info("[blue]Initialized the window manager") } @@ -35,8 +44,8 @@ object WindowManager { val pos = root.localToParentCoordinates(Tmp.v1.set(0f, 0f)); root.setPosition( - Mathf.clamp(pos.x, root.getPrefWidth() / 2, windowGroup.width - root.getPrefWidth() / 2), - Mathf.clamp(pos.y, root.getPrefHeight() / 2, windowGroup.height - root.getPrefHeight() / 2) + Mathf.clamp(pos.x, 0f/*root.getPrefWidth() / 2*/, windowGroup.width - root.getPrefWidth() /*/ 2*/), + Mathf.clamp(pos.y, 0f/*root.getPrefHeight() / 2*/, windowGroup.height - root.getPrefHeight() /*/ 2*/) ); root.color.a = if (it.isDragging) 0.5f else 1f @@ -47,8 +56,8 @@ object WindowManager { } } - /** Constructs & registers the window */ - fun createWindow(window: Window) { + /** Actually creates the window without any delays. Must be called after the initialization. */ + internal fun constructWindow(window: Window) { val windowTable = Table(Styles.black6).apply { lateinit var collapser: Collapser @@ -56,7 +65,8 @@ object WindowManager { //top bar — name, buttons and also a way to drag the table addTable(Styles.black3) { - addLabel({ window.name }, ellipsis = "...").growX() + //window name + addLabel({ window.name }, ellipsis = "...").growX().get().setFontScale(0.6f) //collapse/show textToggle("[accent]-", Styles.togglet) { @@ -67,6 +77,11 @@ object WindowManager { window.onToggle(it) }.size(50f) + //hide button + textButton("[red]X", Styles.togglet) { + this@apply.fadeRemove() + }.size(50f).visible { window.closeable } + //making it draggable addListener(object : InputListener() { var dragx = 0f @@ -75,11 +90,11 @@ object WindowManager { override fun touchDown(event: InputEvent, x: Float, y: Float, pointer: Int, button: KeyCode): Boolean { dragx = x; dragy = y; window.isDragging = true; - return true; + return true; } override fun touchDragged(event: InputEvent, x: Float, y: Float, pointer: Int) { - val pos = window.rootTable.localToParentCoordinates(Tmp.v1.set(x, y)) + val pos = window.rootTable.localToParentCoordinates(Tmp.v1.set(x - dragx, y - dragy)) window.rootTable.setPosition(pos.x, pos.y) window.onDrag() @@ -89,7 +104,7 @@ object WindowManager { window.isDragging = false; } }) - }.fillX().marginBottom(5f) + }.fillX().pad(5f) row() @@ -103,20 +118,46 @@ object WindowManager { } windowGroup.addChild(windowTable) + windowTable.fadeIn() windowTable.setPosition(Core.scene.width / 2, Core.scene.height / 2) windows.add(window) } + /** Constructs & registers the window. If the game hasn't yet loaded, delays the creation */ + fun createWindow(window: Window) { + if (initialized) { + constructWindow(window) + } else { + windowQueue.add(window) + } + } + /** Creates an anonymous window. Such a window won't be able to receive onUpdate, onToggle, onDrag events. */ inline fun createWindow(name: String, crossinline constructor: Table.() -> Unit) { createWindow(object : Window() { override var name = name + override var closeable = true + override fun onCreate() { table.constructor() } }) } + internal fun Element.fadeIn() { + addAction(Actions.sequence( + Actions.alpha(0f), + Actions.fadeIn(0.5f, Interp.pow3) + )) + } + + internal fun Element.fadeRemove() { + addAction(Actions.sequence( + Actions.fadeOut(0.5f, Interp.pow3), + Actions.run { if (parent != null) parent.removeChild(this) } + )) + } + } \ No newline at end of file