1 module unde.draw; 2 3 import unde.global_state; 4 import unde.lib; 5 import unde.scan; 6 import unde.file_manager.remove_paths; 7 import unde.file_manager.copy_paths; 8 import unde.file_manager.draw_path.draw_path; 9 import unde.marks; 10 import unde.file_manager.find_path; 11 import unde.file_manager.events; 12 import unde.viewers.image_viewer.lib; 13 import unde.viewers.text_viewer.lib; 14 import unde.command_line.lib; 15 import unde.keybar.lib; 16 import unde.keybar.settings; 17 import unde.tick; 18 import unde.path_mnt; 19 import unde.clickable; 20 21 import berkeleydb.all; 22 import core.thread; 23 24 import derelict.sdl2.sdl; 25 import derelict.sdl2.ttf; 26 27 import std.math; 28 import std.stdio; 29 import std..string; 30 import std.conv; 31 import std.container.slist; 32 33 enum unDE_Flags { 34 Magnify = 0x01, 35 Unmagnify = 0x02, 36 Left = 0x04, 37 Right = 0x08, 38 Up = 0x10, 39 Down = 0x20, 40 } 41 42 43 class DrawPathFiber : Fiber 44 { 45 GlobalState gs; 46 CoordinatesPlusScale[] surface; 47 int result; 48 49 this(GlobalState gs, DbTxn txn, PathMnt path, 50 DRect apply_rect, 51 SortType sort, 52 CoordinatesPlusScale[] surface) 53 { 54 this.gs = gs; 55 this.txn = txn; 56 this.path = path; 57 this.apply_rect = apply_rect; 58 this.sort = sort; 59 this.surface = surface; 60 61 super(&run, 65536); 62 } 63 64 private: 65 DbTxn txn; 66 PathMnt path; 67 DRect apply_rect; 68 SortType sort; 69 70 void run() 71 { 72 result = draw_path(gs, txn, path, surface[0], apply_rect, sort); 73 draw_marks(gs, surface[0]); 74 } 75 } 76 77 /* EN: The difference of unDE_SDL_RenderCopy from SDL_RenderCopy is 78 that x, y coordinates of srcrect, dstrect maybe negative 79 and width, height maybe also more than texture or window size. 80 And this works as expected. 81 RU: Отличие unDE_SDL_RenderCopy от SDL_RenderCopy в том, 82 что координвты x и y прямоугольников srcrect, dstrect могут 83 быть отрицательными и ширина/высота также может выходить 84 за рамки текстуры или окна и это работает как ожидается 85 */ 86 void unDE_RenderCopy(GlobalState gs, 87 ref SDL_Rect srcrect, ref SDL_Rect dstrect) 88 { 89 if (srcrect.x < 0) 90 { 91 dstrect.x = cast(int)(-srcrect.x*gs.surf.scale/gs.screen.scale); 92 srcrect.x = 0; 93 } 94 if (srcrect.y < 0) 95 { 96 dstrect.y = cast(int)(-srcrect.y*gs.surf.scale/gs.screen.scale); 97 srcrect.y = 0; 98 } 99 if ((srcrect.x+srcrect.w) > 2*gs.screen.w) 100 { 101 dstrect.w = cast(int)(gs.screen.w - 102 (srcrect.x+srcrect.w - 2*gs.screen.w)*gs.surf.scale/gs.screen.scale); 103 srcrect.w = cast(int)(2*gs.screen.w - srcrect.x); 104 } 105 if ((srcrect.y+srcrect.h) > 2*gs.screen.h) 106 { 107 dstrect.h = cast(int)(gs.screen.h - 108 (srcrect.y+srcrect.h - 2*gs.screen.h)*gs.surf.scale/gs.screen.scale); 109 srcrect.h = cast(int)(2*gs.screen.h - srcrect.y); 110 } 111 112 int r = SDL_RenderCopy(gs.renderer, gs.texture, &srcrect, &dstrect); 113 if (r < 0) 114 { 115 writefln( "unDE_RenderCopy(): Error while render copy: %s", SDL_GetError().to!string() ); 116 } 117 } 118 119 120 /*RU: Рассчитать прямоугольник который занимает screen и surface 121 и изменить размер surface если screen вышел за его пределы*/ 122 CoordinatesPlusScale[] 123 calculate_rectangles_of_surf_and_screen_and_change_surf_size_if_needed( 124 GlobalState gs, DrawPathFiber draw_path_fiber, ref bool redraw) 125 { 126 DRect surf_rect = gs.surf.getRect(); 127 DRect scr_rect = gs.screen.getRect(); 128 129 int tries = 0; 130 if ( draw_path_fiber is null && 131 ( (!scr_rect.In(surf_rect) || 132 gs.screen.scale < gs.surf.scale || 133 gs.screen.scale/gs.surf.scale > 2) || redraw || gs.dirty) ) 134 { 135 begin: 136 tries++; 137 redraw = false; 138 gs.dirty = false; 139 if (gs.selection_finish == 1 || 140 (gs.selection_finish == 0 && gs.selection_stage == 2)) 141 { 142 gs.selection_lsof = cast(int)gs.selection_list.length; 143 gs.selection_finish = 2; 144 } 145 146 int r = SDL_SetRenderTarget(gs.renderer, gs.surf_texture); 147 if (r < 0) 148 { 149 throw new Exception(format("Error while set render target gs.surf_texture: %s", 150 SDL_GetError().to!string() )); 151 } 152 153 r = SDL_RenderClear(gs.renderer); 154 if (r < 0) 155 { 156 throw new Exception(format("crosasacssin: Error while clear renderer: %s", 157 SDL_GetError().to!string() )); 158 } 159 160 r = SDL_SetRenderTarget(gs.renderer, null); 161 if (r < 0) 162 { 163 throw new Exception(format("Error while restore render target: %s", 164 SDL_GetError().to!string() )); 165 } 166 167 auto surface = new CoordinatesPlusScale[1]; 168 surface[0].scale = gs.screen.scale/sqrt(2.0); 169 170 surface[0].x = gs.screen.x - 171 surface[0].scale*(gs.screen.w*sqrt(2.0) - gs.screen.w)/2; 172 surface[0].y = gs.screen.y - 173 surface[0].scale*(gs.screen.h*sqrt(2.0) - gs.screen.h)/2; 174 surface[0].w = gs.surf.w; 175 surface[0].h = gs.surf.h; 176 177 { 178 surf_rect = surface[0].getRect(); 179 if ((!scr_rect.In(surf_rect) || 180 gs.screen.scale < surface[0].scale || 181 gs.screen.scale/surface[0].scale > 2)) 182 { 183 scr_rect = DRect(0, 0, 0, 0); 184 gs.initScreenAndSurf(); 185 if (tries < 2) 186 goto begin; 187 } 188 assert(!(!scr_rect.In(surf_rect) || 189 gs.screen.scale < surface[0].scale || 190 gs.screen.scale/surface[0].scale > 2)); 191 } 192 return surface; 193 } 194 else 195 return null; 196 } 197 198 /* RU: рисовать "путь" не больше 100 мс и если успели дорисовать 199 преобразовать surface в текстуру */ 200 void draw_path_while_there_is_time_and_create_texture_if_it_is_finished( 201 GlobalState gs, ref DrawPathFiber draw_path_fiber, ref bool redraw) 202 { 203 int r = SDL_SetRenderTarget(gs.renderer, gs.surf_texture); 204 if (r < 0) 205 { 206 throw new Exception(format("Error while set render target gs.surf_texture: %s", 207 SDL_GetError().to!string() )); 208 } 209 210 uint max_draw_tick = SDL_GetTicks() + 100; 211 while (draw_path_fiber.state != Fiber.State.TERM && 212 (SDL_GetTicks() < max_draw_tick || 213 gs.texture == null) ) 214 { 215 draw_path_fiber.call(); 216 } 217 218 r = SDL_SetRenderTarget(gs.renderer, null); 219 if (r < 0) 220 { 221 throw new Exception(format("Error while restore render target: %s", 222 SDL_GetError().to!string() )); 223 } 224 225 if (draw_path_fiber.state == Fiber.State.TERM) 226 { 227 if (draw_path_fiber.result < 0) 228 redraw = true; 229 230 gs.surf = draw_path_fiber.surface[0]; 231 draw_path_fiber = null; 232 233 gs.clickable_list = gs.new_clickable_list; 234 gs.new_clickable_list = SList!Clickable(); 235 236 gs.double_clickable_list = gs.new_double_clickable_list; 237 gs.new_double_clickable_list = SList!Clickable(); 238 239 gs.right_clickable_list = gs.new_right_clickable_list; 240 gs.new_right_clickable_list = SList!Clickable(); 241 242 gs.double_right_clickable_list = gs.new_double_right_clickable_list; 243 gs.new_double_right_clickable_list = SList!Clickable(); 244 245 gs.middle_clickable_list = gs.new_middle_clickable_list; 246 gs.new_middle_clickable_list = SList!Clickable(); 247 248 if (gs.selection_finish == 2) 249 { 250 gs.selection_list = gs.selection_list[gs.selection_lsof..$]; 251 calculate_selection_sub(gs); 252 253 gs.selection_lsof = 0; 254 gs.selection_finish = 0; 255 /*writefln("Selected:"); 256 foreach(key; gs.selection_hash.byKey()) 257 { 258 writefln("%s", key); 259 }*/ 260 } 261 262 auto texture = gs.texture; 263 gs.texture = gs.surf_texture; 264 gs.surf_texture = texture; 265 } 266 else 267 { 268 process_events(gs); 269 } 270 } 271 272 void draw_anim(GlobalState gs) 273 { 274 foreach (path, ref created_directory; gs.animation_info) 275 { 276 if (created_directory.from_calculated && 277 created_directory.to_calculated) 278 { 279 with (created_directory) 280 { 281 if (frame >= 100) 282 { 283 gs.animation_info.remove(path); 284 continue; 285 } 286 SDL_Rect rect; 287 rect.x = from.x + (to.x - from.x)*cast(int)frame/100; 288 rect.y = from.y + (to.y - from.y)*cast(int)frame/100; 289 rect.w = from.w + (to.w - from.w)*cast(int)frame/100; 290 rect.h = from.h + (to.h - from.h)*cast(int)frame/100; 291 int r = SDL_RenderCopy(gs.renderer, gs.texture_white, null, &rect); 292 if (r < 0) 293 { 294 writefln( "draw_anim(): Error while render copy: %s", SDL_GetError().to!string() ); 295 } 296 297 if (last_frame_time) 298 { 299 frame += cast(double)(SDL_GetTicks() - last_frame_time)/10; 300 } 301 last_frame_time = SDL_GetTicks(); 302 } 303 } 304 } 305 } 306 307 void draw_messages(GlobalState gs) 308 { 309 ssize_t first = -1; 310 int line = 24; 311 ulong y_off; 312 foreach(i, mes; gs.messages) 313 { 314 if (SDL_GetTicks() - mes.from < 5000) 315 { 316 if (first == -1) 317 { 318 first = i; 319 320 y_off = gs.screen.h - line*3 - line*(gs.messages.length - first) - 8; 321 322 /* EN: render background of console messages 323 RU: рендерим фон консоли сообщений */ 324 SDL_Rect rect; 325 rect.x = 32; 326 rect.y = cast(int)y_off; 327 rect.w = gs.screen.w - 32*2; 328 rect.h = cast(int)(line*(gs.messages.length - first) + 8); 329 330 int r = SDL_RenderCopy(gs.renderer, gs.texture_black, null, &rect); 331 if (r < 0) 332 { 333 writefln( "draw_messages(), 1: Error while render copy: %s", 334 SDL_GetError().to!string() ); 335 } 336 } 337 338 if (mes.texture == null && mes.message != "") 339 { 340 int line_height = cast(int)(round(SQRT2^^9)*1.2); 341 auto tt = gs.text_viewer.font.get_line_from_cache(mes.message, 342 9, gs.screen.w - 80, line_height, mes.color); 343 if (!tt && !tt.texture) 344 { 345 throw new Exception("Can't create text_surface: "~ 346 to!string(TTF_GetError())); 347 } 348 349 mes.w = tt.w; 350 mes.h = tt.h; 351 352 mes.texture = tt.texture; 353 } 354 355 if (mes.texture != null) 356 { 357 /* EN: Render text to screeb 358 RU: Рендерим текст на экран */ 359 SDL_Rect rect; 360 rect.x = 40; 361 rect.y = cast(int)(y_off + 4 + line*(i-first)); 362 rect.w = mes.w; 363 rect.h = mes.h; 364 365 int r = SDL_RenderCopy(gs.renderer, mes.texture, null, &rect); 366 if (r < 0) 367 { 368 writefln( 369 "draw_messages(), 2: Error while render copy: %s", 370 SDL_GetError().to!string() ); 371 } 372 } 373 } 374 else 375 { 376 SDL_DestroyTexture(mes.texture); 377 } 378 } 379 if (first > 0) 380 gs.messages = gs.messages[first..$]; 381 } 382 383 void draw_screen(GlobalState gs, DbTxn txn) 384 { 385 SDL_SetRenderDrawColor(gs.renderer, 0, 0, 0, 0); 386 SDL_RenderClear(gs.renderer); 387 388 static DrawPathFiber draw_path_fiber; 389 static bool redraw; 390 391 check_scanners(gs); 392 393 final switch (gs.state) 394 { 395 case State.FileManager: 396 auto new_surface_coordinates = 397 calculate_rectangles_of_surf_and_screen_and_change_surf_size_if_needed( 398 gs, draw_path_fiber, redraw); 399 if (new_surface_coordinates) 400 { 401 find_path(gs, txn, new_surface_coordinates[0], gs.path, gs.apply_rect, gs.sort); 402 //writefln("find_path: path=%s", gs.path); 403 draw_path_fiber = new DrawPathFiber( 404 gs, txn, gs.path, gs.apply_rect, gs.sort, 405 new_surface_coordinates); 406 } 407 408 if (draw_path_fiber !is null) 409 { 410 draw_path_while_there_is_time_and_create_texture_if_it_is_finished( 411 gs, draw_path_fiber, redraw); 412 } 413 414 SDL_Rect srcrect; 415 srcrect.x = cast(int)((gs.screen.x - gs.surf.x)/gs.surf.scale); 416 srcrect.y = cast(int)((gs.screen.y - gs.surf.y)/gs.surf.scale); 417 srcrect.w = cast(int)(gs.screen.w*gs.screen.scale/gs.surf.scale); 418 srcrect.h = cast(int)(gs.screen.h*gs.screen.scale/gs.surf.scale); 419 420 SDL_Rect dstrect; 421 dstrect.x = 0; 422 dstrect.y = 0; 423 dstrect.w = gs.screen.w; 424 dstrect.h = gs.screen.h; 425 426 unDE_RenderCopy(gs, srcrect, dstrect); 427 428 draw_anim(gs); 429 break; 430 431 case State.ImageViewer: 432 draw_image(gs); 433 break; 434 435 case State.TextViewer: 436 draw_text(gs); 437 break; 438 } 439 440 setup_keybar(gs); 441 draw_messages(gs); 442 draw_command_line(gs); 443 foreach (uipage; gs.uipages) 444 { 445 if (uipage.show) 446 uipage.on_draw(gs); 447 } 448 draw_keybar(gs); 449 remark_desktop(gs); 450 451 SDL_SetRenderTarget(gs.renderer, null); 452 SDL_RenderPresent(gs.renderer); 453 }