@@ -16,7 +16,8 @@ import androidx.compose.ui.geometry.Size
1616import androidx.compose.ui.graphics.Brush
1717import androidx.compose.ui.graphics.Color
1818import androidx.compose.ui.graphics.TileMode
19- import androidx.compose.ui.layout.onSizeChanged
19+ import androidx.compose.ui.platform.LocalDensity
20+ import androidx.compose.ui.unit.DpSize
2021import androidx.compose.ui.unit.dp
2122import androidx.compose.ui.unit.sp
2223import com.smarttoolfactory.colorpicker.ui.GradientAngle
@@ -30,18 +31,57 @@ import com.smarttoolfactory.slider.ColorfulSlider
3031import com.smarttoolfactory.slider.MaterialSliderDefaults
3132import com.smarttoolfactory.slider.ui.InactiveTrackColor
3233
34+ enum class GradientType {
35+ Linear , Radial , Sweep
36+ }
37+
3338internal val gradientOptions = listOf (
3439 " Linear" ,
3540 " Radial" ,
3641 " Sweep"
3742)
43+
3844internal val gradientTileModeOptions = listOf (" Clamp" , " Repeated" , " Mirror" , " Decal" )
3945
4046@Composable
41- fun GradientSelector (color : Color , size : Size = Size .Unspecified ) {
47+ fun GradientSelector (
48+ color : Color ,
49+ dpSize : DpSize ,
50+ onGradientChange : (Brush ) -> Unit
51+ ) {
52+
53+ val size = with (LocalDensity .current) {
54+ Size (
55+ dpSize.width.toPx(),
56+ dpSize.width.toPx()
57+ )
58+ }
4259
43- var gradientSelection by remember { mutableStateOf(0 ) }
60+ // Gradient type
61+ var gradientType by remember { mutableStateOf(GradientType .Linear ) }
62+
63+ // Tile mode
4464 var tileModeSelection by remember { mutableStateOf(0 ) }
65+ val tileMode = when (tileModeSelection) {
66+ 0 -> TileMode .Clamp
67+ 1 -> TileMode .Repeated
68+ 2 -> TileMode .Mirror
69+ else -> TileMode .Decal
70+ }
71+
72+ // Color Stops
73+ val colorStops = remember {
74+ mutableStateListOf(
75+ 0.0f to Color .Red ,
76+ 0.3f to Color .Green ,
77+ 1.0f to Color .Blue ,
78+ )
79+ }
80+
81+ // Offset for Linear Gradient
82+ var gradientOffset by remember {
83+ mutableStateOf(GradientOffset (GradientAngle .CW0 ))
84+ }
4585
4686 Column (
4787 modifier = Modifier
@@ -51,14 +91,16 @@ fun GradientSelector(color: Color, size: Size = Size.Unspecified) {
5191 ) {
5292 ExposedSelectionMenu (
5393 modifier = Modifier .fillMaxWidth(),
54- index = gradientSelection ,
94+ index = gradientType.ordinal ,
5595 title = " Gradient" ,
5696 options = gradientOptions,
5797 onSelected = {
58- gradientSelection = it
98+ gradientType = GradientType .values()[it]
5999 }
60100 )
101+
61102 Spacer (modifier = Modifier .height(10 .dp))
103+
62104 ExposedSelectionMenu (
63105 modifier = Modifier .fillMaxWidth(),
64106 index = tileModeSelection,
@@ -69,80 +111,117 @@ fun GradientSelector(color: Color, size: Size = Size.Unspecified) {
69111 }
70112 )
71113
72- val tileMode = when (tileModeSelection) {
73- 0 -> TileMode .Clamp
74- 1 -> TileMode .Repeated
75- 2 -> TileMode .Mirror
76- else -> TileMode .Decal
114+ // Display Brush
115+ BrushDisplay (
116+ gradientType = gradientType,
117+ colorStops = colorStops,
118+ gradientOffset = gradientOffset,
119+ size = size,
120+ tileMode = tileMode
121+ ) { brush: Brush ->
122+ onGradientChange(brush)
123+ }
124+
125+ // Gradient type selection
126+ when (gradientType) {
127+ GradientType .Linear -> LinearGradientSelection (
128+ size,
129+ ) { offset: GradientOffset ->
130+ gradientOffset = offset
131+ }
132+ GradientType .Radial -> RadialGradientSelection (
133+ size,
134+ ) { offset: GradientOffset ->
135+ gradientOffset = offset
136+ }
137+ GradientType .Sweep -> SweepGradientSelection (
138+ size,
139+ ) { offset: GradientOffset ->
140+ gradientOffset = offset
141+ }
77142 }
78- LinearGradientSelection (currentColor = color, tileMode = tileMode)
143+
144+ // Color Stops and Colors
145+ ColorStopSelection (
146+ color = color,
147+ colorStops = colorStops,
148+ onRemoveClick = { index: Int ->
149+ if (colorStops.size > 2 ) {
150+ colorStops.removeAt(index)
151+ }
152+ },
153+ onValueChange = { index: Int , pair: Pair <Float , Color > ->
154+ colorStops[index] = pair.copy()
155+ },
156+ onAddColorStop = { pair: Pair <Float , Color > ->
157+ colorStops.add(pair)
158+ }
159+ )
79160 }
80161}
81162
82163@Composable
83- internal fun LinearGradientSelection (currentColor : Color , tileMode : TileMode ) {
164+ internal fun BrushDisplay (
165+ gradientType : GradientType ,
166+ colorStops : List <Pair <Float , Color >>,
167+ gradientOffset : GradientOffset ,
168+ size : Size ,
169+ tileMode : TileMode ,
170+ onBrushChange : (Brush ) -> Unit
171+ ) {
172+ val brush = when (gradientType) {
173+ GradientType .Linear -> {
174+ if (colorStops.size == 1 ) {
175+ val brushColor = colorStops.first().second
176+ Brush .linearGradient(listOf (brushColor, brushColor))
177+ } else {
178+ Brush .linearGradient(
179+ colorStops = colorStops.toTypedArray(),
180+ start = gradientOffset.start,
181+ end = gradientOffset.end,
182+ tileMode = tileMode
183+ )
184+ }
185+ }
186+ GradientType .Radial -> {
187+ Brush .radialGradient(
188+ colorStops = colorStops.toTypedArray(),
189+ center = gradientOffset.start,
190+ radius = size.width
191+ )
192+ }
84193
85- val colorStops = remember {
86- mutableStateListOf(
87- 0.0f to Color .Red ,
88- 0.3f to Color .Green ,
89- 1.0f to Color .Blue ,
90- )
91- }
194+ GradientType .Sweep -> {
195+ Brush .sweepGradient(
196+ colorStops = colorStops.toTypedArray(),
197+ center = gradientOffset.start
198+ )
199+ }
92200
93- var gradientOffset by remember {
94- mutableStateOf(
95- GradientOffset (GradientAngle .CW0 )
96- )
97201 }
98202
99- val brush = if (colorStops.size == 1 ) {
100- val color = colorStops.first().second
101- Brush .linearGradient(listOf (color, color))
102- } else {
103- Brush .linearGradient(
104- colorStops = colorStops.toTypedArray(),
105- start = gradientOffset.start,
106- end = gradientOffset.end,
107- tileMode = tileMode
108- )
109- }
203+ val contentWidth = size.width
204+ val contentHeight = size.height
205+
206+ onBrushChange(brush)
110207
111- var size by remember {
112- mutableStateOf(Size .Zero )
113- }
114208 // Display Brush
115- Box (
209+ BoxWithConstraints (
116210 modifier = Modifier
117211 .fillMaxWidth()
118- .height(150 .dp)
119- .background(brush)
120- .onSizeChanged {
121- size = Size (it.width.toFloat(), it.height.toFloat())
122- }
123- )
212+ .height(150 .dp),
213+ contentAlignment = Alignment .Center
214+ ) {
215+ Box (
216+ modifier = Modifier
217+ .height(maxHeight)
218+ .aspectRatio(contentWidth / contentHeight)
219+ .background(brush)
220+ ) {
124221
125- GradientOffsetSelection (
126- size = size
127- ) { offset ->
128- gradientOffset = offset
222+ }
129223 }
130224
131- ColorStopSelection (
132- color = currentColor,
133- colorStops = colorStops,
134- onRemoveClick = { index: Int ->
135- if (colorStops.size > 2 ) {
136- colorStops.removeAt(index)
137- }
138- },
139- onValueChange = { index: Int , pair: Pair <Float , Color > ->
140- colorStops[index] = pair.copy()
141- },
142- onAddColorStop = { pair: Pair <Float , Color > ->
143- colorStops.add(pair)
144- }
145- )
146225}
147226
148227@Composable
@@ -152,7 +231,6 @@ internal fun ColorStopSelection(
152231 onRemoveClick : (Int ) -> Unit ,
153232 onAddColorStop : (Pair <Float , Color >) -> Unit ,
154233 onValueChange : (Int , Pair <Float , Color >) -> Unit
155-
156234) {
157235
158236 ExpandableColumn (title = " Colors and Stops" , color = Orange400 ) {
0 commit comments