floating windows
parent
705606e92a
commit
2a4e85c868
|
@ -101,6 +101,7 @@ PanelType :: union {
|
||||||
|
|
||||||
FileBufferPanel :: struct {
|
FileBufferPanel :: struct {
|
||||||
buffer: FileBuffer,
|
buffer: FileBuffer,
|
||||||
|
viewed_symbol: Maybe(string),
|
||||||
|
|
||||||
// only used for initialization
|
// only used for initialization
|
||||||
file_path: string,
|
file_path: string,
|
||||||
|
|
|
@ -59,39 +59,45 @@ draw :: proc(state: ^State) {
|
||||||
new_ui.max_size.x = state.screen_width
|
new_ui.max_size.x = state.screen_width
|
||||||
new_ui.max_size.y = state.screen_height
|
new_ui.max_size.y = state.screen_height
|
||||||
|
|
||||||
ui.open_element(new_ui, nil, {
|
ui.open_element(new_ui, nil,
|
||||||
dir = .LeftToRight,
|
{
|
||||||
kind = {ui.Grow{}, ui.Grow{}},
|
dir = .LeftToRight,
|
||||||
})
|
kind = {ui.Grow{}, ui.Grow{}},
|
||||||
|
},
|
||||||
|
style = {
|
||||||
|
background_color = .Background1
|
||||||
|
}
|
||||||
|
)
|
||||||
{
|
{
|
||||||
|
floating_panels := [16]int{}
|
||||||
|
num_floating := 0
|
||||||
|
|
||||||
for i in 0..<len(state.panels.data) {
|
for i in 0..<len(state.panels.data) {
|
||||||
if panel, ok := util.get(&state.panels, i).?; ok {
|
if panel, ok := util.get(&state.panels, i).?; ok {
|
||||||
if panel.render != nil {
|
if panel.render != nil {
|
||||||
|
if panel.is_floating {
|
||||||
background_color: theme.PaletteColor = .Background1 if panel.id == state.current_panel else .Background2
|
if num_floating < len(floating_panels) {
|
||||||
|
floating_panels[num_floating] = i
|
||||||
ui.open_element(new_ui, nil,
|
num_floating += 1
|
||||||
{
|
|
||||||
dir = .LeftToRight,
|
|
||||||
kind = {ui.Grow{}, ui.Grow{}},
|
|
||||||
},
|
|
||||||
style = {
|
|
||||||
border = {.Left, .Right, .Top, .Bottom },
|
|
||||||
border_color = .Green,
|
|
||||||
background_color = background_color,
|
|
||||||
}
|
}
|
||||||
)
|
} else {
|
||||||
{
|
|
||||||
panel->render(state)
|
panel->render(state)
|
||||||
}
|
}
|
||||||
ui.close_element(new_ui)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i in 0..<num_floating {
|
||||||
|
panel_id := floating_panels[i]
|
||||||
|
|
||||||
|
if panel, ok := util.get(&state.panels, panel_id).?; ok {
|
||||||
|
panel->render(state)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ui.close_element(new_ui)
|
ui.close_element(new_ui)
|
||||||
|
|
||||||
ui.compute_layout_2(new_ui)
|
ui.compute_layout(new_ui)
|
||||||
ui.draw(new_ui, state)
|
ui.draw(new_ui, state)
|
||||||
|
|
||||||
// TODO: figure out when to not show the input help menu
|
// TODO: figure out when to not show the input help menu
|
||||||
|
|
|
@ -69,6 +69,24 @@ make_file_buffer_panel :: proc(file_path: string, line: int = 0, col: int = 0) -
|
||||||
s := transmute(^ui.State)state.ui
|
s := transmute(^ui.State)state.ui
|
||||||
render_file_buffer(state, s, &panel_state.buffer)
|
render_file_buffer(state, s, &panel_state.buffer)
|
||||||
|
|
||||||
|
if viewed_symbol, ok := panel_state.viewed_symbol.?; ok {
|
||||||
|
ui.open_element(s, nil,
|
||||||
|
{
|
||||||
|
dir = .TopToBottom,
|
||||||
|
kind = {ui.Fit{}, ui.Fit{}},
|
||||||
|
floating = true,
|
||||||
|
},
|
||||||
|
style = {
|
||||||
|
background_color = .Background2,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ui.open_element(s, viewed_symbol, {})
|
||||||
|
ui.close_element(s)
|
||||||
|
}
|
||||||
|
ui.close_element(s)
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -143,10 +161,12 @@ render_file_buffer :: proc(state: ^core.State, s: ^ui.State, buffer: ^core.FileB
|
||||||
|
|
||||||
file_buffer_leader_actions :: proc(input_map: ^core.InputActions) {
|
file_buffer_leader_actions :: proc(input_map: ^core.InputActions) {
|
||||||
core.register_key_action(input_map, .K, proc(state: ^core.State, user_data: rawptr) {
|
core.register_key_action(input_map, .K, proc(state: ^core.State, user_data: rawptr) {
|
||||||
buffer := &(&(transmute(^core.Panel)user_data).type.(core.FileBufferPanel)).buffer
|
panel := transmute(^core.Panel)user_data
|
||||||
|
panel_state := &panel.type.(core.FileBufferPanel)
|
||||||
|
buffer := &panel_state.buffer
|
||||||
|
|
||||||
ts.update_cursor(&buffer.tree, buffer.history.cursor.line, buffer.history.cursor.col)
|
ts.update_cursor(&buffer.tree, buffer.history.cursor.line, buffer.history.cursor.col)
|
||||||
ts.print_node_type(&buffer.tree)
|
panel_state.viewed_symbol = ts.print_node_type(&buffer.tree)
|
||||||
|
|
||||||
core.reset_input_map(state)
|
core.reset_input_map(state)
|
||||||
}, "View Symbol")
|
}, "View Symbol")
|
||||||
|
@ -260,6 +280,13 @@ file_buffer_input_actions :: proc(input_map: ^core.InputActions) {
|
||||||
buffer.selection = core.new_selection(buffer.history.cursor);
|
buffer.selection = core.new_selection(buffer.history.cursor);
|
||||||
}, "enter visual mode");
|
}, "enter visual mode");
|
||||||
|
|
||||||
|
core.register_key_action(input_map, .ESCAPE, proc(state: ^core.State, user_data: rawptr) {
|
||||||
|
panel := transmute(^core.Panel)user_data
|
||||||
|
panel_state := &panel.type.(core.FileBufferPanel)
|
||||||
|
buffer := &panel_state.buffer
|
||||||
|
|
||||||
|
panel_state.viewed_symbol = nil
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
file_buffer_visual_actions :: proc(input_map: ^core.InputActions) {
|
file_buffer_visual_actions :: proc(input_map: ^core.InputActions) {
|
||||||
|
|
|
@ -48,6 +48,7 @@ make_grep_panel :: proc() -> core.Panel {
|
||||||
|
|
||||||
return core.Panel {
|
return core.Panel {
|
||||||
type = core.GrepPanel {},
|
type = core.GrepPanel {},
|
||||||
|
is_floating = true,
|
||||||
drop = proc(panel: ^core.Panel, state: ^core.State) {
|
drop = proc(panel: ^core.Panel, state: ^core.State) {
|
||||||
panel_state := &panel.type.(core.GrepPanel)
|
panel_state := &panel.type.(core.GrepPanel)
|
||||||
|
|
||||||
|
@ -147,10 +148,16 @@ make_grep_panel :: proc() -> core.Panel {
|
||||||
if panel_state, ok := &panel.type.(core.GrepPanel); ok {
|
if panel_state, ok := &panel.type.(core.GrepPanel); ok {
|
||||||
s := transmute(^ui.State)state.ui
|
s := transmute(^ui.State)state.ui
|
||||||
|
|
||||||
ui.open_element(s, nil, {
|
ui.open_element(s, nil,
|
||||||
dir = .TopToBottom,
|
{
|
||||||
kind = {ui.Grow{}, ui.Grow{}}
|
dir = .TopToBottom,
|
||||||
})
|
kind = {ui.Grow{}, ui.Grow{}},
|
||||||
|
floating = true,
|
||||||
|
},
|
||||||
|
style = {
|
||||||
|
background_color = .Background1,
|
||||||
|
},
|
||||||
|
)
|
||||||
{
|
{
|
||||||
// query results and file contents side-by-side
|
// query results and file contents side-by-side
|
||||||
ui.open_element(s, nil, {
|
ui.open_element(s, nil, {
|
||||||
|
@ -196,7 +203,7 @@ make_grep_panel :: proc() -> core.Panel {
|
||||||
style.background_color = .Background2
|
style.background_color = .Background2
|
||||||
}
|
}
|
||||||
|
|
||||||
ui.open_element(s, result.file_path, {}, style)
|
ui.open_element(s, result.file_path[len(state.directory):], {}, style)
|
||||||
ui.close_element(s)
|
ui.close_element(s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -217,9 +224,14 @@ make_grep_panel :: proc() -> core.Panel {
|
||||||
ui.close_element(s)
|
ui.close_element(s)
|
||||||
|
|
||||||
// text input
|
// text input
|
||||||
ui.open_element(s, nil, {
|
ui.open_element(s, nil,
|
||||||
kind = {ui.Grow{}, ui.Exact(state.source_font_height)}
|
{
|
||||||
})
|
kind = {ui.Grow{}, ui.Exact(state.source_font_height)}
|
||||||
|
},
|
||||||
|
style = {
|
||||||
|
background_color = .Background2
|
||||||
|
}
|
||||||
|
)
|
||||||
{
|
{
|
||||||
defer ui.close_element(s)
|
defer ui.close_element(s)
|
||||||
|
|
||||||
|
|
|
@ -349,15 +349,15 @@ load_highlights :: proc(state: ^State) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print_node_type :: proc(state: ^State) {
|
print_node_type :: proc(state: ^State) -> Maybe(string) {
|
||||||
if state.tree == nil {
|
if state.tree == nil {
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
current_node := tree_cursor_current_node(&state.cursor)
|
current_node := tree_cursor_current_node(&state.cursor)
|
||||||
if node_is_null(current_node) {
|
if node_is_null(current_node) {
|
||||||
log.error("Current node is null after goto_first_child")
|
log.error("Current node is null after goto_first_child")
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
node_type_str := node_type(current_node)
|
node_type_str := node_type(current_node)
|
||||||
|
@ -376,4 +376,6 @@ print_node_type :: proc(state: ^State) {
|
||||||
log.infof("Node position: (%d:%d) to (%d:%d)",
|
log.infof("Node position: (%d:%d) to (%d:%d)",
|
||||||
start_point.row+1, start_point.column+1,
|
start_point.row+1, start_point.column+1,
|
||||||
end_point.row+1, end_point.column+1)
|
end_point.row+1, end_point.column+1)
|
||||||
|
|
||||||
|
return string(node_type_str)
|
||||||
}
|
}
|
120
src/ui/ui.odin
120
src/ui/ui.odin
|
@ -48,6 +48,8 @@ UI_Layout :: struct {
|
||||||
kind: [2]UI_Size_Kind,
|
kind: [2]UI_Size_Kind,
|
||||||
size: [2]int,
|
size: [2]int,
|
||||||
pos: [2]int,
|
pos: [2]int,
|
||||||
|
|
||||||
|
floating: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
UI_Size_Kind :: union {
|
UI_Size_Kind :: union {
|
||||||
|
@ -82,8 +84,11 @@ open_element :: proc(state: ^State, kind: UI_Element_Kind, layout: UI_Layout, st
|
||||||
layout = layout,
|
layout = layout,
|
||||||
style = style,
|
style = style,
|
||||||
}
|
}
|
||||||
e.layout.pos = state.curr_elements[state.num_curr].layout.pos
|
|
||||||
e.layout.size = state.curr_elements[state.num_curr].layout.size
|
if !e.layout.floating {
|
||||||
|
e.layout.pos = state.curr_elements[state.num_curr].layout.pos
|
||||||
|
e.layout.size = state.curr_elements[state.num_curr].layout.size
|
||||||
|
}
|
||||||
|
|
||||||
if parent, ok := state.current_open_element.?; ok {
|
if parent, ok := state.current_open_element.?; ok {
|
||||||
e.parent = parent
|
e.parent = parent
|
||||||
|
@ -130,9 +135,9 @@ close_element :: proc(state: ^State, loc := #caller_location) -> UI_Layout {
|
||||||
|
|
||||||
case Exact: { e.layout.size.x = int(v) }
|
case Exact: { e.layout.size.x = int(v) }
|
||||||
case Fit: {
|
case Fit: {
|
||||||
child_index := e.first
|
it := e.first
|
||||||
for child_index != nil {
|
for child in iterate_siblings(state, &it) {
|
||||||
child := &state.curr_elements[child_index.?]
|
if child.layout.floating { continue }
|
||||||
|
|
||||||
switch e.layout.dir {
|
switch e.layout.dir {
|
||||||
case .RightToLeft: fallthrough
|
case .RightToLeft: fallthrough
|
||||||
|
@ -145,8 +150,6 @@ close_element :: proc(state: ^State, loc := #caller_location) -> UI_Layout {
|
||||||
e.layout.size.x = math.max(e.layout.size.x, child.layout.size.x)
|
e.layout.size.x = math.max(e.layout.size.x, child.layout.size.x)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
child_index = child.next
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case Grow: {
|
case Grow: {
|
||||||
|
@ -173,9 +176,9 @@ close_element :: proc(state: ^State, loc := #caller_location) -> UI_Layout {
|
||||||
|
|
||||||
case Exact: { e.layout.size.y = int(v) }
|
case Exact: { e.layout.size.y = int(v) }
|
||||||
case Fit: {
|
case Fit: {
|
||||||
child_index := e.first
|
it := e.first
|
||||||
for child_index != nil {
|
for child in iterate_siblings(state, &it) {
|
||||||
child := &state.curr_elements[child_index.?]
|
if child.layout.floating { continue }
|
||||||
|
|
||||||
switch e.layout.dir {
|
switch e.layout.dir {
|
||||||
case .RightToLeft: fallthrough
|
case .RightToLeft: fallthrough
|
||||||
|
@ -188,8 +191,6 @@ close_element :: proc(state: ^State, loc := #caller_location) -> UI_Layout {
|
||||||
e.layout.size.y += child.layout.size.y
|
e.layout.size.y += child.layout.size.y
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
child_index = child.next
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case Grow: { /* Done in the Grow pass */ }
|
case Grow: { /* Done in the Grow pass */ }
|
||||||
|
@ -206,18 +207,64 @@ close_element :: proc(state: ^State, loc := #caller_location) -> UI_Layout {
|
||||||
}
|
}
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
non_fit_parent_size :: proc(state: ^State, index: int, axis: int) -> [2]int {
|
iterate_siblings :: proc(state: ^State, sibling: ^Maybe(int)) -> (e: ^UI_Element, index: int, cond: bool) {
|
||||||
|
if sibling == nil || sibling^ == nil {
|
||||||
|
cond = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e = &state.curr_elements[sibling.?]
|
||||||
|
index = sibling.?
|
||||||
|
cond = true
|
||||||
|
|
||||||
|
sibling^ = e.next
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
iterate_siblings_reverse :: proc(state: ^State, sibling: ^Maybe(int)) -> (e: ^UI_Element, index: int, cond: bool) {
|
||||||
|
if sibling == nil || sibling^ == nil {
|
||||||
|
cond = false
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
e = &state.curr_elements[sibling.?]
|
||||||
|
index = sibling.?
|
||||||
|
cond = true
|
||||||
|
|
||||||
|
sibling^ = e.prev
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
non_fit_parent_size :: proc(state: ^State, index: int, axis: int) -> int {
|
||||||
if _, ok := state.curr_elements[index].layout.kind[axis].(Fit); ok {
|
if _, ok := state.curr_elements[index].layout.kind[axis].(Fit); ok {
|
||||||
if parent_index, ok := state.curr_elements[index].parent.?; ok {
|
if parent_index, ok := state.curr_elements[index].parent.?; ok && !state.curr_elements[index].layout.floating {
|
||||||
return non_fit_parent_size(state, parent_index, axis)
|
return non_fit_parent_size(state, parent_index, axis)
|
||||||
} else {
|
} else {
|
||||||
return state.max_size
|
return state.max_size[axis]
|
||||||
}
|
}
|
||||||
|
} else if state.curr_elements[index].layout.floating {
|
||||||
|
return state.max_size[axis]
|
||||||
} else {
|
} else {
|
||||||
return state.curr_elements[index].layout.size
|
return state.curr_elements[index].layout.size[axis]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
prev_non_floating :: proc(state: ^State, index: Maybe(int)) -> Maybe(int) {
|
||||||
|
it := index
|
||||||
|
for sibling, index in iterate_siblings_reverse(state, &it) {
|
||||||
|
if sibling.layout.floating { continue }
|
||||||
|
|
||||||
|
return index
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
grow_children :: proc(state: ^State, index: int) {
|
grow_children :: proc(state: ^State, index: int) {
|
||||||
e := &state.curr_elements[index]
|
e := &state.curr_elements[index]
|
||||||
|
@ -228,9 +275,14 @@ grow_children :: proc(state: ^State, index: int) {
|
||||||
children_size: [2]int
|
children_size: [2]int
|
||||||
num_growing: [2]int
|
num_growing: [2]int
|
||||||
|
|
||||||
child_index := e.first
|
has_floating := false
|
||||||
for child_index != nil {
|
|
||||||
child := &state.curr_elements[child_index.?]
|
it := e.first
|
||||||
|
for child in iterate_siblings(state, &it) {
|
||||||
|
if child.layout.floating {
|
||||||
|
has_floating = true
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if _, ok := child.layout.kind.x.(Grow); ok {
|
if _, ok := child.layout.kind.x.(Grow); ok {
|
||||||
num_growing.x += 1
|
num_growing.x += 1
|
||||||
|
@ -258,37 +310,33 @@ grow_children :: proc(state: ^State, index: int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
child_index = child.next
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if num_growing.x > 0 || num_growing.y > 0 {
|
if num_growing.x > 0 || num_growing.y > 0 {
|
||||||
remaining_size := [2]int{ x_e.x, y_e.y } - children_size
|
remaining_size := [2]int{ x_e, y_e } - children_size
|
||||||
to_grow: [2]int
|
to_grow: [2]int
|
||||||
to_grow.x = 0 if num_growing.x < 1 else remaining_size.x/num_growing.x
|
to_grow.x = 0 if num_growing.x < 1 else remaining_size.x/num_growing.x
|
||||||
to_grow.y = 0 if num_growing.y < 1 else remaining_size.y/num_growing.y
|
to_grow.y = 0 if num_growing.y < 1 else remaining_size.y/num_growing.y
|
||||||
|
|
||||||
child_index := e.first
|
it := e.first
|
||||||
for child_index != nil {
|
for child, child_index in iterate_siblings(state, &it) {
|
||||||
child := &state.curr_elements[child_index.?]
|
|
||||||
|
|
||||||
switch e.layout.dir {
|
switch e.layout.dir {
|
||||||
case .RightToLeft: fallthrough
|
case .RightToLeft: fallthrough
|
||||||
case .LeftToRight: {
|
case .LeftToRight: {
|
||||||
if _, ok := child.layout.kind.x.(Grow); ok {
|
if _, ok := child.layout.kind.x.(Grow); ok {
|
||||||
child.layout.size.x = to_grow.x
|
child.layout.size.x = state.max_size.x if child.layout.floating else to_grow.x
|
||||||
}
|
}
|
||||||
if _, ok := child.layout.kind.y.(Grow); ok {
|
if _, ok := child.layout.kind.y.(Grow); ok {
|
||||||
child.layout.size.y = remaining_size.y
|
child.layout.size.y = state.max_size.y if child.layout.floating else y_e
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case .BottomToTop: fallthrough
|
case .BottomToTop: fallthrough
|
||||||
case .TopToBottom: {
|
case .TopToBottom: {
|
||||||
if _, ok := child.layout.kind.x.(Grow); ok {
|
if _, ok := child.layout.kind.x.(Grow); ok {
|
||||||
child.layout.size.x = remaining_size.x
|
child.layout.size.x = state.max_size.x if child.layout.floating else x_e
|
||||||
}
|
}
|
||||||
if _, ok := child.layout.kind.y.(Grow); ok {
|
if _, ok := child.layout.kind.y.(Grow); ok {
|
||||||
child.layout.size.y = to_grow.y
|
child.layout.size.y = state.max_size.y if child.layout.floating else to_grow.y
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -296,25 +344,23 @@ grow_children :: proc(state: ^State, index: int) {
|
||||||
_, x_growing := child.layout.kind.x.(Grow)
|
_, x_growing := child.layout.kind.x.(Grow)
|
||||||
_, y_growing := child.layout.kind.y.(Grow)
|
_, y_growing := child.layout.kind.y.(Grow)
|
||||||
|
|
||||||
if x_growing || y_growing {
|
if x_growing || y_growing || child.layout.floating {
|
||||||
grow_children(state, child_index.?)
|
grow_children(state, child_index)
|
||||||
}
|
}
|
||||||
|
|
||||||
child_index = child.next
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compute_layout_2 :: proc(state: ^State) {
|
compute_layout :: proc(state: ^State) {
|
||||||
grow_children(state, 0)
|
grow_children(state, 0)
|
||||||
|
|
||||||
for i in 0..<state.num_curr {
|
for i in 0..<state.num_curr {
|
||||||
e := &state.curr_elements[i]
|
e := &state.curr_elements[i]
|
||||||
|
|
||||||
if parent_index, ok := e.parent.?; ok {
|
if parent_index, ok := e.parent.?; ok && !e.layout.floating {
|
||||||
parent := &state.curr_elements[parent_index]
|
parent := &state.curr_elements[parent_index]
|
||||||
|
|
||||||
if prev_index, ok := e.prev.?; ok {
|
if prev_index, ok := prev_non_floating(state, e.prev).?; ok {
|
||||||
prev := &state.curr_elements[prev_index]
|
prev := &state.curr_elements[prev_index]
|
||||||
|
|
||||||
switch parent.layout.dir {
|
switch parent.layout.dir {
|
||||||
|
|
Loading…
Reference in New Issue