📄 fv.tree.c
字号:
/* Insert existing child into sorted array ...*/ for (i = 0; i < nchild; i++) if (strcmp(existing_child->name, child[i]->name)<0) { existing_child->sibling = child[i]; if (i) child[i-1]->sibling = existing_child; else f_p->child = existing_child; break; } if (i==nchild) { /* ...must belong at end */ child[i-1]->sibling = existing_child; existing_child->sibling = NULL; } } *new = TRUE; } else if (compare) { fv_destroy_tree(f_p->child); f_p->child = NULL; *new = TRUE; } return(SUCCESS);}/* Return -1, 0, 1 if less than, equal to, or greater than */staticcompare_name(f1, f2) FV_TNODE **f1, **f2;{ return(strcmp((*f1)->name, (*f2)->name));}staticcompare_child(ff_p, fc_p, new) FV_TNODE *ff_p, *fc_p; BOOLEAN *new;{ register FV_TNODE *f_p, *c_p, *t_p; long delete = 1; /* Unlikely time (delete marker */ c_p = fc_p; while (c_p) { /* Test current children against previous */ for (f_p = ff_p; f_p; f_p = f_p->sibling) if (strcmp(c_p->name, f_p->name) == 0) break; /* Exists, mark for delete */ if (f_p) c_p->mtime = delete; c_p = c_p->sibling; } f_p = ff_p; while (f_p) { /* Test previous against current */ for (c_p = fc_p; c_p; c_p = c_p->sibling) if (strcmp(c_p->name, f_p->name) == 0) break; /* No longer exists, mark for delete */ if (!c_p) f_p->mtime = delete; f_p = f_p->sibling; } /* Remove deleted/moved folders */ for (f_p = ff_p, c_p = NULL; f_p;) if (f_p->mtime == delete) { if (c_p) c_p->sibling = f_p->sibling; else f_p->parent->child = f_p->sibling; t_p = f_p->sibling; f_p->sibling = NULL; fv_destroy_tree(f_p); *new = TRUE; f_p = t_p; } else { c_p = f_p; f_p = f_p->sibling; } f_p = c_p; /* Add new folders */ for (c_p = fc_p; c_p; c_p = c_p->sibling) if (c_p->mtime != delete) { /* Tack it on the end */ if (f_p) f_p->sibling = c_p; else ff_p->child = c_p; f_p = c_p; *new = TRUE; } else { /* Delete it */ free(c_p->name); free((char *)c_p); } if (f_p) f_p->sibling = NULL;}fv_sort_children(t_p) /* Sort node's children by name */ FV_TNODE *t_p;{ register FV_TNODE *c_p; FV_TNODE *child[256]; register int cno; if (t_p->child == NULL || t_p->child->sibling == NULL) return; for (c_p = t_p->child, cno=0; c_p && cno<256; c_p = c_p->sibling) child[cno++] = c_p; qsort((char *)child, cno, sizeof(FV_TNODE *), compare_name); /* Fix sibling pointers */ child[cno] = NULL; while (cno) { child[cno-1]->sibling = child[cno]; cno--; } t_p->child = child[0];}/* Did we visit this node, does it have any children, etc? */fv_check_children(f_p, new) register FV_TNODE *f_p; /* Node */ BOOLEAN *new; /* New children? */{ struct stat fstatus; /* File status info */ *new = FALSE; /* Get path */ if (fv_getpath(f_p, (char *)0) || chdir(Fv_path) == -1) { fv_putmsg(TRUE, sys_errlist[errno], 0, 0); Fv_tselected = FALSE; return; } if (f_p->mtime) { /* We're already seen this folder. Compare the modification * date and rebuild this portion of the tree if necessary. */ if (stat(".", &fstatus)) { fv_putmsg(TRUE, sys_errlist[errno], 0, 0); return; } if (fstatus.st_mtime > f_p->mtime) { fv_add_children(f_p, new, (char *)0); fv_putmsg(FALSE, Fv_message[MMODIFIED], (int)f_p->name, 0); } }}static char *E_p;fv_expand_all_nodes(){ FV_TNODE *sibling; fv_busy_cursor(TRUE); sibling = Fv_tselected->sibling; Fv_tselected->sibling = NULL; E_p = Fv_path+strlen(Fv_path); expand_all(Fv_tselected); Fv_tselected->sibling = sibling; fv_getpath(Fv_tselected, (char *)0); fv_drawtree(TRUE); fv_busy_cursor(FALSE);}staticexpand_all(f_p) register FV_TNODE *f_p;{ BOOLEAN new; register char *c_p; while (f_p) { /* Unprune branches */ if (f_p->status & PRUNE) f_p->status &= ~PRUNE; if (f_p->mtime == 0) fv_add_children(f_p, &new, Fv_path); if (f_p->child) { c_p = f_p->child->name; *E_p++ = '/'; while (*E_p++ = *c_p++) ; E_p--; expand_all(f_p->child); } if (f_p = f_p->sibling) { c_p = f_p->name; while (*E_p != '/') E_p--; while (*(++E_p) = *c_p++) ; } } while (*E_p != '/') E_p--; *E_p = NULL;}fv_expand_node(f_p, new) register FV_TNODE *f_p; BOOLEAN *new; /* New children? */{ if ((fv_add_children(f_p, new, (char *)0) == SUCCESS) && *new == FALSE) { /* No children (but show that it has been explored) */ reverse(f_p); pw_rop(Fv_tree.pw, f_p->x, f_p->y, GLYPH_WIDTH, (TREE_GLYPH_HEIGHT>>2)-(TREE_GLYPH_HEIGHT>>4), PIX_SRC, Fv_icon[FV_IFOLDER], 0, TREE_GLYPH_TOP); reverse(f_p); }}/* Free up memory allocated to (portion of) tree */fv_destroy_tree(f_p) register FV_TNODE *f_p;{ for ( ; f_p; f_p = f_p->sibling) if (f_p->child) fv_destroy_tree(f_p->child); else { free(f_p->name); free((char *)f_p); }}/* Get full path name from node in tree */fv_getpath(c_p, buf) register FV_TNODE *c_p; /* Node */ char *buf; /* Local copy of path */{ FV_TNODE *level[32]; register int levelno; register char *p_p, *s_p; /* Get full path name; back up tree and copy it in fv_reverse * order. */ for ( levelno = 0; c_p; c_p = c_p->parent, levelno++ ) { if ( levelno > 32 ) { fv_putmsg(TRUE, "> 32 levels deep", 0, 0); return(FAILURE); } level[levelno] = c_p; } if (!buf) buf = Fv_path; p_p = buf; levelno -= 2; /* Skip root */ while ( levelno >= 0 ) { *p_p++ = '/'; s_p = level[levelno]->name; while ( *s_p ) *p_p++ = *s_p++; levelno--; } if ( p_p == buf ) *p_p++ = '/'; *p_p = NULL; c_p = level[0]; return(SUCCESS);}/* Called by filer to request updating of tree */fv_updatetree(){ register FV_TNODE *f_p, *lf_p; /* Current, last nodes */ register FV_TNODE *existing; /* Existing child node */ FV_TNODE *first_p; /* First created node */ register FV_FILE **file_p, **lfile_p; /* Files array pointers */ lf_p = NULL; existing = Fv_current->child; for (file_p=Fv_file, lfile_p=Fv_file+Fv_nfiles; file_p != lfile_p; file_p++) if ((*file_p)->type == FV_IFOLDER) { /* Don't allocate existing children */ if (existing && strcmp(existing->name, (*file_p)->name) == 0) continue; if ((f_p = (FV_TNODE *)fv_malloc(sizeof(FV_TNODE))) == NULL || (f_p->name = fv_malloc((unsigned)strlen((*file_p)->name)+1))==NULL) return; if (!lf_p) first_p = f_p; f_p->parent = Fv_current; f_p->child = NULL; (void)strcpy(f_p->name, (*file_p)->name); f_p->mtime = 0; f_p->status = 0; if (lf_p) lf_p->sibling = f_p; lf_p = f_p; } if (lf_p) lf_p->sibling = NULL; else return; if (Fv_current->child) { /* Insert existing child in alphabetically correct spot. * (Names returned by fv_getnextdir() have been sorted.) */ for (lf_p = NULL, f_p = first_p; f_p; lf_p = f_p, f_p = f_p->sibling ) if (strcmp(existing->name, f_p->name) < 0) { /* Existing child should appear here */ existing->sibling = f_p; break; } if (lf_p) { /* Existing child is no longer first element */ lf_p->sibling = existing; Fv_current->child = first_p; } } else Fv_current->child = first_p;}static FV_TNODE *mouse(x, y, f_p) /* Are we over a folder? */ int x, y; FV_TNODE *f_p;{ Chosen = NULL; mouse_recursive(x, y, f_p); return(Chosen);}staticmouse_recursive(x, y, f_p) register int x, y; register FV_TNODE *f_p;{ if (Chosen) return; for ( ; f_p; f_p = f_p->sibling ) { if (f_p->sibling && f_p->sibling->stack) { /* The visible portion of a stacked folder should * be selectable; since the last stacked folder * is completely visible, work backwards... */ FV_TNODE *lf_p = f_p; register int sno = 0; /* Collect stacked folders... */ Mouse_stack[sno++] = f_p; for (f_p = f_p->sibling; f_p && f_p->stack; f_p = f_p->sibling) Mouse_stack[sno++] = f_p; /* ... and compare them in reverse order */ while (sno--) if ( ( x >= Mouse_stack[sno]->x && x <= Mouse_stack[sno]->x+GLYPH_WIDTH ) && ( y >= Mouse_stack[sno]->y && y <= Mouse_stack[sno]->y+TREE_GLYPH_HEIGHT ) ) { Chosen = Mouse_stack[sno]; return; } f_p = lf_p; } if ( ( x >= f_p->x && x <= f_p->x+GLYPH_WIDTH ) && ( y >= f_p->y && y <= f_p->y+TREE_GLYPH_HEIGHT ) ) { Chosen = f_p; return; } if (f_p->child && !(f_p->status & PRUNE)) mouse_recursive(x, y, f_p->child); }}FV_TNODE *fv_infolder(x, y) /* Return folder name at coordinate */ int x, y;{ if (Fv_treeview) { /* Only the tree can scroll, adjust for scrolling... */ x += Fv_tree.r.r_left; y += Fv_tree.r.r_top; return(mouse(x, y, Fv_thead)); } else return(path_chosen(x, y));}staticreverse(f_p) /* Highlight folder */ register FV_TNODE *f_p;{ if (f_p) pw_rop(Fv_tree.pw, f_p->x, f_p->y, GLYPH_WIDTH, TREE_GLYPH_HEIGHT, PIX_SRC ^ PIX_DST, f_p==Fv_current?Fv_invert[FV_IOPENFOLDER]: f_p->mtime && !(f_p->status&PRUNE) ? Fv_invert[FV_IFOLDER] : Fv_invert[FV_IUNEXPLFOLDER], 0, TREE_GLYPH_TOP);}fv_open_folder() /* Open selected folder */{ int len; char buf[MAXPATH]; BOOLEAN children; fv_busy_cursor(TRUE); /* Cursor wait */ /* Open reveals folder's children, if not currently visible */ if (Fv_tselected->mtime == 0) { fv_expand_node(Fv_tselected, &children); if (children) fv_drawtree(TRUE); } /* Open reveals hidden folder */ if (Fv_tselected->status & PRUNE) { Fv_tselected->status &= ~PRUNE; fv_drawtree(TRUE); } /* Open a symbolically linked folder displays the link contents */ if (Fv_tselected->status & SYMLINK) { /* Symbolic link to directory; get reference's real name. * These names may be relative pathnames... */ char *b_p; (void)strcpy(buf, Fv_path); len = strlen(Fv_path); b_p = buf+len; while (*b_p != '/') /* Back to parent */ b_p--; b_p++; /* Skip / */ if ((len=readlink(Fv_path, b_p, MAXPATH-1)) == -1) { fv_putmsg(TRUE, sys_errlist[errno], 0, 0); fv_busy_cursor(FALSE); return; } /* We've found where it's pointing to, * Either (a) absolute pathname * (b) relative with no indirection * or (c) relative with indirection */ b_p[len] = NULL; fv_putmsg(FALSE, "%s linked to %s", (int)Fv_tselected->name, (int)b_p); if (strncmp(b_p, "../", 3) == 0) /* (c) */ { register char *n_p; n_p = b_p; b_p -= 2; /* Skip /. */ while (*b_p != '/') b_p--; n_p += 3; /* Skip ../ */ b_p++; while (*b_p++ = *n_p++) ; } /* Either (a) or (b) */ reverse(Fv_tselected); Fv_tselected = NULL; fv_openfile(*b_p=='/' ? b_p : buf, (char *)0, TRUE); } else { Fv_current = Fv_tselected; /* Selected is now open */ reverse(Fv_tselected); /* Turn reverse off */ fv_showopen(); /* Show open folder */ reverse(Fv_tselected); /* Turn reverse back on */ (void)strcpy(Fv_openfolder_path, Fv_path); /* Open path */ Fv_dont_paint = TRUE; scrollbar_scroll_to(Fv_foldr.vsbar, 0); Fv_dont_paint = FALSE; fv_display_folder(FV_BUILD_FOLDER); /* Open & paint directory */ } fv_busy_cursor(FALSE); /* Cursor normal */}fv_put_text_on_folder(f_p) /* Place folder name on folder */ register FV_TNODE *f_p; /* Tree node */{ int x, w, y, l; /* Don't bother if not visible */ if (Fv_treeview && (f_p->y >= Fv_tree.r.r_top + Fv_tree.r.r_height || /*f_p->y-(TREE_GLYPH_HEIGHT>>1) < Fv_tree.r.r_top ||*/ f_p->x >= Fv_tree.r.r_left + Fv_tree.r.r_width)) return; /* Some portion must be visible... */ l = fv_strlen(f_p->name); x = f_p->x; w = GLYPH_WIDTH; if (f_p == Fv_current) w -= GLYPH_WIDTH>>4; if (l < w) { y = f_p->y+(TREE_GLYPH_HEIGHT>>1); pw_text(Fv_tree.pw, x+(w>>1)-(l/2), y, PIX_SRC | PIX_DST, Fv_font, f_p->name); } else wrap_text_on_folder(f_p, w, x);}staticwrap_text_on_folder(f_p, w, x) /* Wrap overflow text onto two lines in folder */ register FV_TNODE *f_p; int w, x;{ register char *s_p, *n_p; char first[16]; char second[16]; register short width; register BOOLEAN shadow; /* Name too large to fit within folder: so wrap within two lines and * truncate it if necessary. (If displaying tree, don't bother with * second line if there's another folder stacked over it.) */ shadow = Fv_treeview && f_p->sibling && f_p->sibling->stack>0; *second = NULL; s_p = first; n_p = f_p->name; width = 0; while (*n_p) { width += Fv_fontwidth[*n_p-' ']; if (width > w) if (shadow) break; else if (*second) break; else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -