emilk / egui Goto Github PK
View Code? Open in Web Editor NEWegui: an easy-to-use immediate mode GUI in Rust that runs on both web and native
Home Page: https://www.egui.rs/
License: Apache License 2.0
egui: an easy-to-use immediate mode GUI in Rust that runs on both web and native
Home Page: https://www.egui.rs/
License: Apache License 2.0
Egui currently ships with built-in fonts and (as far as I could see) there's no way for the library user to switch those out.
Font customisation is done via ctx.set_fonts
which accepts a FontDefinitions
. But that requires a FontFamily
which is an enum containing the hardcoded fonts and a no way to change them.
Would bringing your own font be within Egui's scope? The built-in fonts are great for e.g. debugging, level editor etc. UIs, but for a user-facing one (e.g. in-game menu, windows) the fonts often need to match the look & feel of the game.
If this is welcome, I'll be happy to work on it (albeit slowly) and follow any design considerations you might have.
My initial thought is adding a third variant FontFamily::Custom(u32)
and provide a way to register a new font e.g.: impl Context { pub add_custom_font(font: &[u8]) -> u8; }
Where the function and the enum variant would both use a font ID (or maybe a hashed name) to support multiple fonts at the same time.
For reference, this is a commit I'm maintaining in my Egui fork to be able to use a (single) custom font:
And it's used like this in my game:
let font_definitions = {
use egui::paint::fonts::{FontFamily, TextStyle};
let family = FontFamily::Mononoki;
let mut def = egui::paint::FontDefinitions::default();
def.fonts.insert(TextStyle::Body, (family, font_size_px));
def.fonts.insert(TextStyle::Button, (family, font_size_px));
def.fonts.insert(TextStyle::Heading, (family, font_size_px));
def.fonts
.insert(TextStyle::Monospace, (family, font_size_px));
def
};
ctx.set_fonts(font_definitions);
I have been exploring the Immediate Mode GUI concept, and I found a few demos for web applications, including emilk/egui.
One thing I noticed is that the CPU usage by Firefox skyrockets when I play with those demos, unliked with any other pages written with using HTML/CSS/JavaScript.
Q1. Why it happens and is this expected?
Q2. What happens if most of the websites I open in 50+ tabs use the Immediate Mode GUI - will Firefox and OS struggle?
Any input appreciated.
Many thanks,
Anton
I am trying to write my own main loop for egui_glium
integration for a project that required more control over it.
I hit a snag, the input_to_egui
function takes the reference to the GliumInputState
struct (which itself is public) but since I cannot access its private raw
field I cannot use it for its intended purpose outside of the egui_glium
crate.
For reference, I am writing a front end for my Chip-8 interpreter, and it requires access to the keyboard events (which I think cannot be fetched through egui
or the integration context) and other events for accurate timing.
Hey,
I've been having problems sharing the repaint signal between threads. It seems the problem is that Arc requires that it wraps types that implement send and sync. Though I am new enough to rust that it could also be my fault.
The following code (in the ui function) will cause the error.
let repaint_signal = integration_context.repaint_signal.clone();
let thread = std::thread::spawn(|| {
repaint_signal.request_repaint();
});
thread.join();
I'm happy to fix this issue if the problem wasn't caused by my own lack of understanding.
As discussed here, egui_glium
currently only supports GLSL 1.40, which apparently precludes it from working on Windows 7.
The fix would probably include using the glium::program!
macro.
Vimium if you aren't already familiar is a plug-in that listens for particular keypresses so that you can navigate links in your web browser just using the keyboard. Normally it plays well with web forms, only intercepting keypresses when a form isn't selected. However when I click inside the input box in the demo, all of my keypresses are still being captured by Vimium, so I can't actually type anything. It seems there is some "you are in an editing field" state that doesn't get communicated back to the browser. I'm not sure if you would consider fixing this in scope but I could see it being a barrier for using emigui for non-game web apps, where plugins may be relevant for accessibility. I use Vimium so I can navigate webpages with a finite speech recognition command set (only letters like "A", "F" etc need to be recognized to be able to verbally click around). My guess is the current state of web assembly API standardization would make fixing this a horror show but I thought I'd mention it in case it's not ;)
I think this is a bug.
Hi,
While testing the WGPU render backend and Winit platform crates I created, I get following odd error:
Some elments keep expanding once they are visible. In the screenshot you can see that the drawing area of the painting widget expands and keeps expanding. If you scroll down until the end of the drawing area is visible, the expanding will stop.
Do you maybe know where I could start debugging this? I have a hard time figuring out how the backend or the windowing integration could cause this behavior.
The code for reproducing this problem can be found here can be found in this example project.
With imgui-rs
, the API is pretty much the same for everything.
WidgetType::new().param(args).build(&ui, || closure executed if widget is open for example for windows or buttons)
(Actually, that's not entirely true, small widgets use ifs but their API is moving toward this version by version)
However while looking through egui
's source code, I've seen 4 ways the API is declared.
menu
does everything in the constructor:
menu::menu(ui, "Windows", |ui| { ... })
Button
uses ifs and ui.add
:
if ui.add(Button::new("Clear memory")).clicked { ... }
Windows
looks a bit like imgui:
Window::new("Examples").show(ctx, |ui| { ... })
collapsing
comes directly from the ui object:
ui.collapsing("About Egui", |ui| { ... })
4 different ways of doing control flow for the same idea, which makes it a bit awkward to use.
PS: I'm doing a lot of issues but it's because I'm seriously considering the crate for my project and there's a few quirks before I'm thinking of moving to it. I absolutely admire the amount of work you've put into it !
It'd be very nice to be able to run an action when something is dropped in the area, is that possible?
This leads to very jarring movements since while dragging a scrollbar you often move the mouse slightly outside the scrollbar handle. The issue also happens if you move the mouse quickly even in the same direction as the scrollbar.
Either ctl-scrollwheel or ctl-shift-+ needs to work to magnify the UI as a whole. This is pretty much a necessity both for accessibility (my vision is terrible) and for hi-DPI screens (I'm using a 4K monitor). If I understand correctly, the decision to work in screen coordinates may make this hard: however, it's a must-have for any application that is intended for widespread web deployment.
I cannot find a way to access the x, y, width and height of a window. I derived my Node
struct from Window
and I'd like to be able to put things inside relatively to these current parameters.
(sorry I'm a bit learning rust with this project, then it might be a dumb question)
The left edge of the multiline text widget is always invisible if I enable the glScissor with a clip rect from the egui.
clip_rect.min.x
is always +2 from the valid value. The valid value is calculated from vertices for the rendering of a job.
My code to rendering the UI is very similar to egui_glium's painter.
It is really a bug or I am stupid?
OS: Win10 x64
Rust: 1.49
OS: MacOS Catalina
Browser: Safari 13.1.3
When focusing text input, cmd+arrow hotkey not only moves cursor to beginning/end of input (as expected), but also switches tab to prev/next, which is undesirable.
I was trying to create a plugin for https://github.com/bevyengine/bevy and that would require a wgpu backend I think. I'd be interested in working on this, but I have no idea where to start.
Hello,
It appears that the Image
widget does not have a "sense" hooked up and therefore doesn't listen for button clicks.
At least, that's how it appeared after quickly comparing Image
to Button
implementations.
I'm not sure if this is intentional and I should wrap the image in some other container that detects clicks... or if this is indeed a bug / missing functionality.
What I'm trying to do is implement a simple Tile picker/chooser, and so I was looking to just show the image, detect clicks on it, get the mouse cursor offset into the widget, do the math, and pick the tile. I didn't see any other obvious way of doing it with the current EGUI types, so I went this route.
Thanks!
Hello,
I noticed that in the miniquad web demo https://not-fl3.github.io/miniquad-samples/emigui.html the text is blurred.
I tested it on both Firefox and Brave (chromium based) and in both cases the text is rendered in the same way.
Here is a screenshot with Firefox on the left and Brave on the right : https://imgur.com/LIdPU6d
The text become clear when I zoom out (at 67% zoom on brave the text is clear).
But the Egui feature demo https://emilk.github.io/emigui/index.html is rendering sharp text : https://imgur.com/pPRb14W
I noticed that imgur heavily rezises/compresses the screenshots I linked, so the blurriness of the text is not so clear but I can send them by email if you want (the text really is blurry).
I am on Linux 64bit (Manjaro) with a RTX 2080.
Thank you for your awesome work, I wish you the best of luck with this project 👍
I could be wrong about the following. I'm just starting to learn Rust, so I could have misunderstood something. I believe this is the only way to change style elements given the current API:
let mut style = ui.style().clone();
style.item_spacing = egui::vec2(x, y);
ui.set_style(style);
The ui
's style
member is private and the ui.style()
method returns an immutable reference. So the only way to change a single style element is to clone the whole struct out, make the change, and pass ownership back into the ui
. This is awkward to implement, and forces needless copies. It's also redundant with the clone that happens when a child ui is created. Touching a given ui's style won't affect global style settings.
The patterns in the Style::ui
widget hints that some kind of public access is safe and may have been intended, but I can't find a pathway for it.
The demo for egui_web is very overwhelming when using egui/egui_web for the first time, the one used for the Glium one is much more readable and understand able for the first time someone would look at it.
I'm working on a Nodal tool using your crate. To make links between them, I need to draw a line between two points. Is this currently possible?
Hi,
I'm working on an app that has a callback field which should be ignored during saving/loading the app state:
#[derive(serde::Deserialize, serde::Serialize)]
pub struct MyApp {
content: String,
#[serde(skip)]
callback: Option<Arc<Mutex<dyn FnMut(&String)>>>,
}
Nonetheless, when I configure the app with the callback before calling egui_glium::run()
, the callback is overwritten when "load" is called.
This happened after the latest update ... before that, the app state was re-loaded manually before calling run()
. Not sure if there's a good way to handle this ...
Glium is a convenient choice, but is a rather big dependency which compiles slowly, and uses build.rs
. It is also no longer actively maintained.
The ideal choice for compiling Egui natively would be something simple that compiles quickly. I'm not sure there is such an alternative though.
One alternative worth investigating is pure glutin (which Glium depend on). It is a bit lower level compared to Glium, and requires use of unsafe
, but it looks easy enough to use: https://gist.github.com/matthewjberger/9da00592b472b50ec1e6b3238719264b
Would love to have an example on how to fetch resources from using fetch or similar.
Preferably by using web-sys or some built in mechanic :)
... or it is still too early?
Nothing egui-related in the works yet but I am asking since I plan to work with your lib for my project.
I'm trying to list all the files in the combo box (as buttons). This will over spill the window area because the drop down is bigger than the window height as can be seen above. Since combo box itself doesn't seem to support scrolling out of the box, I thought of adding a ScrollArea within the combo box (since it's a container presumably).
This kind of works, in that I can scroll by moving the mouse up and down, but couple of things are broken:
Frankly, I expected the combo box to automatically take care of this. That is, it has a scroll area built into it, so that if the item dimensions > default combo box dimension, the comb box shows appropriate scroll bars (vertical/horizontal).
Failing the above, what would be the idiomatic way to do this in egui? I've included the source code for how I'm doing things now:
&egui::Window::new("Chipper")
.fixed_pos(Pos2::new(0f32,0f32))
//.default_size(vec2(WINDOW_WIDTH as f32, WINDOW_HEIGHT as f32))
.resizable(false)
.collapsible(false)
.show(&mut egui_ctx, |ui| {
if !is_paused {
ui.label(format!("FPS: {} ({} ms/frame)", fps, avg_frame_time));
}
else {
ui.label(format!("PAUSED"));
}
ui.add(Image::new(chip8_tex_id, vec2((CHIP8_DISPLAY_WIDTH * DISPLAY_SCALE) as f32, (CHIP8_DISPLAY_HEIGHT * DISPLAY_SCALE) as f32)));
ui.label("");
combo_box_with_label(ui, "ROM files", selected_rom, |ui| {
ScrollArea::from_max_height(50f32).show(ui, |ui| {
for (f, _p) in &rom_files {
if ui.button(f).clicked {
selected_rom = f;
chip8.boot_rom(rom_files.get(selected_rom).expect("No rom files to load!")).expect("Failed to load rom!");
};
}
})
});
//There is probably a better way to add line breaks in egui....
ui.label("");
if ui.checkbox(&mut use_vy_for_shift_operations, "Use Vy for shift operations").clicked {
chip8.shift_using_vy = use_vy_for_shift_operations;
};
if ui.checkbox(&mut increment_i_on_ld_operations, "Increment I on LD Vx operations").clicked {
chip8.increment_i_on_ld = increment_i_on_ld_operations;
};
ui.label("");
ui.label("ESC = Pause/Resume. F2 = Reset.");
});
rom_files is a HashMap<String, String>.
I hope I'm not missing something blindingly obvious... :S
When selecting and holding on a widget, the window sometimes moves with it.
Maybe this is the expected behavior, but it's very frustrating when you just want to click on a widget and accidentally move the mouse.
Same goes for scrolling in the window.
Pressing tab in a TextEdit box should move the focus to the next TextEdit. However, in egui_web
the focus is instead moved to the browser (e.g. the url bar).
As pointed out by @norcalli in 861573c#r44948551
Egui currently handles text layout and cursors using character boundaries, but using graphemes is the better approach in the long run.
Hi!
I'm trying to integrate egui into a wasm-bindgen app that also needs to draw some other geometry. Basically my app tries to do the job of your AppRunner
class also using egui_web
, but also rendering other things, and doing other things with the input events, etc.
For some reason all my widgets end up looking like this though:
If I use something like SpectorJS I can debug the draw call and see that drawElements is called with the font atlas texture bound to sampler 0, which is why the lines look strange: I think it's drawing them with the texture atlas bound? It is also likely the same thing that is preventing the actual text from showing. I wonder if you know what could be wrong, of if there's anything I'm missing?
Here is how I first setup the egui state:
let mut backend = egui_web::WebBackend::new("mycanvas").expect("Failed to make a web backend for egui");
let mut web_input: WebInput = Default::default();
And here is how I draw every frame:
ctx.clear_color(0.1, 0.1, 0.2, 1.0);
ctx.clear(GL::COLOR_BUFFER_BIT | GL::DEPTH_BUFFER_BIT);
let raw_input = web_input.new_frame();
let ui = backend.begin_frame(raw_input);
let mut s = String::from("test");
let mut value = 0.0;
egui::Window::new("Debug").show(&ui.ctx(), |ui| {
ui.label(format!("Hello, world {}", 123));
if ui.button("Save").clicked {
log::info!("Save!");
}
ui.text_edit(&mut s);
ui.add(egui::Slider::f32(&mut value, 0.0..=1.0).text("float"));
});
let (output, paint_jobs) = backend.end_frame().unwrap();
backend.paint(paint_jobs).expect("Failed to paint!");
ctx.viewport(
0,
0,
canvas_width_on_screen as i32,
canvas_height_on_screen as i32,
);
cube.render(
&context,
(js_sys::Date::now() - start_millis) as f32,
curr_state.canvas_width,
curr_state.canvas_height,
);
This should be working right? Or is there some magical step that AppRunner
does that I overlooked?
Thanks!
Hello,
I'm trying to display a sort of table/spreadsheet with a label and a dragvalue next to it per row, by doing this:
ui.columns(2, |cols| {
cols[0].label("var_a: ");
cols[1].add(egui::DragValue::f32(&mut var_a));
});
ui.columns(2, |cols| {
cols[0].label("var_b: ");
cols[1].add(egui::DragValue::f32(&mut var_b));
});
The problem is that when I drag the var_a
DragValue, the var_b
DragValue also simultaneously responds, and both change at the same time. Am I doing something wrong?
Thanks!
There is currently no way to disable widgets (with few exceptions). One potential way to disable widgets would be like this:
ui.enabled(false, |ui| {
ui.checkbox(...);
ui.add(Slider::f32(...)));
});
where everything in the closure would be non-interactive (except perhaps for on_hover_text
tooltips), and have a grayed out disabled look to them.
Hi,
I'm currently implementing a wgpu based backend crate and a winit based platform crate and would like to use the DemoApp in my simple example.
Since I need to call the ui()
function on the DemoApp
, I need create a DemoEnvironment
struct, which is marked pub
but is not exported. Could you maybe export this struct?
I have the currently scenario:
that i want to control the scroll when moving the selected line keeping the focus at the active line.
This is what I got trying to achieve this:
Currently the offset state that controls the scroll position is not public. I tried creating an simple public fn to set the offset manually, but since we can't get the Id of the ScrollArea.source_id
, we can't change the state. We only have access to the Id of the child_ui (Prepared.content_ui
) inside the show()
function.
Also since the Prepared state is passed from the begin()
to the end()
, we can't change it inside the add_contents()
. We would need to get the state from the memory again in the end()
if we changed it in the add_contents()
.
Maybe the way out is to pass the Id used to save the state in the return of the show: ScrollArea.show() -> ScrollResponse<R>
similar to the CollapsingResponse.
There is probably better solution for this
Is it possible to run webworkers in egui?
I am trying to add a slider and I just noticed they have an input box where the value is displayed.
However, this doesn't seem to always show.
Using this code it is visible:
craft_to_columns[1].add(
egui::Slider::u32(&mut workbench_data.craft_to_count, 1..=20)
.text("Craft to"),
);
Setting the text to ""
makes it dissapear:
It's also worth noting that the first example, the "Craft to"
doesn't expand the column width either (you can see just the C
).
winit is a very popular windowing crate, it would be easier to jump into emigui if it existed.
I'm looking for a way to load fonts dynamically, but I don't know how to implement it
Hi,
it seems like the Tab key is not captured in the text edit widget, could that be ?
Like, when I put some debug output in the event handling loop, it seems like there's no event emitted at all ... just the outer frame flickers ...
Is there a way to capture the tab key ?
Best,
N
I decided to test it after I saw capslock made an event shown as Text("CapsLock") in the raw state window while mashing the keyboard
Hello and Happy upcoming New Year!
I am doing integration between EGUI and our game engine Dotrix. We don't have our UI crate yet and I am about to use EGUI for an editor for now. Results looks like this so far
My question if there is already some widget gallery maybe as an image with widgets and their names? Or should I just refer this list https://docs.rs/egui/0.6.0/egui/widgets/index.html ?
I'd like to integrate egui with my app (currently in development and in the process of picking a UI lib). It uses SDL2 for canvas, events, windows, etc.
Do you know of any issues running those two together (on Win, macOS, Linux)?
It would be great to have support for keyboard only navigation (i.e a concept of focused widget and the ability to move focus to another one) that would allow "tab" key for example to move to the next widget and "return" would act as press, etc.
This in return would make it quite easy to add gamepad support as it would just behave as a subset of a regular keyboard.
Some of these questions may be straightforward but I've never done in game ui or used imgui, and I'm working on my first rust project, so it's all new to me.
I've been reading through the example code try to get a handle on how things work. I see a lot of these sorts of show calls in the example: .show(ui, |ui| self.painting.ui(ui));
Why take the ui object and also a lambda taking a ui object? I started digging to try and see if the ui just gets passed in later but it looks like child ui's are getting passed in?
I guess more generally if the rendering isn't immediate mode, is each frame building one big call-list/vertex-buffer/etc from scratch, or is it somehow figuring out what has or hasn't changed between frames and only sending stuff to the gpu that's different?
Why is a bunch of the core app state serializable? For example the ExampleApp struct. I noticed state seems to be preserved across refreshes if you only manipulate the Examples window -- but if you open any other window than it resets the whole gui to its original state on refresh -- and there's an every frame call to save_memory
, but it looks like ultimately that is is only going to save the Memory
struct, so I'm not sure how that would interact with other application state.
This shows a blank page on Edge: https://emilk.github.io/egui/index.html
Should probably at least show some kind of error message if it isn't supported on Edge (or better yet, fix whatever prevents it from working).
After setting up an app using https://github.com/emilk/egui_template it seems that I am limited to the input data that egui itself uses (https://docs.rs/egui/0.6.0/egui/enum.Event.html). Is this an intentional limitation where I need to "eject" from using the App
trait and setup things manually if I want more keybindings (ie ctrl-P)?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.