2.5 filebrowser
[blender.git] / source / blender / editors / space_file / file_ops.c
1 /**
2  * $Id:
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
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. 
10  *
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.
15  *
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.
19  *
20  * The Original Code is Copyright (C) 2008 Blender Foundation.
21  * All rights reserved.
22  *
23  * 
24  * Contributor(s): Andrea Weikert (c) 2008 Blender Foundation
25  *
26  * ***** END GPL LICENSE BLOCK *****
27  */
28
29 #include "BKE_context.h"
30 #include "BKE_screen.h"
31 #include "BKE_global.h"
32
33 #include "BLI_blenlib.h"
34 #include "BLI_storage_types.h"
35 #ifdef WIN32
36 #include "BLI_winstuff.h"
37 #endif
38 #include "DNA_space_types.h"
39 #include "DNA_userdef_types.h"
40
41 #include "ED_space_api.h"
42 #include "ED_screen.h"
43 #include "ED_fileselect.h"
44
45 #include "WM_api.h"
46 #include "WM_types.h"
47
48 #include "UI_view2d.h"
49
50 #include "file_intern.h"
51 #include "filelist.h"
52 #include "fsmenu.h"
53
54 #include <stdlib.h>
55 #include <string.h>
56 #include <stdio.h>
57
58 /* for events */
59 #define NOTACTIVE                       0
60 #define ACTIVATE                        1
61 #define INACTIVATE                      2
62
63
64 static void set_active_file_thumbs(SpaceFile *sfile, FileSelectParams* params, struct ARegion* ar, short mval[])
65 {
66         float x,y;
67         int active_file = -1;
68         struct direntry* file;
69         int offsetx, offsety;
70         int numfiles = filelist_numfiles(sfile->files);
71         int columns;
72
73         View2D* v2d = &ar->v2d;
74         UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
75         
76         offsetx = (x - (v2d->cur.xmin+sfile->tile_border_x))/(sfile->tile_w + sfile->tile_border_x);
77         offsety = (-y+sfile->tile_border_y)/(sfile->tile_h + sfile->tile_border_y);
78         columns = (v2d->cur.xmax - v2d->cur.xmin) / (sfile->tile_w+ sfile->tile_border_x);
79         active_file = offsetx + columns*offsety;
80
81         if (active_file >= 0 && active_file < numfiles )
82         {
83                 params->active_file = active_file;
84                 if (params->selstate & ACTIVATE) {
85                         file = filelist_file(sfile->files, params->active_file);
86                         file->flags |= ACTIVE;
87                 }                       
88         }
89 }
90
91
92 static void set_active_file(SpaceFile *sfile, FileSelectParams* params, struct ARegion* ar, short mval[])
93 {
94         int offsetx, offsety;
95         float x,y;
96         int active_file = -1;
97         int numfiles = filelist_numfiles(sfile->files);
98         int rows;
99         struct direntry* file;
100
101         View2D* v2d = &ar->v2d;
102         UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y);
103         
104         offsetx = (x-sfile->tile_border_x)/(sfile->tile_w + sfile->tile_border_x);
105         offsety = (v2d->cur.ymax-y-sfile->tile_border_y)/(sfile->tile_h + sfile->tile_border_y);
106         rows = (v2d->cur.ymax - v2d->cur.ymin - 2*sfile->tile_border_y) / (sfile->tile_h+sfile->tile_border_y);
107         active_file = rows*offsetx + offsety;
108         if ( (active_file >= 0) && (active_file < numfiles) )
109         {
110                 params->active_file = active_file;
111                 if (params->selstate & ACTIVATE) {
112                         file = filelist_file(sfile->files, params->active_file);
113                         file->flags |= ACTIVE;
114                 }                       
115         } 
116 }
117
118
119 static void set_active_bookmark(FileSelectParams* params, struct ARegion* ar, short y)
120 {
121         int nentries = fsmenu_get_nentries();
122         short posy = ar->v2d.mask.ymax - TILE_BORDER_Y - y;
123         params->active_bookmark = ((float)posy / (U.fontsize*3.0f/2.0f));
124         if (params->active_bookmark < 0 || params->active_bookmark > nentries) {
125                 params->active_bookmark = -1;
126         }
127 }
128
129 static void mouse_select(SpaceFile* sfile, FileSelectParams* params, ARegion* ar, short *mval)
130 {
131         int numfiles = filelist_numfiles(sfile->files);
132         if(mval[0]>ar->v2d.mask.xmin && mval[0]<ar->v2d.mask.xmax
133                 && mval[1]>ar->v2d.mask.ymin && mval[1]<ar->v2d.mask.ymax) {
134                         params->selstate = NOTACTIVE;
135                         if (params->display) {
136                                 set_active_file_thumbs(sfile, params, ar, mval);
137                         } else {
138                                 set_active_file(sfile, params, ar, mval);
139                         }
140                         if (params->active_file >= 0 && params->active_file < numfiles) {
141                                 struct direntry* file = filelist_file(sfile->files, params->active_file);
142                                 
143                                 if(file && S_ISDIR(file->type)) {
144                                         /* the path is too long and we are not going up! */
145                                         if (strcmp(file->relname, ".") &&
146                                                 strcmp(file->relname, "..") &&
147                                                 strlen(params->dir) + strlen(file->relname) >= FILE_MAX ) 
148                                         {
149                                                 // XXX error("Path too long, cannot enter this directory");
150                                         } else {
151                                                 if (strcmp(file->relname, "..")==0) {
152                                                         /* avoids /../../ */
153                                                         BLI_parent_dir(params->dir);
154                                                 } else {
155                                                         strcat(params->dir, file->relname);
156                                                         strcat(params->dir,"/");
157                                                         params->file[0] = '\0';
158                                                         BLI_cleanup_dir(G.sce, params->dir);
159                                                 }
160                                                 filelist_setdir(sfile->files, params->dir);
161                                                 filelist_free(sfile->files);
162                                                 params->active_file = -1;
163                                         }
164                                 }
165                                 else if (file)
166                                 {
167                                         if (file->relname) {
168                                                 BLI_strncpy(params->file, file->relname, FILE_MAXFILE);
169                                                 /* XXX
170                                                 if(event==MIDDLEMOUSE && filelist_gettype(sfile->files)) 
171                                                         imasel_execute(sfile);
172                                                 */
173                                         }
174                                         
175                                 }       
176                                 /* XXX
177                                 if(BIF_filelist_gettype(sfile->files)==FILE_MAIN) {
178                                         active_imasel_object(sfile);
179                                 }
180                                 */
181                         }
182                 }
183 }
184
185 static void mouse_select_bookmark(SpaceFile* sfile, ARegion* ar, short *mval)
186 {
187         if(mval[0]>ar->v2d.mask.xmin && mval[0]<ar->v2d.mask.xmax
188         && mval[1]>ar->v2d.mask.ymin && mval[1]<ar->v2d.mask.ymax) {
189                 char *selected;
190                 set_active_bookmark(sfile->params, ar, mval[1]);
191                 selected= fsmenu_get_entry(sfile->params->active_bookmark);                     
192                 /* which string */
193                 if (selected) {
194                         FileSelectParams* params = sfile->params;
195                         BLI_strncpy(params->dir, selected, sizeof(params->dir));
196                         BLI_cleanup_dir(G.sce, params->dir);
197                         filelist_free(sfile->files);    
198                         filelist_setdir(sfile->files, params->dir);
199                         params->file[0] = '\0';                 
200                         params->active_file = -1;
201                 }
202         }
203 }
204
205 static int file_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
206 {
207         ARegion *ar= CTX_wm_region(C);
208         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
209         short mval[2];
210         
211         mval[0]= event->x - ar->winrct.xmin;
212         mval[1]= event->y - ar->winrct.ymin;
213         mouse_select(sfile, sfile->params, ar, mval);
214         WM_event_add_notifier(C, NC_WINDOW, NULL);
215         return OPERATOR_FINISHED;
216 }
217
218
219 void ED_FILE_OT_select(wmOperatorType *ot)
220 {
221         /* identifiers */
222         ot->name= "Activate/Select File";
223         ot->idname= "ED_FILE_OT_select";
224         
225         /* api callbacks */
226         ot->invoke= file_select_invoke;
227         ot->poll= ED_operator_file_active;
228 }
229
230
231 static int bookmark_select_invoke(bContext *C, wmOperator *op, wmEvent *event)
232 {
233         ScrArea *sa= CTX_wm_area(C);
234         ARegion *ar= CTX_wm_region(C);
235         SpaceFile *sfile= (SpaceFile*)CTX_wm_space_data(C);
236         short mval[2];
237         
238         mval[0]= event->x - ar->winrct.xmin;
239         mval[1]= event->y - ar->winrct.ymin;
240         mouse_select_bookmark(sfile, ar, mval);
241         ED_area_tag_redraw(sa);
242         return OPERATOR_FINISHED;
243 }
244
245 void ED_FILE_OT_select_bookmark(wmOperatorType *ot)
246 {
247         /* identifiers */
248         ot->name= "Select Directory";
249         ot->idname= "ED_FILE_OT_select_bookmark";
250         
251         /* api callbacks */
252         ot->invoke= bookmark_select_invoke;
253         ot->poll= ED_operator_file_active;
254 }