1 /* <lambda>null2 * Copyright 2024 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package androidx.compose.material3.carousel 18 19 import androidx.compose.foundation.BorderStroke 20 import androidx.compose.foundation.border 21 import androidx.compose.foundation.shape.GenericShape 22 import androidx.compose.material3.ExperimentalMaterial3Api 23 import androidx.compose.runtime.Composable 24 import androidx.compose.runtime.remember 25 import androidx.compose.ui.Modifier 26 import androidx.compose.ui.draw.clip 27 import androidx.compose.ui.geometry.Offset 28 import androidx.compose.ui.geometry.toRect 29 import androidx.compose.ui.graphics.Shape 30 import androidx.compose.ui.graphics.addOutline 31 import androidx.compose.ui.platform.LocalDensity 32 33 /** Receiver scope for [Carousel] item content. */ 34 @ExperimentalMaterial3Api 35 sealed interface CarouselItemScope { 36 /** 37 * Information regarding the carousel item, such as its minimum and maximum size. 38 * 39 * The item information is updated after every scroll. If you use it in a composable function, 40 * it will be recomposed on every change causing potential performance issues. Avoid using it in 41 * the composition. 42 */ 43 val carouselItemDrawInfo: CarouselItemDrawInfo 44 45 /** 46 * Clips the composable to the given [shape], taking into account the item's size in the cross 47 * axis and mask in the main axis. 48 * 49 * @param shape the shape to be applied to the composable 50 */ 51 @Composable fun Modifier.maskClip(shape: Shape): Modifier 52 53 /** 54 * Draw a border on the composable using the given [shape], taking into account the item's size 55 * in the cross axis and mask in the main axis. 56 * 57 * @param border the border to be drawn around the composable 58 * @param shape the shape of the border 59 */ 60 @Composable fun Modifier.maskBorder(border: BorderStroke, shape: Shape): Modifier 61 62 /** 63 * Converts and remembers [shape] into a [GenericShape] that uses the intersection of the 64 * carousel item's mask Rect and Size as the final shape's bounds. 65 * 66 * This method is useful if using a [Shape] in a Modifier other than [maskClip] and [maskBorder] 67 * where the shape should follow the changes in the item's mask size. 68 * 69 * @param shape The shape that will be converted and remembered and react to changes in the 70 * item's mask. 71 */ 72 @Composable fun rememberMaskShape(shape: Shape): GenericShape 73 } 74 75 @ExperimentalMaterial3Api 76 internal class CarouselItemScopeImpl(private val itemInfo: CarouselItemDrawInfo) : 77 CarouselItemScope { 78 override val carouselItemDrawInfo: CarouselItemDrawInfo 79 get() = itemInfo 80 81 @Composable maskClipnull82 override fun Modifier.maskClip(shape: Shape): Modifier = clip(rememberMaskShape(shape = shape)) 83 84 @Composable 85 override fun Modifier.maskBorder(border: BorderStroke, shape: Shape): Modifier = 86 border(border, rememberMaskShape(shape = shape)) 87 88 @Composable 89 override fun rememberMaskShape(shape: Shape): GenericShape { 90 val density = LocalDensity.current 91 return remember(carouselItemDrawInfo, density) { 92 GenericShape { size, direction -> 93 val rect = carouselItemDrawInfo.maskRect.intersect(size.toRect()) 94 addOutline(shape.createOutline(rect.size, direction, density)) 95 translate(Offset(rect.left, rect.top)) 96 } 97 } 98 } 99 } 100