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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
use super::{parts::*, *};
use crate::uses::{math::*, GL::font::Font, GL::window::*, *};

#[derive(Default)]
pub struct Theme {
	pub easing: f32,
	pub bg: Color,
	pub bg_focus: Color,
	pub fg: Color,
	pub fg_focus: Color,
	pub highlight: Color,
	pub text: Color,
	pub text_focus: Color,
	pub text_highlight: Color,
	pub font: Font,
	pub font_size: f32,
}

pub fn hex_to_rgba(c: u32) -> Color {
	Color::to(((c & 0xff000000) >> 24, (c & 0xff0000) >> 16, (c & 0xff00) >> 8, c & 0xff)).div(255)
}

impl Renderer {
	pub fn new(t: Theme) -> Self {
		let s = Self::default();
		s.set_theme(t);
		s
	}
	pub fn set_theme(&self, t: Theme) {
		ASSERT!(borrow_map().is_empty(), "Cannot change theme mid-draw");
		*theme() = t;
	}
}

pub trait GuiStorage {
	fn storage(id: u32) -> &'static mut Self;
}
impl GuiStorage for Button {
	fn storage(id: u32) -> &'static mut Self {
		UnsafeOnce!(HashMap<u32, Button>, { HashMap::new() }).entry(id).or_default()
	}
}
impl GuiStorage for Label {
	fn storage(id: u32) -> &'static mut Self {
		UnsafeOnce!(HashMap<u32, Label>, { HashMap::new() }).entry(id).or_default()
	}
}
impl GuiStorage for Layout {
	fn storage(id: u32) -> &'static mut Self {
		UnsafeOnce!(HashMap<u32, Layout>, { HashMap::new() }).entry(id).or_default()
	}
}
impl GuiStorage for LineEdit {
	fn storage(id: u32) -> &'static mut Self {
		UnsafeOnce!(HashMap<u32, LineEdit>, { HashMap::new() }).entry(id).or_default()
	}
}
impl GuiStorage for Selector {
	fn storage(id: u32) -> &'static mut Self {
		UnsafeOnce!(HashMap<u32, Selector>, { HashMap::new() }).entry(id).or_default()
	}
}
impl GuiStorage for Slider {
	fn storage(id: u32) -> &'static mut Self {
		UnsafeOnce!(HashMap<u32, Slider>, { HashMap::new() }).entry(id).or_default()
	}
}
impl GuiStorage for TextEdit {
	fn storage(id: u32) -> &'static mut Self {
		UnsafeOnce!(HashMap<u32, TextEdit>, { HashMap::new() }).entry(id).or_default()
	}
}

impl<'l> RenderLock<'l> {
	pub fn Button(&mut self, id: u32, pos: Vec2, size: Vec2, text: &str) -> bool {
		check_borrow(id);
		Button::storage(id).draw(self, t(), pos, size, text)
	}
	pub fn Label(&mut self, id: u32, pos: Vec2, size: Vec2, text: &str) {
		check_borrow(id);
		Label::storage(id).draw(self, t(), pos, size, text)
	}
	pub fn Layout(&mut self, id: u32, content: impl FnOnce(&mut RenderLock<'l>, Crop)) {
		check_borrow(id);
		Layout::storage(id).draw(self, t(), content)
	}
	pub fn LineEdit(&mut self, id: u32, pos: Vec2, size: Vec2) {
		check_borrow(id);
		LineEdit::storage(id).draw(self, t(), pos, size)
	}
	pub fn Selector(&mut self, id: u32, pos: Vec2, size: Vec2, options: &'l mut [String]) -> usize {
		check_borrow(id);
		Selector::storage(id).draw(self, t(), pos, size, options)
	}
	pub fn Slider(&mut self, id: u32, pos: Vec2, size: Vec2, pip_size: f32) -> f32 {
		check_borrow(id);
		Slider::storage(id).draw(self, t(), pos, size, pip_size)
	}
	pub fn TextEdit(&mut self, id: u32, pos: Vec2, size: Vec2, scale: f32) {
		check_borrow(id);
		TextEdit::storage(id).draw(self, t(), pos, size, scale, false)
	}
	pub fn TextList(&mut self, id: u32, pos: Vec2, size: Vec2, scale: f32) {
		check_borrow(id);
		TextEdit::storage(id).draw(self, t(), pos, size, scale, true)
	}
	pub fn clipboard() -> &'l str {
		let (str, _) = clip_store();
		str
	}
	pub fn set_clipboard(s: &str) {
		*clip_store() = (s.into(), true);
	}
	pub fn sync_clipboard(&self, w: &mut Window) {
		let (str, changed) = clip_store();
		if *changed {
			w.set_clipboard(str);
			*changed = false;
		}
	}
}

pub fn borrow_map() -> &'static mut HashSet<u32> {
	UnsafeOnce!(HashSet<u32>, { HashSet::new() })
}
fn check_borrow(id: u32) {
	ASSERT!(
		borrow_map().get(&id).is_none(),
		"An element `{}' cannot be drawn more than once per frame",
		chksum::collision_map().get(&id).unwrap()
	);
	borrow_map().insert(id);
}

fn clip_store() -> &'static mut (String, bool) {
	UnsafeOnce!((String, bool), { ("".into(), false) })
}

fn theme() -> &'static mut Theme {
	UnsafeOnce!(Theme, { Def() })
}
fn t() -> &'static Theme {
	let t = theme();
	ASSERT!(!t.font.glyphs.is_empty(), "No theme set for gui");
	t
}