Skip to content

Feature/add carousel#18

Open
EdwardAbrosimov wants to merge 11 commits into
hypengw:mainfrom
EdwardAbrosimov:feature/add_carousel
Open

Feature/add carousel#18
EdwardAbrosimov wants to merge 11 commits into
hypengw:mainfrom
EdwardAbrosimov:feature/add_carousel

Conversation

@EdwardAbrosimov

Copy link
Copy Markdown
Contributor

Summary

Adds MD.Carousel following Material 3 Carousel, with a C++ layout engine, snap scrolling, and an accessibility-focused QML wrapper.

  • 6 layouts: Uncontained, Uncontained Multi-aspect, Multi-browse, Hero (start-aligned), Hero (center-aligned), Full-screen (horizontal and vertical)
  • Engine: CarouselView + keylines / scroll strategy — item sizing, parallax, masks, snap offsets
  • Public API: MD.Carousel, MD.CarouselItem, MD.CarouselImageDelegate; tokens in MD.Token.carousel
  • Navigation: buttons, page indicator, keyboard (arrows, Home/End), focus management, and Accessible
  • Mouse wheel: snap by ±1 item (same as nav buttons), not free flickable scroll
    • horizontal layouts → Shift + wheel
    • CarouselFullScreen → wheel without modifiers (including vertical)
    • Alt+wheel does not scroll the carousel (horizontalScrollModifiers: NoModifier)
  • Model: int, QVariantList, JS array, QAbstractItemModel (including dataChanged and count shrink)
  • Demo: Carousel section in example/Components.qml + CarouselDemoData.qml and sample images
  • Related fixes: WheelHandler (QQmlContext fallback, horizontalScrollModifiers), VerticalFlickable (viewportHeight), NavigationRail / StandardDrawer (implicit height), FocusIndicator

Architecture

Layer Files
QML control qml/control/Carousel.qml
Delegate / item qml/component/carousel/CarouselItem.qml, CarouselImageDelegate.qml
C++ view src/carousel/carousel_view.cpp
Layout engine carousel_keylines.cpp, carousel_scroll_strategy.cpp, carousel_strategy.hpp
Attached carousel_attached.cpp (keyboard / focus hooks)

CarouselLayoutId in carousel_strategy.hpp is kept in sync with MD.Enum.CarouselLayout; CarouselEngineDefaults is validated via static_assert in tests.

Wheel / input (review focus)

Previously MD.WheelHandler scrolled the flickable directly — on Full-screen vertical this produced intermediate positions between snap points. Now:

  • scrollFlickableTarget: false
  • onWheelincrementCurrentIndex() / decrementCurrentIndex() → animated snap in C++
  • Mouse drag still allows free scroll until release (expected M3 behavior)

Demo assets

Abstract images under example/assets/carousel/ were generated programmatically (procedural / code-generated artwork). They are used only for demos and tests and carry no third-party copyright.

Layout demos (screencasts)

Uncontained — fixed width

CarouselUncontained · horizontal · equal item width · peek at trailing edge

Screencast.from.2026-06-18.15-34-53.mp4

Uncontained — multi-aspect

CarouselUncontainedMultiAspect · horizontal · per-item aspect ratio · variable item widths

Screencast.from.2026-06-18.15-46-19.mp4

Multi-browse

CarouselMultiBrowse · horizontal · large / medium / small size classes · page indicator + nav buttons

Screencast.from.2026-06-18.15-49-45.mp4

Hero — start-aligned

CarouselHero · horizontal · dominant start item · trailing peek

Screencast.from.2026-06-18.15-54-14.mp4

Hero — center-aligned

CarouselHeroCenter · horizontal · centered large item · peeks on both sides

Screencast.from.2026-06-18.15-55-49.mp4

Full-screen — vertical

CarouselFullScreen · vertical · one edge-to-edge item per page · wheel without Shift

Screencast.from.2026-06-18.15-58-47.mp4

Tests

Unit / integration (headless, except View tests):

ctest -R "hero_center_end|hero_start_layout|fullscreen_layout|multi_browse_layout|uncontained_layout|set_current_index_sync|model_shrink|model_data_changed|carousel_engine_defaults"

Visual: tests/scenes/carousel.qml (ctest target carousel).

Test plan

  • qm_example → Components → Carousel: all 6 layouts
  • ← → buttons and page indicator stay in sync with currentIndex
  • Shift + wheel on horizontal layouts → ±1 item with snap
  • Full-screen vertical: wheel without Shift → ±1 item, no stopping between cards
  • Alt + wheel does not scroll the carousel
  • Keyboard: Tab → item focus, arrows / Home / End
  • ctest (command above) — green
  • Shrinking the model does not leave currentIndex out of range

e.abrosimov added 11 commits June 16, 2026 10:37
- Added carousel layout enums and tokens for better customization.
- Updated example files to demonstrate carousel functionality with various layouts.
- Included new carousel images in the resource files.
- Adjusted CMakeLists to include carousel sources and resources.
…ayout enum for uncontained multi-aspect carousels, updated CarouselImageDelegate to handle aspect ratios, and modified CarouselView to accommodate variable item widths. Updated example scenes to demonstrate new layout capabilities.
…accessibility and keyboard navigation. Added properties for carousel count, orientation, and current index. Implemented keyboard navigation methods and focus management in CarouselView and CarouselItem. Updated QML components to support new features and improve user experience.
…er radius. Updated corner properties to dynamically adjust based on visible dimensions, enhancing visual consistency and responsiveness in the carousel layout. Hero start-aligned works fine.
…nd structures for hero keylines and scroll strategies, enhancing layout transitions and item sizing. Implemented hero center layout logic in CarouselView and added corresponding tests to validate functionality.
… layout logic for full-screen items, updated CarouselView to handle full-screen layout interactions, and modified example scenes to showcase the new layout. Introduced tests to validate full-screen functionality and ensure correct item sizing and snapping behavior.
…ht calculations and content management. Updated implicit height properties to use contentImplicitHeight and scrollExtent for better responsiveness. Enhanced VerticalFlickable with viewportHeight and implicitContentHeight properties for improved layout handling.
…ting carousel model handling. Enhanced CarouselView to support item model binding and improved layout synchronization. Updated example scenes to utilize new CarouselDemoData for carousel items, ensuring better data management and responsiveness.
- Introduced `carousel_engine_defaults.cpp` to validate default values against `TokenCarouselLiterals`.
- Added `model_data_changed.cpp` to test the interaction between a custom list model and the `CarouselView`, ensuring data updates reflect correctly in the UI.
- Implemented a test structure for verifying carousel item behavior and model binding.
- Added new property for horizontal scroll modifiers in WheelHandler.
- Implemented getter, setter, and reset methods for horizontal scroll modifiers.
- Updated scroll handling logic to utilize horizontal scroll modifiers for improved interaction.
- Modified Carousel.qml to integrate horizontal scroll handling with shift key requirement for better user experience.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant