1 module unde.file_manager.draw_path.draw_elements; 2 3 import unde.global_state; 4 import unde.lib; 5 import unde.viewers.image_viewer.lib; 6 7 import derelict.sdl2.sdl; 8 import derelict.sdl2.ttf; 9 import derelict.sdl2.image; 10 11 import std.stdio; 12 import std.conv; 13 import std.math; 14 import std..string; 15 import std.exception; 16 import std.utf; 17 18 package class SDL_Rect_With_Not_Visible_And_No_Draw 19 { 20 SDL_Rect sdl_rect; 21 bool not_visible; 22 bool no_draw; 23 bool current_path; 24 } 25 26 package SDL_Rect_With_Not_Visible_And_No_Draw 27 draw_rect_with_color_by_size(GlobalState gs, ref RectSize rectsize, 28 SortType sort, 29 ref CoordinatesPlusScale surf, bool selected = false, 30 string path = "") 31 { 32 if (rectsize.rect(sort).w == 0) rectsize.rect(sort).w = 1; 33 if (rectsize.rect(sort).h == 0) rectsize.rect(sort).h = 1; 34 //double density = cast(double)(rectsize.size)/(rectsize.w*rectsize.h); 35 //double density_level = log10(density); 36 uint color = 0x80FFFFFF; 37 if (selected) 38 { 39 color = 0x800000FF; 40 } 41 else if (rectsize.size >= 0) 42 { 43 double size_level = log10(rectsize.size); 44 45 SDL_Color rgba = gs.grad.getColor(size_level); 46 /*writefln("%s. (%s / %sx%s) size_level=%.2f, color=(%d, %d, %d)", 47 path, rectsize.size, rectsize.w, rectsize.h, 48 size_level, 49 rgba.r, rgba.g, rgba.b);*/ 50 color = (0x80<<24) | (rgba.r<<16) | (rgba.g<<8) | rgba.b; 51 } 52 53 auto ret = new SDL_Rect_With_Not_Visible_And_No_Draw; 54 55 /* EN: Calculate output square coordiantes for path 56 RU: Расчитать координаты квадрата для пути */ 57 SDL_Rect sdl_rect = rectsize.rect(sort).to_screen(surf); 58 /*writefln("surf_scale=%s", scale); 59 writefln("%s rectsize(%s, %s, %s, %s) - sdl_rect(%s, %s, %s, %s)", 60 path, 61 rectsize.x, rectsize.y, rectsize.w, rectsize.h, 62 sdl_rect.x, sdl_rect.y, sdl_rect.w, sdl_rect.h);*/ 63 64 /* EN: not visible if it go out of surface 65 RU: не видимый если выходит за рамки surface'а */ 66 bool not_visible = (sdl_rect.x+sdl_rect.w)<0 || sdl_rect.x > gs.surf.w || 67 (sdl_rect.y+sdl_rect.h) < 0 || sdl_rect.y > gs.surf.h; 68 //bool no_draw = (2*sdl_rect.w > width && 2*sdl_rect.h > height); 69 70 SDL_Rect onscreen_rect = rectsize.rect(sort).to_screen(gs.screen); 71 72 /* EN: no draw if too big and takes almost all screen 73 RU: не рисовать, если занимает почти весь экран 74 (т.е. прямоугольник исчезает при приближении) */ 75 bool no_draw = onscreen_rect.x < gs.screen.w/8 && 76 (onscreen_rect.x+onscreen_rect.w)>(gs.screen.w*7/8) || 77 onscreen_rect.y < gs.screen.h/8 && 78 (onscreen_rect.y+onscreen_rect.h)>(gs.screen.h*7/8) || 79 not_visible || 80 sdl_rect.w > 2000 || sdl_rect.h > 2000; 81 82 bool current_path = (no_draw || not_visible) && 83 onscreen_rect.x <= gs.screen.w/2 && (onscreen_rect.x+onscreen_rect.w) >= (gs.screen.w*1/2) && 84 onscreen_rect.y <= gs.screen.h/2 && (onscreen_rect.y+onscreen_rect.h) >= (gs.screen.h*1/2); 85 86 if ( current_path ) 87 gs.current_path_rect = rectsize.rect(sort); 88 89 if (!no_draw && !not_visible) 90 { 91 SDL_Rect sdl_rect_dup = sdl_rect; 92 unDE_RenderFillRect(gs.renderer, &sdl_rect_dup, color); 93 } 94 95 ret.sdl_rect = sdl_rect; 96 ret.not_visible = not_visible; 97 ret.no_draw = no_draw; 98 ret.current_path = current_path; 99 100 return ret; 101 } 102 103 package void 104 draw_center_rect_with_color( 105 GlobalState gs, 106 SDL_Rect_With_Not_Visible_And_No_Draw rnvnd, 107 uint color) 108 { 109 SDL_Rect sdl_rect = rnvnd.sdl_rect; 110 sdl_rect.x = sdl_rect.x+sdl_rect.w/3; 111 sdl_rect.y = sdl_rect.y+sdl_rect.h/3; 112 sdl_rect.w /= 3; 113 sdl_rect.h /= 3; 114 115 if (!rnvnd.no_draw && !rnvnd.not_visible) 116 { 117 SDL_Rect sdl_rect_dup = sdl_rect; 118 unDE_RenderFillRect(gs.renderer, &sdl_rect_dup, color); 119 } 120 } 121 122 /* EN: draw picture - interface element 123 RU: рисует картинку - элемент интерфейса */ 124 /* 125 package SDL_Rect 126 draw_interface_picture(GlobalState gs, 127 string path, 128 int x, int y, 129 double scale, 130 in ref SDL_Rect rect) 131 { 132 immutable int text_size = 1024; 133 134 x = x * rect.w/text_size; 135 y = y * rect.h/text_size; 136 137 auto st = get_image_from_cache(gs, path); 138 139 SDL_Rect dst; 140 if (st && st.texture) 141 { 142 dst.x = rect.x + x; 143 dst.y = rect.y + y; 144 dst.w = cast(int)(st.w*rect.w*scale/1024.0); 145 dst.h = cast(int)(st.h*rect.h*scale/1024.0); 146 147 int r = SDL_RenderCopyEx(gs.renderer, st.texture, null, &dst, 0, 148 null, SDL_FLIP_NONE); 149 if (r < 0) 150 { 151 writefln( "draw_interface_picture(%s): Error while render copy: %s", 152 path, SDL_GetError().to!string() ); 153 } 154 } 155 else 156 { 157 writefln("Can't load %s: %s", 158 path, 159 to!string(IMG_GetError())); 160 } 161 return dst; 162 } 163 */ 164 165 package SDL_Rect 166 draw_button(GlobalState gs, 167 int x, int y, 168 int w, int h, 169 in ref SDL_Rect rect) 170 { 171 immutable int text_size = 1024; 172 173 x = x * rect.w/text_size; 174 y = y * rect.h/text_size; 175 176 SDL_Rect dst; 177 dst.x = rect.x + x; 178 dst.y = rect.y + y; 179 dst.w = cast(int)(w*rect.w/1024.0); 180 dst.h = cast(int)(h*rect.h/1024.0); 181 182 unDE_RenderFillRect(gs.renderer, &dst, 0xFF000080); 183 184 return dst; 185 } 186 187 /* EN: draw file-picture 188 RU: рисует файл-картинку */ 189 package bool 190 draw_picture(GlobalState gs, 191 in ref SDL_Rect_With_Not_Visible_And_No_Draw rnvnd, 192 in string p, 193 in bool fast, 194 ref int ret) 195 { 196 Texture_Tick *st; 197 /* EN: Get picture from cache or load it from file 198 RU: Получить картинку из кеша или загрузить из файла */ 199 if ( !p.endsWith(".xcf") ) 200 { 201 with (gs.image_viewer) 202 { 203 st = p in image_cache; 204 if (st) 205 { 206 //writefln("Get from cache %s", p); 207 st.tick = SDL_GetTicks(); 208 last_image_cache_use = SDL_GetTicks(); 209 } 210 else if (!fast) 211 { 212 //writefln("Load image %s", p); 213 long tick1 = SDL_GetTicks(); 214 auto surface = IMG_Load(p.toStringz()); 215 long tick2 = SDL_GetTicks(); 216 //writefln("%.3f s", (cast(double)tick2-tick1)/1000); 217 if (surface) 218 { 219 auto image_texture = 220 SDL_CreateTextureFromSurface(gs.renderer, surface); 221 222 image_cache[p] = Texture_Tick(surface.w, surface.h, [], image_texture, SDL_GetTicks()); 223 SDL_FreeSurface(surface); 224 last_image_cache_use = SDL_GetTicks(); 225 st = p in image_cache; 226 //writefln("Add to cache %s", p); 227 } 228 229 if (tick2-tick1 > 100) 230 { 231 ret = -1; 232 } 233 } 234 } 235 } 236 237 if (st && st.texture) 238 { 239 SDL_Rect dst; 240 /* EN: Calculate output rectangle: 241 RU: Рассчитать выходной прямоугольник: */ 242 /* EN: If output square for path more than picture 243 RU: Если выходной квадрат для пути больше картинки */ 244 if (rnvnd.sdl_rect.w > st.w && rnvnd.sdl_rect.h > st.h) 245 { 246 /* EN: If square of path takes width less 512 247 RU: Если квадрат пути занимает по ширине меньше 512 */ 248 if (rnvnd.sdl_rect.w < 512) 249 { 250 /* EN: Draw picture at the centre without scaling 251 RU: Рисуем картинку по центру без увеличения */ 252 dst.x = rnvnd.sdl_rect.x + (rnvnd.sdl_rect.w-st.w)/2; 253 dst.y = rnvnd.sdl_rect.y + (rnvnd.sdl_rect.h-st.h)/2; 254 dst.w = st.w; 255 dst.h = st.h; 256 } 257 /* EN: If the picture less by width and height 512 258 RU: Если сама картинка меньше по высоте и ширине 512 */ 259 else if ( st.w < 512 && st.h < 512 ) 260 { 261 /* EN: Scale up and center picture 262 RU: Отцентрировать и увеличить картинку, учитывая 263 что при размере выходного квадрата <= 512 (см. выше) 264 она имеет масштаб 100% */ 265 dst.x = cast(int)(rnvnd.sdl_rect.x + 266 (rnvnd.sdl_rect.w-st.w*rnvnd.sdl_rect.w/512.0)/2); 267 dst.y = cast(int)(rnvnd.sdl_rect.y + 268 (rnvnd.sdl_rect.h-st.h*rnvnd.sdl_rect.w/512.0)/2); 269 dst.w = cast(int)(st.w*rnvnd.sdl_rect.w/512.0); 270 dst.h = cast(int)(st.h*rnvnd.sdl_rect.w/512.0); 271 } 272 else 273 { 274 goto other; 275 } 276 } 277 else 278 { 279 other: 280 if (st.w > st.h) 281 { 282 /* EN: Center and scale down picture to take all width 283 of path square 284 RU: Отцентрировать и уменьшить картинку так, чтобы 285 она заняла всю ширину квадрата */ 286 dst.x = rnvnd.sdl_rect.x; 287 dst.y = rnvnd.sdl_rect.y+ 288 (rnvnd.sdl_rect.h-rnvnd.sdl_rect.h*st.h/st.w)/2; 289 dst.w = rnvnd.sdl_rect.w; 290 dst.h = rnvnd.sdl_rect.h*st.h/st.w; 291 } 292 else 293 { 294 /* EN: Center and scale down picture to take all height 295 of path square 296 RU: Отцентрировать и уменьшить картинку так, чтобы 297 она заняла всю высоту квадрата */ 298 dst.x = rnvnd.sdl_rect.x+ 299 (rnvnd.sdl_rect.w-rnvnd.sdl_rect.w*st.w/st.h)/2; 300 dst.y = rnvnd.sdl_rect.y; 301 dst.w = rnvnd.sdl_rect.w*st.w/st.h; 302 dst.h = rnvnd.sdl_rect.h; 303 } 304 } 305 306 int r = SDL_RenderCopyEx(gs.renderer, st.texture, null, &dst, 0, 307 null, SDL_FLIP_NONE); 308 if (r < 0) 309 { 310 writefln( "draw_picture(%s): Error while render copy: %s", 311 p, SDL_GetError().to!string() ); 312 } 313 314 return true; 315 } 316 else 317 return false; 318 } 319 320 package SDL_Rect 321 draw_line(GlobalState gs, string text, 322 double x, double y, int size, const SDL_Rect rect) 323 { 324 if (text.length > 0 && text[$-1] == '\r') text = text[0..$-1]; 325 326 immutable int text_size = 1024; 327 328 x = x * rect.w/text_size; 329 y = y * rect.h/text_size; 330 331 int line_height = cast(int)(round(SQRT2^^size)*1.2); 332 auto tt = gs.text_viewer.font.get_line_from_cache(text, 333 size, 0, line_height, SDL_Color(255, 255, 255, 255)); 334 if (!tt && !tt.texture) 335 { 336 /*throw new Exception("Can't create text_surface: "~ 337 to!string(TTF_GetError()));*/ 338 return SDL_Rect(); 339 } 340 341 auto text_texture = tt.texture; 342 343 long line_ax = cast(long)(x + rect.x); 344 long line_ay = cast(long)(y + rect.y); 345 /*if (line_x == 0 && line_y == 0) 346 { 347 writefln("sdl_rect.x=%s, line_ax=%s\n", 348 rnvnd.sdl_rect.x, line_ax); 349 }*/ 350 351 SDL_Rect src; 352 src.x = 0; 353 src.y = 0; 354 src.w = (tt.w > 2*text_size) ? 355 2*text_size : 356 tt.w; 357 src.h = tt.h; 358 359 SDL_Rect dst; 360 dst.x = cast(int)line_ax; 361 dst.y = cast(int)line_ay; 362 dst.w = (tt.w > 2*text_size) ? 363 cast(int)(rect.w) : 364 cast(int)(tt.w*rect.w/text_size/2.0); 365 dst.h = 366 cast(int)(tt.h*rect.h/text_size/2.0); 367 /*writefln("%s - %s, %s, %s, %s", 368 line, dst.x, dst.y, dst.w, dst.h);*/ 369 370 int r = SDL_RenderCopyEx(gs.renderer, text_texture, null, &dst, 0, 371 null, SDL_FLIP_NONE); 372 if (r < 0) 373 { 374 writefln( "draw_line(%s): Error while render copy: %s", text, SDL_GetError().to!string() ); 375 } 376 377 return dst; 378 } 379 380 /* RU: Попытаться найти плохой UTF-8 символ в буфере */ 381 private void 382 try_find_bad_utf8_character(in ubyte[] buf, 383 out bool wrongSymbolFound, 384 out int reason) 385 { 386 int sizeofsymbol = 0; 387 388 foreach(b; buf) 389 { 390 if (sizeofsymbol > 0) 391 { 392 if ((b & 0b11000000) == 0b10000000) 393 { 394 sizeofsymbol--; 395 } 396 else 397 { 398 reason = 1; 399 wrongSymbolFound = true; 400 break; 401 } 402 } 403 else 404 { 405 if ((b & 0x10000000) == 0) 406 { 407 if (b < 32 && b != 0x0a && b != 0x0d && b != 0x09) 408 { 409 reason = 2; 410 wrongSymbolFound = true; 411 break; 412 } 413 } 414 else if ((b & 0b11100000) == 0b11000000) 415 { 416 sizeofsymbol = 1; 417 } 418 else if ((b & 0b11110000) == 0b11100000) 419 { 420 sizeofsymbol = 2; 421 } 422 else if ((b & 0b11111000) == 0b11110000) 423 { 424 sizeofsymbol = 3; 425 } 426 else if ((b & 0b11111100) == 0b11111000) 427 { 428 sizeofsymbol = 4; 429 } 430 else if ((b & 0b11111110) == 0b11111100) 431 { 432 sizeofsymbol = 5; 433 } 434 else 435 { 436 reason = 3; 437 wrongSymbolFound = true; 438 break; 439 } 440 } 441 } 442 } 443 444 445 package void 446 draw_text_file(GlobalState gs, 447 in ref SDL_Rect_With_Not_Visible_And_No_Draw rnvnd, 448 in string path, 449 ref int ret) 450 { 451 File file; 452 try { 453 file = File(path); 454 } 455 catch (Exception exp) 456 { 457 return; 458 } 459 460 ubyte[] buf; 461 bool wrongSymbolFound = false; 462 int reason = 0; 463 464 try { 465 buf = file.byChunk(4096).front(); 466 try_find_bad_utf8_character(buf, wrongSymbolFound, reason); 467 } 468 catch (ErrnoException) 469 { 470 reason = 4; 471 wrongSymbolFound = true; 472 } 473 474 /*if (path.endsWith(".brs")) 475 { 476 writefln("reason=%s, wrongSymbolFound=%s", reason, wrongSymbolFound); 477 }*/ 478 479 if (!wrongSymbolFound && !path.endsWith(".pdf") && !path.endsWith(".ps")) 480 { 481 try{ 482 file.seek(0); 483 long lines = 0; 484 foreach(line; file.byLine()) 485 { 486 double line_y = 18*lines; 487 double line_x = 0; 488 if (line_y+18 > 1024) 489 { 490 break; 491 } 492 493 if (line == "") 494 { 495 lines++; 496 continue; 497 } 498 499 draw_line(gs, line.idup(), line_x, line_y, 10, rnvnd.sdl_rect); 500 501 lines++; 502 } 503 504 //return; 505 } 506 catch(UTFException exc) 507 { 508 //return; 509 } 510 } 511 } 512 513 package void 514 draw_direntry_name(GlobalState gs, string name, 515 in ref SDL_Rect_With_Not_Visible_And_No_Draw rnvnd, 516 bool force=false) 517 { 518 try{ 519 if (name > "" && (!rnvnd.no_draw || force)) 520 { 521 int size = rnvnd.sdl_rect.w/16; 522 int f = cast(int)(floor(log2(size)*2)+2); 523 if (f < 5) return; 524 if (f > 14) f = 14; 525 526 //writefln("name=%s", name); 527 /* EN: Render text 528 RU: Рендерим текст */ 529 int line_height = cast(int)(round(SQRT2^^f)*1.2); 530 auto tt = gs.text_viewer.font.get_line_from_cache(name, 531 f, rnvnd.sdl_rect.w, line_height, SDL_Color(255, 255, 255, 255)); 532 if (!tt && !tt.texture) 533 { 534 throw new Exception("Can't create text_surface: "~ 535 to!string(TTF_GetError())); 536 } 537 538 auto ttb = gs.text_viewer.font.get_line_from_cache(name, 539 f, rnvnd.sdl_rect.w, line_height, SDL_Color(0, 0, 0, 255)); 540 if (!tt && !tt.texture) 541 { 542 throw new Exception("Can't create text_surface: "~ 543 to!string(TTF_GetError())); 544 } 545 546 auto text_texture = tt.texture; 547 auto text_texture_black = ttb.texture; 548 549 /* EN: Rerender if it's too wide 550 RU: Перерендериваем меньшим шрифтом, если 551 надпись слишком велика */ 552 /* 553 while ( text_surface.w > rnvnd.sdl_rect.w && f > 6 ) 554 { 555 f--; 556 SDL_FreeSurface(text_surface); 557 text_surface = TTF_RenderUTF8_Blended( 558 gs.text_viewer.font.font[0][f], name.toStringz(), 559 SDL_Color(255, 255, 255, 255)); 560 if (!text_surface) 561 { 562 throw new Exception("Can't create text_surface: "~ 563 to!string(TTF_GetError())); 564 } 565 }*/ 566 567 /* EN: calculate output coordinates 568 RU: расчитывает выходные координаты */ 569 SDL_Rect sdl_rect; 570 sdl_rect.x = cast(int)(rnvnd.sdl_rect.x + 571 (rnvnd.sdl_rect.w - tt.w)/2); 572 sdl_rect.y = cast(int)(rnvnd.sdl_rect.y + 573 (rnvnd.sdl_rect.h - tt.h)/2); 574 sdl_rect.w = tt.w+1; 575 sdl_rect.h = tt.h+1; 576 577 /* EN: Draw 578 RU: Рисуем */ 579 auto r = SDL_RenderCopyEx(gs.renderer, text_texture_black, null, &sdl_rect, 0, 580 null, SDL_FLIP_NONE); 581 if (r < 0) 582 { 583 writefln( "draw_direntry_name(): Error while render copy: %s", SDL_GetError().to!string() ); 584 } 585 586 sdl_rect.x -= 1; 587 sdl_rect.y -= 1; 588 589 r = SDL_RenderCopyEx(gs.renderer, text_texture, null, &sdl_rect, 0, 590 null, SDL_FLIP_NONE); 591 if (r < 0) 592 { 593 writefln( "draw_direntry_name(): Error while render copy: %s", SDL_GetError().to!string() ); 594 } 595 596 597 } 598 } catch (Exception e) 599 { 600 } 601 } 602