@@ -138,6 +138,9 @@ contains |
| 138 | 138 | call update_progress_cb(real(progress, c_double), trim(status_msg)) |
| 139 | 139 | end if |
| 140 | 140 | |
| 141 | + ! Decay flash intensities for all visible nodes |
| 142 | + call decay_flash_highlights() |
| 143 | + |
| 141 | 144 | ! Invalidate layout to force recalculation with new data |
| 142 | 145 | call invalidate_layout() |
| 143 | 146 | |
@@ -530,6 +533,18 @@ contains |
| 530 | 533 | print *, "Restoring sizes before navigation..." |
| 531 | 534 | call recalculate_sizes(root_node) |
| 532 | 535 | |
| 536 | + ! Check if the directory needs to be scanned (progressive scan didn't populate children) |
| 537 | + if (current_view_node%children(index)%num_children == 0 .and. & |
| 538 | + allocated(current_view_node%children(index)%path)) then |
| 539 | + ! This directory was created by progressive scan but never had children populated |
| 540 | + ! We need to scan it now |
| 541 | + print *, "Directory has no children - triggering rescan: ", & |
| 542 | + trim(current_view_node%children(index)%path) |
| 543 | + |
| 544 | + call scan_directory(trim(current_view_node%children(index)%path)) |
| 545 | + return ! scan_directory will set current_view_node appropriately |
| 546 | + end if |
| 547 | + |
| 533 | 548 | ! Navigate into the directory |
| 534 | 549 | current_view_node => current_view_node%children(index) |
| 535 | 550 | |
@@ -901,14 +916,14 @@ contains |
| 901 | 916 | w = real(node%bounds%width, c_double) |
| 902 | 917 | h = real(node%bounds%height, c_double) |
| 903 | 918 | |
| 904 | | - ! Draw semi-transparent white overlay (40% opacity) |
| 905 | | - call cairo_set_source_rgba(cr, 1.0d0, 1.0d0, 1.0d0, 0.4d0) |
| 919 | + ! Draw semi-transparent yellow overlay (30% opacity) - closer to selection color |
| 920 | + call cairo_set_source_rgba(cr, 1.0d0, 0.9d0, 0.3d0, 0.3d0) |
| 906 | 921 | call cairo_rectangle(cr, x, y, w, h) |
| 907 | 922 | call cairo_fill(cr) |
| 908 | 923 | |
| 909 | | - ! Draw thicker highlight border |
| 910 | | - call cairo_set_source_rgb(cr, 1.0d0, 1.0d0, 1.0d0) |
| 911 | | - call cairo_set_line_width(cr, 3.0d0) |
| 924 | + ! Draw thicker yellow highlight border |
| 925 | + call cairo_set_source_rgb(cr, 1.0d0, 0.9d0, 0.2d0) |
| 926 | + call cairo_set_line_width(cr, 2.5d0) |
| 912 | 927 | call cairo_rectangle(cr, x, y, w, h) |
| 913 | 928 | call cairo_stroke(cr) |
| 914 | 929 | end subroutine render_hover_highlight |
@@ -937,6 +952,35 @@ contains |
| 937 | 952 | call cairo_stroke(cr) |
| 938 | 953 | end subroutine render_selection_highlight |
| 939 | 954 | |
| 955 | + ! Render flash highlight overlay (for actively resizing items during scan) |
| 956 | + subroutine render_flash_highlight(cr, node) |
| 957 | + type(c_ptr), intent(in) :: cr |
| 958 | + type(file_node), intent(in) :: node |
| 959 | + real(c_double) :: x, y, w, h |
| 960 | + real(c_double) :: intensity |
| 961 | + |
| 962 | + ! Skip if flash intensity is too low |
| 963 | + if (node%flash_intensity < 0.05d0) return |
| 964 | + |
| 965 | + x = real(node%bounds%x, c_double) |
| 966 | + y = real(node%bounds%y, c_double) |
| 967 | + w = real(node%bounds%width, c_double) |
| 968 | + h = real(node%bounds%height, c_double) |
| 969 | + intensity = real(node%flash_intensity, c_double) |
| 970 | + |
| 971 | + ! Draw bright cyan/white flash overlay (intensity-based opacity) |
| 972 | + ! Cyan gives that "electric" SpaceSniffer feel |
| 973 | + call cairo_set_source_rgba(cr, 0.3d0, 1.0d0, 1.0d0, intensity * 0.6d0) |
| 974 | + call cairo_rectangle(cr, x, y, w, h) |
| 975 | + call cairo_fill(cr) |
| 976 | + |
| 977 | + ! Draw bright flash border |
| 978 | + call cairo_set_source_rgba(cr, 0.5d0, 1.0d0, 1.0d0, intensity * 0.9d0) |
| 979 | + call cairo_set_line_width(cr, 2.0d0) |
| 980 | + call cairo_rectangle(cr, x, y, w, h) |
| 981 | + call cairo_stroke(cr) |
| 982 | + end subroutine render_flash_highlight |
| 983 | + |
| 940 | 984 | ! Get file extension from filename |
| 941 | 985 | function get_file_extension(filename) result(ext) |
| 942 | 986 | character(len=*), intent(in) :: filename |
@@ -1304,6 +1348,11 @@ contains |
| 1304 | 1348 | call cairo_rectangle(cr, x, y, w, h) |
| 1305 | 1349 | call cairo_stroke(cr) |
| 1306 | 1350 | |
| 1351 | + ! Render flash highlight if node is actively being updated |
| 1352 | + if (node%flash_intensity > 0.05d0) then |
| 1353 | + call render_flash_highlight(cr, node) |
| 1354 | + end if |
| 1355 | + |
| 1307 | 1356 | ! Render text label if rectangle is large enough |
| 1308 | 1357 | if (can_show_label) then |
| 1309 | 1358 | call render_label(cr, node, x, y, w, h) |
@@ -1483,6 +1532,51 @@ contains |
| 1483 | 1532 | print *, "Directory cache cleared and deallocated" |
| 1484 | 1533 | end subroutine clear_cache |
| 1485 | 1534 | |
| 1535 | + ! Decay flash highlights for all visible nodes |
| 1536 | + subroutine decay_flash_highlights() |
| 1537 | + use iso_fortran_env, only: int64, real64 |
| 1538 | + integer :: i |
| 1539 | + integer(int64) :: current_time, elapsed_ms |
| 1540 | + real(real64) :: decay_rate |
| 1541 | + |
| 1542 | + if (.not. allocated(root_node%children)) return |
| 1543 | + |
| 1544 | + ! Get current time |
| 1545 | + current_time = get_current_time_ms() |
| 1546 | + |
| 1547 | + ! Decay rate: flash fades out over ~200ms |
| 1548 | + decay_rate = 0.15d0 ! Decay by 15% per update |
| 1549 | + |
| 1550 | + ! Decay flash intensity for all root children |
| 1551 | + do i = 1, root_node%num_children |
| 1552 | + if (root_node%children(i)%flash_intensity > 0.01d0) then |
| 1553 | + ! Calculate time-based decay |
| 1554 | + elapsed_ms = current_time - root_node%children(i)%last_update_time |
| 1555 | + |
| 1556 | + ! If it's been more than 50ms since last update, start decaying |
| 1557 | + if (elapsed_ms > 50_int64) then |
| 1558 | + root_node%children(i)%flash_intensity = & |
| 1559 | + root_node%children(i)%flash_intensity * (1.0d0 - decay_rate) |
| 1560 | + |
| 1561 | + ! Clamp to zero when very small |
| 1562 | + if (root_node%children(i)%flash_intensity < 0.01d0) then |
| 1563 | + root_node%children(i)%flash_intensity = 0.0d0 |
| 1564 | + end if |
| 1565 | + end if |
| 1566 | + end if |
| 1567 | + end do |
| 1568 | + end subroutine decay_flash_highlights |
| 1569 | + |
| 1570 | + ! Get current time in milliseconds (wrapper for progressive_scanner function) |
| 1571 | + function get_current_time_ms() result(time_ms) |
| 1572 | + use iso_fortran_env, only: int64 |
| 1573 | + integer(int64) :: time_ms |
| 1574 | + integer :: count, count_rate, count_max |
| 1575 | + |
| 1576 | + call system_clock(count, count_rate, count_max) |
| 1577 | + time_ms = int(count * 1000_int64 / count_rate, int64) |
| 1578 | + end function get_current_time_ms |
| 1579 | + |
| 1486 | 1580 | ! Recursively deallocate a file tree |
| 1487 | 1581 | recursive subroutine deallocate_tree(node) |
| 1488 | 1582 | type(file_node), intent(inout) :: node |