diff --git a/vlib/builtin/js/builtin.js.v b/vlib/builtin/js/builtin.js.v index b5092ba8aa..71e40f4c59 100644 --- a/vlib/builtin/js/builtin.js.v +++ b/vlib/builtin/js/builtin.js.v @@ -92,8 +92,10 @@ pub fn isnil(val voidptr) bool { res := false // This one is kinda weird. In C and native backend we can cast booleans and integers to pointers // so we just check *for* all possible NULL-like values here. - #val = val.valueOf() - #res.val = val === null || val === undefined || val === false || val === 0 || val === BigInt(0) + #if (typeof val == 'function') { res.val = false; } else { + #val = val instanceof voidptr ? val.valueOf().val : val; + #res.val = val === null || val === undefined || val === false || val === 0 || val === BigInt(0) || (val instanceof int ? val.val == 0 : false) + #} return res } diff --git a/vlib/gg/gg.js.v b/vlib/gg/gg.js.v index e0690a1ca5..dedc7f202e 100644 --- a/vlib/gg/gg.js.v +++ b/vlib/gg/gg.js.v @@ -40,7 +40,7 @@ pub mut: char_code u32 key_repeat bool modifiers u32 - mouse_button DOMMouseButton + mouse_button MouseButton mouse_x f32 mouse_y f32 mouse_dx f32 @@ -252,7 +252,7 @@ pub: enable_dragndrop bool // enable file dropping (drag'n'drop), default is false max_dropped_files int = 1 // max number of dropped files to process (default: 1) max_dropped_file_path_length int = 2048 // max length in bytes of a dropped UTF-8 file path (default: 2048) - context JS.CanvasRenderingContext2D + canvas JS.HTMLCanvasElement } pub struct Context { @@ -283,12 +283,13 @@ pub mut: key_repeat bool // whether the pressed key was an autorepeated one pressed_keys [key_code_max]bool // an array representing all currently pressed keys pressed_keys_edge [key_code_max]bool // true when the previous state of pressed_keys, - canvas JS.CanvasRenderingContext2D [noinit] + context JS.CanvasRenderingContext2D [noinit] // *before* the current event was different } pub fn new_context(cfg Config) &Context { mut g := &Context{} + g.user_data = cfg.user_data g.width = cfg.width g.height = cfg.height @@ -298,8 +299,83 @@ pub fn new_context(cfg Config) &Context { g.user_data = g } g.window = dom.window() - g.canvas = cfg.context + ctx := cfg.canvas.getContext('2d'.str, js_undefined()) or { panic('') } + match ctx { + JS.CanvasRenderingContext2D { + g.context = ctx + } + else { + panic('gg: cannot get 2D context') + } + } + mouse_down_event_handler := fn [mut g] (event JS.Event) { + match event { + JS.MouseEvent { + e := g.handle_mouse_event(event) + if !isnil(g.config.click_fn) { + f := g.config.click_fn + f(e.mouse_x, e.mouse_y, e.mouse_button, g.config.user_data) + } + } + else {} + } + } + mouse_up_event_handler := fn [mut g] (event JS.Event) { + match event { + JS.MouseEvent { + e := g.handle_mouse_event(event) + if !isnil(g.config.unclick_fn) { + f := g.config.unclick_fn + f(e.mouse_x, e.mouse_y, e.mouse_button, g.config.user_data) + } + } + else {} + } + } + mouse_move_event_handler := fn [mut g] (event JS.Event) { + match event { + JS.MouseEvent { + e := g.handle_mouse_event(event) + if !isnil(g.config.move_fn) { + f := g.config.move_fn + f(e.mouse_x, e.mouse_y, g.config.user_data) + } + } + else {} + } + } + + mouse_leave_event_handler := fn [mut g] (event JS.Event) { + match event { + JS.MouseEvent { + e := g.handle_mouse_event(event) + if !isnil(g.config.leave_fn) { + f := g.config.leave_fn + f(e, g.config.user_data) + } + } + else {} + } + } + + mouse_enter_event_handler := fn [mut g] (event JS.Event) { + match event { + JS.MouseEvent { + e := g.handle_mouse_event(event) + if !isnil(g.config.enter_fn) { + f := g.config.enter_fn + f(e, g.config.user_data) + } + } + else {} + } + } + cfg.canvas.addEventListener('mousedown'.str, mouse_down_event_handler, JS.EventListenerOptions{}) + dom.window().addEventListener('mouseup'.str, mouse_up_event_handler, JS.EventListenerOptions{}) + cfg.canvas.addEventListener('mousemove'.str, mouse_move_event_handler, JS.EventListenerOptions{}) + cfg.canvas.addEventListener('mouseleave'.str, mouse_leave_event_handler, JS.EventListenerOptions{}) + cfg.canvas.addEventListener('mouseenter'.str, mouse_enter_event_handler, JS.EventListenerOptions{}) return g } @@ -308,33 +384,34 @@ pub fn (mut ctx Context) run() { } pub fn (mut ctx Context) begin() { - // ctx.canvas.beginPath() + // ctx.context.beginPath() } pub fn (mut ctx Context) end() { - // ctx.canvas.closePath() + // ctx.context.closePath() } pub fn (mut ctx Context) draw_line(x1 f32, y1 f32, x2 f32, y2 f32, c gx.Color) { - ctx.canvas.beginPath() - ctx.canvas.strokeStyle = c.to_css_string().str - ctx.canvas.moveTo(x1, y1) - ctx.canvas.lineTo(x2, y2) - ctx.canvas.stroke() - ctx.canvas.closePath() + ctx.context.beginPath() + ctx.context.strokeStyle = c.to_css_string().str + ctx.context.moveTo(x1, y1) + ctx.context.lineTo(x2, y2) + ctx.context.stroke() + ctx.context.closePath() } pub fn (mut ctx Context) draw_rect(x f32, y f32, w f32, h f32, c gx.Color) { - ctx.canvas.beginPath() - ctx.canvas.fillStyle = c.to_css_string().str - ctx.canvas.fillRect(x, y, w, h) - ctx.canvas.closePath() + ctx.context.beginPath() + ctx.context.fillStyle = c.to_css_string().str + ctx.context.fillRect(x, y, w, h) + ctx.context.closePath() } fn gg_animation_frame_fn(mut g Context) { g.frame++ - g.canvas.clearRect(0, 0, g.config.width, g.config.height) + g.context.clearRect(0, 0, g.config.width, g.config.height) // todo(playXE): handle events + if !isnil(g.config.frame_fn) { f := g.config.frame_fn f(g.user_data) @@ -345,3 +422,38 @@ fn gg_animation_frame_fn(mut g Context) { gg_animation_frame_fn(mut g) }) } + +fn (mut g Context) handle_mouse_event(event JS.MouseEvent) Event { + mut e := Event{} + + e.typ = .mouse_down + e.frame_count = g.frame + + match int(event.button) { + 0 { + e.mouse_button = .left + } + 1 { + e.mouse_button = .middle + } + 2 { + e.mouse_button = .right + } + else { + e.mouse_button = .invalid + } + } + e.mouse_x = int(event.offsetX) + e.mouse_y = int(event.offsetY) + e.mouse_dx = int(event.movementX) + e.mouse_dy = int(event.movementY) + bitplace := int(event.button) + g.mbtn_mask |= byte(1 << bitplace) + // g.mouse_buttons = MouseButtons(g.mbtn_mask) + + g.mouse_pos_x = int(event.offsetX) + g.mouse_pos_y = int(event.offsetY) + g.mouse_dx = int(event.movementX) + g.mouse_dy = int(event.movementY) + return e +} diff --git a/vlib/js/dom/dom.js.v b/vlib/js/dom/dom.js.v index a2f2c9e154..56f163f424 100644 --- a/vlib/js/dom/dom.js.v +++ b/vlib/js/dom/dom.js.v @@ -901,6 +901,14 @@ pub interface JS.MouseEvent { getModifierState(keyArg JS.String) JS.Boolean } +pub interface JS.WheelEvent { + JS.MouseEvent + deltaX JS.Number + deltaY JS.Number + deltaZ JS.Number + deltaMode JS.Number +} + pub interface JS.PointerEvent { JS.MouseEvent height JS.Number