aboutsummaryrefslogtreecommitdiff
path: root/kscurses/ui/line_input.jai
blob: 17823dbf6c1a6d1b599215ea02bcd8273e4945f6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
Char_Type :: u8;
UI_Line_Input :: struct {
	#as using base : UI_Elem = .{type = .LINE_INPUT};
	buffer : []Char_Type;

	// resizeable := false;
	ptr_left, ptr_right : int;
	offset : int;
}

handle_key_line_input :: (ui_elem : *UI_Elem, key : Key) -> bool {
	using ui_line_input := cast(*UI_Line_Input) ui_elem;

	handle_inner :: (using ui_line_input : *UI_Line_Input, key : Key) -> bool {
		if is_printable(key) {
			return add_char(ui_line_input, xx key);
		} else if key == {
			case .LEFT; #through;
			case .RIGHT;
			return move_ptr(ui_line_input, key);
			case .BACKSPACE;
			return remove_char_left(ui_line_input);
			case .ESCAPE;
			cursor_state = .ON;
			return true;
		}
		return false;		
	}

	if cursor_state == .IN {
		return handle_inner(ui_line_input, key);
	} else if cursor_state == .ON && key == .ENTER {
		cursor_state = .IN;
		return true;
	}

	return false;
}
c_draw_line_input :: (canvas : *Canvas, ui_elem : *UI_Elem, zone : Ibox2, style : *UI_Style) -> bool {
	using cast(*UI_Line_Input) ui_elem;

	fix_offset :: () #expand {
		if ptr_left - offset < 0 {
			offset = ptr_left;
		} else if ptr_left - offset >= zone.width {
			offset = ptr_left - zone.width + 1;
		}
	}
	fix_offset();

	left_part, right_part : string;
	left_part.data, left_part.count = buffer.data, ptr_left;

	right_part.data, right_part.count = buffer.data + ptr_right + 1, (buffer.count - ptr_right - 1);

	c_draw_line_ascii(canvas, left_part, zone, .{xx -offset, 0}, style.text.default);
	c_draw_line_ascii(canvas, right_part, zone, .{xx (ptr_left - offset), 0}, style.text.default);

	terminal_state.cursor = ifx cursor_state == .IN then zone.corner + ivec2.{xx(ptr_left - offset), 0} else .{-1, -1};

	return true;
}

init :: (using ui_line_input : *UI_Line_Input, max_length := 100) {
	buffer = NewArray(max_length, Char_Type);
	ptr_left, ptr_right = 0, max_length - 1;
}
add_char :: (using ui_line_input : *UI_Line_Input, c : Char_Type) -> bool {
	if ptr_left > ptr_right return false;
	buffer[ptr_left] = c;
	ptr_left += 1;
	return true;
}
remove_char_left :: (using ui_line_input : *UI_Line_Input) -> bool {
	if ptr_left == 0 return false;
	ptr_left -= 1;
	return true;
}
move_ptr :: (using ui_line_input : *UI_Line_Input, key : Key) -> bool {
	if key == {
		case .LEFT;
		if ptr_left > 0 {
			ptr_left -= 1;
			buffer[ptr_right] = buffer[ptr_left];
			ptr_right -= 1;
			return true;
		}
		case .RIGHT;
		if ptr_right < buffer.count-1 {
			ptr_right += 1;
			buffer[ptr_left] = buffer[ptr_right];
			ptr_left += 1;
			return true;
		}
		case;
		assert(false);
	}
	return false;
}
deinit :: (using ui_line_input : *UI_Line_Input) {
	array_free(buffer);
}

is_printable :: (key : Key) -> bool {
	code := cast(u64) key;
	return (code >= #char" " && code <= #char"~");
}

get_string :: (using ui_line_input : *UI_Line_Input, allocator := context.allocator) -> string {
	result : string;
	size := ptr_left + (buffer.count - ptr_right - 1);
	result.count = size;
	result.data = alloc(size, allocator);

	memcpy(result.data, buffer.data, ptr_left);
	memcpy(result.data + ptr_left, buffer.data + ptr_right + 1, buffer.count - ptr_right - 1);
	return result;
}
reset :: (using ui_line_input : *UI_Line_Input) {
	ptr_left = 0;
	ptr_right = buffer.count - 1;
}