1 #include "nuklear.h"
2 #include "nuklear_internal.h"
3
4 /* ==============================================================
5 *
6 * CONTEXTUAL
7 *
8 * ===============================================================*/
9 NK_API nk_bool
nk_contextual_begin(struct nk_context * ctx,nk_flags flags,struct nk_vec2 size,struct nk_rect trigger_bounds)10 nk_contextual_begin(struct nk_context *ctx, nk_flags flags, struct nk_vec2 size,
11 struct nk_rect trigger_bounds)
12 {
13 struct nk_window *win;
14 struct nk_window *popup;
15 struct nk_rect body;
16
17 NK_STORAGE const struct nk_rect null_rect = {-1,-1,0,0};
18 int is_clicked = 0;
19 int is_open = 0;
20 int ret = 0;
21
22 NK_ASSERT(ctx);
23 NK_ASSERT(ctx->current);
24 NK_ASSERT(ctx->current->layout);
25 if (!ctx || !ctx->current || !ctx->current->layout)
26 return 0;
27
28 win = ctx->current;
29 ++win->popup.con_count;
30 if (ctx->current != ctx->active)
31 return 0;
32
33 /* check if currently active contextual is active */
34 popup = win->popup.win;
35 is_open = (popup && win->popup.type == NK_PANEL_CONTEXTUAL);
36 is_clicked = nk_input_mouse_clicked(&ctx->input, NK_BUTTON_RIGHT, trigger_bounds);
37 if (win->popup.active_con && win->popup.con_count != win->popup.active_con)
38 return 0;
39 if (!is_open && win->popup.active_con)
40 win->popup.active_con = 0;
41 if ((!is_open && !is_clicked))
42 return 0;
43
44 /* calculate contextual position on click */
45 win->popup.active_con = win->popup.con_count;
46 if (is_clicked) {
47 body.x = ctx->input.mouse.pos.x;
48 body.y = ctx->input.mouse.pos.y;
49 } else {
50 body.x = popup->bounds.x;
51 body.y = popup->bounds.y;
52 }
53 body.w = size.x;
54 body.h = size.y;
55
56 /* start nonblocking contextual popup */
57 ret = nk_nonblock_begin(ctx, flags|NK_WINDOW_NO_SCROLLBAR, body,
58 null_rect, NK_PANEL_CONTEXTUAL);
59 if (ret) win->popup.type = NK_PANEL_CONTEXTUAL;
60 else {
61 win->popup.active_con = 0;
62 win->popup.type = NK_PANEL_NONE;
63 if (win->popup.win)
64 win->popup.win->flags = 0;
65 }
66 return ret;
67 }
68 NK_API nk_bool
nk_contextual_item_text(struct nk_context * ctx,const char * text,int len,nk_flags alignment)69 nk_contextual_item_text(struct nk_context *ctx, const char *text, int len,
70 nk_flags alignment)
71 {
72 struct nk_window *win;
73 const struct nk_input *in;
74 const struct nk_style *style;
75
76 struct nk_rect bounds;
77 enum nk_widget_layout_states state;
78
79 NK_ASSERT(ctx);
80 NK_ASSERT(ctx->current);
81 NK_ASSERT(ctx->current->layout);
82 if (!ctx || !ctx->current || !ctx->current->layout)
83 return 0;
84
85 win = ctx->current;
86 style = &ctx->style;
87 state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);
88 if (!state) return nk_false;
89
90 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
91 if (nk_do_button_text(&ctx->last_widget_state, &win->buffer, bounds,
92 text, len, alignment, NK_BUTTON_DEFAULT, &style->contextual_button, in, style->font)) {
93 nk_contextual_close(ctx);
94 return nk_true;
95 }
96 return nk_false;
97 }
98 NK_API nk_bool
nk_contextual_item_label(struct nk_context * ctx,const char * label,nk_flags align)99 nk_contextual_item_label(struct nk_context *ctx, const char *label, nk_flags align)
100 {
101 return nk_contextual_item_text(ctx, label, nk_strlen(label), align);
102 }
103 NK_API nk_bool
nk_contextual_item_image_text(struct nk_context * ctx,struct nk_image img,const char * text,int len,nk_flags align)104 nk_contextual_item_image_text(struct nk_context *ctx, struct nk_image img,
105 const char *text, int len, nk_flags align)
106 {
107 struct nk_window *win;
108 const struct nk_input *in;
109 const struct nk_style *style;
110
111 struct nk_rect bounds;
112 enum nk_widget_layout_states state;
113
114 NK_ASSERT(ctx);
115 NK_ASSERT(ctx->current);
116 NK_ASSERT(ctx->current->layout);
117 if (!ctx || !ctx->current || !ctx->current->layout)
118 return 0;
119
120 win = ctx->current;
121 style = &ctx->style;
122 state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);
123 if (!state) return nk_false;
124
125 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
126 if (nk_do_button_text_image(&ctx->last_widget_state, &win->buffer, bounds,
127 img, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)){
128 nk_contextual_close(ctx);
129 return nk_true;
130 }
131 return nk_false;
132 }
133 NK_API nk_bool
nk_contextual_item_image_label(struct nk_context * ctx,struct nk_image img,const char * label,nk_flags align)134 nk_contextual_item_image_label(struct nk_context *ctx, struct nk_image img,
135 const char *label, nk_flags align)
136 {
137 return nk_contextual_item_image_text(ctx, img, label, nk_strlen(label), align);
138 }
139 NK_API nk_bool
nk_contextual_item_symbol_text(struct nk_context * ctx,enum nk_symbol_type symbol,const char * text,int len,nk_flags align)140 nk_contextual_item_symbol_text(struct nk_context *ctx, enum nk_symbol_type symbol,
141 const char *text, int len, nk_flags align)
142 {
143 struct nk_window *win;
144 const struct nk_input *in;
145 const struct nk_style *style;
146
147 struct nk_rect bounds;
148 enum nk_widget_layout_states state;
149
150 NK_ASSERT(ctx);
151 NK_ASSERT(ctx->current);
152 NK_ASSERT(ctx->current->layout);
153 if (!ctx || !ctx->current || !ctx->current->layout)
154 return 0;
155
156 win = ctx->current;
157 style = &ctx->style;
158 state = nk_widget_fitting(&bounds, ctx, style->contextual_button.padding);
159 if (!state) return nk_false;
160
161 in = (state == NK_WIDGET_ROM || win->layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input;
162 if (nk_do_button_text_symbol(&ctx->last_widget_state, &win->buffer, bounds,
163 symbol, text, len, align, NK_BUTTON_DEFAULT, &style->contextual_button, style->font, in)) {
164 nk_contextual_close(ctx);
165 return nk_true;
166 }
167 return nk_false;
168 }
169 NK_API nk_bool
nk_contextual_item_symbol_label(struct nk_context * ctx,enum nk_symbol_type symbol,const char * text,nk_flags align)170 nk_contextual_item_symbol_label(struct nk_context *ctx, enum nk_symbol_type symbol,
171 const char *text, nk_flags align)
172 {
173 return nk_contextual_item_symbol_text(ctx, symbol, text, nk_strlen(text), align);
174 }
175 NK_API void
nk_contextual_close(struct nk_context * ctx)176 nk_contextual_close(struct nk_context *ctx)
177 {
178 NK_ASSERT(ctx);
179 NK_ASSERT(ctx->current);
180 NK_ASSERT(ctx->current->layout);
181 if (!ctx || !ctx->current || !ctx->current->layout) return;
182 nk_popup_close(ctx);
183 }
184 NK_API void
nk_contextual_end(struct nk_context * ctx)185 nk_contextual_end(struct nk_context *ctx)
186 {
187 struct nk_window *popup;
188 struct nk_panel *panel;
189 NK_ASSERT(ctx);
190 NK_ASSERT(ctx->current);
191 if (!ctx || !ctx->current) return;
192
193 popup = ctx->current;
194 panel = popup->layout;
195 NK_ASSERT(popup->parent);
196 NK_ASSERT(panel->type & NK_PANEL_SET_POPUP);
197 if (panel->flags & NK_WINDOW_DYNAMIC) {
198 /* Close behavior
199 This is a bit of a hack solution since we do not know before we end our popup
200 how big it will be. We therefore do not directly know when a
201 click outside the non-blocking popup must close it at that direct frame.
202 Instead it will be closed in the next frame.*/
203 struct nk_rect body = {0,0,0,0};
204 if (panel->at_y < (panel->bounds.y + panel->bounds.h)) {
205 struct nk_vec2 padding = nk_panel_get_padding(&ctx->style, panel->type);
206 body = panel->bounds;
207 body.y = (panel->at_y + panel->footer_height + panel->border + padding.y + panel->row.height);
208 body.h = (panel->bounds.y + panel->bounds.h) - body.y;
209 }
210 {int pressed = nk_input_is_mouse_pressed(&ctx->input, NK_BUTTON_LEFT);
211 int in_body = nk_input_is_mouse_hovering_rect(&ctx->input, body);
212 if (pressed && in_body)
213 popup->flags |= NK_WINDOW_HIDDEN;
214 }
215 }
216 if (popup->flags & NK_WINDOW_HIDDEN)
217 popup->seq = 0;
218 nk_popup_end(ctx);
219 return;
220 }
221
222