kitgit

tirbofish/dropbear · commit

9a860a35e652d5b955e49dd00cf44fb486d04324

FINALLY GOT TEXT TO RENDER YIPPEEEEEEE!!!! jarvis, run github actions Unverified

Thribhu K <4tkbytes@pm.me> · 2026-01-27 11:35

view full diff

diff --git a/crates/dropbear-engine/src/lib.rs b/crates/dropbear-engine/src/lib.rs
index 35467fb..0028298 100644
--- a/crates/dropbear-engine/src/lib.rs
+++ b/crates/dropbear-engine/src/lib.rs
@@ -225,7 +225,8 @@ Hardware:
             width: initial_width,
             height: initial_height,
             present_mode: surface_caps.present_modes[0],
-            alpha_mode: surface_caps.alpha_modes[0],
+            // alpha_mode: surface_caps.alpha_modes[0],
+            alpha_mode: wgpu::CompositeAlphaMode::Auto,
             view_formats: vec![],
             desired_maximum_frame_latency: 2,
         };
diff --git a/crates/eucalyptus-core/src/ui.rs b/crates/eucalyptus-core/src/ui.rs
index 561ad2e..6a594ca 100644
--- a/crates/eucalyptus-core/src/ui.rs
+++ b/crates/eucalyptus-core/src/ui.rs
@@ -1,5 +1,6 @@
 mod button;
 mod utils;
+mod text;
 
 use std::cell::RefCell;
 use std::collections::HashMap;
@@ -7,12 +8,15 @@ use ::jni::JNIEnv;
 use ::jni::objects::JObject;
 use parking_lot::Mutex;
 use serde::{Deserialize, Serialize};
-use yakui::{Yakui};
+use yakui::{Alignment, MainAxisSize, Yakui};
+use yakui::font::Fonts;
 use dropbear_engine::utils::ResourceReference;
 use dropbear_macro::SerializableComponent;
 use dropbear_traits::SerializableComponent;
 use crate::scripting::jni::utils::{FromJObject};
 use crate::scripting::result::DropbearNativeResult;
+use crate::ui::button::ButtonParser;
+use crate::ui::text::TextParser;
 
 thread_local! {
     pub static UI_CONTEXT: RefCell<UiContext> = RefCell::new(UiContext::new());
@@ -46,16 +50,6 @@ pub struct WrapperWidget<T> {
     pub widget: T,
 }
 
-impl NativeWidget for WrapperWidget<yakui::widgets::Button> {
-    fn build(self: Box<Self>, states: &mut HashMap<i64, WidgetState>) {
-        let res = self.widget.show();
-        states.insert(self.id, WidgetState {
-            clicked: res.clicked,
-            hovering: res.hovering,
-        });
-    }
-}
-
 pub trait WidgetParser: Send + Sync {
     fn parse(&self, env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Option<Box<dyn NativeWidget>>>;
     fn name(&self) -> String;
@@ -67,37 +61,6 @@ pub fn register_widget_parser<P: WidgetParser + 'static>(parser: P) {
     });
 }
 
-struct ButtonParser;
-
-impl WidgetParser for ButtonParser {
-    fn parse(&self, env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Option<Box<dyn NativeWidget>>> {
-        let class = env.get_object_class(obj)?;
-        let name_str_obj = env.call_method(class, "getName", "()Ljava/lang/String;", &[])?.l()?;
-        let name_string: String = env.get_string(&name_str_obj.into())?.into();
-        // println!("ButtonParser obj get_string result: {}", name_string);
-
-        if name_string.contains("ButtonInstruction$Button") {
-            let button_obj = env.get_field(obj, "button", "Lcom/dropbear/ui/widgets/Button;")?.l()?;
-            let btn = yakui::widgets::Button::from_jobject(env, &button_obj)?;
-            
-            let id_obj = env.get_field(obj, "id", "Lcom/dropbear/ui/WidgetId;")?.l()?;
-            let id = env.get_field(id_obj, "id", "J")?.j()?;
-            
-            return Ok(Some(Box::new(WrapperWidget {
-                id,
-                widget: btn,
-            })));
-        }
-
-        Ok(None)
-    }
-
-    fn name(&self) -> String {
-        String::from("ButtonParser")
-    }
-}
-
-
 pub struct UiContext {
     pub yakui_state: Mutex<Yakui>,
     pub instruction_set: Mutex<Vec<Box<dyn NativeWidget>>>,
@@ -114,9 +77,15 @@ pub fn poll() {
         widget_states.clear();
         
         let current_instructions = instructions.drain(..).collect::<Vec<Box<dyn NativeWidget>>>();
-        for i in current_instructions {
-            i.build(&mut widget_states);
-        }
+        yakui::widgets::Align::new(Alignment::TOP_LEFT).show(|| {
+            yakui::widgets::List::column()
+                .main_axis_size(MainAxisSize::Min)
+                .show(|| {
+                    for i in current_instructions {
+                        i.build(&mut widget_states);
+                    }
+                });
+        });
     });
 }
 
