4 * ***** BEGIN GPL LICENSE BLOCK *****
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software Foundation,
18 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 * The Original Code is Copyright (C) 2008 Blender Foundation.
21 * All rights reserved.
24 * Contributor(s): Blender Foundation
26 * ***** END GPL LICENSE BLOCK *****
31 #include "BLI_blenlib.h"
32 #include "BLI_dynstr.h"
33 #include "BLI_storage_types.h"
35 #include "BLI_winstuff.h"
39 #include "BIF_glutil.h"
42 #include "BKE_colortools.h"
43 #include "BKE_context.h"
44 #include "BKE_screen.h"
45 #include "BKE_global.h"
46 #include "BKE_utildefines.h"
48 #include "DNA_space_types.h"
49 #include "DNA_scene_types.h"
50 #include "DNA_screen_types.h"
51 #include "DNA_userdef_types.h"
52 #include "DNA_windowmanager_types.h"
54 #include "IMB_imbuf_types.h"
55 #include "IMB_imbuf.h"
57 #include "MEM_guardedalloc.h"
61 #include "RNA_access.h"
63 #include "ED_fileselect.h"
64 #include "ED_screen.h"
66 #include "UI_interface.h"
67 #include "UI_interface_icons.h"
68 #include "UI_resources.h"
70 #include "UI_view2d.h"
78 #include "file_intern.h" // own include
81 #define IMASEL_BUTTONS_HEIGHT 40
82 #define TILE_BORDER_X 8
83 #define TILE_BORDER_Y 8
93 /* XXX very bad, need to check font code */
94 static int gFontsize=12;
96 static void do_file_buttons(bContext *C, void *arg, int event)
100 file_exec(C, NULL); /* file_ops.c */
103 file_cancel_exec(C, NULL); /* file_ops.c */
106 file_parent_exec(C, NULL); /* file_ops.c */
111 /* note; this function uses pixelspace (0, 0, winx, winy), not view2d */
112 void file_draw_buttons(const bContext *C, ARegion *ar)
114 SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
115 FileSelectParams* params = ED_fileselect_get_params(sfile);
120 int filebuty1, filebuty2;
123 float xmax = ar->winx - 10;
125 filebuty1= ar->winy - IMASEL_BUTTONS_HEIGHT - 12;
126 filebuty2= filebuty1 + IMASEL_BUTTONS_HEIGHT/2 + 4;
129 sprintf(name, "win %p", ar);
130 block = uiBeginBlock(C, ar, name, UI_EMBOSS, UI_HELV);
131 uiBlockSetHandleFunc(block, do_file_buttons, NULL);
134 uiSetButLock( filelist_gettype(simasel->files)==FILE_MAIN && simasel->returnfunc, NULL);
137 /* space available for load/save buttons? */
138 slen = UI_GetStringWidth(G.font, sfile->params->title, 0);
139 loadbutton= slen > 60 ? slen + 20 : MAX2(80, 20+UI_GetStringWidth(G.font, params->title, 0));
140 if(ar->winx > loadbutton+20) {
141 if(params->title[0]==0) {
149 uiDefBut(block, TEX, 0 /* XXX B_FS_FILENAME */,"", xmin+2, filebuty1, xmax-xmin-loadbutton-4, 21, params->file, 0.0, (float)FILE_MAXFILE-1, 0, 0, "");
150 uiDefBut(block, TEX, 0 /* XXX B_FS_DIRNAME */,"", xmin+2, filebuty2, xmax-xmin-loadbutton-4, 21, params->dir, 0.0, (float)FILE_MAXFILE-1, 0, 0, "");
153 uiSetCurFont(block, UI_HELV);
154 uiDefBut(block, BUT, B_FS_EXEC, params->title, xmax-loadbutton, filebuty2, loadbutton, 21, params->dir, 0.0, (float)FILE_MAXFILE-1, 0, 0, "");
155 uiDefBut(block, BUT, B_FS_CANCEL, "Cancel", xmax-loadbutton, filebuty1, loadbutton, 21, params->file, 0.0, (float)FILE_MAXFILE-1, 0, 0, "");
159 /* menu[0] = NULL happens when no .Bfs is there, and first time browse
160 disallow external directory browsing for databrowse */
162 if(menu[0] && (params->type != FILE_MAIN)) {
163 uiDefButS(block, MENU, 0 /* B_FS_DIR_MENU */, menu, xmin, filebuty2, fsmenubut_width, 21, ¶ms->menu, 0, 0, 0, 0, "");
164 uiDefBut(block, BUT, 0 /* B_FS_BOOKMARK */, "B", xmin, filebuty1, bookmarkbut_width, 21, 0, 0, 0, 0, 0, "Bookmark current directory");
171 uiEndBlock(C, block);
172 uiDrawBlock(C, block);
176 static void draw_tile(short sx, short sy, short width, short height, int colorid, int shade)
178 /* TODO: BIF_ThemeColor seems to need this to show the color, not sure why? - elubie */
179 //glEnable(GL_BLEND);
180 //glColor4ub(0, 0, 0, 100);
181 //glDisable(GL_BLEND);
182 /* I think it was a missing glDisable() - ton */
184 UI_ThemeColorShade(colorid, shade);
186 // glRecti(sx, sy - height, sx + width, sy);
188 uiRoundBox(sx, sy - height, sx + width, sy, 6);
191 #define FILE_SHORTEN_END 0
192 #define FILE_SHORTEN_FRONT 1
194 static float shorten_string(char* string, float w, int flag)
201 sw = UI_GetStringWidth(G.font, string,0);
202 if (flag == FILE_SHORTEN_FRONT) {
204 BLI_strncpy(temp, "...", 4);
205 pad = UI_GetStringWidth(G.font, temp,0);
206 while (s && (sw+pad>w)) {
208 sw = UI_GetStringWidth(G.font, s,0);
212 int slen = strlen(s);
213 BLI_strncpy(temp+3, s, slen+1);
215 BLI_strncpy(string, temp, slen+4);
220 int slen = strlen(string);
221 string[slen-1] = '\0';
222 sw = UI_GetStringWidth(G.font, s,0);
226 int slen = strlen(string);
228 BLI_strncpy(string+slen-3, "...", 4);
236 static int get_file_icon(struct direntry *file)
238 if (file->type & S_IFDIR)
239 return ICON_FILE_FOLDER;
240 else if (file->flags & BLENDERFILE)
241 return ICON_FILE_BLEND;
242 else if (file->flags & IMAGEFILE)
243 return ICON_FILE_IMAGE;
244 else if (file->flags & MOVIEFILE)
245 return ICON_FILE_MOVIE;
246 else if (file->flags & PYSCRIPTFILE)
247 return ICON_FILE_SCRIPT;
248 else if (file->flags & PYSCRIPTFILE)
249 return ICON_FILE_SCRIPT;
250 else if (file->flags & SOUNDFILE)
251 return ICON_FILE_SOUND;
252 else if (file->flags & FTFONTFILE)
253 return ICON_FILE_FONT;
255 return ICON_FILE_BLANK;
258 static void file_draw_icon(short sx, short sy, int icon, short width, short height)
264 y = (float)(sy-height);
266 if (icon == ICON_FILE_BLANK) blend = -80;
270 UI_icon_draw_aspect_blended(x, y, icon, 1.f, blend);
273 static void file_draw_string(short sx, short sy, const char* string, short width, short height, int flag)
276 char fname[FILE_MAXFILE];
280 BLI_strncpy(fname,string, FILE_MAXFILE);
281 sw = shorten_string(fname, width, flag );
283 soffs = (width - sw) / 2;
285 y = (float)(sy-height);
287 // XXX was using ui_rasterpos_safe
291 /* XXX TODO: handling of international fonts.
292 TODO: proper support for utf8 in languages different from ja_JP abd zh_CH
293 needs update of iconv in lib/windows to support getting the system language string
295 UI_DrawString(G.font, fname, 0);
299 void file_calc_previews(const bContext *C, ARegion *ar)
301 SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
302 View2D *v2d= &ar->v2d;
304 ED_fileselect_init_layout(sfile, ar);
305 UI_view2d_totRect_set(v2d, sfile->layout->width, sfile->layout->height);
308 void file_draw_previews(const bContext *C, ARegion *ar)
310 SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
311 FileSelectParams* params= ED_fileselect_get_params(sfile);
312 FileLayout* layout= ED_fileselect_get_layout(sfile, ar);
313 View2D *v2d= &ar->v2d;
314 struct FileList* files = sfile->files;
316 struct direntry *file;
326 filelist_imgsize(files,sfile->layout->prv_w,sfile->layout->prv_h);
327 numfiles = filelist_numfiles(files);
329 sx = v2d->cur.xmin + layout->tile_border_x;
330 sy = v2d->cur.ymax - layout->tile_border_y;
332 offset = ED_fileselect_layout_offset(layout, 0, 0);
333 if (offset<0) offset=0;
334 for (i=offset; (i < numfiles) && (i < (offset+(layout->rows+2)*layout->columns)); ++i)
336 ED_fileselect_layout_tilepos(layout, i, &sx, &sy);
337 sx += v2d->tot.xmin+2;
338 sy = v2d->tot.ymax - sy;
339 file = filelist_file(files, i);
341 if (file->flags & ACTIVE) {
343 draw_tile(sx - 1, sy, sfile->layout->tile_w + 1, sfile->layout->tile_h, colorid,0);
344 } else if (params->active_file == i) {
346 draw_tile(sx - 1, sy, sfile->layout->tile_w + 1, sfile->layout->tile_h, colorid,0);
349 if ( (file->flags & IMAGEFILE) /* || (file->flags & MOVIEFILE) */)
351 filelist_loadimage(files, i);
354 imb = filelist_getimage(files, i);
356 imb = filelist_geticon(files,i);
361 float fx = ((float)layout->prv_w - (float)imb->x)/2.0f;
362 float fy = ((float)layout->prv_h - (float)imb->y)/2.0f;
363 float dx = (fx + 0.5f + sfile->layout->prv_border_x);
364 float dy = (fy + 0.5f - sfile->layout->prv_border_y);
365 short xco = (float)sx + dx;
366 short yco = (float)sy - sfile->layout->prv_h + dy;
368 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
371 if (!is_icon && (file->flags & IMAGEFILE))
372 uiDrawBoxShadow(220, xco, yco, xco + imb->x, yco + imb->y);
377 glColor4f(1.0, 1.0, 1.0, 1.0);
378 glaDrawPixelsTex(xco, yco, imb->x, imb->y, GL_UNSIGNED_BYTE, imb->rect);
381 if (!is_icon && (file->flags & IMAGEFILE)) {
382 glColor4f(0.0f, 0.0f, 0.0f, 0.4f);
383 fdrawbox(xco, yco, xco + imb->x, yco + imb->y);
391 UI_ThemeColorShade(TH_BACK, -20);
394 if (S_ISDIR(file->type)) {
395 glColor4f(1.0f, 1.0f, 0.9f, 1.0f);
397 else if (file->flags & IMAGEFILE) {
398 UI_ThemeColor(TH_SEQ_IMAGE);
400 else if (file->flags & MOVIEFILE) {
401 UI_ThemeColor(TH_SEQ_MOVIE);
403 else if (file->flags & BLENDERFILE) {
404 UI_ThemeColor(TH_SEQ_SCENE);
407 if (params->active_file == i) {
408 UI_ThemeColor(TH_GRID); /* grid used for active text */
409 } else if (file->flags & ACTIVE) {
410 UI_ThemeColor(TH_TEXT_HI);
412 UI_ThemeColor(TH_TEXT);
416 file_draw_string(sx + layout->prv_border_x, sy+4, file->relname, layout->tile_w, layout->tile_h, FILE_SHORTEN_END);
418 if (!sfile->loadimage_timer)
419 sfile->loadimage_timer= WM_event_add_window_timer(CTX_wm_window(C), TIMER1, 1.0/30.0); /* max 30 frames/sec. */
427 void file_draw_list(const bContext *C, ARegion *ar)
429 SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
430 FileSelectParams* params = ED_fileselect_get_params(sfile);
431 FileLayout* layout= ED_fileselect_get_layout(sfile, ar);
432 View2D *v2d= &ar->v2d;
433 struct FileList* files = sfile->files;
434 struct direntry *file;
443 numfiles = filelist_numfiles(files);
444 type = filelist_gettype(files);
446 sx = ar->v2d.tot.xmin + layout->tile_border_x/2;
447 sy = ar->v2d.cur.ymax - layout->tile_border_y;
449 offset = ED_fileselect_layout_offset(layout, 0, 0);
450 if (offset<0) offset=0;
452 /* alternating flat shade background */
453 for (i=offset; (i <= numfiles); ++i)
455 ED_fileselect_layout_tilepos(layout, i, &sx, &sy);
457 sy = v2d->tot.ymax - (sy + layout->tile_border_y);
458 //sy = v2d->tot.ymax - sy;
460 if (i % 2) UI_ThemeColor(TH_BACK);
461 else UI_ThemeColorShade(TH_BACK, -7);
462 glRectf(v2d->tot.xmin, sy, v2d->tot.xmax, sy+layout->tile_h+2*layout->tile_border_y);
465 /* vertical column dividers */
466 while (sx < ar->v2d.cur.xmax) {
467 sx += (sfile->layout->tile_w+2*sfile->layout->tile_border_x);
469 UI_ThemeColorShade(TH_BACK, 30);
470 sdrawline(sx+1, ar->v2d.cur.ymax - layout->tile_border_y , sx+1, ar->v2d.cur.ymin);
471 UI_ThemeColorShade(TH_BACK, -30);
472 sdrawline(sx, ar->v2d.cur.ymax - layout->tile_border_y , sx, ar->v2d.cur.ymin);
475 sx = ar->v2d.cur.xmin + layout->tile_border_x;
476 sy = ar->v2d.cur.ymax - layout->tile_border_y;
478 for (i=offset; (i < numfiles); ++i)
480 ED_fileselect_layout_tilepos(layout, i, &sx, &sy);
481 sx += v2d->tot.xmin+2;
482 sy = v2d->tot.ymax - sy;
484 file = filelist_file(files, i);
486 if (params->active_file == i) {
487 if (file->flags & ACTIVE) colorid= TH_HILITE;
488 else colorid = TH_BACK;
489 draw_tile(sx-2, sy-3, layout->tile_w+2, sfile->layout->tile_h+layout->tile_border_y, colorid,20);
490 } else if (file->flags & ACTIVE) {
492 draw_tile(sx-2, sy-3, layout->tile_w+2, sfile->layout->tile_h+layout->tile_border_y, colorid,0);
496 draw_tile(sx, sy, sfile->tile_w, sfile->tile_h, colorid);
501 file_draw_icon(spos, sy-3, get_file_icon(file), ICON_DEFAULT_WIDTH, ICON_DEFAULT_WIDTH);
502 spos += ICON_DEFAULT_WIDTH + 4;
504 UI_ThemeColor4(TH_TEXT);
506 // sw = shorten_filesize(file->size, FILE_SHORTEN_FSIZE_WIDTHONLY);
507 sw = UI_GetStringWidth(G.font, file->size, 0);
508 file_draw_string(spos, sy, file->relname, layout->tile_w - sw - 5, layout->tile_h, FILE_SHORTEN_END);
510 spos += filelist_maxnamelen(sfile->files);
511 if (params->display == FILE_SHOWSHORT) {
512 if (!(file->type & S_IFDIR))
513 file_draw_string(sx + layout->tile_w - layout->tile_border_x - sw, sy, file->size, sw, layout->tile_h, FILE_SHORTEN_END);
515 #if 0 // XXX TODO: add this for non-windows systems
518 sw = UI_GetStringWidth(G.font, file->mode1, 0);
519 file_draw_string(spos, sy, file->mode1, sw, layout->tile_h);
522 sw = UI_GetStringWidth(G.font, file->mode2, 0);
523 file_draw_string(spos, sy, file->mode2, sw, layout->tile_h);
526 sw = UI_GetStringWidth(G.font, file->mode3, 0);
527 file_draw_string(spos, sy, file->mode3, sw, layout->tile_h);
530 sw = UI_GetStringWidth(G.font, file->owner, 0);
531 file_draw_string(spos, sy, file->owner, sw, layout->tile_h);
535 sw = UI_GetStringWidth(G.font, file->date, 0);
536 file_draw_string(spos, sy, file->date, sw, layout->tile_h, FILE_SHORTEN_END);
539 sw = UI_GetStringWidth(G.font, file->time, 0);
540 file_draw_string(spos, sy, file->time, sw, layout->tile_h, FILE_SHORTEN_END);
542 if (!(file->type & S_IFDIR)) {
543 sw = UI_GetStringWidth(G.font, file->size, 0);
545 file_draw_string(spos, sy, file->size, sw, layout->tile_h, FILE_SHORTEN_END);
551 static void file_draw_fsmenu_category(const bContext *C, ARegion *ar, FSMenuCategory category, const char* category_name, short *starty)
553 SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
554 struct FSMenu* fsmenu = fsmenu_get();
555 char bookmark[FILE_MAX];
556 int nentries = fsmenu_get_nentries(fsmenu, category);
557 int linestep = gFontsize*2.0f;
558 short sx, sy, xpos, ypos;
559 int bmwidth = ar->v2d.cur.xmax - ar->v2d.cur.xmin - 2*TILE_BORDER_X - ICON_DEFAULT_WIDTH - 4;
560 int fontsize = gFontsize;
564 sx = ar->v2d.cur.xmin + TILE_BORDER_X;
567 UI_ThemeColor(TH_TEXT_HI);
568 file_draw_string(sx, sy, category_name, bmwidth, fontsize, FILE_SHORTEN_END);
572 for (i=0; i< nentries && (sy > ar->v2d.cur.ymin) ;++i) {
573 char *fname = fsmenu_get_entry(fsmenu, category, i);
577 BLI_strncpy(bookmark, fname, FILE_MAX);
579 sl = strlen(bookmark)-1;
580 while (bookmark[sl] == '\\' || bookmark[sl] == '/') {
584 if (fsmenu_is_selected(fsmenu, category, i) ) {
585 UI_ThemeColor(TH_HILITE);
586 /* uiSetRoundBox(15);
587 * uiRoundBox(sx, sy - linestep, sx + bmwidth, sy, 4.0f); */
588 glRectf(ar->v2d.cur.xmin, sy-linestep, ar->v2d.cur.xmax + 2*TILE_BORDER_X, sy);
589 UI_ThemeColor(TH_TEXT);
591 UI_ThemeColor(TH_TEXT_HI);
595 ypos = sy - (TILE_BORDER_Y * 0.5);
597 file_draw_icon(xpos, ypos, ICON_FILE_FOLDER, ICON_DEFAULT_WIDTH, ICON_DEFAULT_WIDTH);
598 xpos += ICON_DEFAULT_WIDTH + 4;
599 file_draw_string(xpos, ypos, bookmark, bmwidth, fontsize, FILE_SHORTEN_FRONT);
601 fsmenu_set_pos(fsmenu, category, i, xpos, ypos);
608 void file_draw_fsmenu(const bContext *C, ARegion *ar)
610 int linestep = gFontsize*2.0f;
611 short sy= ar->v2d.cur.ymax-2*TILE_BORDER_Y;
613 file_draw_fsmenu_category(C, ar, FS_CATEGORY_SYSTEM, "SYSTEM", &sy);
615 file_draw_fsmenu_category(C, ar, FS_CATEGORY_BOOKMARKS, "BOOKMARKS", &sy);
617 file_draw_fsmenu_category(C, ar, FS_CATEGORY_RECENT, "RECENT", &sy);