foo
[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
75                 if(cur_node->children[idx]->type == FSTYPE_DIR) {
76                         continue;
77                 }
78
79                 Vec3 pos = icon_pos(row, col, ncols, row_spacing, radius);
80
81                 Mat4 xform = base_xform;
82                 xform.translate(pos);
83
84                 glPushMatrix();
85                 glMultMatrixf(xform[0]);
86                 iconrend->draw(cur_node->children[idx]);
87                 glPopMatrix();
88
89                 if(++col >= ncols) {
90                         col = 0;
91                         ++row;
92                 }
93         }
94 }
95
96 FSNode *get_fsnode(const char *path)
97 {
98         char *abspath = make_abs_path(path);
99
100         FSNode *node = node_cache[abspath];
101         if(!node) {
102                 node = new FSNode;
103                 node->path = path;
104
105                 struct stat st;
106                 if(stat(node->path, &st) == -1) {
107                         fprintf(stderr, "failed to stat: %s\n", node->path.get_path());
108                         delete node;
109                         return 0;
110                 }
111                 node->size = st.st_size;
112
113                 switch(st.st_mode & S_IFMT) {
114                 case S_IFREG:
115                         node->type = FSTYPE_FILE;
116                         break;
117
118                 case S_IFDIR:
119                         node->type = FSTYPE_DIR;
120                         break;
121
122                 case S_IFBLK:
123                 case S_IFCHR:
124                         node->type = FSTYPE_DEV;
125                         break;
126
127                 default:
128                         node->type = FSTYPE_UNKNOWN;
129                 }
130                 node_cache[abspath] = node;
131         }
132
133         return node;
134 }
135
136 FSNode *get_fsnode(const char *dir, const char *name)
137 {
138         if(!dir) {
139                 return get_fsnode(name);
140         }
141         if(!name || *name == '/') {
142                 return 0;
143         }
144
145         int len = strlen(dir) + 1 + strlen(name);
146         char *buf = new char[len + 1];
147         sprintf(buf, "%s/%s", dir, name);
148         FSNode *res = get_fsnode(buf);
149         delete [] buf;
150         return res;
151 }
152
153 // ---- FSNode implementation ----
154 FSNode::FSNode()
155 {
156         type = FSTYPE_UNKNOWN;
157         size = 0;
158         parent = 0;
159 }
160
161 bool FSNode::expand()
162 {
163         if(type != FSTYPE_DIR) {
164                 return false;
165         }
166
167         DIR *dir = opendir(path);
168         if(!dir) {
169                 fprintf(stderr, "failed to open dir: %s: %s\n", path.get_path(), strerror(errno));
170                 return false;
171         }
172
173         struct dirent *dent;
174         while((dent = readdir(dir))) {
175                 if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) {
176                         continue;
177                 }
178
179                 FSNode *node = get_fsnode(path, dent->d_name);
180                 if(!node) continue;
181
182                 children.push_back(node);
183         }
184         printf("expanded %d children\n", (int)children.size());
185
186         parent = get_fsnode(path.get_parent());
187         return true;
188 }