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