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
|
odin build plugins/highlighter/src/ -build-mode:dll -no-entry-point -out:bin/highlighter
|
||||||
|
|
||||||
grep:
|
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/
|
cp plugins/grep/target/debug/libgrep_plugin.dylib bin/
|
||||||
|
|
18
flake.lock
18
flake.lock
|
@ -5,11 +5,11 @@
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1701680307,
|
"lastModified": 1705309234,
|
||||||
"narHash": "sha256-kAuep2h5ajznlPMD9rnQyffWG8EM/C73lejGofXvdM8=",
|
"narHash": "sha256-uNRRNRKmJyCRC/8y1RqBkqWBLM034y4qN7EprSdmgyA=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "4022d587cbbfd70fe950c1e2083a02621806a725",
|
"rev": "1ef2e671c3b0c19053962c07dbda38332dcebf26",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -87,11 +87,11 @@
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1703013332,
|
"lastModified": 1705856552,
|
||||||
"narHash": "sha256-+tFNwMvlXLbJZXiMHqYq77z/RfmpfpiI3yjL6o/Zo9M=",
|
"narHash": "sha256-JXfnuEf5Yd6bhMs/uvM67/joxYKoysyE3M2k6T3eWbg=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "54aac082a4d9bb5bbc5c4e899603abfb76a3f6d6",
|
"rev": "612f97239e2cc474c13c9dafa0df378058c5ad8d",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
@ -131,11 +131,11 @@
|
||||||
"nixpkgs": "nixpkgs_3"
|
"nixpkgs": "nixpkgs_3"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1704075545,
|
"lastModified": 1706235145,
|
||||||
"narHash": "sha256-L3zgOuVKhPjKsVLc3yTm2YJ6+BATyZBury7wnhyc8QU=",
|
"narHash": "sha256-3jh5nahTlcsX6QFcMPqxtLn9p9CgT9RSce5GLqjcpi4=",
|
||||||
"owner": "oxalica",
|
"owner": "oxalica",
|
||||||
"repo": "rust-overlay",
|
"repo": "rust-overlay",
|
||||||
"rev": "a0df72e106322b67e9c6e591fe870380bd0da0d5",
|
"rev": "3a57c4e29cb2beb777b2e6ae7309a680585b8b2f",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
|
|
|
@ -16,6 +16,13 @@
|
||||||
local-rust = (pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain).override {
|
local-rust = (pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain).override {
|
||||||
extensions = [ "rust-analysis" ];
|
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 {
|
fixed-odin = pkgs.odin.overrideAttrs (finalAttrs: prevAttr: rec {
|
||||||
src = pkgs.fetchFromGitHub {
|
src = pkgs.fetchFromGitHub {
|
||||||
owner = "pcleavelin";
|
owner = "pcleavelin";
|
||||||
|
@ -58,6 +65,7 @@
|
||||||
buildInputs = with pkgs; (if pkgs.system == "aarch64-darwin" || pkgs.system == "x86_64-darwin" then [
|
buildInputs = with pkgs; (if pkgs.system == "aarch64-darwin" || pkgs.system == "x86_64-darwin" then [
|
||||||
fixed-odin
|
fixed-odin
|
||||||
local-rust
|
local-rust
|
||||||
|
nightly-cargo
|
||||||
rust-analyzer
|
rust-analyzer
|
||||||
SDL2
|
SDL2
|
||||||
SDL2_ttf
|
SDL2_ttf
|
||||||
|
|
|
@ -166,6 +166,137 @@ pub struct IteratorVTable {
|
||||||
pub until_end_of_word: *const c_void,
|
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 OnColorBufferProc = extern "C" fn(plugin: Plugin, buffer: *const c_void);
|
||||||
type OnHookProc = extern "C" fn(plugin: Plugin, buffer: Buffer);
|
type OnHookProc = extern "C" fn(plugin: Plugin, buffer: Buffer);
|
||||||
type InputGroupProc = extern "C" fn(plugin: Plugin, input_map: InputMap);
|
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)]
|
#[repr(C)]
|
||||||
pub struct Plugin {
|
pub struct Plugin {
|
||||||
state: *const c_void,
|
state: *const c_void,
|
||||||
|
|
||||||
pub iter_table: IteratorVTable,
|
pub iter_table: IteratorVTable,
|
||||||
pub buffer_table: BufferVTable,
|
pub buffer_table: BufferVTable,
|
||||||
|
pub ui_table: UiVTable,
|
||||||
|
|
||||||
pub register_hook: extern "C" fn(hook: Hook, on_hook: OnHookProc),
|
pub register_hook: extern "C" fn(hook: Hook, on_hook: OnHookProc),
|
||||||
pub register_highlighter:
|
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) {
|
draw_buffer_window :: proc "c" (plugin: Plugin, win: rawptr) {
|
||||||
context = runtime.default_context();
|
context = runtime.default_context();
|
||||||
|
runtime.free_all(context.temp_allocator);
|
||||||
|
|
||||||
win := cast(^BufferListWindow)win;
|
win := cast(^BufferListWindow)win;
|
||||||
if win == nil {
|
if win == nil {
|
||||||
return;
|
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_width := plugin.get_screen_width();
|
||||||
screen_height := plugin.get_screen_height();
|
screen_height := plugin.get_screen_height();
|
||||||
source_font_width := plugin.get_font_width();
|
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);
|
runtime.free_all(context.temp_allocator);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
[toolchain]
|
||||||
|
channel = "nightly-2024-01-24"
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
error::Error,
|
error::Error,
|
||||||
ffi::OsString,
|
ffi::{CString, OsString},
|
||||||
path::Path,
|
path::Path,
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
sync::mpsc::{Receiver, Sender},
|
sync::mpsc::{Receiver, Sender},
|
||||||
|
@ -11,7 +11,7 @@ use grep::{
|
||||||
regex::RegexMatcherBuilder,
|
regex::RegexMatcherBuilder,
|
||||||
searcher::{BinaryDetection, SearcherBuilder, Sink, SinkError},
|
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 std::sync::mpsc::channel;
|
||||||
use walkdir::WalkDir;
|
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_width = (plugin.get_screen_width)() as i32;
|
||||||
let screen_height = (plugin.get_screen_height)() 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 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 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 dir = plugin.get_current_directory();
|
||||||
let directory = Path::new(dir.as_ref());
|
let directory = Path::new(dir.as_ref());
|
||||||
|
|
||||||
(plugin.draw_rect)(x, y, width, height, PaletteColor::Background4);
|
plugin.ui_table.push_floating(
|
||||||
(plugin.draw_rect)(
|
c"grep canvas",
|
||||||
x + font_width,
|
(screen_width as isize) / 8,
|
||||||
y + font_height,
|
(screen_height as isize) / 8,
|
||||||
width - font_width * 2,
|
|ui_table| {
|
||||||
height - font_height * 3,
|
ui_table.push_rect(
|
||||||
PaletteColor::Background3,
|
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 {
|
ui_table.push_rect(
|
||||||
(plugin.draw_rect)(
|
c"results list",
|
||||||
x + font_width,
|
false,
|
||||||
y + height - font_height * 2,
|
UiAxis::Vertical,
|
||||||
buffer_prev_width,
|
UiSemanticSize::Fill,
|
||||||
font_height,
|
UiSemanticSize::Fill,
|
||||||
PaletteColor::Background2,
|
|ui_table| match &window.sink {
|
||||||
);
|
Some(sink) if !sink.matches.is_empty() => {
|
||||||
(plugin.draw_buffer)(
|
let num_mats_to_draw = std::cmp::min(
|
||||||
buffer,
|
(sink.matches.len() - window.top_index) as i32,
|
||||||
(x + font_width) as isize,
|
(height - font_height) / (font_height),
|
||||||
(y + height - font_height * 2) as isize,
|
);
|
||||||
(glyph_buffer_width) as isize,
|
|
||||||
(glyph_buffer_height) as isize,
|
|
||||||
false,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(sink) = window.rx.try_recv() {
|
for (i, mat) in sink.matches[window.top_index..].iter().enumerate()
|
||||||
window.sink = Some(sink);
|
{
|
||||||
}
|
let index = i + window.top_index;
|
||||||
|
if i as i32 >= num_mats_to_draw {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(sink) = &window.sink {
|
let path = Path::new(&mat.path);
|
||||||
if !sink.matches.is_empty() {
|
let relative_file_path = path
|
||||||
let num_mats_to_draw = std::cmp::min(
|
.strip_prefix(directory)
|
||||||
(sink.matches.len() - window.top_index) as i32,
|
.unwrap_or(path)
|
||||||
(height - font_height * 2) / (font_height) - 1,
|
.to_str()
|
||||||
);
|
.unwrap_or("");
|
||||||
let max_mat_length = (width - font_width * 2) / font_width;
|
|
||||||
|
|
||||||
for (i, mat) in sink.matches[window.top_index..].iter().enumerate() {
|
let matched_text = String::from_utf8_lossy(&mat.text);
|
||||||
let index = i + window.top_index;
|
let text = match mat.line_number {
|
||||||
if i as i32 >= num_mats_to_draw {
|
Some(line_number) => format!(
|
||||||
break;
|
"{}:{}:{}: {}",
|
||||||
}
|
relative_file_path,
|
||||||
|
line_number,
|
||||||
|
mat.column,
|
||||||
|
matched_text
|
||||||
|
),
|
||||||
|
None => format!(
|
||||||
|
"{}:{}: {}",
|
||||||
|
relative_file_path, mat.column, matched_text
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
let path = Path::new(&mat.path);
|
if index == window.selected_match {
|
||||||
let relative_file_path = path
|
ui_table.button(&CString::new(text).expect("valid text"));
|
||||||
.strip_prefix(directory)
|
} else {
|
||||||
.unwrap_or(path)
|
ui_table.label(&CString::new(text).expect("valid text"));
|
||||||
.to_str()
|
}
|
||||||
.unwrap_or("");
|
}
|
||||||
|
}
|
||||||
let matched_text = String::from_utf8_lossy(&mat.text);
|
Some(_) | None => {
|
||||||
let text = match mat.line_number {
|
ui_table.push_rect(
|
||||||
Some(line_number) => format!(
|
c"top spacer",
|
||||||
"{}:{}:{}: {}",
|
false,
|
||||||
relative_file_path, line_number, mat.column, matched_text
|
UiAxis::Vertical,
|
||||||
),
|
UiSemanticSize::Fill,
|
||||||
None => format!("{}:{}: {}", relative_file_path, mat.column, matched_text),
|
UiSemanticSize::Fill,
|
||||||
};
|
|ui_table| {},
|
||||||
let text = if text.len() > max_mat_length as usize {
|
);
|
||||||
text.as_str().split_at(max_mat_length as usize).0
|
ui_table.push_rect(
|
||||||
} else {
|
c"centered text container",
|
||||||
&text
|
false,
|
||||||
};
|
UiAxis::Horizontal,
|
||||||
|
UiSemanticSize::Fill,
|
||||||
let text = format!("{text}\0");
|
UiSemanticSize::Fill,
|
||||||
|
|ui_table| {
|
||||||
if index == window.selected_match {
|
ui_table.push_rect(
|
||||||
(plugin.draw_rect)(
|
c"left spacer",
|
||||||
x + font_width,
|
false,
|
||||||
y + font_height + ((index - window.top_index) as i32) * font_height,
|
UiAxis::Vertical,
|
||||||
(text.chars().count() as i32) * font_width,
|
UiSemanticSize::Fill,
|
||||||
font_height,
|
UiSemanticSize::Fill,
|
||||||
PaletteColor::Background2,
|
|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)(
|
ui_table.push_rect(
|
||||||
text.as_ptr() as *const i8,
|
c"grep window",
|
||||||
(x + font_width) as f32,
|
false,
|
||||||
(y + font_height + ((index - window.top_index) as i32) * font_height) as f32,
|
UiAxis::Vertical,
|
||||||
PaletteColor::Foreground2,
|
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) {
|
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;
|
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) {
|
color_buffer_odin :: proc "c" (plugin: Plugin, buffer: rawptr) {
|
||||||
context = runtime.default_context();
|
context = runtime.default_context();
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import "vendor:sdl2/ttf"
|
||||||
|
|
||||||
import "../theme"
|
import "../theme"
|
||||||
|
|
||||||
scale :: 2;
|
scale :: 1;
|
||||||
start_char :: ' ';
|
start_char :: ' ';
|
||||||
end_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
|
// Scale font size
|
||||||
{
|
{
|
||||||
core.register_ctrl_key_action(input_map, .MINUS, proc(state: ^State) {
|
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 {
|
if state.source_font_height > 16 {
|
||||||
state.source_font_height -= 2;
|
state.source_font_height -= 2;
|
||||||
state.source_font_width = 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);
|
//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);
|
//raylib.SetTextureFilter(state.font.texture, .BILINEAR);
|
||||||
}
|
}
|
||||||
|
fmt.println(state.source_font_height);
|
||||||
}, "increase font size");
|
}, "increase font size");
|
||||||
core.register_ctrl_key_action(input_map, .EQUAL, proc(state: ^State) {
|
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_height += 2;
|
||||||
state.source_font_width = 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) {
|
core.register_key_action(input_map, .I, proc(state: ^State) {
|
||||||
state.mode = .Insert;
|
state.mode = .Insert;
|
||||||
|
sdl2.StartTextInput();
|
||||||
}, "enter insert mode");
|
}, "enter insert mode");
|
||||||
core.register_key_action(input_map, .A, proc(state: ^State) {
|
core.register_key_action(input_map, .A, proc(state: ^State) {
|
||||||
core.move_cursor_right(&state.buffers[state.current_buffer], false);
|
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.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);
|
sdl2.RenderClear(state_with_ui.state.sdl_renderer);
|
||||||
|
|
||||||
// raylib.ClearBackground(theme.get_palette_raylib_color(.Background));
|
// 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);
|
||||||
// core.draw_file_buffer(state_with_ui.state, buffer, 32, state_with_ui.state.source_font_height);
|
// }
|
||||||
|
|
||||||
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.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(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 {
|
if state_with_ui.state.current_input_map != &state_with_ui.state.input_map {
|
||||||
longest_description := 0;
|
longest_description := 0;
|
||||||
|
@ -375,20 +373,8 @@ ui_file_buffer :: proc(ctx: ^ui.Context, buffer: ^FileBuffer) -> ui.Interaction
|
||||||
return interaction;
|
return interaction;
|
||||||
}
|
}
|
||||||
|
|
||||||
main :: proc() {
|
init_plugin_vtable :: proc(ui_context: ^ui.Context) -> plugin.Plugin {
|
||||||
state = State {
|
return plugin.Plugin {
|
||||||
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 {
|
|
||||||
state = cast(rawptr)&state,
|
state = cast(rawptr)&state,
|
||||||
register_hook = proc "c" (hook: plugin.Hook, on_hook: plugin.OnHookProc) {
|
register_hook = proc "c" (hook: plugin.Hook, on_hook: plugin.OnHookProc) {
|
||||||
context = state.ctx;
|
context = state.ctx;
|
||||||
|
@ -507,6 +493,7 @@ main :: proc() {
|
||||||
},
|
},
|
||||||
enter_insert_mode = proc "c" () {
|
enter_insert_mode = proc "c" () {
|
||||||
state.mode = .Insert;
|
state.mode = .Insert;
|
||||||
|
sdl2.StartTextInput();
|
||||||
},
|
},
|
||||||
draw_rect = proc "c" (x: i32, y: i32, width: i32, height: i32, color: theme.PaletteColor) {
|
draw_rect = proc "c" (x: i32, y: i32, width: i32, height: i32, color: theme.PaletteColor) {
|
||||||
context = state.ctx;
|
context = state.ctx;
|
||||||
|
@ -864,8 +851,109 @@ main :: proc() {
|
||||||
free(buffer);
|
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;
|
state.current_input_map = &state.input_map;
|
||||||
register_default_input_actions(&state.input_map);
|
register_default_input_actions(&state.input_map);
|
||||||
|
|
||||||
|
@ -879,16 +967,6 @@ main :: proc() {
|
||||||
runtime.append(&state.buffers, buffer);
|
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 {
|
if sdl2.Init({.VIDEO}) < 0 {
|
||||||
fmt.eprintln("SDL failed to initialize:", sdl2.GetError());
|
fmt.eprintln("SDL failed to initialize:", sdl2.GetError());
|
||||||
return;
|
return;
|
||||||
|
@ -936,18 +1014,22 @@ main :: proc() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sdl2.StartTextInput();
|
||||||
|
sdl2.StopTextInput();
|
||||||
|
|
||||||
ui_context := ui.init(state.sdl_renderer);
|
ui_context := ui.init(state.sdl_renderer);
|
||||||
|
|
||||||
sdl2.AddEventWatch(expose_event_watcher, &StateWithUi { &state, &ui_context });
|
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]");
|
// Load plugins
|
||||||
// raylib.SetWindowState({ .WINDOW_RESIZABLE, .VSYNC_HINT });
|
// TODO(pcleavelin): Get directory of binary instead of shells current working directory
|
||||||
// raylib.SetTargetFPS(144);
|
filepath.walk(filepath.join({ os.get_current_directory(), "bin" }), load_plugin, transmute(rawptr)&state);
|
||||||
// raylib.SetExitKey(.KEY_NULL);
|
|
||||||
|
|
||||||
// TODO: don't just hard code a MacOS font path
|
for plugin in state.plugins {
|
||||||
// state.font = raylib.LoadFontEx("/System/Library/Fonts/Supplemental/Andale Mono.ttf", i32(state.source_font_height), nil, 0);
|
if plugin.on_initialize != nil {
|
||||||
// raylib.SetTextureFilter(state.font.texture, .BILINEAR);
|
plugin.on_initialize(state.plugin_vtable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
control_key_pressed: bool;
|
control_key_pressed: bool;
|
||||||
|
@ -958,7 +1040,7 @@ main :: proc() {
|
||||||
{
|
{
|
||||||
buffer := &state.buffers[state.current_buffer];
|
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);
|
defer ui.pop_parent(&ui_context);
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1012,7 +1094,7 @@ main :: proc() {
|
||||||
defer ui.pop_parent(&ui_context);
|
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;
|
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_left_down = ui_context.mouse_left_down;
|
||||||
ui_context.last_mouse_right_down = ui_context.mouse_right_down;
|
ui_context.last_mouse_right_down = ui_context.mouse_right_down;
|
||||||
|
@ -1091,40 +1177,98 @@ main :: proc() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sdl_event.type == .KEYDOWN {
|
switch state.mode {
|
||||||
key := plugin.Key(sdl_event.key.keysym.sym);
|
case .Normal: {
|
||||||
if key == .LCTRL {
|
if sdl_event.type == .KEYDOWN {
|
||||||
control_key_pressed = true;
|
key := plugin.Key(sdl_event.key.keysym.sym);
|
||||||
} else if state.current_input_map != nil {
|
if key == .ESCAPE {
|
||||||
if control_key_pressed {
|
core.request_window_close(&state);
|
||||||
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 {
|
if key == .LCTRL {
|
||||||
switch value in action.action {
|
control_key_pressed = true;
|
||||||
case core.PluginEditorAction:
|
} else if state.current_input_map != nil {
|
||||||
value(state.plugin_vtable);
|
if control_key_pressed {
|
||||||
case core.EditorAction:
|
if action, exists := state.current_input_map.ctrl_key_actions[key]; exists {
|
||||||
value(&state);
|
switch value in action.action {
|
||||||
case core.InputMap:
|
case core.PluginEditorAction:
|
||||||
state.current_input_map = &(&state.current_input_map.key_actions[key]).action.(core.InputMap)
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
case .Insert: {
|
||||||
if sdl_event.type == .KEYUP {
|
buffer: ^FileBuffer;
|
||||||
key := plugin.Key(sdl_event.key.keysym.sym);
|
|
||||||
if key == .LCTRL {
|
if state.window != nil && state.window.get_buffer != nil {
|
||||||
control_key_pressed = false;
|
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,
|
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);
|
OnColorBufferProc :: proc "c" (plugin: Plugin, buffer: rawptr);
|
||||||
InputGroupProc :: proc "c" (plugin: Plugin, input_map: rawptr);
|
InputGroupProc :: proc "c" (plugin: Plugin, input_map: rawptr);
|
||||||
InputActionProc :: proc "c" (plugin: Plugin);
|
InputActionProc :: proc "c" (plugin: Plugin);
|
||||||
|
@ -97,6 +138,7 @@ Plugin :: struct {
|
||||||
state: rawptr,
|
state: rawptr,
|
||||||
iter: Iterator,
|
iter: Iterator,
|
||||||
buffer: Buffer,
|
buffer: Buffer,
|
||||||
|
ui: Ui,
|
||||||
|
|
||||||
register_hook: proc "c" (hook: Hook, on_hook: OnHookProc),
|
register_hook: proc "c" (hook: Hook, on_hook: OnHookProc),
|
||||||
register_highlighter: proc "c" (extension: cstring, on_color_buffer: OnColorBufferProc),
|
register_highlighter: proc "c" (extension: cstring, on_color_buffer: OnColorBufferProc),
|
||||||
|
|
|
@ -49,11 +49,12 @@ Flag :: enum {
|
||||||
DrawText,
|
DrawText,
|
||||||
DrawBorder,
|
DrawBorder,
|
||||||
DrawBackground,
|
DrawBackground,
|
||||||
|
Floating,
|
||||||
CustomDrawFunc,
|
CustomDrawFunc,
|
||||||
}
|
}
|
||||||
|
|
||||||
SemanticSizeKind :: enum {
|
SemanticSizeKind :: enum {
|
||||||
FitText,
|
FitText = 0,
|
||||||
Exact,
|
Exact,
|
||||||
ChildrenSum,
|
ChildrenSum,
|
||||||
Fill,
|
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 {
|
make_box :: proc(ctx: ^Context, key: Key, label: string, flags: bit_set[Flag], axis: Axis, semantic_size: [2]SemanticSize) -> ^Box {
|
||||||
box: ^Box = nil;
|
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 {
|
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);
|
key := gen_key(ctx, label, value);
|
||||||
box := make_box(ctx, key, label, flags, axis, semantic_size);
|
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;
|
box.hot = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if hovering && mouse_is_clicked {
|
|
||||||
fmt.println("hot", box.hot);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Interaction {
|
return Interaction {
|
||||||
hovering = hovering,
|
hovering = hovering,
|
||||||
clicked = hovering && mouse_is_clicked,
|
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;
|
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;
|
ctx.current_parent = ctx.root;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: consider not using `ctx` here
|
// TODO: consider not using `ctx` here
|
||||||
ancestor_size :: proc(ctx: ^Context, box: ^Box, axis: Axis) -> int {
|
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];
|
return ctx.root.computed_size[axis];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,17 +304,35 @@ ancestor_size :: proc(ctx: ^Context, box: ^Box, axis: Axis) -> int {
|
||||||
return 1337;
|
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) {
|
compute_layout :: proc(ctx: ^Context, canvas_size: [2]int, font_width: int, font_height: int, box: ^Box) {
|
||||||
if box == nil { return; }
|
if box == nil { return; }
|
||||||
|
|
||||||
axis := Axis.Horizontal;
|
axis := Axis.Horizontal;
|
||||||
if box.parent != nil {
|
if box.parent != nil && !(.Floating in box.flags) {
|
||||||
axis = box.parent.axis;
|
axis = box.parent.axis;
|
||||||
box.computed_pos = box.parent.computed_pos;
|
box.computed_pos = box.parent.computed_pos;
|
||||||
}
|
}
|
||||||
|
|
||||||
if box.prev != nil {
|
if .Floating in box.flags {
|
||||||
box.computed_pos[axis] = box.prev.computed_pos[axis] + box.prev.computed_size[axis];
|
// 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 };
|
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;
|
our_size := box.computed_size;
|
||||||
|
|
||||||
for child in iterate_box(&iter) {
|
for child in iterate_box(&iter) {
|
||||||
|
if .Floating in child.flags { continue; }
|
||||||
|
|
||||||
compute_layout(ctx, canvas_size, font_width, font_height, child);
|
compute_layout(ctx, canvas_size, font_width, font_height, child);
|
||||||
if child.semantic_size[box.axis].kind == .Fill {
|
if child.semantic_size[box.axis].kind == .Fill {
|
||||||
number_of_fills[box.axis] += 1;
|
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);
|
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 {
|
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);
|
return test_box(ctx, box);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue