Skip to content

Instantly share code, notes, and snippets.

@lazalong
Last active November 29, 2023 22:30
Show Gist options
  • Save lazalong/6b15cfca6301b44b90baac54f6cbe79c to your computer and use it in GitHub Desktop.
Save lazalong/6b15cfca6301b44b90baac54f6cbe79c to your computer and use it in GitHub Desktop.
Test code to rework the V file browser component
/*
Test code to rework the file browser component.
NOTE:
- Some truct & fcts have '_LL' or '_ll' appended to differentiate them from existing ones.
They contain some changes to make the subwindow match the menubar style
- Multiple small changes to make the file browser more stylish
Issues in v.ui code IMO:
- The decoration is see subwindow.h in draw_device() is hard coded (ie gx.black) and can't be set
- The panel in the filebrowser is limited in height and truncates if there is too many lines. I didn't find yet where this is set. Help appreciated
- In FileBrowserParams, settings the Dirs to '/' will not show the content if you click on it. You need to use './'. At least on Windows.
- Unclear where the initialisation of the filebrowser_subwindow should happen
*/
import ui
import ui.component as uic
import gx
import os
const (
win_width = 800
win_height = 600
// See ui/src/menu.v
menu_bar_color = gx.rgb(230, 230, 230)
menu_bg_color = gx.rgb(240, 240, 240)
menu_bg_color_hover = gx.rgb(220, 220, 220)
menu_border_color = gx.rgb(123, 123, 123)
)
__global (
g_filebrowser_subwindow_initialised bool
)
struct App {
mut:
window &ui.Window = unsafe { nil }
// line_numbers bool
default_text string = 'test test test'
default_text2 string = 'test2 test2 test2'
}
fn main() {
mut app := &App{
window: 0
}
g_filebrowser_subwindow_initialised = false
// dirs = dirs.map(os.real_path(it))
dirs := 'D:/Documents/_Projects/_VLang/projects/30_Sample_FileMenu'
mut window := ui.window(
width: win_width
height: win_height
title: 'V UI Edit: ${dirs}'
native_message: false
mode: .resizable
on_init: init
// on_char: on_char
children: [
]
layout: ui.column(
id: 'main'
spacing: 5
children: [
ui.column(
margin_: 0
heights: [ui.compact, ui.compact, ui.stretch]
children: [
uic.hideable_stack(
id: 'openfile'
layout: filebrowser_stack_ll(
// todo ?s
)
),
ui.menubar(
items: [
ui.menuitem(
text: 'Open'
action: menu_open
),
ui.menuitem(
text: 'New'
action: menu_new
),
ui.menuitem(
text: 'Save'
action: menu_save
)
]
),
ui.textbox(
id: 'edit'
mode: .multiline
//height: 200
bg_color: gx.Color{0, 0, 0, 128}
)
]
)
]
)
)
app.window = window
ui.run(window)
}
const (
// filebrowser_subwindow_id_ll = '_sw_filebrowser'
newfilebrowser_subwindow_id_ll = '_sw_newfilebrowser'
)
@[params]
pub struct FileBrowserParams_LL {
id string
// dirs []string = ['..', os.expand_tilde_to_home('~'), './'] // TODO: just using '/' will not show the content when we click on it
dirs []string = ['..', './'] // TODO: just using '/' will not show the content when we click on it
text_ok string = 'Open'
text_cancel string = 'Cancel'
height int = int(ui.compact)
width int = int(ui.compact)
z_index int
folder_only bool
filter_types []string
with_fpath bool
hidden bool
bg_color gx.Color = gx.red // gx.hex(0xfcf4e4ff)
on_click_ok ui.ButtonFn = ui.ButtonFn(0)
on_click_cancel ui.ButtonFn = ui.ButtonFn(0)
}
@[params]
pub struct FileBrowserSubWindowParams_LL {
FileBrowserParams_LL
x int
y int
}
pub fn filebrowser_stack_ll(p FileBrowserParams_LL) &ui.Stack {
btn_cancel := ui.button(
id: ui.component_id(p.id, 'btn_cancel')
text: p.text_cancel
//radius: 5
bg_color: menu_bg_color
z_index: 100
on_click: p.on_click_cancel
)
mut btn_ok := ui.button(
id: ui.component_id(p.id, 'btn_ok')
text: p.text_ok
//radius: 5
bg_color: menu_bg_color
z_index: 100
on_click: p.on_click_ok
)
tv_layout := uic.dirtreeview_stack(
id: ui.component_id(p.id, 'tvd')
trees: p.dirs
folder_only: p.folder_only
filter_types: p.filter_types
bg_color: ui.transparent
)
mut children := [
ui.Widget(ui.column(
id: ui.component_id(p.id, 'tvd_col')
scrollview: true
// heights: ui.compact
bg_color: p.bg_color
children: [tv_layout]
)),
ui.Widget(ui.row(
id: ui.component_id(p.id, 'btns_row')
widths: [ui.stretch, 50, ui.stretch, 50, ui.stretch]
heights: 20.0
margin_: 5
bg_color: menu_bar_color
children: [ui.spacing(), btn_ok, ui.spacing(), btn_cancel, ui.spacing()]
)),
]
if p.with_fpath {
tb := ui.textbox(
id: ui.component_id(p.id, 'tb'),
placeholder: 'File path...'
bg_color: gx.light_gray
)
children.insert(1, ui.Widget(tb))
}
mut layout := ui.column(
id: ui.component_id(p.id, 'layout')
width: p.width
height: p.height
heights: if p.with_fpath { [ui.stretch, 20, 30] } else { [ui.stretch, 30] }
children: children
)
tv := uic.treeview_component(tv_layout) // TODO: consider making it a _LL one for testing
// The heart of the file browser !
mut fb := &uic.FileBrowserComponent{ // TODO: consider making it a _LL one for testing
layout: layout
btn_ok: btn_ok
btn_cancel: btn_cancel
tv: tv
}
ui.component_connect(fb, layout, btn_ok, btn_cancel)
// TODO: Where would be logical place to call this? In init() doesn't work
if !g_filebrowser_subwindow_initialised {
println(' init menufile. Called only once...')
layout.on_init = menufile_init
g_filebrowser_subwindow_initialised = true
}
return layout
}
// see subwindow_filebrowser.v filebrowser_subwindow_add
fn create_filebrowser_subwindow(mut w ui.Window, p FileBrowserSubWindowParams_LL) {
// only once
if !ui.Layout(w).has_child_id(newfilebrowser_subwindow_id_ll) {
w.subwindows << ui.subwindow(
decoration: false // TODO: set to gray the rounded_rect_filled (see subwindow.h in draw_device() !!!) and - better a text 'Open file...'
id: newfilebrowser_subwindow_id_ll
x: p.x
y: p.y
layout: filebrowser_stack_ll(p.FileBrowserParams_LL)
)
}
}
fn menu_open(item &ui.MenuItem) {
println('Open')
// See subwindow_filebrowser.h newfilebrowser_subwindow_visible
w := item.menu.ui.window
mut s := w.get_or_panic[ui.SubWindow](newfilebrowser_subwindow_id_ll)
s.set_visible(s.hidden)
s.update_layout()
}
pub fn newfilebrowser_subwindow_close(w &ui.Window, id string) {
mut s := w.get_or_panic[ui.SubWindow](id) // i.e. newfilebrowser_subwindow_id_ll
s.set_visible(false)
s.update_layout()
}
fn menu_new(item &ui.MenuItem) {
println('New')
}
fn menu_save(item &ui.MenuItem) {
println('Save')
}
fn init(mut w &ui.Window) {
println('init()')
// Can't call create_filebrowser_subwindow() here
}
pub fn menufile_init(layout &ui.Stack) {
mut window := layout.ui.window
create_filebrowser_subwindow(
mut window,
FileBrowserSubWindowParams_LL { // TODO: Personally I prefer to put explicitly the struct that is set here.. not implicitly
id: newfilebrowser_subwindow_id_ll // ui.component_id_from(layout.id, 'fb')
folder_only: false
width: 400
height: 300
x: 50
y: 50
bg_color: menu_bg_color
on_click_ok: btn_open_ok
on_click_cancel: btn_open_cancel
}
)
}
fn btn_open_ok(b &ui.Button) {
println('ok')
fb := uic.filebrowser_component(b)
fi := fb.selected_full_title()
newfilebrowser_subwindow_close(b.ui.window, ui.component_parent_id(b.id))
println('File/Folder to open: ${fb.selected_full_title()}')
// mut dtv := uic.treeview_component_from_id(b.ui.window, ui.component_id_from_by(b.id, 2, 'dtv'))
// mut mf := uic.menufile_component_from_id(b.ui.window, ui.component_parent_id_by(b.id, 2))
// mf.folder_to_open = fb.selected_full_title()
// dtv.open_dir(mf.folder_to_open)
}
fn btn_open_cancel(b &ui.Button) {
println('cancel open')
newfilebrowser_subwindow_close(b.ui.window, ui.component_parent_id(b.id))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment