├── gpu
├── README.md
├── imgs
│ └── leaves.png
├── src
│ ├── wgpu_impl
│ │ └── shaders
│ │ │ ├── clear_texture.wgsl
│ │ │ ├── copy_texture.wgsl
│ │ │ └── alpha_triangles.wgsl
│ └── error.rs
└── Cargo.toml
├── algo
├── README.md
├── src
│ └── lib.rs
└── Cargo.toml
├── core
├── README.md
└── src
│ ├── context.rs
│ ├── builtin_widgets
│ ├── icon_miss.svg
│ ├── void.rs
│ ├── painting_style.rs
│ ├── container.rs
│ ├── clip.rs
│ ├── foreground.rs
│ ├── image_widget.rs
│ ├── opacity.rs
│ ├── text_align.rs
│ ├── text_style.rs
│ ├── disabled.rs
│ ├── ignore_pointer.rs
│ ├── track_widget_id.rs
│ └── constrained_box.rs
│ ├── animation
│ └── progress.rs
│ ├── events
│ ├── device_id.rs
│ ├── listener_impl_helper.rs
│ ├── pointers
│ │ └── from_mouse.rs
│ ├── ime_pre_edit.rs
│ └── wheel.rs
│ ├── animation.rs
│ ├── ticker.rs
│ ├── local_sender.rs
│ └── state
│ └── watcher.rs
├── macros
├── README.md
├── src
│ ├── pipe_macro.rs
│ ├── distinct_pipe_macro.rs
│ ├── util.rs
│ ├── fn_widget_macro.rs
│ ├── asset
│ │ ├── basic.rs
│ │ └── svg.rs
│ └── lerp_derive.rs
└── Cargo.toml
├── painter
├── README.md
├── src
│ ├── text
│ │ └── Lato-Regular.ttf
│ ├── lib.rs
│ └── style.rs
└── Cargo.toml
├── ribir
├── README.md
└── src
│ ├── platform.rs
│ ├── backends.rs
│ ├── backends
│ ├── mock_backend.rs
│ └── wgpu_backend.rs
│ └── lib.rs
├── widgets
├── README.md
├── src
│ ├── label.rs
│ ├── layout.rs
│ ├── lib.rs
│ ├── transform_box.rs
│ └── layout
│ │ └── sized_box.rs
└── Cargo.toml
├── docs
├── zh
│ ├── assets
│ ├── practice_todos_app
│ │ └── improving_styles_and_animations.md
│ ├── get_started
│ │ └── try_it.md
│ ├── guide
│ │ └── README.md
│ └── understanding_ribir
│ │ └── widget_in_depth.md
├── en
│ ├── assets
│ │ ├── box_counter.gif
│ │ ├── todos-demo.gif
│ │ └── todos-widgets.png
│ ├── practice_todos_app
│ │ ├── improving_styles_and_animations.md
│ │ └── _category_.json
│ ├── get_started
│ │ ├── _category_.json
│ │ └── try_it.md
│ └── understanding_ribir
│ │ └── _category_.json
└── readme.md
├── .github
├── workflows
│ ├── ISSUE_TEMPLATE
│ │ ├── config.yml
│ │ └── documentation.md
│ ├── dispatch-other-repo.yml
│ ├── alpha-version.yml
│ └── patch-version.yml
├── ISSUE_TEMPLATE
│ ├── others.md
│ ├── feature_request.md
│ ├── bug_report.md
│ └── documentation.md
├── dependabot.yml
└── pull_request_template.md
├── cli
├── src
│ ├── util
│ │ └── mod.rs
│ └── program_check.rs
├── template
│ └── index.html
├── Cargo.toml
└── README.md
├── examples
├── todos
│ ├── src
│ │ ├── main.rs
│ │ ├── lib.rs
│ │ └── todos.rs
│ ├── README.md
│ └── Cargo.toml
├── counter
│ ├── src
│ │ ├── main.rs
│ │ └── lib.rs
│ ├── README.md
│ ├── ci
│ │ ├── bundle-windows.toml
│ │ ├── bundle-linux.toml
│ │ └── bundle-macos.toml
│ └── Cargo.toml
├── messages
│ ├── src
│ │ ├── main.rs
│ │ └── lib.rs
│ ├── README.md
│ └── Cargo.toml
├── storybook
│ ├── src
│ │ ├── main.rs
│ │ └── lib.rs
│ ├── README.md
│ └── Cargo.toml
├── wordle_game
│ ├── src
│ │ ├── main.rs
│ │ └── lib.rs
│ ├── wordle_win.png
│ ├── wordle_guess.png
│ ├── README.md
│ └── Cargo.toml
├── Logo.ico
├── pomodoro
│ ├── icon.ico
│ ├── static
│ │ ├── icon.png
│ │ ├── play.svg
│ │ ├── minimize.svg
│ │ ├── pause.svg
│ │ ├── full.svg
│ │ ├── skip_next.svg
│ │ ├── close.svg
│ │ ├── mini.svg
│ │ ├── volume_up.svg
│ │ ├── volume_off.svg
│ │ ├── pin.svg
│ │ └── pin_off.svg
│ ├── Cargo.toml
│ └── src
│ │ └── main.rs
├── attachments
│ ├── 3DDD-1.png
│ ├── 3DDD-2.png
│ ├── 3DDD-3.png
│ └── 3DDD-4.png
├── README.md
└── animation_demo.rs
├── tests
├── assets_conflict
│ ├── dir1
│ │ └── test.txt
│ └── dir2
│ │ └── test.txt
├── assets
│ ├── test1.svg
│ └── fill_with_gradient.svg
├── benches
│ ├── widgets_bench.rs
│ ├── text_bench.rs
│ └── example_bench.rs
├── path_child_test.rs
├── Cargo.toml
└── declare_builder_test.rs
├── fonts
├── DejaVuSans.ttf
├── GaramondNo8-Reg.ttf
├── material-search.ttf
├── NotoSerifSC-Bold.你好世界.otf
└── Nunito-VariableFont_wght.ttf
├── static
├── hero-banner.png
├── wordle-wasm.png
├── counter_demo.gif
├── theme-switch.gif
└── logo.svg
├── .vscode
└── settings.json
├── dev-helper
├── src
│ └── lib.rs
├── Cargo.toml
└── readme.md
├── themes
├── material
│ ├── src
│ │ ├── fonts
│ │ │ ├── Roboto-Medium.ttf
│ │ │ └── Roboto-Regular.ttf
│ │ ├── classes
│ │ │ ├── disabled_cls.rs
│ │ │ ├── avatar_cls.rs
│ │ │ ├── tooltips_cls.rs
│ │ │ ├── badge_cls.rs
│ │ │ ├── input_cls.rs
│ │ │ ├── menu_cls.rs
│ │ │ └── divider_cls.rs
│ │ └── classes.rs
│ ├── icons
│ │ ├── arrow_drop_down_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── menu_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── add_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── done_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── expand_more_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── arrow_back_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── check_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── arrow_forward_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── chevron_right_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── text_caret.svg
│ │ ├── home_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── close_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── login_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── file_download_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── logout_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── delete_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── grade_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── star_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── more_vert_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── refresh_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── search_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── miss_icon.svg
│ │ ├── sms_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── add_circle_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── more_horiz_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── check_circle_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── cancel_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── favorite_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── info_FILL0_wght400_GRAD0_opsz48.svg
│ │ ├── account_circle_FILL0_wght400_GRAD0_opsz48.svg
│ │ └── settings_FILL0_wght400_GRAD0_opsz48.svg
│ └── Cargo.toml
└── ribir_slim
│ ├── src
│ ├── classes.rs
│ └── slim.rs
│ └── Cargo.toml
├── test_cases
├── ribir_gpu
│ └── gpu_backend
│ │ └── tests
│ │ ├── smoke_wgpu.png
│ │ ├── clip_layers_wgpu.png
│ │ ├── two_img_brush_wgpu.png
│ │ ├── draw_bundle_svg_wgpu.png
│ │ ├── draw_partial_img_wgpu.png
│ │ ├── draw_svg_gradient_wgpu.png
│ │ ├── multi_draw_phase_wgpu.png
│ │ ├── transform_img_brush_wgpu.png
│ │ └── stroke_include_border_wgpu.png
├── todos
│ └── tests
│ │ ├── todos_with_default_by_wgpu.png
│ │ └── todos_with_material_by_wgpu.png
├── counter
│ └── tests
│ │ ├── counter_with_default_by_wgpu.png
│ │ ├── counter_with_material_by_wgpu.png
│ │ └── counter_with_default_by_wgpu_diff_0.png
├── assets_test
│ └── fix_draw_svg_not_apply_alpha_wgpu.png
├── storybook
│ └── tests
│ │ ├── storybook_with_default_by_wgpu.png
│ │ └── storybook_with_material_by_wgpu.png
├── pomodoro
│ └── tests
│ │ ├── full_pomodoro_with_default_by_wgpu.png
│ │ ├── full_pomodoro_with_material_by_wgpu.png
│ │ ├── mini_pomodoro_with_default_by_wgpu.png
│ │ └── mini_pomodoro_with_material_by_wgpu.png
├── ribir_widgets
│ ├── list
│ │ └── tests
│ │ │ ├── list_with_default_by_wgpu.png
│ │ │ └── list_with_material_by_wgpu.png
│ ├── badge
│ │ └── tests
│ │ │ ├── badge_with_default_by_wgpu.png
│ │ │ └── badge_with_material_by_wgpu.png
│ ├── buttons
│ │ └── tests
│ │ │ ├── fab_with_default_by_wgpu.png
│ │ │ ├── button_with_default_by_wgpu.png
│ │ │ ├── fab_with_material_by_wgpu.png
│ │ │ ├── button_with_material_by_wgpu.png
│ │ │ ├── mini_fab_with_default_by_wgpu.png
│ │ │ ├── large_fab_with_default_by_wgpu.png
│ │ │ ├── large_fab_with_material_by_wgpu.png
│ │ │ ├── mini_fab_with_material_by_wgpu.png
│ │ │ ├── filled_button_with_default_by_wgpu.png
│ │ │ ├── filled_button_with_material_by_wgpu.png
│ │ │ ├── outlined_button_with_default_by_wgpu.png
│ │ │ └── outlined_button_with_material_by_wgpu.png
│ ├── icon
│ │ └── tests
│ │ │ ├── icons_with_default_by_wgpu.png
│ │ │ ├── icons_with_material_by_wgpu.png
│ │ │ ├── keep_icon_visual_with_default_by_wgpu.png
│ │ │ └── keep_icon_visual_with_material_by_wgpu.png
│ ├── path
│ │ └── tests
│ │ │ ├── circle40_with_default_by_wgpu.png
│ │ │ ├── circle40_with_material_by_wgpu.png
│ │ │ ├── circle40_kit_with_default_by_wgpu.png
│ │ │ ├── circle40_kit_with_material_by_wgpu.png
│ │ │ ├── fill_circle40_with_default_by_wgpu.png
│ │ │ ├── fill_circle40_with_material_by_wgpu.png
│ │ │ ├── stroke_circle40_with_default_by_wgpu.png
│ │ │ └── stroke_circle40_with_material_by_wgpu.png
│ ├── scrollbar
│ │ └── test
│ │ │ ├── init_with_default_by_wgpu.png
│ │ │ ├── init_with_material_by_wgpu.png
│ │ │ ├── scrolled_with_default_by_wgpu.png
│ │ │ └── scrolled_with_material_by_wgpu.png
│ ├── switch
│ │ └── tests
│ │ │ ├── switch_with_default_by_wgpu.png
│ │ │ └── switch_with_material_by_wgpu.png
│ ├── tabs
│ │ └── tests
│ │ │ ├── primary_top_with_default_by_wgpu.png
│ │ │ ├── primary_bottom_with_default_by_wgpu.png
│ │ │ ├── primary_left_with_default_by_wgpu.png
│ │ │ ├── primary_left_with_material_by_wgpu.png
│ │ │ ├── primary_right_with_default_by_wgpu.png
│ │ │ ├── primary_right_with_material_by_wgpu.png
│ │ │ ├── primary_top_with_material_by_wgpu.png
│ │ │ ├── secondary_left_with_default_by_wgpu.png
│ │ │ ├── secondary_top_with_default_by_wgpu.png
│ │ │ ├── secondary_top_with_material_by_wgpu.png
│ │ │ ├── primary_bottom_with_material_by_wgpu.png
│ │ │ ├── secondary_bottom_with_default_by_wgpu.png
│ │ │ ├── secondary_left_with_material_by_wgpu.png
│ │ │ ├── secondary_right_with_default_by_wgpu.png
│ │ │ ├── secondary_right_with_material_by_wgpu.png
│ │ │ └── secondary_bottom_with_material_by_wgpu.png
│ ├── avatar
│ │ └── tests
│ │ │ ├── label_avatar_with_default_by_wgpu.png
│ │ │ ├── label_avatar_with_material_by_wgpu.png
│ │ │ ├── widget_avatar_with_default_by_wgpu.png
│ │ │ └── widget_avatar_with_material_by_wgpu.png
│ ├── checkbox
│ │ └── tests
│ │ │ ├── checkbox_with_default_by_wgpu.png
│ │ │ └── checkbox_with_material_by_wgpu.png
│ ├── radio
│ │ └── tests
│ │ │ ├── radio_widget_with_default_by_wgpu.png
│ │ │ └── radio_widget_with_material_by_wgpu.png
│ ├── slider
│ │ └── tests
│ │ │ ├── slider_widgets_with_default_by_wgpu.png
│ │ │ └── slider_widgets_with_material_by_wgpu.png
│ └── progress
│ │ └── tests
│ │ ├── progress_widget_with_default_by_wgpu.png
│ │ └── progress_widget_with_material_by_wgpu.png
├── wordle_game
│ └── tests
│ │ ├── wordle_game_with_default_by_wgpu.png
│ │ └── wordle_game_with_material_by_wgpu.png
├── ribir_core
│ └── builtin_widgets
│ │ ├── border
│ │ └── tests
│ │ │ ├── all_borders.png
│ │ │ ├── left_borders.png
│ │ │ ├── top_borders.png
│ │ │ ├── bottom_borders.png
│ │ │ ├── right_borders.png
│ │ │ ├── top_left_borders.png
│ │ │ ├── top_right_borders.png
│ │ │ ├── bottom_left_borders.png
│ │ │ ├── right_bottom_borders.png
│ │ │ ├── left_and_right_borders.png
│ │ │ ├── top_and_bottom_borders.png
│ │ │ ├── bottom_left_and_top_borders.png
│ │ │ ├── top_left_and_right_borders.png
│ │ │ └── right_bottom_and_left_borders.png
│ │ ├── svg
│ │ └── tests
│ │ │ └── svgs_smoke_wgpu.png
│ │ ├── padding
│ │ └── tests
│ │ │ └── padding_draw.png
│ │ ├── smooth_layout
│ │ └── tests
│ │ │ ├── smooth_x.png
│ │ │ ├── smooth_y.png
│ │ │ ├── smooth_pos.png
│ │ │ ├── smooth_height.png
│ │ │ ├── smooth_width.png
│ │ │ ├── smooth_size_from_5.png
│ │ │ ├── smooth_size_from_50p.png
│ │ │ └── smooth_size_from_real.png
│ │ ├── clip_boundary
│ │ └── tests
│ │ │ └── clip_boundary.png
│ │ ├── text
│ │ └── tests
│ │ │ ├── h1_with_default_by_wgpu.png
│ │ │ ├── h1_with_material_by_wgpu.png
│ │ │ ├── text_clip_with_default_by_wgpu.png
│ │ │ ├── text_clip_with_material_by_wgpu.png
│ │ │ ├── default_text_with_default_by_wgpu.png
│ │ │ ├── default_text_with_material_by_wgpu.png
│ │ │ ├── middle_baseline_with_default_by_wgpu.png
│ │ │ └── middle_baseline_with_material_by_wgpu.png
│ │ ├── color_filter
│ │ └── tests
│ │ │ ├── color_filter_with_default_by_wgpu.png
│ │ │ └── color_filter_with_material_by_wgpu.png
│ │ ├── box_shadow
│ │ └── tests
│ │ │ ├── box_shadow_basic_with_default_by_wgpu.png
│ │ │ └── box_shadow_basic_with_material_by_wgpu.png
│ │ ├── backdrop_filter
│ │ └── tests
│ │ │ ├── backdrop_filter_with_default_by_wgpu.png
│ │ │ └── backdrop_filter_with_material_by_wgpu.png
│ │ └── filter_widget
│ │ └── tests
│ │ ├── filter_drop_shadow_with_default_by_wgpu.png
│ │ └── filter_drop_shadow_with_material_by_wgpu.png
└── messages
│ └── messages
│ └── tests
│ ├── messages_with_default_by_wgpu.png
│ └── messages_with_material_by_wgpu.png
├── .cargo
└── config.toml
├── geom
├── Cargo.toml
└── src
│ └── lib.rs
├── rustfmt.toml
├── .gitignore
├── LICENSE
└── changelog.config.js
/gpu/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/algo/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/core/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/macros/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/painter/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ribir/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/widgets/README.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/zh/assets:
--------------------------------------------------------------------------------
1 | ../en/assets
--------------------------------------------------------------------------------
/.github/workflows/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/cli/src/util/mod.rs:
--------------------------------------------------------------------------------
1 | pub mod cargo_settings;
2 |
--------------------------------------------------------------------------------
/examples/todos/src/main.rs:
--------------------------------------------------------------------------------
1 | fn main() { todos::run(); }
2 |
--------------------------------------------------------------------------------
/examples/counter/src/main.rs:
--------------------------------------------------------------------------------
1 | fn main() { counter::run(); }
2 |
--------------------------------------------------------------------------------
/examples/messages/src/main.rs:
--------------------------------------------------------------------------------
1 | fn main() { messages::run() }
2 |
--------------------------------------------------------------------------------
/tests/assets_conflict/dir1/test.txt:
--------------------------------------------------------------------------------
1 | This is test file from dir1
--------------------------------------------------------------------------------
/tests/assets_conflict/dir2/test.txt:
--------------------------------------------------------------------------------
1 | This is test file from dir2
--------------------------------------------------------------------------------
/examples/storybook/src/main.rs:
--------------------------------------------------------------------------------
1 | fn main() { storybook::run() }
2 |
--------------------------------------------------------------------------------
/examples/wordle_game/src/main.rs:
--------------------------------------------------------------------------------
1 | fn main() { wordle_game::run() }
2 |
--------------------------------------------------------------------------------
/examples/Logo.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/examples/Logo.ico
--------------------------------------------------------------------------------
/fonts/DejaVuSans.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/fonts/DejaVuSans.ttf
--------------------------------------------------------------------------------
/gpu/imgs/leaves.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/gpu/imgs/leaves.png
--------------------------------------------------------------------------------
/static/hero-banner.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/static/hero-banner.png
--------------------------------------------------------------------------------
/static/wordle-wasm.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/static/wordle-wasm.png
--------------------------------------------------------------------------------
/fonts/GaramondNo8-Reg.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/fonts/GaramondNo8-Reg.ttf
--------------------------------------------------------------------------------
/fonts/material-search.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/fonts/material-search.ttf
--------------------------------------------------------------------------------
/static/counter_demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/static/counter_demo.gif
--------------------------------------------------------------------------------
/static/theme-switch.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/static/theme-switch.gif
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "rust-analyzer.rustfmt.extraArgs": [
3 | "+nightly"
4 | ],
5 | }
--------------------------------------------------------------------------------
/examples/pomodoro/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/examples/pomodoro/icon.ico
--------------------------------------------------------------------------------
/docs/en/assets/box_counter.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/docs/en/assets/box_counter.gif
--------------------------------------------------------------------------------
/docs/en/assets/todos-demo.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/docs/en/assets/todos-demo.gif
--------------------------------------------------------------------------------
/docs/en/assets/todos-widgets.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/docs/en/assets/todos-widgets.png
--------------------------------------------------------------------------------
/examples/attachments/3DDD-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/examples/attachments/3DDD-1.png
--------------------------------------------------------------------------------
/examples/attachments/3DDD-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/examples/attachments/3DDD-2.png
--------------------------------------------------------------------------------
/examples/attachments/3DDD-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/examples/attachments/3DDD-3.png
--------------------------------------------------------------------------------
/examples/attachments/3DDD-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/examples/attachments/3DDD-4.png
--------------------------------------------------------------------------------
/fonts/NotoSerifSC-Bold.你好世界.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/fonts/NotoSerifSC-Bold.你好世界.otf
--------------------------------------------------------------------------------
/dev-helper/src/lib.rs:
--------------------------------------------------------------------------------
1 | mod image_test;
2 | pub use image_test::*;
3 | mod unit_test_describe;
4 | mod widget_test;
5 |
--------------------------------------------------------------------------------
/examples/pomodoro/static/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/examples/pomodoro/static/icon.png
--------------------------------------------------------------------------------
/examples/wordle_game/wordle_win.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/examples/wordle_game/wordle_win.png
--------------------------------------------------------------------------------
/fonts/Nunito-VariableFont_wght.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/fonts/Nunito-VariableFont_wght.ttf
--------------------------------------------------------------------------------
/painter/src/text/Lato-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/painter/src/text/Lato-Regular.ttf
--------------------------------------------------------------------------------
/examples/wordle_game/wordle_guess.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/examples/wordle_game/wordle_guess.png
--------------------------------------------------------------------------------
/docs/zh/practice_todos_app/improving_styles_and_animations.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 2
3 | ---
4 |
5 | # 改进样式和动画
6 |
7 | > 即将推出
8 |
--------------------------------------------------------------------------------
/themes/material/src/fonts/Roboto-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/themes/material/src/fonts/Roboto-Medium.ttf
--------------------------------------------------------------------------------
/themes/material/src/fonts/Roboto-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/themes/material/src/fonts/Roboto-Regular.ttf
--------------------------------------------------------------------------------
/themes/ribir_slim/src/classes.rs:
--------------------------------------------------------------------------------
1 | use ribir_core::prelude::Classes;
2 |
3 | pub fn initd_classes() -> Classes { Classes::default() }
4 |
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | # Ribir Examples
2 |
3 | To run the examples, you can use the following commands:
4 |
5 | ``` sh
6 | cargo run -p storybook
7 | ```
8 |
--------------------------------------------------------------------------------
/test_cases/ribir_gpu/gpu_backend/tests/smoke_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_gpu/gpu_backend/tests/smoke_wgpu.png
--------------------------------------------------------------------------------
/test_cases/todos/tests/todos_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/todos/tests/todos_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/todos/tests/todos_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/todos/tests/todos_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/counter/tests/counter_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/counter/tests/counter_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/docs/en/practice_todos_app/improving_styles_and_animations.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 2
3 | ---
4 |
5 | # Improving styles and animations
6 |
7 | > coming soon
8 |
--------------------------------------------------------------------------------
/examples/pomodoro/static/play.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test_cases/assets_test/fix_draw_svg_not_apply_alpha_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/assets_test/fix_draw_svg_not_apply_alpha_wgpu.png
--------------------------------------------------------------------------------
/test_cases/counter/tests/counter_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/counter/tests/counter_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_gpu/gpu_backend/tests/clip_layers_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_gpu/gpu_backend/tests/clip_layers_wgpu.png
--------------------------------------------------------------------------------
/themes/material/icons/arrow_drop_down_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test_cases/ribir_gpu/gpu_backend/tests/two_img_brush_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_gpu/gpu_backend/tests/two_img_brush_wgpu.png
--------------------------------------------------------------------------------
/test_cases/storybook/tests/storybook_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/storybook/tests/storybook_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/storybook/tests/storybook_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/storybook/tests/storybook_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/counter/tests/counter_with_default_by_wgpu_diff_0.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/counter/tests/counter_with_default_by_wgpu_diff_0.png
--------------------------------------------------------------------------------
/test_cases/pomodoro/tests/full_pomodoro_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/pomodoro/tests/full_pomodoro_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/pomodoro/tests/full_pomodoro_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/pomodoro/tests/full_pomodoro_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/pomodoro/tests/mini_pomodoro_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/pomodoro/tests/mini_pomodoro_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/pomodoro/tests/mini_pomodoro_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/pomodoro/tests/mini_pomodoro_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_gpu/gpu_backend/tests/draw_bundle_svg_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_gpu/gpu_backend/tests/draw_bundle_svg_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_gpu/gpu_backend/tests/draw_partial_img_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_gpu/gpu_backend/tests/draw_partial_img_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_gpu/gpu_backend/tests/draw_svg_gradient_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_gpu/gpu_backend/tests/draw_svg_gradient_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_gpu/gpu_backend/tests/multi_draw_phase_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_gpu/gpu_backend/tests/multi_draw_phase_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/list/tests/list_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/list/tests/list_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/wordle_game/tests/wordle_game_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/wordle_game/tests/wordle_game_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/border/tests/all_borders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/border/tests/all_borders.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/border/tests/left_borders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/border/tests/left_borders.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/border/tests/top_borders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/border/tests/top_borders.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/svg/tests/svgs_smoke_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/svg/tests/svgs_smoke_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_gpu/gpu_backend/tests/transform_img_brush_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_gpu/gpu_backend/tests/transform_img_brush_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/badge/tests/badge_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/badge/tests/badge_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/buttons/tests/fab_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/buttons/tests/fab_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/icon/tests/icons_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/icon/tests/icons_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/icon/tests/icons_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/icon/tests/icons_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/list/tests/list_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/list/tests/list_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/wordle_game/tests/wordle_game_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/wordle_game/tests/wordle_game_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/themes/material/icons/menu_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/others.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Others
3 | about: Create issue by using blank template
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/examples/pomodoro/static/minimize.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test_cases/messages/messages/tests/messages_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/messages/messages/tests/messages_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/messages/messages/tests/messages_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/messages/messages/tests/messages_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/border/tests/bottom_borders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/border/tests/bottom_borders.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/border/tests/right_borders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/border/tests/right_borders.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/padding/tests/padding_draw.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/padding/tests/padding_draw.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/smooth_layout/tests/smooth_x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/smooth_layout/tests/smooth_x.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/smooth_layout/tests/smooth_y.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/smooth_layout/tests/smooth_y.png
--------------------------------------------------------------------------------
/test_cases/ribir_gpu/gpu_backend/tests/stroke_include_border_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_gpu/gpu_backend/tests/stroke_include_border_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/badge/tests/badge_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/badge/tests/badge_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/buttons/tests/button_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/buttons/tests/button_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/buttons/tests/fab_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/buttons/tests/fab_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/path/tests/circle40_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/path/tests/circle40_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/path/tests/circle40_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/path/tests/circle40_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/scrollbar/test/init_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/scrollbar/test/init_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/scrollbar/test/init_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/scrollbar/test/init_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/switch/tests/switch_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/switch/tests/switch_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/switch/tests/switch_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/switch/tests/switch_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/themes/material/icons/add_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/border/tests/top_left_borders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/border/tests/top_left_borders.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/border/tests/top_right_borders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/border/tests/top_right_borders.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/smooth_layout/tests/smooth_pos.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/smooth_layout/tests/smooth_pos.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/buttons/tests/button_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/buttons/tests/button_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/buttons/tests/mini_fab_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/buttons/tests/mini_fab_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/tabs/tests/primary_top_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/tabs/tests/primary_top_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/border/tests/bottom_left_borders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/border/tests/bottom_left_borders.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/border/tests/right_bottom_borders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/border/tests/right_bottom_borders.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/clip_boundary/tests/clip_boundary.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/clip_boundary/tests/clip_boundary.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/smooth_layout/tests/smooth_height.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/smooth_layout/tests/smooth_height.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/smooth_layout/tests/smooth_width.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/smooth_layout/tests/smooth_width.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/avatar/tests/label_avatar_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/avatar/tests/label_avatar_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/buttons/tests/large_fab_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/buttons/tests/large_fab_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/buttons/tests/large_fab_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/buttons/tests/large_fab_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/buttons/tests/mini_fab_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/buttons/tests/mini_fab_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/checkbox/tests/checkbox_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/checkbox/tests/checkbox_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/checkbox/tests/checkbox_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/checkbox/tests/checkbox_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/path/tests/circle40_kit_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/path/tests/circle40_kit_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/path/tests/circle40_kit_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/path/tests/circle40_kit_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/path/tests/fill_circle40_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/path/tests/fill_circle40_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/path/tests/fill_circle40_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/path/tests/fill_circle40_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/radio/tests/radio_widget_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/radio/tests/radio_widget_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/radio/tests/radio_widget_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/radio/tests/radio_widget_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/scrollbar/test/scrolled_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/scrollbar/test/scrolled_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/scrollbar/test/scrolled_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/scrollbar/test/scrolled_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/tabs/tests/primary_bottom_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/tabs/tests/primary_bottom_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/tabs/tests/primary_left_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/tabs/tests/primary_left_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/tabs/tests/primary_left_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/tabs/tests/primary_left_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/tabs/tests/primary_right_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/tabs/tests/primary_right_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/tabs/tests/primary_right_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/tabs/tests/primary_right_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/tabs/tests/primary_top_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/tabs/tests/primary_top_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/tabs/tests/secondary_left_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/tabs/tests/secondary_left_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/tabs/tests/secondary_top_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/tabs/tests/secondary_top_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/tabs/tests/secondary_top_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/tabs/tests/secondary_top_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/themes/material/icons/done_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/themes/material/icons/expand_more_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/border/tests/left_and_right_borders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/border/tests/left_and_right_borders.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/border/tests/top_and_bottom_borders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/border/tests/top_and_bottom_borders.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/text/tests/h1_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/text/tests/h1_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/text/tests/h1_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/text/tests/h1_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/avatar/tests/label_avatar_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/avatar/tests/label_avatar_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/avatar/tests/widget_avatar_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/avatar/tests/widget_avatar_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/avatar/tests/widget_avatar_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/avatar/tests/widget_avatar_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/buttons/tests/filled_button_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/buttons/tests/filled_button_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/icon/tests/keep_icon_visual_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/icon/tests/keep_icon_visual_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/path/tests/stroke_circle40_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/path/tests/stroke_circle40_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/path/tests/stroke_circle40_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/path/tests/stroke_circle40_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/slider/tests/slider_widgets_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/slider/tests/slider_widgets_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/tabs/tests/primary_bottom_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/tabs/tests/primary_bottom_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/tabs/tests/secondary_bottom_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/tabs/tests/secondary_bottom_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/tabs/tests/secondary_left_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/tabs/tests/secondary_left_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/tabs/tests/secondary_right_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/tabs/tests/secondary_right_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/tabs/tests/secondary_right_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/tabs/tests/secondary_right_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/themes/material/icons/arrow_back_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/themes/material/icons/check_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/smooth_layout/tests/smooth_size_from_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/smooth_layout/tests/smooth_size_from_5.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/buttons/tests/filled_button_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/buttons/tests/filled_button_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/buttons/tests/outlined_button_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/buttons/tests/outlined_button_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/buttons/tests/outlined_button_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/buttons/tests/outlined_button_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/icon/tests/keep_icon_visual_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/icon/tests/keep_icon_visual_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/progress/tests/progress_widget_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/progress/tests/progress_widget_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/slider/tests/slider_widgets_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/slider/tests/slider_widgets_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/tabs/tests/secondary_bottom_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/tabs/tests/secondary_bottom_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/themes/material/icons/arrow_forward_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/themes/material/icons/chevron_right_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.cargo/config.toml:
--------------------------------------------------------------------------------
1 | [env]
2 | CARGO_WORKSPACE_DIR = {value = "", relative = true}
3 | [alias]
4 | run-wasm = "run --package cli -- run-wasm --template ./cli/template"
5 | bundle = "run --package cli -- bundle"
6 |
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/border/tests/bottom_left_and_top_borders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/border/tests/bottom_left_and_top_borders.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/border/tests/top_left_and_right_borders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/border/tests/top_left_and_right_borders.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/smooth_layout/tests/smooth_size_from_50p.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/smooth_layout/tests/smooth_size_from_50p.png
--------------------------------------------------------------------------------
/test_cases/ribir_widgets/progress/tests/progress_widget_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_widgets/progress/tests/progress_widget_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/border/tests/right_bottom_and_left_borders.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/border/tests/right_bottom_and_left_borders.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/smooth_layout/tests/smooth_size_from_real.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/smooth_layout/tests/smooth_size_from_real.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/text/tests/text_clip_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/text/tests/text_clip_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/text/tests/text_clip_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/text/tests/text_clip_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/text/tests/default_text_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/text/tests/default_text_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/text/tests/default_text_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/text/tests/default_text_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/examples/pomodoro/static/pause.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/text/tests/middle_baseline_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/text/tests/middle_baseline_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/text/tests/middle_baseline_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/text/tests/middle_baseline_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/themes/material/icons/text_caret.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/examples/pomodoro/static/full.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/pomodoro/static/skip_next.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/storybook/README.md:
--------------------------------------------------------------------------------
1 | # Story Book
2 |
3 | A widgets workshop.
4 |
5 | You can run with:
6 |
7 | ``` sh
8 | cargo run -p storybook
9 | ```
10 |
11 | or run in web:
12 | ``` sh
13 | cargo run-wasm -p storybook
14 | ```
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/color_filter/tests/color_filter_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/color_filter/tests/color_filter_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/color_filter/tests/color_filter_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/color_filter/tests/color_filter_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/box_shadow/tests/box_shadow_basic_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/box_shadow/tests/box_shadow_basic_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/box_shadow/tests/box_shadow_basic_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/box_shadow/tests/box_shadow_basic_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/themes/material/icons/home_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/backdrop_filter/tests/backdrop_filter_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/backdrop_filter/tests/backdrop_filter_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/algo/src/lib.rs:
--------------------------------------------------------------------------------
1 | #![allow(clippy::needless_lifetimes)]
2 |
3 | mod cow_rc;
4 | mod frame_cache;
5 | pub use cow_rc::{CowArc, Substr};
6 | pub use frame_cache::*;
7 | mod resource;
8 | pub use resource::*;
9 | mod sc;
10 | pub use sc::*;
11 |
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/backdrop_filter/tests/backdrop_filter_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/backdrop_filter/tests/backdrop_filter_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/filter_widget/tests/filter_drop_shadow_with_default_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/filter_widget/tests/filter_drop_shadow_with_default_by_wgpu.png
--------------------------------------------------------------------------------
/test_cases/ribir_core/builtin_widgets/filter_widget/tests/filter_drop_shadow_with_material_by_wgpu.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RibirX/Ribir/HEAD/test_cases/ribir_core/builtin_widgets/filter_widget/tests/filter_drop_shadow_with_material_by_wgpu.png
--------------------------------------------------------------------------------
/themes/material/icons/close_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/widgets/src/label.rs:
--------------------------------------------------------------------------------
1 | use ribir_core::prelude::*;
2 |
3 | pub struct Label(pub PipeValue>);
4 |
5 | impl Label {
6 | #[inline]
7 | pub fn new(str: impl RInto>, K>) -> Self { Self(str.r_into()) }
8 | }
9 |
--------------------------------------------------------------------------------
/examples/pomodoro/static/close.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/counter/README.md:
--------------------------------------------------------------------------------
1 | # Counter
2 |
3 | Exampling how to increase count or decrease count via buttons.
4 |
5 | You can run with:
6 |
7 | ``` sh
8 | cargo run -p counter
9 | ```
10 | or run in web:
11 | ``` sh
12 | cargo run-wasm -p counter
13 | ```
--------------------------------------------------------------------------------
/examples/pomodoro/static/mini.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/en/get_started/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Getting Started",
3 | "position": 2,
4 | "link": {
5 | "type": "generated-index",
6 | "description": "This guide will help you get started with Ribir, covering all the basics you need to know."
7 | }
8 | }
--------------------------------------------------------------------------------
/themes/material/icons/login_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/messages/README.md:
--------------------------------------------------------------------------------
1 | # Messages
2 |
3 | Exampling a message ui mainly demonstrates the use of `Tabs` and `Lists`.
4 |
5 | You can run with:
6 |
7 | ``` sh
8 | cargo run -p messages
9 | ```
10 |
11 | or run in web:
12 | ``` sh
13 | cargo run-wasm -p messages
14 | ```
--------------------------------------------------------------------------------
/themes/material/icons/file_download_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/themes/material/icons/logout_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/en/practice_todos_app/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Practice Todos App",
3 | "position": 3,
4 | "link": {
5 | "type": "generated-index",
6 | "description": "This guide will help you learn Ribir by walking you through a full example of a Todos application."
7 | }
8 | }
--------------------------------------------------------------------------------
/themes/material/src/classes/disabled_cls.rs:
--------------------------------------------------------------------------------
1 | use ribir_core::prelude::*;
2 |
3 | pub(super) fn init(classes: &mut Classes) {
4 | classes.insert(
5 | DISABLED,
6 | style_class! {
7 | filter: Filter::grayscale(1.),
8 | opacity: 0.38,
9 | },
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/widgets/src/layout.rs:
--------------------------------------------------------------------------------
1 | pub mod text_clamp;
2 | pub use text_clamp::*;
3 | mod sized_box;
4 | pub use sized_box::*;
5 | pub mod no_affected_parent_size;
6 | pub use no_affected_parent_size::*;
7 | mod fractionally;
8 | pub use fractionally::*;
9 | mod linear;
10 | pub use linear::*;
11 |
--------------------------------------------------------------------------------
/examples/counter/ci/bundle-windows.toml:
--------------------------------------------------------------------------------
1 | [bundle]
2 | "productName" = "Counter"
3 | "version" = "1.0.0"
4 | "identifier" = "com.ribir.counter"
5 | # Keep CI simple: produce an MSI on Windows
6 | "targets" = ["msi"]
7 | "icon" = ["../Logo.ico"]
8 | "resources" = []
9 | "externalBin" = []
10 |
--------------------------------------------------------------------------------
/examples/counter/ci/bundle-linux.toml:
--------------------------------------------------------------------------------
1 | [bundle]
2 | "productName" = "Counter"
3 | "version" = "1.0.0"
4 | "identifier" = "com.ribir.counter"
5 | # Keep CI simple: produce an AppImage on Linux
6 | "targets" = ["appimage"]
7 | "icon" = ["../Logo.ico"]
8 | "resources" = []
9 | "externalBin" = []
10 |
--------------------------------------------------------------------------------
/examples/counter/ci/bundle-macos.toml:
--------------------------------------------------------------------------------
1 | [bundle]
2 | "productName" = "Counter"
3 | "version" = "1.0.0"
4 | "identifier" = "com.ribir.counter"
5 | # Keep CI simple: only build an app bundle on macOS
6 | "targets" = ["app"]
7 | "icon" = ["../Logo.ico"]
8 | "resources" = []
9 | "externalBin" = []
10 |
--------------------------------------------------------------------------------
/ribir/src/platform.rs:
--------------------------------------------------------------------------------
1 | //! For platform-specific code.
2 |
3 | #[cfg(target_os = "macos")]
4 | mod macos;
5 | #[cfg(target_os = "macos")]
6 | pub use macos::register_platform_app_events_handlers;
7 |
8 | #[cfg(not(target_os = "macos"))]
9 | pub fn register_platform_app_events_handlers() {}
10 |
--------------------------------------------------------------------------------
/gpu/src/wgpu_impl/shaders/clear_texture.wgsl:
--------------------------------------------------------------------------------
1 | @vertex
2 | fn vs_main(@location(0) pos: vec2) -> @builtin(position) vec4 {
3 | return vec4(pos * vec2(2., -2.) + vec2(-1., 1.), 0., 1.);
4 | }
5 |
6 | @fragment
7 | fn fs_main() -> @location(0) vec4 {
8 | return vec4(0., 0., 0., 0.);
9 | }
--------------------------------------------------------------------------------
/themes/material/icons/delete_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/themes/material/icons/grade_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/themes/material/icons/star_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/ribir/src/backends.rs:
--------------------------------------------------------------------------------
1 | #[cfg(feature = "wgpu")]
2 | mod wgpu_backend;
3 | #[cfg(feature = "wgpu")]
4 | pub(crate) use wgpu_backend::WgpuBackend as Backend;
5 |
6 | #[cfg(not(any(feature = "wgpu")))]
7 | mod mock_backend;
8 | #[cfg(not(any(feature = "wgpu")))]
9 | pub(crate) use mock_backend::MockBackend as Backend;
10 |
--------------------------------------------------------------------------------
/themes/ribir_slim/src/slim.rs:
--------------------------------------------------------------------------------
1 | use ribir_core::prelude::*;
2 |
3 | pub const SIZE_16: Size = Size::new(16.0, 16.0);
4 | pub const SIZE_24: Size = Size::new(24.0, 24.0);
5 | pub const SIZE_32: Size = Size::new(32.0, 32.0);
6 | pub const SIZE_48: Size = Size::new(48.0, 48.0);
7 | pub const SIZE_64: Size = Size::new(64.0, 64.0);
8 |
--------------------------------------------------------------------------------
/examples/todos/README.md:
--------------------------------------------------------------------------------
1 | # Todos
2 |
3 | Example of a to-do list application. Showing CURD of states and auto update the view.
4 |
5 | 
6 |
7 | You can run with:
8 |
9 | ``` sh
10 | cargo run -p todos
11 | ```
12 | or run in web:
13 | ``` sh
14 | cargo run-wasm -p todos
15 | ```
--------------------------------------------------------------------------------
/docs/en/understanding_ribir/_category_.json:
--------------------------------------------------------------------------------
1 | {
2 | "label": "Understanding Ribir",
3 | "position": 3,
4 | "link": {
5 | "type": "generated-index",
6 | "description": "This guide will walk you through the key concepts and features of the Ribir framework, helping you to build efficient and effective user interfaces."
7 | }
8 | }
--------------------------------------------------------------------------------
/gpu/src/error.rs:
--------------------------------------------------------------------------------
1 | #[derive(Debug)]
2 | pub enum Error {
3 | /// atlas is full unable to store the texture and the texture is grow to its
4 | /// limit, but the texture is good for store in the atlas if it's not store
5 | /// too many others.
6 | TextureSpaceLimit,
7 | /// The image is too large to good for the atlas store.
8 | LargeImageAvoid,
9 | }
10 |
--------------------------------------------------------------------------------
/themes/material/icons/more_vert_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/pomodoro/static/volume_up.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/themes/material/icons/refresh_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/docs/readme.md:
--------------------------------------------------------------------------------
1 | # Ribir Documentation
2 |
3 | Please place all asset files in the 'assets' subdirectory within the respective language directory. This helps us manage the versions of assets that correspond to the documentation when we build the website.
4 |
5 | Since all assets are linked to the same folder, if you need an image for a specific language, create a new image with the language code as a suffix. Please avoid overwriting the original image.
--------------------------------------------------------------------------------
/core/src/context.rs:
--------------------------------------------------------------------------------
1 | mod painting_ctx;
2 | pub use painting_ctx::PaintingCtx;
3 | mod layout_ctx;
4 | mod visual_ctx;
5 | mod widget_ctx;
6 | pub use layout_ctx::*;
7 | pub use visual_ctx::*;
8 | pub use widget_ctx::*;
9 | pub(crate) mod build_ctx;
10 | pub use build_ctx::BuildCtx;
11 | pub mod app_ctx;
12 | pub use app_ctx::*;
13 | mod build_variant;
14 | #[cfg(feature = "test-utils")]
15 | pub use app_ctx::test_utils;
16 | pub use build_variant::*;
17 |
--------------------------------------------------------------------------------
/themes/material/icons/search_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/geom/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors.workspace = true
3 | categories.workspace = true
4 | description.workspace = true
5 | documentation.workspace = true
6 | edition.workspace = true
7 | homepage.workspace = true
8 | keywords.workspace = true
9 | license.workspace = true
10 | name = "ribir_geom"
11 | readme.workspace = true
12 | repository = "https://github.com/RibirX/Ribir/geom"
13 | version.workspace = true
14 |
15 | [dependencies]
16 | euclid.workspace = true
17 |
--------------------------------------------------------------------------------
/examples/messages/src/lib.rs:
--------------------------------------------------------------------------------
1 | mod messages;
2 | pub use messages::messages;
3 | use ribir::prelude::*;
4 |
5 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)]
6 | pub fn run() {
7 | #[cfg(target_arch = "wasm32")]
8 | std::panic::set_hook(Box::new(console_error_panic_hook::hook));
9 |
10 | App::run(messages)
11 | .with_app_theme(material::purple::light)
12 | .with_size(Size::new(400., 600.))
13 | .with_title("Messages");
14 | }
15 |
--------------------------------------------------------------------------------
/examples/pomodoro/static/volume_off.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/core/src/builtin_widgets/icon_miss.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/themes/material/icons/miss_icon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/painter/src/lib.rs:
--------------------------------------------------------------------------------
1 | #![allow(clippy::needless_lifetimes)]
2 |
3 | //! A 2d logic painter, generate the paint command
4 | pub mod color;
5 | pub mod filter;
6 | mod painter;
7 | pub mod path;
8 | pub mod path_builder;
9 | pub use path::*;
10 | mod text;
11 | pub use text::*;
12 |
13 | pub use crate::{
14 | color::{Color, GradientStop, LightnessTone},
15 | filter::*,
16 | painter::*,
17 | };
18 | pub mod image;
19 | mod style;
20 | pub use style::*;
21 |
22 | pub use crate::image::PixelImage;
23 | mod svg;
24 | pub use svg::Svg;
25 |
--------------------------------------------------------------------------------
/tests/assets/test1.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/macros/src/pipe_macro.rs:
--------------------------------------------------------------------------------
1 | use proc_macro2::TokenStream;
2 | use quote::quote_spanned;
3 | use syn::spanned::Spanned;
4 |
5 | use crate::{error::result_to_token_stream, symbol_process::*, watch_macro::*};
6 |
7 | pub fn gen_code(input: TokenStream, refs_ctx: Option<&mut DollarRefsCtx>) -> TokenStream {
8 | let span = input.span();
9 | let res = process_watch_body(input, refs_ctx).map(|WatchBody { upstream, map_handler }| {
10 | quote_spanned! {span => Pipe::new(#upstream.box_it(), #map_handler) }
11 | });
12 | result_to_token_stream(res)
13 | }
14 |
--------------------------------------------------------------------------------
/ribir/src/backends/mock_backend.rs:
--------------------------------------------------------------------------------
1 | use crate::winit_shell_wnd::WinitBackend;
2 |
3 | pub struct MockBackend;
4 |
5 | impl WinitBackend for MockBackend {
6 | fn new(_: &winit::window::Window) -> Self { Self }
7 |
8 | fn on_resize(&mut self, _: ribir_core::prelude::DeviceSize) {}
9 |
10 | fn begin_frame(&mut self) {}
11 |
12 | fn draw_commands(
13 | &mut self, _: ribir_core::prelude::DeviceRect, _: Vec,
14 | _: ribir_core::prelude::Color,
15 | ) {
16 | }
17 |
18 | fn end_frame(&mut self) {}
19 | }
20 |
--------------------------------------------------------------------------------
/rustfmt.toml:
--------------------------------------------------------------------------------
1 | error_on_line_overflow = true
2 | error_on_unformatted = false
3 | fn_single_line = true
4 | use_small_heuristics = "Max"
5 | tab_spaces = 2
6 | style_edition = "2024"
7 | wrap_comments = true
8 | merge_derives = false
9 |
10 | unstable_features = true
11 | format_code_in_doc_comments = true
12 | format_macro_bodies = true
13 | format_macro_matchers = true
14 | format_strings = true
15 | imports_granularity = "Crate"
16 | group_imports = "StdExternalCrate"
17 | normalize_doc_attributes = true
18 | fn_params_layout = "Compressed"
19 | chain_width = 50
--------------------------------------------------------------------------------
/.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: "cargo" # See documentation for possible values
9 | directory: "/" # Location of package manifests
10 | schedule:
11 | interval: "weekly"
12 |
--------------------------------------------------------------------------------
/cli/template/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Ribir
7 |
12 |
13 |
14 |
15 |
16 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/themes/material/icons/sms_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/themes/material/icons/add_circle_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/themes/material/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors.workspace = true
3 | categories.workspace = true
4 | description.workspace = true
5 | documentation.workspace = true
6 | edition.workspace = true
7 | homepage.workspace = true
8 | keywords.workspace = true
9 | license.workspace = true
10 | name = "ribir_material"
11 | readme.workspace = true
12 | repository = "https://github.com/RibirX/Ribir/themes/material"
13 | version.workspace = true
14 |
15 | [dependencies]
16 | ribir_core = {path = "../../core", version = "0.4.0-alpha.53" }
17 | ribir_widgets = {path = "../../widgets", version = "0.4.0-alpha.53" }
18 |
--------------------------------------------------------------------------------
/ribir/src/lib.rs:
--------------------------------------------------------------------------------
1 | pub use ribir_core as core;
2 | #[cfg(feature = "widgets")]
3 | pub use ribir_widgets as widgets;
4 | pub mod app;
5 | mod backends;
6 |
7 | #[cfg(not(target_arch = "wasm32"))]
8 | pub mod clipboard;
9 | mod winit_shell_wnd;
10 | #[cfg(feature = "material")]
11 | pub use ribir_material as material;
12 |
13 | mod platform;
14 | pub use platform::*;
15 | pub mod prelude {
16 | pub use ribir_core::prelude::*;
17 |
18 | #[cfg(feature = "material")]
19 | pub use super::material;
20 | #[cfg(feature = "widgets")]
21 | pub use super::widgets::prelude::*;
22 | pub use crate::app::*;
23 | }
24 |
--------------------------------------------------------------------------------
/themes/material/icons/more_horiz_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/themes/material/icons/check_circle_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/themes/ribir_slim/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors.workspace = true
3 | categories.workspace = true
4 | description.workspace = true
5 | documentation.workspace = true
6 | edition.workspace = true
7 | homepage.workspace = true
8 | keywords.workspace = true
9 | license.workspace = true
10 | name = "ribir_slim"
11 | readme.workspace = true
12 | repository = "https://github.com/RibirX/Ribir/themes/ribir_slim"
13 | version.workspace = true
14 | publish = false
15 |
16 | [dependencies]
17 | ribir_core = {path = "../../core", version = "0.4.0-alpha.53" }
18 | ribir_widgets = {path = "../../widgets", version = "0.4.0-alpha.53" }
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Generated by Cargo
2 | # will have compiled files and executables
3 | /target/
4 |
5 | # Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
6 | # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
7 | Cargo.lock
8 |
9 | # These are backup files generated by rustfmt
10 | **/*.rs.bk
11 |
12 | .git-old/**
13 |
14 | #Added by cargo
15 | #
16 | #already existing elements were commented out
17 |
18 | /target
19 | #Cargo.lock
20 | .vscode/*
21 |
22 | **/.DS_Store
23 | **/.log/**
24 | /test_cases/**/*_actual.png
25 | /test_cases/**/*_diff.png
--------------------------------------------------------------------------------
/themes/material/icons/cancel_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/algo/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors.workspace = true
3 | categories.workspace = true
4 | description.workspace = true
5 | documentation.workspace = true
6 | edition.workspace = true
7 | homepage.workspace = true
8 | keywords.workspace = true
9 | license.workspace = true
10 | name = "ribir_algo"
11 | readme.workspace = true
12 | repository = "https://github.com/RibirX/Ribir/algo"
13 | version.workspace = true
14 |
15 | [dependencies]
16 | triomphe.workspace = true
17 | ahash.workspace = true
18 | log.workspace = true
19 | serde = {workspace = true, features = ["derive", "rc"]}
20 |
21 | [dev-dependencies]
22 | scoped_threadpool.workspace = true
23 |
--------------------------------------------------------------------------------
/macros/src/distinct_pipe_macro.rs:
--------------------------------------------------------------------------------
1 | use proc_macro2::TokenStream;
2 | use quote::quote_spanned;
3 | use syn::spanned::Spanned;
4 |
5 | use crate::{error::result_to_token_stream, symbol_process::*, watch_macro::*};
6 |
7 | pub fn gen_code(input: TokenStream, refs_ctx: Option<&mut DollarRefsCtx>) -> TokenStream {
8 | let span = input.span();
9 | let res = process_watch_body(input, refs_ctx).map(|WatchBody { upstream, map_handler }| {
10 | quote_spanned! {span =>
11 | Pipe::new(#upstream.box_it(), #map_handler)
12 | .transform(|s| s.distinct_until_changed().box_it())
13 | }
14 | });
15 | result_to_token_stream(res)
16 | }
17 |
--------------------------------------------------------------------------------
/tests/benches/widgets_bench.rs:
--------------------------------------------------------------------------------
1 | use criterion::{Bencher, Criterion, criterion_group, criterion_main};
2 | use ribir::{core::test_helper::*, prelude::*};
3 |
4 | fn widget_bench(b: &mut Bencher, w: GenWidget) {
5 | let wnd = TestWindow::from_widget(w);
6 | b.iter(|| wnd.draw_frame());
7 | AppCtx::remove_wnd(wnd.id())
8 | }
9 |
10 | fn widgets_bench_one_by_one(c: &mut Criterion) {
11 | c.bench_function("checkbox", |b| {
12 | widget_bench(b, fn_widget!(@Checkbox { checked: true, indeterminate: true }).r_into());
13 | });
14 | }
15 |
16 | criterion_group!(widgets_benches, widgets_bench_one_by_one);
17 | criterion_main!(widgets_benches);
18 |
--------------------------------------------------------------------------------
/cli/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "cli"
3 | version = "0.4.0-alpha.53"
4 | edition = "2021"
5 | publish = false
6 |
7 | [dependencies]
8 | xshell = "0.2.3"
9 | clap = {version = "4.5.4", features = ["cargo", "derive"] }
10 | anyhow = "1.0"
11 | fs_extra = "1.3.0"
12 | notify-debouncer-mini = "0.6.0"
13 | gitignore = "1.0.8"
14 | tauri-bundler.workspace = true
15 | tauri-utils.workspace = true
16 | serde_json.workspace = true
17 | serde = {workspace = true, features = ["derive"]}
18 | serde-value.workspace = true
19 | serde_with.workspace = true
20 | toml.workspace = true
21 | log = { workspace = true, features = ["kv", "kv_std"]}
22 | env_logger.workspace = true
23 |
--------------------------------------------------------------------------------
/themes/material/icons/favorite_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: enhancement
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/core/src/animation/progress.rs:
--------------------------------------------------------------------------------
1 | #[derive(PartialEq, Copy, Clone, Debug)]
2 | pub enum AnimateProgress {
3 | Dismissed,
4 | Between(f32),
5 | Finish,
6 | }
7 |
8 | impl AnimateProgress {
9 | pub fn value(&self) -> f32 {
10 | match self {
11 | AnimateProgress::Dismissed => 0.,
12 | AnimateProgress::Between(val) => *val,
13 | AnimateProgress::Finish => 1.,
14 | }
15 | }
16 |
17 | #[inline]
18 | pub fn is_dismissed(&self) -> bool { matches!(self, AnimateProgress::Dismissed) }
19 |
20 | #[inline]
21 | pub fn is_between(&self) -> bool { matches!(self, AnimateProgress::Between(_)) }
22 |
23 | #[inline]
24 | pub fn is_finish(&self) -> bool { matches!(self, AnimateProgress::Finish) }
25 | }
26 |
--------------------------------------------------------------------------------
/core/src/builtin_widgets/void.rs:
--------------------------------------------------------------------------------
1 | use crate::prelude::*;
2 |
3 | /// A widget that represents an empty node in the widget tree.
4 | ///
5 | /// This widget is used when you need a placeholder widget that doesn't render
6 | /// anything and doesn't accept children. It's useful for conditional rendering
7 | /// or as a neutral widget in compositions.
8 | ///
9 | /// # Example
10 | ///
11 | /// ```rust no_run
12 | /// use ribir::prelude::*;
13 | ///
14 | /// fn_widget! {
15 | /// @Void {}
16 | /// };
17 | /// ```
18 | #[derive(Declare)]
19 | pub struct Void;
20 |
21 | impl Render for Void {
22 | fn perform_layout(&self, clamp: BoxClamp, _: &mut LayoutCtx) -> Size { clamp.min }
23 |
24 | fn paint(&self, _: &mut PaintingCtx) {}
25 | }
26 |
--------------------------------------------------------------------------------
/gpu/src/wgpu_impl/shaders/copy_texture.wgsl:
--------------------------------------------------------------------------------
1 | struct VertexOutput {
2 | @builtin(position) pos: vec4,
3 | @location(0) tex_pos: vec2,
4 | }
5 |
6 | @vertex
7 | fn vs_main(@location(0) input_pos: vec2, @location(1) tex: vec2) -> VertexOutput {
8 | var output: VertexOutput;
9 | let pos = input_pos * vec2(2., -2.) + vec2(-1., 1.);
10 | output.pos = vec4(pos, 0.0, 1.0);
11 | output.tex_pos = tex;
12 | return output;
13 | }
14 |
15 | @group(0) @binding(0)
16 | var texture: texture_2d;
17 | @group(0) @binding(1)
18 | var tex_sampler: sampler;
19 |
20 |
21 | @fragment
22 | fn fs_main(@location(0) tex_pos: vec2) -> @location(0) vec4 {
23 | return textureSample(texture, tex_sampler, tex_pos);
24 | }
--------------------------------------------------------------------------------
/themes/material/icons/info_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/todos/src/lib.rs:
--------------------------------------------------------------------------------
1 | mod todos;
2 | use ribir::prelude::*;
3 | mod ui;
4 | pub use ui::todos;
5 |
6 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)]
7 | pub fn run() {
8 | #[cfg(target_arch = "wasm32")]
9 | std::panic::set_hook(Box::new(console_error_panic_hook::hook));
10 |
11 | App::run(todos)
12 | .with_app_theme(material::purple::light)
13 | .with_title("Todos");
14 | }
15 |
16 | #[cfg(test)]
17 | mod tests {
18 | use ribir::{core::test_helper::*, material as ribir_material};
19 | use ribir_dev_helper::*;
20 |
21 | use super::*;
22 |
23 | widget_image_tests!(
24 | todos,
25 | WidgetTester::new(todos)
26 | .with_wnd_size(Size::new(400., 640.))
27 | .with_comparison(0.0002)
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/core/src/events/device_id.rs:
--------------------------------------------------------------------------------
1 | pub trait DeviceId: Send {
2 | fn as_any(&self) -> &dyn std::any::Any;
3 | fn is_same_device(&self, other: &dyn DeviceId) -> bool;
4 | fn clone_boxed(&self) -> Box;
5 | }
6 |
7 | #[derive(Copy, Clone, PartialEq, Eq, Hash)]
8 | pub struct DummyDeviceId;
9 |
10 | impl DeviceId for DummyDeviceId {
11 | fn as_any(&self) -> &dyn std::any::Any { self }
12 | fn is_same_device(&self, other: &dyn DeviceId) -> bool {
13 | other
14 | .as_any()
15 | .downcast_ref::()
16 | .is_some_and(|this| this == self)
17 | }
18 |
19 | fn clone_boxed(&self) -> Box { Box::new(*self) }
20 | }
21 |
22 | impl Clone for Box {
23 | fn clone(&self) -> Box { self.clone_boxed() }
24 | }
25 |
--------------------------------------------------------------------------------
/core/src/animation.rs:
--------------------------------------------------------------------------------
1 | pub mod easing;
2 | mod progress;
3 | mod transition;
4 | pub use easing::Easing;
5 | pub use progress::AnimateProgress;
6 | pub use transition::*;
7 | mod animate;
8 | pub use animate::*;
9 | mod lerp;
10 | pub use lerp::Lerp;
11 | mod animate_state;
12 | pub use animate_state::*;
13 | mod stagger;
14 | pub use stagger::Stagger;
15 | mod keyframes;
16 | pub use keyframes::*;
17 |
18 | /// Trait to describe how to control the animation.
19 | pub trait Animation {
20 | /// Start the animation.
21 | fn run(&self);
22 | /// Stop the animation if it is running, otherwise do nothing.
23 | fn stop(&self);
24 | /// Check if the animation is running.
25 | fn is_running(&self) -> bool;
26 | /// clone the animation.
27 | fn box_clone(&self) -> Box;
28 | }
29 |
--------------------------------------------------------------------------------
/examples/wordle_game/src/lib.rs:
--------------------------------------------------------------------------------
1 | mod ui;
2 | pub mod wordle;
3 | use ribir::prelude::*;
4 | pub use ui::wordle_game;
5 |
6 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)]
7 | pub fn run() {
8 | #[cfg(target_arch = "wasm32")]
9 | std::panic::set_hook(Box::new(console_error_panic_hook::hook));
10 |
11 | App::run(wordle_game)
12 | .with_app_theme(material::purple::light)
13 | .with_size(Size::new(700., 620.));
14 | }
15 |
16 | #[cfg(test)]
17 | mod tests {
18 | use ribir::{core::test_helper::*, material as ribir_material};
19 | use ribir_dev_helper::*;
20 |
21 | use super::*;
22 |
23 | widget_image_tests!(
24 | wordle_game,
25 | WidgetTester::new(wordle_game)
26 | .with_wnd_size(Size::new(700., 620.))
27 | .with_comparison(0.008)
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/examples/storybook/src/lib.rs:
--------------------------------------------------------------------------------
1 | mod storybook;
2 | use ribir::prelude::*;
3 | pub use storybook::storybook;
4 |
5 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)]
6 | pub fn run() {
7 | #[cfg(target_arch = "wasm32")]
8 | std::panic::set_hook(Box::new(console_error_panic_hook::hook));
9 |
10 | App::run(storybook)
11 | .with_app_theme(material::purple::light)
12 | .with_title("Storybook")
13 | .with_size(Size::new(1024., 768.));
14 | }
15 |
16 | #[cfg(test)]
17 | mod tests {
18 | use ribir::{core::test_helper::*, material as ribir_material};
19 | use ribir_dev_helper::*;
20 |
21 | use super::*;
22 |
23 | widget_image_tests!(
24 | storybook,
25 | WidgetTester::new(storybook)
26 | .with_wnd_size(Size::new(1024., 768.))
27 | .with_comparison(0.001)
28 | );
29 | }
30 |
--------------------------------------------------------------------------------
/macros/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors.workspace = true
3 | categories.workspace = true
4 | description.workspace = true
5 | documentation.workspace = true
6 | edition.workspace = true
7 | homepage.workspace = true
8 | keywords.workspace = true
9 | license.workspace = true
10 | name = "ribir_macros"
11 | readme.workspace = true
12 | repository = "https://github.com/RibirX/Ribir/macros"
13 | version.workspace = true
14 |
15 | [lib]
16 | proc-macro = true
17 |
18 | [dependencies]
19 | ahash.workspace = true
20 | bitflags.workspace = true
21 | proc-macro2.workspace = true
22 | quote.workspace = true
23 | ribir_painter = {path = "../painter", version = "0.4.0-alpha.53" }
24 | smallvec = { workspace = true, features= ["drain_filter"] }
25 | syn = { workspace = true, features = ["fold", "full", "extra-traits"]}
26 | heck.workspace = true
27 |
--------------------------------------------------------------------------------
/tests/assets/fill_with_gradient.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/widgets/src/lib.rs:
--------------------------------------------------------------------------------
1 | pub mod avatar;
2 | pub mod badge;
3 | pub mod buttons;
4 | pub mod checkbox;
5 | pub mod common_widget;
6 | pub mod divider;
7 | pub mod grid_view;
8 | pub mod icon;
9 | pub mod input;
10 | pub mod label;
11 | pub mod layout;
12 | pub mod list;
13 | pub mod menu;
14 | pub mod path;
15 | pub mod progress;
16 | pub mod radio;
17 | pub mod router;
18 | pub mod scrollbar;
19 | pub mod select_region;
20 | pub mod slider;
21 | pub mod switch;
22 | pub mod tabs;
23 |
24 | pub mod transform_box;
25 | pub mod prelude {
26 | pub use super::{
27 | avatar::*, badge::*, buttons::*, checkbox::*, common_widget::*, divider::*, grid_view::*,
28 | icon::*, input::*, label::*, layout::*, list::*, menu::*, path::*, progress::*, radio::*,
29 | router::*, scrollbar::*, select_region::*, slider::*, switch::*, tabs::*, transform_box::*,
30 | };
31 | }
32 |
--------------------------------------------------------------------------------
/dev-helper/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors.workspace = true
3 | categories.workspace = true
4 | description.workspace = true
5 | documentation.workspace = true
6 | edition.workspace = true
7 | homepage.workspace = true
8 | keywords.workspace = true
9 | license.workspace = true
10 | name = "ribir_dev_helper"
11 | repository = "https://github.com/RibirX/Ribir/test-helper"
12 | version.workspace = true
13 |
14 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
15 |
16 | [dependencies]
17 | futures.workspace = true
18 | ribir_geom = {path = "../geom", version = "0.4.0-alpha.53" }
19 | ribir_gpu = {path = "../gpu", version = "0.4.0-alpha.53" }
20 | ribir_painter = {path = "../painter", features = ["png"], version = "0.4.0-alpha.53" }
21 | image.workspace = true
22 | dssim-core.workspace = true
23 |
24 | [dev-dependencies]
25 | colored.workspace = true
26 |
--------------------------------------------------------------------------------
/themes/material/icons/account_circle_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/examples/wordle_game/README.md:
--------------------------------------------------------------------------------
1 | # Wordle Game
2 |
3 | Example of a wordle game.
4 |
5 | You can run with:
6 |
7 | ``` sh
8 | cargo run -p wordle_game
9 | ```
10 |
11 | or run in web:
12 | ``` sh
13 | cargo run-wasm -p wordle_game
14 | ```
15 |
16 | ## How to play
17 |
18 | You have to guess the hidden word in 5 tries and the color of the letters hints how close you are.
19 | To start the game, just enter the word and press 'Enter' to submit, for example:
20 |
21 |
22 |
23 | ``` text
24 | Pink color like O and T, hint that not the letter in the target word at all.
25 | Light orange color like R, hint that the letter in the word but in the wrong spot.
26 | Green color like B and I, hint that the letter in the word and in the correct spot.
27 | ```
28 |
29 | Another try to find matching letters in the target word.
30 |
31 |
32 |
--------------------------------------------------------------------------------
/static/logo.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tests/benches/text_bench.rs:
--------------------------------------------------------------------------------
1 | use criterion::{Criterion, criterion_group, criterion_main};
2 | use font_db::GlyphBaseline;
3 | use ribir_painter::{shaper::*, *};
4 |
5 | fn shape_1k(c: &mut Criterion) {
6 | let mut shaper = TextShaper::new(<_>::default());
7 | shaper.font_db().borrow_mut().load_system_fonts();
8 |
9 | let ids = shaper
10 | .font_db()
11 | .borrow_mut()
12 | .select_all_match(&FontFace {
13 | families: Box::new([FontFamily::Serif, FontFamily::Cursive]),
14 | ..<_>::default()
15 | });
16 |
17 | c.bench_function("shape_1k", |b| {
18 | b.iter(|| {
19 | // clean cache
20 | shaper.end_frame();
21 | shaper.end_frame();
22 |
23 | let str = include_str!("../../LICENSE").into();
24 | shaper.shape_text(&str, &ids, TextDirection::LeftToRight, GlyphBaseline::Alphabetic)
25 | })
26 | });
27 | }
28 |
29 | criterion_group!(text_benches, shape_1k);
30 | criterion_main!(text_benches);
31 |
--------------------------------------------------------------------------------
/themes/material/src/classes/avatar_cls.rs:
--------------------------------------------------------------------------------
1 | use ribir_core::prelude::*;
2 | use ribir_widgets::avatar::*;
3 |
4 | use crate::md;
5 |
6 | pub(super) fn init(classes: &mut Classes) {
7 | named_styles_impl!( base_container => {
8 | clamp: BoxClamp::fixed_size(md::SIZE_40),
9 | radius: md::RADIUS_20,
10 | });
11 |
12 | classes.insert(AVATAR_WIDGET_CONTAINER, base_container);
13 | classes.insert(AVATAR_WIDGET, empty_cls);
14 | classes.insert(
15 | AVATAR_LABEL_CONTAINER,
16 | class_multi_impl![
17 | style_class! { background: BuildCtx::color().into_container_color(BuildCtx::get()) },
18 | base_container
19 | ],
20 | );
21 | classes.insert(
22 | AVATAR_LABEL,
23 | style_class! {
24 | foreground: BuildCtx::color().on_this_container_color(BuildCtx::get()),
25 | text_style: TypographyTheme::of(BuildCtx::get()).title_medium.text.clone(),
26 | h_align: HAlign::Center,
27 | v_align: VAlign::Center,
28 | },
29 | );
30 | }
31 |
--------------------------------------------------------------------------------
/dev-helper/readme.md:
--------------------------------------------------------------------------------
1 | # Development Helper
2 |
3 | This library offers macros to facilitate testing for `Ribir`.
4 |
5 | ## Dependencies
6 |
7 | To utilize these macros, include `paste` and `ribir_dev_helper` in the `[dev-dependencies]` section of your `Cargo.toml`. For more details, refer to the macro documentation.
8 |
9 | ## Test Case Files
10 |
11 | These macros may require reading files for testing. All such files are sourced from the `test_cases` directory located at the root of your workspace.
12 |
13 | Use the `RIBIR_IMG_TEST=overwrite` environment variable to overwrite or generate the files. For instance, `RIBIR_IMG_TEST=overwrite cargo test` can be used to overwrite all test case files. For a specific test, use `RIBIR_IMG_TEST=overwrite cargo test -- test_name`.
14 |
15 | For image tests, if the actual image differs from the expected one, both the actual image and the difference image are saved alongside the expected image. The difference image represents the discrepancies between the actual and expected images.
--------------------------------------------------------------------------------
/examples/wordle_game/Cargo.toml:
--------------------------------------------------------------------------------
1 |
2 | [package]
3 | authors.workspace = true
4 | categories.workspace = true
5 | description.workspace = true
6 | documentation.workspace = true
7 | edition.workspace = true
8 | homepage.workspace = true
9 | keywords.workspace = true
10 | license.workspace = true
11 | name = "wordle_game"
12 | publish = false
13 | version.workspace = true
14 |
15 | [dependencies]
16 | paste.workspace = true
17 | ribir = {path = "../../ribir", features = ["material", "widgets"]}
18 | csv = "1.3.0"
19 | rand = "0.9.1"
20 | getrandom-v3 = { workspace = true }
21 |
22 | [target.'cfg(target_arch = "wasm32")'.dependencies]
23 | console_error_panic_hook = "0.1.6"
24 | wasm-bindgen = "0.2.92"
25 |
26 | [dev-dependencies]
27 | ribir_dev_helper = {path = "../../dev-helper"}
28 | ribir_slim = { path = "../../themes/ribir_slim" }
29 | ribir_core = { path = "../../core", features = ["test-utils"]}
30 |
31 | [features]
32 | wgpu = ["ribir/wgpu"]
33 |
34 |
35 | [lib]
36 | crate-type = ["cdylib", "rlib"]
37 | path = "src/lib.rs"
38 |
39 |
--------------------------------------------------------------------------------
/examples/storybook/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors.workspace = true
3 | categories.workspace = true
4 | description.workspace = true
5 | documentation.workspace = true
6 | edition.workspace = true
7 | homepage.workspace = true
8 | keywords.workspace = true
9 | license.workspace = true
10 | name = "storybook"
11 | publish = false
12 | version.workspace = true
13 |
14 | [dependencies]
15 | paste.workspace = true
16 | # we disable `default-features`, because we want more control over testing.
17 | ribir = {path = "../../ribir", features = ["material", "widgets"]}
18 | webbrowser = "1.0.5"
19 |
20 | [dev-dependencies]
21 | ribir_dev_helper = {path = "../../dev-helper"}
22 | ribir_slim = { path = "../../themes/ribir_slim" }
23 | ribir_core = { path = "../../core", features = ["test-utils"]}
24 |
25 | [target.'cfg(target_arch = "wasm32")'.dependencies]
26 | console_error_panic_hook = "0.1.6"
27 | wasm-bindgen = "0.2.92"
28 |
29 |
30 | [features]
31 | wgpu = ["ribir/wgpu"]
32 |
33 | [lib]
34 | crate-type = ["cdylib", "rlib"]
35 | path = "src/lib.rs"
36 |
--------------------------------------------------------------------------------
/macros/src/util.rs:
--------------------------------------------------------------------------------
1 | use syn::{Data, spanned::Spanned};
2 |
3 | pub fn data_struct_unwrap<'a>(
4 | data: &'a mut syn::Data, derive_trait: &'static str,
5 | ) -> syn::Result<&'a mut syn::DataStruct> {
6 | match data {
7 | Data::Struct(stt) => Ok(stt),
8 | Data::Enum(e) => {
9 | let err_str = format!("`{derive_trait}` not support for Enum");
10 | Err(syn::Error::new(e.enum_token.span(), err_str))
11 | }
12 | Data::Union(u) => {
13 | let err_str = format!("`{derive_trait}` not support for Union");
14 | Err(syn::Error::new(u.union_token.span(), err_str))
15 | }
16 | }
17 | }
18 |
19 | pub fn doc_attr(field: &syn::Field) -> Option<&syn::Attribute> {
20 | field
21 | .attrs
22 | .iter()
23 | .find(|attr| matches!(&attr.meta, syn::Meta::NameValue(nv) if nv.path.is_ident("doc")))
24 | }
25 |
26 | pub fn declare_init_method(member: &syn::Ident) -> syn::Ident {
27 | if member.to_string().starts_with("on_") {
28 | member.clone()
29 | } else {
30 | syn::Ident::new(&format!("with_{}", member), member.span())
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/examples/messages/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors.workspace = true
3 | categories.workspace = true
4 | description.workspace = true
5 | documentation.workspace = true
6 | edition.workspace = true
7 | homepage.workspace = true
8 | keywords.workspace = true
9 | license.workspace = true
10 | name = "messages"
11 | publish = false
12 | version.workspace = true
13 |
14 | [dependencies]
15 | paste.workspace = true
16 | # we disable `default-features`, because we want more control over testing.
17 | ribir = {path = "../../ribir", features = ["material", "widgets"]}
18 | ribir_slim = { path = "../../themes/ribir_slim" }
19 |
20 | [target.'cfg(target_arch = "wasm32")'.dependencies]
21 | console_error_panic_hook = "0.1.6"
22 | wasm-bindgen = "0.2.92"
23 |
24 | [dev-dependencies]
25 | ribir_dev_helper = {path = "../../dev-helper"}
26 | ribir_core = { path = "../../core", features = ["test-utils"]}
27 |
28 | [features]
29 | wgpu = ["ribir/wgpu"]
30 |
31 |
32 | [lib]
33 | crate-type = ["cdylib", "rlib"]
34 | path = "src/lib.rs"
35 |
36 | [package.metadata.wasm-pack.profile.release]
37 | wasm-opt = false
38 |
--------------------------------------------------------------------------------
/examples/counter/src/lib.rs:
--------------------------------------------------------------------------------
1 | use ribir::prelude::*;
2 |
3 | pub fn counter(cnt: &'static Stateful) -> Widget<'static> {
4 | button! {
5 | h_align: HAlign::Center,
6 | v_align: VAlign::Center,
7 | on_tap: move |_| *$write(cnt) += 1,
8 | @pipe!($read(cnt).to_string())
9 | }
10 | .into_widget()
11 | }
12 |
13 | #[cfg_attr(target_arch = "wasm32", wasm_bindgen::prelude::wasm_bindgen)]
14 | pub fn run() {
15 | #[cfg(target_arch = "wasm32")]
16 | std::panic::set_hook(Box::new(console_error_panic_hook::hook));
17 |
18 | App::run_with_data(|| Stateful::new(0), counter)
19 | .with_app_theme(material::purple::light)
20 | .with_size(Size::new(320., 240.))
21 | .with_title("Counter");
22 | }
23 |
24 | #[cfg(test)]
25 | mod tests {
26 | use ribir::{core::test_helper::*, material as ribir_material};
27 | use ribir_dev_helper::*;
28 |
29 | use super::*;
30 |
31 | widget_image_tests!(
32 | counter,
33 | WidgetTester::new_with_data(Stateful::new(0), counter)
34 | .with_wnd_size(Size::new(320., 240.))
35 | .with_comparison(0.0001)
36 | );
37 | }
38 |
--------------------------------------------------------------------------------
/.github/workflows/dispatch-other-repo.yml:
--------------------------------------------------------------------------------
1 | name: "Call Website To Sync Docs"
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | branches:
7 | - master
8 | - release-*
9 | jobs:
10 | dispatch:
11 | # Prevent this job from running on forked repositories
12 | if: github.repository == 'RibirX/Ribir'
13 | runs-on: ubuntu-latest
14 | steps:
15 | - uses: actions/github-script@v7
16 | with:
17 | github-token: ${{ secrets.RIBIR_RELEASE }}
18 | script: |-
19 | await github.rest.actions.createWorkflowDispatch({
20 | owner: 'RibirX',
21 | repo: 'ribir-website',
22 | workflow_id: 'sync-docs.yml',
23 | ref: 'main',
24 | inputs: {
25 | branch_ref: "${{ github.ref }}"
26 | },
27 | }).catch(error => error).then(response => {
28 | core.debug(response);
29 | if (response.status !== 204) {
30 | core.setFailed(`create workflow_dispatch received status code ${response.status}`);
31 | }
32 | });
33 |
--------------------------------------------------------------------------------
/examples/todos/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors.workspace = true
3 | categories.workspace = true
4 | description.workspace = true
5 | documentation.workspace = true
6 | edition.workspace = true
7 | homepage.workspace = true
8 | keywords.workspace = true
9 | license.workspace = true
10 | name = "todos"
11 | publish = false
12 | version.workspace = true
13 |
14 | [dependencies]
15 | paste.workspace = true
16 | # we disable `default-features`, because we want more control over testing.
17 | ribir = {path = "../../ribir", features = ["material", "widgets"]}
18 | serde = {workspace = true, features = ["derive"]}
19 | serde_json = {workspace = true}
20 |
21 | [target.'cfg(target_arch = "wasm32")'.dependencies]
22 | console_error_panic_hook = "0.1.6"
23 | wasm-bindgen = "0.2.92"
24 |
25 |
26 | [dev-dependencies]
27 | ribir_slim = { path = "../../themes/ribir_slim" }
28 | ribir_dev_helper = {path = "../../dev-helper"}
29 | ribir_core = { path = "../../core", features = ["test-utils"]}
30 |
31 | [features]
32 | wgpu = ["ribir/wgpu"]
33 |
34 |
35 | [lib]
36 | crate-type = ["cdylib", "rlib"]
37 | path = "src/lib.rs"
38 |
39 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) RibirX
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 |
--------------------------------------------------------------------------------
/themes/material/src/classes.rs:
--------------------------------------------------------------------------------
1 | use ribir_core::prelude::Classes;
2 |
3 | mod avatar_cls;
4 | mod badge_cls;
5 | mod buttons_cls;
6 | mod checkbox_cls;
7 | mod disabled_cls;
8 | mod divider_cls;
9 | mod input_cls;
10 | mod list_cls;
11 | mod menu_cls;
12 | mod progress_cls;
13 | mod radio_cls;
14 | mod scrollbar_cls;
15 | mod slider_cls;
16 | mod switch_cls;
17 | mod tabs_cls;
18 | mod tooltips_cls;
19 |
20 | pub fn initd_classes() -> Classes {
21 | let mut classes = Classes::default();
22 |
23 | buttons_cls::init(&mut classes);
24 | scrollbar_cls::init(&mut classes);
25 | radio_cls::init(&mut classes);
26 | progress_cls::init(&mut classes);
27 | checkbox_cls::init(&mut classes);
28 | tooltips_cls::init(&mut classes);
29 | slider_cls::init(&mut classes);
30 | input_cls::init(&mut classes);
31 | divider_cls::init(&mut classes);
32 | menu_cls::init(&mut classes);
33 | tabs_cls::init(&mut classes);
34 | disabled_cls::init(&mut classes);
35 | avatar_cls::init(&mut classes);
36 | list_cls::init(&mut classes);
37 | switch_cls::init(&mut classes);
38 | badge_cls::init(&mut classes);
39 |
40 | classes
41 | }
42 |
--------------------------------------------------------------------------------
/examples/pomodoro/static/pin.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/themes/material/src/classes/tooltips_cls.rs:
--------------------------------------------------------------------------------
1 | use ribir_core::prelude::*;
2 |
3 | use crate::md;
4 |
5 | pub(super) fn init(classes: &mut Classes) {
6 | classes.insert(TOOLTIPS, |w| {
7 | fn_widget! {
8 | let mut w = FatObj::new(w);
9 | let mut w = @FatObj {
10 | background: Palette::of(BuildCtx::get()).inverse_surface(),
11 | margin: EdgeInsets::only_bottom(4.),
12 | radius: Radius::all(4.),
13 | @(w) {
14 | margin: EdgeInsets::new(4., 8., 4., 8.),
15 | foreground: Palette::of(BuildCtx::get()).inverse_on_surface(),
16 | v_align: VAlign::Center,
17 | h_align: HAlign::Center,
18 | }
19 | };
20 | let animate = w.opacity()
21 | .transition(EasingTransition{
22 | easing: md::easing::STANDARD_ACCELERATE,
23 | duration: md::easing::duration::SHORT2
24 | }.box_it());
25 | @(w) {
26 | keep_alive: pipe!($read(animate).is_running() || *$read(w.opacity()) != 0.),
27 | on_disposed: move |_| {
28 | *$write(w.opacity()) = 0.;
29 | }
30 | }
31 | }
32 | .into_widget()
33 | });
34 | }
35 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | ## Purpose of this Pull Request
2 |
3 | *Please briefly describe what this Pull Request is aiming to achieve.*
4 |
5 | ## Checklist Before Merging
6 |
7 | Please ensure the following are completed before merging:
8 | - [ ] If this is linked to an issue, include the link in your description.
9 | - [ ] If you've made changes to the code or documentation, make sure these are updated in the `CHANGELOG.md` file.
10 | - [ ] If you've introduced any break changes, briefly describe them in the `Breaking` section of the `CHANGELOG.md` file.
11 |
12 | ## Additional Information
13 |
14 | **The bot will replace `#pr` in `CHANGELOG.md` with your pull request number. If your branch is out of sync, use `git pull --rebase` to update it.**
15 |
16 | If you're unsure about which branch to submit your Pull Request to, or when it will be released after being merged, please refer to our [Release Guide](https://github.com/RibirX/Ribir/blob/master/RELEASE.md).
17 |
18 | If you're working on a widget and need help writing test cases, we have some macros that can assist you. Please refer to the [Ribir Dev Helper](https://docs.rs/ribir_dev_helper) documentation.
--------------------------------------------------------------------------------
/core/src/builtin_widgets/painting_style.rs:
--------------------------------------------------------------------------------
1 | use crate::prelude::*;
2 |
3 | /// A widget that sets the strategies for painting shapes and paths . It's can
4 | /// be inherited by its descendants.
5 | #[derive(Default)]
6 | pub struct PaintingStyleWidget {
7 | pub painting_style: PaintingStyle,
8 | }
9 |
10 | impl Declare for PaintingStyleWidget {
11 | type Builder = FatObj<()>;
12 | #[inline]
13 | fn declarer() -> Self::Builder { FatObj::new(()) }
14 | }
15 |
16 | impl<'c> ComposeChild<'c> for PaintingStyleWidget {
17 | type Child = Widget<'c>;
18 |
19 | fn compose_child(this: impl StateWriter, child: Self::Child) -> Widget<'c> {
20 | Providers::new([Self::into_provider(this)]).with_child(child)
21 | }
22 | }
23 |
24 | impl PaintingStyleWidget {
25 | pub fn into_provider(this: impl StateWriter) -> Provider {
26 | match this.try_into_value() {
27 | Ok(this) => Provider::new(this.painting_style),
28 | Err(this) => Provider::writer(
29 | this.part_writer(PartialId::any(), |w| PartMut::new(&mut w.painting_style)),
30 | Some(DirtyPhase::LayoutSubtree),
31 | ),
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/core/src/events/listener_impl_helper.rs:
--------------------------------------------------------------------------------
1 | #[macro_export]
2 | macro_rules! impl_common_event_deref {
3 | ($event_name:ident) => {
4 | impl std::ops::Deref for $event_name {
5 | type Target = CommonEvent;
6 |
7 | #[inline]
8 | fn deref(&self) -> &Self::Target { &self.common }
9 | }
10 |
11 | impl std::ops::DerefMut for $event_name {
12 | #[inline]
13 | fn deref_mut(&mut self) -> &mut Self::Target { &mut self.common }
14 | }
15 |
16 | impl std::borrow::Borrow for $event_name {
17 | #[inline]
18 | fn borrow(&self) -> &CommonEvent { &self.common }
19 | }
20 |
21 | impl std::borrow::BorrowMut for $event_name {
22 | #[inline]
23 | fn borrow_mut(&mut self) -> &mut CommonEvent { &mut self.common }
24 | }
25 |
26 | impl AsRef<$crate::prelude::ProviderCtx> for $event_name {
27 | fn as_ref(&self) -> &$crate::prelude::ProviderCtx { self.common.as_ref() }
28 | }
29 |
30 | impl AsMut<$crate::prelude::ProviderCtx> for $event_name {
31 | fn as_mut(&mut self) -> &mut $crate::prelude::ProviderCtx { self.common.as_mut() }
32 | }
33 | };
34 | }
35 |
--------------------------------------------------------------------------------
/gpu/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors.workspace = true
3 | categories.workspace = true
4 | description.workspace = true
5 | documentation.workspace = true
6 | edition.workspace = true
7 | homepage.workspace = true
8 | keywords.workspace = true
9 | license.workspace = true
10 | name = "ribir_gpu"
11 | readme.workspace = true
12 | repository = "https://github.com/RibirX/Ribir/gpu"
13 | version.workspace = true
14 |
15 | [dependencies]
16 | ahash.workspace = true
17 | tokio = {workspace = true, optional = true, features=["sync"]}
18 | guillotiere.workspace = true
19 | log.workspace = true
20 | rayon.workspace = true
21 | ribir_algo = {path = "../algo", version = "0.4.0-alpha.53" }
22 | ribir_geom = {path = "../geom", version = "0.4.0-alpha.53" }
23 | ribir_painter = {path = "../painter", features = ["tessellation"], version = "0.4.0-alpha.53" }
24 | slab = "0.4.9"
25 | wgpu = {workspace = true, optional = true}
26 | zerocopy = {workspace=true, features = ["derive"]}
27 |
28 | [dev-dependencies]
29 | paste.workspace = true
30 | ribir_dev_helper = {path = "../dev-helper"}
31 | futures.workspace = true
32 |
33 | [features]
34 | default = ["wgpu"]
35 | wgpu = ["dep:wgpu", "tokio"]
36 |
--------------------------------------------------------------------------------
/themes/material/icons/settings_FILL0_wght400_GRAD0_opsz48.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/widgets/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors.workspace = true
3 | categories.workspace = true
4 | description.workspace = true
5 | documentation.workspace = true
6 | edition.workspace = true
7 | homepage.workspace = true
8 | keywords.workspace = true
9 | license.workspace = true
10 | name = "ribir_widgets"
11 | readme.workspace = true
12 | repository = "https://github.com/RibirX/Ribir/widgets"
13 | version.workspace = true
14 |
15 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
16 |
17 | [dependencies]
18 | lyon_algorithms.workspace = true
19 | lyon_path.workspace = true
20 | ribir_core = {path = "../core", version = "0.4.0-alpha.53" }
21 | ribir_geom = {path = "../geom", version = "0.4.0-alpha.53" }
22 | unicode-segmentation.workspace = true
23 | thiserror.workspace = true
24 | ahash.workspace = true
25 |
26 | [dev-dependencies]
27 | paste.workspace = true
28 | winit.workspace = true
29 | ribir_core = { path = "../core", features=["test-utils"] }
30 | ribir_dev_helper = {path = "../dev-helper"}
31 | ribir_material = {path = "../themes/material"}
32 | ribir_slim = {path = "../themes/ribir_slim"}
33 | ribir = { path = "../ribir", features = ["material"] }
34 |
--------------------------------------------------------------------------------
/macros/src/fn_widget_macro.rs:
--------------------------------------------------------------------------------
1 | use proc_macro2::TokenStream;
2 | use quote::quote;
3 |
4 | use crate::{
5 | error::result_to_token_stream,
6 | symbol_process::{DollarRefsCtx, symbol_to_macro},
7 | watch_macro::BodyExpr,
8 | };
9 |
10 | pub(crate) fn gen_code(input: TokenStream, ctx: Option<&mut DollarRefsCtx>) -> TokenStream {
11 | let res = symbol_to_macro(input).and_then(|input| {
12 | let body = syn::parse2::(input)?;
13 | let (stmts, refs) = if let Some(ctx) = ctx {
14 | ctx.new_dollar_scope(None);
15 | let stmts = body.fold(ctx).0;
16 | let refs = ctx.pop_dollar_scope(false);
17 | (stmts, refs)
18 | } else {
19 | let mut ctx = DollarRefsCtx::top_level();
20 | let stmts = body.fold(&mut ctx).0;
21 | let refs = ctx.pop_dollar_scope(false);
22 |
23 | (stmts, refs)
24 | };
25 | if !refs.is_empty() {
26 | Ok(quote! {{
27 | #refs
28 | let f = move || { #(#stmts)* };
29 | FnWidget::new(f)
30 | }})
31 | } else {
32 | Ok(quote! {{
33 | let f = move || { #(#stmts)* };
34 | FnWidget::new(f)
35 | }})
36 | }
37 | });
38 |
39 | result_to_token_stream(res)
40 | }
41 |
--------------------------------------------------------------------------------
/core/src/builtin_widgets/container.rs:
--------------------------------------------------------------------------------
1 | use crate::prelude::*;
2 |
3 | /// A simple container widget with a fixed size for its child.
4 | ///
5 | /// # Example
6 | ///
7 | /// Place text inside a 100x100 container.
8 | ///
9 | /// ```rust
10 | /// use ribir::prelude::*;
11 | ///
12 | /// container! {
13 | /// size: Size::new(100., 100.),
14 | /// background: Color::BLUE,
15 | /// @Text { text: "Hello" }
16 | /// };
17 | /// ```
18 | #[derive(Declare, SingleChild)]
19 | pub struct Container {
20 | pub size: Size,
21 | }
22 |
23 | impl Render for Container {
24 | fn perform_layout(&self, clamp: BoxClamp, ctx: &mut LayoutCtx) -> Size {
25 | let size = clamp.clamp(self.size);
26 | ctx.perform_single_child_layout(BoxClamp::max_size(size));
27 | size
28 | }
29 |
30 | #[inline]
31 | fn size_affected_by_child(&self) -> bool { false }
32 | }
33 |
34 | #[cfg(test)]
35 | mod tests {
36 | use ribir_dev_helper::*;
37 |
38 | use super::*;
39 | use crate::test_helper::*;
40 |
41 | const SIZE: Size = Size::new(100., 100.);
42 |
43 | widget_layout_test!(
44 | smoke,
45 | WidgetTester::new(fn_widget! { @Container { size: SIZE }}),
46 | LayoutCase::default().with_size(SIZE)
47 | );
48 | }
49 |
--------------------------------------------------------------------------------
/themes/material/src/classes/badge_cls.rs:
--------------------------------------------------------------------------------
1 | use ribir_core::prelude::*;
2 | use ribir_widgets::prelude::{BADGE_LARGE, BADGE_SMALL, BadgeColor};
3 |
4 | fn get_badge_color() -> VariantMap Color + Clone> {
5 | Variant::new_or_else(BuildCtx::get(), || BadgeColor(Palette::of(BuildCtx::get()).error()))
6 | .map(|c| c.0)
7 | }
8 |
9 | pub(super) fn init(classes: &mut Classes) {
10 | classes.insert(
11 | BADGE_SMALL,
12 | style_class! {
13 | clamp: BoxClamp::fixed_size(Size::new(6., 6.)),
14 | radius: Radius::all(3.),
15 | padding: EdgeInsets::all(0.),
16 | background: get_badge_color(),
17 | },
18 | );
19 |
20 | classes.insert(BADGE_LARGE, move |w| {
21 | fn_widget! {
22 | let color = get_badge_color();
23 | @FatObj {
24 | clamp: BoxClamp::min_width(16.).with_min_height(16.),
25 | radius: Radius::all(8.),
26 | padding: EdgeInsets::horizontal(4.),
27 | background: color.clone(),
28 | foreground: color.on_this_color(BuildCtx::get()),
29 | text_style: TypographyTheme::of(BuildCtx::get()).label_small.text.clone(),
30 | @ { w }
31 | }
32 | }
33 | .into_widget()
34 | });
35 | }
36 |
--------------------------------------------------------------------------------
/cli/src/program_check.rs:
--------------------------------------------------------------------------------
1 | /// ** This implementation is base on [https://github.com/gfx-rs/wgpu/blob/trunk/xtask/src/util.rs]!**
2 | use std::{io, process::Command};
3 |
4 | pub(crate) struct Program {
5 | pub binary_name: &'static str,
6 | pub crate_name: &'static str,
7 | }
8 |
9 | pub(crate) fn check_all_programs(programs: &[Program]) -> anyhow::Result<()> {
10 | let mut failed = Vec::new();
11 | for Program { binary_name, crate_name } in programs {
12 | let mut cmd = Command::new(binary_name);
13 | cmd.arg("--help");
14 | let output = cmd.output();
15 | match output {
16 | Ok(_output) => {
17 | println!("Checking for {binary_name} in PATH: ✅");
18 | }
19 | Err(e) if matches!(e.kind(), io::ErrorKind::NotFound) => {
20 | eprintln!("Checking for {binary_name} in PATH: ❌");
21 | failed.push(*crate_name);
22 | }
23 | Err(e) => {
24 | eprintln!("Checking for {binary_name} in PATH: ❌");
25 | panic!("Unknown IO error: {:?}", e);
26 | }
27 | }
28 | }
29 |
30 | if !failed.is_empty() {
31 | eprintln!("Please install them with: cargo install {}", failed.join(" "));
32 | anyhow::bail!("Missing programs in PATH");
33 | }
34 |
35 | Ok(())
36 | }
37 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 |
2 | ---
3 | name: Bug report
4 | about: Create a report to help us improve Ribir
5 | title: ''
6 | labels: bug
7 | assignees: ''
8 |
9 | ---
10 |
11 | **Problem**
12 |
13 |
14 | **Steps To Reproduce**
15 | Steps to reproduce the behavior:
16 | 1. Go to '...'
17 | 2. Click on '....'
18 | 3. Scroll down to '....'
19 | 4. See error
20 |
21 | Or paste reproducible error codes:
22 |
23 | **Expected behavior**
24 | A clear and concise description of what you expected to happen.
25 |
26 | **Screenshots**
27 | If applicable, add screenshots to help explain your problem.
28 |
29 | **Environment:**
30 | - Ribir version: [e.g. `master`]
31 | - Rust version: [e.g. 1.43.0, `nightly`]
32 | - OS, if relevant: [e.g. MacOS]
33 | - Browser and version, if relevant: [e.g. Chrome v83]
34 |
35 | **Questionnaire**
36 |
37 |
38 | - [ ] I'm interested in fixing this myself but don't know where to start
39 | - [ ] I would like to fix and I have a solution
40 | - [ ] I don't have time to fix this right now, but maybe later
--------------------------------------------------------------------------------
/tests/path_child_test.rs:
--------------------------------------------------------------------------------
1 | use ribir::{core::test_helper::*, prelude::*};
2 | use ribir_dev_helper::*;
3 | enum AB {
4 | A,
5 | B,
6 | }
7 |
8 | const SIZE_ONE: Size = Size::new(1., 1.);
9 | impl Compose for AB {
10 | fn compose(this: impl StateWriter) -> Widget<'static> {
11 | fn_widget! {
12 | @SizedBox {
13 | size: match *$read(this) {
14 | AB::A => ZERO_SIZE,
15 | AB::B => SIZE_ONE
16 | }
17 | }
18 | }
19 | .into_widget()
20 | }
21 | }
22 |
23 | impl AB {
24 | fn a() -> Self { AB::A }
25 |
26 | fn b() -> Self { AB::B }
27 | }
28 |
29 | #[test]
30 | fn path_widget() {
31 | let _ = fn_widget! { AB::A };
32 | let _ = fn_widget! { AB::B };
33 | let _ = fn_widget! { AB::a() };
34 | let _ = fn_widget! { AB::b() };
35 | }
36 |
37 | struct TupleBox(Size);
38 | impl Compose for TupleBox {
39 | fn compose(this: impl StateWriter) -> Widget<'static> {
40 | fn_widget! {
41 | @SizedBox {
42 | size: pipe!($read(this).0),
43 | }
44 | }
45 | .into_widget()
46 | }
47 | }
48 |
49 | widget_layout_test!(
50 | tuple_widget,
51 | WidgetTester::new(fn_widget! {
52 | TupleBox(Size::new(1., 1.))
53 | }),
54 | LayoutCase::default().with_size(Size::new(1., 1.))
55 | );
56 |
--------------------------------------------------------------------------------
/core/src/builtin_widgets/clip.rs:
--------------------------------------------------------------------------------
1 | use crate::prelude::*;
2 |
3 | /// A widget that clips its child using a specified path.
4 | ///
5 | /// # Example
6 | ///
7 | /// Clip a container by a rounded rectangle path.
8 | ///
9 | /// ```rust
10 | /// use ribir::prelude::*;
11 | ///
12 | /// fn_widget! {
13 | /// @Clip {
14 | /// clip_path: Path::rect_round(&Rect::new(Point::zero(), Size::new(50., 50.)), &Radius::all(25.)),
15 | /// @Container {
16 | /// size: Size::new(100., 100.),
17 | /// background: Color::RED
18 | /// }
19 | /// }
20 | /// };
21 | /// ```
22 | #[derive(SingleChild, Declare)]
23 | pub struct Clip {
24 | pub clip_path: Path,
25 | }
26 |
27 | impl Render for Clip {
28 | fn size_affected_by_child(&self) -> bool { false }
29 |
30 | fn perform_layout(&self, clamp: BoxClamp, ctx: &mut LayoutCtx) -> Size {
31 | ctx.assert_perform_single_child_layout(clamp);
32 | self
33 | .clip_path
34 | .bounds(None)
35 | .max()
36 | .to_tuple()
37 | .into()
38 | }
39 |
40 | fn paint(&self, ctx: &mut PaintingCtx) { ctx.painter().clip(self.clip_path.clone().into()); }
41 |
42 | fn visual_box(&self, ctx: &mut VisualCtx) -> Option {
43 | let clip_rect = self.clip_path.bounds(None);
44 | ctx.clip(clip_rect);
45 | Some(clip_rect)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/examples/counter/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors.workspace = true
3 | categories.workspace = true
4 | description.workspace = true
5 | documentation.workspace = true
6 | edition.workspace = true
7 | homepage.workspace = true
8 | keywords.workspace = true
9 | license.workspace = true
10 | name = "counter"
11 | publish = false
12 | version.workspace = true
13 |
14 | [dependencies]
15 | paste.workspace = true
16 | # we disable `default-features`, because we want more control over testing.
17 | ribir = {path = "../../ribir", features = ["material", "widgets"]}
18 |
19 | [target.'cfg(target_arch = "wasm32")'.dependencies]
20 | console_error_panic_hook = "0.1.6"
21 | wasm-bindgen = "0.2.92"
22 |
23 | [dev-dependencies]
24 | ribir_slim = { path = "../../themes/ribir_slim" }
25 | ribir_dev_helper = {path = "../../dev-helper"}
26 | ribir_core = { path = "../../core", features = ["test-utils"]}
27 |
28 | [features]
29 | wgpu = ["ribir/wgpu"]
30 |
31 |
32 | [lib]
33 | crate-type = ["cdylib", "rlib"]
34 | path = "src/lib.rs"
35 |
36 | [package.metadata.bundle]
37 | "productName" = "Counter"
38 | "version" = "1.0.0"
39 | "identifier" = "com.ribir.counter"
40 | "shortDescription" = ""
41 | "longDescription" = ""
42 | "copyright" = "Copyright (c) You 2021. All rights reserved."
43 | "icon" = ["../Logo.ico"]
44 | "resources" = []
45 | "externalBin" = []
46 |
--------------------------------------------------------------------------------
/.github/workflows/alpha-version.yml:
--------------------------------------------------------------------------------
1 | on:
2 | workflow_dispatch: # allows manual triggering
3 | schedule:
4 | - cron: "0 0 * * 3" # runs every wednesday at 00:00 UTC
5 | permissions:
6 | contents: write
7 | name: "Alpha Version"
8 | jobs:
9 | master_check:
10 | runs-on: ubuntu-latest
11 | steps:
12 | - name: Master check
13 | if: github.ref != 'refs/heads/master'
14 | run: |
15 | echo "Alpha version can be released only from master branch"
16 | exit 1
17 | commit_check:
18 | needs: master_check
19 | runs-on: ubuntu-latest
20 | steps:
21 | - uses: actions/checkout@v3
22 | with:
23 | fetch-depth: 0
24 | fetch-tags: true
25 | - run: |
26 | new_commit=$(git log $(git describe --tags --abbrev=0)..HEAD --oneline | wc -l)
27 | if [ $new_commit -eq 0 ]; then
28 | echo "No new commits since last version"
29 | exit 1
30 | fi
31 | call-workflow-passing-data:
32 | needs: commit_check
33 | uses: RibirX/rclog/.github/workflows/release-version.yml@main
34 | with:
35 | level: 'alpha'
36 | ref: ${{ github.ref }}
37 | merge_changelog: false
38 | toolchain: stable
39 | secrets:
40 | CRATE_RELEASE_TOKEN: ${{ secrets.CRATE_RELEASE_TOKEN }}
41 | GITHUB_RELEASE_TOKEN: ${{ secrets.RIBIR_RELEASE }}
--------------------------------------------------------------------------------
/core/src/events/pointers/from_mouse.rs:
--------------------------------------------------------------------------------
1 | use winit::event::MouseButton;
2 |
3 | use super::PointerId;
4 | use crate::prelude::*;
5 |
6 | impl PointerEvent {
7 | pub(crate) fn from_mouse(target: WidgetId, wnd: &Window) -> Self {
8 | let no_button = wnd
9 | .dispatcher
10 | .borrow()
11 | .info
12 | .mouse_buttons()
13 | .is_empty();
14 | PointerEvent {
15 | // todo: we need to trace the pressed pointer, how to generate pointer id, by device + button?
16 | id: PointerId(0),
17 | width: 1.0,
18 | height: 1.0,
19 | pressure: if no_button { 0. } else { 0.5 },
20 | tilt_x: 90.,
21 | tilt_y: 90.,
22 | twist: 0.,
23 | point_type: PointerType::Mouse,
24 | is_primary: true,
25 | common: CommonEvent::new(target, wnd.tree),
26 | }
27 | }
28 | }
29 |
30 | impl From for MouseButtons {
31 | fn from(btns: MouseButton) -> Self {
32 | match btns {
33 | MouseButton::Left => MouseButtons::PRIMARY,
34 | MouseButton::Right => MouseButtons::SECONDARY,
35 | MouseButton::Middle => MouseButtons::AUXILIARY,
36 | MouseButton::Back => MouseButtons::FOURTH,
37 | MouseButton::Forward => MouseButtons::FIFTH,
38 | MouseButton::Other(v) => {
39 | log::warn!("Not support the mouse button {} now", v);
40 | MouseButtons::default()
41 | }
42 | }
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/examples/animation_demo.rs:
--------------------------------------------------------------------------------
1 | /*
2 | use ribir::prelude::*;
3 | use std::time::Duration;
4 |
5 | fn main() {
6 | let style = PathPaintStyle::Stroke(StrokeOptions::default());
7 | let lyon_path = include_svg!("./Logo.svg");
8 | let mut paths = vec![];
9 | lyon_path.paths.into_iter().for_each(|render_path| {
10 | paths.push(PathPaintKit {
11 | path: render_path.path,
12 | brush: render_path.brush.map_or(Brush::Color(Color::BLACK), |b| b),
13 | style,
14 | });
15 | });
16 | let w = widget! {
17 | PathsPaintKit {
18 | anchor: Anchor::left_top(100., 100.),
19 | transform: Transform::scale(0.5, 0.5),
20 | id: path_widget,
21 | paths,
22 | on_mounted: move |_| circle_animate.run(),
23 | }
24 | Animate {
25 | id: circle_animate,
26 | transition: Transition {
27 | delay: None,
28 | duration: Duration::from_millis(5000),
29 | easing: easing::LINEAR,
30 | repeat: Some(f32::MAX),
31 | },
32 | prop: prop!(path_widget.paths, PathPaintKit::paths_lerp_fn(prop!(path_widget.paths))),
33 | from: vec![
34 | PathPaintKit {
35 | path: Path::rect(&Rect::zero()),
36 | brush: Brush::Color(Color::WHITE),
37 | style
38 | }
39 | ]
40 | }
41 | };
42 | App::run(w);
43 | }
44 | */
45 |
46 | fn main() { panic!("Blocked by path sampler finished.") }
47 |
--------------------------------------------------------------------------------
/core/src/events/ime_pre_edit.rs:
--------------------------------------------------------------------------------
1 | use crate::{impl_common_event_deref, prelude::*};
2 |
3 | #[derive(Debug, Clone)]
4 | pub enum ImePreEdit {
5 | /// Notifies when the IME PreEdit begin a new round.
6 | ///
7 | /// After getting this event you could receive [`PreEdit`](Self::PreEdit).
8 | Begin,
9 |
10 | /// Notifies when a new composing text should be set at the cursor position.
11 | ///
12 | /// The value represents a pair of the preedit string and the cursor begin
13 | /// position and end position. When it's `None`, the cursor should be
14 | /// hidden. When `String` is an empty string this indicates that preedit was
15 | /// cleared.
16 | ///
17 | /// The cursor position is byte-wise indexed.
18 | PreEdit { value: String, cursor: Option<(usize, usize)> },
19 |
20 | /// Notifies when the IME PreEdit was finished this round.
21 | ///
22 | /// After receiving this event you won't get any more PreEdit event in this
23 | /// round.You should clear pending pre_edit text.
24 | End,
25 | }
26 |
27 | #[derive(Debug)]
28 | pub struct ImePreEditEvent {
29 | pub pre_edit: ImePreEdit,
30 | pub common: CommonEvent,
31 | }
32 |
33 | impl ImePreEditEvent {
34 | pub(crate) fn new(pre_edit: ImePreEdit, target: WidgetId, wnd: &Window) -> Self {
35 | ImePreEditEvent { pre_edit, common: CommonEvent::new(target, wnd.tree) }
36 | }
37 | }
38 |
39 | impl_common_event_deref!(ImePreEditEvent);
40 |
--------------------------------------------------------------------------------
/examples/pomodoro/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors.workspace = true
3 | categories.workspace = true
4 | description.workspace = true
5 | documentation.workspace = true
6 | edition.workspace = true
7 | homepage.workspace = true
8 | keywords.workspace = true
9 | license.workspace = true
10 | name = "pomodoro"
11 | publish = false
12 | version.workspace = true
13 |
14 | [dependencies]
15 | paste.workspace = true
16 | # we disable `default-features`, because we want more control over testing.
17 | ribir = {path = "../../ribir", features = ["material", "widgets"]}
18 | tokio.workspace = true
19 | serde = { version = "1.0", features = ["derive"] }
20 | serde_json = "1.0"
21 | rodio = "0.21"
22 | dirs = "5.0"
23 |
24 | [dev-dependencies]
25 | ribir_dev_helper = {path = "../../dev-helper"}
26 | ribir_slim = { path = "../../themes/ribir_slim" }
27 | ribir_core = { path = "../../core", features = ["test-utils"]}
28 |
29 | [features]
30 | wgpu = ["ribir/wgpu"]
31 |
32 | [package.metadata.release]
33 | opt-level = "z"
34 | lto = true
35 | codegen-units = 1
36 | strip = true
37 | panic = "abort"
38 |
39 | [package.metadata.bundle]
40 | "productName" = "Pomodoro"
41 | "version" = "1.0.0"
42 | "identifier" = "com.ribir.pomodoro"
43 | "shortDescription" = ""
44 | "longDescription" = ""
45 | "copyright" = "Copyright (c) You 2021. All rights reserved."
46 | "icon" = ["./icon.ico"]
47 | "resources" = ["./static"]
48 | "externalBin" = []
49 |
--------------------------------------------------------------------------------
/gpu/src/wgpu_impl/shaders/alpha_triangles.wgsl:
--------------------------------------------------------------------------------
1 | @group(0) @binding(0)
2 | var view_size: vec4;
3 |
4 | // An 8x sample provides better quality than a 4x sample in text rendering.
5 | // https://learn.microsoft.com/en-us/windows/win32/api/d3d11/ne-d3d11-d3d11_standard_multisample_quality_levels
6 | const sample_pattern: array = array(
7 | // 4x sample pattern
8 | // vec2(-6.0, 2.0) / 16.0,
9 | // vec2(-2.0, -6.0) / 16.0,
10 | // vec2(2.0, 6.0) / 16.0
11 | // vec2(6.0, -2.0) / 16.0,
12 |
13 | // 8x sample pattern
14 | vec2( -7. / 16., -1. / 16.),
15 | vec2( -5. / 16., 5. / 16.),
16 | vec2( -3. / 16., -5. / 16.),
17 | vec2( -1. / 16., 3. / 16.),
18 | vec2(1. / 16., -3. / 16.),
19 | vec2( 3. / 16., 7. / 16.),
20 | vec2( 5. / 16., 1. / 16.),
21 | vec2( 7. / 16., -7. / 16.)
22 | );
23 | const sample_size: u32 = 8;
24 |
25 |
26 | @vertex
27 | fn vs_main(@location(0) pos: vec2, @builtin(instance_index) instance: u32) -> @builtin(position) vec4 {
28 |
29 | let size = vec2(f32(view_size.x), f32(view_size.y));
30 | var sample_pos = pos + sample_pattern[instance % sample_size];
31 | sample_pos = sample_pos * vec2(2., -2.) / size + vec2(-1., 1.);
32 | return vec4(sample_pos, 0.0, 1.0);
33 | }
34 |
35 | @fragment
36 | fn fs_main() -> @location(0) vec4 {
37 | let value: f32 = 1.0 / f32(sample_size);
38 | return vec4(value, value, value, value);
39 | }
40 |
--------------------------------------------------------------------------------
/docs/zh/get_started/try_it.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 1
3 | ---
4 |
5 | # 体验 Ribir
6 |
7 | 这篇文档将向你介绍如何配置和创建一个 Ribir 应用。
8 |
9 | > 你将了解
10 | >
11 | > - 如何编写和启动一个简单的 `Hello world!` 应用
12 |
13 |
14 | ## 安装 Rust
15 |
16 | 首先, 你需要安装 Rust,你可以参考 [Rust 官方文档](https://www.rust-lang.org/tools/install).
17 |
18 | ## 新建 Ribir 项目
19 |
20 | 然后,打开你的终端,创建一个新的 Rust 项目:
21 |
22 | ```sh
23 | cargo new ribir-hello-world
24 | cd ribir-hello-world
25 | ```
26 |
27 | 接下来, 编辑 `Cargo.toml` 文件, 添加 Ribir 作为依赖:
28 |
29 | ```toml
30 | [dependencies]
31 | ribir = "@RIBIR_VERSION"
32 | ```
33 |
34 | 或者直接运行 `cargo add --git "https://github.com/RibirX/Ribir" ribir` 让 Cargo 为你添加正在开发中的最新 Ribir 版本.
35 |
36 | ## 编写 `main.rs`
37 |
38 | 打开编辑器, 将 `src/main.rs` 文件修改为:
39 |
40 | ```rust no_run
41 | // main.rs
42 | use ribir::prelude::*;
43 |
44 | fn main() {
45 | App::run(text! { text: "Hello World!" });
46 | }
47 | ```
48 |
49 | ## 运行应用
50 |
51 | ```sh
52 | cargo run
53 | ```
54 |
55 | 恭喜! 你完成了第一个 Ribir 项目。
56 |
57 | ## 运行 Ribir 自带示例
58 |
59 | 最后,Ribir 仓库中还有一些其他示例,你可以克隆 Git 仓库:
60 |
61 | ```sh
62 | git clone git@github.com:RibirX/Ribir.git
63 | cd Ribir/Ribir
64 | ```
65 |
66 | 并使用以下命令之一运行示例:
67 |
68 | ```sh
69 | cargo run -p counter
70 | cargo run -p storybook
71 | cargo run -p messages
72 | cargo run -p todos
73 | ```
74 |
75 |
76 | ## 下一步
77 |
78 | 如果你更喜欢直接使用函数调用来构建 UI,而不是通过 "DSL",在进入下一步之前,你可能会想先看看 [如何在不使用 "DSL" 的情况下使用 Ribir](../understanding_ribir/without_dsl.md)。
79 |
--------------------------------------------------------------------------------
/tests/benches/example_bench.rs:
--------------------------------------------------------------------------------
1 | use criterion::{Bencher, Criterion, criterion_group, criterion_main};
2 | use ribir::{
3 | core::{reset_test_env, test_helper::*},
4 | prelude::*,
5 | };
6 |
7 | fn bench_example(b: &mut Bencher, f: impl RInto) {
8 | let _ = AppCtx::shared();
9 | let f: GenWidget = f.r_into();
10 | b.iter(|| {
11 | let wnd = TestWindow::from_widget(f.clone());
12 | wnd.draw_frame();
13 | AppCtx::remove_wnd(wnd.id())
14 | })
15 | }
16 |
17 | fn bench_example_with_data>(
18 | b: &mut Bencher, data: D, f: impl Fn(&'static D) -> W + 'static,
19 | ) {
20 | let _ = AppCtx::shared();
21 | let widget_builder = move || f(unsafe { &*(&data as *const _) }).into_widget();
22 | bench_example(b, widget_builder);
23 | }
24 |
25 | fn examples(c: &mut Criterion) {
26 | reset_test_env!();
27 |
28 | let mut g = c.benchmark_group("Examples");
29 |
30 | g.bench_function("todos", |b| bench_example(b, todos::todos));
31 | g.bench_function("counter", |b| bench_example_with_data(b, Stateful::new(0), counter::counter));
32 |
33 | g.bench_function("messages", |b| bench_example(b, messages::messages));
34 | g.bench_function("storybook", |b| bench_example(b, storybook::storybook));
35 | g.bench_function("wordle_game", |b| bench_example(b, wordle_game::wordle_game));
36 | }
37 |
38 | criterion_group!(example_benches, examples);
39 | criterion_main!(example_benches);
40 |
--------------------------------------------------------------------------------
/core/src/builtin_widgets/foreground.rs:
--------------------------------------------------------------------------------
1 | use crate::{prelude::*, wrap_render::*};
2 |
3 | /// A widget that provides a foreground brush for painting elements in its
4 | /// subtree. The foreground brush is inherited by descendant widgets; children
5 | /// can access it via the `Provider`. The built-in `Text` widget uses this brush
6 | /// when painting text.
7 | ///
8 | /// # Example
9 | /// Apply a foreground brush to render text in red.
10 | ///
11 | /// ```rust
12 | /// use ribir::prelude::*;
13 | ///
14 | /// fn_widget! {
15 | /// @Text {
16 | /// text: "I am red!",
17 | /// foreground: Color::RED,
18 | /// }
19 | /// };
20 | /// ```
21 | #[derive(Default)]
22 | pub struct Foreground {
23 | pub foreground: Brush,
24 | }
25 |
26 | impl Declare for Foreground {
27 | type Builder = FatObj<()>;
28 | #[inline]
29 | fn declarer() -> Self::Builder { FatObj::new(()) }
30 | }
31 |
32 | impl_compose_child_for_wrap_render!(Foreground);
33 |
34 | impl WrapRender for Foreground {
35 | fn perform_layout(&self, clamp: BoxClamp, host: &dyn Render, ctx: &mut LayoutCtx) -> Size {
36 | host.perform_layout(clamp, ctx)
37 | }
38 |
39 | fn paint(&self, host: &dyn Render, ctx: &mut PaintingCtx) {
40 | ctx
41 | .painter()
42 | .set_fill_brush(self.foreground.clone())
43 | .set_stroke_brush(self.foreground.clone());
44 | host.paint(ctx)
45 | }
46 |
47 | #[inline]
48 | fn wrapper_dirty_phase(&self) -> DirtyPhase { DirtyPhase::Paint }
49 | }
50 |
--------------------------------------------------------------------------------
/core/src/builtin_widgets/image_widget.rs:
--------------------------------------------------------------------------------
1 | //! Implement `Render` for `Resource` so images can be used as
2 | //! widgets directly.
3 | //!
4 | //! # Example
5 | //!
6 | //! Display an image loaded from bytes.
7 | //!
8 | //! ```rust,no_run
9 | //! use ribir::prelude::*;
10 | //!
11 | //! fn_widget! {
12 | //! // Load an image from bytes (e.g., included from a file)
13 | //! let img = Resource::new(
14 | //! PixelImage::from_png(include_bytes!("../../../static/hero-banner.png"))
15 | //! );
16 | //! @ { img }
17 | //! };
18 | //! ```
19 | use crate::prelude::*;
20 |
21 | impl Render for Resource {
22 | fn perform_layout(&self, clamp: BoxClamp, _: &mut LayoutCtx) -> Size {
23 | let size = Size::new(self.width() as f32, self.height() as f32);
24 | clamp.clamp(size)
25 | }
26 |
27 | fn paint(&self, ctx: &mut PaintingCtx) {
28 | let size = ctx.box_size().unwrap();
29 | let box_rect = Rect::from_size(size);
30 | let img_rect = Rect::from_size(Size::new(self.width() as f32, self.height() as f32));
31 | let painter = ctx.painter();
32 | if let Some(rc) = img_rect.intersection(&box_rect) {
33 | painter.draw_img(self.clone(), &rc, &Some(rc));
34 | }
35 | }
36 |
37 | fn visual_box(&self, ctx: &mut VisualCtx) -> Option {
38 | let box_rect = Rect::from_size(ctx.box_size()?);
39 | let img_rect = Rect::from_size(Size::new(self.width() as f32, self.height() as f32));
40 | img_rect.intersection(&box_rect)
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/examples/pomodoro/static/pin_off.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/ribir/src/backends/wgpu_backend.rs:
--------------------------------------------------------------------------------
1 | use ribir_core::prelude::{Color, DeviceRect, DeviceSize, PaintCommand, PainterBackend, Transform};
2 | use ribir_gpu::Surface;
3 |
4 | use crate::winit_shell_wnd::WinitBackend;
5 |
6 | pub struct WgpuBackend<'a> {
7 | surface: Surface<'a>,
8 | backend: ribir_gpu::GPUBackend,
9 | }
10 |
11 | impl<'a> WinitBackend<'a> for WgpuBackend<'a> {
12 | async fn new(window: &'a winit::window::Window) -> WgpuBackend<'a> {
13 | let (wgpu, surface) = ribir_gpu::WgpuImpl::new(window).await;
14 | let size = window.inner_size();
15 | let size = DeviceSize::new(size.width as i32, size.height as i32);
16 |
17 | let mut wgpu = WgpuBackend { surface, backend: ribir_gpu::GPUBackend::new(wgpu) };
18 | wgpu.on_resize(size);
19 |
20 | wgpu
21 | }
22 |
23 | fn on_resize(&mut self, size: DeviceSize) {
24 | if size != self.surface.size() {
25 | self.surface.resize(size, self.backend.get_impl());
26 | }
27 | }
28 |
29 | fn begin_frame(&mut self, surface_color: Color) { self.backend.begin_frame(surface_color); }
30 |
31 | fn draw_commands(
32 | &mut self, viewport: DeviceRect, global_matrix: &Transform, commands: &[PaintCommand],
33 | ) {
34 | self.backend.draw_commands(
35 | viewport,
36 | commands,
37 | global_matrix,
38 | self.surface.get_current_texture(),
39 | );
40 | }
41 |
42 | fn end_frame(&mut self) {
43 | self.backend.end_frame();
44 | self.surface.present();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/core/src/ticker.rs:
--------------------------------------------------------------------------------
1 | use std::convert::Infallible;
2 |
3 | use rxrust::subject::LocalSubject;
4 | pub use rxrust::{Duration, Instant};
5 |
6 | /// Frame ticker emit message when new frame need to draw.
7 | pub type FrameTicker = LocalSubject<'static, FrameMsg, Infallible>;
8 |
9 | /// Message emitted at different status of a frame.
10 |
11 | #[derive(Clone, Debug)]
12 | pub enum FrameMsg {
13 | /// This message is emitted when all events have been processed and the
14 | /// framework begins the layout and painting of the frame.
15 | ///
16 | /// Only the first frame of continuous frames that do not require drawing will
17 | /// receive this message.
18 | NewFrame(Instant),
19 | /// This message is emitted before the framework starts the layout of the
20 | /// frame.
21 | BeforeLayout(Instant),
22 | /// This message is emitted when the layout process is completed, and the
23 | /// widget tree is ready to be rendered. # Notice
24 | /// - This message may be emitted more than once if there are listeners
25 | /// performing actions that trigger a widget relayout. Exercise caution when
26 | /// modifying widgets in the listener of this message.
27 | LayoutReady(Instant),
28 | /// This message is emitted after the render data has been submitted,
29 | /// indicating that all tasks for the current frame have been completed by the
30 | /// framework.
31 | ///
32 | /// Only the first frame of continuous frames that do not require drawing will
33 | /// receive this message.
34 | Finish(Instant),
35 | }
36 |
--------------------------------------------------------------------------------
/macros/src/asset/basic.rs:
--------------------------------------------------------------------------------
1 | use proc_macro2::TokenStream;
2 | use quote::quote;
3 |
4 | use super::{Asset, AssetContext};
5 |
6 | pub(crate) struct BinaryAsset;
7 |
8 | impl Asset for BinaryAsset {
9 | fn generate(&self, ctx: &AssetContext) -> syn::Result {
10 | if ctx.embed {
11 | let path = &ctx.input_path;
12 | Ok(quote! { include_bytes!(#path).to_vec() })
13 | } else {
14 | ctx.copy_input_to_output()?;
15 | let path_tokens = ctx.runtime_path_tokens();
16 | let panic_msg = ctx.panic_msg("read binary");
17 | Ok(quote! {
18 | {
19 | let asset_path = #path_tokens;
20 | std::fs::read(&asset_path)
21 | .unwrap_or_else(|e| panic!("{}: {}. Asset path: {:?}", #panic_msg, e, asset_path))
22 | }
23 | })
24 | }
25 | }
26 | }
27 |
28 | pub(crate) struct TextAsset;
29 |
30 | impl Asset for TextAsset {
31 | fn generate(&self, ctx: &AssetContext) -> syn::Result {
32 | if ctx.embed {
33 | let path = &ctx.input_path;
34 | Ok(quote! { include_str!(#path).to_string() })
35 | } else {
36 | ctx.copy_input_to_output()?;
37 | let path_tokens = ctx.runtime_path_tokens();
38 | let panic_msg = ctx.panic_msg("read text");
39 | Ok(quote! {
40 | {
41 | let asset_path = #path_tokens;
42 | std::fs::read_to_string(&asset_path)
43 | .unwrap_or_else(|e| panic!("{}: {}. Asset path: {:?}", #panic_msg, e, asset_path))
44 | }
45 | })
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/cli/README.md:
--------------------------------------------------------------------------------
1 | ## Cli for ribir
2 | ### SubCommand
3 | #### run-wasm
4 | build the example to wasm
5 | 1. Compile to target wasm32-unknown-unknown
6 | 2. Use wasm-bindgen to export relative function to js
7 | 3. Serve the wasm in 127.0.0.1:8000 by simpl-http-server
8 |
9 | #### bundle
10 | Bundle the native app
11 | 1. Change the directory to the package of the app
12 | 2. Add bundle config to Cargo.toml or Create a new bundle.toml.
13 | 3. Build the app by cargo.
14 | 4. Run the bundle command in the directory of the app.
15 | For example(used the config in the Cargo.toml):
16 | ``` bash
17 | cli bundle --verbose
18 | ```
19 | By default, this will bundle the release binary. To bundle the debug binary instead, use the --debug flag.
20 | You can also specify the path to the bundle config file by --config follow by the file path. If no path is specified, it will read config from the current package Cargo.toml file.
21 |
22 | ##### Bundle Config File Example
23 | The bundle config file is in toml format. Here is an simple example:
24 | ``` toml
25 | [bundle]
26 | "productName" = "Counter"
27 | "version" = "1.0.0"
28 | "identifier" = "com.ribir.counter"
29 | "shortDescription" = ""
30 | "longDescription" = ""
31 | "copyright" = "Copyright (c) You 2021. All rights reserved."
32 | "icon" = ["../Logo.ico"]
33 | "resources" = []
34 | "externalBin" = []
35 | ```
36 | Note that this is just an example, and the actual configuration will depend on the specific requirements of your application. and for more details, you can refer to the [`BundleConfig`] struct in the cli crate.
37 |
--------------------------------------------------------------------------------
/core/src/builtin_widgets/opacity.rs:
--------------------------------------------------------------------------------
1 | use crate::{prelude::*, wrap_render::*};
2 |
3 | /// A wrapper that controls the opacity of its child.
4 | ///
5 | /// This is a built-in `FatObj` field. Setting the `opacity` field attaches an
6 | /// `Opacity` wrapper which applies an alpha multiplier when painting.
7 | ///
8 | /// # Example
9 | ///
10 | /// Display a red container with 50% opacity.
11 | ///
12 | /// ```rust
13 | /// use ribir::prelude::*;
14 | ///
15 | /// container! {
16 | /// size: Size::new(100., 100.),
17 | /// background: Color::RED,
18 | /// opacity: 0.5,
19 | /// };
20 | /// ```
21 | #[derive(Clone)]
22 | pub struct Opacity {
23 | pub opacity: f32,
24 | }
25 |
26 | impl Declare for Opacity {
27 | type Builder = FatObj<()>;
28 | #[inline]
29 | fn declarer() -> Self::Builder { FatObj::new(()) }
30 | }
31 |
32 | impl Default for Opacity {
33 | #[inline]
34 | fn default() -> Self { Self { opacity: 1.0 } }
35 | }
36 |
37 | impl_compose_child_for_wrap_render!(Opacity);
38 |
39 | impl WrapRender for Opacity {
40 | fn paint(&self, host: &dyn Render, ctx: &mut PaintingCtx) {
41 | ctx.painter().apply_alpha(self.opacity);
42 | if self.opacity > 0. {
43 | host.paint(ctx)
44 | }
45 | }
46 |
47 | fn visual_box(&self, host: &dyn Render, ctx: &mut VisualCtx) -> Option {
48 | if self.opacity > 0. {
49 | host.visual_box(ctx)
50 | } else {
51 | ctx.clip(Rect::from_size(Size::zero()));
52 | None
53 | }
54 | }
55 |
56 | #[inline]
57 | fn wrapper_dirty_phase(&self) -> DirtyPhase { DirtyPhase::Paint }
58 | }
59 |
--------------------------------------------------------------------------------
/macros/src/lerp_derive.rs:
--------------------------------------------------------------------------------
1 | use proc_macro2::TokenStream;
2 | use quote::quote;
3 | use syn::spanned::Spanned;
4 |
5 | use crate::util::data_struct_unwrap;
6 |
7 | pub(crate) fn lerp_derive(input: &mut syn::DeriveInput) -> syn::Result {
8 | let syn::DeriveInput { ident: name, generics, data, .. } = input;
9 | let (g_impl, g_ty, g_where) = generics.split_for_impl();
10 | let stt = data_struct_unwrap(data, "Lerp")?;
11 |
12 | let tokens = match &stt.fields {
13 | syn::Fields::Named(n) => {
14 | let fields = n.named.iter().map(|f| &f.ident);
15 | quote! {
16 | impl #g_impl Lerp for #name #g_ty #g_where {
17 | fn lerp(&self, to: &Self, factor: f32) -> Self {
18 | #name {
19 | #(#fields: Lerp::lerp(&self.#fields, &to.#fields, factor)),*
20 | }
21 | }
22 | }
23 | }
24 | }
25 | syn::Fields::Unnamed(u) => {
26 | let indexes = u
27 | .unnamed
28 | .iter()
29 | .enumerate()
30 | .map(|(i, f)| syn::Index { index: i as u32, span: f.span() });
31 | quote! {
32 | impl #g_impl Lerp for #name #g_ty #g_where {
33 | fn lerp(&self, to: &Self, factor: f32) -> Self {
34 | #name(#(Lerp::lerp(&self.#indexes, &to.#indexes, factor)) ,*)
35 | }
36 | }
37 | }
38 | }
39 | syn::Fields::Unit => quote! {
40 | impl #g_impl Lerp for #name #g_ty #g_impl #g_where {
41 | fn lerp(&self, to: &Self, factor: f32) -> Self {
42 | #name
43 | }
44 | }
45 | },
46 | };
47 |
48 | Ok(tokens)
49 | }
50 |
--------------------------------------------------------------------------------
/core/src/builtin_widgets/text_align.rs:
--------------------------------------------------------------------------------
1 | use crate::prelude::*;
2 |
3 | /// Controls alignment of multi-line text within its bounds. Descendant
4 | /// `Text` widgets will use the `TextAlign` value to determine line alignment.
5 | ///
6 | /// This is a built-in `FatObj` field. Setting `text_align` attaches a
7 | /// `TextAlignWidget` that provides alignment to descendant text renderers.
8 | ///
9 | /// # Example
10 | ///
11 | /// Center-align all lines of a multi-line `Text` widget.
12 | ///
13 | /// ```rust
14 | /// use ribir::prelude::*;
15 | ///
16 | /// container! {
17 | /// size: Size::new(120., 40.),
18 | /// text_align: TextAlign::Center,
19 | /// @Text { text: "Line 1\nlong line 2" }
20 | /// };
21 | /// ```
22 | #[derive(Default)]
23 | pub struct TextAlignWidget {
24 | pub text_align: TextAlign,
25 | }
26 |
27 | impl Declare for TextAlignWidget {
28 | type Builder = FatObj<()>;
29 |
30 | #[inline]
31 | fn declarer() -> Self::Builder { FatObj::new(()) }
32 | }
33 |
34 | impl<'c> ComposeChild<'c> for TextAlignWidget {
35 | type Child = Widget<'c>;
36 |
37 | fn compose_child(this: impl StateWriter, child: Self::Child) -> Widget<'c> {
38 | Providers::new([Self::into_provider(this)]).with_child(child)
39 | }
40 | }
41 |
42 | impl TextAlignWidget {
43 | pub fn into_provider(this: impl StateWriter) -> Provider {
44 | match this.try_into_value() {
45 | Ok(this) => Provider::new(this.text_align),
46 | Err(this) => Provider::writer(
47 | this.part_writer(PartialId::any(), |w| PartMut::new(&mut w.text_align)),
48 | Some(DirtyPhase::LayoutSubtree),
49 | ),
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/core/src/local_sender.rs:
--------------------------------------------------------------------------------
1 | use std::{cell::Cell, thread::ThreadId};
2 |
3 | /// This wrapper ensures that the data can only be accessed in the thread that
4 | /// initially utilizes it.
5 | ///
6 | /// Any attempt to access it from another thread will result in a panic.
7 | pub struct LocalSender {
8 | data: *mut T,
9 | id: Cell,
10 | }
11 |
12 | impl LocalSender {
13 | pub fn new(data: T) -> Self {
14 | let id = Cell::new(std::thread::current().id());
15 | Self { data: Box::into_raw(Box::new(data)), id }
16 | }
17 |
18 | pub fn reset(&self) { self.id.set(std::thread::current().id()); }
19 |
20 | pub fn take(&self)
21 | where
22 | T: Default,
23 | {
24 | unsafe { self.data.replace(<_>::default()) };
25 | }
26 |
27 | #[track_caller]
28 | fn assert_same_thread(&self) {
29 | assert_eq!(
30 | self.id.get(),
31 | std::thread::current().id(),
32 | "Access is only supported within the same thread."
33 | );
34 | }
35 | }
36 |
37 | impl std::ops::Deref for LocalSender {
38 | type Target = T;
39 |
40 | fn deref(&self) -> &Self::Target {
41 | self.assert_same_thread();
42 | unsafe { &*self.data }
43 | }
44 | }
45 |
46 | impl std::ops::DerefMut for LocalSender {
47 | fn deref_mut(&mut self) -> &mut Self::Target {
48 | self.assert_same_thread();
49 | unsafe { &mut *self.data }
50 | }
51 | }
52 |
53 | impl Drop for LocalSender {
54 | fn drop(&mut self) {
55 | self.assert_same_thread();
56 | let _drop = unsafe { Box::from_raw(self.data) };
57 | }
58 | }
59 |
60 | unsafe impl Send for LocalSender {}
61 | unsafe impl Sync for LocalSender {}
62 |
--------------------------------------------------------------------------------
/themes/material/src/classes/input_cls.rs:
--------------------------------------------------------------------------------
1 | use ribir_core::prelude::*;
2 | use ribir_widgets::input::{INPUT, TEXT_CARET, TEXT_SELECTION, TEXTAREA};
3 |
4 | use crate::md;
5 |
6 | pub(super) fn init(classes: &mut Classes) {
7 | classes.insert(TEXT_CARET, |w| {
8 | rdl! {
9 | let mut w = FatObj::new(w);
10 | let blink_interval = Duration::from_millis(500);
11 | let u = Local::interval(blink_interval)
12 | .subscribe(move |idx| *$write(w.opacity()) = (idx % 2) as f32);
13 | let border = BuildCtx::color()
14 | .map(|color| Border::only_left(BorderSide::new(2., (*color).into())));
15 | @(w) {
16 | clamp: BoxClamp::fixed_width(2.),
17 | border,
18 | on_disposed: move |_| u.unsubscribe()
19 | }
20 | }
21 | .into_widget()
22 | });
23 |
24 | classes.insert(
25 | TEXT_SELECTION,
26 | style_class! {
27 | background: {
28 | let color = BuildCtx::color();
29 | color.into_container_color(BuildCtx::get()).map(|c| c.with_alpha(0.8))
30 | }
31 | },
32 | );
33 |
34 | fn input_border(w: Widget) -> Widget {
35 | let mut w = FatObj::new(w);
36 | let blur = Palette::of(BuildCtx::get()).on_surface_variant();
37 |
38 | let focus_watcher = w.is_focused();
39 | let border = BuildCtx::color().map_with_watcher(focus_watcher, move |c, focus| {
40 | let color = if *focus { *c } else { blur };
41 | Border::all(BorderSide::new(1., color.into()))
42 | });
43 |
44 | w.with_border(border).with_radius(md::RADIUS_2);
45 | w.into_widget()
46 | }
47 | classes.insert(INPUT, input_border);
48 | classes.insert(TEXTAREA, input_border);
49 | }
50 |
--------------------------------------------------------------------------------
/painter/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors.workspace = true
3 | categories.workspace = true
4 | description.workspace = true
5 | documentation.workspace = true
6 | edition.workspace = true
7 | homepage.workspace = true
8 | keywords.workspace = true
9 | license.workspace = true
10 | name = "ribir_painter"
11 | readme.workspace = true
12 | repository = "https://github.com/RibirX/Ribir/painter"
13 | version.workspace = true
14 |
15 | [dependencies]
16 | bitflags = "2.3.0"
17 | image = {workspace = true, optional = true}
18 | log.workspace = true
19 | lyon_algorithms = {version = "1.0.3", features = ["serialization"]}
20 | lyon_tessellation = {version = "1.0.3", features = ["serialization"], optional = true}
21 | material-colors = {workspace = true}
22 | ribir_algo = {path = "../algo", version = "0.4.0-alpha.53" }
23 | ribir_geom = {path = "../geom", version = "0.4.0-alpha.53" }
24 | serde = {version = "1.0", features = ["derive"]}
25 | serde_json.workspace = true
26 | usvg.workspace = true
27 | zerocopy = {workspace = true, optional = true, features = ["derive"]}
28 | derive_more= {workspace = true, features = ["add", "add_assign", "not", "mul"]}
29 | smallvec = { workspace = true, features = ["serde"] }
30 | fontdb.workspace = true
31 | rustybuzz.workspace = true
32 | unicode-bidi.workspace = true
33 | unicode-script.workspace = true
34 | unicode-segmentation.workspace = true
35 | quick-xml.workspace = true
36 | ahash.workspace = true
37 | triomphe.workspace = true
38 |
39 |
40 | [target.'cfg(target_arch = "wasm32")'.dependencies]
41 | getrandom-v3.workspace = true
42 |
43 | [features]
44 | png = ["image/png"]
45 | jpeg = ["image/jpeg"]
46 | tessellation = ["lyon_tessellation", "zerocopy"]
47 |
--------------------------------------------------------------------------------
/macros/src/asset/svg.rs:
--------------------------------------------------------------------------------
1 | use proc_macro2::TokenStream;
2 | use quote::quote;
3 |
4 | use super::{Asset, AssetContext};
5 |
6 | pub(crate) struct SvgAsset {
7 | pub(crate) inherit_fill: bool,
8 | pub(crate) inherit_stroke: bool,
9 | }
10 |
11 | impl Asset for SvgAsset {
12 | fn generate(&self, ctx: &AssetContext) -> syn::Result {
13 | // SVG always requires processing (compression/serialization), so we always
14 | // write to output, even if embedding.
15 | let compressed_data =
16 | ribir_painter::Svg::open(&ctx.abs_input, self.inherit_fill, self.inherit_stroke)
17 | .and_then(|svg| svg.serialize())
18 | .map_err(|e| {
19 | syn::Error::new(
20 | ctx.input_span,
21 | format!("Failed to compress SVG file '{}': {}", ctx.input_path, e),
22 | )
23 | })?;
24 |
25 | // The data source is always the processed output file
26 | let load_expr = if ctx.embed {
27 | quote! { #compressed_data }
28 | } else {
29 | ctx
30 | .write_output(compressed_data.as_bytes())
31 | .expect("Failed to write SVG data");
32 | let path_tokens = ctx.runtime_path_tokens();
33 | let panic_msg = ctx.panic_msg("read SVG");
34 | quote! {
35 | &std::fs::read_to_string(path_tokens)
36 | .unwrap_or_else(|e| panic!("{}: {}", #panic_msg, e))
37 | }
38 | };
39 |
40 | let deserialize_msg = format!("Failed to deserialize SVG asset '{}'", ctx.relative_output);
41 |
42 | Ok(quote! {
43 | {
44 | Svg::deserialize(#load_expr)
45 | .unwrap_or_else(|e| panic!("{}: {}", #deserialize_msg, e))
46 | }
47 | })
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/tests/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | authors.workspace = true
3 | categories.workspace = true
4 | description.workspace = true
5 | documentation.workspace = true
6 | edition.workspace = true
7 | homepage.workspace = true
8 | keywords.workspace = true
9 | license.workspace = true
10 | name = "tests"
11 | publish = false
12 | readme.workspace = true
13 | repository = "https://github.com/RibirX/Ribir/tests"
14 | version.workspace = true
15 |
16 | [dev-dependencies]
17 | paste.workspace = true
18 | ribir = {path = "../ribir", features = ["material", "widgets"]}
19 | ribir_dev_helper = {path = "../dev-helper"}
20 | ribir_geom = {path = "../geom"}
21 | ribir_painter = {path = "../painter"}
22 | ribir_core = {path = "../core", features=["test-utils"]}
23 | winit.workspace = true
24 | criterion = "0.7.0"
25 | todos = {path = "../examples/todos"}
26 | counter = {path = "../examples/counter"}
27 | messages = {path = "../examples/messages"}
28 | storybook = {path = "../examples/storybook"}
29 | wordle_game = {path = "../examples/wordle_game"}
30 |
31 | [[test]]
32 | name = "assets_test"
33 | path = "assets_test.rs"
34 |
35 | [[test]]
36 | name = "rdl_macro_test"
37 | path = "rdl_macro_test.rs"
38 |
39 | [[test]]
40 | name = "child_template_derive"
41 | path = "child_template_derive_test.rs"
42 |
43 | [[test]]
44 | name = "declare_builder"
45 | path = "declare_builder_test.rs"
46 |
47 | [[test]]
48 | name = "path_child"
49 | path = "path_child_test.rs"
50 |
51 |
52 | [[bench]]
53 | name = "text_bench"
54 | harness = false
55 |
56 | [[bench]]
57 | name = "example_bench"
58 | harness = false
59 |
60 | [[bench]]
61 | name = "core_bench"
62 | harness = false
63 |
64 | [[bench]]
65 | name = "widgets_bench"
66 | harness = false
67 |
--------------------------------------------------------------------------------
/tests/declare_builder_test.rs:
--------------------------------------------------------------------------------
1 | use ribir::{core::reset_test_env, prelude::*};
2 |
3 | #[test]
4 | fn declarer_smoke() {
5 | reset_test_env!();
6 | // empty struct
7 | #[derive(Declare)]
8 | struct A;
9 |
10 | let _: FatObj = A::declarer().finish();
11 |
12 | #[derive(Declare)]
13 | struct B {
14 | a: f32,
15 | b: i32,
16 | }
17 |
18 | let mut b = ::declarer();
19 | b.with_a(1.).with_b(1);
20 | let b = b.finish();
21 | assert_eq!(b.read().a, 1.);
22 | assert_eq!(b.read().b, 1);
23 | }
24 |
25 | #[test]
26 | #[should_panic = "Required field `T::a` not set"]
27 | fn panic_if_miss_require_field() {
28 | reset_test_env!();
29 | #[derive(Declare)]
30 | struct T {
31 | a: f32,
32 | }
33 |
34 | let _ = ::declarer().finish();
35 | }
36 |
37 | #[test]
38 |
39 | fn default_field() {
40 | reset_test_env!();
41 | #[derive(Declare)]
42 | struct DefaultDeclare {
43 | #[declare(default)]
44 | a: f32,
45 | }
46 |
47 | let t = ::declarer().finish();
48 | assert_eq!(t.read().a, 0.);
49 | }
50 |
51 | #[test]
52 |
53 | fn default_field_with_value() {
54 | reset_test_env!();
55 | #[derive(Declare)]
56 | struct DefaultWithValue {
57 | #[declare(default = "hi!")]
58 | text: &'static str,
59 | }
60 |
61 | let t = ::declarer().finish();
62 | assert_eq!(t.read().text, "hi!");
63 | }
64 |
65 | #[test]
66 | fn declarer_simple_attr() {
67 | reset_test_env!();
68 | #[simple_declare]
69 | struct Simple {
70 | a: f32,
71 | b: i32,
72 | }
73 |
74 | let mut s = Simple::declarer();
75 | s.with_a(1.).with_b(1);
76 | let s = s.finish();
77 | assert_eq!(s.read().a, 1.);
78 | assert_eq!(s.read().b, 1);
79 | }
80 |
--------------------------------------------------------------------------------
/core/src/builtin_widgets/text_style.rs:
--------------------------------------------------------------------------------
1 | use crate::prelude::*;
2 |
3 | /// Provides a `TextStyle` to descendant text widgets for painting text.
4 | ///
5 | /// This is a built-in `FatObj` field. Setting `text_style` attaches a
6 | /// `TextStyleWidget` which supplies text style information to descendants.
7 | ///
8 | /// # Example
9 | ///
10 | /// Paint text using the title-large style from the typography theme.
11 | ///
12 | /// ```rust
13 | /// use ribir::prelude::*;
14 | ///
15 | /// text! {
16 | /// text: "Big Text",
17 | /// text_style: TypographyTheme::of(BuildCtx::get()).title_large.text.clone(),
18 | /// };
19 | /// ```
20 | pub struct TextStyleWidget {
21 | pub text_style: TextStyle,
22 | }
23 |
24 | impl Declare for TextStyleWidget {
25 | type Builder = FatObj<()>;
26 | #[inline]
27 | fn declarer() -> Self::Builder { FatObj::new(()) }
28 | }
29 |
30 | impl<'c> ComposeChild<'c> for TextStyleWidget {
31 | type Child = Widget<'c>;
32 |
33 | fn compose_child(this: impl StateWriter, child: Self::Child) -> Widget<'c> {
34 | Providers::new([Self::into_provider(this)]).with_child(child)
35 | }
36 | }
37 |
38 | impl TextStyleWidget {
39 | pub fn into_provider(this: impl StateWriter) -> Provider {
40 | match this.try_into_value() {
41 | Ok(this) => Provider::new(this.text_style),
42 | Err(this) => Provider::writer(
43 | this.part_writer(PartialId::any(), |w| PartMut::new(&mut w.text_style)),
44 | Some(DirtyPhase::LayoutSubtree),
45 | ),
46 | }
47 | }
48 | }
49 |
50 | impl TextStyleWidget {
51 | pub fn inherit_widget() -> Self {
52 | TextStyleWidget {
53 | text_style: Provider::of::(BuildCtx::get())
54 | .unwrap()
55 | .clone(),
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/widgets/src/transform_box.rs:
--------------------------------------------------------------------------------
1 | use ribir_core::prelude::*;
2 |
3 | #[derive(SingleChild, Declare, Clone)]
4 | pub struct TransformBox {
5 | pub matrix: Transform,
6 | }
7 |
8 | impl Render for TransformBox {
9 | fn perform_layout(&self, clamp: BoxClamp, ctx: &mut LayoutCtx) -> Size {
10 | self
11 | .matrix
12 | .inverse()
13 | .map_or_else(Size::zero, |t| {
14 | let min_box = t.outer_transformed_box(&Box2D::from_size(clamp.min));
15 | let min = min_box.size();
16 |
17 | let max_box = t.outer_transformed_box(&Box2D::from_size(clamp.max));
18 | let max = max_box.size();
19 |
20 | let child_clamp = BoxClamp { min, max };
21 |
22 | let size = ctx.assert_perform_single_child_layout(child_clamp);
23 | let rect = self
24 | .matrix
25 | .outer_transformed_rect(&Rect::from_size(size));
26 | rect.size
27 | })
28 | }
29 |
30 | #[inline]
31 | fn visual_box(&self, ctx: &mut VisualCtx) -> Option {
32 | Some(Rect::from_size(ctx.box_size()?))
33 | }
34 |
35 | #[inline]
36 | fn paint(&self, ctx: &mut PaintingCtx) { ctx.painter().apply_transform(&self.matrix); }
37 | }
38 |
39 | impl TransformBox {
40 | #[inline]
41 | pub fn new(matrix: Transform) -> Self { Self { matrix } }
42 | }
43 |
44 | #[cfg(test)]
45 | mod tests {
46 | use ribir_core::test_helper::*;
47 | use ribir_dev_helper::*;
48 |
49 | use super::*;
50 | use crate::prelude::*;
51 |
52 | widget_layout_test!(
53 | smoke,
54 | WidgetTester::new(fn_widget! {
55 | @TransformBox {
56 | matrix: Transform::new(2., 0., 0., 2., 0., 0.),
57 | @SizedBox { size: Size::new(100., 100.) }
58 | }
59 | }),
60 | LayoutCase::default().with_size(Size::new(200., 200.))
61 | );
62 | }
63 |
--------------------------------------------------------------------------------
/painter/src/style.rs:
--------------------------------------------------------------------------------
1 | use ribir_algo::Resource;
2 | use serde::{Deserialize, Serialize};
3 |
4 | use crate::{
5 | Color, PixelImage,
6 | color::{LinearGradient, RadialGradient},
7 | };
8 |
9 | /// The brush is used to fill or stroke shapes with color, image, or gradient.
10 | #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
11 | pub enum Brush {
12 | Color(Color),
13 | /// Image brush always use a repeat mode to brush the path.
14 | Image(Resource),
15 | RadialGradient(RadialGradient),
16 | LinearGradient(LinearGradient),
17 | }
18 |
19 | impl Brush {
20 | /// Returns the color of the brush, or `None` if the brush is not a color.
21 | pub fn get_color(&self) -> Option {
22 | match self {
23 | Brush::Color(c) => Some(*c),
24 | _ => None,
25 | }
26 | }
27 |
28 | pub fn is_visible(&self) -> bool {
29 | match self {
30 | Brush::Color(c) => c.alpha > 0,
31 | Brush::Image(_) => true,
32 | Brush::RadialGradient(RadialGradient { stops, .. })
33 | | Brush::LinearGradient(LinearGradient { stops, .. }) => {
34 | stops.iter().any(|s| s.color.alpha > 0)
35 | }
36 | }
37 | }
38 | }
39 |
40 | impl From for Brush {
41 | #[inline]
42 | fn from(c: Color) -> Self { Brush::Color(c) }
43 | }
44 |
45 | impl From for Option {
46 | #[inline]
47 | fn from(c: Color) -> Self { Some(c.into()) }
48 | }
49 |
50 | impl From> for Brush {
51 | #[inline]
52 | fn from(img: Resource) -> Self { Brush::Image(img) }
53 | }
54 |
55 | impl From for Brush {
56 | #[inline]
57 | fn from(img: PixelImage) -> Self { Resource::new(img).into() }
58 | }
59 |
60 | impl Default for Brush {
61 | #[inline]
62 | fn default() -> Self { Color::BLACK.into() }
63 | }
64 |
--------------------------------------------------------------------------------
/themes/material/src/classes/menu_cls.rs:
--------------------------------------------------------------------------------
1 | use ribir_core::prelude::*;
2 | use ribir_widgets::prelude::*;
3 |
4 | pub(super) fn init(classes: &mut Classes) {
5 | classes.insert(
6 | MENU,
7 | style_class! {
8 | background: Palette::of(BuildCtx::get()).surface_container(),
9 | clamp: BoxClamp::min_width(112.).with_max_width(280.),
10 | radius: Radius::all(4.),
11 | },
12 | );
13 | classes.insert(
14 | MENU_ITEM,
15 | style_class! {
16 | clamp: BoxClamp::fixed_height(48.),
17 | },
18 | );
19 | classes.insert(
20 | MENU_ITEM_SELECTED,
21 | style_class! {
22 | clamp: BoxClamp::fixed_height(48.),
23 | background: Palette::of(BuildCtx::get()).secondary_container(),
24 | },
25 | );
26 | classes.insert(
27 | MENU_ITEM_LABEL,
28 | style_class! {
29 | foreground: Palette::of(BuildCtx::get()).on_surface_variant(),
30 | padding: EdgeInsets::horizontal(12.),
31 | text_line_height: 20.,
32 | font_size: 14.,
33 | },
34 | );
35 | classes.insert(
36 | MENU_ITEM_LEADING,
37 | style_class! {
38 | clamp: BoxClamp::fixed_size(Size::new(24., 24.)),
39 | margin: EdgeInsets::only_left(12.),
40 | },
41 | );
42 | classes.insert(
43 | MENU_ITEM_HINT_TEXT,
44 | style_class! {
45 | padding: EdgeInsets::only_right(12.),
46 | },
47 | );
48 | classes.insert(
49 | MENU_ITEM_TRAILING,
50 | style_class! {
51 | clamp: BoxClamp::fixed_size(Size::new(24., 24.)),
52 | margin: EdgeInsets::only_right(12.),
53 | },
54 | );
55 | classes.insert(
56 | MENU_DIVIDER,
57 | style_class! {
58 | clamp: BoxClamp::fixed_height(1.).with_fixed_width(f32::INFINITY),
59 | background: Palette::of(BuildCtx::get()).surface_variant(),
60 | margin: EdgeInsets::vertical(8.),
61 | },
62 | );
63 | }
64 |
--------------------------------------------------------------------------------
/changelog.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "disableEmoji": false,
3 | "list": [
4 | "test",
5 | "feat",
6 | "fix",
7 | "build",
8 | "docs",
9 | "refactor",
10 | "perf",
11 | "ce"
12 | ],
13 | "maxMessageLength": 96,
14 | "minMessageLength": 3,
15 | "questions": [
16 | "type",
17 | "scope",
18 | "subject",
19 | "body",
20 | "breaking",
21 | "issues",
22 | "lerna"
23 | ],
24 | "scopes": [
25 | "core",
26 | "painter",
27 | "macros",
28 | "gpu",
29 | "algo",
30 | "widgets",
31 | "ribir",
32 | "theme",
33 | "geom",
34 | "examples",
35 | "deps",
36 | "dev-helper"
37 | ],
38 | "types": {
39 | "build": {
40 | "description": "Build process or auxiliary tool changes",
41 | "emoji": "🤖",
42 | "value": "build"
43 | },
44 | "docs": {
45 | "description": "Documentation only changes",
46 | "emoji": "✏️",
47 | "value": "docs"
48 | },
49 | "feat": {
50 | "description": "A new feature",
51 | "emoji": "🎸",
52 | "value": "feat"
53 | },
54 | "fix": {
55 | "description": "A bug fix",
56 | "emoji": "🐛",
57 | "value": "fix"
58 | },
59 | "perf": {
60 | "description": "A code change that improves performance",
61 | "emoji": "⚡️",
62 | "value": "perf"
63 | },
64 | "refactor": {
65 | "description": "A code change that neither fixes a bug or adds a feature",
66 | "emoji": "💡",
67 | "value": "refactor"
68 | },
69 | "test": {
70 | "description": "Adding missing tests or correcting existing tests",
71 | "emoji": "💍",
72 | "value": "test"
73 | },
74 | "ce": {
75 | "description": "improve the compile error of macros",
76 | "emoji": "🔧",
77 | "value": "ce"
78 | }
79 | }
80 | };
--------------------------------------------------------------------------------
/.github/workflows/patch-version.yml:
--------------------------------------------------------------------------------
1 | on:
2 | workflow_dispatch: # allows manual triggering
3 | inputs:
4 | level:
5 | description: 'Release a patch version on the release branch, `auto` follow the last version level.'
6 | required: true
7 | default: 'auto'
8 | type: choice
9 | options:
10 | - 'auto'
11 | - 'beta'
12 | - 'rc'
13 | - 'patch'
14 | permissions:
15 | contents: write
16 | name: "Patch Version"
17 | jobs:
18 | release_level:
19 | runs-on: ubuntu-latest
20 | outputs:
21 | level: ${{ steps.concrete_level.outputs.level }}
22 | steps:
23 | - name: Release branch check
24 | if: startsWith(github.ref, 'refs/heads/release-') != true
25 | run: |
26 | echo "You should only run this workflow on the release branch."
27 | exit 1
28 | - uses: actions/checkout@v3
29 | with:
30 | fetch-depth: 0
31 | fetch-tags: true
32 | - id: auto_detect
33 | if: ${{ github.event.inputs.level == 'auto' || github.event.inputs.level == '' }}
34 | run: echo "level=$(git describe --tags --abbrev=0 | grep -o "rc\|beta")" >> $GITHUB_OUTPUT
35 | - id: concrete_level
36 | run: |
37 | level=${{ steps.auto_detect.outputs.level }}
38 | echo "level=${level:=${{inputs.level}}}" >> $GITHUB_OUTPUT
39 | call-workflow-passing-data:
40 | needs: release_level
41 | uses: RibirX/rclog/.github/workflows/release-version.yml@main
42 | with:
43 | level: ${{ needs.release_level.outputs.level }}
44 | ref: ${{ github.ref }}
45 | merge_changelog: ${{ needs.release_level.outputs.level == 'patch' }}
46 | toolchain: stable
47 | secrets:
48 | CRATE_RELEASE_TOKEN: ${{ secrets.CRATE_RELEASE_TOKEN }}
49 | GITHUB_RELEASE_TOKEN: ${{ secrets.RIBIR_RELEASE }}
--------------------------------------------------------------------------------
/core/src/events/wheel.rs:
--------------------------------------------------------------------------------
1 | use crate::{impl_common_event_deref, prelude::*};
2 |
3 | #[derive(Debug)]
4 | pub struct WheelEvent {
5 | pub delta_x: f32,
6 | pub delta_y: f32,
7 | pub common: CommonEvent,
8 | }
9 |
10 | impl_common_event_deref!(WheelEvent);
11 |
12 | impl WheelEvent {
13 | #[inline]
14 | pub fn new(delta_x: f32, delta_y: f32, id: WidgetId, wnd: &Window) -> Self {
15 | Self { delta_x, delta_y, common: CommonEvent::new(id, wnd.tree) }
16 | }
17 | }
18 |
19 | #[cfg(test)]
20 | mod tests {
21 | use super::*;
22 | use crate::{reset_test_env, test_helper::*};
23 |
24 | #[test]
25 | fn smoke() {
26 | reset_test_env!();
27 |
28 | let (bubble_receive_reader, bubble_receive) = split_value((0., 0.));
29 | let (capture_receive_reader, capture_receive) = split_value((0., 0.));
30 | let (event_order_reader, event_order) = split_value(vec![]);
31 |
32 | let widget = fn_widget! {
33 | @MockBox {
34 | size: Size::new(200., 200.),
35 | on_wheel_capture: move |wheel| {
36 | *$write(capture_receive) = (wheel.delta_x, wheel.delta_y);
37 | $write(event_order).push("capture");
38 | },
39 | @MockBox {
40 | size: Size::new(100., 100.),
41 | auto_focus: true,
42 | on_wheel: move |wheel| {
43 | *$write(bubble_receive) = (wheel.delta_x, wheel.delta_y);
44 | $write(event_order).push("bubble");
45 | }
46 | }
47 | }
48 | };
49 |
50 | let wnd = TestWindow::new_with_size(widget, Size::new(100., 100.));
51 |
52 | wnd.draw_frame();
53 |
54 | wnd.process_wheel(1.0, 1.0);
55 | wnd.run_frame_tasks();
56 |
57 | assert_eq!(*bubble_receive_reader.read(), (1., 1.));
58 | assert_eq!(*capture_receive_reader.read(), (1., 1.));
59 | assert_eq!(*event_order_reader.read(), ["capture", "bubble"]);
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/docs/zh/guide/README.md:
--------------------------------------------------------------------------------
1 | # 指南
2 |
3 | 本指南介绍 Ribir 的基本概念和使用模式,Ribir 是一个非侵入式的 Rust GUI 框架,让您能够从单一代码库构建跨平台应用程序。
4 |
5 | ## 核心概念
6 |
7 | ### 声明式 UI
8 | Ribir 使用声明式方法进行 UI 开发,您可以根据当前状态描述 UI 应该是什么样子。当状态改变时,框架会自动处理渲染和更新。
9 |
10 | ### Widget 和组合
11 | Ribir 中的一切都是由 Widget 构建的。您可以使用 `fn_widget!` 宏和 `@` 语法将简单的 Widget 组合成复杂的 UI:
12 |
13 | ```rust no_run
14 | use ribir::prelude::*;
15 | fn_widget! {
16 | @Container {
17 | size: Size::new(100., 100.),
18 | background: Color::RED,
19 | @Text { text: "Hello, Ribir!" }
20 | }
21 | };
22 | ```
23 |
24 | ### 状态管理
25 | Ribir 通过 `Stateful` 对象提供响应式状态管理。您可以使用 `$read` 读取状态,使用 `$write` 写入状态,并使用 `pipe!` 和 `watch!` 创建响应式绑定:
26 |
27 | ```rust no_run
28 | use ribir::prelude::*;
29 | let counter = Stateful::new(0);
30 | fn_widget! {
31 | @Column {
32 | @Text { text: pipe!($read(counter).to_string()) }
33 | @Button {
34 | on_tap: move |_| *$write(counter) += 1,
35 | @{ "Increment" }
36 | }
37 | }
38 | };
39 | ```
40 |
41 | ### 布局系统
42 | Ribir 的布局系统使用约束向下流动到 Widget 树,尺寸信息向上回流。`clamp` 属性允许您控制 Widget 在可用空间内如何调整尺寸。
43 |
44 | ### 数据共享和事件
45 | 使用 `Provider` 通过 Widget 树自上而下地共享数据,使用 `自定义事件` 从子 Widget 向上冒泡事件到父 Widget。
46 |
47 | ## 入门
48 |
49 | 要开始使用 Ribir 构建应用,请详细了解这些核心概念:
50 | - **[声明式 UI](./core_concepts/declarative_ui.md)**: 了解 DSL 语法和 Widget 组合
51 | - **[内置属性和 FatObj](./core_concepts/built_in_attributes_and_fat_obj.md)**: 使用内置功能
52 | - **[状态管理](./core_concepts/state_management.md)**: 管理应用程序状态
53 | - **[数据共享和事件](./core_concepts/data_sharing_and_events.md)**: 组件间的通信
54 | - **[Widget 系统](./core_concepts/widgets_composition.md)**: 了解架构
55 | - **[布局系统](./core_concepts/layout.md)**: 控制 UI 的排列方式
56 |
57 | 一旦您熟悉了这些基础知识,可以继续学习高级主题以扩展您的知识:
58 | - **[自定义 Widget](./advanced/custom_widgets.md)**: 构建可重用组件
59 | - **[动画](./advanced/animations.md)**: 为 UI 添加动态效果
60 | - **[主题](./advanced/theming.md)**: 自定义外观和风格
61 | - **[Widget 组件](./advanced/widgets.md)**: 详细了解 Widget 组件
--------------------------------------------------------------------------------
/themes/material/src/classes/divider_cls.rs:
--------------------------------------------------------------------------------
1 | use ribir_core::prelude::*;
2 | use ribir_widgets::prelude::*;
3 |
4 | use crate::md;
5 |
6 | const THICKNESS: f32 = 1.;
7 |
8 | named_style_impl!(horizontal_base => {
9 | clamp: BoxClamp::fixed_height(THICKNESS),
10 | h_align: HAlign::Stretch,
11 | background: Palette::of(BuildCtx::get()).outline_variant(),
12 | });
13 |
14 | named_style_impl!(vertical_base => {
15 | clamp: BoxClamp::fixed_width(THICKNESS),
16 | v_align: VAlign::Stretch,
17 | background: Palette::of(BuildCtx::get()).outline_variant(),
18 | });
19 | pub(super) fn init(classes: &mut Classes) {
20 | classes.insert(HORIZONTAL_DIVIDER, horizontal_base);
21 |
22 | classes.insert(
23 | HORIZONTAL_DIVIDER_INDENT_START,
24 | class_multi_impl! {
25 | horizontal_base,
26 | style_class!{ margin: md::EDGES_LEFT_16 }
27 | },
28 | );
29 |
30 | classes.insert(
31 | HORIZONTAL_DIVIDER_INDENT_END,
32 | class_multi_impl! {
33 | horizontal_base,
34 | style_class!{ margin: md::EDGES_RIGHT_16 }
35 | },
36 | );
37 |
38 | classes.insert(
39 | HORIZONTAL_DIVIDER_INDENT_BOTH,
40 | class_multi_impl! {
41 | horizontal_base,
42 | style_class!{ margin: md::EDGES_HOR_16 }
43 | },
44 | );
45 |
46 | classes.insert(VERTICAL_DIVIDER, vertical_base);
47 |
48 | classes.insert(
49 | VERTICAL_DIVIDER_INDENT_START,
50 | class_multi_impl! {
51 | vertical_base,
52 | style_class! { margin: md::EDGES_TOP_8 }
53 | },
54 | );
55 |
56 | classes.insert(
57 | VERTICAL_DIVIDER_INDENT_END,
58 | class_multi_impl! {
59 | vertical_base,
60 | style_class! { margin: md::EDGES_BOTTOM_8}
61 | },
62 | );
63 |
64 | classes.insert(
65 | VERTICAL_DIVIDER_INDENT_BOTH,
66 | class_multi_impl! {
67 | vertical_base,
68 | style_class! { margin: md::EDGES_VER_8 }
69 | },
70 | );
71 | }
72 |
--------------------------------------------------------------------------------
/core/src/builtin_widgets/disabled.rs:
--------------------------------------------------------------------------------
1 | use crate::prelude::*;
2 |
3 | class_names! {
4 | #[doc = "Class name for the Disabled"]
5 | DISABLED,
6 | }
7 |
8 | /// A widget wrapper that marks its subtree as disabled.
9 | ///
10 | /// When disabled, a widget and its descendants do not receive keyboard or
11 | /// pointer events. Toggle the built-in `disabled` field to apply this
12 | /// behavior. To change the visual appearance, provide a custom `Disabled`
13 | /// style class.
14 | ///
15 | /// This is a built-in `FatObj` field. Setting `disabled` attaches a
16 | /// `Disabled` wrapper to the host.
17 | ///
18 | /// # Example
19 | ///
20 | /// Disable a text widget so it cannot be clicked.
21 | ///
22 | /// ```rust
23 | /// use ribir::prelude::*;
24 | ///
25 | /// text! {
26 | /// text: "You can't click me",
27 | /// disabled: true,
28 | /// on_tap: |_: &mut PointerEvent| println!("Click!"),
29 | /// };
30 | /// ```
31 | #[derive(Clone, Default)]
32 | pub struct Disabled {
33 | pub disabled: bool,
34 | }
35 |
36 | impl Declare for Disabled {
37 | type Builder = FatObj<()>;
38 | #[inline]
39 | fn declarer() -> Self::Builder { FatObj::new(()) }
40 | }
41 |
42 | impl<'c> ComposeChild<'c> for Disabled {
43 | type Child = Widget<'c>;
44 | fn compose_child(this: impl StateWriter, child: Self::Child) -> Widget<'c> {
45 | fn_widget! {
46 | let mut child = FatObj::new(child);
47 | @FocusScope {
48 | skip_descendants: pipe!($read(this).disabled()),
49 | skip_host: pipe!($read(this).disabled()),
50 | @IgnorePointer {
51 | ignore: pipe! {
52 | if $read(this).disabled() { IgnoreScope::Subtree } else { IgnoreScope::None }
53 | },
54 | @(child) { class: pipe!($read(this).disabled().then_some(DISABLED)) }
55 | }
56 | }
57 | }
58 | .into_widget()
59 | }
60 | }
61 |
62 | impl Disabled {
63 | fn disabled(&self) -> bool { self.disabled }
64 | }
65 |
--------------------------------------------------------------------------------
/examples/pomodoro/src/main.rs:
--------------------------------------------------------------------------------
1 | #![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
2 |
3 | mod audio;
4 | mod config;
5 | mod pomodoro;
6 | mod ui;
7 |
8 | use pomodoro::Pomodoro;
9 | use ribir::{material, prelude::*};
10 |
11 | use crate::ui::{
12 | APP_ICON, load_icons,
13 | styles::{MINI_HEIGHT, MINI_WIDTH},
14 | };
15 |
16 | pub fn main() {
17 | load_icons();
18 | App::run(fn_widget! { @Pomodoro {}})
19 | .with_app_theme(material::purple::light)
20 | .with_size(Size::new(MINI_WIDTH, MINI_HEIGHT))
21 | .with_resizable(false)
22 | .with_icon(&APP_ICON)
23 | .with_decorations(false)
24 | .with_title("Pomodoro Timer");
25 | }
26 |
27 | #[cfg(not(target_arch = "wasm32"))]
28 | #[cfg(test)]
29 | mod tests {
30 | use ribir::{core::test_helper::*, material as ribir_material};
31 | use ribir_dev_helper::*;
32 |
33 | use super::*;
34 | use crate::config::PomodoroConfig;
35 |
36 | fn mini_pomodoro() -> Widget<'static> {
37 | load_icons();
38 | let mut config = PomodoroConfig::default_config();
39 | config.auto_run = false;
40 | config.start_mini_mode = true;
41 | fn_widget! {
42 | @Pomodoro {
43 | config: config,
44 | }
45 | }
46 | .into_widget()
47 | }
48 |
49 | fn full_pomodoro() -> Widget<'static> {
50 | load_icons();
51 | let mut config = PomodoroConfig::default_config();
52 | config.auto_run = false;
53 | config.start_mini_mode = false;
54 | fn_widget! {
55 | @Pomodoro {
56 | config: config,
57 | }
58 | }
59 | .into_widget()
60 | }
61 |
62 | widget_image_tests!(
63 | mini_pomodoro,
64 | WidgetTester::new(mini_pomodoro)
65 | .with_wnd_size(Size::new(320., 240.))
66 | .with_comparison(0.0005)
67 | );
68 | widget_image_tests!(
69 | full_pomodoro,
70 | WidgetTester::new(full_pomodoro)
71 | .with_wnd_size(Size::new(320., 240.))
72 | .with_comparison(0.0005)
73 | );
74 | }
75 |
--------------------------------------------------------------------------------
/core/src/builtin_widgets/ignore_pointer.rs:
--------------------------------------------------------------------------------
1 | use crate::{prelude::*, wrap_render::*};
2 |
3 | /// A wrapper that ignores pointer events according to a specified scope.
4 | ///
5 | /// `IgnorePointer` can suppress pointer events for the host, only the host,
6 | /// or the whole subtree depending on `IgnoreScope`.
7 | ///
8 | /// # Example
9 | ///
10 | /// The red container below will not respond to pointer events when the scope
11 | /// is set to `IgnoreScope::Subtree`.
12 | ///
13 | /// ```rust
14 | /// use ribir::prelude::*;
15 | ///
16 | /// fn_widget! {
17 | /// @IgnorePointer {
18 | /// ignore: IgnoreScope::Subtree,
19 | /// @Container {
20 | /// size: Size::new(100., 100.),
21 | /// background: Color::RED,
22 | /// on_tap: |_: &mut PointerEvent| println!("This will never be printed"),
23 | /// }
24 | /// }
25 | /// };
26 | /// ```
27 | #[derive(Declare, Clone)]
28 | pub struct IgnorePointer {
29 | #[declare(default)]
30 | pub ignore: IgnoreScope,
31 | }
32 |
33 | /// Specify the scope for ignoring events.
34 | #[derive(Debug, Clone, Copy, Default)]
35 | pub enum IgnoreScope {
36 | /// Not ignore
37 | None,
38 | /// Ignore only the event of the current widget.
39 | OnlySelf,
40 | /// Ignored the event within the subtree, including the current widget.
41 | #[default]
42 | Subtree,
43 | }
44 |
45 | impl_compose_child_for_wrap_render!(IgnorePointer);
46 |
47 | impl WrapRender for IgnorePointer {
48 | fn hit_test(&self, host: &dyn Render, ctx: &mut HitTestCtx, pos: Point) -> HitTest {
49 | match self.ignore {
50 | IgnoreScope::Subtree => HitTest { hit: false, can_hit_child: false },
51 | IgnoreScope::OnlySelf => {
52 | let hit = host.hit_test(ctx, pos);
53 | HitTest { hit: false, can_hit_child: hit.can_hit_child }
54 | }
55 | IgnoreScope::None => host.hit_test(ctx, pos),
56 | }
57 | }
58 |
59 | #[inline]
60 | fn wrapper_dirty_phase(&self) -> DirtyPhase { DirtyPhase::Paint }
61 | }
62 |
--------------------------------------------------------------------------------
/docs/en/get_started/try_it.md:
--------------------------------------------------------------------------------
1 | ---
2 | sidebar_position: 1
3 | ---
4 |
5 | # Try Ribir
6 |
7 | > You will learn
8 | >
9 | > - How to write and start a simple `Hello world!` application
10 |
11 |
12 | ## Install Rust
13 |
14 | At first, you need to install Rust, you can reference the [official documentation](https://www.rust-lang.org/tools/install).
15 |
16 |
17 | ## Create a new Ribir project
18 |
19 | Then, open your terminal and create a new Rust project:
20 |
21 | ```sh
22 | cargo new ribir-hello-world
23 | cd ribir-hello-world
24 | ```
25 |
26 | Next, edit the `Cargo.toml` file and add Ribir as a dependency:
27 |
28 | ```toml
29 | [dependencies]
30 | ribir = "@RIBIR_VERSION"
31 | ```
32 |
33 | Or you can directly run `cargo add --git "https://github.com/RibirX/Ribir" ribir` to let Cargo add the latest Ribir version that is under development for you.
34 |
35 | ## Start writing `main.rs`
36 |
37 | Open your editor and modify the `src/main.rs` file to:
38 |
39 | ```rust no_run
40 | // main.rs
41 | use ribir::prelude::*;
42 |
43 | fn main() {
44 | App::run(text! { text: "Hello World!" });
45 | }
46 | ```
47 |
48 | ## Run the application
49 |
50 | ```sh
51 | cargo run
52 | ```
53 |
54 | Congratulations! You have completed your first Ribir project.
55 |
56 | ## Run Ribir's built-in examples
57 |
58 | Finally, there are some other examples in the Ribir repository, you can clone the Git repository:
59 |
60 | ```sh
61 | git clone git@github.com:RibirX/Ribir.git
62 | cd Ribir/Ribir
63 | ```
64 |
65 | and run the examples with one of the following commands:
66 |
67 | ```sh
68 | cargo run -p counter
69 | cargo run -p storybook
70 | cargo run -p messages
71 | cargo run -p todos
72 | cargo run -p wordle_game
73 | ```
74 |
75 | ## Next Steps
76 |
77 | If you're hesitant about creating UI with "DSL" and prefer to build your UI through direct function calls, before moving on to the next step, you might want to read [Using Ribir without "DSL"](../understanding_ribir/without_dsl.md) first.
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/documentation.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Documentation
3 | about: Report an issue relating to Ribir's documetation
4 | title: ''
5 | labels: documentation
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
12 | This is about:
13 | - [ ] A typo
14 | - [ ] Innaccurate/misleading documentation (e.g. technically incorrect advice)
15 | - [ ] Undocumented code
16 | - [ ] Outdated documentation
17 | - [ ] Other
18 |
19 | **Problem**
20 |
25 |
26 |
27 |
28 |
30 |
31 |
32 |
33 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | **Details about the solution you'd like** _(Optional)_
44 |
45 | **Additional context** _(Optional)_
46 |
47 |
48 | **Questionaire** _(Optional)_
49 | - [ ] I'd like to write this documentation
50 | - [ ] I'd like to write this documentation but I'm not sure what's needed
51 | - [ ] I don't have time to add this right now, but maybe later
52 |
--------------------------------------------------------------------------------
/.github/workflows/ISSUE_TEMPLATE/documentation.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Documentation
3 | about: Report an issue relating to this project's documetation.
4 | title: ''
5 | labels: documentation
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
12 | This is about:
13 | - [ ] A typo
14 | - [ ] Innaccurate/misleading documentation (e.g. technically incorrect advice)
15 | - [ ] Undocumented code
16 | - [ ] Outdated documentation
17 | - [ ] Other
18 |
19 | **Problem**
20 |
25 |
26 |
27 |
28 |
30 |
31 |
32 |
33 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | **Details about the solution you'd like** _(Optional)_
44 |
45 | **Additional context** _(Optional)_
46 |
47 |
48 | **Questionaire** _(Optional)_
49 | - [ ] I'd like to write this documentation
50 | - [ ] I'd like to write this documentation but I'm not sure what's needed
51 | - [ ] I don't have time to add this right now, but maybe later
--------------------------------------------------------------------------------
/core/src/builtin_widgets/track_widget_id.rs:
--------------------------------------------------------------------------------
1 | use crate::prelude::*;
2 |
3 | #[derive(Default)]
4 | pub struct TrackWidgetId {
5 | pub(crate) wid: TrackId,
6 | }
7 |
8 | impl<'c> ComposeChild<'c> for TrackWidgetId {
9 | type Child = Widget<'c>;
10 | fn compose_child(this: impl StateWriter, child: Self::Child) -> Widget<'c> {
11 | let track_id = this.read().wid.clone();
12 | child
13 | .on_build(move |id| track_id.set(Some(id)))
14 | .attach_data(Box::new(Queryable(this.read().wid.clone())))
15 | }
16 | }
17 |
18 | impl TrackWidgetId {
19 | /// The WidgetId of the Widget may be changed durning running.
20 | /// Don't rely on the id to do things unless necessary. If you must get the
21 | /// id, you can use TrackId to capture the value.
22 | pub fn track_id(&self) -> TrackId { self.wid.clone() }
23 | }
24 |
25 | impl Declare for TrackWidgetId {
26 | type Builder = FatObj<()>;
27 | #[inline]
28 | fn declarer() -> Self::Builder { FatObj::new(()) }
29 | }
30 |
31 | #[cfg(test)]
32 | mod tests {
33 | use super::*;
34 | use crate::{
35 | reset_test_env,
36 | test_helper::{split_value, *},
37 | };
38 |
39 | #[test]
40 | fn track_id_of_pipe() {
41 | reset_test_env!();
42 | let (trigger, w_trigger) = split_value(false);
43 | let (id, w_id) = split_value(