Add support for hyperlinks
This commit is contained in:
parent
25b06a6ff0
commit
b39555bb23
18 changed files with 211 additions and 55 deletions
17
Cargo.lock
generated
17
Cargo.lock
generated
|
@ -187,6 +187,7 @@ dependencies = [
|
|||
"emigui 0.1.0",
|
||||
"emigui_glium 0.1.0",
|
||||
"glium 0.24.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"webbrowser 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -827,6 +828,20 @@ dependencies = [
|
|||
"wasm-bindgen 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "webbrowser"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "widestring"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.8"
|
||||
|
@ -994,6 +1009,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
"checksum wayland-scanner 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3828c568714507315ee425a9529edc4a4aa9901409e373e9e0027e7622b79e"
|
||||
"checksum wayland-sys 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)" = "520ab0fd578017a0ee2206623ba9ef4afe5e8f23ca7b42f6acfba2f4e66b1628"
|
||||
"checksum web-sys 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)" = "2d6f51648d8c56c366144378a33290049eafdd784071077f6fe37dae64c1c4cb"
|
||||
"checksum webbrowser 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "97d468a911faaaeb783693b004e1c62e0063e646b0afae5c146cd144e566e66d"
|
||||
"checksum widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effc0e4ff8085673ea7b9b2e3c73f6bd4d118810c9009ed8f1e16bd96c331db6"
|
||||
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-util 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fa515c5163a99cc82bab70fd3bfdd36d827be85de63737b40fcef2ce084a436e"
|
||||
|
|
|
@ -196,12 +196,20 @@ function _assertClass(instance, klass) {
|
|||
/**
|
||||
* @param {State} state
|
||||
* @param {string} raw_input_json
|
||||
* @returns {string}
|
||||
*/
|
||||
__exports.run_gui = function(state, raw_input_json) {
|
||||
_assertClass(state, State);
|
||||
var ptr0 = passStringToWasm0(raw_input_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
var len0 = WASM_VECTOR_LEN;
|
||||
wasm.run_gui(state.ptr, ptr0, len0);
|
||||
try {
|
||||
_assertClass(state, State);
|
||||
var ptr0 = passStringToWasm0(raw_input_json, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
|
||||
var len0 = WASM_VECTOR_LEN;
|
||||
wasm.run_gui(8, state.ptr, ptr0, len0);
|
||||
var r0 = getInt32Memory0()[8 / 4 + 0];
|
||||
var r1 = getInt32Memory0()[8 / 4 + 1];
|
||||
return getStringFromWasm0(r0, r1);
|
||||
} finally {
|
||||
wasm.__wbindgen_free(r0, r1);
|
||||
}
|
||||
};
|
||||
|
||||
function isLikeNone(x) {
|
||||
|
|
Binary file not shown.
|
@ -56,8 +56,27 @@
|
|||
if (g_wasm_app === null) {
|
||||
g_wasm_app = wasm_bindgen.new_webgl_gui("canvas", pixels_per_point());
|
||||
}
|
||||
wasm_bindgen.run_gui(g_wasm_app, JSON.stringify(input));
|
||||
|
||||
let output = JSON.parse(wasm_bindgen.run_gui(g_wasm_app, JSON.stringify(input)));
|
||||
// console.log(`output: ${JSON.stringify(output)}`);
|
||||
document.body.style.cursor = from_emigui_cursor(output.cursor_icon);
|
||||
if (output.open_url) {
|
||||
window.open(output.open_url, "_self");
|
||||
}
|
||||
}
|
||||
|
||||
function from_emigui_cursor(cursor) {
|
||||
if (cursor == "no_drop") { return "no-drop"; }
|
||||
else if (cursor == "not_allowed") { return "not-allowed"; }
|
||||
else if (cursor == "resize_nw_se") { return "nwse-resize"; }
|
||||
else if (cursor == "pointing_hand") { return "pointer"; }
|
||||
// TODO: more
|
||||
else {
|
||||
// default, help, pointer, progress, wait, cell, crosshair, text, alias, copy, move, grab, grabbing,
|
||||
return cursor;
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
var g_mouse_pos = null;
|
||||
var g_mouse_down = false;
|
||||
|
|
|
@ -19,6 +19,7 @@ This is the core library crate Emigui. It is fully platform independent without
|
|||
* [x] Scroll-wheel input
|
||||
* [x] Drag background to scroll
|
||||
* [ ] Kinetic scrolling
|
||||
* [x] Add support for clicking links
|
||||
* [ ] Menu bar (File, Edit, etc)
|
||||
* [ ] One-line TextField
|
||||
* [ ] Clipboard copy/paste
|
||||
|
@ -28,8 +29,7 @@ This is the core library crate Emigui. It is fully platform independent without
|
|||
|
||||
### Web version:
|
||||
* [x] Scroll input
|
||||
* [ ] Add support for clicking links
|
||||
* [ ] Change to resize cursor on hover
|
||||
* [x] Change to resize cursor on hover
|
||||
|
||||
### Animations
|
||||
Add extremely quick animations for some things, maybe 2-3 frames. For instance:
|
||||
|
@ -44,6 +44,7 @@ Add extremely quick animations for some things, maybe 2-3 frames. For instance:
|
|||
### Other
|
||||
* [ ] Generalize Layout so we can create grid layouts etc
|
||||
* [ ] Persist UI state in external storage
|
||||
* [ ] Pixel-perfect rendering (round positions to nearest pixel).
|
||||
* [ ] Build in a profiler which tracks which region in which window takes up CPU.
|
||||
* [ ] Draw as flame graph
|
||||
* [ ] Draw as hotmap
|
||||
|
|
|
@ -36,3 +36,4 @@ pub const BLACK: Color = srgba(0, 0, 0, 255);
|
|||
pub const RED: Color = srgba(255, 0, 0, 255);
|
||||
pub const GREEN: Color = srgba(0, 255, 0, 255);
|
||||
pub const BLUE: Color = srgba(0, 0, 255, 255);
|
||||
pub const LIGHT_BLUE: Color = srgba(140, 160, 255, 255);
|
||||
|
|
|
@ -4,18 +4,6 @@ use parking_lot::Mutex;
|
|||
|
||||
use crate::{layout::align_rect, *};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum CursorIcon {
|
||||
Default,
|
||||
ResizeNorthWestSouthEast,
|
||||
}
|
||||
|
||||
impl Default for CursorIcon {
|
||||
fn default() -> Self {
|
||||
CursorIcon::Default
|
||||
}
|
||||
}
|
||||
|
||||
/// Contains the input, style and output of all GUI commands.
|
||||
pub struct Context {
|
||||
/// The default style for new regions
|
||||
|
@ -25,8 +13,7 @@ pub struct Context {
|
|||
pub(crate) memory: Mutex<Memory>,
|
||||
pub(crate) graphics: Mutex<GraphicLayers>,
|
||||
|
||||
/// Set each frame to what the mouse cursor should look like.
|
||||
pub cursor_icon: Mutex<CursorIcon>,
|
||||
pub output: Mutex<Output>,
|
||||
|
||||
/// Used to debug name clashes of e.g. windows
|
||||
used_ids: Mutex<HashMap<Id, Pos2>>,
|
||||
|
@ -41,7 +28,7 @@ impl Clone for Context {
|
|||
input: self.input,
|
||||
memory: Mutex::new(self.memory.lock().clone()),
|
||||
graphics: Mutex::new(self.graphics.lock().clone()),
|
||||
cursor_icon: Mutex::new(self.cursor_icon.lock().clone()),
|
||||
output: Mutex::new(self.output.lock().clone()),
|
||||
used_ids: Mutex::new(self.used_ids.lock().clone()),
|
||||
}
|
||||
}
|
||||
|
@ -55,11 +42,16 @@ impl Context {
|
|||
input: Default::default(),
|
||||
memory: Default::default(),
|
||||
graphics: Default::default(),
|
||||
cursor_icon: Default::default(),
|
||||
output: Default::default(),
|
||||
used_ids: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Useful for pixel-perfect rendering
|
||||
pub fn round_to_pixel(&self, point: f32) -> f32 {
|
||||
(point * self.input.pixels_per_point).round() / self.input.pixels_per_point
|
||||
}
|
||||
|
||||
pub fn input(&self) -> &GuiInput {
|
||||
&self.input
|
||||
}
|
||||
|
@ -73,10 +65,13 @@ impl Context {
|
|||
}
|
||||
|
||||
// TODO: move
|
||||
pub fn new_frame(&mut self, gui_input: GuiInput) {
|
||||
pub fn begin_frame(&mut self, gui_input: GuiInput) {
|
||||
self.used_ids.lock().clear();
|
||||
self.input = gui_input;
|
||||
*self.cursor_icon.lock() = CursorIcon::Default;
|
||||
}
|
||||
|
||||
pub fn end_frame(&self) -> Output {
|
||||
std::mem::take(&mut self.output.lock())
|
||||
}
|
||||
|
||||
pub fn drain_paint_lists(&self) -> Vec<(Rect, PaintCmd)> {
|
||||
|
|
|
@ -32,7 +32,7 @@ impl Emigui {
|
|||
self.ctx.fonts.texture()
|
||||
}
|
||||
|
||||
pub fn new_frame(&mut self, new_input: RawInput) {
|
||||
pub fn begin_frame(&mut self, new_input: RawInput) {
|
||||
if !self.last_input.mouse_down || self.last_input.mouse_pos.is_none() {
|
||||
self.ctx.memory.lock().active_id = None;
|
||||
}
|
||||
|
@ -42,17 +42,17 @@ impl Emigui {
|
|||
|
||||
// TODO: avoid this clone
|
||||
let mut new_ctx = (*self.ctx).clone();
|
||||
new_ctx.new_frame(gui_input);
|
||||
new_ctx.begin_frame(gui_input);
|
||||
self.ctx = Arc::new(new_ctx);
|
||||
}
|
||||
|
||||
/// A region for the entire screen, behind any windows.
|
||||
pub fn background_region(&mut self) -> Region {
|
||||
let rect = Rect::from_min_size(Default::default(), self.ctx.input.screen_size);
|
||||
Region::new(self.ctx.clone(), Layer::Background, Id::background(), rect)
|
||||
pub fn end_frame(&mut self) -> (Output, PaintBatches) {
|
||||
let output = self.ctx.end_frame();
|
||||
let paint_batches = self.paint();
|
||||
(output, paint_batches)
|
||||
}
|
||||
|
||||
pub fn paint(&mut self) -> PaintBatches {
|
||||
fn paint(&mut self) -> PaintBatches {
|
||||
self.mesher_options.aa_size = 1.0 / self.last_input.pixels_per_point;
|
||||
let paint_commands = self.ctx.drain_paint_lists();
|
||||
let batches = mesh_paint_commands(&self.mesher_options, &self.ctx.fonts, paint_commands);
|
||||
|
@ -65,6 +65,14 @@ impl Emigui {
|
|||
batches
|
||||
}
|
||||
|
||||
/// A region for the entire screen, behind any windows.
|
||||
pub fn background_region(&mut self) -> Region {
|
||||
let rect = Rect::from_min_size(Default::default(), self.ctx.input.screen_size);
|
||||
Region::new(self.ctx.clone(), Layer::Background, Id::background(), rect)
|
||||
}
|
||||
}
|
||||
|
||||
impl Emigui {
|
||||
pub fn ui(&mut self, region: &mut Region) {
|
||||
region.collapsing("Style", |region| {
|
||||
region.add(Checkbox::new(
|
||||
|
|
|
@ -43,6 +43,11 @@ impl ExampleApp {
|
|||
region.add(label!(
|
||||
"Emigui is an experimental immediate mode GUI written in Rust."
|
||||
));
|
||||
|
||||
region.horizontal(Align::Min, |region| {
|
||||
region.add_label("Project home page:");
|
||||
region.add_hyperlink("https://github.com/emilk/emigui/");
|
||||
});
|
||||
});
|
||||
|
||||
CollapsingHeader::new("Widgets")
|
||||
|
|
|
@ -158,7 +158,7 @@ impl Font {
|
|||
(point * self.pixels_per_point).round() / self.pixels_per_point
|
||||
}
|
||||
|
||||
/// In points
|
||||
/// Height of one line of text. In points
|
||||
pub fn line_spacing(&self) -> f32 {
|
||||
self.scale_in_pixels / self.pixels_per_point
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ pub use {
|
|||
crate::emigui::Emigui,
|
||||
collapsing_header::CollapsingHeader,
|
||||
color::Color,
|
||||
context::{Context, CursorIcon},
|
||||
context::Context,
|
||||
fonts::{FontDefinitions, Fonts, TextStyle},
|
||||
id::Id,
|
||||
layers::*,
|
||||
|
|
|
@ -109,6 +109,10 @@ impl Region {
|
|||
.extend(cmds.drain(..).map(|cmd| (clip_rect, cmd)));
|
||||
}
|
||||
|
||||
pub fn round_to_pixel(&self, point: f32) -> f32 {
|
||||
self.ctx.round_to_pixel(point)
|
||||
}
|
||||
|
||||
/// Options for this region, and any child regions we may spawn.
|
||||
pub fn style(&self) -> &Style {
|
||||
&self.style
|
||||
|
@ -183,7 +187,7 @@ impl Region {
|
|||
|
||||
// draw a grey line on the left to mark the region
|
||||
let line_start = child_rect.min() - indent * 0.5;
|
||||
let line_start = line_start.round();
|
||||
let line_start = line_start.round(); // TODO: round to pixel instead
|
||||
let line_end = pos2(line_start.x, line_start.y + size.y - 8.0);
|
||||
self.add_paint_cmd(PaintCmd::Line {
|
||||
points: vec![line_start, line_end],
|
||||
|
@ -272,7 +276,7 @@ impl Region {
|
|||
Rect::from_min_max(pos, pos2(pos.x + column_width, self.desired_rect.bottom()));
|
||||
|
||||
Region {
|
||||
id: self.make_child_region_id(&("column", col_idx)),
|
||||
id: self.make_child_id(&("column", col_idx)),
|
||||
dir: Direction::Vertical,
|
||||
..self.child_region(child_rect)
|
||||
}
|
||||
|
@ -303,6 +307,10 @@ impl Region {
|
|||
self.add(Label::new(text))
|
||||
}
|
||||
|
||||
pub fn add_hyperlink(&mut self, url: impl Into<String>) -> GuiResponse {
|
||||
self.add(Hyperlink::new(url))
|
||||
}
|
||||
|
||||
pub fn collapsing<S, F>(&mut self, text: S, add_contents: F) -> GuiResponse
|
||||
where
|
||||
S: Into<String>,
|
||||
|
@ -365,7 +373,7 @@ impl Region {
|
|||
self.id.with(&Id::from_pos(self.cursor))
|
||||
}
|
||||
|
||||
pub fn make_child_region_id<H: Hash>(&self, child_id: &H) -> Id {
|
||||
pub fn make_child_id<H: Hash>(&self, child_id: &H) -> Id {
|
||||
self.id.with(child_id)
|
||||
}
|
||||
|
||||
|
|
|
@ -84,6 +84,28 @@ impl GuiInput {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Serialize)]
|
||||
pub struct Output {
|
||||
pub cursor_icon: CursorIcon,
|
||||
/// If set, open this url.
|
||||
pub open_url: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Serialize)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum CursorIcon {
|
||||
Default,
|
||||
/// Pointing hand, used for e.g. web links
|
||||
PointingHand,
|
||||
ResizeNwSe,
|
||||
}
|
||||
|
||||
impl Default for CursorIcon {
|
||||
fn default() -> Self {
|
||||
CursorIcon::Default
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize)]
|
||||
|
|
|
@ -59,6 +59,62 @@ impl Widget for Label {
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
pub struct Hyperlink {
|
||||
url: String,
|
||||
text: String,
|
||||
}
|
||||
|
||||
impl Hyperlink {
|
||||
pub fn new(url: impl Into<String>) -> Self {
|
||||
let url = url.into();
|
||||
Self {
|
||||
text: url.clone(),
|
||||
url,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for Hyperlink {
|
||||
fn add_to(self, region: &mut Region) -> GuiResponse {
|
||||
let color = color::LIGHT_BLUE;
|
||||
let text_style = TextStyle::Body;
|
||||
let id = region.make_child_id(&self.url);
|
||||
let font = ®ion.fonts()[text_style];
|
||||
let line_spacing = font.line_spacing();
|
||||
// TODO: underline
|
||||
let (text, text_size) = font.layout_multiline(&self.text, region.available_width());
|
||||
let interact = region.reserve_space(text_size, Some(id));
|
||||
if interact.hovered {
|
||||
region.ctx().output.lock().cursor_icon = CursorIcon::PointingHand;
|
||||
}
|
||||
if interact.clicked {
|
||||
region.ctx().output.lock().open_url = Some(self.url.clone());
|
||||
}
|
||||
|
||||
if interact.hovered {
|
||||
// Underline:
|
||||
for fragment in &text {
|
||||
let pos = interact.rect.min();
|
||||
let y = pos.y + fragment.y_offset + line_spacing;
|
||||
let y = region.round_to_pixel(y);
|
||||
let min_x = pos.x + fragment.min_x();
|
||||
let max_x = pos.x + fragment.max_x();
|
||||
region.add_paint_cmd(PaintCmd::Line {
|
||||
points: vec![pos2(min_x, y), pos2(max_x, y)],
|
||||
color,
|
||||
width: region.style().line_width,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
region.add_text(interact.rect.min(), text_style, text, Some(color));
|
||||
|
||||
region.response(interact)
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
pub struct Button {
|
||||
text: String,
|
||||
text_color: Option<Color>,
|
||||
|
@ -416,7 +472,7 @@ impl<'a> Widget for Slider<'a> {
|
|||
let value = self.get_value_f32();
|
||||
|
||||
let rect = interact.rect;
|
||||
let rail_radius = (height / 8.0).round().max(2.0);
|
||||
let rail_radius = region.round_to_pixel((height / 8.0).max(2.0));
|
||||
let rail_rect = Rect::from_min_max(
|
||||
pos2(interact.rect.left(), rect.center().y - rail_radius),
|
||||
pos2(interact.rect.right(), rect.center().y + rail_radius),
|
||||
|
|
|
@ -139,6 +139,8 @@ impl Window {
|
|||
}
|
||||
};
|
||||
|
||||
state.outer_pos = state.outer_pos.round(); // TODO: round to pixel
|
||||
|
||||
let min_inner_size = self.min_size;
|
||||
let max_inner_size = self
|
||||
.max_size
|
||||
|
@ -227,16 +229,16 @@ impl Window {
|
|||
state.outer_pos += ctx.input().mouse_move;
|
||||
}
|
||||
|
||||
if corner_interact.hovered || corner_interact.active {
|
||||
ctx.output.lock().cursor_icon = CursorIcon::ResizeNwSe;
|
||||
}
|
||||
|
||||
state = State {
|
||||
outer_pos: state.outer_pos,
|
||||
inner_size: new_inner_size,
|
||||
outer_rect: outer_rect,
|
||||
};
|
||||
|
||||
if corner_interact.hovered || corner_interact.active {
|
||||
*ctx.cursor_icon.lock() = CursorIcon::ResizeNorthWestSouthEast;
|
||||
}
|
||||
|
||||
if win_interact.active || corner_interact.active || mouse_pressed_on_window(ctx, id) {
|
||||
ctx.memory.lock().move_window_to_top(id);
|
||||
}
|
||||
|
|
|
@ -9,3 +9,4 @@ emigui = { path = "../emigui" }
|
|||
emigui_glium = { path = "../emigui_glium" }
|
||||
|
||||
glium = "0.24"
|
||||
webbrowser = "0.5"
|
||||
|
|
|
@ -102,7 +102,7 @@ fn main() {
|
|||
_ => (),
|
||||
});
|
||||
|
||||
emigui.new_frame(raw_input);
|
||||
emigui.begin_frame(raw_input);
|
||||
let mut region = emigui.background_region();
|
||||
let mut region = region.centered_column(region.available_width().min(480.0));
|
||||
region.set_align(Align::Min);
|
||||
|
@ -127,13 +127,21 @@ fn main() {
|
|||
emigui.ui(region);
|
||||
});
|
||||
|
||||
painter.paint_batches(&display, emigui.paint(), emigui.texture());
|
||||
let (output, paint_batches) = emigui.end_frame();
|
||||
painter.paint_batches(&display, paint_batches, emigui.texture());
|
||||
|
||||
let cursor = *emigui.ctx.cursor_icon.lock();
|
||||
let cursor = match cursor {
|
||||
let cursor = match output.cursor_icon {
|
||||
CursorIcon::Default => glutin::MouseCursor::Default,
|
||||
CursorIcon::ResizeNorthWestSouthEast => glutin::MouseCursor::NwseResize,
|
||||
CursorIcon::PointingHand => glutin::MouseCursor::Hand,
|
||||
CursorIcon::ResizeNwSe => glutin::MouseCursor::NwseResize,
|
||||
};
|
||||
|
||||
if let Some(url) = output.open_url {
|
||||
if let Err(err) = webbrowser::open(&url) {
|
||||
eprintln!("Failed to open url: {}", err); // TODO show error in imgui
|
||||
}
|
||||
}
|
||||
|
||||
display.gl_window().set_cursor(cursor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,10 +38,10 @@ impl State {
|
|||
})
|
||||
}
|
||||
|
||||
fn run(&mut self, raw_input: RawInput) -> Result<(), JsValue> {
|
||||
fn run(&mut self, raw_input: RawInput) -> Result<Output, JsValue> {
|
||||
let everything_start = now_sec();
|
||||
|
||||
self.emigui.new_frame(raw_input);
|
||||
self.emigui.begin_frame(raw_input);
|
||||
|
||||
let mut region = self.emigui.background_region();
|
||||
let mut region = region.centered_column(region.available_width().min(480.0));
|
||||
|
@ -53,6 +53,10 @@ impl State {
|
|||
);
|
||||
region.add_label("This is not JavaScript. This is Rust, running at 60 FPS. This is the web page, reinvented with game tech.");
|
||||
region.add_label("This is also work in progress, and not ready for production... yet :)");
|
||||
region.horizontal(Align::Min, |region| {
|
||||
region.add_label("Project home page:");
|
||||
region.add_hyperlink("https://github.com/emilk/emigui/");
|
||||
});
|
||||
region.add(Separator::new());
|
||||
|
||||
region.set_align(Align::Min);
|
||||
|
@ -88,20 +92,20 @@ impl State {
|
|||
});
|
||||
|
||||
let bg_color = srgba(16, 16, 16, 255);
|
||||
let batches = self.emigui.paint();
|
||||
let result = self.webgl_painter.paint_batches(
|
||||
let (output, batches) = self.emigui.end_frame();
|
||||
self.webgl_painter.paint_batches(
|
||||
bg_color,
|
||||
batches,
|
||||
self.emigui.texture(),
|
||||
raw_input.pixels_per_point,
|
||||
);
|
||||
)?;
|
||||
|
||||
self.frame_times.push_back(now_sec() - everything_start);
|
||||
while self.frame_times.len() > 30 {
|
||||
self.frame_times.pop_front();
|
||||
}
|
||||
|
||||
result
|
||||
Ok(output)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -111,8 +115,9 @@ pub fn new_webgl_gui(canvas_id: &str, pixels_per_point: f32) -> Result<State, Js
|
|||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn run_gui(state: &mut State, raw_input_json: &str) -> Result<(), JsValue> {
|
||||
pub fn run_gui(state: &mut State, raw_input_json: &str) -> Result<String, JsValue> {
|
||||
// TODO: nicer interface than JSON
|
||||
let raw_input: RawInput = serde_json::from_str(raw_input_json).unwrap();
|
||||
state.run(raw_input)
|
||||
let output = state.run(raw_input)?;
|
||||
Ok(serde_json::to_string(&output).unwrap())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue