get plugin interface sorta working with the ui lib
parent
96338e2924
commit
de908cfe06
2
Makefile
2
Makefile
|
@ -9,5 +9,5 @@ odin_highlighter:
|
|||
odin build plugins/highlighter/src/ -build-mode:dll -no-entry-point -out:bin/highlighter
|
||||
|
||||
grep:
|
||||
cargo b --manifest-path=plugins/grep/Cargo.toml
|
||||
nightly-cargo b --manifest-path=plugins/grep/Cargo.toml
|
||||
cp plugins/grep/target/debug/libgrep_plugin.dylib bin/
|
||||
|
|
18
flake.lock
18
flake.lock
|
@ -5,11 +5,11 @@
|
|||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1701680307,
|
||||
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
||||
"lastModified": 1705309234,
|
||||
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
||||
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -87,11 +87,11 @@
|
|||
},
|
||||
"nixpkgs_2": {
|
||||
"locked": {
|
||||
"lastModified": 1703013332,
|
||||
"narHash": "sha256-+tFNwMvlXLbJZXiMHqYq77z/RfmpfpiI3yjL6o/Zo9M=",
|
||||
"lastModified": 1705856552,
|
||||
"narHash": "sha256-JXfnuEf5Yd6bhMs/uvM67/joxYKoysyE3M2k6T3eWbg=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "54aac082a4d9bb5bbc5c4e899603abfb76a3f6d6",
|
||||
"rev": "612f97239e2cc474c13c9dafa0df378058c5ad8d",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
@ -131,11 +131,11 @@
|
|||
"nixpkgs": "nixpkgs_3"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1704075545,
|
||||
"narHash": "sha256-L3zgOuVKhPjKsVLc3yTm2YJ6+BATyZBury7wnhyc8QU=",
|
||||
"lastModified": 1706235145,
|
||||
"narHash": "sha256-3jh5nahTlcsX6QFcMPqxtLn9p9CgT9RSce5GLqjcpi4=",
|
||||
"owner": "oxalica",
|
||||
"repo": "rust-overlay",
|
||||
"rev": "a0df72e106322b67e9c6e591fe870380bd0da0d5",
|
||||
"rev": "3a57c4e29cb2beb777b2e6ae7309a680585b8b2f",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
|
@ -16,6 +16,13 @@
|
|||
local-rust = (pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain).override {
|
||||
extensions = [ "rust-analysis" ];
|
||||
};
|
||||
local-nightly-rust = (pkgs.rust-bin.fromRustupToolchainFile ./plugins/grep/rust-toolchain.toml).override {
|
||||
extensions = [ "rust-analysis" ];
|
||||
};
|
||||
nightly-cargo = pkgs.writeShellScriptBin "nightly-cargo" ''
|
||||
export RUSTC="${local-nightly-rust}/bin/rustc";
|
||||
exec "${local-nightly-rust}/bin/cargo" "$@"
|
||||
'';
|
||||
fixed-odin = pkgs.odin.overrideAttrs (finalAttrs: prevAttr: rec {
|
||||
src = pkgs.fetchFromGitHub {
|
||||
owner = "pcleavelin";
|
||||
|
@ -58,6 +65,7 @@
|
|||
buildInputs = with pkgs; (if pkgs.system == "aarch64-darwin" || pkgs.system == "x86_64-darwin" then [
|
||||
fixed-odin
|
||||
local-rust
|
||||
nightly-cargo
|
||||
rust-analyzer
|
||||
SDL2
|
||||
SDL2_ttf
|
||||
|
|
|
@ -166,6 +166,137 @@ pub struct IteratorVTable {
|
|||
pub until_end_of_word: *const c_void,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct UiInteraction {
|
||||
pub hovering: bool,
|
||||
pub clicked: bool,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
struct InternalUiSemanticSize {
|
||||
kind: isize,
|
||||
value: isize,
|
||||
}
|
||||
|
||||
#[repr(isize)]
|
||||
pub enum UiAxis {
|
||||
Horizontal = 0,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
pub enum UiSemanticSize {
|
||||
FitText,
|
||||
Exact(isize),
|
||||
ChildrenSum,
|
||||
Fill,
|
||||
PercentOfParent(isize),
|
||||
}
|
||||
|
||||
impl From<UiSemanticSize> for InternalUiSemanticSize {
|
||||
fn from(value: UiSemanticSize) -> Self {
|
||||
let (kind, value) = match value {
|
||||
UiSemanticSize::FitText => (0, 0),
|
||||
UiSemanticSize::Exact(value) => (1, value),
|
||||
UiSemanticSize::ChildrenSum => (2, 0),
|
||||
UiSemanticSize::Fill => (3, 0),
|
||||
UiSemanticSize::PercentOfParent(value) => (4, value),
|
||||
};
|
||||
|
||||
Self { kind, value }
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct UiContext(*const c_void);
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct UiBox(*const c_void);
|
||||
|
||||
type UiPushParentProc = extern "C" fn(ui_context: UiContext, ui_box: UiBox);
|
||||
type UiPopParentProc = extern "C" fn(ui_context: UiContext);
|
||||
type UiFloatingProc =
|
||||
extern "C" fn(ui_context: UiContext, label: *const i8, pos: [isize; 2]) -> UiBox;
|
||||
type UiRectProc = extern "C" fn(
|
||||
ui_context: UiContext,
|
||||
label: *const i8,
|
||||
border: bool,
|
||||
axis: UiAxis,
|
||||
size: [InternalUiSemanticSize; 2],
|
||||
) -> UiBox;
|
||||
type UiSimpleProc = extern "C" fn(ui_context: UiContext, label: *const i8) -> UiInteraction;
|
||||
type UiBufferProc = extern "C" fn(ui_context: UiContext, buffer: Buffer, show_line_numbers: bool);
|
||||
|
||||
#[repr(C)]
|
||||
pub struct UiVTable {
|
||||
ui_context: UiContext,
|
||||
|
||||
push_parent: UiPushParentProc,
|
||||
pop_parent: UiPopParentProc,
|
||||
|
||||
floating: UiFloatingProc,
|
||||
rect: UiRectProc,
|
||||
|
||||
button: UiSimpleProc,
|
||||
label: UiSimpleProc,
|
||||
|
||||
buffer: UiBufferProc,
|
||||
buffer_from_index: UiBufferProc,
|
||||
}
|
||||
|
||||
impl UiVTable {
|
||||
pub fn push_parent(&self, ui_box: UiBox) {
|
||||
(self.push_parent)(self.ui_context, ui_box);
|
||||
}
|
||||
pub fn pop_parent(&self) {
|
||||
(self.pop_parent)(self.ui_context);
|
||||
}
|
||||
|
||||
pub fn push_rect(
|
||||
&self,
|
||||
label: &CStr,
|
||||
show_border: bool,
|
||||
axis: UiAxis,
|
||||
horizontal_size: UiSemanticSize,
|
||||
vertical_size: UiSemanticSize,
|
||||
inner: impl FnOnce(&UiVTable),
|
||||
) {
|
||||
let rect = (self.rect)(
|
||||
self.ui_context,
|
||||
label.as_ptr(),
|
||||
show_border,
|
||||
axis,
|
||||
[horizontal_size.into(), vertical_size.into()],
|
||||
);
|
||||
self.push_parent(rect);
|
||||
|
||||
inner(self);
|
||||
|
||||
self.pop_parent();
|
||||
}
|
||||
|
||||
pub fn push_floating(&self, label: &CStr, x: isize, y: isize, inner: impl FnOnce(&UiVTable)) {
|
||||
let floating = (self.floating)(self.ui_context, label.as_ptr(), [x, y]);
|
||||
self.push_parent(floating);
|
||||
|
||||
inner(self);
|
||||
|
||||
self.pop_parent();
|
||||
}
|
||||
|
||||
pub fn label(&self, label: &CStr) -> UiInteraction {
|
||||
(self.label)(self.ui_context, label.as_ptr())
|
||||
}
|
||||
pub fn button(&self, label: &CStr) -> UiInteraction {
|
||||
(self.button)(self.ui_context, label.as_ptr())
|
||||
}
|
||||
|
||||
pub fn buffer(&self, buffer: Buffer, show_line_numbers: bool) {
|
||||
(self.buffer)(self.ui_context, buffer, show_line_numbers)
|
||||
}
|
||||
}
|
||||
|
||||
type OnColorBufferProc = extern "C" fn(plugin: Plugin, buffer: *const c_void);
|
||||
type OnHookProc = extern "C" fn(plugin: Plugin, buffer: Buffer);
|
||||
type InputGroupProc = extern "C" fn(plugin: Plugin, input_map: InputMap);
|
||||
|
@ -176,8 +307,10 @@ type WindowGetBufferProc = extern "C" fn(plugin: Plugin, window: *const c_void)
|
|||
#[repr(C)]
|
||||
pub struct Plugin {
|
||||
state: *const c_void,
|
||||
|
||||
pub iter_table: IteratorVTable,
|
||||
pub buffer_table: BufferVTable,
|
||||
pub ui_table: UiVTable,
|
||||
|
||||
pub register_hook: extern "C" fn(hook: Hook, on_hook: OnHookProc),
|
||||
pub register_highlighter:
|
||||
|
|
|
@ -98,11 +98,58 @@ buffer_list_iter :: proc(plugin: Plugin, buffer_index: ^int) -> (int, int, bool)
|
|||
|
||||
draw_buffer_window :: proc "c" (plugin: Plugin, win: rawptr) {
|
||||
context = runtime.default_context();
|
||||
runtime.free_all(context.temp_allocator);
|
||||
|
||||
win := cast(^BufferListWindow)win;
|
||||
if win == nil {
|
||||
return;
|
||||
}
|
||||
|
||||
screen_width := plugin.get_screen_width();
|
||||
screen_height := plugin.get_screen_height();
|
||||
directory := string(plugin.get_current_directory());
|
||||
|
||||
canvas := plugin.ui.floating(plugin.ui.ui_context, "buffer search canvas", {screen_width/8, screen_height/8});
|
||||
|
||||
plugin.ui.push_parent(plugin.ui.ui_context, canvas);
|
||||
{
|
||||
defer plugin.ui.pop_parent(plugin.ui.ui_context);
|
||||
|
||||
ui_window := plugin.ui.rect(plugin.ui.ui_context, "buffer search window", true, .Horizontal, {{4, 75}, {4, 75}});
|
||||
plugin.ui.push_parent(plugin.ui.ui_context, ui_window);
|
||||
{
|
||||
defer plugin.ui.pop_parent(plugin.ui.ui_context);
|
||||
|
||||
buffer_list_view := plugin.ui.rect(plugin.ui.ui_context, "buffer list view", false, .Vertical, {{4, 60}, {3, 0}});
|
||||
plugin.ui.push_parent(plugin.ui.ui_context, buffer_list_view);
|
||||
{
|
||||
defer plugin.ui.pop_parent(plugin.ui.ui_context);
|
||||
|
||||
_buffer_index := 0;
|
||||
for index in buffer_list_iter(plugin, &_buffer_index) {
|
||||
buffer := plugin.buffer.get_buffer_info_from_index(index);
|
||||
relative_file_path, _ := filepath.rel(directory, string(buffer.file_path), context.temp_allocator)
|
||||
text := fmt.ctprintf("%s:%d", relative_file_path, buffer.cursor.line+1);
|
||||
|
||||
if index == win.selected_index {
|
||||
plugin.ui.button(plugin.ui.ui_context, text);
|
||||
} else {
|
||||
plugin.ui.label(plugin.ui.ui_context, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
buffer_preview := plugin.ui.rect(plugin.ui.ui_context, "buffer preview", false, .Horizontal, {{3, 0}, {3, 0}});
|
||||
plugin.ui.push_parent(plugin.ui.ui_context, buffer_preview);
|
||||
{
|
||||
defer plugin.ui.pop_parent(plugin.ui.ui_context);
|
||||
|
||||
plugin.ui.buffer_from_index(plugin.ui.ui_context, win.selected_index, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
screen_width := plugin.get_screen_width();
|
||||
screen_height := plugin.get_screen_height();
|
||||
source_font_width := plugin.get_font_width();
|
||||
|
@ -173,4 +220,5 @@ draw_buffer_window :: proc "c" (plugin: Plugin, win: rawptr) {
|
|||
|
||||
runtime.free_all(context.temp_allocator);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
[toolchain]
|
||||
channel = "nightly-2024-01-24"
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
use std::{
|
||||
error::Error,
|
||||
ffi::OsString,
|
||||
ffi::{CString, OsString},
|
||||
path::Path,
|
||||
str::FromStr,
|
||||
sync::mpsc::{Receiver, Sender},
|
||||
|
@ -11,7 +11,7 @@ use grep::{
|
|||
regex::RegexMatcherBuilder,
|
||||
searcher::{BinaryDetection, SearcherBuilder, Sink, SinkError},
|
||||
};
|
||||
use plugin_rs_bindings::{Buffer, Closure, Hook, InputMap, Key, PaletteColor, Plugin};
|
||||
use plugin_rs_bindings::{Buffer, Closure, Hook, InputMap, Key, Plugin, UiAxis, UiSemanticSize};
|
||||
use std::sync::mpsc::channel;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
|
@ -273,109 +273,142 @@ extern "C" fn draw_window(plugin: Plugin, window: *const std::ffi::c_void) {
|
|||
|
||||
let screen_width = (plugin.get_screen_width)() as i32;
|
||||
let screen_height = (plugin.get_screen_height)() as i32;
|
||||
let font_width = (plugin.get_font_width)() as i32;
|
||||
|
||||
let font_height = (plugin.get_font_height)() as i32;
|
||||
|
||||
let x = screen_width / 8;
|
||||
let y = screen_height / 8;
|
||||
let width = screen_width - screen_width / 4;
|
||||
let height = screen_height - screen_height / 4;
|
||||
|
||||
let buffer_prev_width = (width - font_width * 2) / 2;
|
||||
|
||||
let glyph_buffer_width = buffer_prev_width / font_width - 1;
|
||||
let glyph_buffer_height = 1;
|
||||
|
||||
let dir = plugin.get_current_directory();
|
||||
let directory = Path::new(dir.as_ref());
|
||||
|
||||
(plugin.draw_rect)(x, y, width, height, PaletteColor::Background4);
|
||||
(plugin.draw_rect)(
|
||||
x + font_width,
|
||||
y + font_height,
|
||||
width - font_width * 2,
|
||||
height - font_height * 3,
|
||||
PaletteColor::Background3,
|
||||
);
|
||||
plugin.ui_table.push_floating(
|
||||
c"grep canvas",
|
||||
(screen_width as isize) / 8,
|
||||
(screen_height as isize) / 8,
|
||||
|ui_table| {
|
||||
ui_table.push_rect(
|
||||
c"grep window",
|
||||
true,
|
||||
UiAxis::Vertical,
|
||||
UiSemanticSize::PercentOfParent(75),
|
||||
UiSemanticSize::PercentOfParent(75),
|
||||
|ui_table| {
|
||||
if let Ok(sink) = window.rx.try_recv() {
|
||||
window.sink = Some(sink);
|
||||
}
|
||||
|
||||
if let Some(buffer) = window.input_buffer {
|
||||
(plugin.draw_rect)(
|
||||
x + font_width,
|
||||
y + height - font_height * 2,
|
||||
buffer_prev_width,
|
||||
font_height,
|
||||
PaletteColor::Background2,
|
||||
);
|
||||
(plugin.draw_buffer)(
|
||||
buffer,
|
||||
(x + font_width) as isize,
|
||||
(y + height - font_height * 2) as isize,
|
||||
(glyph_buffer_width) as isize,
|
||||
(glyph_buffer_height) as isize,
|
||||
false,
|
||||
);
|
||||
}
|
||||
ui_table.push_rect(
|
||||
c"results list",
|
||||
false,
|
||||
UiAxis::Vertical,
|
||||
UiSemanticSize::Fill,
|
||||
UiSemanticSize::Fill,
|
||||
|ui_table| match &window.sink {
|
||||
Some(sink) if !sink.matches.is_empty() => {
|
||||
let num_mats_to_draw = std::cmp::min(
|
||||
(sink.matches.len() - window.top_index) as i32,
|
||||
(height - font_height) / (font_height),
|
||||
);
|
||||
|
||||
if let Ok(sink) = window.rx.try_recv() {
|
||||
window.sink = Some(sink);
|
||||
}
|
||||
for (i, mat) in sink.matches[window.top_index..].iter().enumerate()
|
||||
{
|
||||
let index = i + window.top_index;
|
||||
if i as i32 >= num_mats_to_draw {
|
||||
break;
|
||||
}
|
||||
|
||||
if let Some(sink) = &window.sink {
|
||||
if !sink.matches.is_empty() {
|
||||
let num_mats_to_draw = std::cmp::min(
|
||||
(sink.matches.len() - window.top_index) as i32,
|
||||
(height - font_height * 2) / (font_height) - 1,
|
||||
);
|
||||
let max_mat_length = (width - font_width * 2) / font_width;
|
||||
let path = Path::new(&mat.path);
|
||||
let relative_file_path = path
|
||||
.strip_prefix(directory)
|
||||
.unwrap_or(path)
|
||||
.to_str()
|
||||
.unwrap_or("");
|
||||
|
||||
for (i, mat) in sink.matches[window.top_index..].iter().enumerate() {
|
||||
let index = i + window.top_index;
|
||||
if i as i32 >= num_mats_to_draw {
|
||||
break;
|
||||
}
|
||||
let matched_text = String::from_utf8_lossy(&mat.text);
|
||||
let text = match mat.line_number {
|
||||
Some(line_number) => format!(
|
||||
"{}:{}:{}: {}",
|
||||
relative_file_path,
|
||||
line_number,
|
||||
mat.column,
|
||||
matched_text
|
||||
),
|
||||
None => format!(
|
||||
"{}:{}: {}",
|
||||
relative_file_path, mat.column, matched_text
|
||||
),
|
||||
};
|
||||
|
||||
let path = Path::new(&mat.path);
|
||||
let relative_file_path = path
|
||||
.strip_prefix(directory)
|
||||
.unwrap_or(path)
|
||||
.to_str()
|
||||
.unwrap_or("");
|
||||
|
||||
let matched_text = String::from_utf8_lossy(&mat.text);
|
||||
let text = match mat.line_number {
|
||||
Some(line_number) => format!(
|
||||
"{}:{}:{}: {}",
|
||||
relative_file_path, line_number, mat.column, matched_text
|
||||
),
|
||||
None => format!("{}:{}: {}", relative_file_path, mat.column, matched_text),
|
||||
};
|
||||
let text = if text.len() > max_mat_length as usize {
|
||||
text.as_str().split_at(max_mat_length as usize).0
|
||||
} else {
|
||||
&text
|
||||
};
|
||||
|
||||
let text = format!("{text}\0");
|
||||
|
||||
if index == window.selected_match {
|
||||
(plugin.draw_rect)(
|
||||
x + font_width,
|
||||
y + font_height + ((index - window.top_index) as i32) * font_height,
|
||||
(text.chars().count() as i32) * font_width,
|
||||
font_height,
|
||||
PaletteColor::Background2,
|
||||
if index == window.selected_match {
|
||||
ui_table.button(&CString::new(text).expect("valid text"));
|
||||
} else {
|
||||
ui_table.label(&CString::new(text).expect("valid text"));
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(_) | None => {
|
||||
ui_table.push_rect(
|
||||
c"top spacer",
|
||||
false,
|
||||
UiAxis::Vertical,
|
||||
UiSemanticSize::Fill,
|
||||
UiSemanticSize::Fill,
|
||||
|ui_table| {},
|
||||
);
|
||||
ui_table.push_rect(
|
||||
c"centered text container",
|
||||
false,
|
||||
UiAxis::Horizontal,
|
||||
UiSemanticSize::Fill,
|
||||
UiSemanticSize::Fill,
|
||||
|ui_table| {
|
||||
ui_table.push_rect(
|
||||
c"left spacer",
|
||||
false,
|
||||
UiAxis::Vertical,
|
||||
UiSemanticSize::Fill,
|
||||
UiSemanticSize::Fill,
|
||||
|ui_table| {},
|
||||
);
|
||||
ui_table.label(c"no results");
|
||||
ui_table.push_rect(
|
||||
c"right spacer",
|
||||
false,
|
||||
UiAxis::Vertical,
|
||||
UiSemanticSize::Fill,
|
||||
UiSemanticSize::Fill,
|
||||
|ui_table| {},
|
||||
);
|
||||
},
|
||||
);
|
||||
ui_table.push_rect(
|
||||
c"bottom spacer",
|
||||
false,
|
||||
UiAxis::Vertical,
|
||||
UiSemanticSize::Fill,
|
||||
UiSemanticSize::Fill,
|
||||
|ui_table| {},
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
(plugin.draw_text)(
|
||||
text.as_ptr() as *const i8,
|
||||
(x + font_width) as f32,
|
||||
(y + font_height + ((index - window.top_index) as i32) * font_height) as f32,
|
||||
PaletteColor::Foreground2,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
ui_table.push_rect(
|
||||
c"grep window",
|
||||
false,
|
||||
UiAxis::Vertical,
|
||||
UiSemanticSize::Fill,
|
||||
UiSemanticSize::Exact(font_height as isize),
|
||||
|ui_table| {
|
||||
if let Some(buffer) = window.input_buffer {
|
||||
ui_table.buffer(buffer, false);
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
extern "C" fn on_buffer_input(plugin: Plugin, buffer: Buffer) {
|
||||
|
|
|
@ -277,6 +277,9 @@ is_rust_keyword :: proc(plugin: Plugin, start: BufferIter, end: BufferIter) -> (
|
|||
return;
|
||||
}
|
||||
|
||||
// TODO: split logic into single line coloring, and multi-line coloring.
|
||||
// single line coloring can be done directly on the glyph buffer
|
||||
// (with some edge cases, literally, the edge of the screen)
|
||||
color_buffer_odin :: proc "c" (plugin: Plugin, buffer: rawptr) {
|
||||
context = runtime.default_context();
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import "vendor:sdl2/ttf"
|
|||
|
||||
import "../theme"
|
||||
|
||||
scale :: 2;
|
||||
scale :: 1;
|
||||
start_char :: ' ';
|
||||
end_char :: '~';
|
||||
|
||||
|
|
292
src/main.odin
292
src/main.odin
|
@ -162,6 +162,7 @@ register_default_input_actions :: proc(input_map: ^core.InputMap) {
|
|||
// Scale font size
|
||||
{
|
||||
core.register_ctrl_key_action(input_map, .MINUS, proc(state: ^State) {
|
||||
fmt.print("You pressed <C>-MINUS", state.source_font_height, " ");
|
||||
if state.source_font_height > 16 {
|
||||
state.source_font_height -= 2;
|
||||
state.source_font_width = state.source_font_height / 2;
|
||||
|
@ -170,8 +171,11 @@ register_default_input_actions :: proc(input_map: ^core.InputMap) {
|
|||
//state.font = raylib.LoadFontEx("/System/Library/Fonts/Supplemental/Andale Mono.ttf", i32(state.source_font_height*2), nil, 0);
|
||||
//raylib.SetTextureFilter(state.font.texture, .BILINEAR);
|
||||
}
|
||||
fmt.println(state.source_font_height);
|
||||
}, "increase font size");
|
||||
core.register_ctrl_key_action(input_map, .EQUAL, proc(state: ^State) {
|
||||
fmt.println("You pressed <C>-EQUAL");
|
||||
|
||||
state.source_font_height += 2;
|
||||
state.source_font_width = state.source_font_height / 2;
|
||||
|
||||
|
@ -185,6 +189,7 @@ register_default_input_actions :: proc(input_map: ^core.InputMap) {
|
|||
{
|
||||
core.register_key_action(input_map, .I, proc(state: ^State) {
|
||||
state.mode = .Insert;
|
||||
sdl2.StartTextInput();
|
||||
}, "enter insert mode");
|
||||
core.register_key_action(input_map, .A, proc(state: ^State) {
|
||||
core.move_cursor_right(&state.buffers[state.current_buffer], false);
|
||||
|
@ -240,19 +245,12 @@ draw :: proc(state_with_ui: ^StateWithUi) {
|
|||
sdl2.SetRenderDrawColor(state_with_ui.state.sdl_renderer, render_color.r, render_color.g, render_color.b, render_color.a);
|
||||
sdl2.RenderClear(state_with_ui.state.sdl_renderer);
|
||||
|
||||
// raylib.ClearBackground(theme.get_palette_raylib_color(.Background));
|
||||
|
||||
// core.draw_file_buffer(state_with_ui.state, buffer, 32, state_with_ui.state.source_font_height);
|
||||
// if state_with_ui.state.window != nil && state_with_ui.state.window.draw != nil {
|
||||
// state_with_ui.state.window.draw(state_with_ui.state.plugin_vtable, state_with_ui.state.window.user_data);
|
||||
// }
|
||||
|
||||
ui.compute_layout(state_with_ui.ui_context, { state_with_ui.state.screen_width, state_with_ui.state.screen_height }, state_with_ui.state.source_font_width, state_with_ui.state.source_font_height, state_with_ui.ui_context.root);
|
||||
ui.draw(state_with_ui.ui_context, state_with_ui.state, state_with_ui.state.source_font_width, state_with_ui.state.source_font_height, state_with_ui.ui_context.root);
|
||||
//ui.draw_menu_bar(&state_with_ui.state, &menu_bar_state_with_ui.state, 0, 0, i32(state_with_ui.state.screen_width), i32(state_with_ui.state.screen_height), state_with_ui.state.source_font_height);
|
||||
|
||||
//raylib.DrawRectangle(0, i32(state_with_ui.state.screen_height - state_with_ui.state.source_font_height), i32(state_with_ui.state.screen_width), i32(state_with_ui.state.source_font_height), theme.get_palette_raylib_color(.Background2));
|
||||
|
||||
if state_with_ui.state.window != nil && state_with_ui.state.window.draw != nil {
|
||||
state_with_ui.state.window.draw(state_with_ui.state.plugin_vtable, state_with_ui.state.window.user_data);
|
||||
}
|
||||
|
||||
if state_with_ui.state.current_input_map != &state_with_ui.state.input_map {
|
||||
longest_description := 0;
|
||||
|
@ -375,20 +373,8 @@ ui_file_buffer :: proc(ctx: ^ui.Context, buffer: ^FileBuffer) -> ui.Interaction
|
|||
return interaction;
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
state = State {
|
||||
ctx = context,
|
||||
source_font_width = 8 + 2 * 3,
|
||||
source_font_height = 16 + 2 * 3,
|
||||
input_map = core.new_input_map(),
|
||||
window = nil,
|
||||
directory = os.get_current_directory(),
|
||||
plugins = make([dynamic]plugin.Interface),
|
||||
highlighters = make(map[string]plugin.OnColorBufferProc),
|
||||
hooks = make(map[plugin.Hook][dynamic]plugin.OnHookProc),
|
||||
};
|
||||
|
||||
state.plugin_vtable = plugin.Plugin {
|
||||
init_plugin_vtable :: proc(ui_context: ^ui.Context) -> plugin.Plugin {
|
||||
return plugin.Plugin {
|
||||
state = cast(rawptr)&state,
|
||||
register_hook = proc "c" (hook: plugin.Hook, on_hook: plugin.OnHookProc) {
|
||||
context = state.ctx;
|
||||
|
@ -507,6 +493,7 @@ main :: proc() {
|
|||
},
|
||||
enter_insert_mode = proc "c" () {
|
||||
state.mode = .Insert;
|
||||
sdl2.StartTextInput();
|
||||
},
|
||||
draw_rect = proc "c" (x: i32, y: i32, width: i32, height: i32, color: theme.PaletteColor) {
|
||||
context = state.ctx;
|
||||
|
@ -864,8 +851,109 @@ main :: proc() {
|
|||
free(buffer);
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
ui = plugin.Ui {
|
||||
ui_context = ui_context,
|
||||
|
||||
push_parent = proc "c" (ui_context: rawptr, box: plugin.UiBox) {
|
||||
context = state.ctx;
|
||||
ui_context := transmute(^ui.Context)ui_context;
|
||||
box := transmute(^ui.Box)box;
|
||||
|
||||
ui.push_parent(ui_context, box);
|
||||
},
|
||||
|
||||
pop_parent = proc "c" (ui_context: rawptr) {
|
||||
context = state.ctx;
|
||||
ui_context := transmute(^ui.Context)ui_context;
|
||||
|
||||
ui.pop_parent(ui_context);
|
||||
},
|
||||
|
||||
// TODO: allow this to have more flags sent to it
|
||||
floating = proc "c" (ui_context: rawptr, label: cstring, pos: [2]int) -> plugin.UiBox {
|
||||
context = state.ctx;
|
||||
ui_context := transmute(^ui.Context)ui_context;
|
||||
label := strings.clone(string(label), context.temp_allocator);
|
||||
|
||||
return ui.push_floating(ui_context, label, pos);
|
||||
},
|
||||
rect = proc "c" (ui_context: rawptr, label: cstring, border: bool, axis: plugin.UiAxis, size: [2]plugin.UiSemanticSize) -> plugin.UiBox {
|
||||
context = state.ctx;
|
||||
ui_context := transmute(^ui.Context)ui_context;
|
||||
label := strings.clone(string(label), context.temp_allocator);
|
||||
|
||||
size := [2]ui.SemanticSize {
|
||||
ui.SemanticSize {
|
||||
kind = ui.SemanticSizeKind(size.x.kind),
|
||||
value = size.x.value,
|
||||
},
|
||||
ui.SemanticSize {
|
||||
kind = ui.SemanticSizeKind(size.y.kind),
|
||||
value = size.y.value,
|
||||
},
|
||||
};
|
||||
|
||||
return ui.push_rect(ui_context, label, border, ui.Axis(axis), size);
|
||||
},
|
||||
|
||||
label = proc "c" (ui_context: rawptr, label: cstring) -> plugin.UiInteraction {
|
||||
context = state.ctx;
|
||||
ui_context := transmute(^ui.Context)ui_context;
|
||||
label := strings.clone(string(label), context.temp_allocator);
|
||||
|
||||
interaction := ui.label(ui_context, label);
|
||||
|
||||
return plugin.UiInteraction {
|
||||
hovering = interaction.hovering,
|
||||
clicked = interaction.clicked,
|
||||
};
|
||||
},
|
||||
button = proc "c" (ui_context: rawptr, label: cstring) -> plugin.UiInteraction {
|
||||
context = state.ctx;
|
||||
ui_context := transmute(^ui.Context)ui_context;
|
||||
label := strings.clone(string(label), context.temp_allocator);
|
||||
|
||||
interaction := ui.button(ui_context, label);
|
||||
|
||||
return plugin.UiInteraction {
|
||||
hovering = interaction.hovering,
|
||||
clicked = interaction.clicked,
|
||||
};
|
||||
},
|
||||
buffer = proc "c" (ui_context: rawptr, buffer: rawptr, show_line_numbers: bool) {
|
||||
context = state.ctx;
|
||||
ui_context := transmute(^ui.Context)ui_context;
|
||||
buffer := transmute(^FileBuffer)buffer;
|
||||
|
||||
ui_file_buffer(ui_context, buffer);
|
||||
},
|
||||
|
||||
buffer_from_index = proc "c" (ui_context: rawptr, buffer: int, show_line_numbers: bool) {
|
||||
context = state.ctx;
|
||||
ui_context := transmute(^ui.Context)ui_context;
|
||||
|
||||
buffer := &state.buffers[buffer];
|
||||
|
||||
ui_file_buffer(ui_context, buffer);
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
main :: proc() {
|
||||
state = State {
|
||||
ctx = context,
|
||||
source_font_width = 8 + 2 * 3,
|
||||
source_font_height = 16 + 2 * 3,
|
||||
input_map = core.new_input_map(),
|
||||
window = nil,
|
||||
directory = os.get_current_directory(),
|
||||
plugins = make([dynamic]plugin.Interface),
|
||||
highlighters = make(map[string]plugin.OnColorBufferProc),
|
||||
hooks = make(map[plugin.Hook][dynamic]plugin.OnHookProc),
|
||||
};
|
||||
|
||||
state.current_input_map = &state.input_map;
|
||||
register_default_input_actions(&state.input_map);
|
||||
|
||||
|
@ -879,16 +967,6 @@ main :: proc() {
|
|||
runtime.append(&state.buffers, buffer);
|
||||
}
|
||||
|
||||
// Load plugins
|
||||
// TODO(pcleavelin): Get directory of binary instead of shells current working directory
|
||||
filepath.walk(filepath.join({ os.get_current_directory(), "bin" }), load_plugin, transmute(rawptr)&state);
|
||||
|
||||
for plugin in state.plugins {
|
||||
if plugin.on_initialize != nil {
|
||||
plugin.on_initialize(state.plugin_vtable);
|
||||
}
|
||||
}
|
||||
|
||||
if sdl2.Init({.VIDEO}) < 0 {
|
||||
fmt.eprintln("SDL failed to initialize:", sdl2.GetError());
|
||||
return;
|
||||
|
@ -936,18 +1014,22 @@ main :: proc() {
|
|||
}
|
||||
}
|
||||
|
||||
sdl2.StartTextInput();
|
||||
sdl2.StopTextInput();
|
||||
|
||||
ui_context := ui.init(state.sdl_renderer);
|
||||
|
||||
sdl2.AddEventWatch(expose_event_watcher, &StateWithUi { &state, &ui_context });
|
||||
state.plugin_vtable = init_plugin_vtable(&ui_context);
|
||||
|
||||
// raylib.InitWindow(640, 480, "odin_editor - [now with more ui]");
|
||||
// raylib.SetWindowState({ .WINDOW_RESIZABLE, .VSYNC_HINT });
|
||||
// raylib.SetTargetFPS(144);
|
||||
// raylib.SetExitKey(.KEY_NULL);
|
||||
// Load plugins
|
||||
// TODO(pcleavelin): Get directory of binary instead of shells current working directory
|
||||
filepath.walk(filepath.join({ os.get_current_directory(), "bin" }), load_plugin, transmute(rawptr)&state);
|
||||
|
||||
// TODO: don't just hard code a MacOS font path
|
||||
// state.font = raylib.LoadFontEx("/System/Library/Fonts/Supplemental/Andale Mono.ttf", i32(state.source_font_height), nil, 0);
|
||||
// raylib.SetTextureFilter(state.font.texture, .BILINEAR);
|
||||
for plugin in state.plugins {
|
||||
if plugin.on_initialize != nil {
|
||||
plugin.on_initialize(state.plugin_vtable);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
control_key_pressed: bool;
|
||||
|
@ -958,7 +1040,7 @@ main :: proc() {
|
|||
{
|
||||
buffer := &state.buffers[state.current_buffer];
|
||||
|
||||
ui.push_parent(&ui_context, ui.push_box(&ui_context, "main", {}, .Vertical, semantic_size = {ui.make_semantic_size(.PercentOfParent, 100), ui.make_semantic_size(.PercentOfParent, 100)}));
|
||||
ui.push_parent(&ui_context, ui.push_box(&ui_context, "main", {}, .Vertical, semantic_size = {ui.make_semantic_size(.Fill, 100), ui.make_semantic_size(.Fill, 100)}));
|
||||
defer ui.pop_parent(&ui_context);
|
||||
|
||||
{
|
||||
|
@ -1012,7 +1094,7 @@ main :: proc() {
|
|||
defer ui.pop_parent(&ui_context);
|
||||
|
||||
{
|
||||
if ui_file_buffer(&ui_context, &state.buffers[0+3]).clicked {
|
||||
if ui_file_buffer(&ui_context, &state.buffers[state.current_buffer]).clicked {
|
||||
state.current_buffer = 3;
|
||||
}
|
||||
}
|
||||
|
@ -1065,6 +1147,10 @@ main :: proc() {
|
|||
}
|
||||
}
|
||||
|
||||
if state.window != nil && state.window.draw != nil {
|
||||
state.window.draw(state.plugin_vtable, state.window.user_data);
|
||||
}
|
||||
|
||||
{
|
||||
ui_context.last_mouse_left_down = ui_context.mouse_left_down;
|
||||
ui_context.last_mouse_right_down = ui_context.mouse_right_down;
|
||||
|
@ -1091,40 +1177,98 @@ main :: proc() {
|
|||
}
|
||||
}
|
||||
|
||||
if sdl_event.type == .KEYDOWN {
|
||||
key := plugin.Key(sdl_event.key.keysym.sym);
|
||||
if key == .LCTRL {
|
||||
control_key_pressed = true;
|
||||
} else if state.current_input_map != nil {
|
||||
if control_key_pressed {
|
||||
if action, exists := state.current_input_map.ctrl_key_actions[key]; exists {
|
||||
switch value in action.action {
|
||||
case core.PluginEditorAction:
|
||||
value(state.plugin_vtable);
|
||||
case core.EditorAction:
|
||||
value(&state);
|
||||
case core.InputMap:
|
||||
state.current_input_map = &(&state.current_input_map.ctrl_key_actions[key]).action.(core.InputMap)
|
||||
}
|
||||
switch state.mode {
|
||||
case .Normal: {
|
||||
if sdl_event.type == .KEYDOWN {
|
||||
key := plugin.Key(sdl_event.key.keysym.sym);
|
||||
if key == .ESCAPE {
|
||||
core.request_window_close(&state);
|
||||
}
|
||||
} else {
|
||||
if action, exists := state.current_input_map.key_actions[key]; exists {
|
||||
switch value in action.action {
|
||||
case core.PluginEditorAction:
|
||||
value(state.plugin_vtable);
|
||||
case core.EditorAction:
|
||||
value(&state);
|
||||
case core.InputMap:
|
||||
state.current_input_map = &(&state.current_input_map.key_actions[key]).action.(core.InputMap)
|
||||
|
||||
if key == .LCTRL {
|
||||
control_key_pressed = true;
|
||||
} else if state.current_input_map != nil {
|
||||
if control_key_pressed {
|
||||
if action, exists := state.current_input_map.ctrl_key_actions[key]; exists {
|
||||
switch value in action.action {
|
||||
case core.PluginEditorAction:
|
||||
value(state.plugin_vtable);
|
||||
case core.EditorAction:
|
||||
value(&state);
|
||||
case core.InputMap:
|
||||
state.current_input_map = &(&state.current_input_map.ctrl_key_actions[key]).action.(core.InputMap)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if action, exists := state.current_input_map.key_actions[key]; exists {
|
||||
switch value in action.action {
|
||||
case core.PluginEditorAction:
|
||||
value(state.plugin_vtable);
|
||||
case core.EditorAction:
|
||||
value(&state);
|
||||
case core.InputMap:
|
||||
state.current_input_map = &(&state.current_input_map.key_actions[key]).action.(core.InputMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if sdl_event.type == .KEYUP {
|
||||
key := plugin.Key(sdl_event.key.keysym.sym);
|
||||
if key == .LCTRL {
|
||||
control_key_pressed = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if sdl_event.type == .KEYUP {
|
||||
key := plugin.Key(sdl_event.key.keysym.sym);
|
||||
if key == .LCTRL {
|
||||
control_key_pressed = false;
|
||||
case .Insert: {
|
||||
buffer: ^FileBuffer;
|
||||
|
||||
if state.window != nil && state.window.get_buffer != nil {
|
||||
buffer = transmute(^core.FileBuffer)(state.window.get_buffer(state.plugin_vtable, state.window.user_data));
|
||||
} else {
|
||||
buffer = &state.buffers[state.current_buffer];
|
||||
}
|
||||
|
||||
if sdl_event.type == .KEYDOWN {
|
||||
key := plugin.Key(sdl_event.key.keysym.sym);
|
||||
|
||||
#partial switch key {
|
||||
case .ESCAPE: {
|
||||
state.mode = .Normal;
|
||||
|
||||
core.insert_content(buffer, buffer.input_buffer[:]);
|
||||
runtime.clear(&buffer.input_buffer);
|
||||
|
||||
sdl2.StopTextInput();
|
||||
}
|
||||
case .BACKSPACE: {
|
||||
core.delete_content(buffer, 1);
|
||||
|
||||
for hook_proc in state.hooks[plugin.Hook.BufferInput] {
|
||||
hook_proc(state.plugin_vtable, buffer);
|
||||
}
|
||||
}
|
||||
case .ENTER: {
|
||||
append(&buffer.input_buffer, '\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if sdl_event.type == .TEXTINPUT {
|
||||
for char in sdl_event.text.text {
|
||||
if char < 1 {
|
||||
break;
|
||||
}
|
||||
|
||||
if char >= 32 && char <= 125 && len(buffer.input_buffer) < 1024-1 {
|
||||
append(&buffer.input_buffer, u8(char));
|
||||
|
||||
for hook_proc in state.hooks[plugin.Hook.BufferInput] {
|
||||
hook_proc(state.plugin_vtable, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,6 +84,47 @@ Iterator :: struct {
|
|||
until_end_of_word: rawptr,
|
||||
}
|
||||
|
||||
UiInteraction :: struct {
|
||||
hovering: bool,
|
||||
clicked: bool
|
||||
}
|
||||
|
||||
UiAxis :: enum {
|
||||
Horizontal = 0,
|
||||
Vertical,
|
||||
}
|
||||
|
||||
UiSemanticSize :: struct {
|
||||
kind: int,
|
||||
value: int,
|
||||
}
|
||||
|
||||
UiBox :: rawptr;
|
||||
|
||||
UiPushParentProc :: proc "c" (ui_context: rawptr, box: UiBox);
|
||||
UiPopParentProc :: proc "c" (ui_context: rawptr);
|
||||
UiFloatingProc :: proc "c" (ui_context: rawptr, label: cstring, pos: [2]int) -> UiBox;
|
||||
UiCreateBoxProc :: proc "c" (ui_context: rawptr, label: cstring) -> UiBox;
|
||||
UiRectProc :: proc "c" (ui_context: rawptr, label: cstring, border: bool, axis: UiAxis, size: [2]UiSemanticSize) -> UiBox;
|
||||
UiSimpleProc :: proc "c" (ui_context: rawptr, label: cstring) -> UiInteraction;
|
||||
UiBufferProc :: proc "c" (ui_context: rawptr, buffer: rawptr, show_line_numbers: bool);
|
||||
UiBufferIndexProc :: proc "c" (ui_context: rawptr, buffer: int, show_line_numbers: bool);
|
||||
Ui :: struct {
|
||||
ui_context: rawptr,
|
||||
|
||||
push_parent: UiPushParentProc,
|
||||
pop_parent: UiPopParentProc,
|
||||
|
||||
floating: UiFloatingProc,
|
||||
rect: UiRectProc,
|
||||
|
||||
button: UiSimpleProc,
|
||||
label: UiSimpleProc,
|
||||
|
||||
buffer: UiBufferProc,
|
||||
buffer_from_index: UiBufferIndexProc,
|
||||
}
|
||||
|
||||
OnColorBufferProc :: proc "c" (plugin: Plugin, buffer: rawptr);
|
||||
InputGroupProc :: proc "c" (plugin: Plugin, input_map: rawptr);
|
||||
InputActionProc :: proc "c" (plugin: Plugin);
|
||||
|
@ -97,6 +138,7 @@ Plugin :: struct {
|
|||
state: rawptr,
|
||||
iter: Iterator,
|
||||
buffer: Buffer,
|
||||
ui: Ui,
|
||||
|
||||
register_hook: proc "c" (hook: Hook, on_hook: OnHookProc),
|
||||
register_highlighter: proc "c" (extension: cstring, on_color_buffer: OnColorBufferProc),
|
||||
|
|
|
@ -49,11 +49,12 @@ Flag :: enum {
|
|||
DrawText,
|
||||
DrawBorder,
|
||||
DrawBackground,
|
||||
Floating,
|
||||
CustomDrawFunc,
|
||||
}
|
||||
|
||||
SemanticSizeKind :: enum {
|
||||
FitText,
|
||||
FitText = 0,
|
||||
Exact,
|
||||
ChildrenSum,
|
||||
Fill,
|
||||
|
@ -126,6 +127,7 @@ gen_key :: proc(ctx: ^Context, label: string, value: int) -> Key {
|
|||
};
|
||||
}
|
||||
|
||||
@(private)
|
||||
make_box :: proc(ctx: ^Context, key: Key, label: string, flags: bit_set[Flag], axis: Axis, semantic_size: [2]SemanticSize) -> ^Box {
|
||||
box: ^Box = nil;
|
||||
|
||||
|
@ -193,6 +195,15 @@ ChildrenSum :[2]SemanticSize: {
|
|||
}
|
||||
};
|
||||
|
||||
Fill :[2]SemanticSize: {
|
||||
SemanticSize {
|
||||
kind = .Fill,
|
||||
},
|
||||
SemanticSize {
|
||||
kind = .Fill,
|
||||
}
|
||||
};
|
||||
|
||||
push_box :: proc(ctx: ^Context, label: string, flags: bit_set[Flag], axis: Axis = .Horizontal, semantic_size: [2]SemanticSize = FitText, value: int = 0) -> ^Box {
|
||||
key := gen_key(ctx, label, value);
|
||||
box := make_box(ctx, key, label, flags, axis, semantic_size);
|
||||
|
@ -227,10 +238,6 @@ test_box :: proc(ctx: ^Context, box: ^Box) -> Interaction {
|
|||
box.hot = 0;
|
||||
}
|
||||
|
||||
if hovering && mouse_is_clicked {
|
||||
fmt.println("hot", box.hot);
|
||||
}
|
||||
|
||||
return Interaction {
|
||||
hovering = hovering,
|
||||
clicked = hovering && mouse_is_clicked,
|
||||
|
@ -265,16 +272,21 @@ prune :: proc(ctx: ^Context) {
|
|||
}
|
||||
}
|
||||
|
||||
computed_pos := ctx.root.computed_pos;
|
||||
computed_size := ctx.root.computed_size;
|
||||
root_key := ctx.root.key;
|
||||
ctx.root^ = {
|
||||
key = root_key,
|
||||
};
|
||||
|
||||
ctx.root.first = nil;
|
||||
ctx.root.last = nil;
|
||||
ctx.root.next = nil;
|
||||
ctx.root.prev = nil;
|
||||
ctx.root.parent = nil;
|
||||
ctx.current_parent = ctx.root;
|
||||
}
|
||||
|
||||
// TODO: consider not using `ctx` here
|
||||
ancestor_size :: proc(ctx: ^Context, box: ^Box, axis: Axis) -> int {
|
||||
if box == nil || box.parent == nil {
|
||||
if box == nil || box.parent == nil || .Floating in box.flags {
|
||||
return ctx.root.computed_size[axis];
|
||||
}
|
||||
|
||||
|
@ -292,17 +304,35 @@ ancestor_size :: proc(ctx: ^Context, box: ^Box, axis: Axis) -> int {
|
|||
return 1337;
|
||||
}
|
||||
|
||||
prev_non_floating_sibling :: proc(ctx: ^Context, box: ^Box) -> ^Box {
|
||||
if box == nil {
|
||||
return nil;
|
||||
} else if box.prev == nil {
|
||||
return nil;
|
||||
} else if !(.Floating in box.prev.flags) {
|
||||
return box.prev;
|
||||
} else {
|
||||
return prev_non_floating_sibling(ctx, box.prev);
|
||||
}
|
||||
}
|
||||
|
||||
compute_layout :: proc(ctx: ^Context, canvas_size: [2]int, font_width: int, font_height: int, box: ^Box) {
|
||||
if box == nil { return; }
|
||||
|
||||
axis := Axis.Horizontal;
|
||||
if box.parent != nil {
|
||||
if box.parent != nil && !(.Floating in box.flags) {
|
||||
axis = box.parent.axis;
|
||||
box.computed_pos = box.parent.computed_pos;
|
||||
}
|
||||
|
||||
if box.prev != nil {
|
||||
box.computed_pos[axis] = box.prev.computed_pos[axis] + box.prev.computed_size[axis];
|
||||
if .Floating in box.flags {
|
||||
// box.computed_pos = {0,0};
|
||||
} else if box.prev != nil {
|
||||
prev := prev_non_floating_sibling(ctx, box);
|
||||
|
||||
if prev != nil {
|
||||
box.computed_pos[axis] = prev.computed_pos[axis] + prev.computed_size[axis];
|
||||
}
|
||||
}
|
||||
|
||||
post_compute_size := [2]bool { false, false };
|
||||
|
@ -415,6 +445,8 @@ compute_layout :: proc(ctx: ^Context, canvas_size: [2]int, font_width: int, font
|
|||
our_size := box.computed_size;
|
||||
|
||||
for child in iterate_box(&iter) {
|
||||
if .Floating in child.flags { continue; }
|
||||
|
||||
compute_layout(ctx, canvas_size, font_width, font_height, child);
|
||||
if child.semantic_size[box.axis].kind == .Fill {
|
||||
number_of_fills[box.axis] += 1;
|
||||
|
@ -644,8 +676,19 @@ spacer :: proc(ctx: ^Context, label: string, flags: bit_set[Flag] = {}, semantic
|
|||
return push_box(ctx, label, flags, semantic_size = semantic_size);
|
||||
}
|
||||
|
||||
push_floating :: proc(ctx: ^Context, label: string, pos: [2]int, flags: bit_set[Flag] = {.Floating}, axis: Axis = .Vertical, semantic_size: [2]SemanticSize = Fill) -> ^Box {
|
||||
box := push_box(ctx, label, flags, semantic_size = semantic_size);
|
||||
box.computed_pos = pos;
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
push_rect :: proc(ctx: ^Context, label: string, border: bool = true, axis: Axis = .Vertical, semantic_size: [2]SemanticSize = Fill) -> ^Box {
|
||||
return push_box(ctx, label, {.DrawBackground, .DrawBorder if border else nil}, axis, semantic_size = semantic_size);
|
||||
}
|
||||
|
||||
label :: proc(ctx: ^Context, label: string) -> Interaction {
|
||||
box := push_box(ctx, label, {.DrawText, .Hoverable});
|
||||
box := push_box(ctx, label, {.DrawText});
|
||||
|
||||
return test_box(ctx, box);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue