Rotated UI rendering
This commit is contained in:
parent
fc1aa617af
commit
a9870fe133
1123
firmware2/Cargo.lock
generated
1123
firmware2/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -49,7 +49,7 @@ itertools = { version = "0.14.0", default-features = false }
|
||||||
bytemuck = "1.24.0"
|
bytemuck = "1.24.0"
|
||||||
slint = { version = "1.14.1", default-features = false, features = ["compat-1-2", "libm", "log", "unsafe-single-threaded", "renderer-software"]}
|
slint = { version = "1.14.1", default-features = false, features = ["compat-1-2", "libm", "log", "unsafe-single-threaded", "renderer-software"]}
|
||||||
critical-section = "1.2.0"
|
critical-section = "1.2.0"
|
||||||
shadow-rs = { version = "1.5.0", default-features = false }
|
backtrace = { version = "0.3.76", default-features = false }
|
||||||
|
|
||||||
# Crates for serial UART CLI
|
# Crates for serial UART CLI
|
||||||
embedded-cli = { version = "0.2.1", default-features = false, features = ["help", "macros"] }
|
embedded-cli = { version = "0.2.1", default-features = false, features = ["help", "macros"] }
|
||||||
|
|
@ -62,7 +62,7 @@ const-gen = "1.6"
|
||||||
embuild = "0.33"
|
embuild = "0.33"
|
||||||
cc = "1.2.9"
|
cc = "1.2.9"
|
||||||
slint-build = "1.14.1"
|
slint-build = "1.14.1"
|
||||||
shadow-rs = { version = "1.5.0", features = ["no_std"]}
|
gix = { version = "0.76.0", default-features = false, features = ["max-performance", "status"] }
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "acid-firmware"
|
name = "acid-firmware"
|
||||||
|
|
|
||||||
|
|
@ -6,13 +6,24 @@ use std::{env, fs};
|
||||||
use const_gen::*;
|
use const_gen::*;
|
||||||
use slint_build::{CompilerConfiguration, EmbedResourcesKind};
|
use slint_build::{CompilerConfiguration, EmbedResourcesKind};
|
||||||
use xz2::read::XzEncoder;
|
use xz2::read::XzEncoder;
|
||||||
use shadow_rs::ShadowBuilder;
|
// use shadow_rs::{BuildPattern, ShadowBuilder};
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
ShadowBuilder::builder()
|
if let Ok(repo) = gix::discover(env::var_os("CARGO_MANIFEST_DIR").unwrap().into_string().unwrap()) {
|
||||||
.deny_const(Default::default())
|
let commit_hash = repo.head_commit().unwrap().short_id().unwrap();
|
||||||
.build()
|
println!("cargo:rustc-env=GIT_COMMIT_HASH={}", commit_hash);
|
||||||
.unwrap();
|
println!("cargo:rustc-env=GIT_COMMIT={}",
|
||||||
|
repo.find_tag(repo.head_id().unwrap())
|
||||||
|
.ok()
|
||||||
|
.map(|tag| format!("{} ({})", tag.decode().unwrap().name, commit_hash))
|
||||||
|
.unwrap_or_else(|| commit_hash.to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// ShadowBuilder::builder()
|
||||||
|
// .build_pattern(BuildPattern::Lazy)
|
||||||
|
// .deny_const(Default::default())
|
||||||
|
// .build()
|
||||||
|
// .unwrap();
|
||||||
|
|
||||||
// Generate vial config at the root of project
|
// Generate vial config at the root of project
|
||||||
println!("cargo:rerun-if-changed=vial.json");
|
println!("cargo:rerun-if-changed=vial.json");
|
||||||
|
|
@ -24,6 +35,8 @@ fn main() {
|
||||||
// println!("cargo:rustc-link-arg=-Tdefmt.x");
|
// println!("cargo:rustc-link-arg=-Tdefmt.x");
|
||||||
|
|
||||||
let slint_config = CompilerConfiguration::new()
|
let slint_config = CompilerConfiguration::new()
|
||||||
|
// .with_scale_factor(4.0)
|
||||||
|
.with_style("cosmic-dark".to_string())
|
||||||
.embed_resources(EmbedResourcesKind::EmbedForSoftwareRenderer);
|
.embed_resources(EmbedResourcesKind::EmbedForSoftwareRenderer);
|
||||||
slint_build::compile_with_config("ui/main.slint", slint_config).expect("Slint build failed");
|
slint_build::compile_with_config("ui/main.slint", slint_config).expect("Slint build failed");
|
||||||
slint_build::print_rustc_flags().unwrap()
|
slint_build::print_rustc_flags().unwrap()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,6 @@
|
||||||
|
|
||||||
|
use core::fmt::Write;
|
||||||
|
|
||||||
use embedded_cli::cli::CliBuilder;
|
use embedded_cli::cli::CliBuilder;
|
||||||
use embedded_cli::Command;
|
use embedded_cli::Command;
|
||||||
use esp_hal::{Async, uart::{TxError, UartRx}};
|
use esp_hal::{Async, uart::{TxError, UartRx}};
|
||||||
|
|
@ -71,7 +73,7 @@ pub async fn run_console(mut uart_rx: UartRx<'_, Async>) {
|
||||||
// write!(cli.writer(), "Hello, {}", name.unwrap_or("World"))?;
|
// write!(cli.writer(), "Hello, {}", name.unwrap_or("World"))?;
|
||||||
// }
|
// }
|
||||||
Base::Version => {
|
Base::Version => {
|
||||||
cli.writer().write_str(crate::build::CLAP_LONG_VERSION).unwrap();
|
cli.writer().write_fmt(format_args!("{} - {} - {}", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION"), env!("GIT_COMMIT"))).unwrap();
|
||||||
}
|
}
|
||||||
Base::Reset => {
|
Base::Reset => {
|
||||||
cli.writer().write_str("Performing software reset.").unwrap();
|
cli.writer().write_str("Performing software reset.").unwrap();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
use core::fmt::Write;
|
use core::fmt::Write;
|
||||||
|
|
||||||
|
use alloc::{string::String, vec::Vec};
|
||||||
|
use backtrace::{BytesOrWideString, Symbol, SymbolName};
|
||||||
use critical_section::{CriticalSection, Mutex};
|
use critical_section::{CriticalSection, Mutex};
|
||||||
use esp_hal::uart::UartTx;
|
use esp_hal::uart::UartTx;
|
||||||
use esp_hal::Blocking;
|
use esp_hal::Blocking;
|
||||||
|
|
@ -83,7 +85,7 @@ fn panic_handler(info: &core::panic::PanicInfo) -> ! {
|
||||||
use esp_backtrace::Backtrace;
|
use esp_backtrace::Backtrace;
|
||||||
|
|
||||||
println!("{RED}");
|
println!("{RED}");
|
||||||
println!("====================== PANIC ======================");
|
println!("=============== CUSTOM PANIC HANDLER ==============");
|
||||||
println!("{info}{RESET}");
|
println!("{info}{RESET}");
|
||||||
println!("");
|
println!("");
|
||||||
println!("Backtrace:");
|
println!("Backtrace:");
|
||||||
|
|
@ -93,11 +95,39 @@ fn panic_handler(info: &core::panic::PanicInfo) -> ! {
|
||||||
|
|
||||||
for frame in backtrace.frames() {
|
for frame in backtrace.frames() {
|
||||||
println!("0x{:x}", frame.program_counter());
|
println!("0x{:x}", frame.program_counter());
|
||||||
|
print_resolved_symbol(frame.program_counter());
|
||||||
}
|
}
|
||||||
|
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "usb-log"))]
|
||||||
|
fn print_resolved_symbol(address: usize) {
|
||||||
|
unsafe {
|
||||||
|
backtrace::resolve_unsynchronized(address as _, |sym| {
|
||||||
|
println!("? {:x?}\n{}\n\n", sym.addr().map(|addr| addr as usize), sym.name().unwrap_or(SymbolName::new(b"(unknown)")));
|
||||||
|
// sym.filename_raw().unwrap_or(BytesOrWideString::Bytes(&[]));
|
||||||
|
// let segments: Vec<String> = vec![
|
||||||
|
// sym.addr().map(|a| format!("{:x?}", a as isize)),
|
||||||
|
// sym.name().map(|n| n.to_string()),
|
||||||
|
// sym.filename().map(|p| {
|
||||||
|
// format!(
|
||||||
|
// "{}{}",
|
||||||
|
// p.to_string_lossy(),
|
||||||
|
// sym.lineno()
|
||||||
|
// .map(|n| format!(" (line {})", n))
|
||||||
|
// .unwrap_or_else(|| "".to_string())
|
||||||
|
// )
|
||||||
|
// }),
|
||||||
|
// ]
|
||||||
|
// .into_iter()
|
||||||
|
// .flatten()
|
||||||
|
// .collect();
|
||||||
|
// segments.join("\n")
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn setup_alternative_logging(alt_uart: UartTx<'static, Blocking>, level_filter: LevelFilter)
|
pub fn setup_alternative_logging(alt_uart: UartTx<'static, Blocking>, level_filter: LevelFilter)
|
||||||
{
|
{
|
||||||
critical_section::with(|cs| {
|
critical_section::with(|cs| {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ use core::time::Duration;
|
||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::rc::Rc;
|
use alloc::rc::Rc;
|
||||||
use alloc::vec;
|
use alloc::vec;
|
||||||
use shadow_rs::shadow;
|
|
||||||
use bt_hci::controller::ExternalController;
|
use bt_hci::controller::ExternalController;
|
||||||
use embassy_executor::Spawner;
|
use embassy_executor::Spawner;
|
||||||
use esp_alloc::{HeapRegion, MemoryCapability};
|
use esp_alloc::{HeapRegion, MemoryCapability};
|
||||||
|
|
@ -26,7 +25,7 @@ use esp_hal::lcd_cam::lcd::dpi::Dpi;
|
||||||
use esp_hal::mcpwm::{McPwm, PeripheralClockConfig};
|
use esp_hal::mcpwm::{McPwm, PeripheralClockConfig};
|
||||||
use esp_hal::psram::{FlashFreq, PsramConfig, PsramSize, SpiRamFreq, SpiTimingConfigCoreClock};
|
use esp_hal::psram::{FlashFreq, PsramConfig, PsramSize, SpiRamFreq, SpiTimingConfigCoreClock};
|
||||||
use esp_hal::rng::TrngSource;
|
use esp_hal::rng::TrngSource;
|
||||||
use esp_hal::system::Stack;
|
use esp_hal::system::{CpuControl, Stack};
|
||||||
use esp_hal::time::Instant;
|
use esp_hal::time::Instant;
|
||||||
use esp_hal::timer::timg::TimerGroup;
|
use esp_hal::timer::timg::TimerGroup;
|
||||||
use esp_hal::{Blocking, ram};
|
use esp_hal::{Blocking, ram};
|
||||||
|
|
@ -44,14 +43,17 @@ use rmk::{join_all};
|
||||||
use rmk::keyboard::Keyboard;
|
use rmk::keyboard::Keyboard;
|
||||||
use rmk::storage::async_flash_wrapper;
|
use rmk::storage::async_flash_wrapper;
|
||||||
use rmk::{initialize_keymap_and_storage, run_devices, run_rmk};
|
use rmk::{initialize_keymap_and_storage, run_devices, run_rmk};
|
||||||
use slint::platform::software_renderer::Rgb565Pixel;
|
use slint::platform::WindowAdapter;
|
||||||
|
use slint::platform::software_renderer::{MinimalSoftwareWindow, RenderingRotation, RepaintBufferType, Rgb565Pixel, SoftwareRenderer};
|
||||||
use slint::{ComponentHandle, PhysicalSize, WindowSize};
|
use slint::{ComponentHandle, PhysicalSize, WindowSize};
|
||||||
use static_cell::StaticCell;
|
use static_cell::StaticCell;
|
||||||
use ui::AppWindow;
|
use ui::AppWindow;
|
||||||
|
use ui::window_adapter::SoftwareWindowAdapter;
|
||||||
use {esp_alloc as _, esp_backtrace as _};
|
use {esp_alloc as _, esp_backtrace as _};
|
||||||
|
|
||||||
use crate::matrix::IoeMatrix;
|
use crate::matrix::IoeMatrix;
|
||||||
use crate::peripherals::st7701s::St7701s;
|
use crate::peripherals::st7701s::St7701s;
|
||||||
|
use crate::ui::backend::{FramebufferPtr, SlintBackend};
|
||||||
use crate::vial::{VIAL_KEYBOARD_DEF, VIAL_KEYBOARD_ID};
|
use crate::vial::{VIAL_KEYBOARD_DEF, VIAL_KEYBOARD_ID};
|
||||||
|
|
||||||
mod keymap;
|
mod keymap;
|
||||||
|
|
@ -64,8 +66,6 @@ mod logging;
|
||||||
#[cfg(feature = "alt-log")]
|
#[cfg(feature = "alt-log")]
|
||||||
mod console;
|
mod console;
|
||||||
|
|
||||||
shadow!(build);
|
|
||||||
|
|
||||||
// This creates a default app-descriptor required by the esp-idf bootloader.
|
// This creates a default app-descriptor required by the esp-idf bootloader.
|
||||||
// For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
|
// For more information see: <https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/system/app_image_format.html#application-description>
|
||||||
esp_bootloader_esp_idf::esp_app_desc!();
|
esp_bootloader_esp_idf::esp_app_desc!();
|
||||||
|
|
@ -267,10 +267,11 @@ async fn main(_spawner: Spawner) {
|
||||||
960,
|
960,
|
||||||
));
|
));
|
||||||
|
|
||||||
let window_size = [framebuffer.width, framebuffer.height];
|
// let window_size = [framebuffer.width, framebuffer.height];
|
||||||
|
let window_size = [framebuffer.height, framebuffer.width];
|
||||||
let framebuffer_ptr = FramebufferPtr(framebuffer.as_target_pixels() as _);
|
let framebuffer_ptr = FramebufferPtr(framebuffer.as_target_pixels() as _);
|
||||||
|
|
||||||
static SECOND_CORE_STACK: StaticCell<Stack<8192>> = StaticCell::new();
|
static SECOND_CORE_STACK: StaticCell<Stack<{8192 * 2}>> = StaticCell::new();
|
||||||
let second_core_stack = SECOND_CORE_STACK.init(Stack::new());
|
let second_core_stack = SECOND_CORE_STACK.init(Stack::new());
|
||||||
esp_rtos::start_second_core(
|
esp_rtos::start_second_core(
|
||||||
peripherals.CPU_CTRL,
|
peripherals.CPU_CTRL,
|
||||||
|
|
@ -381,50 +382,6 @@ impl Framebuffer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct SlintBackend {
|
|
||||||
window_size: [u32; 2],
|
|
||||||
window: RefCell<Option<Rc<slint::platform::software_renderer::MinimalSoftwareWindow>>>,
|
|
||||||
framebuffer: FramebufferPtr,
|
|
||||||
// peripherals: RefCell<Option<Peripherals>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FramebufferPtr(*mut [Rgb565Pixel]);
|
|
||||||
|
|
||||||
unsafe impl Send for FramebufferPtr {}
|
|
||||||
|
|
||||||
impl slint::platform::Platform for SlintBackend {
|
|
||||||
fn create_window_adapter(&self) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {
|
|
||||||
let window = slint::platform::software_renderer::MinimalSoftwareWindow::new(
|
|
||||||
slint::platform::software_renderer::RepaintBufferType::ReusedBuffer,
|
|
||||||
);
|
|
||||||
window.set_size(WindowSize::Physical(PhysicalSize::new(self.window_size[0], self.window_size[1])));
|
|
||||||
self.window.replace(Some(window.clone()));
|
|
||||||
Ok(window)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn duration_since_start(&self) -> Duration {
|
|
||||||
Duration::from_millis(Instant::now().duration_since_epoch().as_millis())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_event_loop(&self) -> Result<(), slint::PlatformError> {
|
|
||||||
loop {
|
|
||||||
slint::platform::update_timers_and_animations();
|
|
||||||
|
|
||||||
if let Some(window) = self.window.borrow().clone() {
|
|
||||||
// window.try_dispatch_event(todo!())?;
|
|
||||||
|
|
||||||
window.draw_if_needed(|renderer| {
|
|
||||||
// TODO: Proper synchronization.
|
|
||||||
let framebuffer = unsafe { &mut *self.framebuffer.0 };
|
|
||||||
// TODO: Try using height to see if it rotates the screen correctly. Might need
|
|
||||||
// to swap dimensions elsewhere.
|
|
||||||
renderer.render(framebuffer, self.window_size[0] as usize);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// impl DrawTarget for Framebuffer {
|
// impl DrawTarget for Framebuffer {
|
||||||
// type Color = Rgb565;
|
// type Color = Rgb565;
|
||||||
// type Error = ();
|
// type Error = ();
|
||||||
|
|
|
||||||
56
firmware2/src/ui/backend.rs
Normal file
56
firmware2/src/ui/backend.rs
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
use core::{cell::RefCell, time::Duration};
|
||||||
|
|
||||||
|
use alloc::rc::Rc;
|
||||||
|
use esp_hal::time::Instant;
|
||||||
|
use log::info;
|
||||||
|
use slint::{PhysicalSize, WindowSize, platform::software_renderer::{RenderingRotation, RepaintBufferType, Rgb565Pixel, SoftwareRenderer}};
|
||||||
|
|
||||||
|
use super::window_adapter::SoftwareWindowAdapter;
|
||||||
|
|
||||||
|
pub struct FramebufferPtr(pub *mut [Rgb565Pixel]);
|
||||||
|
|
||||||
|
unsafe impl Send for FramebufferPtr {}
|
||||||
|
|
||||||
|
pub struct SlintBackend {
|
||||||
|
pub window_size: [u32; 2],
|
||||||
|
pub window: RefCell<Option<Rc<SoftwareWindowAdapter>>>,
|
||||||
|
pub framebuffer: FramebufferPtr,
|
||||||
|
// pub peripherals: RefCell<Option<Peripherals>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl slint::platform::Platform for SlintBackend {
|
||||||
|
fn create_window_adapter(&self) -> Result<Rc<dyn slint::platform::WindowAdapter>, slint::PlatformError> {
|
||||||
|
// TODO: Custom window adapter impl needs to be implemented, so we can change `rotation` on
|
||||||
|
// `SoftwareRenderer`.
|
||||||
|
let renderer = SoftwareRenderer::new_with_repaint_buffer_type(RepaintBufferType::ReusedBuffer /* TODO: Implement a swapchain */);
|
||||||
|
renderer.set_rendering_rotation(RenderingRotation::Rotate270);
|
||||||
|
let window = SoftwareWindowAdapter::new(renderer);
|
||||||
|
// window.set_scale_factor(4.0);
|
||||||
|
window.set_size(WindowSize::Physical(PhysicalSize::new(self.window_size[0], self.window_size[1])));
|
||||||
|
self.window.replace(Some(window.clone()));
|
||||||
|
Ok(window)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn duration_since_start(&self) -> Duration {
|
||||||
|
Duration::from_millis(Instant::now().duration_since_epoch().as_millis())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_event_loop(&self) -> Result<(), slint::PlatformError> {
|
||||||
|
loop {
|
||||||
|
slint::platform::update_timers_and_animations();
|
||||||
|
|
||||||
|
if let Some(window) = self.window.borrow().clone() {
|
||||||
|
// window.try_dispatch_event(todo!())?;
|
||||||
|
|
||||||
|
window.draw_if_needed(|renderer| {
|
||||||
|
// TODO: Proper synchronization.
|
||||||
|
let framebuffer = unsafe { &mut *self.framebuffer.0 };
|
||||||
|
// TODO: Try using height to see if it rotates the screen correctly. Might need
|
||||||
|
// to swap dimensions elsewhere.
|
||||||
|
renderer.render(framebuffer, self.window_size[1] as usize);
|
||||||
|
info!("UI rendered.");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,6 @@
|
||||||
// #![cfg_attr(not(feature = "simulator"), no_main)]
|
// #![cfg_attr(not(feature = "simulator"), no_main)]
|
||||||
|
|
||||||
|
pub mod window_adapter;
|
||||||
|
pub mod backend;
|
||||||
|
|
||||||
slint::include_modules!();
|
slint::include_modules!();
|
||||||
|
|
|
||||||
86
firmware2/src/ui/window_adapter.rs
Normal file
86
firmware2/src/ui/window_adapter.rs
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
use core::{cell::Cell, ops::{Deref, DerefMut}};
|
||||||
|
|
||||||
|
use alloc::rc::{Rc, Weak};
|
||||||
|
use slint::{PhysicalSize, Window, WindowSize, platform::{Renderer, WindowAdapter, WindowEvent, software_renderer::{RepaintBufferType, SoftwareRenderer}}};
|
||||||
|
|
||||||
|
/// This is a minimal adapter for a Window that doesn't have any other feature than rendering
|
||||||
|
/// using the software renderer.
|
||||||
|
pub struct SoftwareWindowAdapter {
|
||||||
|
pub window: Window,
|
||||||
|
pub renderer: SoftwareRenderer,
|
||||||
|
needs_redraw: Cell<bool>,
|
||||||
|
size: Cell<PhysicalSize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SoftwareWindowAdapter {
|
||||||
|
/// Instantiate a new MinimalWindowAdaptor
|
||||||
|
///
|
||||||
|
/// The `repaint_buffer_type` parameter specify what kind of buffer are passed to the [`SoftwareRenderer`]
|
||||||
|
pub fn new(renderer: SoftwareRenderer) -> Rc<Self> {
|
||||||
|
Rc::new_cyclic(|w: &Weak<Self>| Self {
|
||||||
|
window: Window::new(w.clone()),
|
||||||
|
renderer,
|
||||||
|
needs_redraw: Cell::new(true),
|
||||||
|
size: Default::default(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If the window needs to be redrawn, the callback will be called with the
|
||||||
|
/// [renderer](SoftwareRenderer) that should be used to do the drawing.
|
||||||
|
///
|
||||||
|
/// [`SoftwareRenderer::render()`] or [`SoftwareRenderer::render_by_line()`] should be called
|
||||||
|
/// in that callback.
|
||||||
|
///
|
||||||
|
/// Return true if something was redrawn.
|
||||||
|
pub fn draw_if_needed(&self, render_callback: impl FnOnce(&SoftwareRenderer)) -> bool {
|
||||||
|
if self.needs_redraw.replace(false) /*|| self.renderer.rendering_metrics_collector.is_some()*/ {
|
||||||
|
render_callback(&self.renderer);
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_scale_factor(&self, scale_factor: f32) {
|
||||||
|
self.window.dispatch_event(WindowEvent::ScaleFactorChanged { scale_factor });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WindowAdapter for SoftwareWindowAdapter {
|
||||||
|
fn window(&self) -> &Window {
|
||||||
|
&self.window
|
||||||
|
}
|
||||||
|
|
||||||
|
fn renderer(&self) -> &dyn Renderer {
|
||||||
|
&self.renderer
|
||||||
|
}
|
||||||
|
|
||||||
|
fn size(&self) -> PhysicalSize {
|
||||||
|
self.size.get()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_size(&self, size: WindowSize) {
|
||||||
|
let sf = self.window.scale_factor();
|
||||||
|
self.size.set(size.to_physical(sf));
|
||||||
|
self.window
|
||||||
|
.dispatch_event(WindowEvent::Resized { size: size.to_logical(sf) })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn request_redraw(&self) {
|
||||||
|
self.needs_redraw.set(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Deref for SoftwareWindowAdapter {
|
||||||
|
type Target = Window;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.window
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for SoftwareWindowAdapter {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.window
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,18 +1,40 @@
|
||||||
import { Button, VerticalBox } from "std-widgets.slint";
|
import { Button, VerticalBox, LineEdit, GridBox } from "std-widgets.slint";
|
||||||
|
|
||||||
export component AppWindow inherits Window {
|
export component AppWindow inherits Window {
|
||||||
|
y: 0px;
|
||||||
in-out property <int> counter: 42;
|
in-out property <int> counter: 42;
|
||||||
|
default-font-family: "IBM Plex Sans";
|
||||||
|
default-font-size: 16pt;
|
||||||
callback request-increase-value();
|
callback request-increase-value();
|
||||||
VerticalBox {
|
GridBox {
|
||||||
Text {
|
height: 240px;
|
||||||
text: "Counter: \{root.counter}";
|
padding: 0px;
|
||||||
|
padding-top: 8px;
|
||||||
|
width: 960px;
|
||||||
|
VerticalBox {
|
||||||
|
Text {
|
||||||
|
text: "Counter: \{root.counter}";
|
||||||
|
}
|
||||||
|
|
||||||
|
Button {
|
||||||
|
text: "Increase value";
|
||||||
|
clicked => {
|
||||||
|
root.request-increase-value();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LineEdit {
|
||||||
|
input-type: InputType.password;
|
||||||
|
text: "LineEdit";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Button {
|
Button {
|
||||||
text: "Increase value";
|
text: "Button";
|
||||||
clicked => {
|
}
|
||||||
root.request-increase-value();
|
|
||||||
}
|
Button {
|
||||||
|
text: "Button";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue