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