b8f7420d75717af9be87e221e6e3360b8043fec1
[vrfileman] / src / fs.cc
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <string>
6 #include <map>
7 #include <unistd.h>
8 #include <dirent.h>
9 #include <sys/stat.h>
10 #include "fs.h"
11 #include "icon.h"
12 #include "gmath/gmath.h"
13 #include "opengl.h"
14 #include "app.h"
15 #include "drawtext.h"
16
17 static IconRenderer *iconrend;
18
19 static std::map<std::string, FSNode*> node_cache;
20 static FSNode *cur_node;
21 static int start_child;
22
23 static dtx_font *fat_font;
24 #define FAT_FONT_SZ     32
25
26
27 bool init_fs()
28 {
29         iconrend = new ShapesIcons;
30         if(!iconrend->init()) {
31                 return false;
32         }
33
34         if(!(fat_font = dtx_open_font("data/fat.font", FAT_FONT_SZ))) {
35                 fprintf(stderr, "failed to open font file data/fat.font\n");
36                 return false;
37         }
38
39         cur_node = get_fsnode(0);
40         cur_node->expand();
41         return true;
42 }
43
44 void cleanup_fs()
45 {
46         std::map<std::string, FSNode*>::iterator it = node_cache.begin();
47         while(it != node_cache.end()) {
48                 FSNode *node = it++->second;
49                 delete node;
50         }
51         node_cache.clear();
52         delete iconrend;
53 }
54
55 static Vec3 icon_pos(int row, int col, int ncols, float row_spacing, float radius)
56 {
57         float angle = 2.0 * M_PI * (float)col / (float)ncols;
58         float x = sin(angle) * radius;
59         float z = -cos(angle) * radius;
60         float y = (float)row * row_spacing;
61         return Vec3(x, y, z);
62 }
63
64 void draw_fs()
65 {
66         static const int ncols = 8;
67         static const float row_spacing = 2.0;
68         static const float radius = 5;
69
70         Mat4 base_xform;
71         base_xform.rotate(time_sec, 0, 0);
72         base_xform.rotate(0, 0, time_sec * 0.5);
73         base_xform.translate(0, 2, 0);
74
75         glUseProgram(0);
76         glDisable(GL_TEXTURE_2D);
77
78         int first = start_child % ncols;
79         int nchildren = (int)cur_node->children.size();
80         int col = 0, row = 0;
81
82         for(int i=0; i<nchildren; i++) {
83                 int idx = (i + first) % nchildren;
84                 FSNode *node = cur_node->children[idx];
85
86                 if(node->type == FSTYPE_DIR) {
87                         continue;
88                 }
89
90                 float angle = -2.0 * M_PI * (float)col / (float)ncols;
91
92                 Mat4 xform = base_xform;
93                 xform.translate(0, row * row_spacing, -radius);
94                 xform.rotate_y(angle);
95
96                 glPushMatrix();
97                 glMultMatrixf(xform[0]);
98                 iconrend->draw(node);
99                 glPopMatrix();
100
101                 glPushMatrix();
102                 xform = Mat4::identity;
103                 xform.translate(-dtx_string_width(node->path.get_name()) / 2.0, 0, 0);
104                 xform.scale(0.01);
105                 xform.translate(0, 1 + row * row_spacing, -radius);
106                 xform.rotate_y(angle);
107                 glMultMatrixf(xform[0]);
108
109                 dtx_string(node->path.get_name());
110                 glPopMatrix();
111
112                 if(++col >= ncols) {
113                         col = 0;
114                         ++row;
115                 }
116         }
117 }
118
119 FSNode *get_fsnode(const char *path)
120 {
121         char *abspath = make_abs_path(path);
122
123         FSNode *node = node_cache[abspath];
124         if(!node) {
125                 node = new FSNode;
126                 node->path = path;
127
128                 struct stat st;
129                 if(stat(node->path, &st) == -1) {
130                         fprintf(stderr, "failed to stat: %s\n", node->path.get_path());
131                         delete node;
132                         return 0;
133                 }
134                 node->size = st.st_size;
135
136                 switch(st.st_mode & S_IFMT) {
137                 case S_IFREG:
138                         node->type = FSTYPE_FILE;
139                         break;
140
141                 case S_IFDIR:
142                         node->type = FSTYPE_DIR;
143                         break;
144
145                 case S_IFBLK:
146                 case S_IFCHR:
147                         node->type = FSTYPE_DEV;
148                         break;
149
150                 default:
151                         node->type = FSTYPE_UNKNOWN;
152                 }
153                 node_cache[abspath] = node;
154         }
155
156         return node;
157 }
158
159 FSNode *get_fsnode(const char *dir, const char *name)
160 {
161         if(!dir) {
162                 return get_fsnode(name);
163         }
164         if(!name || *name == '/') {
165                 return 0;
166         }
167
168         int len = strlen(dir) + 1 + strlen(name);
169         char *buf = new char[len + 1];
170         sprintf(buf, "%s/%s", dir, name);
171         FSNode *res = get_fsnode(buf);
172         delete [] buf;
173         return res;
174 }
175
176 // ---- FSNode implementation ----
177 FSNode::FSNode()
178 {
179         type = FSTYPE_UNKNOWN;
180         size = 0;
181         parent = 0;
182 }
183
184 bool FSNode::expand()
185 {
186         if(type != FSTYPE_DIR) {
187                 return false;
188         }
189
190         DIR *dir = opendir(path);
191         if(!dir) {
192                 fprintf(stderr, "failed to open dir: %s: %s\n", path.get_path(), strerror(errno));
193                 return false;
194         }
195
196         struct dirent *dent;
197         while((dent = readdir(dir))) {
198                 if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
199                         continue;
200                 }
201
202                 FSNode *node = get_fsnode(path, dent->d_name);
203                 if(!node) continue;
204
205                 children.push_back(node);
206         }
207         printf("expanded %d children\n", (int)children.size());
208
209         parent = get_fsnode(path.get_parent());
210         return true;
211 }