Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lokui: GUI framework experiment #5

Draft
wants to merge 49 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
468dc30
I think I'm on to something there
Speykious Apr 15, 2023
6054eef
I got one button inside a panel with paddings 👀
Speykious Apr 16, 2023
cb469f6
Got events to work with the whole system too
Speykious Apr 16, 2023
3a73fb4
Turn playground into counter example
Speykious Apr 17, 2023
432a955
Do not print while drawing
Speykious Apr 17, 2023
acd189a
Stop printing while solving layout
Speykious Apr 17, 2023
502494e
Add `debug` function to `Widget` trait
Speykious Apr 17, 2023
6ebb16a
Simplify `Anchor`
Speykious Apr 17, 2023
38d06ca
flex
Speykious Apr 17, 2023
ed737bb
Remove other useless prints
Speykious Apr 17, 2023
e9dc989
Get anchor-origin system right
Speykious Apr 17, 2023
b88dd1e
Consistency in placement of constructor functions
Speykious Apr 17, 2023
25fce4f
Implement text rendering
Speykious Apr 17, 2023
ad39404
Implement `Display` for `Lazy<T>`
Speykious Apr 17, 2023
bd6c2b9
Implement basics of flex layout
Speykious Apr 17, 2023
29e6b54
Add a few comments
Speykious Apr 17, 2023
4bd9b0e
Add `debug` for `Text` component
Speykious Apr 17, 2023
46d59e4
Make `Widget::draw` take a Skia canvas
Speykious Apr 17, 2023
008451f
small format and clean
Speykious Apr 17, 2023
8726f8b
That wasn't needed
Speykious Apr 17, 2023
73d659e
Make lokinit a dev dependency
Speykious Apr 18, 2023
f5a05dc
Put buttons on true center
Speykious Apr 18, 2023
a1350ff
`FlexLayout`'s `align` property has no effect
Speykious Apr 18, 2023
d1174ba
Remove `PaneChild` struct
Speykious Apr 19, 2023
fee22f3
Put flex layout solving into a single function
Speykious Apr 19, 2023
045e040
Add flex layout gap logic
Speykious Apr 19, 2023
cc6e3b6
refactor: functions to solve width and height
Speykious Apr 19, 2023
e8fa294
fix: cargo fmt
Speykious Apr 19, 2023
6b34435
Handle hover events
Speykious Apr 19, 2023
547580c
Basics of animation system
Speykious Apr 21, 2023
241aad8
Woops, didn't mean to change that
Speykious Apr 21, 2023
1b36d4f
Add `WithBackground` widget wrapper
Speykious Apr 22, 2023
7edfde9
Add a `WidgetContainer` trait
Speykious Apr 24, 2023
a927665
Remove `Laz`
Speykious Apr 24, 2023
289f752
Remove unused imports
Speykious Apr 24, 2023
6393c0d
Use `get_mut()` in example
Speykious Apr 24, 2023
1aed813
Remove now useless `set` method for `Lazy`
Speykious Apr 24, 2023
27f1aed
Make padding a wrapper
Speykious Apr 25, 2023
b2a4f5f
Slightly decrease verbosity w/ color in RectState
Speykious Apr 25, 2023
58f247d
Rename `FlexLayout` to `Flex`
Speykious Apr 25, 2023
363a9f0
Introduce a prelude module for ease of imports
Speykious Apr 25, 2023
9a7247a
Actually making padding a wrapper was a bad idea
Speykious Apr 25, 2023
8fcefa3
Add WithOnCLick and WithOnEvent wrappers
Speykious May 14, 2023
cf11755
Make `on_click` callback return a boolean
Speykious May 14, 2023
3845d90
Add `argb_hex` method to `Color`
Speykious May 14, 2023
6b6cb6e
Make counter example look slightly better
Speykious May 14, 2023
3fdf34b
Replace old lokinit code with winit for now
Speykious Jul 26, 2023
bbd32b9
Ah yes, the up is made out of down
Speykious Jul 27, 2023
6508348
Fix Skia drop order bug and simplify example
Speykious Jul 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,878 changes: 1,741 additions & 137 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions lokui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,11 @@ version = "0.1.0"
edition = "2021"

[dependencies]
skia-safe = { version = "0.63.0", features = ["gl"] }

[dev-dependencies]
gl = "0.14.0"
glutin = "0.30.9"
glutin-winit = "0.3.0"
raw-window-handle = "0.5.2"
winit = "0.28.6"
198 changes: 198 additions & 0 deletions lokui/examples/common/skia_window.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,198 @@
use std::{error::Error, ffi::CString, num::NonZeroU32};

use gl::types::*;
use glutin::{
config::{ConfigTemplateBuilder, GlConfig},
context::{
ContextApi, ContextAttributesBuilder, NotCurrentGlContextSurfaceAccessor,
PossiblyCurrentContext,
},
display::{GetGlDisplay, GlDisplay},
surface::{Surface as GlutinSurface, SurfaceAttributesBuilder, WindowSurface},
};
use glutin_winit::DisplayBuilder;
use raw_window_handle::HasRawWindowHandle;
use skia_safe::{
gpu::{gl::FramebufferInfo, BackendRenderTarget, SurfaceOrigin},
ColorType, Surface,
};
use winit::{
dpi::{PhysicalSize, Size},
event_loop::EventLoop,
window::{Window, WindowBuilder},
};

