static void a3d_layer_layout(a3d_widget_t* widget, int dragx, int dragy) { assert(widget); LOGD("debug dragx=%i, dragy=%i", dragx, dragy); // the rect_clip is constant across all layers a3d_rect4f_t rect_clip; a3d_rect4f_intersect(&widget->rect_draw, &widget->rect_clip, &rect_clip); a3d_layer_t* self = (a3d_layer_t*) widget; a3d_listitem_t* iter = a3d_list_head(self->list); while(iter) { a3d_widget_t* child = (a3d_widget_t*) a3d_list_peekitem(iter); // layout the layer float x = 0.0f; float y = 0.0f; a3d_widget_anchorPt(&widget->rect_draw, child->anchor, &x, &y); a3d_widget_layoutXYClip(child, x, y, &rect_clip, dragx, dragy); iter = a3d_list_next(iter); } }
static void a3d_bulletbox_layout(a3d_widget_t* widget, int dragx, int dragy) { assert(widget); a3d_bulletbox_t* self = (a3d_bulletbox_t*) widget; a3d_widget_t* icon = (a3d_widget_t*) self->icon; a3d_widget_t* text = (a3d_widget_t*) self->text; // initialize the layout float x = 0.0f; float y = 0.0f; float t = widget->rect_draw.t; float l = widget->rect_draw.l; float h = widget->rect_draw.h; float iw = icon->rect_border.w; float tw = text->rect_border.w; // layout icon a3d_rect4f_t rect_draw; rect_draw.t = t; rect_draw.l = l; rect_draw.w = iw; rect_draw.h = h; a3d_rect4f_t rect_clip; a3d_widget_anchorPt(&rect_draw, icon->anchor, &x, &y); a3d_rect4f_intersect(&rect_draw, &widget->rect_clip, &rect_clip); a3d_widget_layoutXYClip(icon, x, y, &rect_clip, dragx, dragy); // layout text rect_draw.l = l + A3D_BULLETBOX_SPACE*iw; rect_draw.w = tw; a3d_widget_anchorPt(&rect_draw, text->anchor, &x, &y); a3d_rect4f_intersect(&rect_draw, &widget->rect_clip, &rect_clip); a3d_widget_layoutXYClip(text, x, y, &rect_clip, dragx, dragy); }
static void a3d_listbox_layoutHorizontalStretch(a3d_listbox_t* self, int dragx, int dragy) { assert(self); LOGD("debug dragx=%i, dragy=%i", dragx, dragy); // initialize the layout float x = 0.0f; float y = 0.0f; float t = self->widget.rect_draw.t; float l = self->widget.rect_draw.l; float w = self->widget.rect_draw.w; float h = self->widget.rect_draw.h; float cnt = (float) a3d_list_size(self->list); float dw = w/cnt; a3d_rect4f_t rect_clip; a3d_rect4f_t rect_draw; a3d_listitem_t* iter = a3d_list_head(self->list); while(iter) { a3d_widget_t* child = (a3d_widget_t*) a3d_list_peekitem(iter); rect_draw.t = t; rect_draw.l = l; rect_draw.w = dw; rect_draw.h = h; l += dw; a3d_widget_anchorPt(&rect_draw, child->anchor, &x, &y); a3d_rect4f_intersect(&rect_draw, &self->widget.rect_clip, &rect_clip); a3d_widget_layoutXYClip(child, x, y, &rect_clip, dragx, dragy); iter = a3d_list_next(iter); } }
static void a3d_listbox_layoutVerticalShrink(a3d_listbox_t* self, int dragx, int dragy) { assert(self); LOGD("debug dragx=%i, dragy=%i", dragx, dragy); // initialize the layout float x = 0.0f; float y = 0.0f; float t = self->widget.rect_draw.t; float l = self->widget.rect_draw.l; float w = self->widget.rect_draw.w; a3d_rect4f_t rect_clip; a3d_rect4f_t rect_draw; a3d_listitem_t* iter = a3d_list_head(self->list); while(iter) { a3d_widget_t* child = (a3d_widget_t*) a3d_list_peekitem(iter); float h = child->rect_border.h; rect_draw.t = t; rect_draw.l = l; rect_draw.w = w; rect_draw.h = h; t += h; a3d_widget_anchorPt(&rect_draw, child->anchor, &x, &y); a3d_rect4f_intersect(&rect_draw, &self->widget.rect_clip, &rect_clip); a3d_widget_layoutXYClip(child, x, y, &rect_clip, dragx, dragy); iter = a3d_list_next(iter); } }
static void a3d_hline_draw(a3d_widget_t* widget) { assert(widget); a3d_hline_t* self = (a3d_hline_t*) widget; // clip separator to border a3d_rect4f_t rect_border_clip; if(a3d_rect4f_intersect(&widget->rect_border, &widget->rect_clip, &rect_border_clip) == 0) { return; } // clip separator float top = widget->rect_clip.t; float h2 = widget->rect_clip.h/2.0f; a3d_rect4f_t line = { .t = top + h2, .l = rect_border_clip.l, .w = rect_border_clip.w, .h = 0.0f }; // draw the separator a3d_screen_t* screen = widget->screen; a3d_vec4f_t* c = &self->color; float alpha = widget->fade*c->a; if(alpha > 0.0f) { glDisable(GL_SCISSOR_TEST); if(alpha < 1.0f) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } glUseProgram(screen->prog); glEnableVertexAttribArray(screen->attr_coords); int line_style = A3D_WIDGET_LINE_MEDIUM; if(self->style == A3D_HLINE_STYLE_SMALL) { line_style = A3D_WIDGET_LINE_SMALL; } else if(self->style == A3D_HLINE_STYLE_LARGE) { line_style = A3D_WIDGET_LINE_LARGE; } float lw = a3d_screen_layoutLine(screen, line_style); glLineWidth(lw); a3d_rect4f_t* r = &line; glBindBuffer(GL_ARRAY_BUFFER, screen->id_coords2); glVertexAttribPointer(screen->attr_coords, 2, GL_FLOAT, GL_FALSE, 0, 0); a3d_mat4f_t mvp; a3d_mat4f_ortho(&mvp, 1, 0.0f, screen->w, screen->h, 0.0f, 0.0f, 2.0f); glUniformMatrix4fv(screen->unif_mvp, 1, GL_FALSE, (GLfloat*) &mvp); glUniform4f(screen->unif_rect, r->t, r->l, r->w, r->h); glUniform4f(screen->unif_color, c->r, c->g, c->b, alpha); glDrawArrays(GL_LINES, 0, 2); glLineWidth(1.0f); glBindBuffer(GL_ARRAY_BUFFER, 0); glDisableVertexAttribArray(screen->attr_coords); glUseProgram(0); if(alpha < 1.0f) { glDisable(GL_BLEND); } glEnable(GL_SCISSOR_TEST); } } /*********************************************************** * public * ***********************************************************/ a3d_hline_t* a3d_hline_new(a3d_screen_t* screen, int wsize, int anchor, int style_line, a3d_vec4f_t* color_line, int max_len) { assert(screen); assert(color_line); a3d_vec4f_t clear = { .r = 0.0f, .g = 0.0f, .b = 0.0f, .a = 0.0f }; if(wsize == 0) { wsize = sizeof(a3d_hline_t); } a3d_hline_t* self = (a3d_hline_t*) a3d_widget_new(screen, wsize, anchor, A3D_WIDGET_WRAP_SHRINK, A3D_WIDGET_WRAP_SHRINK, A3D_WIDGET_STRETCH_NA, 1.0f, A3D_WIDGET_BORDER_NONE, A3D_WIDGET_LINE_NONE, &clear, &clear, NULL, a3d_hline_size, NULL, NULL, NULL, a3d_hline_draw, NULL, NULL); if(self == NULL) { return NULL; } self->wrapx = A3D_HLINE_WRAP_SHRINK; self->max_len = max_len; self->style = style_line; a3d_vec4f_copy(color_line, &self->color); return self; } void a3d_hline_delete(a3d_hline_t** _self) { assert(_self); a3d_hline_t* self = *_self; if(self) { a3d_widget_delete((a3d_widget_t**) _self); } }
void a3d_widget_draw(a3d_widget_t* self) { assert(self); LOGD("debug"); if(self->fade == 0.0f) { return; } a3d_rect4f_t rect_border_clip; if(a3d_rect4f_intersect(&self->rect_border, &self->rect_clip, &rect_border_clip) == 0) { return; } // draw the fill a3d_screen_t* screen = self->screen; a3d_vec4f_t* c = &self->color_fill; float alpha = self->fade*c->a; if(alpha > 0.0f) { a3d_screen_scissor(screen, &rect_border_clip); if(alpha < 1.0f) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } a3d_mat4f_t mvp; glBindBuffer(GL_ARRAY_BUFFER, self->id_vtx_rect); a3d_mat4f_ortho(&mvp, 1, 0.0f, screen->w, screen->h, 0.0f, 0.0f, 2.0f); if(self->tone_y2 == 0.0f) { glEnableVertexAttribArray(self->attr_vertex); glVertexAttribPointer(self->attr_vertex, 2, GL_FLOAT, GL_FALSE, 0, 0); glUseProgram(self->prog); glUniform4f(self->unif_color, c->r, c->g, c->b, alpha); glUniformMatrix4fv(self->unif_mvp, 1, GL_FALSE, (GLfloat*) &mvp); } else { a3d_vec4f_t* c2 = &self->color_fill2; float alpha2 = self->fade*c2->a; glEnableVertexAttribArray(self->attr_vertex2); glVertexAttribPointer(self->attr_vertex2, 2, GL_FLOAT, GL_FALSE, 0, 0); glUseProgram(self->prog2); glUniform4f(self->unif_color2a, c->r, c->g, c->b, alpha); glUniform4f(self->unif_color2b, c2->r, c2->g, c2->b, alpha2); glUniform1f(self->unif_y2, self->tone_y2); glUniformMatrix4fv(self->unif_mvp2, 1, GL_FALSE, (GLfloat*) &mvp); } glDrawArrays(GL_TRIANGLE_FAN, 0, 4*A3D_WIDGET_BEZEL); glBindBuffer(GL_ARRAY_BUFFER, 0); if(self->tone_y2 == 0.0f) { glDisableVertexAttribArray(self->attr_vertex); } else { glDisableVertexAttribArray(self->attr_vertex2); } glUseProgram(0); if(alpha < 1.0f) { glDisable(GL_BLEND); } } // draw the contents a3d_rect4f_t rect_draw_clip; if(a3d_rect4f_intersect(&self->rect_draw, &self->rect_clip, &rect_draw_clip)) { a3d_widget_draw_fn draw_fn = self->draw_fn; if(draw_fn) { a3d_screen_scissor(screen, &rect_draw_clip); (*draw_fn)(self); } // draw the scroll bar float s = rect_draw_clip.h/self->rect_draw.h; if(self->scroll_bar && (s < 1.0f)) { // clamp the start/end points float a = -self->drag_dy/self->rect_draw.h; float b = a + s; if(a < 0.0f) { a = 0.0f; } else if(a > 1.0f) { a = 1.0f; } if(b < 0.0f) { b = 0.0f; } else if(b > 1.0f) { b = 1.0f; } a3d_vec4f_t* c0 = &self->color_scroll0; a3d_vec4f_t* c1 = &self->color_scroll1; a3d_screen_scissor(screen, &rect_border_clip); if((c0->a < 1.0f) || (c1->a < 1.0f)) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } a3d_mat4f_t mvp; glBindBuffer(GL_ARRAY_BUFFER, self->scroll_id_vtx_rect); a3d_mat4f_ortho(&mvp, 1, 0.0f, screen->w, screen->h, 0.0f, 0.0f, 2.0f); glEnableVertexAttribArray(self->scroll_attr_vertex); glVertexAttribPointer(self->scroll_attr_vertex, 4, GL_FLOAT, GL_FALSE, 0, 0); glUseProgram(self->scroll_prog); glUniform4f(self->scroll_unif_color0, c0->r, c0->g, c0->b, c0->a); glUniform4f(self->scroll_unif_color1, c1->r, c1->g, c1->b, c1->a); glUniform1f(self->scroll_unif_a, a); glUniform1f(self->scroll_unif_b, b); glUniformMatrix4fv(self->scroll_unif_mvp, 1, GL_FALSE, (GLfloat*) &mvp); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glBindBuffer(GL_ARRAY_BUFFER, 0); glDisableVertexAttribArray(self->scroll_attr_vertex); glUseProgram(0); if((c0->a < 1.0f) || (c1->a < 1.0f)) { glDisable(GL_BLEND); } } } // draw the border c = &self->color_line; alpha = self->fade*c->a; if((alpha > 0.0f) && (self->style_line != A3D_WIDGET_LINE_NONE)) { glDisable(GL_SCISSOR_TEST); if(alpha < 1.0f) { glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } glUseProgram(self->prog); glEnableVertexAttribArray(self->attr_vertex); // draw rounded line glBindBuffer(GL_ARRAY_BUFFER, self->id_vtx_line); glVertexAttribPointer(self->attr_vertex, 2, GL_FLOAT, GL_FALSE, 0, 0); a3d_mat4f_t mvp; a3d_mat4f_ortho(&mvp, 1, 0.0f, screen->w, screen->h, 0.0f, 0.0f, 2.0f); glUniformMatrix4fv(self->unif_mvp, 1, GL_FALSE, (GLfloat*) &mvp); glUniform4f(self->unif_color, c->r, c->g, c->b, alpha); glDrawArrays(GL_TRIANGLE_STRIP, 0, 2*(4*A3D_WIDGET_BEZEL + 1)); glBindBuffer(GL_ARRAY_BUFFER, 0); glDisableVertexAttribArray(self->attr_vertex); glUseProgram(0); if(alpha < 1.0f) { glDisable(GL_BLEND); } glEnable(GL_SCISSOR_TEST); } }
void a3d_widget_layoutXYClip(a3d_widget_t* self, float x, float y, a3d_rect4f_t* clip, int dragx, int dragy) { assert(self); assert(clip); LOGD("debug x=%f, y=%f, dragx=%i, dragy=%i", x, y, dragx, dragy); float w = self->rect_border.w; float h = self->rect_border.h; float ct = clip->t; float cl = clip->l; float cw = clip->w; float ch = clip->h; float w2 = w/2.0f; float h2 = h/2.0f; float t = y; float l = x; a3d_rect4f_copy(clip, &self->rect_clip); // anchor the widget origin if(self->anchor == A3D_WIDGET_ANCHOR_TC) { l = x - w2; } else if(self->anchor == A3D_WIDGET_ANCHOR_TR) { l = x - w; } else if(self->anchor == A3D_WIDGET_ANCHOR_CL) { t = y - h2; } else if(self->anchor == A3D_WIDGET_ANCHOR_CC) { t = y - h2; l = x - w2; } else if(self->anchor == A3D_WIDGET_ANCHOR_CR) { t = y - h2; l = x - w; } else if(self->anchor == A3D_WIDGET_ANCHOR_BL) { t = y - h; } else if(self->anchor == A3D_WIDGET_ANCHOR_BC) { t = y - h; l = x - w2; } else if(self->anchor == A3D_WIDGET_ANCHOR_BR) { t = y - h; l = x - w; } // drag the widget (see dragable rules) if(dragx && (w > cw)) { l += self->drag_dx; if(l > cl) { self->drag_dx -= l - cl; l = cl; } else if((l + w) < (cl + cw)) { self->drag_dx += (cl + cw) - (l + w); l = cl + cw - w; } dragx = 0; } if(dragy && (h > ch)) { t += self->drag_dy; if(t > ct) { self->drag_dy -= t - ct; t = ct; } else if((t + h) < (ct + ch)) { self->drag_dy += (ct + ch) - (t + h); t = ct + ch - h; } dragy = 0; } // set the layout float h_bo = 0.0f; float v_bo = 0.0f; a3d_screen_layoutBorder(self->screen, self->style_border, &h_bo, &v_bo); self->rect_border.t = t; self->rect_border.l = l; self->rect_draw.t = t + v_bo; self->rect_draw.l = l + h_bo; // allow the widget to layout it's children a3d_widget_layout_fn layout_fn = self->layout_fn; if(layout_fn) { (*layout_fn)(self, dragx, dragy); } // initialize rounded rectangle float b = self->rect_border.t + self->rect_border.h; float r = self->rect_border.l + self->rect_border.w; float radius = (h_bo == v_bo) ? h_bo : 0.0f; int steps = A3D_WIDGET_BEZEL; int size_rect = 4*steps*2; // corners*steps*xy GLfloat vtx_rect[size_rect]; a3d_widget_makeRoundRect(vtx_rect, steps, t + v_bo, l + h_bo, b - v_bo, r - v_bo, radius); glBindBuffer(GL_ARRAY_BUFFER, self->id_vtx_rect); glBufferData(GL_ARRAY_BUFFER, size_rect*sizeof(GLfloat), vtx_rect, GL_STATIC_DRAW); a3d_rect4f_t rect_border_clip; if(a3d_rect4f_intersect(&self->rect_border, &self->rect_clip, &rect_border_clip)) { if(self->scroll_bar) { float h_bo = 0.0f; float v_bo = 0.0f; a3d_screen_layoutBorder(self->screen, A3D_WIDGET_BORDER_MEDIUM, &h_bo, &v_bo); float w = h_bo; float t = rect_border_clip.t; float l = rect_border_clip.l + rect_border_clip.w - w; float h = rect_border_clip.h; float b = t + h; float r = l + w; int sz = 16; // 4*xyuv GLfloat xyuv[] = { l, t, 0.0f, 0.0f, // top-left l, b, 0.0f, 1.0f, // bottom-left r, t, 1.0f, 0.0f, // top-right r, b, 1.0f, 1.0f, // bottom-right }; glBindBuffer(GL_ARRAY_BUFFER, self->scroll_id_vtx_rect); glBufferData(GL_ARRAY_BUFFER, sz*sizeof(GLfloat), xyuv, GL_STATIC_DRAW); } } // initialize rounded line float lw = a3d_screen_layoutLine(self->screen, self->style_line); int size_line = 2*4*steps*2 + 2*2; // edges*corners*steps*xy + edges*xy GLfloat vtx_line[size_line]; a3d_widget_makeRoundLines(vtx_line, steps, t + v_bo, l + h_bo, b - v_bo, r - v_bo, radius, lw); glBindBuffer(GL_ARRAY_BUFFER, self->id_vtx_line); glBufferData(GL_ARRAY_BUFFER, size_line*sizeof(GLfloat), vtx_line, GL_STATIC_DRAW); }