#include #include #include #include #include #include #include #include #include #include #include "embedded-view.h" #include "font-info.h" #include "lkb-tree.h" void postscript_hierarchy_view(embedded_view_t *view); font_info hierarchy_font = {"helvetica", 12, fsRoman, {0,0,0}, 0}; #define RANK_SEP 75 #define FILE_SEP 40 #define TX(i) (priv->rankx[priv->ranks[i]-1]) #define TX2(i) (priv->rankx[priv->ranks[i]-1]+priv->textw[i]) #define TY(i) (priv->y[i]) /* single hierarchy view */ struct hierarchy_priv { int id; int focused_type; char *typename; int ntypes; struct lui_hierarchy **types; int *ranks; int *rankx; int *rankw; int *textw; float *y; float ymax; int maxrank, biggest_rank; int hilight_id; }; #define HP ((struct hierarchy_priv*)view->private) int init_hierarchy_view(embedded_view_t *view, int id, char *typename, int ntypes, struct lui_hierarchy **types) { view->private = calloc(sizeof(struct hierarchy_priv),1); HP->id = id; HP->typename = strdup(typename); HP->ntypes = ntypes; HP->types = types; HP->ranks = calloc(sizeof(int),ntypes); HP->rankx = calloc(sizeof(int),ntypes); HP->rankw = calloc(sizeof(int),ntypes); HP->textw = calloc(sizeof(int),ntypes); HP->y = calloc(sizeof(float),ntypes); HP->hilight_id = -1; HP->focused_type = -1; int i, j; for(i=0;inpar;j++) assert(h->par[j] >=0 && h->par[j] name))HP->focused_type = i; } HP->hilight_id = HP->focused_type; use_font(&hierarchy_font); calculate_hierarchy_placement(HP); view->width = HP->rankx[HP->maxrank-1] + HP->rankw[HP->maxrank-1] + 30; view->height = (int)HP->ymax + 35;//HP->biggest_rank*FILE_SEP + 15; return 0; } void prescroll_hierarchy_view(embedded_view_t *view) { struct hierarchy_priv *priv = HP; if(HP->focused_type != -1) { int x = TX(HP->focused_type); int y = TY(HP->focused_type); scroll_embedded_view_to(view, x, y); } } void close_hierarchy_view(embedded_view_t *view) { lkb_forget_hierarchy(HP->id); free(HP->typename); int i; for(i=0;intypes;i++)free_hierarchy(HP->types[i]); free(HP->types); free(HP->ranks); free(HP->rankx); free(HP->rankw); free(HP->textw); free(HP->y); free(HP); } void update_hierarchy_view(embedded_view_t *view, int x1, int y1, int x2, int y2) { use_font(&hierarchy_font); yzPenColor(65535,65535,65535); yzRect(x1, y1, x2, y2); yzPenColor(0,0,0); yzPushOrigin(15, 15); render_hierarchy(HP); yzPopOrigin(); } int locate_hierarchy(struct hierarchy_priv *priv, int x, int y) { int i; x -= 15; y -= 15; for(i=0;intypes;i++) { if(y>priv->y[i] + 7 || y < priv->y[i] - 7)continue; if(xrankx[priv->ranks[i]-1] || x>priv->rankx[priv->ranks[i]-1] + priv->textw[i])continue; return i; } return -1; } misc_hierarchy_popup(embedded_view_t *view, int x, int y) { window_t *par; menu_data_t *md; int id; md = yzNewMenuData("Hierarchy Options"); yzAddMenuDataItem(md, "Output Postscript", 1); //yzAddMenuDataItem(md, "Output LaTeX", 2); yzAddMenuDataItem(md, "Close Window", 3); par = yzGetSelectedWindow(); yzShowMenu(md, &id, x-8, y-8); fprintf(stderr, "showmenu id %d\n", id); switch(id) { case 0: break; // cancelled default: fprintf(stderr, "unknown item %d\n", id); break; case 1: postscript_hierarchy_view(view); break; //case 2: latex_hierarchy_view(view); break; case 3: sim_key('q'); return -1; } // XXX should dispose memory here return 0; } popup_hierarchy_node(embedded_view_t *view, int tid, int x, int y) { window_t *par; menu_data_t *md; int id; md = yzNewMenuData("Hierarchy Options"); yzAddMenuDataItem(md, "Type Hierarchy", 4); yzAddMenuDataItem(md, "Type Definition", 1); yzAddMenuDataItem(md, "Expanded Type", 2); yzAddMenuDataItem(md, "Show Source", 3); par = yzGetSelectedWindow(); yzShowMenu(md, &id, x-8, y-8); switch(id) { case 0: break; // cancelled default: fprintf(stderr, "unknown item %d\n", id); break; case 1: lkb_type_command(HP->types[tid]->name, "skeleton"); break; case 2: lkb_type_command(HP->types[tid]->name, "expansion"); break; case 3: lkb_type_command(HP->types[tid]->name, "source"); break; case 4: lkb_type_command(HP->types[tid]->name, "hierarchy"); break; } // XXX should dispose memory here return 0; } void click_hierarchy_node(embedded_view_t *view, int tid) { lkb_type_command(HP->types[tid]->name, "expansion"); } void click_hierarchy_view(embedded_view_t *view, int x, int y, int b) { int id = locate_hierarchy(HP, x, y); int pop = (b!=1) || yzQueryKey(YZ_KEYCODE_CONTROL); if(id != -1) { if(!pop)click_hierarchy_node(view, id); else popup_hierarchy_node(view, id, x, y); } else if(pop)misc_hierarchy_popup(view, x, y); } void event_hierarchy_view(embedded_view_t *view, event_t ev) { switch(ev.type) { case YZ_MOUSE_DOWN: click_hierarchy_view(view, ev.x, ev.y, ev.button); break; } } void hierarchy_mouse(embedded_view_t *view, int x, int y) { int id = locate_hierarchy(HP, x, y); if(id == -1)id = HP->focused_type; if(id == HP->hilight_id)return; yzRecomputeScrollAreaClipping(view->scroll_area); yzPushOrigin(15,15); int old_id = HP->hilight_id; HP->hilight_id = id; //if(old_id != -1)render_hierarchy_node(HP, old_id, 1); //if(id != -1)render_hierarchy_node(HP, id, 1); yzBufferMode(YZ_BUFFER_BACK); yzPenColor(65535,65535,65535); yzRect(0, 0, view->width, view->height); render_hierarchy(HP); yzPopOrigin(); yzPopClipRect(); yzPopOrigin(); yzUpdateBuffer(YZ_BUFFER_FRONT); } void postscript_hierarchy_view(embedded_view_t *view) { window_t *hierarchy_ps, *old; int dy, dx, fd; float scale; char message[1024], fname[768] = "hierarchy-print.ps"; sprintf(fname, "/tmp/hierarchy.%d.ps", HP->id); unlink(fname); fd = open(fname, O_WRONLY | O_CREAT, 0664); hierarchy_ps = (window_t*)yzPostScriptWindow("Type Hierarchy", 555, 800, fd); old = yzSelectWindow(hierarchy_ps); scale = 500.0 / (view->width); if((660.0 / (view->height)) < scale) scale = 660.0 / (view->height); yzSetOrigin(0,4+hierarchy_font.size*16/14); extern int yzPostScriptSetScale(float); yzPostScriptSetScale(scale); yzPushOrigin(25, 25); render_hierarchy(HP); yzPopOrigin(); yzPostScriptEndPage(); close(fd); sprintf(message, "Printed hierarchy to `%s' at scale %.1f%%\n", fname, 100*scale); console_add(message); yzSelectWindow(old); } void latex_hierarchy_view(embedded_view_t *view) { char fname[768], message[1024]; FILE *f; //sprintf(fname, "/tmp/hierarchy.%d.tex", HP->id); //f = fopen(fname, "w"); //latex_hierarchy(HP->hierarchy, f, 0); //fclose(f); //sprintf(message, "Output hierarchy to `%s'\n", fname); //console_add(message); } embedded_view_t prototype_hierarchy_view = { init: init_hierarchy_view, update: update_hierarchy_view, event: event_hierarchy_view, postscript: postscript_hierarchy_view, latex: latex_hierarchy_view, close: close_hierarchy_view, mouse_moved: hierarchy_mouse}; hierarchy_assign_ranks(struct hierarchy_priv *priv, int target) { int pmax = 0; int i; struct lui_hierarchy *h = priv->types[target]; for(i=0;inpar;i++) { int prank = priv->ranks[h->par[i]]; if(prank > pmax)pmax = prank; } priv->ranks[target] = pmax+1; if(priv->ranks[target] > priv->maxrank)priv->maxrank = priv->ranks[target]; } struct sortable { int tnum; float y; }; int sortablecmp(const struct sortable *a, const struct sortable *b) { if(a->y > b->y)return 1; if(a->y < b->y)return -1; return 0; } layout_hierarchy_y(struct hierarchy_priv *priv, int *ranksize, int dir, float perturb) { int i, j, k; struct sortable elems[priv->ntypes]; for(i = (dir?0:(priv->maxrank-1)) ; dir ? (i < priv->maxrank-1) : (i >= 0) ; i += dir?1:-1) { //float bias = (priv->biggest_rank - ranksize[i]) * FILE_SEP; //bias /= 2; float bias = 0; int n = 0; for(j=0;jntypes;j++) { if(priv->ranks[j]-1 != i)continue; elems[n].tnum = j; n++; } assert(n == ranksize[i]); // set each element to the average of its neighbors, plus some random perturbation for(j=0;jtypes[elems[j].tnum]; for(k=0;knpar;k++)y += priv->y[h->par[k]]; for(k=0;knsub;k++)y += priv->y[h->sub[k]]; y += perturb * (float)rand() / RAND_MAX; y /= h->npar + h->nsub; assert(!isinf(y) && !isnan(y)); elems[j].y = y; bias += y; } bias /= n; // get them in y order qsort(elems, n, sizeof(elems[0]), sortablecmp); //printf("rank %d : n = %d ; bias = %f\n", i, n, bias); // spread them out for(j=0;jy[elems[j].tnum] = j * FILE_SEP + bias - (float)n * FILE_SEP / 2; } float ymin = priv->y[0], ymax = 0; //printf("ymin = %f\n", ymin); for(i=0;intypes;i++)if(priv->y[i]y[i]; for(i=0;intypes;i++)priv->y[i] -= ymin; for(i=0;intypes;i++)if(priv->y[i]>ymax)ymax=priv->y[i]; priv->ymax = ymax; } calculate_hierarchy_placement(struct hierarchy_priv *priv) { int i; priv->maxrank = 0; for(i=0;intypes;i++) { hierarchy_assign_ranks(priv, i); priv->rankw[i] = 0; priv->rankx[i] = 0; } //fprintf(stderr, "layed out hierarchy with %d types in %d ranks\n", priv->ntypes, priv->maxrank); int ranksize[priv->maxrank]; bzero(ranksize, sizeof(ranksize)); for(i=0;intypes;i++) { int w = yzStringSize(priv->types[i]->name, strlen(priv->types[i]->name)); priv->textw[i] = w; if(w>priv->rankw[priv->ranks[i]-1]) priv->rankw[priv->ranks[i]-1] = w; ranksize[priv->ranks[i]-1]++; } priv->biggest_rank = 0; for(i=0;imaxrank;i++) { //fprintf(stderr, " rank %d has size %d\n", i+1, ranksize[i]); if(ranksize[i] > priv->biggest_rank) priv->biggest_rank = ranksize[i]; if(i)priv->rankx[i] = priv->rankx[i-1] + priv->rankw[i-1] + RANK_SEP; else priv->rankx[i] = 0; } //fprintf(stderr, " ... biggest rank has size %d\n", priv->biggest_rank); // pick y positions for(i=0;intypes;i++)priv->y[i] = 0; float perturb[10] = {20, 5, 1, 0.25, 0.20, 0.15, 0.10, 0.05, 0.04, 0.03}; for(i=0;i<20;i++) { layout_hierarchy_y(priv, ranksize, 1, (i<10)?perturb[i]:0.01); layout_hierarchy_y(priv, ranksize, 0, (i<10)?perturb[i]:0.01); } } render_hierarchy_node(struct hierarchy_priv *priv, int id, int include_par) { int j; struct lui_hierarchy *h = priv->types[id]; yzText(TX(id), TY(id)+4, h->name); if(include_par)yzText(TX(id), TY(id)+3, h->name); for(j=0;jnsub;j++) yzLine(TX2(id) + 2, TY(id), TX(h->sub[j]) - 2, TY(h->sub[j])); if(include_par) for(j=0;jnpar;j++) yzLine(TX(id) - 2, TY(id), TX2(h->par[j]) + 2, TY(h->par[j])); } render_hierarchy(struct hierarchy_priv *priv) { int i, j; yzPenColor(0,0,0); for(i=0;intypes;i++) if(i != priv->hilight_id) render_hierarchy_node(priv, i, 0); yzPenColor(60000,20000,20000); if(priv->hilight_id != -1) render_hierarchy_node(priv, priv->hilight_id, 1); }