📄 libpg_dirview.c
字号:
return 1; /* The rest depends on the user-defined filter */ return (*dat->filefilter)(name,dat->pattern);}/*****************************************************************************//* Given a filename, constructs it's full path in dirview_buf * careful to avoid overflowing any buffers. */static voiddirview_fullpath(const char *file){ int len = strlen(dirview_dir); strcpy(dirview_buf,dirview_dir); if (len<(FILEMAX-1) && dirview_buf[len-1]!='/') { strcat(dirview_buf,"/"); len--; } strncat(dirview_buf,file,FILEMAX-1-len);}/*****************************************************************************//* Utility to populate the dialog box with the current directory's files */static voiddirview_setdir(struct filepickdata *dat){ DIR *d; struct dirent *arthur; /* Dirent, Arthur Dirent... */ struct stat st; struct filenode *names, *p; int total = 0, count, i; int itemheight; char *s; pghandle font; pghandle wNameBoxP, wSizeBoxP, wXyzBoxP; char buf[20]; /* Clear the directory context */ pgLeaveContext(); pgEnterContext(); /* Scroll back to the top */ pgSetWidget(dat->wScroll, PG_WP_VALUE,0, 0); /* Set the directory button's text. We don't need to use replacetext here * because clearing the context also takes care of this string handle. * * Use strrchr() to display only the last directory name in the path */ s = strrchr(dirview_dir,'/'); if (s[1]) s++; pgSetWidget(dat->wDirectory,PG_WP_TEXT,pgNewString(s),0); /* Select the relevant entries, store them, and sort them. This is just * like what scandir() does, but scandir doesn't allow passing extra * data to the selection function. I suppose another reason to avoid * scandir() is that uClibc doesn't yet implement it correctly... */ /* first just count the files... */ d = opendir(dirview_dir); if (!d) return; while (readdir(d)) total++; rewinddir(d); /* ... so we can allocate the array */ names = malloc(sizeof(struct filenode) * total); if (!names) { closedir(d); return; } /* Now copy all the relevant directory entries */ count = 0; p = names; while (count<total && (arthur = readdir(d))) { dirview_fullpath(arthur->d_name); lstat(dirview_buf,&st); if (dirview_filter(dat,arthur->d_name,&st)) { /* We want this file, so store it */ memcpy(&p->st,&st,sizeof(st)); p->name[NAMEMAX-1] = 0; strncpy(p->name,arthur->d_name,NAMEMAX-1); p++; count++; } } closedir(d); if (!count) { /* No items? It's like a "this page intentionally left blank" message */ pgNewWidget(PG_WIDGET_LABEL,PG_DERIVE_INSIDE,dat->wFileList); pgSetWidget(PGDEFAULT, PG_WP_SIDE,PG_S_ALL, PG_WP_TEXT,pgNewString("(no visible files)"), 0); } else { /* Normal item drawing stuff... */ /* Get the height for list items */ itemheight = pgThemeLookup(PGTH_O_LISTITEM,PGTH_P_HEIGHT); /* Sort them */ qsort(names,count,sizeof(struct filenode),&dirview_compare); /* Make Columns */ wNameBoxP = pgNewWidget(PG_WIDGET_BOX,PG_DERIVE_INSIDE,dat->wFileList); pgSetWidget(PGDEFAULT, PG_WP_TRANSPARENT,1, PG_WP_SIDE,PG_S_LEFT, 0); wSizeBoxP = pgNewWidget(PG_WIDGET_BOX,0,0); pgSetWidget(PGDEFAULT, PG_WP_TRANSPARENT,1, PG_WP_SIDE,PG_S_LEFT, 0); wXyzBoxP = pgNewWidget(PG_WIDGET_BOX,0,0); pgSetWidget(PGDEFAULT, PG_WP_TRANSPARENT,1, PG_WP_SIDE,PG_S_LEFT, 0); /* Column headings */ wNameBoxP = pgNewWidget(PG_WIDGET_LABEL,PG_DERIVE_INSIDE,wNameBoxP); pgSetWidget(PGDEFAULT, PG_WP_TRANSPARENT,0, PG_WP_FONT,dat->fHeading, PG_WP_TEXT,pgNewString("Name"), PG_WP_ALIGN,PG_A_LEFT, PG_WP_SIZE,itemheight, 0); wSizeBoxP = pgNewWidget(PG_WIDGET_LABEL,PG_DERIVE_INSIDE,wSizeBoxP); pgSetWidget(PGDEFAULT, PG_WP_TRANSPARENT,0, PG_WP_FONT,dat->fHeading, PG_WP_TEXT,pgNewString("Size"), PG_WP_ALIGN,PG_A_LEFT, PG_WP_SIZE,itemheight, 0); wXyzBoxP = pgNewWidget(PG_WIDGET_LABEL,PG_DERIVE_INSIDE,wXyzBoxP); pgSetWidget(PGDEFAULT, PG_WP_TRANSPARENT,0, PG_WP_FONT,dat->fHeading, PG_WP_TEXT,pgNewString("Xyz"), PG_WP_ALIGN,PG_A_LEFT, PG_WP_SIZE,itemheight, 0); /* List all the items */ for (p=names,i=0;i<count;p++,i++) { /* Normally we'd use the default font, but directories and links * get special fonts */ font = 0; if (S_ISLNK(p->st.st_mode)) font = dat->fLink; /* * IMPORTANT: Directory must override link for directory symlinks * to be followed. Currently the event loop checks the font * to see if an item is a file or directory */ if (S_ISDIR(p->st.st_mode)) font = dat->fDirectory; /* Create the file name widget */ wNameBoxP = pgNewWidget(PG_WIDGET_LISTITEM,PG_DERIVE_AFTER,wNameBoxP); pgSetWidget(PGDEFAULT, PG_WP_TEXT,pgNewString(p->name), PG_WP_ALIGN,PG_A_LEFT, PG_WP_FONT,font, 0); pgSetPayload(PGDEFAULT,FILETAG); /* Listitems normally have PG_EXEV_TOGGLE and PG_EXEV_EXCLUSIVE turned * on. This makes them work basically like a radio button would. * They automatically turn off other listitems in the same container, * and they send an activate event when the mouse is pressed down. * * For directories, we don't care about hilighting (because we will redraw * it all anyway) and we want an activate when the mouse is released * after being pressed. In other words, a normal button. * If it's a directory, turn off all the EXEVs */ if (font == dat->fDirectory) pgSetWidget(PGDEFAULT, PG_WP_EXTDEVENTS,0, 0); /* FIXME: We'd like some icons here to indicate file type... * The icons themselves could be stored in a theme. * Determining file types might be more complex. */ /* Make a more human-readable size */ if (font) /* Non-normal file? */ strcpy(buf," -"); else if (p->st.st_size > 1048576) /* Megabytes? */ sprintf(buf,"%d.%02d M", p->st.st_size / 1048576, (p->st.st_size / 10485) % 100); else if (p->st.st_size > 1024) /* Kilobytes? */ sprintf(buf,"%d.%02d K", p->st.st_size / 1024, (p->st.st_size / 10) % 100); else /* Bytes? */ sprintf(buf,"%d",p->st.st_size); /* Add another widget for size */ wSizeBoxP = pgNewWidget(PG_WIDGET_LISTITEM,PG_DERIVE_AFTER,wSizeBoxP); pgSetWidget(PGDEFAULT, PG_WP_TEXT,pgNewString(buf), PG_WP_ALIGN,PG_A_LEFT, PG_WP_SIZE,itemheight, PG_WP_TRANSPARENT,0, PG_WP_STATE,PGTH_O_LISTITEM, 0); /* Add another widget for Xyz */ wXyzBoxP = pgNewWidget(PG_WIDGET_LISTITEM,PG_DERIVE_AFTER,wXyzBoxP); pgSetWidget(PGDEFAULT, PG_WP_TEXT,pgNewString("Xyz"), PG_WP_ALIGN,PG_A_LEFT, PG_WP_SIZE,itemheight, PG_WP_TRANSPARENT,0, PG_WP_STATE,PGTH_O_LISTITEM, //PG_WP_ON,1, 0); } } /* Free the memory! */ free(names);}/*****************************************************************************/static int va_count_tag(LpgdvTag tag, va_list va){ int nb = 0; for (;;) { int t = va_arg(va, int); int v = va_arg(va, int); if(t==0 && v==0) break; if(t==tag) ++nb; } return nb;}Parameters params;static LpgdvStatusva_parse_params(Parameters* *params, MenuItemParams* *menu_item_params, ColumnParams* *column_params, va_list va){ LpgdvStatus status = LPGDV_OK; int current_menu_item = -1; int current_column = -1; LpgdvColumnRenderF last_render_f = 0; *params = 0; *menu_item_params = 0; *column_params = 0; /* alloc mem for params */ *params = malloc(sizeof(Parameters)); if(*params == 0) { status = LPGDV_ERROR_MEMORY; goto done; } memset(*params, 0, sizeof(Parameters)); /* count the number of menu items */ (*params)->menu_items_nb = va_count_tag(LPGDV_MENU_ITEM_ADD, va); /* count the number of columns */ (*params)->columns_nb = va_count_tag(LPGDV_COLUMN_ADD, va); /* alloc mem */ if((*params)->menu_items_nb) { size_t size = (*params)->menu_items_nb * sizeof(MenuItemParams); *menu_item_params = malloc(size); if(*menu_item_params) memset(*menu_item_params, 0, size); else { status = LPGDV_ERROR_MEMORY; goto done; } } if((*params)->columns_nb) { size_t size = (*params)->columns_nb * sizeof(ColumnParams); *column_params = malloc(size); if(*column_params) memset(*column_params, 0, size); else { status = LPGDV_ERROR_MEMORY; goto done; } } /* parse tags */ for (;;) { int tag = va_arg(va, int); void* val = va_arg(va, void*); if(tag==0 && val==0) break; switch(tag) { case LPGDV_TITLE: (*params)->title = (const char*)val; break; case LPGDV_TITLE_VISIBLE: (*params)->title_is_visible = (int)val; break; case LPGDV_LOCATION_VISIBLE: (*params)->location_visible = (int)val; break; case LPGDV_LIST_HEADER_VISIBLE: (*params)->list_is_header_visible = (int)val; break; case LPGDV_LIST_SORT_BY_COL_NR: (*params)->list_sort_by_col_nr = (int)val; break; case LPGDV_LIST_INCLUDE_PARENT: (*params)->list_do_include_parent = (int)val; break; case LPGDV_LIST_SORT: (*params)->list_sort = (int)val; break; case LPGDV_LIST_GROUP: (*params)->list_group = (int)val; break; case LPGDV_COLUMN_ADD: current_column++; (*column_params)[current_column].name = (const char*)val; (*column_params)[current_column].column_render = last_render_f; break; case LPGDV_COLUMN_PLACE: if(current_column<0) break; (*column_params)[current_column].place = (int)val; break; case LPGDV_COLUMN_PLACE_AT: if(current_column<0) break; (*column_params)[current_column].place_at = (int)val; break; case LPGDV_COLUMN_RENDER_FUNC: if(current_column<0) break; (*column_params)[current_column].column_render = (LpgdvColumnRenderF)val; last_render_f = (LpgdvColumnRenderF)val; break; case LPGDV_COLUMN_RENDER_PAYLOAD: if(current_column<0) break; (*column_params)[current_column].payload = (void*)val; break; case LPGDV_SELECTION_CHANGE_FUNC: (*params)->selection_changed = (LpgdvSelectionChangedF)val; break; case LPGDV_ITEM_FOCUS_FUNC: (*params)->item_focused = (LpgdvItemFocusedF)val; break; case LPGDV_ITEM_CLICK_FUNC: (*params)->item_clicked = (LpgdvItemClickedF)val; break; case LPGDV_MENU_TITLE: (*params)->menu_title = (const char*)val; break; case LPGDV_MENU_RENDERING: (*params)->menu_rendering = (int)val; break; case LPGDV_MENU_ITEM_ADD: current_menu_item++; (*menu_item_params)[current_menu_item].name = (const char*)val; break; case LPGDV_MENU_ITEM_ENABLE_FUNC: if(current_menu_item<0) break; (*menu_item_params)[current_menu_item] .menu_item_enable = (LpgdvMenuItemEnableF)val; break; case LPGDV_MENU_ITEMS_ENABLE_FUNC: if(current_menu_item<0) break; (*menu_item_params) [current_menu_item].menu_items_enable = (LpgdvMenuItemsEnableF)val; break; case LPGDV_PROTOCOL_DEFAULT: (*params)->protocol_default = (const char*)val; case LPGDV_BROWSE_SITE_ENTER_FUNC: (*params)->browse_site_enter = (LpgdvBrowseSiteEnterF)val; break; case LPGDV_BROWSE_SITE_LEAVE_FUNC: (*params)->browse_site_leave = (LpgdvBrowseSiteLeaveF)val; break; case LPGDV_BROWSE_DIR_ENTER_FUNC: (*params)->browse_dir_enter = (LpgdvBrowseDirEnterF)val; break; case LPGDV_BROWSE_DIR_LEAVE_FUNC: (*params)->browse_dir_leave = (LpgdvBrowseDirLeaveF)val; break; case LPGDV_BROWSE_ITEM_NEXT_FUNC: (*params)->browse_item_next = (LpgdvBrowseItemNextF)val; break; } } done: if(status!=LPGDV_OK) { if(*params) free(*params); if(*menu_item_params) free(*menu_item_params); if(*column_params) free(*column_params); } return status;# undef BEFORE_VA}/*****************************************************************************//* Example Main function *//* this contains a lot of Micah's file dialog code, as example. It will eventually disappear and serve as inspiration in the displets code.*/const char *_dirview(pgfilter filefilter, const char *pattern, const char *deffile, int flags, const char *title) { pghandle wTB, wOk, wCancel, wUp; struct pgEvent evt; struct filepickdata dat; int w,h; char *p; /* If this is the first invocation, use the current directory */ if (!dirview_dir[0]) getcwd(dirview_dir,FILEMAX); /* Store picker data */ memset(&dat,0,sizeof(dat)); dat.flags = flags; dat.filefilter = filefilter; dat.pattern = pattern; /********* Set up dialog box and top-level widgets */ pgEnterContext(); /* Size the dialog box ourselves. On a handheld this should * be basically as large as possible. Just forcing it to take * the whole screen at 1280x1024 would be a little awkward. * Since using absolute coordinates would be a Bad Thing, size * it relative to the default font. * * Usually the letter 'a' is 6x10 pixels, so multiplying by 66x40 would * make the dialog box about 400x400. That will suck up the whole * screen on 320x240 or 240x320 or smaller handhelds, but on a * desktop-sized screen it will look very reasonable. * Measuring relative to a font is useful, but make sure to use the * PG_FSTYLE_FLUSH flag! */ pgEnterContext(); pgSizeText(&w,&h,pgNewFont(NULL,0,PG_FSTYLE_DEFAULT | PG_FSTYLE_FLUSH), pgNewString("a")); /* A good metric */ pgLeaveContext();#if 0 pgNewPopup(w*66,h*40); pgNewWidget(PG_WIDGET_LABEL,0,0); pgSetWidget(PGDEFAULT, PG_WP_TEXT,pgNewString(title), PG_WP_TRANSPARENT,0, /* The PG_WP_STATE property is fun :) */ PG_WP_STATE,PGTH_O_LABEL_DLGTITLE, 0);#endif /* Special fonts for directories and links */ dat.fDirectory = pgNewFont(NULL,0,PG_FSTYLE_DEFAULT | PG_FSTYLE_BOLD); dat.fLink = pgNewFont(NULL,0,PG_FSTYLE_DEFAULT | PG_FSTYLE_ITALIC); dat.fHeading = pgNewFont(NULL,0,PG_FSTYLE_DEFAULT | PG_FSTYLE_BOLD | PG_FSTYLE_UNDERLINE); /* Make containers for the directory and file. They are ok without * containers, but it looks better putting them in toolbars. */ wTB = pgNewWidget(PG_WIDGET_TOOLBAR,0,0); pgSetWidget(PGDEFAULT, PG_WP_SIDE,PG_S_BOTTOM, 0); dat.wDirectory = pgNewWidget(PG_WIDGET_TOOLBAR,0,0); pgSetWidget(PGDEFAULT, PG_WP_SIDE,PG_S_TOP, 0); dat.wScroll = pgNewWidget(PG_WIDGET_SCROLL,0,0); dat.wFileList = pgNewWidget(PG_WIDGET_BOX,0,0); pgSetWidget(PGDEFAULT, PG_WP_SIDE,PG_S_ALL, 0); pgSetWidget(dat.wScroll, PG_WP_BIND,dat.wFileList, 0); /* Put the file and directory in their toolbars */ if (flags & PG_FILE_FIELD) { dat.wFile = pgNewWidget(PG_WIDGET_FIELD,PG_DERIVE_INSIDE,wTB); pgSetWidget(PGDEFAULT, PG_WP_SIDE,PG_S_ALL, 0); if (deffile) pgSetWidget(PGDEFAULT,PG_WP_TEXT,pgNewString(deffile),0); } wUp = pgNewWidget(PG_WIDGET_BUTTON, PG_DERIVE_INSIDE,dat.wDirectory); pgSetWidget(PGDEFAULT, PG_WP_TEXT,pgNewString(".."), 0); dat.wDirectory = pgNewWidget(PG_WIDGET_BUTTON,0,0); pgSetWidget(PGDEFAULT, PG_WP_SIDE,PG_S_ALL, PG_WP_EXTDEVENTS,PG_EXEV_PNTR_DOWN, 0); /********** Widgets */ wCancel = pgNewWidget(PG_WIDGET_BUTTON,PG_DERIVE_INSIDE,wTB); pgSetWidget(PGDEFAULT, PG_WP_SIDE,PG_S_RIGHT, PG_WP_TEXT,pgNewString("Cancel"), PG_WP_HOTKEY,PGKEY_ESCAPE, PG_WP_BITMAP,pgThemeLookup(PGTH_O_POPUP_MESSAGEDLG, PGTH_P_ICON_CANCEL), PG_WP_BITMASK,pgThemeLookup(PGTH_O_POPUP_MESSAGEDLG, PGTH_P_ICON_CANCEL_MASK), 0); wOk = pgNewWidget(PG_WIDGET_BUTTON,PG_DERIVE_INSIDE,wTB); pgSetWidget(PGDEFAULT, PG_WP_SIDE,PG_S_RIGHT, PG_WP_TEXT,pgNewString((flags&PG_FILE_SAVEBTN) ? "Save" : "Open"), PG_WP_HOTKEY,PGKEY_RETURN, PG_WP_BITMAP,pgThemeLookup(PGTH_O_POPUP_MESSAGEDLG, PGTH_P_ICON_OK), PG_WP_BITMASK,pgThemeLookup(PGTH_O_POPUP_MESSAGEDLG, PGTH_P_ICON_OK_MASK), 0); /********** Run the dialog */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -