#include #include #include #include #include "font-info.h" #include "lkb-tree.h" #include "lkb-avm.h" #include #include #include "gc-list.h" // feature structure visualization extern window_t *avm_window; extern lkb_avm *avm; int color_terminal_types = 1; int center_features = 1; font_info terminal_font; font_info type_display_font = {"helvetica", 12, fsRoman, {20000,20000,60000}, 0}; font_info error_display_font = {"helvetica", 12, fsRoman, {60000,20000,20000}, 0}; font_info error_fdisplay_font = {"courier", 12, fsRoman, {60000,20000,20000}, 0}; font_info feature_display_font = {"courier", 12, fsRoman, {0,0,0}, 0}; font_info tag_display_font = {"helvetica", 12, fsRoman, {20000,50000,0}, 0}; color_t structure_bracket_color = {0,0,0}; color_t list_bracket_color = {0,0,0}; color_t tag_box_color = {20000,50000,0}; color_t black={0,0,0}; int current_offset_x = 0, current_offset_y = 0; void *hilite_avm = 0; char *hilite_tag = 0; gc_list *target_gcl = 0; extern char *non_empty_list_type, *empty_list_type, *list_type; void downcase_string(char *s); int draw_type(int x, int y, char *type, int display, struct font_info *fi); int render_avm(lkb_avm *t, int *DY, int *DX, int display); int render_avm_list(lkb_avm_list *list, int *DY, int *DX, int display); get_font(font_info *fi) { char name[256], *attr[4] = {"","b","i","bi"}; if(!fi->font) { sprintf(name, "%s-%d%s", fi->family, fi->size, ((unsigned)fi->style<4)?attr[fi->style]:""); //printf("asking for font %s\n", name); fi->font = yzGetFont(name); //printf("on return fi->font->attr = %d\n", fi->font->attr); } } use_font(font_info *fi) { if(!fi->font)get_font(fi); yzPenColor1c(fi->color); yzUseFont(fi->font); } render_avm_item(lkb_avm *t, int what, int *DY, int *DX, int display, lkb_avm_tag *tag) { int tag_dx = 0, rest_dx = 0, tag_dy = 0; int item_dx, item_dy; color_t sel_col = {40000, 40000, 65535}; if(display && t && t == hilite_avm) { // prepare a light blue backdrop for the item if it's hilited render_avm_item(t, what, &item_dy, &item_dx, 0, tag); add_rect_gcl(target_gcl, 0, 0, item_dx-1, item_dy-1, sel_col); //yzPenColor1c(sel_col); //yzRect(0, 0, item_dx-1, item_dy-1); } if(tag) { if(!tag_dx && !tag_dy) { tag_dy = tag_display_font.size*13/12; if(!tag->width) { use_font(&tag_display_font); tag->width = yzStringSize(tag->name, strlen(tag->name)); if(!tag->width)tag->width = 1; } tag_dx = 3 + tag->width; } if(t) { //yzPushOrigin(tag_dx + 3, 0); current_offset_x += tag_dx + 3; } } if(t)switch(what) { case avm_structure: render_avm(t, DY, DX, display); break; case avm_list: render_avm_list((lkb_avm_list*)t, DY, DX, display); break; case avm_terminal: downcase_string((char*)t); *DX = draw_type(0, type_display_font.size*0.75 -6, (char*)t, display, &terminal_font); *DY = terminal_font.size*20/12; break; } else *DX = *DY = 0; if(tag) { if(t) { current_offset_x -= tag_dx + 3; //yzPopOrigin(); *DX += tag_dx + 3; } else *DX = tag_dx; if(*DY < tag_dy + tag_display_font.size*4/12)*DY = tag_dy + tag_display_font.size*4/12; draw_tag(0, (*DY)/2 - tag_dy/2 - 1, tag, display); } } void downcase_string(char *s) { while(*s) { *s = tolower(*s); s++; } } render_avm(lkb_avm *t, int *DY, int *DX, int display) { int i, mdy, fdy, tdy, dx, mdx = 0, mtdx, fdx, type_dx, type_dy; int *type_y = 0; char typetext[1024] = "UNINITIALIZED"; if(terminal_font.font)yzFreeFont(terminal_font.font); terminal_font = type_display_font; terminal_font.font = 0; if(!color_terminal_types)terminal_font.color = black; // calculate feature-name widths mtdx = 0; if(t->expand) { use_font(&feature_display_font); for(i=0;inattr;i++) { if(t->attr_hide[i]==2)continue; if(t->attr_ldx[i]==0) t->attr_ldx[i] = yzStringSize(t->attr_name[i], strlen(t->attr_name[i])) + 4 + 15; dx = t->attr_ldx[i]; if(dx > mtdx)mtdx = dx; } } // mtdx = x pos for 'value's. // calculate size for type name downcase_string(t->type); use_font(&type_display_font); type_dx = yzStringSize(t->type, strlen(t->type)) + 4 + 4; if(t->failure) { //free(t->type); switch(t->failure->what) { case ufail_no_glb: //sprintf(typetext, "%s (!) %s", t->failure->type1, t->failure->type2); downcase_string(t->failure->type1); downcase_string(t->failure->type2); i = yzStringSize(t->failure->type2, strlen(t->failure->type2)) + 4 + 4; if(i>type_dx)type_dx = i; type_dy = 2; break; case ufail_cycle: //sprintf(typetext, "%s - ERROR", t->type); type_dy = 1; break; case ufail_constraint: //sprintf(typetext, "%s (!) %s (!) %s", t->failure->type1, t->failure->type2, t->failure->constraint); downcase_string(t->failure->type1); downcase_string(t->failure->type2); downcase_string(t->failure->constraint); i = yzStringSize(t->failure->type2, strlen(t->failure->type2)) + 4 + 4; if(i>type_dx)type_dx = i; i = yzStringSize(t->failure->constraint, strlen(t->failure->constraint)) + 4 + 4; if(i>type_dx)type_dx = i; type_dy = 3; break; default: printf("ERROR\n"); break; } //t->type = strdup(typetext); } else type_dy = 1; type_dy *= type_display_font.size; if(type_dx>mdx)mdx=type_dx; /*if(type_dx + 3 < mtdx) // can nestle slightly beside values mdy = type_display_font.size*0.75 + 4; else */mdy = type_dy + 7; if(t->expand) // display rest of structure if expanded { if(display)type_y = malloc(sizeof(int)*t->nattr); for(i=0;inattr;i++) { if(t->attr_hide[i]==2)continue; tdy = 6 + type_display_font.size; //yzPushOrigin(mtdx, mdy); current_offset_x += mtdx; current_offset_y += mdy; render_avm_item(t->attr_value[i], t->attr_what[i], &fdy, &fdx, display, t->attr_tag[i]); t->attr_x[i] = current_offset_x; t->attr_y[i] = current_offset_y; t->attr_dx[i] = fdx; t->attr_dy[i] = fdy; current_offset_x -= mtdx; current_offset_y -= mdy; //yzPopOrigin(); if(fdy < feature_display_font.size+4)fdy = feature_display_font.size+4; if(display) { if(center_features)type_y[i] = mdy+fdy/2+ feature_display_font.size*5/12; else type_y[i] = mdy+tdy- feature_display_font.size*4/12; } mdy += fdy; if(fdx + mtdx + 4 > mdx)mdx = fdx + mtdx + 4; } if(display) { //use_font(&feature_display_font); error_fdisplay_font.font = feature_display_font.font; for(i=0;inattr;i++) { if(t->attr_hide[i]==2)continue; //yzText(4, type_y[i], t->attr_name[i]); add_text_gcl(target_gcl, mtdx - 8, 4, type_y[i], t->attr_name[i], (t->attr_cycle[i])?&error_fdisplay_font:&feature_display_font); // if(t->attr_cycle[i]) // t->attr_cycle[i]->x = 4+current_offset_x, t->attr_cycle[i]->y = type_y[i]+current_offset_y; } free(type_y); } } else mdx = type_dx; t->type_dx = type_dx; t->type_dy = type_dy; if(display) { error_display_font.font = type_display_font.font; t->x1 = 4 + current_offset_x; t->y1 = type_display_font.size*0.75 + 4 + current_offset_y; if(t->expand)type_dx = mdx - 8; // consider the entire top of the avm to be the type if(!t->failure) { if(t->nattr)add_text_gcl(target_gcl, type_dx, 4, type_display_font.size*0.75 + 4, t->type, &type_display_font); else add_text_gcl(target_gcl, type_dx, 4, type_display_font.size*0.75 + 4, t->type, &terminal_font); } else switch(t->failure->what) { case ufail_no_glb: add_text_gcl(target_gcl, type_dx, 4, type_display_font.size*0.75 + 4, t->failure->type1, &error_display_font); add_text_gcl(target_gcl, type_dx, 4, type_display_font.size*0.75 + type_dy/2 + 4, t->failure->type2, &error_display_font); break; case ufail_cycle: add_text_gcl(target_gcl, type_dx, 4, type_display_font.size*0.75 + 4, t->type, &error_display_font); break; case ufail_constraint: add_text_gcl(target_gcl, type_dx, 4, type_display_font.size*0.75 + 4, t->failure->type1, &error_display_font); add_text_gcl(target_gcl, type_dx, 4, type_display_font.size*0.75 + type_dy/3 + 4, t->failure->type2, &error_display_font); add_text_gcl(target_gcl, type_dx, 4,type_display_font.size*0.75 + 2*type_dy/3 + 4, t->failure->constraint, &error_display_font); break; default: printf("ERROR\n"); break; } //yzText(4, type_display_font.size*0.75 + 4, t->type); if(t->failure)t->failure->x = t->x1, t->failure->y = t->y1; } mdy += 2; if(!t->nattr && !t->failure) { mdy = type_display_font.size * 17/12 - 2; } if(display) { if(t->nattr) { //yzPenColor1c(structure_bracket_color); add_line_gcl(target_gcl, 0, 0, 0, mdy, structure_bracket_color); add_line_gcl(target_gcl, mdx, 0, mdx, mdy, structure_bracket_color); add_line_gcl(target_gcl, 0, 0, 5, 0, structure_bracket_color); add_line_gcl(target_gcl, 0, mdy, 5, mdy, structure_bracket_color); add_line_gcl(target_gcl, mdx, 0, mdx-5, 0, structure_bracket_color); add_line_gcl(target_gcl, mdx, mdy, mdx-5, mdy, structure_bracket_color); } //yzLine(0, 0, 0, mdy); //yzLine(mdx, 0, mdx, mdy); //yzLine(0, 0, 5, 0); //yzLine(0, mdy, 5, mdy); //yzLine(mdx, 0, mdx-5, 0); //yzLine(mdx, mdy, mdx-5, mdy); t->dx = mdx; t->dy = mdy+2; } *DY = mdy + 2; *DX = mdx; } open_bracket(int *X, int ldy, int mdy, int display) { if(ldy > 200)ldy=200; if(display) { //yzPenColor1c(list_bracket_color); //yzLine(*X, mdy/2, *X+5, mdy/2-(ldy*0.25)); add_line_gcl(target_gcl, *X, mdy/2, *X+5, mdy/2-(ldy*0.25), list_bracket_color); //yzLine(*X, mdy/2, *X+5, mdy/2+(ldy*0.25)); add_line_gcl(target_gcl, *X, mdy/2, *X+5, mdy/2+(ldy*0.25), list_bracket_color); } *X += 6; } close_bracket(int *X, int ldy, int mdy, int display) { if(ldy > 200)ldy=200; if(display) { //yzPenColor1c(list_bracket_color); //yzLine(*X+5, mdy/2, *X, mdy/2-(ldy*0.25)); add_line_gcl(target_gcl, *X+5, mdy/2, *X, mdy/2-(ldy*0.25), list_bracket_color); //yzLine(*X+5, mdy/2, *X, mdy/2+(ldy*0.25)); add_line_gcl(target_gcl, *X+5, mdy/2, *X, mdy/2+(ldy*0.25), list_bracket_color); } *X += 6; } list_addition(int *X, int mdy, int display) { int radius = 5; color_t black = {0,0,0}; if(display) { //yzPenColor1c(black); //yzCircle(*X+radius, mdy/2, radius); add_circle_gcl(target_gcl, *X+radius, mdy/2, radius, black); //yzLine(*X, mdy/2, *X+radius*2, mdy/2); add_line_gcl(target_gcl, *X, mdy/2, *X+radius*2, mdy/2, black); //yzLine(*X+radius, mdy/2-radius, *X+radius, mdy/2+radius); add_line_gcl(target_gcl, *X+radius, mdy/2-radius, *X+radius, mdy/2+radius, black); } *X += radius*2; } draw_ellipsis(int *X, int mdy, int display) { static int dx = -1; if(dx<0)dx = yzStringSize("...", 3) + 2; if(display) { //yzPenColor(0,0,0); //yzText(*X, mdy/2 + 3, "..."); add_text_gcl(target_gcl, dx, *X, mdy/2 + 3, "...", &feature_display_font); } *X += dx; } draw_tag(int x, int y, lkb_avm_tag *tag, int display) { int tag_dx, hilite = 0; color_t white_color = {65535,65535,65535}; color_t red = {65535,0,0}; if(!tag->width) { use_font(&tag_display_font); tag->width = yzStringSize(tag->name, strlen(tag->name)); if(!tag->width)tag->width = 1; } tag_dx = 3 + tag->width; if(display) { //if(hilite_avm == tag || (hilite_tag && !strcmp(tag->name, hilite_tag))) //hilite = 1; /*if(hilite) { yzPenColor(30000, 30000, 65535); yzRect(x, y, x + tag_dx-1, y + 13); } yzPenColor1c(tag_box_color); yzOutlineRect(x, y, x + tag_dx-1, y + 13); if(hilite)yzPenColor(65535, 65535, 40000); else yzPenColor1c(tag_display_font.color); yzText(x+2, y + 11, tag->name);*/ /*if(tag->failure) add_tag_gcl(target_gcl, x, y, x+tag_dx-1, y+13, x+2, y+11, tag->name, tag, &tag_display_font, error_display_font.color, white_color, error_display_font.color); else */ add_tag_gcl(target_gcl, x, y, x+tag_dx-1, y+tag_display_font.size*15.0/12, x+2, y+tag_display_font.size*14.0/12, tag->name, tag, &tag_display_font, tag->failure?red:tag_display_font.color, white_color, tag->failure?red:tag_box_color); tag->x1 = x+2 + current_offset_x; tag->y1 = y+tag_display_font.size*8/12 + current_offset_y; if(tag->failure)tag->failure->x = tag->x1, tag->failure->y = tag->y1; } return tag_dx; } int draw_type(int x, int y, char *type, int display, struct font_info *fi) { int dx; use_font(fi); dx = yzStringSize(type, strlen(type)); if(display) { //yzText(x, y+11, type); add_text_gcl(target_gcl, dx, x, y+11, type, fi); } return 3 + dx; } int find_tallest(int *h, lkb_avm_tag **t, int i0, int len) { int i, m = 1.5 * feature_display_font.size; for(i=i0;im)m=h[i]; if(t[i])break; } return m; } render_avm_list(lkb_avm_list *list, int *DY, int *DX, int display) { int i, x = 0, mdy, dy, dx, Mdy = 1.5 * feature_display_font.size, LL; int *heights; if(!list->length && list->rest_weird) { render_avm_item(list->rest_weird, list->rest_type, DY, DX, display, 0); return; } LL = list->length + (list->rest_weird?1:0); heights = malloc(LL * sizeof(int)); // compute this lists's vertical size for centering and <> positioning for(i=0;ilength;i++) { render_avm_item(list->items[i], list->what[i], &dy, &dx, 0, list->tags[i]); if(dy > Mdy)Mdy = dy; heights[i] = dy; } if(list->rest_weird) { render_avm_item(list->rest_weird, list->rest_type, &dy, &dx, 0, 0); if(dy > Mdy)Mdy = dy; heights[i] = dy; } mdy = find_tallest(heights, list->rtags, 0, list->length); if(list->length && list->type[0] && strcasecmp(list->type[0], non_empty_list_type) && strcasecmp(list->type[0], empty_list_type) && strcasecmp(list->type[0], list_type)) { x += 3; downcase_string(list->type[0]); x += draw_type(x, Mdy/2 - 7, list->type[0], display, &terminal_font); x += 3; } open_bracket(&x, mdy, Mdy, display); x += 4; for(i=0;ilength;i++) { //yzPushOrigin(x, (Mdy - heights[i]+1)/2); current_offset_x += x; current_offset_y += (Mdy - heights[i]+1)/2; render_avm_item(list->items[i], list->what[i], &dy, &dx, display, list->tags[i]); current_offset_x -= x; current_offset_y -= (Mdy - heights[i]+1)/2; //yzPopOrigin(); x += dx; if(list->rtags[i] || list->type[i+1]) { if(heights[i] < mdy * 0.4)x += 0; else x += 4; close_bracket(&x, mdy, Mdy, display); x += 3; list_addition(&x, Mdy, display); if(list->rtags[i]) { x += 5; x += draw_tag(x, Mdy/2 - 7, list->rtags[i], display); } if(list->type[i+1]) { x += 5; x += draw_type(x, Mdy/2 - 7, list->type[i+1], display, &type_display_font); } if(i+1 == list->length)goto draw_weird; // compute height of next segment, for brackets mdy = find_tallest(heights, list->rtags, i+1, list->length); x += 3; open_bracket(&x, mdy, Mdy, display); x += 3; } else if(i < (list->length-1)) { x += 2; if(display) { //yzPenColor(0,0,0); //yzText(x, 14 + (Mdy - 18)/2, ","); static int comma_size = -1; if(comma_size<0)comma_size = yzLetterSize(','); add_text_gcl(target_gcl, comma_size, x, 14 + (Mdy-18)/2, ",", &feature_display_font); } x += 8; } else x += 4; } if(list->open_ended) draw_ellipsis(&x, Mdy, display); if(list->length && i>0 && heights[i-1] < mdy * 0.4)x -= 4; close_bracket(&x, mdy, Mdy, display); if(list->rest_weird) // weird 'rest' { x += 3; list_addition(&x, Mdy, display); } draw_weird: if(list->rest_weird) // weird 'rest' { x += 5; //yzPushOrigin(x, (Mdy-heights[LL-1]+1)/2); current_offset_x += x; if(list->length)current_offset_y += (Mdy-heights[LL-1]+1)/2; render_avm_item(list->rest_weird, list->rest_type, &dy, &dx, display, 0); current_offset_x -= x; if(list->length)current_offset_y -= (Mdy-heights[LL-1]+1)/2; //yzPopOrigin(); x += dx; if(dy > Mdy)Mdy = dy; } free(heights); *DX = x; *DY = Mdy; }