├── .gitattributes ├── .github ├── dependabot.yml └── workflows │ ├── check.yml │ ├── release.yml │ └── test.yml ├── .gitignore ├── CHANGELOG.md ├── Cargo.lock ├── Cargo.toml ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── examples └── demo.rs └── src └── lib.rs /.gitattributes: -------------------------------------------------------------------------------- 1 | *.gif filter=lfs diff=lfs merge=lfs -text 2 | *.png filter=lfs diff=lfs merge=lfs -text 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: "weekly" 12 | - package-ecosystem: "cargo" # See documentation for possible values 13 | directory: "/" # Location of package manifests 14 | schedule: 15 | interval: "weekly" 16 | -------------------------------------------------------------------------------- /.github/workflows/check.yml: -------------------------------------------------------------------------------- 1 | name: Check 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | jobs: 9 | check: 10 | permissions: 11 | checks: write 12 | uses: joshka/github-workflows/.github/workflows/rust-check.yml@main 13 | with: 14 | msrv: 1.80.0 15 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | # see https://release-plz.ieni.dev/docs/github for more information 2 | 3 | name: Release 4 | 5 | permissions: 6 | pull-requests: write 7 | contents: write 8 | 9 | on: 10 | push: 11 | branches: 12 | - main 13 | workflow_dispatch: 14 | 15 | jobs: 16 | release-plz: 17 | name: Release-plz 18 | runs-on: ubuntu-latest 19 | steps: 20 | - uses: actions/checkout@v4 21 | with: 22 | fetch-depth: 0 23 | - uses: dtolnay/rust-toolchain@stable 24 | - uses: MarcoIeni/release-plz-action@v0.5 25 | env: 26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 27 | CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }} 28 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | 9 | jobs: 10 | test: 11 | uses: joshka/github-workflows/.github/workflows/rust-test.yml@main 12 | secrets: 13 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [0.1.2](https://github.com/joshka/tui-equalizer/compare/v0.1.1...v0.1.2) - 2025-02-11 11 | 12 | ### Other 13 | 14 | - add clone trait to equalizer ([#2](https://github.com/joshka/tui-equalizer/pull/2)) 15 | 16 | ## [0.1.1](https://github.com/joshka/tui-equalizer/compare/v0.1.0...v0.1.1) - 2025-02-11 17 | 18 | ### Other 19 | 20 | - fix examples 21 | - add repo and docs link 22 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.21.0" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler" 16 | version = "1.0.2" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" 19 | 20 | [[package]] 21 | name = "allocator-api2" 22 | version = "0.2.21" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" 25 | 26 | [[package]] 27 | name = "autocfg" 28 | version = "1.4.0" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 31 | 32 | [[package]] 33 | name = "backtrace" 34 | version = "0.3.71" 35 | source = "registry+https://github.com/rust-lang/crates.io-index" 36 | checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" 37 | dependencies = [ 38 | "addr2line", 39 | "cc", 40 | "cfg-if", 41 | "libc", 42 | "miniz_oxide", 43 | "object", 44 | "rustc-demangle", 45 | ] 46 | 47 | [[package]] 48 | name = "bitflags" 49 | version = "2.8.0" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "8f68f53c83ab957f72c32642f3868eec03eb974d1fb82e453128456482613d36" 52 | 53 | [[package]] 54 | name = "byteorder" 55 | version = "1.5.0" 56 | source = "registry+https://github.com/rust-lang/crates.io-index" 57 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 58 | 59 | [[package]] 60 | name = "cassowary" 61 | version = "0.3.0" 62 | source = "registry+https://github.com/rust-lang/crates.io-index" 63 | checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" 64 | 65 | [[package]] 66 | name = "castaway" 67 | version = "0.2.3" 68 | source = "registry+https://github.com/rust-lang/crates.io-index" 69 | checksum = "0abae9be0aaf9ea96a3b1b8b1b55c602ca751eba1b1500220cea4ecbafe7c0d5" 70 | dependencies = [ 71 | "rustversion", 72 | ] 73 | 74 | [[package]] 75 | name = "cc" 76 | version = "1.2.13" 77 | source = "registry+https://github.com/rust-lang/crates.io-index" 78 | checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda" 79 | dependencies = [ 80 | "shlex", 81 | ] 82 | 83 | [[package]] 84 | name = "cfg-if" 85 | version = "1.0.0" 86 | source = "registry+https://github.com/rust-lang/crates.io-index" 87 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 88 | 89 | [[package]] 90 | name = "color-eyre" 91 | version = "0.6.3" 92 | source = "registry+https://github.com/rust-lang/crates.io-index" 93 | checksum = "55146f5e46f237f7423d74111267d4597b59b0dad0ffaf7303bce9945d843ad5" 94 | dependencies = [ 95 | "backtrace", 96 | "color-spantrace", 97 | "eyre", 98 | "indenter", 99 | "once_cell", 100 | "owo-colors", 101 | "tracing-error", 102 | ] 103 | 104 | [[package]] 105 | name = "color-spantrace" 106 | version = "0.2.1" 107 | source = "registry+https://github.com/rust-lang/crates.io-index" 108 | checksum = "cd6be1b2a7e382e2b98b43b2adcca6bb0e465af0bdd38123873ae61eb17a72c2" 109 | dependencies = [ 110 | "once_cell", 111 | "owo-colors", 112 | "tracing-core", 113 | "tracing-error", 114 | ] 115 | 116 | [[package]] 117 | name = "compact_str" 118 | version = "0.8.1" 119 | source = "registry+https://github.com/rust-lang/crates.io-index" 120 | checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32" 121 | dependencies = [ 122 | "castaway", 123 | "cfg-if", 124 | "itoa", 125 | "rustversion", 126 | "ryu", 127 | "static_assertions", 128 | ] 129 | 130 | [[package]] 131 | name = "crossterm" 132 | version = "0.28.1" 133 | source = "registry+https://github.com/rust-lang/crates.io-index" 134 | checksum = "829d955a0bb380ef178a640b91779e3987da38c9aea133b20614cfed8cdea9c6" 135 | dependencies = [ 136 | "bitflags", 137 | "crossterm_winapi", 138 | "mio", 139 | "parking_lot", 140 | "rustix", 141 | "signal-hook", 142 | "signal-hook-mio", 143 | "winapi", 144 | ] 145 | 146 | [[package]] 147 | name = "crossterm_winapi" 148 | version = "0.9.1" 149 | source = "registry+https://github.com/rust-lang/crates.io-index" 150 | checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" 151 | dependencies = [ 152 | "winapi", 153 | ] 154 | 155 | [[package]] 156 | name = "darling" 157 | version = "0.20.10" 158 | source = "registry+https://github.com/rust-lang/crates.io-index" 159 | checksum = "6f63b86c8a8826a49b8c21f08a2d07338eec8d900540f8630dc76284be802989" 160 | dependencies = [ 161 | "darling_core", 162 | "darling_macro", 163 | ] 164 | 165 | [[package]] 166 | name = "darling_core" 167 | version = "0.20.10" 168 | source = "registry+https://github.com/rust-lang/crates.io-index" 169 | checksum = "95133861a8032aaea082871032f5815eb9e98cef03fa916ab4500513994df9e5" 170 | dependencies = [ 171 | "fnv", 172 | "ident_case", 173 | "proc-macro2", 174 | "quote", 175 | "strsim", 176 | "syn", 177 | ] 178 | 179 | [[package]] 180 | name = "darling_macro" 181 | version = "0.20.10" 182 | source = "registry+https://github.com/rust-lang/crates.io-index" 183 | checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" 184 | dependencies = [ 185 | "darling_core", 186 | "quote", 187 | "syn", 188 | ] 189 | 190 | [[package]] 191 | name = "derive_builder" 192 | version = "0.20.2" 193 | source = "registry+https://github.com/rust-lang/crates.io-index" 194 | checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" 195 | dependencies = [ 196 | "derive_builder_macro", 197 | ] 198 | 199 | [[package]] 200 | name = "derive_builder_core" 201 | version = "0.20.2" 202 | source = "registry+https://github.com/rust-lang/crates.io-index" 203 | checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" 204 | dependencies = [ 205 | "darling", 206 | "proc-macro2", 207 | "quote", 208 | "syn", 209 | ] 210 | 211 | [[package]] 212 | name = "derive_builder_macro" 213 | version = "0.20.2" 214 | source = "registry+https://github.com/rust-lang/crates.io-index" 215 | checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" 216 | dependencies = [ 217 | "derive_builder_core", 218 | "syn", 219 | ] 220 | 221 | [[package]] 222 | name = "either" 223 | version = "1.13.0" 224 | source = "registry+https://github.com/rust-lang/crates.io-index" 225 | checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" 226 | 227 | [[package]] 228 | name = "equivalent" 229 | version = "1.0.1" 230 | source = "registry+https://github.com/rust-lang/crates.io-index" 231 | checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" 232 | 233 | [[package]] 234 | name = "errno" 235 | version = "0.3.10" 236 | source = "registry+https://github.com/rust-lang/crates.io-index" 237 | checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" 238 | dependencies = [ 239 | "libc", 240 | "windows-sys 0.59.0", 241 | ] 242 | 243 | [[package]] 244 | name = "eyre" 245 | version = "0.6.12" 246 | source = "registry+https://github.com/rust-lang/crates.io-index" 247 | checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" 248 | dependencies = [ 249 | "indenter", 250 | "once_cell", 251 | ] 252 | 253 | [[package]] 254 | name = "fnv" 255 | version = "1.0.7" 256 | source = "registry+https://github.com/rust-lang/crates.io-index" 257 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 258 | 259 | [[package]] 260 | name = "foldhash" 261 | version = "0.1.4" 262 | source = "registry+https://github.com/rust-lang/crates.io-index" 263 | checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" 264 | 265 | [[package]] 266 | name = "getrandom" 267 | version = "0.3.1" 268 | source = "registry+https://github.com/rust-lang/crates.io-index" 269 | checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" 270 | dependencies = [ 271 | "cfg-if", 272 | "libc", 273 | "wasi 0.13.3+wasi-0.2.2", 274 | "windows-targets", 275 | ] 276 | 277 | [[package]] 278 | name = "gimli" 279 | version = "0.28.1" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" 282 | 283 | [[package]] 284 | name = "hashbrown" 285 | version = "0.15.2" 286 | source = "registry+https://github.com/rust-lang/crates.io-index" 287 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 288 | dependencies = [ 289 | "allocator-api2", 290 | "equivalent", 291 | "foldhash", 292 | ] 293 | 294 | [[package]] 295 | name = "heck" 296 | version = "0.5.0" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" 299 | 300 | [[package]] 301 | name = "ident_case" 302 | version = "1.0.1" 303 | source = "registry+https://github.com/rust-lang/crates.io-index" 304 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 305 | 306 | [[package]] 307 | name = "indenter" 308 | version = "0.3.3" 309 | source = "registry+https://github.com/rust-lang/crates.io-index" 310 | checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" 311 | 312 | [[package]] 313 | name = "indoc" 314 | version = "2.0.5" 315 | source = "registry+https://github.com/rust-lang/crates.io-index" 316 | checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" 317 | 318 | [[package]] 319 | name = "instability" 320 | version = "0.3.7" 321 | source = "registry+https://github.com/rust-lang/crates.io-index" 322 | checksum = "0bf9fed6d91cfb734e7476a06bde8300a1b94e217e1b523b6f0cd1a01998c71d" 323 | dependencies = [ 324 | "darling", 325 | "indoc", 326 | "proc-macro2", 327 | "quote", 328 | "syn", 329 | ] 330 | 331 | [[package]] 332 | name = "itertools" 333 | version = "0.13.0" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" 336 | dependencies = [ 337 | "either", 338 | ] 339 | 340 | [[package]] 341 | name = "itertools" 342 | version = "0.14.0" 343 | source = "registry+https://github.com/rust-lang/crates.io-index" 344 | checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" 345 | dependencies = [ 346 | "either", 347 | ] 348 | 349 | [[package]] 350 | name = "itoa" 351 | version = "1.0.14" 352 | source = "registry+https://github.com/rust-lang/crates.io-index" 353 | checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" 354 | 355 | [[package]] 356 | name = "lazy_static" 357 | version = "1.5.0" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 360 | 361 | [[package]] 362 | name = "libc" 363 | version = "0.2.169" 364 | source = "registry+https://github.com/rust-lang/crates.io-index" 365 | checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" 366 | 367 | [[package]] 368 | name = "linux-raw-sys" 369 | version = "0.4.15" 370 | source = "registry+https://github.com/rust-lang/crates.io-index" 371 | checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" 372 | 373 | [[package]] 374 | name = "lock_api" 375 | version = "0.4.12" 376 | source = "registry+https://github.com/rust-lang/crates.io-index" 377 | checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" 378 | dependencies = [ 379 | "autocfg", 380 | "scopeguard", 381 | ] 382 | 383 | [[package]] 384 | name = "log" 385 | version = "0.4.25" 386 | source = "registry+https://github.com/rust-lang/crates.io-index" 387 | checksum = "04cbf5b083de1c7e0222a7a51dbfdba1cbe1c6ab0b15e29fff3f6c077fd9cd9f" 388 | 389 | [[package]] 390 | name = "lru" 391 | version = "0.12.5" 392 | source = "registry+https://github.com/rust-lang/crates.io-index" 393 | checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" 394 | dependencies = [ 395 | "hashbrown", 396 | ] 397 | 398 | [[package]] 399 | name = "memchr" 400 | version = "2.7.4" 401 | source = "registry+https://github.com/rust-lang/crates.io-index" 402 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 403 | 404 | [[package]] 405 | name = "miniz_oxide" 406 | version = "0.7.4" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" 409 | dependencies = [ 410 | "adler", 411 | ] 412 | 413 | [[package]] 414 | name = "mio" 415 | version = "1.0.3" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 418 | dependencies = [ 419 | "libc", 420 | "log", 421 | "wasi 0.11.0+wasi-snapshot-preview1", 422 | "windows-sys 0.52.0", 423 | ] 424 | 425 | [[package]] 426 | name = "object" 427 | version = "0.32.2" 428 | source = "registry+https://github.com/rust-lang/crates.io-index" 429 | checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" 430 | dependencies = [ 431 | "memchr", 432 | ] 433 | 434 | [[package]] 435 | name = "once_cell" 436 | version = "1.20.3" 437 | source = "registry+https://github.com/rust-lang/crates.io-index" 438 | checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" 439 | 440 | [[package]] 441 | name = "owo-colors" 442 | version = "3.5.0" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "c1b04fb49957986fdce4d6ee7a65027d55d4b6d2265e5848bbb507b58ccfdb6f" 445 | 446 | [[package]] 447 | name = "parking_lot" 448 | version = "0.12.3" 449 | source = "registry+https://github.com/rust-lang/crates.io-index" 450 | checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" 451 | dependencies = [ 452 | "lock_api", 453 | "parking_lot_core", 454 | ] 455 | 456 | [[package]] 457 | name = "parking_lot_core" 458 | version = "0.9.10" 459 | source = "registry+https://github.com/rust-lang/crates.io-index" 460 | checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" 461 | dependencies = [ 462 | "cfg-if", 463 | "libc", 464 | "redox_syscall", 465 | "smallvec", 466 | "windows-targets", 467 | ] 468 | 469 | [[package]] 470 | name = "paste" 471 | version = "1.0.15" 472 | source = "registry+https://github.com/rust-lang/crates.io-index" 473 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 474 | 475 | [[package]] 476 | name = "pin-project-lite" 477 | version = "0.2.16" 478 | source = "registry+https://github.com/rust-lang/crates.io-index" 479 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 480 | 481 | [[package]] 482 | name = "ppv-lite86" 483 | version = "0.2.20" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" 486 | dependencies = [ 487 | "zerocopy 0.7.35", 488 | ] 489 | 490 | [[package]] 491 | name = "proc-macro2" 492 | version = "1.0.93" 493 | source = "registry+https://github.com/rust-lang/crates.io-index" 494 | checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99" 495 | dependencies = [ 496 | "unicode-ident", 497 | ] 498 | 499 | [[package]] 500 | name = "quote" 501 | version = "1.0.38" 502 | source = "registry+https://github.com/rust-lang/crates.io-index" 503 | checksum = "0e4dccaaaf89514f546c693ddc140f729f958c247918a13380cccc6078391acc" 504 | dependencies = [ 505 | "proc-macro2", 506 | ] 507 | 508 | [[package]] 509 | name = "rand" 510 | version = "0.9.1" 511 | source = "registry+https://github.com/rust-lang/crates.io-index" 512 | checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" 513 | dependencies = [ 514 | "rand_chacha", 515 | "rand_core", 516 | ] 517 | 518 | [[package]] 519 | name = "rand_chacha" 520 | version = "0.9.0" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 523 | dependencies = [ 524 | "ppv-lite86", 525 | "rand_core", 526 | ] 527 | 528 | [[package]] 529 | name = "rand_core" 530 | version = "0.9.0" 531 | source = "registry+https://github.com/rust-lang/crates.io-index" 532 | checksum = "b08f3c9802962f7e1b25113931d94f43ed9725bebc59db9d0c3e9a23b67e15ff" 533 | dependencies = [ 534 | "getrandom", 535 | "zerocopy 0.8.17", 536 | ] 537 | 538 | [[package]] 539 | name = "ratatui" 540 | version = "0.29.0" 541 | source = "registry+https://github.com/rust-lang/crates.io-index" 542 | checksum = "eabd94c2f37801c20583fc49dd5cd6b0ba68c716787c2dd6ed18571e1e63117b" 543 | dependencies = [ 544 | "bitflags", 545 | "cassowary", 546 | "compact_str", 547 | "crossterm", 548 | "indoc", 549 | "instability", 550 | "itertools 0.13.0", 551 | "lru", 552 | "paste", 553 | "strum", 554 | "unicode-segmentation", 555 | "unicode-truncate", 556 | "unicode-width 0.2.0", 557 | ] 558 | 559 | [[package]] 560 | name = "redox_syscall" 561 | version = "0.5.8" 562 | source = "registry+https://github.com/rust-lang/crates.io-index" 563 | checksum = "03a862b389f93e68874fbf580b9de08dd02facb9a788ebadaf4a3fd33cf58834" 564 | dependencies = [ 565 | "bitflags", 566 | ] 567 | 568 | [[package]] 569 | name = "rustc-demangle" 570 | version = "0.1.24" 571 | source = "registry+https://github.com/rust-lang/crates.io-index" 572 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 573 | 574 | [[package]] 575 | name = "rustix" 576 | version = "0.38.44" 577 | source = "registry+https://github.com/rust-lang/crates.io-index" 578 | checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" 579 | dependencies = [ 580 | "bitflags", 581 | "errno", 582 | "libc", 583 | "linux-raw-sys", 584 | "windows-sys 0.59.0", 585 | ] 586 | 587 | [[package]] 588 | name = "rustversion" 589 | version = "1.0.19" 590 | source = "registry+https://github.com/rust-lang/crates.io-index" 591 | checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" 592 | 593 | [[package]] 594 | name = "ryu" 595 | version = "1.0.19" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" 598 | 599 | [[package]] 600 | name = "scopeguard" 601 | version = "1.2.0" 602 | source = "registry+https://github.com/rust-lang/crates.io-index" 603 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 604 | 605 | [[package]] 606 | name = "sharded-slab" 607 | version = "0.1.7" 608 | source = "registry+https://github.com/rust-lang/crates.io-index" 609 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 610 | dependencies = [ 611 | "lazy_static", 612 | ] 613 | 614 | [[package]] 615 | name = "shlex" 616 | version = "1.3.0" 617 | source = "registry+https://github.com/rust-lang/crates.io-index" 618 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 619 | 620 | [[package]] 621 | name = "signal-hook" 622 | version = "0.3.17" 623 | source = "registry+https://github.com/rust-lang/crates.io-index" 624 | checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" 625 | dependencies = [ 626 | "libc", 627 | "signal-hook-registry", 628 | ] 629 | 630 | [[package]] 631 | name = "signal-hook-mio" 632 | version = "0.2.4" 633 | source = "registry+https://github.com/rust-lang/crates.io-index" 634 | checksum = "34db1a06d485c9142248b7a054f034b349b212551f3dfd19c94d45a754a217cd" 635 | dependencies = [ 636 | "libc", 637 | "mio", 638 | "signal-hook", 639 | ] 640 | 641 | [[package]] 642 | name = "signal-hook-registry" 643 | version = "1.4.2" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" 646 | dependencies = [ 647 | "libc", 648 | ] 649 | 650 | [[package]] 651 | name = "smallvec" 652 | version = "1.13.2" 653 | source = "registry+https://github.com/rust-lang/crates.io-index" 654 | checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" 655 | 656 | [[package]] 657 | name = "static_assertions" 658 | version = "1.1.0" 659 | source = "registry+https://github.com/rust-lang/crates.io-index" 660 | checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" 661 | 662 | [[package]] 663 | name = "strsim" 664 | version = "0.11.1" 665 | source = "registry+https://github.com/rust-lang/crates.io-index" 666 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 667 | 668 | [[package]] 669 | name = "strum" 670 | version = "0.26.3" 671 | source = "registry+https://github.com/rust-lang/crates.io-index" 672 | checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" 673 | dependencies = [ 674 | "strum_macros", 675 | ] 676 | 677 | [[package]] 678 | name = "strum_macros" 679 | version = "0.26.4" 680 | source = "registry+https://github.com/rust-lang/crates.io-index" 681 | checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" 682 | dependencies = [ 683 | "heck", 684 | "proc-macro2", 685 | "quote", 686 | "rustversion", 687 | "syn", 688 | ] 689 | 690 | [[package]] 691 | name = "syn" 692 | version = "2.0.98" 693 | source = "registry+https://github.com/rust-lang/crates.io-index" 694 | checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1" 695 | dependencies = [ 696 | "proc-macro2", 697 | "quote", 698 | "unicode-ident", 699 | ] 700 | 701 | [[package]] 702 | name = "thread_local" 703 | version = "1.1.8" 704 | source = "registry+https://github.com/rust-lang/crates.io-index" 705 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 706 | dependencies = [ 707 | "cfg-if", 708 | "once_cell", 709 | ] 710 | 711 | [[package]] 712 | name = "tracing" 713 | version = "0.1.41" 714 | source = "registry+https://github.com/rust-lang/crates.io-index" 715 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 716 | dependencies = [ 717 | "pin-project-lite", 718 | "tracing-core", 719 | ] 720 | 721 | [[package]] 722 | name = "tracing-core" 723 | version = "0.1.33" 724 | source = "registry+https://github.com/rust-lang/crates.io-index" 725 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 726 | dependencies = [ 727 | "once_cell", 728 | "valuable", 729 | ] 730 | 731 | [[package]] 732 | name = "tracing-error" 733 | version = "0.2.1" 734 | source = "registry+https://github.com/rust-lang/crates.io-index" 735 | checksum = "8b1581020d7a273442f5b45074a6a57d5757ad0a47dac0e9f0bd57b81936f3db" 736 | dependencies = [ 737 | "tracing", 738 | "tracing-subscriber", 739 | ] 740 | 741 | [[package]] 742 | name = "tracing-subscriber" 743 | version = "0.3.19" 744 | source = "registry+https://github.com/rust-lang/crates.io-index" 745 | checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" 746 | dependencies = [ 747 | "sharded-slab", 748 | "thread_local", 749 | "tracing-core", 750 | ] 751 | 752 | [[package]] 753 | name = "tui-equalizer" 754 | version = "0.1.2" 755 | dependencies = [ 756 | "color-eyre", 757 | "crossterm", 758 | "derive_builder", 759 | "itertools 0.14.0", 760 | "rand", 761 | "ratatui", 762 | ] 763 | 764 | [[package]] 765 | name = "unicode-ident" 766 | version = "1.0.16" 767 | source = "registry+https://github.com/rust-lang/crates.io-index" 768 | checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" 769 | 770 | [[package]] 771 | name = "unicode-segmentation" 772 | version = "1.12.0" 773 | source = "registry+https://github.com/rust-lang/crates.io-index" 774 | checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" 775 | 776 | [[package]] 777 | name = "unicode-truncate" 778 | version = "1.1.0" 779 | source = "registry+https://github.com/rust-lang/crates.io-index" 780 | checksum = "b3644627a5af5fa321c95b9b235a72fd24cd29c648c2c379431e6628655627bf" 781 | dependencies = [ 782 | "itertools 0.13.0", 783 | "unicode-segmentation", 784 | "unicode-width 0.1.14", 785 | ] 786 | 787 | [[package]] 788 | name = "unicode-width" 789 | version = "0.1.14" 790 | source = "registry+https://github.com/rust-lang/crates.io-index" 791 | checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" 792 | 793 | [[package]] 794 | name = "unicode-width" 795 | version = "0.2.0" 796 | source = "registry+https://github.com/rust-lang/crates.io-index" 797 | checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" 798 | 799 | [[package]] 800 | name = "valuable" 801 | version = "0.1.1" 802 | source = "registry+https://github.com/rust-lang/crates.io-index" 803 | checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" 804 | 805 | [[package]] 806 | name = "wasi" 807 | version = "0.11.0+wasi-snapshot-preview1" 808 | source = "registry+https://github.com/rust-lang/crates.io-index" 809 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 810 | 811 | [[package]] 812 | name = "wasi" 813 | version = "0.13.3+wasi-0.2.2" 814 | source = "registry+https://github.com/rust-lang/crates.io-index" 815 | checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" 816 | dependencies = [ 817 | "wit-bindgen-rt", 818 | ] 819 | 820 | [[package]] 821 | name = "winapi" 822 | version = "0.3.9" 823 | source = "registry+https://github.com/rust-lang/crates.io-index" 824 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 825 | dependencies = [ 826 | "winapi-i686-pc-windows-gnu", 827 | "winapi-x86_64-pc-windows-gnu", 828 | ] 829 | 830 | [[package]] 831 | name = "winapi-i686-pc-windows-gnu" 832 | version = "0.4.0" 833 | source = "registry+https://github.com/rust-lang/crates.io-index" 834 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 835 | 836 | [[package]] 837 | name = "winapi-x86_64-pc-windows-gnu" 838 | version = "0.4.0" 839 | source = "registry+https://github.com/rust-lang/crates.io-index" 840 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 841 | 842 | [[package]] 843 | name = "windows-sys" 844 | version = "0.52.0" 845 | source = "registry+https://github.com/rust-lang/crates.io-index" 846 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 847 | dependencies = [ 848 | "windows-targets", 849 | ] 850 | 851 | [[package]] 852 | name = "windows-sys" 853 | version = "0.59.0" 854 | source = "registry+https://github.com/rust-lang/crates.io-index" 855 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 856 | dependencies = [ 857 | "windows-targets", 858 | ] 859 | 860 | [[package]] 861 | name = "windows-targets" 862 | version = "0.52.6" 863 | source = "registry+https://github.com/rust-lang/crates.io-index" 864 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 865 | dependencies = [ 866 | "windows_aarch64_gnullvm", 867 | "windows_aarch64_msvc", 868 | "windows_i686_gnu", 869 | "windows_i686_gnullvm", 870 | "windows_i686_msvc", 871 | "windows_x86_64_gnu", 872 | "windows_x86_64_gnullvm", 873 | "windows_x86_64_msvc", 874 | ] 875 | 876 | [[package]] 877 | name = "windows_aarch64_gnullvm" 878 | version = "0.52.6" 879 | source = "registry+https://github.com/rust-lang/crates.io-index" 880 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 881 | 882 | [[package]] 883 | name = "windows_aarch64_msvc" 884 | version = "0.52.6" 885 | source = "registry+https://github.com/rust-lang/crates.io-index" 886 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 887 | 888 | [[package]] 889 | name = "windows_i686_gnu" 890 | version = "0.52.6" 891 | source = "registry+https://github.com/rust-lang/crates.io-index" 892 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 893 | 894 | [[package]] 895 | name = "windows_i686_gnullvm" 896 | version = "0.52.6" 897 | source = "registry+https://github.com/rust-lang/crates.io-index" 898 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 899 | 900 | [[package]] 901 | name = "windows_i686_msvc" 902 | version = "0.52.6" 903 | source = "registry+https://github.com/rust-lang/crates.io-index" 904 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 905 | 906 | [[package]] 907 | name = "windows_x86_64_gnu" 908 | version = "0.52.6" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 911 | 912 | [[package]] 913 | name = "windows_x86_64_gnullvm" 914 | version = "0.52.6" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 917 | 918 | [[package]] 919 | name = "windows_x86_64_msvc" 920 | version = "0.52.6" 921 | source = "registry+https://github.com/rust-lang/crates.io-index" 922 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 923 | 924 | [[package]] 925 | name = "wit-bindgen-rt" 926 | version = "0.33.0" 927 | source = "registry+https://github.com/rust-lang/crates.io-index" 928 | checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" 929 | dependencies = [ 930 | "bitflags", 931 | ] 932 | 933 | [[package]] 934 | name = "zerocopy" 935 | version = "0.7.35" 936 | source = "registry+https://github.com/rust-lang/crates.io-index" 937 | checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" 938 | dependencies = [ 939 | "byteorder", 940 | "zerocopy-derive 0.7.35", 941 | ] 942 | 943 | [[package]] 944 | name = "zerocopy" 945 | version = "0.8.17" 946 | source = "registry+https://github.com/rust-lang/crates.io-index" 947 | checksum = "aa91407dacce3a68c56de03abe2760159582b846c6a4acd2f456618087f12713" 948 | dependencies = [ 949 | "zerocopy-derive 0.8.17", 950 | ] 951 | 952 | [[package]] 953 | name = "zerocopy-derive" 954 | version = "0.7.35" 955 | source = "registry+https://github.com/rust-lang/crates.io-index" 956 | checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" 957 | dependencies = [ 958 | "proc-macro2", 959 | "quote", 960 | "syn", 961 | ] 962 | 963 | [[package]] 964 | name = "zerocopy-derive" 965 | version = "0.8.17" 966 | source = "registry+https://github.com/rust-lang/crates.io-index" 967 | checksum = "06718a168365cad3d5ff0bb133aad346959a2074bd4a85c121255a11304a8626" 968 | dependencies = [ 969 | "proc-macro2", 970 | "quote", 971 | "syn", 972 | ] 973 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "tui-equalizer" 3 | description = "An equalizer widget for Ratatui with multiple frequency bands." 4 | version = "0.1.2" 5 | edition = "2021" 6 | license = "MIT OR Apache-2.0" 7 | repository = "https://github.com/joshka/tui-equalizer" 8 | documentation = "https://docs.rs/tui-equalizer" 9 | 10 | [dependencies] 11 | derive_builder = "0.20" 12 | ratatui = { version = "0.29", default-features = false } 13 | 14 | [dev-dependencies] 15 | color-eyre = "0.6.3" 16 | crossterm = "0.28.1" 17 | itertools = "0.14.0" 18 | rand = "0.9.1" 19 | ratatui = "0.29.0" 20 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) Josh McKinney 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tui-equalizer 2 | 3 | 4 | 5 | An equalizer widget for [Ratatui] with multiple frequency bands. 6 | 7 | The equalizer is a vertical bar chart where each band represents a frequency range. Each band 8 | can display a value from 0.0 to 1.0, where 1.0 is the maximum value. 9 | 10 | ![Made with VHS](https://vhs.charm.sh/vhs-FiRQkkDAUEnH2BrPbUx5i.gif) 11 | 12 | This demo can be found in the examples folder in the git repo. 13 | 14 | ```shell 15 | cargo run --example demo 16 | ``` 17 | 18 | Inspired by [a comment in the ratatui 19 | repo](https://github.com/ratatui/ratatui/issues/1325#issuecomment-2335095486). 20 | 21 | ## Example 22 | 23 | ```rust 24 | use tui_equalizer::{Band, Equalizer}; 25 | 26 | let equalizer = Equalizer { 27 | bands: vec![ 28 | Band::from(0.5), 29 | Band::from(0.8), 30 | Band::from(0.3), 31 | ], 32 | brightness: 1.0, 33 | }; 34 | equalizer.render(area, &mut buf); 35 | ``` 36 | 37 | ## License 38 | 39 | Copyright (c) Josh McKinney 40 | 41 | This project is licensed under either of: 42 | 43 | - Apache License, Version 2.0 ([LICENSE-APACHE] or ) 44 | - MIT license ([LICENSE-MIT] or ) 45 | 46 | at your option. 47 | 48 | [LICENSE-APACHE]: ./LICENSE-APACHE 49 | [LICENSE-MIT]: ./LICENSE-MIT 50 | 51 | 52 | [Ratatui]: https://crates.io/crates/ratatui 53 | 54 | 55 | -------------------------------------------------------------------------------- /examples/demo.rs: -------------------------------------------------------------------------------- 1 | use std::time::Duration; 2 | 3 | use color_eyre::Result; 4 | use crossterm::event::{self, Event, KeyCode, KeyEventKind}; 5 | use itertools::Itertools; 6 | use rand::{rng, Rng}; 7 | use ratatui::{DefaultTerminal, Frame}; 8 | use tui_equalizer::{Band, Equalizer}; 9 | 10 | fn main() -> Result<()> { 11 | color_eyre::install()?; 12 | let terminal = ratatui::init(); 13 | let result = run(terminal); 14 | ratatui::restore(); 15 | result 16 | } 17 | 18 | fn run(mut terminal: DefaultTerminal) -> Result<()> { 19 | let width = terminal.size()?.width; 20 | let mut current_bands = random_bands(width); 21 | let mut next_bands = random_bands(width); 22 | let mut last_time = std::time::Instant::now(); 23 | // Update the bands every 500ms 24 | const UPDATE_INTERVAL: Duration = Duration::from_millis(500); 25 | loop { 26 | let percent = last_time.elapsed().as_secs_f64() / UPDATE_INTERVAL.as_secs_f64(); 27 | let interpolated = interpolate(¤t_bands, &next_bands, percent); 28 | if percent >= 1.0 { 29 | last_time = std::time::Instant::now(); 30 | current_bands = interpolated.clone(); 31 | next_bands = random_bands(width); 32 | } 33 | terminal.draw(|frame| draw(frame, ¤t_bands, &interpolated))?; 34 | if handle_input()? == Command::Quit { 35 | break Ok(()); 36 | } 37 | } 38 | } 39 | 40 | fn interpolate(current: &Vec, next: &Vec, percent: f64) -> Vec { 41 | let interpolated = current 42 | .iter() 43 | .zip(next.iter()) 44 | .map(|(current, next)| Band { 45 | value: current.value + (next.value - current.value) * percent.clamp(0.0, 1.0), 46 | }) 47 | .collect_vec(); 48 | interpolated 49 | } 50 | 51 | fn random_bands(count: u16) -> Vec { 52 | (0..count / 2) 53 | .map(|_| Band::from(rng().random_range(0.1..1.0))) 54 | .collect_vec() 55 | } 56 | 57 | fn draw(frame: &mut Frame, current: &[Band], bands: &[Band]) { 58 | let size = frame.area(); 59 | frame.render_widget( 60 | Equalizer { 61 | bands: current.to_vec(), 62 | brightness: 0.15, 63 | }, 64 | size, 65 | ); 66 | frame.render_widget( 67 | Equalizer { 68 | bands: bands.to_vec(), 69 | brightness: 1.0, 70 | }, 71 | size, 72 | ); 73 | } 74 | 75 | #[derive(Debug, Clone, PartialEq, Eq)] 76 | enum Command { 77 | Noop, 78 | Quit, 79 | } 80 | 81 | fn handle_input() -> Result { 82 | if !event::poll(Duration::from_secs_f64(1.0 / 60.0))? { 83 | return Ok(Command::Noop); 84 | } 85 | match event::read()? { 86 | Event::Key(key) if key.kind == KeyEventKind::Press => match key.code { 87 | KeyCode::Char('q') => Ok(Command::Quit), 88 | _ => Ok(Command::Noop), 89 | }, 90 | _ => Ok(Command::Noop), 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //! An equalizer widget for [Ratatui] with multiple frequency bands. 2 | //! 3 | //! The equalizer is a vertical bar chart where each band represents a frequency range. Each band 4 | //! can display a value from 0.0 to 1.0, where 1.0 is the maximum value. 5 | //! 6 | //! ![Made with VHS](https://vhs.charm.sh/vhs-FiRQkkDAUEnH2BrPbUx5i.gif) 7 | //! 8 | //! This demo can be found in the examples folder in the git repo. 9 | //! 10 | //! ```shell 11 | //! cargo run --example demo 12 | //! ``` 13 | //! 14 | //! Inspired by [a comment in the ratatui 15 | //! repo](https://github.com/ratatui/ratatui/issues/1325#issuecomment-2335095486). 16 | //! 17 | //! # Example 18 | //! 19 | //! ```rust 20 | //! # use ratatui::{widgets::Widget, layout::Rect, buffer::Buffer}; 21 | //! # let area = Rect::default(); 22 | //! # let mut buf = Buffer::empty(area); 23 | //! use tui_equalizer::{Band, Equalizer}; 24 | //! 25 | //! let equalizer = Equalizer { 26 | //! bands: vec![ 27 | //! Band::from(0.5), 28 | //! Band::from(0.8), 29 | //! Band::from(0.3), 30 | //! ], 31 | //! brightness: 1.0, 32 | //! }; 33 | //! equalizer.render(area, &mut buf); 34 | //! ``` 35 | //! 36 | //! # License 37 | //! 38 | //! Copyright (c) Josh McKinney 39 | //! 40 | //! This project is licensed under either of: 41 | //! 42 | //! - Apache License, Version 2.0 ([LICENSE-APACHE] or ) 43 | //! - MIT license ([LICENSE-MIT] or ) 44 | //! 45 | //! at your option. 46 | //! 47 | //! [LICENSE-APACHE]: ./LICENSE-APACHE 48 | //! [LICENSE-MIT]: ./LICENSE-MIT 49 | //! 50 | //! 51 | //! [Ratatui]: https://crates.io/crates/ratatui 52 | 53 | use std::iter::zip; 54 | 55 | use ratatui::{ 56 | buffer::Buffer, 57 | layout::{Constraint, Layout, Rect}, 58 | style::Color, 59 | widgets::Widget, 60 | }; 61 | 62 | /// An equalizer widget with multiple frequency bands. 63 | /// 64 | /// The equalizer is a vertical bar chart where each band represents a frequency range. 65 | /// 66 | /// # Example 67 | /// 68 | /// ``` 69 | /// # use ratatui::widgets::Widget; 70 | /// # let area = ratatui::layout::Rect::default(); 71 | /// # let mut buf = ratatui::buffer::Buffer::empty(area); 72 | /// use tui_equalizer::{Band, Equalizer}; 73 | /// 74 | /// let equalizer = Equalizer { 75 | /// bands: vec![ 76 | /// Band::from(0.5), 77 | /// Band::from(0.8), 78 | /// Band::from(0.3), 79 | /// ], 80 | /// brightness: 1.0, 81 | /// }; 82 | /// equalizer.render(area, &mut buf); 83 | /// ``` 84 | #[derive(Debug, Clone)] 85 | pub struct Equalizer { 86 | /// A vector of `Band` structs representing each frequency band. 87 | pub bands: Vec, 88 | pub brightness: f64, 89 | } 90 | 91 | /// A struct representing a single frequency band in the equalizer. 92 | #[derive(Debug, Clone)] 93 | pub struct Band { 94 | /// The normalized value of the band, where the maximum is 1.0. 95 | pub value: f64, 96 | } 97 | 98 | impl From for Band { 99 | fn from(value: f64) -> Self { 100 | Self { value } 101 | } 102 | } 103 | 104 | impl Widget for Equalizer { 105 | fn render(self, area: Rect, buf: &mut Buffer) { 106 | let areas = Layout::horizontal(vec![Constraint::Length(2); self.bands.len()]).split(area); 107 | for (band, area) in zip(self.bands, areas.iter()) { 108 | band.render(*area, buf, self.brightness); 109 | } 110 | } 111 | } 112 | 113 | impl Band { 114 | fn render(self, area: Rect, buf: &mut Buffer, brightness: f64) { 115 | let value = self.value.clamp(0.0, 1.0); 116 | let height = (value * area.height as f64) as u16; 117 | 118 | // Calculate the color gradient step 119 | let color_step = 1.0 / area.height as f64; 120 | 121 | // Iterate over each segment and render it with the corresponding color 122 | for i in 0..height { 123 | // Green to Yellow to Red gradient 124 | let v = i as f64 * color_step; 125 | let vv = 1.0 - v; 126 | let br = brightness.clamp(0.0, 1.0) * 255.0; 127 | let r = if v < 0.5 { v * 2.0 * br } else { br } as u8; 128 | let g = if v < 0.5 { br } else { vv * 2.0 * br } as u8; 129 | let b = 0; 130 | let color = Color::Rgb(r, g, b); 131 | buf[(area.left(), area.bottom().saturating_sub(i + 1))] 132 | .set_fg(color) 133 | .set_symbol(ratatui::symbols::bar::HALF); 134 | } 135 | } 136 | } 137 | --------------------------------------------------------------------------------