diff --git a/.vdocignore b/.vdocignore new file mode 100644 index 00000000..7c1486d2 --- /dev/null +++ b/.vdocignore @@ -0,0 +1,2 @@ +/examples +/bin diff --git a/component/accordion.v b/component/accordion.v index 64bdf5c5..9c397a6a 100644 --- a/component/accordion.v +++ b/component/accordion.v @@ -18,6 +18,7 @@ pub mut: @[params] pub struct AccordionParams { +pub: id string titles []string children []ui.Widget diff --git a/component/alpha.v b/component/alpha.v index 685e90b2..e6bf61e0 100644 --- a/component/alpha.v +++ b/component/alpha.v @@ -17,6 +17,7 @@ pub mut: @[params] pub struct AlphaParams { +pub: id string alpha int direction ui.Direction = .column diff --git a/component/colorbox.v b/component/colorbox.v index aad62f75..b337343a 100644 --- a/component/colorbox.v +++ b/component/colorbox.v @@ -29,6 +29,8 @@ struct HSVColor { pub struct ColorBoxComponent { mut: simg C.sg_image + sampler C.sg_sampler + buf &u8 = unsafe { 0 } h f64 = 0.0 s f64 = 0.75 v f64 = 0.75 @@ -62,6 +64,7 @@ pub mut: @[params] pub struct ColorBoxParams { +pub: id string light bool hsl bool @@ -184,6 +187,8 @@ fn colorbox_init(layout &ui.Stack) { } cb.update_theme() cb.simg = ui.create_dynamic_texture(256, 256) + cb.sampler = ui.create_image_sampler() + cb.buf = unsafe { malloc(4 * 256 * 256) } cb.update_buffer() } @@ -248,7 +253,7 @@ fn cv_sv_draw(mut d ui.DrawDevice, mut c ui.CanvasLayout) { mut cb := colorbox_component(c) // TODO: check extra_draw c.draw_device_texture - c.draw_texture(cb.simg) + c.draw_texture(cb.simg, cb.sampler) c.draw_device_rounded_rect_filled(d, int(cb.s * 256.0) - 10, int((1.0 - cb.v) * 256.0) - 10, 20, 20, 10, cb.hsv_to_rgb(cb.h, 1 - cb.s, 1.0 - cb.v)) @@ -335,9 +340,7 @@ pub fn (mut cb ColorBoxComponent) update_sel_color() { // TODO: documentation pub fn (mut cb ColorBoxComponent) update_buffer() { - unsafe { ui.destroy_texture(cb.simg) } - sz := 256 * 256 * 4 - buf := unsafe { malloc(sz) } + buf := unsafe { cb.buf } mut col := gx.Color{} mut i := 0 for y in 0 .. 256 { @@ -352,11 +355,7 @@ pub fn (mut cb ColorBoxComponent) update_buffer() { } } } - unsafe { - cb.simg = ui.create_texture(256, 256, buf) - // update_text_texture(cb.simg, 256, 256, buf) - free(buf) - } + ui.update_text_texture(cb.simg, 256, 256, cb.buf) } fn tb_char(tb &ui.TextBox, cp u32) { diff --git a/component/colorbutton.v b/component/colorbutton.v index 8a96c828..38ef45cc 100644 --- a/component/colorbutton.v +++ b/component/colorbutton.v @@ -18,6 +18,7 @@ pub mut: @[params] pub struct ColorButtonParams { +pub: id string text string height int diff --git a/component/colorpalette.v b/component/colorpalette.v index e17549e2..dd0deb5f 100644 --- a/component/colorpalette.v +++ b/component/colorpalette.v @@ -18,6 +18,7 @@ pub mut: @[params] pub struct ColorPaletteParams { +pub: id string title string items []string diff --git a/component/colorsliders.v b/component/colorsliders.v index 547a04da..3b8a59ef 100644 --- a/component/colorsliders.v +++ b/component/colorsliders.v @@ -29,6 +29,7 @@ pub mut: @[params] pub struct ColorSlidersParams { +pub: id string color gx.Color = gx.white orientation ui.Orientation = .vertical diff --git a/component/demo.v b/component/demo.v index 760b36bc..cd158497 100644 --- a/component/demo.v +++ b/component/demo.v @@ -15,6 +15,7 @@ pub mut: @[params] pub struct DemoParams { +pub: id string = 'demo' } diff --git a/component/double_listbox.v b/component/double_listbox.v index c894156b..f1cec35a 100644 --- a/component/double_listbox.v +++ b/component/double_listbox.v @@ -15,6 +15,7 @@ pub mut: @[params] pub struct DoubleListBoxParams { +pub: id string title string items []string diff --git a/component/filebrowser.v b/component/filebrowser.v index f319a105..9d4f59ce 100644 --- a/component/filebrowser.v +++ b/component/filebrowser.v @@ -16,6 +16,7 @@ pub mut: @[params] pub struct FileBrowserParams { +pub: id string dirs []string = [os.expand_tilde_to_home('~'), '/'] text_ok string = 'Ok' diff --git a/component/fontbutton.v b/component/fontbutton.v index 4f8d433c..0d18ff76 100644 --- a/component/fontbutton.v +++ b/component/fontbutton.v @@ -12,6 +12,7 @@ pub mut: @[params] pub struct FontButtonParams { +pub: id string dtw ui.DrawTextWidget = ui.canvas_plus() text string diff --git a/component/fontchooser.v b/component/fontchooser.v index 00243a92..80440675 100644 --- a/component/fontchooser.v +++ b/component/fontchooser.v @@ -15,6 +15,7 @@ pub mut: @[params] pub struct FontChooserParams { +pub: id string = component.fontchooser_lb_id draw_lines bool = true dtw ui.DrawTextWidget = ui.canvas_plus() // since it requires an intialisation diff --git a/component/gg_app.v b/component/gg_app.v index 43edf23e..2f66f457 100644 --- a/component/gg_app.v +++ b/component/gg_app.v @@ -14,6 +14,7 @@ pub mut: @[params] pub struct GGComponentParams { +pub: id string = 'gg_app' app ui.GGApplication z_index int diff --git a/component/grid.v b/component/grid.v index a99ca209..bc4bfcaf 100644 --- a/component/grid.v +++ b/component/grid.v @@ -6,7 +6,7 @@ import gx import math pub struct Factor { -mut: +pub mut: levels []string values []int } @@ -78,6 +78,7 @@ pub mut: @[params] pub struct GridParams { +pub: vars map[string]GridData formulas map[string]string width int = 100 @@ -85,7 +86,7 @@ pub struct GridParams { scrollview bool = true is_focused bool fixed_height bool = true -mut: +pub mut: id string } diff --git a/component/grid_data.v b/component/grid_data.v index 19d236d4..1ca77fe2 100644 --- a/component/grid_data.v +++ b/component/grid_data.v @@ -14,6 +14,7 @@ pub mut: @[params] pub struct DataGridParams { GridParams // for settings prepended by settings_ +pub: settings_bg_color gx.Color = gx.light_blue settings_z_index int = 100 } diff --git a/component/grid_formula.v b/component/grid_formula.v index 5915792b..6dd77d9e 100644 --- a/component/grid_formula.v +++ b/component/grid_formula.v @@ -17,6 +17,7 @@ type ActiveCells = AlphaCell | AlphaCellBlock // Matrix-like (zero indexed) pub struct GridCell { +pub: i int j int } diff --git a/component/grid_tools.v b/component/grid_tools.v index f0a84c10..ba1e5606 100644 --- a/component/grid_tools.v +++ b/component/grid_tools.v @@ -15,6 +15,7 @@ pub mut: @[params] pub struct GridSettingsParams { +pub: id string bg_color gx.Color = gx.light_blue grid &GridComponent = unsafe { nil } diff --git a/component/hideable.v b/component/hideable.v index 7e99cc6d..5c11ebdc 100644 --- a/component/hideable.v +++ b/component/hideable.v @@ -18,6 +18,7 @@ pub mut: @[params] pub struct HideableParams { +pub: id string bg_color gx.Color layout &ui.Stack = unsafe { nil } diff --git a/component/menufile.v b/component/menufile.v index c0dda465..6ffb1296 100644 --- a/component/menufile.v +++ b/component/menufile.v @@ -22,6 +22,7 @@ pub mut: @[params] pub struct MenuFileParams { +pub: id string hidden_files bool dirs []string diff --git a/component/messagebox.v b/component/messagebox.v index ae9ee5ac..a0109b07 100644 --- a/component/messagebox.v +++ b/component/messagebox.v @@ -16,6 +16,7 @@ pub struct MessageBoxComponent { @[params] pub struct MessageBoxParams { +pub: id string text string on_click MessageBoxFn = MessageBoxFn(0) diff --git a/component/rasterview.v b/component/rasterview.v index 8c04256b..b50a1e18 100644 --- a/component/rasterview.v +++ b/component/rasterview.v @@ -51,6 +51,7 @@ pub mut: @[params] pub struct RasterViewParams { +pub: id string width int = 16 height int = 16 diff --git a/component/settings.v b/component/settings.v index 0b335e4a..c9983717 100644 --- a/component/settings.v +++ b/component/settings.v @@ -19,6 +19,7 @@ mut: @[params] pub struct SettingFontParams { +pub: id string param string text string diff --git a/component/splitpanel.v b/component/splitpanel.v index 844188ce..54b23fdd 100644 --- a/component/splitpanel.v +++ b/component/splitpanel.v @@ -20,6 +20,7 @@ pub mut: @[params] pub struct SplitPanelParams { +pub: id string child1 &ui.Widget = unsafe { nil } child2 &ui.Widget = unsafe { nil } diff --git a/component/subwindow_filebrowser.v b/component/subwindow_filebrowser.v index 139964d0..d8e026fd 100644 --- a/component/subwindow_filebrowser.v +++ b/component/subwindow_filebrowser.v @@ -9,6 +9,7 @@ const newfilebrowser_subwindow_id = '_sw_newfilebrowser' @[params] pub struct FileBrowserSubWindowParams { FileBrowserParams +pub: x int y int } diff --git a/component/subwindow_messagebox.v b/component/subwindow_messagebox.v index ea9c5e75..6d8a39e5 100644 --- a/component/subwindow_messagebox.v +++ b/component/subwindow_messagebox.v @@ -4,6 +4,7 @@ import ui @[params] pub struct MessageBoxSubWindowParams { +pub: id string text string shortcut string = 'ctrl + h' diff --git a/component/tabs.v b/component/tabs.v index e1fe04af..89f327c6 100644 --- a/component/tabs.v +++ b/component/tabs.v @@ -29,6 +29,7 @@ pub mut: @[params] pub struct TabsParams { +pub: id string mode TabsMode = .vertical active int @@ -51,7 +52,12 @@ pub fn tabs_stack(c TabsParams) &ui.Stack { // bg_color: gx.white on_key_down: tab_key_down children: [ - ui.label(id: tab_id(c.id, i) + '_label', text: tab), + ui.row( + id: tab_id(c.id, i) + '_row' + children: [ + ui.label(id: tab_id(c.id, i) + '_label', text: tab), + ] + ), ] ) } @@ -259,7 +265,8 @@ fn (tabs &TabsComponent) update_pos(win &ui.Window) { // println("$dx, $dy $lab.x $lab.y") lab.set_pos(dx, dy) // println("$dx, $dy $lab.x $lab.y") + row_id := tab_id(tabs.id, i) + '_row' mut c := win.get_or_panic[ui.CanvasLayout](tab_id(tabs.id, i)) - c.set_child_relative_pos(lab_id, dx, dy) + c.set_child_relative_pos(row_id, dx, dy) } } diff --git a/component/treeview.v b/component/treeview.v index 5188254c..0a63aee2 100644 --- a/component/treeview.v +++ b/component/treeview.v @@ -10,7 +10,7 @@ const root_sep = '_|||_' type TreeItem = Tree | string pub struct Tree { -mut: +pub mut: title string items []TreeItem } @@ -152,6 +152,7 @@ pub mut: @[params] pub struct TreeViewParams { +pub: id string trees []Tree icons map[string]string @@ -205,6 +206,7 @@ pub fn treeview_stack(c TreeViewParams) &ui.Stack { @[params] pub struct TreeViewDirParams { +pub: id string = 'tvd' trees []string icons map[string]string diff --git a/examples/canvas_plus_gradient_texture.v b/examples/canvas_plus_gradient_texture.v new file mode 100644 index 00000000..a61fe502 --- /dev/null +++ b/examples/canvas_plus_gradient_texture.v @@ -0,0 +1,60 @@ +// A small demo of how to draw arbitrary images to a custom canvas, +// by using ui.create_dynamic_texture and c.draw_texture . +// The gradient is generated by calculating the color of each pixel in the canvas, +// then blitting the resulting image/texture to the canvas at once at the end. +import ui +import gx +import sokol.gfx + +@[heap] +struct App { +mut: + window &ui.Window = unsafe { nil } + buf &u8 = unsafe { nil } + texture gfx.Image + sampler gfx.Sampler +} + +fn main() { + mut app := App{} + app.window = ui.window( + width: 600 + height: 400 + title: 'gradient' + on_init: app.init_texture + children: [ + ui.canvas_plus( + id: 'canvas_gradient' + on_draw: app.draw_gradient + ), + ] + ) + ui.run(app.window) +} + +fn (mut app App) init_texture(w &ui.Window) { + app.texture = ui.create_dynamic_texture(256, 256) + app.sampler = ui.create_image_sampler() + app.buf = unsafe { malloc(256 * 256 * 4) } +} + +fn (app &App) draw_gradient(mut d ui.DrawDevice, c &ui.CanvasLayout) { + target_hue, _, _ := ui.rgb_to_hsv(gx.rgb(255, 0, 0)) + mut i := 0 + for y in 0 .. 256 { + for x in 0 .. 256 { + saturation := f32(y) / 255.0 + value := f32(255 - x) / 255.0 + rgb_color := ui.hsv_to_rgb(target_hue, saturation, value) + unsafe { + app.buf[i] = rgb_color.r + app.buf[i + 1] = rgb_color.g + app.buf[i + 2] = rgb_color.b + app.buf[i + 3] = 255 + i += 4 + } + } + } + ui.update_text_texture(app.texture, 256, 256, app.buf) + c.draw_texture(app.texture, app.sampler) +} diff --git a/libvg/raster.v b/libvg/raster.v index 27dc9877..7c56fd11 100644 --- a/libvg/raster.v +++ b/libvg/raster.v @@ -32,6 +32,7 @@ pub mut: @[params] pub struct RasterParams { +pub: width int = 16 height int = 16 channels int = 4 diff --git a/libvg/raster_tool.v b/libvg/raster_tool.v index b5fd8e6b..88e0c168 100644 --- a/libvg/raster_tool.v +++ b/libvg/raster_tool.v @@ -599,6 +599,7 @@ fn color_multiply_alpha(c gx.Color, a f64) gx.Color { @[params] pub struct TextBlockParams { +pub: x int // x postion of the left high corner y int // y postion of the left high corner w int // width of the text block diff --git a/libvg/raster_ttf.v b/libvg/raster_ttf.v index 2c081318..d646fc23 100644 --- a/libvg/raster_ttf.v +++ b/libvg/raster_ttf.v @@ -44,6 +44,7 @@ pub fn (r &Raster) get_info_string() { @[params] pub struct SetFontSizeParams { +pub: font_size int device_dpi int = 72 } diff --git a/libvg/svg.v b/libvg/svg.v index d3bcac32..24e6adc4 100644 --- a/libvg/svg.v +++ b/libvg/svg.v @@ -15,6 +15,7 @@ pub mut: @[params] pub struct SvgParams { +pub: height int width int } @@ -60,6 +61,7 @@ pub fn (mut s Svg) save(filepath string) ! { @[params] pub struct Params { +pub: stroke string = 'none' strokewidth int fill string = 'none' diff --git a/src/assets/img/arrow.png b/src/assets/img/arrow.png new file mode 100644 index 00000000..ac449dd1 Binary files /dev/null and b/src/assets/img/arrow.png differ diff --git a/src/button.v b/src/button.v index 804f27a7..db199583 100644 --- a/src/button.v +++ b/src/button.v @@ -31,6 +31,7 @@ type ButtonMouseMoveFn = fn (&Button, &MouseMoveEvent) @[heap] pub struct Button { // init size read-only +pub: width_ int height_ int pub mut: @@ -89,6 +90,7 @@ pub mut: @[params] pub struct ButtonParams { ButtonStyleParams +pub: id string text string icon_path string diff --git a/src/button_style.v b/src/button_style.v index 20d0620d..415aba86 100644 --- a/src/button_style.v +++ b/src/button_style.v @@ -74,17 +74,20 @@ pub fn (mut b Button) load_style() { if b.style_params.style != no_style { style = b.style_params.style } - b.update_theme_style(style) + b.apply_theme_style(style) // forced overload default style b.update_style(b.style_params) } -pub fn (mut b Button) update_theme_style(theme string) { +pub fn (mut b Button) update_theme_style(style string) { // println("update_style <$p.style>") - style := if theme == '' { 'default' } else { theme } + b.theme_style = style + b.apply_theme_style(style) +} + +fn (mut b Button) apply_theme_style(style string) { if style != no_style && style in b.ui.styles { bs := b.ui.styles[style].btn - b.theme_style = theme b.update_shape_theme_style(bs) mut dtw := DrawTextWidget(b) dtw.update_theme_style(bs) diff --git a/src/canvas.v b/src/canvas.v index ed730500..97998c81 100644 --- a/src/canvas.v +++ b/src/canvas.v @@ -30,6 +30,7 @@ mut: @[params] pub struct CanvasParams { +pub: id string width int height int diff --git a/src/style_checkbox.v b/src/checkbox_style.v similarity index 94% rename from src/style_checkbox.v rename to src/checkbox_style.v index aacdfc53..10564f1a 100644 --- a/src/style_checkbox.v +++ b/src/checkbox_style.v @@ -25,7 +25,7 @@ pub mut: @[params] pub struct CheckBoxStyleParams { WidgetTextStyleParams -mut: +pub mut: style string = no_style border_color gx.Color = no_color bg_color gx.Color = no_color @@ -66,18 +66,21 @@ pub fn (mut cb CheckBox) load_style() { if cb.style_params.style != no_style { style = cb.style_params.style } - cb.update_theme_style(style) + cb.apply_theme_style(style) // forced overload default style cb.update_style(cb.style_params) cb.ui.cb_image = cb.ui.img(cb.style.check_mode) } -pub fn (mut cb CheckBox) update_theme_style(theme string) { +pub fn (mut cb CheckBox) update_theme_style(style string) { + cb.theme_style = style + cb.apply_theme_style(style) +} + +fn (mut cb CheckBox) apply_theme_style(style string) { // println("update_style <$p.style>") - style := if theme == '' { 'default' } else { theme } if style != no_style && style in cb.ui.styles { cbs := cb.ui.styles[style].cb - cb.theme_style = theme cb.update_shape_theme_style(cbs) mut dtw := DrawTextWidget(cb) dtw.update_theme_style(cbs) diff --git a/src/chunkview.v b/src/chunkview.v index f4731cdc..85b13371 100644 --- a/src/chunkview.v +++ b/src/chunkview.v @@ -16,7 +16,7 @@ const para_style_delim = '|' @[params] pub struct Offset { -mut: +pub mut: x int y int } @@ -60,6 +60,7 @@ mut: @[params] pub struct TextChunkParams { +pub: x int y int text string @@ -167,6 +168,7 @@ mut: @[params] pub struct ParaChunkParams { +pub: x int y int margin int @@ -279,7 +281,7 @@ fn (mut c ParaChunk) update_chunks(cv &ChunkView) { ind = -2 } else { // index of last whitespace except when at the end - ind = left.trim_right(' ').index_last(' ') or { -2 } + ind = left.trim_right(' ').last_index(' ') or { -2 } if ind >= 0 { if right.len == 0 { right = left[(ind + 1)..] @@ -374,6 +376,7 @@ pub mut: @[params] pub struct AlignChunkParams { +pub: x int y int spacing int = 10 @@ -384,6 +387,7 @@ pub struct AlignChunkParams { @[params] pub struct VerticalAlignChunkParams { AlignChunkParams +pub: align f32 // in [0,1] } @@ -624,6 +628,7 @@ pub mut: @[params] pub struct RowChunkParams { +pub: x int y int chunks []ChunkContent @@ -776,6 +781,7 @@ pub mut: @[params] pub struct ChunkViewParams { +pub: id string chunks []ChunkContent clipping bool = true diff --git a/src/draw_device_bitmap.v b/src/draw_device_bitmap.v index cf81ea88..6a04165a 100644 --- a/src/draw_device_bitmap.v +++ b/src/draw_device_bitmap.v @@ -13,6 +13,7 @@ pub mut: @[params] pub struct DrawDeviceBitmapParams { +pub: id string = 'dd_bitmap' } diff --git a/src/draw_device_print.v b/src/draw_device_print.v index 6b2d874e..2bb5a235 100644 --- a/src/draw_device_print.v +++ b/src/draw_device_print.v @@ -10,6 +10,7 @@ struct DrawDevicePrint { @[params] pub struct DrawDevicePrintParams { +pub: id string = 'dd_print' filename string } diff --git a/src/draw_device_svg.v b/src/draw_device_svg.v index 01f35c97..8329f33a 100644 --- a/src/draw_device_svg.v +++ b/src/draw_device_svg.v @@ -14,6 +14,7 @@ pub mut: @[params] struct DrawDeviceSVGParams { +pub: id string = 'dd_svg' } diff --git a/src/dropdown.v b/src/dropdown.v index 5c05abad..43e901fe 100644 --- a/src/dropdown.v +++ b/src/dropdown.v @@ -41,6 +41,7 @@ pub mut: @[params] pub struct DropdownParams { DropdownStyleParams +pub: id string def_text string x int diff --git a/src/style_dropdown.v b/src/dropdown_style.v similarity index 94% rename from src/style_dropdown.v rename to src/dropdown_style.v index 840f0224..31cced0f 100644 --- a/src/style_dropdown.v +++ b/src/dropdown_style.v @@ -60,17 +60,20 @@ fn (mut dd Dropdown) load_style() { if dd.style_params.style != no_style { style = dd.style_params.style } - dd.update_theme_style(style) + dd.apply_theme_style(style) // forced overload default style dd.update_style(dd.style_params) } -pub fn (mut dd Dropdown) update_theme_style(theme string) { +pub fn (mut dd Dropdown) update_theme_style(style string) { + dd.theme_style = style + dd.apply_theme_style(style) +} + +fn (mut dd Dropdown) apply_theme_style(style string) { // println("update_style <$p.style>") - style := if theme == '' { 'default' } else { theme } if style != no_style && style in dd.ui.styles { dds := dd.ui.styles[style].dd - dd.theme_style = theme dd.update_shape_theme_style(dds) mut dtw := DrawTextWidget(dd) dtw.update_theme_style(dds) diff --git a/src/extra_draw.v b/src/extra_draw.v index acea5b18..d0b356ea 100644 --- a/src/extra_draw.v +++ b/src/extra_draw.v @@ -3,6 +3,7 @@ module ui import gx import math import sokol.sgl +import sokol.gfx // const ( // empty_text_cfg = gx.TextCfg{} @@ -330,16 +331,12 @@ pub fn create_dynamic_texture(w int, h int) C.sg_image { mut img_desc := C.sg_image_desc{ width: w height: h - num_mipmaps: 0 - // min_filter: .linear - // mag_filter: .linear + pixel_format: .rgba8 + num_mipmaps: 1 + num_slices: 1 usage: .dynamic - // wrap_u: .clamp_to_edge - // wrap_v: .clamp_to_edge - label: &u8(0) - d3d11_texture: 0 + label: c'a dynamic texture' } - sg_img := C.sg_make_image(&img_desc) return sg_img } @@ -355,9 +352,30 @@ pub fn update_text_texture(sg_img C.sg_image, w int, h int, buf &u8) { C.sg_update_image(sg_img, &tmp_sbc) } +@[params] +pub struct StreamingImageConfig { +pub: + wrap_u gfx.Wrap = .clamp_to_edge + wrap_v gfx.Wrap = .clamp_to_edge + min_filter gfx.Filter = .linear + mag_filter gfx.Filter = .linear + num_mipmaps int = 1 + num_slices int = 1 +} + +pub fn create_image_sampler(sicfg StreamingImageConfig) gfx.Sampler { + mut smp_desc := gfx.SamplerDesc{ + wrap_u: sicfg.wrap_u + wrap_v: sicfg.wrap_v + min_filter: sicfg.min_filter + mag_filter: sicfg.mag_filter + } + return gfx.make_sampler(&smp_desc) +} + // REMOVED: this function uses internals of gg.Context which we probably do not // want to reproduce in the DrawDevice interface -pub fn (c &CanvasLayout) draw_texture(simg C.sg_image) { +pub fn (c &CanvasLayout) draw_texture(simg gfx.Image, sampler gfx.Sampler) { ctx := c.ui.dd if ctx is DrawDeviceContext { cx, cy := c.x + c.offset_x, c.y + c.offset_y @@ -371,7 +389,7 @@ pub fn (c &CanvasLayout) draw_texture(simg C.sg_image) { y1 := f32((cy + c.height) * ctx.scale) sgl.load_pipeline(ctx.pipeline.alpha) sgl.enable_texture() - // sgl.texture(simg) + sgl.texture(simg, sampler) sgl.begin_quads() sgl.c4b(255, 255, 255, 255) sgl.v2f_t2f(x0, y0, u0, v0) diff --git a/src/extra_size.v b/src/extra_size.v index ce698123..96e74a95 100644 --- a/src/extra_size.v +++ b/src/extra_size.v @@ -113,6 +113,7 @@ pub mut: // for Config pub struct Margin { +pub: top f64 right f64 bottom f64 diff --git a/src/grid.v b/src/grid.v index 587ea487..fb2f5ed8 100644 --- a/src/grid.v +++ b/src/grid.v @@ -24,6 +24,7 @@ pub mut: @[params] pub struct GridParams { +pub: header []string body [][]string height int = 200 diff --git a/src/interface_action.v b/src/interface_action.v index 036f7d52..ef11b24a 100644 --- a/src/interface_action.v +++ b/src/interface_action.v @@ -30,8 +30,7 @@ pub fn (mut s Actionable) add_action(action string, context voidptr, action_fn A // TODO: documentation pub fn (s &Actionable) run_action(action string) { - if action in s.actions { - action_ := s.actions[action] - action_.action_fn(action_.context) + if a := s.actions[action] { + a.action_fn(a.context) } } diff --git a/src/interface_application.v b/src/interface_application.v index f8e722f2..9f20cc36 100644 --- a/src/interface_application.v +++ b/src/interface_application.v @@ -26,6 +26,7 @@ pub fn (mut app Application) add_window(p WindowParams) { @[params] pub struct WindowCallbackParams { +pub: on_click WindowMouseFn = unsafe { nil } on_mouse_down WindowMouseFn = unsafe { nil } on_mouse_up WindowMouseFn = unsafe { nil } diff --git a/src/interface_shortcut.v b/src/interface_shortcut.v index d765916b..e64a3cb7 100644 --- a/src/interface_shortcut.v +++ b/src/interface_shortcut.v @@ -29,9 +29,13 @@ pub fn (mut s Shortcutable) add_shortcut(shortcut string, key_fn ShortcutFn) { pub fn (mut s Shortcutable) add_shortcut_context(shortcut string, context voidptr) { _, code, key := parse_shortcut(shortcut) if code == 0 { - s.shortcuts.chars[key].context = context + unsafe { + s.shortcuts.chars[key].context = context + } } else { - s.shortcuts.keys[code].context = context + unsafe { + s.shortcuts.keys[code].context = context + } } } @@ -69,8 +73,7 @@ pub fn char_shortcut(e KeyEvent, shortcuts Shortcuts, context voidptr) { s = rune(96 + e.codepoint).str() } } - if s in shortcuts.chars { - sc := shortcuts.chars[s] + if sc := shortcuts.chars[s] { if has_key_mods(e.mods, sc.mods) { if sc.context != unsafe { nil } { sc.key_fn(sc.context) @@ -84,8 +87,8 @@ pub fn char_shortcut(e KeyEvent, shortcuts Shortcuts, context voidptr) { // TODO: documentation pub fn key_shortcut(e KeyEvent, shortcuts Shortcuts, context voidptr) { // println("key_shortcut ${int(e.key)}") - if int(e.key) in shortcuts.keys { - sc := shortcuts.keys[int(e.key)] + ikey := int(e.key) + if sc := shortcuts.keys[ikey] { if has_key_mods(e.mods, sc.mods) { if sc.context != unsafe { nil } { sc.key_fn(sc.context) diff --git a/src/interface_themestyle.v b/src/interface_themestyle.v index d6db0773..15b6b3ac 100644 --- a/src/interface_themestyle.v +++ b/src/interface_themestyle.v @@ -9,7 +9,7 @@ mut: // TODO: documentation pub fn (mut w WidgetThemeStyle) update_theme_style(theme_style string) { - w.theme_style = theme_style + // w.theme_style = theme_style } // TODO: documentation diff --git a/src/label.v b/src/label.v index d51b03c7..a4bcd717 100644 --- a/src/label.v +++ b/src/label.v @@ -39,6 +39,7 @@ pub mut: @[params] pub struct LabelParams { LabelStyleParams +pub: id string width int height int diff --git a/src/style_label.v b/src/label_style.v similarity index 90% rename from src/style_label.v rename to src/label_style.v index d8bc4197..8401ad70 100644 --- a/src/style_label.v +++ b/src/label_style.v @@ -42,17 +42,20 @@ pub fn (mut l Label) load_style() { if l.style_params.style != no_style { style = l.style_params.style } - l.update_theme_style(style) + l.apply_theme_style(style) // forced overload default style l.update_style(l.style_params) } -pub fn (mut l Label) update_theme_style(theme string) { +pub fn (mut l Label) update_theme_style(style string) { + l.theme_style = style + l.apply_theme_style(style) +} + +fn (mut l Label) apply_theme_style(style string) { // println("update_style <$p.style>") - style := if theme == '' { 'default' } else { theme } if style != no_style && style in l.ui.styles { ls := l.ui.styles[style].label - l.theme_style = theme mut dtw := DrawTextWidget(l) dtw.update_theme_style(ls) } diff --git a/src/layout_canvas.v b/src/layout_canvas.v index 6d65f9a5..ded54ed1 100644 --- a/src/layout_canvas.v +++ b/src/layout_canvas.v @@ -94,6 +94,7 @@ mut: @[params] pub struct CanvasLayoutParams { CanvasLayoutStyleParams +pub: id string width int height int diff --git a/src/layout_column.v b/src/layout_column.v index c24c0840..43bd1042 100644 --- a/src/layout_column.v +++ b/src/layout_column.v @@ -7,6 +7,7 @@ import gx @[params] pub struct ColumnParams { +pub: id string width int // To remove soon height int // To remove soon diff --git a/src/layout_row.v b/src/layout_row.v index e8a24774..587f1a18 100644 --- a/src/layout_row.v +++ b/src/layout_row.v @@ -28,6 +28,7 @@ pub: scrollview bool clipping bool children []Widget + hidden bool } pub fn row(c RowParams) &Stack { @@ -50,5 +51,6 @@ pub fn row(c RowParams) &Stack { scrollview: c.scrollview clipping: c.clipping children: c.children + // hidden: c.hidden ) } diff --git a/src/style_layouts.v b/src/layouts_style.v similarity index 94% rename from src/style_layouts.v rename to src/layouts_style.v index a4c3f72e..0585130f 100644 --- a/src/style_layouts.v +++ b/src/layouts_style.v @@ -57,12 +57,11 @@ fn (mut l CanvasLayout) load_style() { l.update_style(l.style_params) } -pub fn (mut l CanvasLayout) update_theme_style(theme string) { +pub fn (mut l CanvasLayout) update_theme_style(style string) { // println("$l.id update_theme_style <$theme>") - style := if theme == '' { 'default' } else { theme } if style != no_style && style in l.ui.styles { ls := l.ui.styles[style].cl - l.theme_style = theme + l.theme_style = style l.update_shape_theme_style(ls) mut dtw := DrawTextWidget(l) dtw.update_theme_style(ls) @@ -155,18 +154,21 @@ fn (mut l Stack) load_style() { if l.style_params.style != no_style { style = l.style_params.style } - l.update_theme_style(style) + l.apply_theme_style(style) // forced overload default style l.update_style(l.style_params) // println("s ls $l.theme_style $l.style $l.style_params") } -pub fn (mut l Stack) update_theme_style(theme string) { +pub fn (mut l Stack) update_theme_style(style string) { + l.theme_style = style + l.apply_theme_style(style) +} + +fn (mut l Stack) apply_theme_style(style string) { // println("update_style <$p.style>") - style := if theme == '' { 'default' } else { theme } if style != no_style && style in l.ui.styles { ls := l.ui.styles[style].stack - l.theme_style = theme l.update_shape_theme_style(ls) mut dtw := DrawTextWidget(l) dtw.update_theme_style(ls) diff --git a/src/listbox.v b/src/listbox.v index c5b7c8ed..df54d8a7 100644 --- a/src/listbox.v +++ b/src/listbox.v @@ -70,7 +70,7 @@ pub mut: @[params] pub struct ListBoxParams { ListBoxStyleParams -mut: +pub mut: x int y int width int @@ -913,6 +913,7 @@ pub mut: @[params] struct ListItemParams { +pub: id string list &ListBox = unsafe { nil } x int diff --git a/src/style_listbox.v b/src/listbox_style.v similarity index 95% rename from src/style_listbox.v rename to src/listbox_style.v index 21a93ddb..71ef79e3 100644 --- a/src/style_listbox.v +++ b/src/listbox_style.v @@ -27,7 +27,7 @@ pub mut: @[params] pub struct ListBoxStyleParams { WidgetTextStyleParams -mut: +pub mut: style string = no_style radius f32 border_color gx.Color = no_color @@ -74,17 +74,20 @@ pub fn (mut lb ListBox) load_style() { if lb.style_params.style != no_style { style = lb.style_params.style } - lb.update_theme_style(style) + lb.apply_theme_style(style) // forced overload default style lb.update_style(lb.style_params) } -pub fn (mut lb ListBox) update_theme_style(theme string) { +pub fn (mut lb ListBox) update_theme_style(style string) { + lb.theme_style = style + lb.apply_theme_style(style) +} + +fn (mut lb ListBox) apply_theme_style(style string) { // println("update_style <$p.style>") - style := if theme == '' { 'default' } else { theme } if style != no_style && style in lb.ui.styles { lbs := lb.ui.styles[style].lb - lb.theme_style = theme lb.update_shape_theme_style(lbs) mut dtw := DrawTextWidget(lb) dtw.update_theme_style(lbs) diff --git a/src/menu.v b/src/menu.v index f646ed58..be00787b 100644 --- a/src/menu.v +++ b/src/menu.v @@ -54,6 +54,7 @@ mut: @[params] pub struct MenuParams { MenuStyleParams +pub: id string width int = ui.menu_width height int = ui.menu_height @@ -499,6 +500,7 @@ mut: @[params] pub struct MenuItemParams { +pub: id string text string submenu &Menu = unsafe { nil } diff --git a/src/style_menu.v b/src/menu_style.v similarity index 95% rename from src/style_menu.v rename to src/menu_style.v index 9fb9c143..c21e2a44 100644 --- a/src/style_menu.v +++ b/src/menu_style.v @@ -70,17 +70,20 @@ pub fn (mut m Menu) load_style() { if m.style_params.style != no_style { style = m.style_params.style } - m.update_theme_style(style) + m.apply_theme_style(style) // forced overload default style m.update_style(m.style_params) } -pub fn (mut m Menu) update_theme_style(theme string) { +pub fn (mut m Menu) update_theme_style(style string) { + m.theme_style = style + m.apply_theme_style(style) +} + +fn (mut m Menu) apply_theme_style(style string) { // println("update_style $m.id") - style := if theme == '' { 'default' } else { theme } if style != no_style && style in m.ui.styles { ms := m.ui.styles[style].menu - m.theme_style = theme m.update_shape_theme_style(ms) mut dtw := DrawTextWidget(m) dtw.update_theme_style(ms) diff --git a/src/picture.v b/src/picture.v index 940c4e2d..19f292be 100644 --- a/src/picture.v +++ b/src/picture.v @@ -37,6 +37,7 @@ mut: @[params] pub struct PictureParams { +pub: id string path string width int @@ -93,7 +94,7 @@ fn (mut pic Picture) init(parent Layout) { eprintln('V UI: picture file "${pic.path}" not found') } if !pic.use_cache && pic.path in u.resource_cache { - pic.image = u.resource_cache[pic.path] + pic.image = unsafe { u.resource_cache[pic.path] } } else if mut pic.ui.dd is DrawDeviceContext { mut dd := pic.ui.dd if img := dd.create_image(pic.path) { diff --git a/src/progressbar.v b/src/progressbar.v index 9dca2163..53cba412 100644 --- a/src/progressbar.v +++ b/src/progressbar.v @@ -31,6 +31,7 @@ pub mut: @[params] pub struct ProgressBarParams { ProgressBarStyleParams +pub: id string width int height int = 16 diff --git a/src/style_progressbar.v b/src/progressbar_style.v similarity index 91% rename from src/style_progressbar.v rename to src/progressbar_style.v index cc678773..28181c83 100644 --- a/src/style_progressbar.v +++ b/src/progressbar_style.v @@ -49,17 +49,20 @@ fn (mut pb ProgressBar) load_style() { if pb.style_params.style != no_style { style = pb.style_params.style } - pb.update_theme_style(style) + pb.apply_theme_style(style) // forced overload default style pb.update_style(pb.style_params) } -pub fn (mut pb ProgressBar) update_theme_style(theme string) { +pub fn (mut pb ProgressBar) update_theme_style(style string) { + pb.theme_style = style + pb.apply_theme_style(style) +} + +fn (mut pb ProgressBar) apply_theme_style(style string) { // println("update_style <$p.style>") - style := if theme == '' { 'default' } else { theme } if style != no_style && style in pb.ui.styles { pbs := pb.ui.styles[style].pgbar - pb.theme_style = theme pb.style.color = pbs.color pb.style.border_color = pbs.border_color pb.style.bg_color = pbs.bg_color diff --git a/src/radio.v b/src/radio.v index 417aaa68..e5a3974c 100644 --- a/src/radio.v +++ b/src/radio.v @@ -62,6 +62,7 @@ pub mut: @[params] pub struct RadioParams { RadioStyleParams +pub: id string on_click RadioFn = unsafe { nil } values []string diff --git a/src/style_radio.v b/src/radio_style.v similarity index 94% rename from src/style_radio.v rename to src/radio_style.v index 05d80af5..a8e21753 100644 --- a/src/style_radio.v +++ b/src/radio_style.v @@ -25,7 +25,7 @@ pub mut: @[params] pub struct RadioStyleParams { WidgetTextStyleParams -mut: +pub mut: style string = no_style border_color gx.Color = no_color bg_color gx.Color = no_color @@ -66,18 +66,21 @@ pub fn (mut r Radio) load_style() { if r.style_params.style != no_style { style = r.style_params.style } - r.update_theme_style(style) + r.apply_theme_style(style) // forced overload default style r.update_style(r.style_params) r.ui.radio_selected_image = r.ui.img(r.style.radio_mode + '_selected') } -pub fn (mut r Radio) update_theme_style(theme string) { +pub fn (mut r Radio) update_theme_style(style string) { + r.theme_style = style + r.apply_theme_style(style) +} + +fn (mut r Radio) apply_theme_style(style string) { // println("update_style <$p.style>") - style := if theme == '' { 'default' } else { theme } if style != no_style && style in r.ui.styles { rs := r.ui.styles[style].radio - r.theme_style = theme r.update_shape_theme_style(rs) mut dtw := DrawTextWidget(r) dtw.update_theme_style(rs) diff --git a/src/rectangle.v b/src/rectangle.v index 1225ddc2..f9fb6f38 100644 --- a/src/rectangle.v +++ b/src/rectangle.v @@ -37,6 +37,7 @@ mut: @[params] pub struct RectangleParams { RectangleStyleParams +pub: id string text string height int diff --git a/src/style_rectangle.v b/src/rectangle_style.v similarity index 93% rename from src/style_rectangle.v rename to src/rectangle_style.v index eafc1907..56cf284a 100644 --- a/src/style_rectangle.v +++ b/src/rectangle_style.v @@ -24,7 +24,7 @@ pub mut: @[params] pub struct RectangleStyleParams { WidgetTextStyleParams -mut: +pub mut: style string = no_style border_color gx.Color = no_color color gx.Color = no_color @@ -62,17 +62,20 @@ pub fn (mut rect Rectangle) load_style() { if rect.style_params.style != no_style { style = rect.style_params.style } - rect.update_theme_style(style) + rect.apply_theme_style(style) // forced overload default style rect.update_style(rect.style_params) } -pub fn (mut rect Rectangle) update_theme_style(theme string) { +pub fn (mut rect Rectangle) update_theme_style(style string) { + rect.theme_style = style + rect.apply_theme_style(style) +} + +fn (mut rect Rectangle) apply_theme_style(style string) { // println("update_style <$p.style>") - style := if theme == '' { 'default' } else { theme } if style != no_style && style in rect.ui.styles { rects := rect.ui.styles[style].rect - rect.theme_style = theme rect.update_shape_theme_style(rects) mut dtw := DrawTextWidget(rect) dtw.update_theme_style(rects) diff --git a/src/slider.v b/src/slider.v index 6b1cad0a..d171e872 100644 --- a/src/slider.v +++ b/src/slider.v @@ -55,6 +55,7 @@ pub mut: @[params] pub struct SliderParams { SliderStyleParams +pub: id string width int height int diff --git a/src/style_slider.v b/src/slider_style.v similarity index 92% rename from src/style_slider.v rename to src/slider_style.v index 3240d1f1..e8877602 100644 --- a/src/style_slider.v +++ b/src/slider_style.v @@ -49,17 +49,20 @@ fn (mut s Slider) load_style() { if s.style_params.style != no_style { style = s.style_params.style } - s.update_theme_style(style) + s.apply_theme_style(style) // forced overload default style s.update_style(s.style_params) } -pub fn (mut s Slider) update_theme_style(theme string) { +pub fn (mut s Slider) update_theme_style(style string) { + s.theme_style = style + s.apply_theme_style(style) +} + +fn (mut s Slider) apply_theme_style(style string) { // println("update_style <$p.style>") - style := if theme == '' { 'default' } else { theme } if style != no_style && style in s.ui.styles { ss := s.ui.styles[style].slider - s.theme_style = theme s.style.thumb_color = ss.thumb_color s.style.bg_color = ss.bg_color s.style.bg_border_color = ss.bg_border_color diff --git a/src/stack.v b/src/stack.v index 0561d510..e2d45e35 100644 --- a/src/stack.v +++ b/src/stack.v @@ -106,6 +106,7 @@ pub mut: @[params] struct StackParams { StackStyleParams +pub: id string width int // useful for root_layout to init size height int @@ -127,6 +128,7 @@ struct StackParams { scrollview bool clipping bool children []Widget + hidden bool } fn stack(c StackParams) &Stack { @@ -150,6 +152,7 @@ fn stack(c StackParams) &Stack { alignments: c.align style_params: c.StackStyleParams title: c.title + hidden: c.hidden ui: unsafe { nil } } s.style_params.style = c.theme @@ -1421,7 +1424,7 @@ fn (s &Stack) get_horizontal_alignment(i int) HorizontalAlignment { //**** ChildrenParams ***** @[params] pub struct ChildrenParams { -mut: +pub mut: // add or remove or migrate at int = -1 widths Size = Size(-1.0) diff --git a/src/style_drawtextwidget.v b/src/style_drawtextwidget.v index 46dc31c3..95115e64 100644 --- a/src/style_drawtextwidget.v +++ b/src/style_drawtextwidget.v @@ -22,6 +22,7 @@ pub mut: text_size f64 text_align TextHorizontalAlign = .@none text_vertical_align TextVerticalAlign = .@none + cursor_color gx.Color = no_color } // Style with Text diff --git a/src/subwindow.v b/src/subwindow.v index abb8c623..5fa06e2f 100644 --- a/src/subwindow.v +++ b/src/subwindow.v @@ -43,6 +43,7 @@ pub mut: @[params] pub struct SubWindowParams { +pub: id string x int y int diff --git a/src/switch.v b/src/switch.v index b10f7118..9ceed08e 100644 --- a/src/switch.v +++ b/src/switch.v @@ -41,6 +41,7 @@ pub mut: @[params] pub struct SwitchParams { +pub: id string z_index int on_click SwitchFn = unsafe { nil } diff --git a/src/textbox.v b/src/textbox.v index 6c5fcee5..0d13b3bb 100644 --- a/src/textbox.v +++ b/src/textbox.v @@ -119,6 +119,7 @@ pub enum TextBoxMode { @[params] pub struct TextBoxParams { TextBoxStyleParams +pub: id string width int height int = 22 @@ -337,6 +338,10 @@ pub fn (mut tb TextBox) draw() { } pub fn (mut tb TextBox) draw_device(mut d DrawDevice) { + mut is_native_rendering := false + $if macos { + is_native_rendering = tb.ui.gg.native_rendering + } offset_start(mut tb) defer { offset_end(mut tb) @@ -392,13 +397,13 @@ pub fn (mut tb TextBox) draw_device(mut d DrawDevice) { // Placeholder if text == '' && placeholder != '' { dtw.draw_device_styled_text(d, tb.x + ui.textbox_padding_x, text_y, placeholder, - color: gx.gray + color: gx.gray // tb.text_color ) // Native text rendering $if macos { if tb.ui.gg.native_rendering { tb.ui.gg.draw_text(tb.x + ui.textbox_padding_x, text_y, placeholder, - color: gx.gray + color: gx.gray // tb.text_color ) } } @@ -408,31 +413,33 @@ pub fn (mut tb TextBox) draw_device(mut d DrawDevice) { // Selection box tb.draw_selection() // Native text rendering - $if macos { - if tb.ui.gg.native_rendering { - tb.ui.gg.draw_text(tb.x + ui.textbox_padding_x, text_y, text) - } - } - // The text doesn't fit, find the largest substring we can draw - if tb.large_text { // width > tb.width - 2 * ui.textbox_padding_x && !tb.is_password { - if !tb.is_focused || tb.read_only { - skip_idx := tb.skip_index_from_start(ustr, dtw) - dtw.draw_device_text(d, tb.x + ui.textbox_padding_x, text_y, ustr[..(skip_idx + - 1)].string()) - } else { - dtw.draw_device_text(d, tb.x + ui.textbox_padding_x, text_y, ustr[tb.draw_start..tb.draw_end].string()) - } + if is_native_rendering { + tb.ui.gg.draw_text(tb.x + ui.textbox_padding_x, text_y, text, + color: tb.style_params.text_color + ) } else { - if tb.is_password { - dtw.draw_device_text(d, tb.x + ui.textbox_padding_x, text_y, '*'.repeat(text_len)) + // The text doesn't fit, find the largest substring we can draw + if tb.large_text { // width > tb.width - 2 * ui.textbox_padding_x && !tb.is_password { + if !tb.is_focused || tb.read_only { + skip_idx := tb.skip_index_from_start(ustr, dtw) + dtw.draw_device_text(d, tb.x + ui.textbox_padding_x, text_y, ustr[..( + skip_idx + 1)].string()) + } else { + dtw.draw_device_text(d, tb.x + ui.textbox_padding_x, text_y, ustr[tb.draw_start..tb.draw_end].string()) + } } else { - if tb.justify != top_left { - mut aw := AdjustableWidget(tb) - dx, dy := aw.get_align_offset(tb.justify[0], tb.justify[1]) - dtw.draw_device_text(d, tb.x + ui.textbox_padding_x + dx, text_y + dy, - text) + if tb.is_password { + dtw.draw_device_text(d, tb.x + ui.textbox_padding_x, text_y, '*'.repeat(text_len)) } else { - dtw.draw_device_text(d, tb.x + ui.textbox_padding_x, text_y, text) + if tb.justify != top_left { + mut aw := AdjustableWidget(tb) + dx, dy := aw.get_align_offset(tb.justify[0], tb.justify[1]) + dtw.draw_device_text(d, tb.x + ui.textbox_padding_x + dx, + text_y + dy, text) + } else { + dtw.draw_device_text(d, tb.x + ui.textbox_padding_x, text_y, + text) + } } } } @@ -457,9 +464,14 @@ pub fn (mut tb TextBox) draw_device(mut d DrawDevice) { cursor_x += dtw.text_width(left) } } - // tb.ui.dd.draw_line(cursor_x, tb.y+2, cursor_x, tb.y-2+tb.height-1)//, gx.Black) - d.draw_rect_filled(cursor_x, tb.y + ui.textbox_padding_y, 1, tb.line_height, - gx.black) // , gx.Black) + if is_native_rendering { + tb.ui.gg.draw_rect_filled(cursor_x, tb.y + ui.textbox_padding_y, 1, tb.line_height, + tb.style_params.cursor_color) + } else { + // tb.ui.dd.draw_line(cursor_x, tb.y+2, cursor_x, tb.y-2+tb.height-1)//, gx.Black) + d.draw_rect_filled(cursor_x, tb.y + ui.textbox_padding_y, 1, tb.line_height, + tb.style_params.cursor_color) + } } } $if bb ? { diff --git a/src/style_textbox.v b/src/textbox_style.v similarity index 75% rename from src/style_textbox.v rename to src/textbox_style.v index 5efea708..dce2209d 100644 --- a/src/style_textbox.v +++ b/src/textbox_style.v @@ -30,10 +30,6 @@ pub mut: bg_color gx.Color = no_color } -pub fn textbox_style(p TextBoxStyleParams) TextBoxStyleParams { - return p -} - pub fn (ts TextBoxStyle) to_toml() string { mut toml_ := map[string]toml.Any{} toml_['bg_radius'] = ts.bg_radius @@ -44,6 +40,19 @@ pub fn (ts TextBoxStyle) to_toml() string { pub fn (mut ts TextBoxStyle) from_toml(a toml.Any) { ts.bg_radius = a.value('bg_radius').f32() ts.bg_color = HexColor(a.value('bg_color').string()).color() + ts.text_color = HexColor(a.value('text_color').string()).color() + if font_name := a.value_opt('text_font_name') { + ts.text_font_name = font_name.string() + } + if size := a.value_opt('text_size') { + ts.text_size = size.int() + } + if align := a.value_opt('text_align') { + ts.text_align = unsafe { TextHorizontalAlign(align.int()) } + } + if vertical_align := a.value_opt('text_vertical_align') { + ts.text_vertical_align = unsafe { TextVerticalAlign(vertical_align.int()) } + } } fn (mut t TextBox) load_style() { @@ -52,17 +61,21 @@ fn (mut t TextBox) load_style() { if t.style_params.style != no_style { style = t.style_params.style } - t.update_theme_style(style) + t.apply_theme_style(style) // forced overload default style t.update_style(t.style_params) } -pub fn (mut t TextBox) update_theme_style(theme string) { +pub fn (mut t TextBox) update_theme_style(style string) { + // println("update_style <$p.style>") + t.theme_style = style + t.apply_theme_style(style) +} + +fn (mut t TextBox) apply_theme_style(style string) { // println("update_style <$p.style>") - style := if theme == '' { 'default' } else { theme } if style != no_style && style in t.ui.styles { ts := t.ui.styles[style].tb - t.theme_style = theme t.update_shape_theme_style(ts) mut dtw := DrawTextWidget(t) dtw.update_theme_style(ts) diff --git a/src/tool_align.v b/src/tool_align.v index fa4c6230..cae99b95 100644 --- a/src/tool_align.v +++ b/src/tool_align.v @@ -18,12 +18,14 @@ pub enum HorizontalAlignment { } pub struct HorizontalAlignments { +pub: left []int center []int right []int } pub struct VerticalAlignments { +pub: top []int center []int bottom []int @@ -31,6 +33,7 @@ pub struct VerticalAlignments { // Anticipating replacement of VerticalAlignments pub struct Alignments { +pub: center []int left_top []int top []int diff --git a/src/tool_tooltip.v b/src/tool_tooltip.v index 074f257c..24f5fa31 100644 --- a/src/tool_tooltip.v +++ b/src/tool_tooltip.v @@ -38,6 +38,7 @@ mut: } pub struct TooltipMessage { +pub: text string side Side = .right } diff --git a/src/transition.v b/src/transition.v index a7ea152d..c5c1ade1 100644 --- a/src/transition.v +++ b/src/transition.v @@ -32,6 +32,7 @@ pub mut: @[params] pub struct TransitionParams { +pub: z_index int duration int animated_value &int = unsafe { nil } diff --git a/src/ui.v b/src/ui.v index db56f2c2..7300c87c 100644 --- a/src/ui.v +++ b/src/ui.v @@ -30,6 +30,7 @@ pub mut: keymods KeyMod styles map[string]Style style_colors []gx.Color + // run_fn fn () = unsafe { nil } mut: cb_image gg.Image // used only in checkbox.v @@ -113,6 +114,7 @@ fn (mut gui UI) idle_loop() { fn (mut gui UI) load_imgs() { // images + gui.load_img('arrow', $embed_file('assets/img/arrow.png').to_bytes(), 'assets/img/arrow.png') gui.load_img('arrow_black', $embed_file('assets/img/arrow_black.png').to_bytes(), 'assets/img/arrow_black.png') gui.load_img('arrow_white', $embed_file('assets/img/arrow_white.png').to_bytes(), @@ -145,15 +147,22 @@ fn (mut gui UI) load_imgs() { // complete the drawing system pub fn (mut gui UI) load_img(id string, b []u8, path string) { if mut gui.dd is DrawDeviceContext { - if img := gui.dd.create_image_from_byte_array(b) { + if mut img := gui.dd.create_image_from_byte_array(b) { + img.path = path gui.imgs[id] = img - gui.imgs[id].path = path } } } pub fn (gui &UI) img(id string) gg.Image { - return gui.imgs[id] + if img := gui.imgs[id] { + return img + } + eprintln('> present gui.imgs.keys(): ') + for k in gui.imgs.keys() { + eprintln(' k: ${k}') + } + panic('img with id: `${id}` not found') } pub fn (gui &UI) has_img(id string) bool { @@ -203,6 +212,13 @@ pub fn run(window &Window) { // waiting 2x this time should be enough to ensure the gui.loop // thread will exit before us, without using a waitgroup here too time.sleep(20 * time.millisecond) + + /* + if gui.run_fn != unsafe { nil } { + gui.run_fn() + gui.run_fn = unsafe { nil } + } + */ } } diff --git a/src/widget_checkbox.v b/src/widget_checkbox.v index f5f04458..e81cfca1 100644 --- a/src/widget_checkbox.v +++ b/src/widget_checkbox.v @@ -54,6 +54,7 @@ pub mut: @[params] pub struct CheckBoxParams { CheckBoxStyleParams +pub: id string x int y int diff --git a/src/window.v b/src/window.v index b4301f37..a6957db3 100644 --- a/src/window.v +++ b/src/window.v @@ -155,6 +155,8 @@ pub: enable_dragndrop bool = true max_dropped_files int = 5 max_dropped_file_path_length int = 2048 + min_width int = 100 + min_height int = 100 } pub fn window(cfg WindowParams) &Window { @@ -249,7 +251,8 @@ pub fn window(cfg WindowParams) &Window { Context: gg.new_context( width: width height: height - use_ortho: true // This is needed for 2D drawing + min_width: cfg.min_width + min_height: cfg.min_height create_window: true // TODO: Unused ? window_title: cfg.title resizable: resizable @@ -496,6 +499,10 @@ fn frame_native(mut w Window) { } */ + if w.on_draw != WindowFn(0) { + w.on_draw(w) + } + mut children := if unsafe { w.child_window == 0 } { w.children } else { w.child_window.children } // if w.child_window == 0 { // Render all widgets, including Canvas @@ -1265,6 +1272,15 @@ pub fn (w &Window) get_subscriber() &eventbus.Subscriber[string] { pub fn (mut window Window) resize(w int, h int) { window.width, window.height = w, h if mut window.ui.dd is DrawDeviceContext { + // Update ui.gg.ft.scale if the dpi has changed (dragging to another monitor) + window.dpi_scale = gg.dpi_scale() + window.ui.gg.scale = window.dpi_scale + if window.resizable { + mut ft_scale := &window.ui.gg.ft.scale + unsafe { + *ft_scale = window.ui.gg.scale + } + } window.ui.dd.resize(w, h) } for mut child in window.children { diff --git a/src/window_manager.v b/src/window_manager.v index 5d766835..6ff11d1c 100644 --- a/src/window_manager.v +++ b/src/window_manager.v @@ -22,6 +22,7 @@ pub mut: // inside an unique sokol Window @[params] pub struct WindowManagerParams { WindowParams +pub: scrollview bool kind WMMode apps map[string]Application diff --git a/src/window_style.v b/src/window_style.v index b921ea92..39e2c210 100644 --- a/src/window_style.v +++ b/src/window_style.v @@ -42,12 +42,11 @@ pub fn (mut w Window) load_style() { // l.update_theme_style(style) } -pub fn (mut w Window) update_theme_style(theme string) { +pub fn (mut w Window) update_theme_style(style string) { // println("update_style <$p.style>") - style := if theme == '' { 'default' } else { theme } if style != no_style && style in w.ui.styles { ws := w.ui.styles[style].win - w.theme_style = theme + w.theme_style = style w.bg_color = ws.bg_color } } @@ -57,3 +56,14 @@ fn (mut w Window) update_style(p WindowStyleParams) { w.bg_color = p.bg_color } } + +pub fn (mut w Window) apply_style() { + w.load_style() + for _, mut widget in w.widgets { + if mut widget is WidgetThemeStyle { + mut wdgt := widget // work-around v compiler smart-casting bug + // wdgt.update_theme_style(w.theme_style) + wdgt.load_style() + } + } +} \ No newline at end of file diff --git a/tools/tools.v b/tools/tools.v index a00f846a..dadc8f29 100644 --- a/tools/tools.v +++ b/tools/tools.v @@ -49,6 +49,7 @@ pub fn tree_layout(layout ui.Layout) uic.Tree { @[params] pub struct TreeViewLayoutParams { +pub: id string = 'tvlc' layout ui.Layout = ui.empty_stack widget ui.Widget = ui.empty_stack diff --git a/webview/webview.v b/webview/webview.v index 5240ff12..4a5400fb 100644 --- a/webview/webview.v +++ b/webview/webview.v @@ -8,12 +8,14 @@ type NavFinishedFn = fn (url string) pub struct WebView { // widget ui.Widget url string - obj voidptr mut: nav_finished_fn NavFinishedFn = NavFinishedFn(0) +pub: + obj voidptr } pub struct Config { +pub: url string title string // parent &ui.Window @@ -53,6 +55,13 @@ pub fn get_global_js_val() string { return '' } +pub fn get_global_cookie_val() string { + $if macos { + return C.darwin_get_webview_cookie_val() + } + return '' +} + pub fn (mut wv WebView) on_navigate_fn(nav_callback fn (url string)) { wv.nav_finished_fn = nav_callback } diff --git a/webview/webview_darwin.c.v b/webview/webview_darwin.c.v index 6d55deaa..07119617 100644 --- a/webview/webview_darwin.c.v +++ b/webview/webview_darwin.c.v @@ -8,14 +8,16 @@ fn C.new_darwin_web_view(url string, title string, js_on_init string) voidptr // fn create_darwin_web_view(url string, title string) { // C.new_darwin_web_view(url, title) //} -fn C.darwin_webview_eval_js(obj voidptr, js string, result &string) string +// fn C.darwin_webview_eval_js(obj voidptr, js string, result &string) string +fn C.darwin_webview_eval_js(obj voidptr, js string) string fn C.darwin_webview_load(obj voidptr, url string) +fn C.darwin_delete_all_cookies2(obj voidptr) fn C.darwin_webview_close() -pub fn (w &WebView) eval_js(s string, result &string) { - C.darwin_webview_eval_js(w.obj, s, result) +pub fn (w &WebView) eval_js(s string) { //, result &string) { + C.darwin_webview_eval_js(w.obj, s) //, result) } pub fn (w &WebView) load(url string) { @@ -28,4 +30,9 @@ pub fn delete_all_cookies() { C.darwin_delete_all_cookies() } +pub fn (w &WebView) delete_all_cookies() { + C.darwin_delete_all_cookies2(w.obj) +} + fn C.darwin_get_webview_js_val() string +fn C.darwin_get_webview_cookie_val() string diff --git a/webview/webview_darwin.m b/webview/webview_darwin.m index f657be69..37142b3c 100644 --- a/webview/webview_darwin.m +++ b/webview/webview_darwin.m @@ -6,8 +6,10 @@ NSString *nsstring(string); string g_vui_webview_js_val; +string g_vui_webview_cookie_val; @interface MyBrowserDelegate : NSObject { + //@public //@public // NSWindow *parent_window; // void (*nav_finished_fn)(string); @@ -16,6 +18,13 @@ @interface MyBrowserDelegate : NSObject { @end @implementation MyBrowserDelegate + +- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { +// NSLog(@"Navigation finished"); +} + + + @end @interface MyScriptHandler : NSObject { @@ -26,6 +35,7 @@ @interface MyScriptHandler : NSObject { @implementation MyScriptHandler - (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message { // [_ObjcLog logWithFile:"[WKWebView]" function:[message.name UTF8String] line:0 color:[UIColor whiteColor] message:message.body]; +puts(".m received script message"); NSLog(message.body); g_vui_webview_js_val = string_clone(tos2([message.body UTF8String])); // *resultt = string_clone(tos2([result UTF8String])); @@ -38,6 +48,11 @@ string darwin_get_webview_js_val() { return g_vui_webview_js_val; } +string darwin_get_webview_cookie_val() { + return g_vui_webview_cookie_val; +} + MyBrowserDelegate *del ;//= [[MyBrowserDelegate alloc] init]; + void *new_darwin_web_view(string url, string title, string js_on_init) { [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; bool enable_js = 1; @@ -55,8 +70,9 @@ string darwin_get_webview_js_val() { // initWithFrame:frame //ns->view.frame configuration:config]; webView.customUserAgent = - @"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 " - @"(KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36"; +// @"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 " +// @"(KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36"; + @"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.1 Safari/605.1.15"; //[webView retain]; // Create a new window @@ -65,7 +81,7 @@ string darwin_get_webview_js_val() { NSWindowStyleMaskResizable; NSRect window_rect = - NSMakeRect(0, 0, 1000, 600); //_sapp.window_width, _sapp.window_height); + NSMakeRect(0, 0, 1000, 800); //_sapp.window_width, _sapp.window_height); g_webview_window = [[NSWindow alloc] initWithContentRect:window_rect styleMask:style @@ -74,11 +90,13 @@ string darwin_get_webview_js_val() { g_webview_window.title = nsstring(title); g_webview_window.releasedWhenClosed = false; - MyBrowserDelegate *del = [[MyBrowserDelegate alloc] init]; +// MyBrowserDelegate *del = [[MyBrowserDelegate alloc] init]; + del = [[MyBrowserDelegate alloc] init]; // del->parent_window = ns->w; // del->nav_finished_fn = cfg.nav_finished_fn; // del->js_on_init = cfg.js_on_init; [webView setNavigationDelegate:del]; +// del.webView = webView; // webView.navigationDelegate = ns->view; NSURL *nsurl = [NSURL URLWithString:nsstring(url)]; NSURLRequest *nsrequest = [NSURLRequest requestWithURL:nsurl]; @@ -113,7 +131,7 @@ string darwin_get_webview_js_val() { return (__bridge void *)(webView); } -void darwin_webview_eval_js(void *web_view_, string js, string *resultt) { +void darwin_webview_eval_js(void *web_view_, string js) { //, string *resultt) { WKWebView *web_view = (__bridge WKWebView *)(web_view_); //__block NSString *resultString = nil; @@ -123,10 +141,11 @@ void darwin_webview_eval_js(void *web_view_, string js, string *resultt) { // completionHandler:nil]; [web_view evaluateJavaScript:nsstring(js) completionHandler:^(id result, NSError *error) { - NSLog(@"DA RESULT = %@", result); + NSLog(@"eval js result = %@", result); // finished = YES; - if (result != nil) { - *resultt = string_clone(tos2([result UTF8String])); + if (result != nil&& result != [NSNull null] ) { +// *resultt = string_clone(tos2([result UTF8String])); +g_vui_webview_js_val = string_clone(tos2([result UTF8String])); } }]; @@ -144,9 +163,38 @@ void darwin_webview_load(void *web_view_, string url) { [web_view loadRequest:nsrequest]; } +void darwin_delete_all_cookies2(void *web_view_) { + WKWebView *web_view = (__bridge WKWebView *)(web_view_); + // Assume webView is your WKWebView instance +WKWebsiteDataStore *dataStore = web_view.configuration.websiteDataStore; + +// Fetch all website data types +NSSet *websiteDataTypes = [WKWebsiteDataStore allWebsiteDataTypes]; + +// You can specify a date in the past to fetch all cookies +NSDate *dateFrom = [NSDate dateWithTimeIntervalSince1970:0]; + +// Fetch data records +[dataStore fetchDataRecordsOfTypes:websiteDataTypes + completionHandler:^(NSArray *records) { + for (WKWebsiteDataRecord *record in records) { + // Check if the record is for the domain you want to delete cookies for +// if ([record.displayName containsString:@"domain-you-want-to-delete-cookies-for.com"]) { + // Delete the cookies + [dataStore removeDataOfTypes:record.dataTypes + forDataRecords:@[record] + completionHandler:^{ + NSLog(@"Cookies for %@ deleted successfully", record.displayName); + }]; +// } + } +}]; + } + void darwin_webview_close() { [g_webview_window close]; } void darwin_delete_all_cookies() { + /* NSHTTPCookie *cookie; NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage]; @@ -154,4 +202,19 @@ void darwin_delete_all_cookies() { for (cookie in cookies) { [cookieJar deleteCookie:cookie]; } + */ + // Get the default website data store +WKWebsiteDataStore *dataStore = [WKWebsiteDataStore defaultDataStore]; + +// Fetch data types to delete +NSSet *websiteDataTypes = [WKWebsiteDataStore allWebsiteDataTypes]; + +// Set the date from which to delete data (use [NSDate distantPast] to delete all data) +NSDate *dateFrom = [NSDate distantPast]; + +// Delete the data +[dataStore removeDataOfTypes:websiteDataTypes modifiedSince:dateFrom completionHandler:^{ + NSLog(@"All cookies deleted"); +}]; + }