~rycwo/forge

ref: HEAD forge/src/gui_basic.c -rw-r--r-- 2.9 KiB
d7ee94d6Ryan Chan Fix missing cd in .build.yml 8 days ago
                                                                                
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
// This file is part of Forge, the foundation library for Forge tools.
//
// Copyright (C) 2021 Ryan Chan <rycwo@posteo.net>
// SPDX-License-Identifier: GPL-3.0-only
//
// This Source Code Form is subject to the terms of the GNU General Public
// License v3.0 only. You should have received a copy of the license along with
// this program. If not, see <https://www.gnu.org/licenses/>.

#include "forge/gui_basic.h"

#include <assert.h>

#include "forge/gui_draw.h"
#include "forge/gui_input.h"
#include "forge/gui_layout.h"
#include "forge/input.h"
#include "forge/vector.h"

void
fg_set_gui_layer(struct fg_gui_context* context, int layer) {
	context->layer = layer;
}

void
fg_gui_rect(
		struct fg_gui_context* context,
		struct fg_gui_style const* style,
		fg_vec2 const size) {
	fg_vec2 pos;
	fg_pop_next_gui_position(context, pos, true);
	fg_draw_gui_rect(
		context,
		style,
		(fg_vec4){pos[0], pos[1], size[0], size[1]});
}

void
fg_begin_gui_container(
		struct fg_gui_context* context,
		struct fg_gui_style const* style,
		fg_vec2 const size) {
	fg_vec2 pos;
	fg_pop_next_gui_position(context, pos, false);

	fg_push_gui_layout_container(
			context,
			(fg_vec4){pos[0], pos[1], size[0], size[1]},
			false);

	fg_vec4 rect;
	fg_gui_top_layout_container(context, rect, true);
	fg_draw_gui_rect(context, style, rect);
}

void
fg_end_gui_container(struct fg_gui_context* context) {
	fg_pop_gui_layout_container(context, (fg_vec4){0}, false);
}

bool
fg_gui_button(
		struct fg_gui_context* context,
		uint64_t id,
		struct fg_gui_button_style const* button_style,
		fg_vec2 const size,
		int flags) {
	assert(id != 0);
	fg_vec2 pos;
	fg_pop_next_gui_position(context, pos, true);
	fg_vec4 const rect = {pos[0], pos[1], size[0], size[1]};

	// TODO: Take button flags into account
	bool const hovered = fg_gui_item_hovered(context, id, rect);
	int state = FG_GUI_BUTTON_STATE_NONE;
	if (hovered && !context->active) {
		// The button stays active as long as the mouse button is held
		if (context->input.mouse_press & FG_MOUSE_BUTTON_LEFT)
			context->active = id;
		// Only enter hover state if the mouse wasn't already pressed
		if (!(context->input.mouse & FG_MOUSE_BUTTON_LEFT))
			state = FG_GUI_BUTTON_STATE_HOVER;
	}
	if (context->active == id) {
		if (context->input.mouse_release & FG_MOUSE_BUTTON_LEFT) {
			// Only trigger the button if the mouse was released over it
			if (hovered)
				state = FG_GUI_BUTTON_STATE_TRIGGER;
			context->active = 0;
		}
		else if (hovered)
			state = FG_GUI_BUTTON_STATE_ACTIVE;
	}

	static int const states[FG_GUI_BUTTON_STATE_Size] = {
		FG_GUI_BUTTON_STYLE_NONE,
		FG_GUI_BUTTON_STYLE_HOVER,
		FG_GUI_BUTTON_STYLE_FOCUS,
		FG_GUI_BUTTON_STYLE_ACTIVE,
		FG_GUI_BUTTON_STYLE_TRIGGER
	};

	struct fg_gui_style const* style
		= &button_style->style[FG_GUI_BUTTON_STATE_NONE];
	if (button_style->states & states[state])
		style = &button_style->style[state];
	fg_draw_gui_rect(context, style, rect);
	return state == FG_GUI_BUTTON_STATE_TRIGGER;
}