@@ -125,8 +94,15 @@ impl UiContext {
         let mut parsers: Vec<Box<dyn WidgetParser>> = Vec::new();
 
         parsers.push(Box::new(ButtonParser));
+        parsers.push(Box::new(TextParser));
 
         let yakui = Yakui::new();
+        let fonts = yakui.dom().get_global_or_init(Fonts::default);
+        fonts.set_sans_serif_family("Roboto");
+        fonts.set_serif_family("Roboto");
+        fonts.set_cursive_family("Roboto");
+        fonts.set_fantasy_family("Roboto");
+        fonts.set_monospace_family("Roboto");
 
         Self {
             yakui_state: Mutex::new(yakui),
@@ -181,7 +157,7 @@ pub mod jni {
                         rust_instructions.push(widget);
                         break;
                     },
-                    Ok(None) => {println!("[Java_com_dropbear_ui_UINative_renderUI] Ok but None"); continue},
+                    Ok(None) => continue,
                     Err(e) => {
                         eprintln!("[Java_com_dropbear_ui_UINative_renderUI] Error converting UI instruction: {:?}", e);
                     }
@@ -199,9 +175,9 @@ pub mod jni {
         ui_buf_ptr: jlong,
         id: jlong,
     ) -> jboolean {
-         let ui = convert_ptr!(ui_buf_ptr => UiContext);
-         let states = ui.widget_states.lock();
-         states.get(&id).map(|s| s.clicked).unwrap_or(false).into()
+        let ui = convert_ptr!(ui_buf_ptr => UiContext);
+        let states = ui.widget_states.lock();
+        states.get(&id).map(|s| s.clicked).unwrap_or(false).into()
     }
 
     #[unsafe(no_mangle)]
@@ -211,8 +187,8 @@ pub mod jni {
         ui_buf_ptr: jlong,
         id: jlong,
     ) -> jboolean {
-         let ui = convert_ptr!(ui_buf_ptr => UiContext);
-         let states = ui.widget_states.lock();
-         states.get(&id).map(|s| s.hovering).unwrap_or(false).into()
+        let ui = convert_ptr!(ui_buf_ptr => UiContext);
+        let states = ui.widget_states.lock();
+        states.get(&id).map(|s| s.hovering).unwrap_or(false).into()
     }
 }
\ No newline at end of file
diff --git a/crates/eucalyptus-core/src/ui/button.rs b/crates/eucalyptus-core/src/ui/button.rs
index a56dc72..dc7ecb6 100644
--- a/crates/eucalyptus-core/src/ui/button.rs
+++ b/crates/eucalyptus-core/src/ui/button.rs
@@ -5,6 +5,48 @@ use yakui::widgets::{Button, Pad, DynamicButtonStyle};
 use crate::scripting::jni::utils::FromJObject;
 use crate::scripting::result::DropbearNativeResult;
 use std::borrow::Cow;
+use std::collections::HashMap;
+use crate::ui::{NativeWidget, WidgetParser, WidgetState, WrapperWidget};
+
+pub(crate) struct ButtonParser;
+
+impl WidgetParser for ButtonParser {
+    fn parse(&self, env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Option<Box<dyn NativeWidget>>> {
+        let class = env.get_object_class(obj)?;
+        let name_str_obj = env.call_method(class, "getName", "()Ljava/lang/String;", &[])?.l()?;
+        let name_string: String = env.get_string(&name_str_obj.into())?.into();
+        // println!("ButtonParser obj get_string result: {}", name_string);
+
+        if name_string.contains("ButtonInstruction$Button") {
+            let button_obj = env.get_field(obj, "button", "Lcom/dropbear/ui/widgets/Button;")?.l()?;
+            let btn = yakui::widgets::Button::from_jobject(env, &button_obj)?;
+
+            let id_obj = env.get_field(obj, "id", "Lcom/dropbear/ui/WidgetId;")?.l()?;
+            let id = env.get_field(id_obj, "id", "J")?.j()?;
+
+            return Ok(Some(Box::new(WrapperWidget {
+                id,
+                widget: btn,
+            })));
+        }
+
+        Ok(None)
+    }
+
+    fn name(&self) -> String {
+        String::from("ButtonParser")
+    }
+}
+
+impl NativeWidget for WrapperWidget<yakui::widgets::Button> {
+    fn build(self: Box<Self>, states: &mut HashMap<i64, WidgetState>) {
+        let res = self.widget.show();
+        states.insert(self.id, WidgetState {
+            clicked: res.clicked,
+            hovering: res.hovering,
+        });
+    }
+}
 
 impl FromJObject for Button {
     fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self> {
diff --git a/crates/eucalyptus-core/src/ui/text.rs b/crates/eucalyptus-core/src/ui/text.rs
new file mode 100644
index 0000000..e7c084e
--- /dev/null
+++ b/crates/eucalyptus-core/src/ui/text.rs
@@ -0,0 +1,71 @@
+use std::borrow::Cow;
+use std::collections::HashMap;
+use jni::JNIEnv;
+use jni::objects::JObject;
+use yakui::style::TextStyle;
+use yakui::widgets::Pad;
+use crate::scripting::jni::utils::FromJObject;
+use crate::scripting::result::DropbearNativeResult;
+use crate::ui::{NativeWidget, WidgetParser, WidgetState, WrapperWidget};
+
+pub(crate) struct TextParser;
+
+impl WidgetParser for TextParser {
+    fn parse(&self, env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Option<Box<dyn NativeWidget>>> {
+        let class = env.get_object_class(obj)?;
+        let name_str_obj = env.call_method(class, "getName", "()Ljava/lang/String;", &[])?.l()?;
+        let name_string: String = env.get_string(&name_str_obj.into())?.into();
+        // println!("TextParser obj get_string result: {}", name_string);
+
+        if name_string.contains("TextInstruction$Text") {
+            let text_obj = env.get_field(obj, "text", "Lcom/dropbear/ui/widgets/Text;")?.l()?;
+            let text = yakui::widgets::Text::from_jobject(env, &text_obj)?;
+
+            let id_obj = env.get_field(obj, "id", "Lcom/dropbear/ui/WidgetId;")?.l()?;
+            let id = env.get_field(id_obj, "id", "J")?.j()?;
+
+            return Ok(Some(Box::new(WrapperWidget {
+                id,
+                widget: text,
+            })));
+        }
+
+        Ok(None)
+    }
+
+    fn name(&self) -> String {
+        String::from("TextParser")
+    }
+}
+
+impl NativeWidget for WrapperWidget<yakui::widgets::Text> {
+    fn build(self: Box<Self>, _states: &mut HashMap<i64, WidgetState>) {
+        self.widget.show();
+    }
+}
+
+impl FromJObject for yakui::widgets::Text {
+    fn from_jobject(env: &mut JNIEnv, obj: &JObject) -> DropbearNativeResult<Self>
+    where
+        Self: Sized
+    {
+        let text_field = env.get_field(obj, "text", "Ljava/lang/String;")?;
+        let text_jstring = text_field.l()?.into();
+        let text: String = env.get_string(&text_jstring)?.into();
+
+        let style_obj = env.get_field(obj, "style", "Lcom/dropbear/ui/styling/TextStyle;")?.l()?;
+        let style = TextStyle::from_jobject(env, &style_obj)?;
+
+        let f = env.get_field(obj, "padding", "Lcom/dropbear/ui/styling/Padding;")?.l()?;
+        let padding = Pad::from_jobject(
+            env,
+            &f
+        )?;
+        
+        Ok(Self {
+            text: Cow::Owned(text),
+            style,
+            padding,
+        })
+    }
+}
\ No newline at end of file
diff --git a/crates/eucalyptus-editor/src/main.rs b/crates/eucalyptus-editor/src/main.rs
index 1d023c1..35da56f 100644
--- a/crates/eucalyptus-editor/src/main.rs
+++ b/crates/eucalyptus-editor/src/main.rs
@@ -93,9 +93,10 @@ async fn main() -> anyhow::Result<()> {
 
                 Ok(())
             })
+            .filter_level(LevelFilter::Warn)
             .filter(Some("dropbear_engine"), LevelFilter::Trace)
             .filter(
-                Some("eucalyptus-editor".replace('-', "_").as_str()),
+                Some("eucalyptus_editor"),
                 LevelFilter::Debug,
             )
             .filter(Some("eucalyptus_core"), LevelFilter::Debug)
diff --git a/crates/redback-runtime/src/scene.rs b/crates/redback-runtime/src/scene.rs
index f3f562c..5a2d151 100644
--- a/crates/redback-runtime/src/scene.rs
+++ b/crates/redback-runtime/src/scene.rs
@@ -13,7 +13,6 @@ use wgpu::{Color};
 use wgpu::util::DeviceExt;
 use winit::event_loop::ActiveEventLoop;
 use winit::event::WindowEvent;
-use yakui::font::Fonts;
 use yakui_wgpu::SurfaceInfo;
 use dropbear_engine::camera::Camera;
 use dropbear_engine::buffer::ResizableBuffer;
@@ -465,20 +464,26 @@ impl Scene for PlayMode {
                         let yak = yakui_cell.borrow();
                         let mut yakui = yak.yakui_state.lock();
 
-                        yakui.set_surface_size(yakui::geometry::Vec2::new(display_width, display_height));
-                        yakui.start();
+                        let tex_size = graphics.viewport_texture.size;
+                        let viewport_size = yakui::geometry::Vec2::new(
+                            tex_size.width as f32,
+                            tex_size.height as f32,
+                        );
+                        yakui.set_surface_size(viewport_size);
+                        yakui.set_unscaled_viewport(yakui::geometry::Rect::from_pos_size(
+                            yakui::geometry::Vec2::ZERO,
+                            viewport_size,
+                        ));
+                        yakui.set_scale_factor(graphics.window.scale_factor() as f32);
 
-                        let fonts = yakui.dom().get_global_or_init(Fonts::default);
-                        fonts.with_system(|v| {
-                            log_once::debug_once!("font len: {}", v.db().len());
-                        });
+                        yakui.start();
 
                         eucalyptus_core::ui::poll();
 
-                        // Layer::new().show(|| {
-                        //     column(|| {
-                        //         let button_response = Button::styled("My Button")
-                        //             .padding(Pad::all(10.0))
+                        // yakui::widgets::Layer::new().show(|| {
+                        //     yakui::column(|| {
+                        //         let button_response = yakui::widgets::Button::styled("My Button")
+                        //             .padding(yakui::widgets::Pad::all(10.0))
                         //             .show();
                         //         if button_response.clicked {
                         //             println!("This is clicked!");
@@ -887,7 +892,6 @@ impl Scene for PlayMode {
             let mut yakui = yak.yakui_state.lock();
             if let Some(yak) = &mut self.yakui_winit {
                 yak.handle_window_event(&mut yakui, event);
-
             }
         });
     }
diff --git a/resources/fonts/Roboto-Regular.ttf b/resources/fonts/Roboto-Regular.ttf
new file mode 100644
index 0000000..7e3bb2f
Binary files /dev/null and b/resources/fonts/Roboto-Regular.ttf differ
diff --git a/scripting/commonMain/kotlin/com/dropbear/ui/styling/Padding.kt b/scripting/commonMain/kotlin/com/dropbear/ui/styling/Padding.kt
index 01f1647..f3f72f3 100644
--- a/scripting/commonMain/kotlin/com/dropbear/ui/styling/Padding.kt
+++ b/scripting/commonMain/kotlin/com/dropbear/ui/styling/Padding.kt
@@ -8,6 +8,9 @@ data class Padding(
     var top: Double,
     var bottom: Double,
 ) {
+    constructor(value: Double): this(value, value, value, value)
+    constructor(horizontal: Double, vertical: Double) : this(horizontal, horizontal, vertical, vertical)
+
     companion object {
         fun zero() = Padding.all(0.0)
 
diff --git a/scripting/commonMain/kotlin/com/dropbear/ui/widgets/Button.kt b/scripting/commonMain/kotlin/com/dropbear/ui/widgets/Button.kt
index 348f8ba..f729063 100644
--- a/scripting/commonMain/kotlin/com/dropbear/ui/widgets/Button.kt
+++ b/scripting/commonMain/kotlin/com/dropbear/ui/widgets/Button.kt
@@ -12,6 +12,7 @@ import com.dropbear.ui.styling.Padding
 import com.dropbear.ui.styling.TextStyle
 import com.dropbear.ui.styling.fonts.TextAlignment
 import com.dropbear.utils.Colour
+import com.dropbear.utils.ID
 
 class Button(
     var text: String,
@@ -21,8 +22,13 @@ class Button(
     var style: DynamicButtonStyle,
     var hoverStyle: DynamicButtonStyle,
     var downStyle: DynamicButtonStyle,
+    id: WidgetId = WidgetId(text.hashCode().toLong()),
 ): Widget() {
-    override lateinit var id: WidgetId
+    override var id: WidgetId
+
+    init {
+        this.id = id
+    }
 
     val clicked: Boolean
         get() = getClicked()
diff --git a/scripting/commonMain/kotlin/com/dropbear/ui/widgets/Text.kt b/scripting/commonMain/kotlin/com/dropbear/ui/widgets/Text.kt
new file mode 100644
index 0000000..c02043e
--- /dev/null
+++ b/scripting/commonMain/kotlin/com/dropbear/ui/widgets/Text.kt
@@ -0,0 +1,66 @@
+package com.dropbear.ui.widgets
+
+import com.dropbear.ui.UIBuilder
+import com.dropbear.ui.UIInstruction
+import com.dropbear.ui.Widget
+import com.dropbear.ui.WidgetId
+import com.dropbear.ui.styling.Padding
+import com.dropbear.ui.styling.TextStyle
+
+class Text(
+    var text: String,
+    var style: TextStyle = TextStyle(),
+    var padding: Padding,
+    id: WidgetId = WidgetId(text.hashCode().toLong()),
+) : Widget() {
+    override var id: WidgetId
+
+    init {
+        this.id = id
+    }
+
+    companion object {
+        fun withStyle(text: String, style: TextStyle, id: String = text): Text {
+            val text = Text(text, style, padding = Padding.zero())
+            text.id = WidgetId(id.hashCode().toLong())
+            return text
+        }
+
+        fun label(text: String, id: String = text): Text {
+            val text = Text(text, TextStyle(), Padding.all(8.0))
+            text.id = WidgetId(id.hashCode().toLong())
+            return text
+        }
+    }
+
+    sealed class TextInstruction: UIInstruction {
+        data class Text(val id: WidgetId, val text: com.dropbear.ui.widgets.Text) : TextInstruction()
+    }
+
+    fun toInstruction(): TextInstruction.Text {
+        return TextInstruction.Text(this.id, this)
+    }
+}
+
+fun UIBuilder.label(text: String, block: Text.() -> Unit = {}): Text {
+    val style = TextStyle()
+    val text = Text(
+        text = text,
+        style = style,
+        padding = Padding.zero()
+    ).apply(block)
+    instructions.add(text.toInstruction())
+    return text
+}
+
+fun UIBuilder.text(size: Double, text: String, block: Text.() -> Unit = {}): Text {
+    val style = TextStyle()
+    style.fontSize = size
+    val text = Text(
+        text = text,
+        style = style,
+        padding = Padding.zero()
+    ).apply(block)
+    instructions.add(text.toInstruction())
+    return text
+}
\ No newline at end of file