static void a3d_hline_size(a3d_widget_t* widget, float* w, float* h) { assert(widget); assert(w); assert(h); a3d_hline_t* self = (a3d_hline_t*) widget; a3d_font_t* font = a3d_screen_font(widget->screen, A3D_SCREEN_FONT_REGULAR); float size = a3d_screen_layoutText(widget->screen, self->style); if(self->wrapx == A3D_HLINE_WRAP_STRETCH) { float aspect = a3d_font_aspectRatioAvg(font); int max_len = self->max_len; *w = size*aspect*max_len; } else if(self->wrapx == A3D_HLINE_WRAP_STRETCH_PARENT) { // ignore } else { float width = (float) a3d_hline_width(self); float height = (float) a3d_hline_height(self); *w = size*(width/height); } *h = size; }
int a3d_hline_height(a3d_hline_t* self) { assert(self); a3d_widget_t* widget = (a3d_widget_t*) self; a3d_font_t* font = a3d_screen_font(widget->screen, A3D_SCREEN_FONT_REGULAR); return a3d_font_height(font); }
static void a3d_textbox_reflow(a3d_widget_t* widget, float w, float h) { assert(widget); LOGD("debug w=%f, h=%f", w, h); a3d_textbox_t* self = (a3d_textbox_t*) widget; // reflow text when changes occur if((self->dirty == 0) && (self->last_w == w) && (self->last_h == h)) { return; } self->dirty = 0; self->last_w = w; self->last_h = h; // determine maxi a3d_font_t* font = a3d_screen_font(widget->screen); float aspect = a3d_font_aspectRatio(font); float size = a3d_screen_layoutText(widget->screen, self->style_text); int maxi = (int) (w/(aspect*size)) - 1; // maxi does not include null character // but max_len does // limit to max_len if((maxi >= self->max_len) || (maxi == 0)) { maxi = self->max_len - 1; } // clear the text a3d_listbox_t* listbox = (a3d_listbox_t*) self; a3d_listitem_t* iter = a3d_list_head(listbox->list); while(iter) { a3d_text_t* text; text = (a3d_text_t*) a3d_list_remove(listbox->list, &iter); a3d_text_delete(&text); } // initialize parser char tok[256]; char dst[256]; int srci = 0; int toki = 0; int dsti = 0; int type = A3D_TOKEN_END; // reflow the string(s) iter = a3d_list_head(self->strings); while(iter) { const char* src = (const char*) a3d_list_peekitem(iter); srci = 0; type = getToken(src, tok, &srci, &toki); while(type != A3D_TOKEN_END) { if(type == A3D_TOKEN_BREAK) { if(dsti > 0) { a3d_textbox_printText(self, dst); a3d_textbox_printText(self, ""); } else { a3d_textbox_printText(self, ""); } dsti = 0; break; } if(dsti == 0) { strncpy(dst, tok, 256); dst[255] = '\0'; dsti = toki; } else { if(dsti + toki + 1 <= maxi) { strcat(dst, " "); strcat(dst, tok); dst[255] = '\0'; dsti += toki + 1; } else { a3d_textbox_printText(self, dst); strncpy(dst, tok, 256); dst[255] = '\0'; dsti = toki; } } type = getToken(src, tok, &srci, &toki); } iter = a3d_list_next(iter); } if(dsti > 0) { a3d_textbox_printText(self, dst); } }
void a3d_widget_layoutSize(a3d_widget_t* self, float* w, float* h) { assert(self); assert(w); assert(h); LOGD("debug w=%f, h=%f", *w, *h); float sw; float sh; a3d_screen_sizef(self->screen, &sw, &sh); a3d_font_t* font = a3d_screen_font(self->screen, A3D_SCREEN_FONT_REGULAR); float ar = a3d_font_aspectRatioAvg(font); float th = 0.0f; if((self->wrapy >= A3D_WIDGET_WRAP_STRETCH_TEXT_SMALL) && (self->wrapy <= A3D_WIDGET_WRAP_STRETCH_TEXT_LARGE)) { int style = self->wrapy - A3D_WIDGET_WRAP_STRETCH_TEXT_SMALL; th = a3d_screen_layoutText(self->screen, style); } float tw = ar*th; // screen/text/parent square float ssq = (sw > sh) ? sh : sw; float tsq = th; // always use the height for square float psq = (*w > *h) ? *h : *w; int sq = (self->stretch_mode == A3D_WIDGET_STRETCH_SQUARE); // initialize size float h_bo = 0.0f; float v_bo = 0.0f; a3d_screen_layoutBorder(self->screen, self->style_border, &h_bo, &v_bo); if(self->wrapx == A3D_WIDGET_WRAP_SHRINK) { self->rect_draw.w = *w - 2.0f*h_bo; self->rect_border.w = *w; } else { float rw = 0.0f; if(self->wrapx == A3D_WIDGET_WRAP_STRETCH_SCREEN) { rw = sq ? ssq : sw; rw *= self->stretch_factor; self->rect_draw.w = rw - 2.0f*h_bo; self->rect_border.w = rw; } else if((self->wrapx >= A3D_WIDGET_WRAP_STRETCH_TEXT_SMALL) && (self->wrapx <= A3D_WIDGET_WRAP_STRETCH_TEXT_LARGE)) { rw = sq ? tsq : tw; rw *= self->stretch_factor; self->rect_draw.w = rw; self->rect_border.w = rw + 2.0f*h_bo; } else { rw = sq ? psq : *w; rw *= self->stretch_factor; self->rect_draw.w = rw - 2.0f*h_bo; self->rect_border.w = rw; } } // intersect draw with border interior if(self->rect_draw.w < 0.0f) { self->rect_draw.w = 0.0f; } if(self->wrapy == A3D_WIDGET_WRAP_SHRINK) { self->rect_draw.h = *h - 2.0f*v_bo; self->rect_border.h = *h; } else { float rh = 0.0f; if(self->wrapy == A3D_WIDGET_WRAP_STRETCH_SCREEN) { rh = sq ? ssq : sh; rh *= self->stretch_factor; self->rect_draw.h = rh - 2.0f*v_bo; self->rect_border.h = rh; } else if((self->wrapy >= A3D_WIDGET_WRAP_STRETCH_TEXT_SMALL) && (self->wrapy <= A3D_WIDGET_WRAP_STRETCH_TEXT_LARGE)) { rh = sq ? tsq : th; rh *= self->stretch_factor; self->rect_draw.h = rh; self->rect_border.h = rh + 2.0f*v_bo; } else { rh = sq ? psq : *h; rh *= self->stretch_factor; self->rect_draw.h = rh - 2.0f*v_bo; self->rect_border.h = rh; } } // intersect draw with border interior if(self->rect_draw.h < 0.0f) { self->rect_draw.h = 0.0f; } // reflow dynamically sized widgets (e.g. textbox) // this makes the most sense for stretched widgets float draw_w = self->rect_draw.w; float draw_h = self->rect_draw.h; a3d_widget_reflow_fn reflow_fn = self->reflow_fn; if(reflow_fn) { (*reflow_fn)(self, draw_w, draw_h); } // compute draw size for shrink wrapped widgets and // recursively compute size of any children // the draw size of the widget also becomes the border // size of any children a3d_widget_size_fn size_fn = self->size_fn; if(size_fn) { (*size_fn)(self, &draw_w, &draw_h); } // wrap width if(self->wrapx == A3D_WIDGET_WRAP_SHRINK) { self->rect_draw.w = draw_w; self->rect_border.w = draw_w + 2.0f*h_bo; } // wrap height if(self->wrapy == A3D_WIDGET_WRAP_SHRINK) { self->rect_draw.h = draw_h; self->rect_border.h = draw_h + 2.0f*v_bo; } *w = self->rect_border.w; *h = self->rect_border.h; }