Rename Data to Context and move to own file
This commit is contained in:
parent
de76cb6190
commit
f709423809
8 changed files with 159 additions and 158 deletions
104
emigui/src/context.rs
Normal file
104
emigui/src/context.rs
Normal file
|
@ -0,0 +1,104 @@
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use crate::*;
|
||||
|
||||
/// Contains the input, style and output of all GUI commands.
|
||||
pub struct Context {
|
||||
/// The default style for new regions
|
||||
pub(crate) style: Mutex<Style>,
|
||||
pub(crate) fonts: Arc<Fonts>,
|
||||
pub(crate) input: GuiInput,
|
||||
pub(crate) memory: Mutex<Memory>,
|
||||
pub(crate) graphics: Mutex<GraphicLayers>,
|
||||
}
|
||||
|
||||
impl Clone for Context {
|
||||
fn clone(&self) -> Self {
|
||||
Context {
|
||||
style: Mutex::new(self.style()),
|
||||
fonts: self.fonts.clone(),
|
||||
input: self.input,
|
||||
memory: Mutex::new(self.memory.lock().unwrap().clone()),
|
||||
graphics: Mutex::new(self.graphics.lock().unwrap().clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn new(pixels_per_point: f32) -> Context {
|
||||
Context {
|
||||
style: Default::default(),
|
||||
fonts: Arc::new(Fonts::new(pixels_per_point)),
|
||||
input: Default::default(),
|
||||
memory: Default::default(),
|
||||
graphics: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn input(&self) -> &GuiInput {
|
||||
&self.input
|
||||
}
|
||||
|
||||
pub fn style(&self) -> Style {
|
||||
*self.style.lock().unwrap()
|
||||
}
|
||||
|
||||
pub fn set_style(&self, style: Style) {
|
||||
*self.style.lock().unwrap() = style;
|
||||
}
|
||||
|
||||
// TODO: move
|
||||
pub fn new_frame(&mut self, gui_input: GuiInput) {
|
||||
self.input = gui_input;
|
||||
if !gui_input.mouse_down || gui_input.mouse_pos.is_none() {
|
||||
self.memory.lock().unwrap().active_id = None;
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the user interacting with anything?
|
||||
pub fn any_active(&self) -> bool {
|
||||
self.memory.lock().unwrap().active_id.is_some()
|
||||
}
|
||||
|
||||
pub fn interact(&self, layer: Layer, rect: Rect, interaction_id: Option<Id>) -> InteractInfo {
|
||||
let mut memory = self.memory.lock().unwrap();
|
||||
|
||||
let hovered = if let Some(mouse_pos) = self.input.mouse_pos {
|
||||
if rect.contains(mouse_pos) {
|
||||
let is_something_else_active =
|
||||
memory.active_id.is_some() && memory.active_id != interaction_id;
|
||||
|
||||
!is_something_else_active && layer == memory.layer_at(mouse_pos)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let active = if interaction_id.is_some() {
|
||||
if hovered && self.input.mouse_clicked {
|
||||
memory.active_id = interaction_id;
|
||||
}
|
||||
memory.active_id == interaction_id
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let clicked = hovered && self.input.mouse_released;
|
||||
|
||||
InteractInfo {
|
||||
rect,
|
||||
hovered,
|
||||
clicked,
|
||||
active,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn style_ui(&self, region: &mut Region) {
|
||||
let mut style = self.style();
|
||||
style.ui(region);
|
||||
self.set_style(style);
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ struct Stats {
|
|||
/// Encapsulates input, layout and painting for ease of use.
|
||||
pub struct Emigui {
|
||||
pub last_input: RawInput,
|
||||
pub data: Arc<layout::Data>,
|
||||
pub ctx: Arc<Context>,
|
||||
stats: Stats,
|
||||
anti_alias: bool,
|
||||
}
|
||||
|
@ -20,14 +20,14 @@ impl Emigui {
|
|||
pub fn new(pixels_per_point: f32) -> Emigui {
|
||||
Emigui {
|
||||
last_input: Default::default(),
|
||||
data: Arc::new(layout::Data::new(pixels_per_point)),
|
||||
ctx: Arc::new(Context::new(pixels_per_point)),
|
||||
stats: Default::default(),
|
||||
anti_alias: true,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn texture(&self) -> &Texture {
|
||||
self.data.fonts.texture()
|
||||
self.ctx.fonts.texture()
|
||||
}
|
||||
|
||||
pub fn new_frame(&mut self, new_input: RawInput) {
|
||||
|
@ -35,31 +35,31 @@ impl Emigui {
|
|||
self.last_input = new_input;
|
||||
|
||||
// TODO: avoid this clone
|
||||
let mut new_data = (*self.data).clone();
|
||||
let mut new_data = (*self.ctx).clone();
|
||||
new_data.new_frame(gui_input);
|
||||
self.data = Arc::new(new_data);
|
||||
self.ctx = Arc::new(new_data);
|
||||
}
|
||||
|
||||
pub fn whole_screen_region(&mut self) -> Region {
|
||||
Region {
|
||||
data: self.data.clone(),
|
||||
ctx: self.ctx.clone(),
|
||||
layer: Layer::Background,
|
||||
style: self.data.style(),
|
||||
style: self.ctx.style(),
|
||||
id: Default::default(),
|
||||
dir: layout::Direction::Vertical,
|
||||
align: layout::Align::Center,
|
||||
cursor: Default::default(),
|
||||
bounding_size: Default::default(),
|
||||
available_space: self.data.input.screen_size,
|
||||
available_space: self.ctx.input.screen_size,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn paint(&mut self) -> Mesh {
|
||||
let paint_commands: Vec<PaintCmd> = self.data.graphics.lock().unwrap().drain().collect();
|
||||
let paint_commands: Vec<PaintCmd> = self.ctx.graphics.lock().unwrap().drain().collect();
|
||||
let mut mesher = Mesher::new(self.last_input.pixels_per_point);
|
||||
mesher.anti_alias = self.anti_alias;
|
||||
|
||||
mesher.paint(&self.data.fonts, &paint_commands);
|
||||
mesher.paint(&self.ctx.fonts, &paint_commands);
|
||||
let mesh = mesher.mesh;
|
||||
self.stats.num_vertices = mesh.vertices.len();
|
||||
self.stats.num_triangles = mesh.indices.len() / 3;
|
||||
|
@ -69,20 +69,20 @@ impl Emigui {
|
|||
pub fn ui(&mut self, region: &mut Region) {
|
||||
region.foldable("Style", |region| {
|
||||
region.add(Checkbox::new(&mut self.anti_alias, "Antialias"));
|
||||
self.data.style_ui(region);
|
||||
self.ctx.style_ui(region);
|
||||
});
|
||||
|
||||
region.foldable("Fonts", |region| {
|
||||
let old_font_definitions = self.data.fonts.definitions();
|
||||
let old_font_definitions = self.ctx.fonts.definitions();
|
||||
let mut new_font_definitions = old_font_definitions.clone();
|
||||
font_definitions_ui(&mut new_font_definitions, region);
|
||||
self.data.fonts.texture().ui(region);
|
||||
self.ctx.fonts.texture().ui(region);
|
||||
if *old_font_definitions != new_font_definitions {
|
||||
let mut new_data = (*self.data).clone();
|
||||
let mut new_data = (*self.ctx).clone();
|
||||
let fonts =
|
||||
Fonts::from_definitions(new_font_definitions, self.data.input.pixels_per_point);
|
||||
Fonts::from_definitions(new_font_definitions, self.ctx.input.pixels_per_point);
|
||||
new_data.fonts = Arc::new(fonts);
|
||||
self.data = Arc::new(new_data);
|
||||
self.ctx = Arc::new(new_data);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
use std::{
|
||||
hash::Hash,
|
||||
sync::{Arc, Mutex},
|
||||
};
|
||||
use std::{hash::Hash, sync::Arc};
|
||||
|
||||
use crate::{widgets::*, *};
|
||||
|
||||
|
@ -22,7 +19,7 @@ pub struct GuiResponse {
|
|||
pub rect: Rect,
|
||||
|
||||
/// Used for showing a popup (if any)
|
||||
pub data: Arc<Data>,
|
||||
pub ctx: Arc<Context>,
|
||||
}
|
||||
|
||||
impl GuiResponse {
|
||||
|
@ -32,9 +29,9 @@ impl GuiResponse {
|
|||
F: FnOnce(&mut Region),
|
||||
{
|
||||
if self.hovered {
|
||||
if let Some(mouse_pos) = self.data.input().mouse_pos {
|
||||
if let Some(mouse_pos) = self.ctx.input().mouse_pos {
|
||||
let window_pos = mouse_pos + vec2(16.0, 16.0);
|
||||
show_popup(&self.data, window_pos, add_contents);
|
||||
show_popup(&self.ctx, window_pos, add_contents);
|
||||
}
|
||||
}
|
||||
self
|
||||
|
@ -95,121 +92,19 @@ pub fn make_id<H: Hash>(source: &H) -> Id {
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// TODO: give a better name. Context?
|
||||
/// Contains the input, style and output of all GUI commands.
|
||||
pub struct Data {
|
||||
/// The default style for new regions
|
||||
pub(crate) style: Mutex<Style>,
|
||||
pub(crate) fonts: Arc<Fonts>,
|
||||
pub(crate) input: GuiInput,
|
||||
pub(crate) memory: Mutex<Memory>,
|
||||
pub(crate) graphics: Mutex<GraphicLayers>,
|
||||
}
|
||||
|
||||
impl Clone for Data {
|
||||
fn clone(&self) -> Self {
|
||||
Data {
|
||||
style: Mutex::new(self.style()),
|
||||
fonts: self.fonts.clone(),
|
||||
input: self.input,
|
||||
memory: Mutex::new(self.memory.lock().unwrap().clone()),
|
||||
graphics: Mutex::new(self.graphics.lock().unwrap().clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Data {
|
||||
pub fn new(pixels_per_point: f32) -> Data {
|
||||
Data {
|
||||
style: Default::default(),
|
||||
fonts: Arc::new(Fonts::new(pixels_per_point)),
|
||||
input: Default::default(),
|
||||
memory: Default::default(),
|
||||
graphics: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn input(&self) -> &GuiInput {
|
||||
&self.input
|
||||
}
|
||||
|
||||
pub fn style(&self) -> Style {
|
||||
*self.style.lock().unwrap()
|
||||
}
|
||||
|
||||
pub fn set_style(&self, style: Style) {
|
||||
*self.style.lock().unwrap() = style;
|
||||
}
|
||||
|
||||
// TODO: move
|
||||
pub fn new_frame(&mut self, gui_input: GuiInput) {
|
||||
self.input = gui_input;
|
||||
if !gui_input.mouse_down || gui_input.mouse_pos.is_none() {
|
||||
self.memory.lock().unwrap().active_id = None;
|
||||
}
|
||||
}
|
||||
|
||||
/// Is the user interacting with anything?
|
||||
pub fn any_active(&self) -> bool {
|
||||
self.memory.lock().unwrap().active_id.is_some()
|
||||
}
|
||||
|
||||
pub fn interact(&self, layer: Layer, rect: Rect, interaction_id: Option<Id>) -> InteractInfo {
|
||||
let mut memory = self.memory.lock().unwrap();
|
||||
|
||||
let hovered = if let Some(mouse_pos) = self.input.mouse_pos {
|
||||
if rect.contains(mouse_pos) {
|
||||
let is_something_else_active =
|
||||
memory.active_id.is_some() && memory.active_id != interaction_id;
|
||||
|
||||
!is_something_else_active && layer == memory.layer_at(mouse_pos)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
};
|
||||
let active = if interaction_id.is_some() {
|
||||
if hovered && self.input.mouse_clicked {
|
||||
memory.active_id = interaction_id;
|
||||
}
|
||||
memory.active_id == interaction_id
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
let clicked = hovered && self.input.mouse_released;
|
||||
|
||||
InteractInfo {
|
||||
rect,
|
||||
hovered,
|
||||
clicked,
|
||||
active,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Data {
|
||||
pub fn style_ui(&self, region: &mut Region) {
|
||||
let mut style = self.style();
|
||||
style.ui(region);
|
||||
self.set_style(style);
|
||||
}
|
||||
}
|
||||
|
||||
/// Show a pop-over window
|
||||
pub fn show_popup<F>(data: &Arc<Data>, window_pos: Vec2, add_contents: F)
|
||||
pub fn show_popup<F>(ctx: &Arc<Context>, window_pos: Vec2, add_contents: F)
|
||||
where
|
||||
F: FnOnce(&mut Region),
|
||||
{
|
||||
let layer = Layer::Popup;
|
||||
let where_to_put_background = data.graphics.lock().unwrap().layer(layer).len();
|
||||
let where_to_put_background = ctx.graphics.lock().unwrap().layer(layer).len();
|
||||
|
||||
let style = data.style();
|
||||
let style = ctx.style();
|
||||
let window_padding = style.window_padding;
|
||||
|
||||
let mut contents_region = Region {
|
||||
data: data.clone(),
|
||||
ctx: ctx.clone(),
|
||||
layer: Layer::Popup,
|
||||
style,
|
||||
id: Default::default(),
|
||||
|
@ -217,7 +112,7 @@ where
|
|||
align: Align::Min,
|
||||
cursor: window_pos + window_padding,
|
||||
bounding_size: vec2(0.0, 0.0),
|
||||
available_space: vec2(data.input.screen_size.x.min(350.0), std::f32::INFINITY), // TODO: popup/tooltip width
|
||||
available_space: vec2(ctx.input.screen_size.x.min(350.0), std::f32::INFINITY), // TODO: popup/tooltip width
|
||||
};
|
||||
|
||||
add_contents(&mut contents_region);
|
||||
|
@ -230,7 +125,7 @@ where
|
|||
|
||||
let rect = Rect::from_min_size(window_pos, outer_size);
|
||||
|
||||
let mut graphics = data.graphics.lock().unwrap();
|
||||
let mut graphics = ctx.graphics.lock().unwrap();
|
||||
let graphics = graphics.layer(layer);
|
||||
graphics.insert(
|
||||
where_to_put_background,
|
||||
|
|
|
@ -7,6 +7,7 @@ extern crate serde;
|
|||
extern crate serde_derive;
|
||||
|
||||
pub mod color;
|
||||
mod context;
|
||||
mod emigui;
|
||||
pub mod example_app;
|
||||
mod font;
|
||||
|
@ -26,6 +27,7 @@ mod window;
|
|||
pub use {
|
||||
crate::emigui::Emigui,
|
||||
color::Color,
|
||||
context::Context,
|
||||
fonts::{FontDefinitions, Fonts, TextStyle},
|
||||
layers::*,
|
||||
layout::{Align, Id},
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{font::TextFragment, layout::*, widgets::*, *};
|
|||
/// with a type of layout (horizontal or vertical).
|
||||
/// TODO: make Region a trait so we can have type-safe HorizontalRegion etc?
|
||||
pub struct Region {
|
||||
pub(crate) data: Arc<Data>,
|
||||
pub(crate) ctx: Arc<Context>,
|
||||
|
||||
/// Where to put the graphics output of this Region
|
||||
pub(crate) layer: Layer,
|
||||
|
@ -39,7 +39,7 @@ impl Region {
|
|||
/// Can be used for free painting.
|
||||
/// NOTE: all coordinates are screen coordinates!
|
||||
pub fn add_paint_cmd(&mut self, paint_cmd: PaintCmd) {
|
||||
self.data
|
||||
self.ctx
|
||||
.graphics
|
||||
.lock()
|
||||
.unwrap()
|
||||
|
@ -48,7 +48,7 @@ impl Region {
|
|||
}
|
||||
|
||||
pub fn add_paint_cmds(&mut self, mut cmds: Vec<PaintCmd>) {
|
||||
self.data
|
||||
self.ctx
|
||||
.graphics
|
||||
.lock()
|
||||
.unwrap()
|
||||
|
@ -61,16 +61,16 @@ impl Region {
|
|||
&self.style
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &Arc<Data> {
|
||||
&self.data
|
||||
pub fn ctx(&self) -> &Arc<Context> {
|
||||
&self.ctx
|
||||
}
|
||||
|
||||
pub fn input(&self) -> &GuiInput {
|
||||
self.data.input()
|
||||
self.ctx.input()
|
||||
}
|
||||
|
||||
pub fn fonts(&self) -> &Fonts {
|
||||
&*self.data.fonts
|
||||
&*self.ctx.fonts
|
||||
}
|
||||
|
||||
pub fn width(&self) -> f32 {
|
||||
|
@ -124,7 +124,7 @@ impl Region {
|
|||
);
|
||||
|
||||
let open = {
|
||||
let mut memory = self.data.memory.lock().unwrap();
|
||||
let mut memory = self.ctx.memory.lock().unwrap();
|
||||
if interact.clicked {
|
||||
if memory.open_foldables.contains(&id) {
|
||||
memory.open_foldables.remove(&id);
|
||||
|
@ -194,7 +194,7 @@ impl Region {
|
|||
{
|
||||
let indent = vec2(self.style.indent, 0.0);
|
||||
let mut child_region = Region {
|
||||
data: self.data.clone(),
|
||||
ctx: self.ctx.clone(),
|
||||
layer: self.layer,
|
||||
style: self.style,
|
||||
id: self.id,
|
||||
|
@ -212,7 +212,7 @@ impl Region {
|
|||
/// Return a sub-region relative to the parent
|
||||
pub fn relative_region(&mut self, rect: Rect) -> Region {
|
||||
Region {
|
||||
data: self.data.clone(),
|
||||
ctx: self.ctx.clone(),
|
||||
layer: self.layer,
|
||||
style: self.style,
|
||||
id: self.id,
|
||||
|
@ -254,7 +254,7 @@ impl Region {
|
|||
F: FnOnce(&mut Region),
|
||||
{
|
||||
let mut child_region = Region {
|
||||
data: self.data.clone(),
|
||||
ctx: self.ctx.clone(),
|
||||
layer: self.layer,
|
||||
style: self.style,
|
||||
id: self.id,
|
||||
|
@ -302,7 +302,7 @@ impl Region {
|
|||
|
||||
let mut columns: Vec<Region> = (0..num_columns)
|
||||
.map(|col_idx| Region {
|
||||
data: self.data.clone(),
|
||||
ctx: self.ctx.clone(),
|
||||
layer: self.layer,
|
||||
style: self.style,
|
||||
id: self.make_child_id(&("column", col_idx)),
|
||||
|
@ -337,7 +337,7 @@ impl Region {
|
|||
pub fn reserve_space(&mut self, size: Vec2, interaction_id: Option<Id>) -> InteractInfo {
|
||||
let pos = self.reserve_space_without_padding(size + self.style.item_spacing);
|
||||
let rect = Rect::from_min_size(pos, size);
|
||||
self.data.interact(self.layer, rect, interaction_id)
|
||||
self.ctx.interact(self.layer, rect, interaction_id)
|
||||
}
|
||||
|
||||
/// Reserve this much space and move the cursor.
|
||||
|
@ -438,7 +438,7 @@ impl Region {
|
|||
clicked: interact.clicked,
|
||||
active: interact.active,
|
||||
rect: interact.rect,
|
||||
data: self.data.clone(),
|
||||
ctx: self.ctx.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -124,7 +124,7 @@ impl Texture {
|
|||
|
||||
if let Some(mouse_pos) = region.input().mouse_pos {
|
||||
if interact.hovered {
|
||||
show_popup(region.data(), mouse_pos, |region| {
|
||||
show_popup(region.ctx(), mouse_pos, |region| {
|
||||
let zoom_rect = region.reserve_space(vec2(128.0, 128.0), None).rect;
|
||||
let u = remap_clamp(
|
||||
mouse_pos.x,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use crate::{
|
||||
layout::{make_id, Data, Direction},
|
||||
layout::{make_id, Direction},
|
||||
widgets::Label,
|
||||
*,
|
||||
};
|
||||
|
@ -24,13 +24,13 @@ impl Window {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn show<F>(self, data: Arc<Data>, add_contents: F)
|
||||
pub fn show<F>(self, ctx: &Arc<Context>, add_contents: F)
|
||||
where
|
||||
F: FnOnce(&mut Region),
|
||||
{
|
||||
let id = make_id(&self.title);
|
||||
|
||||
let mut state = data.memory.lock().unwrap().get_or_create_window(
|
||||
let mut state = ctx.memory.lock().unwrap().get_or_create_window(
|
||||
id,
|
||||
Rect::from_min_size(
|
||||
vec2(400.0, 200.0), // TODO
|
||||
|
@ -39,13 +39,13 @@ impl Window {
|
|||
);
|
||||
|
||||
let layer = Layer::Window(id);
|
||||
let where_to_put_background = data.graphics.lock().unwrap().layer(layer).len();
|
||||
let where_to_put_background = ctx.graphics.lock().unwrap().layer(layer).len();
|
||||
|
||||
let style = data.style();
|
||||
let style = ctx.style();
|
||||
let window_padding = style.window_padding;
|
||||
|
||||
let mut contents_region = Region {
|
||||
data: data.clone(),
|
||||
ctx: ctx.clone(),
|
||||
layer: Layer::Popup,
|
||||
style,
|
||||
id: Default::default(),
|
||||
|
@ -53,7 +53,7 @@ impl Window {
|
|||
align: Align::Min,
|
||||
cursor: state.rect.min() + window_padding,
|
||||
bounding_size: vec2(0.0, 0.0),
|
||||
available_space: vec2(data.input.screen_size.x.min(350.0), std::f32::INFINITY), // TODO: window.width
|
||||
available_space: vec2(ctx.input.screen_size.x.min(350.0), std::f32::INFINITY), // TODO: window.width
|
||||
};
|
||||
|
||||
// Show top bar:
|
||||
|
@ -69,7 +69,7 @@ impl Window {
|
|||
|
||||
state.rect = Rect::from_min_size(state.rect.min(), outer_size);
|
||||
|
||||
let mut graphics = data.graphics.lock().unwrap();
|
||||
let mut graphics = ctx.graphics.lock().unwrap();
|
||||
let graphics = graphics.layer(layer);
|
||||
graphics.insert(
|
||||
where_to_put_background,
|
||||
|
@ -84,12 +84,12 @@ impl Window {
|
|||
},
|
||||
);
|
||||
|
||||
let interact = data.interact(layer, state.rect, Some(id));
|
||||
let interact = ctx.interact(layer, state.rect, Some(id));
|
||||
if interact.active {
|
||||
state.rect = state.rect.translate(data.input().mouse_move);
|
||||
state.rect = state.rect.translate(ctx.input().mouse_move);
|
||||
}
|
||||
|
||||
let mut memory = data.memory.lock().unwrap();
|
||||
let mut memory = ctx.memory.lock().unwrap();
|
||||
if interact.active || interact.clicked {
|
||||
memory.move_window_to_top(id);
|
||||
}
|
||||
|
|
|
@ -92,7 +92,7 @@ fn main() {
|
|||
emigui.ui(&mut region);
|
||||
|
||||
// TODO: Make it simpler to show a window
|
||||
Window::new("Test window").show(region.data().clone(), |region| {
|
||||
Window::new("Test window").show(region.ctx(), |region| {
|
||||
region.add(label!("Grab the window and move it around!"));
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in a new issue