1 module unde.marks;
2 
3 import unde.global_state;
4 import unde.lib;
5 import unde.font;
6 import unde.path_mnt;
7 import unde.viewers.image_viewer.lib;
8 import unde.viewers.text_viewer.lib;
9 import unde.slash;
10 
11 version (Windows)
12 {
13 import unde.file_manager.find_path;
14 }
15 
16 import berkeleydb.all;
17 
18 import derelict.sdl2.sdl;
19 import derelict.sdl2.ttf;
20 
21 import std.math;
22 import std.stdio;
23 import std..string;
24 import std.conv;
25 
26 
27 public DRect
28 get_rectsize_for_path(GlobalState gs, PathMnt path, string full_path,
29         DRect apply_rect, SortType sort = SortType.ByName)
30 {
31     bool pmnt;
32     Dbt key, data;
33     if (path in gs.lsblk)
34     {
35         string path0 = path.get_key(gs.lsblk);
36         key = path0;
37         auto res = gs.db_map.get(null, &key, &data);
38         if (res == 0)
39         {
40             RectSize rectsize;
41             rectsize = data.to!(RectSize);
42             apply_rect = rectsize.rect(sort).apply(apply_rect);
43         }
44         else
45         {
46 		version(Windows)
47 		{
48 			if (path.length == 2)
49 			{
50 				DRect rect = get_drect_of_drives(gs, path);
51 				apply_rect = rect.apply(apply_rect);
52 			}
53 		}
54 
55 		{
56 		    // TODO: Created mount point, rescan up path
57 		}
58         }
59 
60         pmnt = true;
61     }
62 
63     try
64     {
65         path.update(gs.lsblk);
66     }
67     catch (Exception e)
68     {
69         return DRect();
70     }
71 
72     string path0 = path.get_key(gs.lsblk);
73     key = path0;
74     //writefln("GET %s", path0.replace("\0", SL));
75     auto res = gs.db_map.get(null, &key, &data);
76     version(Windows)
77     {
78     if (path == SL) res = 0;
79     }
80 
81     if (res == 0)
82     {
83         RectSize rectsize;
84 	version(Windows)
85 	{
86 		if (path == SL) 
87 		{
88 			DRect full_rect = DRect(0, 0, 1024*1024, 1024*1024);
89 			rectsize = RectSize(full_rect, full_rect, full_rect);
90 		}
91 		else
92 			rectsize = data.to!(RectSize);
93 	}
94 	else
95 	{
96 		rectsize = data.to!(RectSize);
97 	}
98         rectsize.rect(sort) = rectsize.rect(sort).apply(apply_rect);
99 
100         //writefln("path=%s, full_path=%s", path, full_path);
101         if (path == full_path)
102         {
103             return rectsize.rect(sort);
104         }
105 
106 	string next;
107 	bool found = false;
108 	version (Windows)
109 	{
110 		if (path == SL && full_path[1] == ':')
111 		{
112 			next = full_path[0..2];
113 			found = true;
114 		}
115 	}
116 	if (!found)
117 	{
118 		auto after_path = full_path[path.length+1..$];
119 		if (path == SL) after_path = full_path[1..$];
120 		//writefln("after_path=%s", after_path);
121 		if (after_path.indexOf(SL) > 0)
122 		    next = path ~ SL ~ after_path[0..after_path.indexOf(SL)];
123 		else
124 		    next = path ~ SL ~ after_path;
125 		if (path == SL) next = next[1..$];
126 	}
127 		//writefln("next=%s", next);
128 
129         auto drect = get_rectsize_for_path(gs, path.next(next), full_path, rectsize.rect(sort), rectsize.sort);
130         return drect;
131     }
132     return DRect();
133 }
134 
135 void draw_marks(GlobalState gs, ref CoordinatesPlusScale surf)
136 {
137 //unmark(gs, "L");
138     foreach(char m; 'A'..('Z'+1))
139     {
140         Dbt key = m;
141         Dbt data;
142 
143         auto res = gs.db_marks.get(null, &key, &data);
144         if (res == 0)
145         {
146             Mark mark = data.to!(Mark);
147             string path = from_char_array(mark.path);
148             string uuid = path[0..path.indexOf("\0")];
149 
150             string full_path = null;
151             foreach(mount_point, lsblk_info; gs.lsblk)
152             {
153                 if (lsblk_info.uuid == uuid)
154                 {
155                     full_path = mount_point ~ path[path.indexOf("\0")..$].replace("\0", SL);
156                     if (mount_point == SL) full_path = full_path[1..$];
157                     break;
158                 }
159             }
160 
161             if (full_path)
162             {
163                 auto apply_rect = DRect(0, 0, 1024*1024, 1024*1024);
164                 auto drect = get_rectsize_for_path(gs, PathMnt(gs.lsblk, SL), full_path, apply_rect);
165 
166                 SDL_Rect on_surf = drect.to_screen(surf);
167                 SDL_Rect on_screen = drect.to_screen(gs.screen);
168                 //writefln("%s: %s", m, full_path);
169                 //writefln("SDL_Rect: %s", on_screen);
170                 //writefln("Mark screen_rect: %s", mark.screen_rect);
171 
172                 if (on_screen.w <= mark.screen_rect.w && on_screen.h <= mark.screen_rect.h)
173                 {
174                     double xrelation = cast(double)(gs.screen.w/2 - mark.screen_rect.x) / (mark.screen_rect.x + mark.screen_rect.w - gs.screen.w/2);
175                     double yrelation = cast(double)(gs.screen.h/2 - mark.screen_rect.y) / (mark.screen_rect.y + mark.screen_rect.h - gs.screen.h/2);
176 
177                     //xrelation = X / (on_screen.w - X);
178                     //xrelation*on_screen.w = xrelation*X + X
179 
180                     int x = cast(int)( on_surf.x + xrelation*on_surf.w/(xrelation+1) );
181                     int y = cast(int)( on_surf.y + yrelation*on_surf.h/(yrelation+1) );
182 
183                     //writefln("%dx%d", x, y);
184 
185                     auto tt1 = gs.text_viewer.font.get_char_from_cache(
186                             "⬤", 10, SDL_Color(0x00, 0xFF, 0xFF, 0x80));
187                     auto tt2 = gs.text_viewer.font.get_char_from_cache(
188                             "◯", 10, SDL_Color(0x00, 0x00, 0x00, 0xFF));
189                     auto tt3 = gs.text_viewer.font.get_char_from_cache(
190                             ""~m, 9, SDL_Color(0x00, 0x00, 0x00, 0xFF));
191 
192                     SDL_Rect rect1 = SDL_Rect(x-tt1.w/2, y-tt1.h/2, 
193                                                 tt1.w, tt1.h);
194                     SDL_Rect rect2 = SDL_Rect(x-tt2.w/2, y-tt2.h/2, 
195                                                 tt2.w, tt2.h);
196                     SDL_Rect rect3 = SDL_Rect(x-tt3.w/2, y-tt3.h/2, 
197                                                 tt3.w, tt3.h);
198 
199                     auto r = SDL_RenderCopy(gs.renderer, tt1.texture, 
200                                                 null, &rect1);
201                     if (r < 0)
202                     {
203                         writefln( "draw_marks(): Error while render copy 1: %s",
204                                 SDL_GetError().to!string() );
205                     }
206 
207                     r = SDL_RenderCopy(gs.renderer, tt2.texture, 
208                                                 null, &rect2);
209                     if (r < 0)
210                     {
211                         writefln( "draw_marks(): Error while render copy 2: %s",
212                                 SDL_GetError().to!string() );
213                     }
214 
215                     r = SDL_RenderCopy(gs.renderer, tt3.texture, 
216                                                 null, &rect3);
217                     if (r < 0)
218                     {
219                         writefln( "draw_marks(): Error while render copy 3: %s", SDL_GetError().to!string() );
220                     }
221                 }
222             }
223         }
224     }
225 }
226 
227 void remark_desktop(GlobalState gs)
228 {
229     static CoordinatesPlusScale old_screen;
230     static State old_state;
231     static string old_path;
232     static long old_offset;
233 
234     bool remark = false;
235     if (gs.screen != old_screen || gs.state != old_state)
236     {
237         remark = true;
238         old_screen = gs.screen;
239         old_state = gs.state;
240     }
241     else if (gs.screen == old_screen && gs.state == old_state &&
242             (gs.state == State.ImageViewer || gs.state == State.TextViewer))
243     {
244         string path;
245         long offset;
246         if (gs.state == State.ImageViewer)
247         {
248             path = gs.image_viewer.path.get_key(gs.lsblk);
249             offset = old_offset;
250         }
251         else
252         {
253             path = gs.text_viewer.path.get_key(gs.lsblk);
254             offset = gs.text_viewer.rectsize.offset;
255         }
256 
257         if (path != old_path || offset != old_offset)
258             remark = true;
259 
260         old_path = path;
261         old_offset = offset;
262     }
263 
264     if (remark)
265         mark(gs, gs.desktop, true);
266 }
267 
268 void mark(GlobalState gs, string m, bool hide_remark_message = false)
269 {
270     writefln("mark %s", m);
271     Mark mark;
272     mark.state = gs.state;
273     string path;
274     final switch (gs.state)
275     {
276         case State.FileManager:
277             path = gs.current_path;
278             break;
279         case State.ImageViewer:
280             path = gs.image_viewer.path.get_key(gs.lsblk);
281             break;
282         case State.TextViewer:
283             path = gs.text_viewer.path.get_key(gs.lsblk);
284             mark.offset = gs.text_viewer.rectsize.offset;
285             break;
286     }
287     mark.path = to_char_array!MARKS_PATH_MAX(path);
288 
289     final switch (gs.state)
290     {
291         case State.FileManager:
292             mark.screen_rect = gs.current_path_rect.to_screen(gs.screen);
293             if (!(m >= "0" && m <= "9"))
294             {
295                 mark.screen_rect.x += gs.screen.w/2 - gs.mouse_screen_x;
296                 mark.screen_rect.y += gs.screen.h/2 - gs.mouse_screen_y;
297             }
298             break;
299         case State.ImageViewer:
300             goto case;
301         case State.TextViewer:
302             mark.screen_rect = SDL_Rect((gs.screen.w - gs.screen.h)/2, 0, gs.screen.h, gs.screen.h);
303             break;
304     }
305 
306     writefln("%s, screen_rect = %s, path = %s", m, mark.screen_rect, path);
307     Dbt key, data;
308     key = m;
309     data = mark;
310 
311     auto res = gs.db_marks.put(null, &key, &data);
312     if (res != 0)
313         throw new Exception("Mark info to marks-db not written");
314 
315     else if (!hide_remark_message && m >= "0" && m <= "9")
316     {
317         string msg = format("Desktop %s remarked", m);
318         gs.messages ~= ConsoleMessage(
319                 SDL_Color(0xFF, 0xFF, 0xFF, 0xFF),
320                 msg,
321                 SDL_GetTicks()
322                 );
323         writeln(msg);
324     }
325 }
326 
327 void unmark(GlobalState gs, string m)
328 {
329     Dbt key;
330     key = m;
331 
332     auto res = gs.db_marks.del(null, &key);
333     if (res != 0)
334         throw new Exception("Mark info from marks-db not deleted");
335 
336     if (m >= "0" && m <= "9")
337     {
338         string msg = format("Desktop %s removed", m);
339         gs.messages ~= ConsoleMessage(
340                 SDL_Color(0xFF, 0xFF, 0xFF, 0xFF),
341                 msg,
342                 SDL_GetTicks()
343                 );
344         writeln(msg);
345     }
346 }
347 
348 bool check_mark(GlobalState gs, string m)
349 {
350     Dbt key = m;
351     Dbt data;
352 
353     auto res = gs.db_marks.get(null, &key, &data);
354     return (res == 0);
355 }
356 
357 void go_mark(GlobalState gs, string m)
358 {
359     Dbt key = m;
360     Dbt data;
361 
362     writefln("Go Mark %s", m);
363     auto res = gs.db_marks.get(null, &key, &data);
364     if (res == 0)
365     {
366         Mark mark = data.to!(Mark);
367         string path = from_char_array(mark.path);
368 
369         if (path == "")
370             goto create_desktop;
371 
372         string uuid = path[0..path.indexOf("\0")];
373 
374         string full_path = null;
375         foreach(mount_point, lsblk_info; gs.lsblk)
376         {
377             if (lsblk_info.uuid == uuid)
378             {
379                 full_path = mount_point ~ path[path.indexOf("\0")..$].replace("\0", SL);
380                 if (mount_point == SL) full_path = full_path[1..$];
381                 break;
382             }
383         }
384 
385 	version (Windows)
386 	{
387 		if (full_path.length == 3 && full_path[1] == ':')
388 		{
389 			full_path = full_path[0..2];
390 		}
391 	}
392 	    writefln("path=%s, screen_rect=%s", path, mark.screen_rect);
393 
394         if (full_path)
395         {
396             auto apply_rect = DRect(0, 0, 1024*1024, 1024*1024);
397             auto drect = get_rectsize_for_path(gs, PathMnt(gs.lsblk, SL), full_path, apply_rect);
398 
399             if (!isNaN(drect.w))
400             {
401                 //SDL_Rect on_screen = drect.to_screen(gs.screen);
402                 //writefln("Recalculate screen coordinates on %s", full_path);
403                 drect.rescale_screen(gs.screen, mark.screen_rect);
404             }
405             else
406             {
407                 writefln("Can't calculate DRect for %s", full_path);
408             }
409 
410             gs.state = State.FileManager;
411 
412             if (mark.state != State.FileManager)
413             {
414                 if (mark.state == State.ImageViewer)
415                     image_viewer(gs, PathMnt(gs.lsblk, full_path));
416                 else if (mark.state == State.TextViewer)
417                 {
418                     text_viewer(gs, PathMnt(gs.lsblk, full_path));
419                     gs.text_viewer.rectsize.offset = mark.offset;
420                 }
421             }
422         }
423     }
424     
425 create_desktop:
426     if (res != 0 && m >= "0" && m <= "9")
427     {
428         gs.initScreenAndSurf();
429         gs.state = State.FileManager;
430 
431         string msg = format("Desktop %s created", m);
432         gs.messages ~= ConsoleMessage(
433                 SDL_Color(0xFF, 0xFF, 0xFF, 0xFF),
434                 msg,
435                 SDL_GetTicks()
436                 );
437         writeln(msg);
438     }
439 
440     if (m >= "0" && m <= "9")
441     {
442         gs.desktop = m;
443 
444         string current_desktop = "current_desktop";
445         key = current_desktop;
446         data = m;
447 
448         res = gs.db_marks.put(null, &key, &data);
449         if (res != 0)
450             throw new Exception("Can't write current desktop to marks-db");
451 	//writefln("gs.desktop=%s", gs.desktop);
452     }
453 }