// Guarantee the drop order inside the FnMut closure. `Window` _must_ be dropped after
// `DirectContext`.
//
// https://github.com/rust-skia/rust-skia/issues/476
pub struct SkiaWindowCtx {
pub fb_info: FramebufferInfo,
pub num_samples: usize,
pub stencil_size: usize,
pub surface: Surface,
pub gl_surface: GlutinSurface<WindowSurface>,
pub gr_context: skia_safe::gpu::DirectContext,
pub gl_context: PossiblyCurrentContext,
pub window: Window,
pub events: EventLoop<()>,
}

pub fn create_skia_window(
title: &str,
width: u32,
height: u32,
) -> Result<SkiaWindowCtx, Box<dyn Error>> {
let events = EventLoop::new();

let winit_window_builder = WindowBuilder::new()
.with_title(title)
.with_inner_size(Size::Physical(PhysicalSize::new(width, height)));

let template = ConfigTemplateBuilder::new()
.with_alpha_size(8)
.with_transparency(true);

let display_builder = DisplayBuilder::new().with_window_builder(Some(winit_window_builder));
let (window, gl_config) = display_builder
.build(&events, template, |configs| {
// Find the config with the minimum number of samples. Usually Skia takes care of
// anti-aliasing and may not be able to create appropriate Surfaces for samples > 0.
// See https://github.com/rust-skia/rust-skia/issues/782
// And https://github.com/rust-skia/rust-skia/issues/764
configs
.reduce(|accum, config| {
let transparency_check = config.supports_transparency().unwrap_or(false)
& !accum.supports_transparency().unwrap_or(false);

if transparency_check || config.num_samples() < accum.num_samples() {
config
} else {
accum
}
})
.unwrap()
})
.unwrap();

println!("Picked a config with {} samples", gl_config.num_samples());

let mut window = window.expect("Could not create window with OpenGL context");
let raw_window_handle = window.raw_window_handle();

// The context creation part. It can be created before surface and that's how
// it's expected in multithreaded + multiwindow operation mode, since you
// can send NotCurrentContext, but not Surface.
let context_attributes = ContextAttributesBuilder::new().build(Some(raw_window_handle));

// Since glutin by default tries to create OpenGL core context, which may not be
// present we should try gles.
let fallback_context_attributes = ContextAttributesBuilder::new()
.with_context_api(ContextApi::Gles(None))
.build(Some(raw_window_handle));

let not_current_gl_context = unsafe {
gl_config
.display()
.create_context(&gl_config, &context_attributes)
.unwrap_or_else(|_| {
gl_config
.display()
.create_context(&gl_config, &fallback_context_attributes)
.expect("failed to create context")
})
};

let attrs = SurfaceAttributesBuilder::<WindowSurface>::new().build(
raw_window_handle,
NonZeroU32::new(width).unwrap(),
NonZeroU32::new(height).unwrap(),
);

let gl_surface = unsafe {
gl_config
.display()
.create_window_surface(&gl_config, &attrs)
.expect("Could not create gl window surface")
};

let gl_context = not_current_gl_context
.make_current(&gl_surface)
.expect("Could not make GL context current when setting up skia renderer");

gl::load_with(|s| {
gl_config
.display()
.get_proc_address(CString::new(s).unwrap().as_c_str())
});

let interface = skia_safe::gpu::gl::Interface::new_load_with(|name| {
if name == "eglGetCurrentDisplay" {
return std::ptr::null();
}
gl_config
.display()
.get_proc_address(CString::new(name).unwrap().as_c_str())
})
.expect("Could not create interface");

let mut gr_context = skia_safe::gpu::DirectContext::new_gl(Some(interface), None)
.expect("Could not create direct context");

let fb_info = {
let mut fboid: GLint = 0;
unsafe { gl::GetIntegerv(gl::FRAMEBUFFER_BINDING, &mut fboid) };

FramebufferInfo {
fboid: fboid.try_into().unwrap(),
format: skia_safe::gpu::gl::Format::RGBA8.into(),
}
};

let num_samples = gl_config.num_samples() as usize;
let stencil_size = gl_config.stencil_size() as usize;

let surface = create_surface(
&mut window,
fb_info,
&mut gr_context,
num_samples,
stencil_size,
);

Ok(SkiaWindowCtx {
fb_info,
num_samples,
stencil_size,
surface,
gl_surface,
gr_context,
gl_context,
window,
events,
})
}

pub fn create_surface(
window: &mut Window,
fb_info: FramebufferInfo,
gr_context: &mut skia_safe::gpu::DirectContext,
num_samples: usize,
stencil_size: usize,
) -> Surface {
let size = window.inner_size();
let size = (size.width as i32, size.height as i32);

let backend_render_target =
BackendRenderTarget::new_gl(size, num_samples, stencil_size, fb_info);

Surface::from_backend_render_target(
gr_context,
&backend_render_target,
SurfaceOrigin::BottomLeft,
ColorType::RGBA8888,
None,
None,
)
.expect("Could not create skia surface")
}
Loading