Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import androidx.compose.ui.unit.dp
import com.halilibo.richtext.ui.BlockQuote
import com.halilibo.richtext.ui.CodeBlock
import com.halilibo.richtext.ui.ColumnArrangement.Adaptive
import com.halilibo.richtext.ui.DividerStyle
import com.halilibo.richtext.ui.FormattedList
import com.halilibo.richtext.ui.Heading
import com.halilibo.richtext.ui.HorizontalRule
Expand Down Expand Up @@ -129,15 +130,20 @@ import com.halilibo.richtext.ui.material3.RichText
val currentStyle = style!!
WithStyle(
currentStyle.copy(
tableStyle = currentStyle.tableStyle!!.copy(columnArrangement = Adaptive(200.dp))
tableStyle = currentStyle.tableStyle!!.copy(
columnArrangement = Adaptive(200.dp),
dividerStyle = DividerStyle.Minimal,
headerBorderColor = Color.DarkGray,
borderColor = Color.LightGray
)
)
) {
Heading(0, "Scrollable Table")
Table(
modifier = Modifier.fillMaxWidth(),
headerRow = {
cell { Text("Column 1") }
cell { Text("Column 2") }
cell { Text("Column 2 has a pretty long title") }
cell { Text("Column 3") }
cell { Text("Column 4") }
}) {
Expand Down
46 changes: 34 additions & 12 deletions richtext-ui/src/commonMain/kotlin/com/halilibo/richtext/ui/Table.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,14 +32,18 @@ import kotlin.math.roundToInt
* @param cellPadding The spacing between the contents of each cell and the borders.
* @param borderColor The [Color] of the table border.
* @param borderStrokeWidth The width of the table border.
* @param headerBorderColor Optional override of the header's [Color], defaulting to borderColor.
* @param drawVerticalDividers Whether to draw vertical dividers.
*/
@Immutable
public data class TableStyle(
val headerTextStyle: TextStyle? = null,
val cellPadding: TextUnit? = null,
val columnArrangement: ColumnArrangement? = null,
val borderColor: Color? = null,
val borderStrokeWidth: Float? = null
val borderStrokeWidth: Float? = null,
val headerBorderColor: Color? = null,
val dividerStyle: DividerStyle? = null,
) {
public companion object {
public val Default: TableStyle = TableStyle()
Expand All @@ -51,18 +55,26 @@ public sealed interface ColumnArrangement {
public class Adaptive(public val maxWidth: Dp) : ColumnArrangement
}

public sealed interface DividerStyle {
public object Full : DividerStyle
public object Minimal : DividerStyle
}

private val DefaultTableHeaderTextStyle = TextStyle(fontWeight = FontWeight.Bold)
private val DefaultCellPadding = 8.sp
private val DefaultBorderColor = Color.Unspecified
private val DefaultColumnArrangement = ColumnArrangement.Uniform
private const val DefaultBorderStrokeWidth = 1f
private val DefaultDividerStyle = DividerStyle.Full

internal fun TableStyle.resolveDefaults() = TableStyle(
headerTextStyle = headerTextStyle ?: DefaultTableHeaderTextStyle,
cellPadding = cellPadding ?: DefaultCellPadding,
columnArrangement = columnArrangement ?: DefaultColumnArrangement,
borderColor = borderColor ?: DefaultBorderColor,
borderStrokeWidth = borderStrokeWidth ?: DefaultBorderStrokeWidth
borderStrokeWidth = borderStrokeWidth ?: DefaultBorderStrokeWidth,
headerBorderColor = headerBorderColor,
dividerStyle = dividerStyle ?: DefaultDividerStyle,
)

public interface RichTextTableRowScope {
Expand Down Expand Up @@ -176,17 +188,21 @@ public fun RichTextScope.Table(
modifier
}

val borderColor = tableStyle.borderColor!!.takeOrElse { contentColor }
TableLayout(
columns = columns,
rows = styledRows,
hasHeader = header != null,
cellSpacing = tableStyle.borderStrokeWidth,
tableMeasurer = measurer,
drawDecorations = { layoutResult ->
Modifier.drawTableBorders(
rowOffsets = layoutResult.rowOffsets,
columnOffsets = layoutResult.columnOffsets,
borderColor = tableStyle.borderColor!!.takeOrElse { contentColor },
borderStrokeWidth = tableStyle.borderStrokeWidth
borderColor = borderColor,
borderStrokeWidth = tableStyle.borderStrokeWidth,
headerBorderColor = tableStyle.headerBorderColor ?: borderColor,
dividerStyle = tableStyle.dividerStyle!!,
)
},
modifier = tableModifier
Expand All @@ -197,25 +213,31 @@ private fun Modifier.drawTableBorders(
rowOffsets: List<Float>,
columnOffsets: List<Float>,
borderColor: Color,
borderStrokeWidth: Float
borderStrokeWidth: Float,
headerBorderColor: Color,
dividerStyle: DividerStyle,
) = drawBehind {
// Draw horizontal borders.
rowOffsets.forEach { position ->
drawLine(
borderColor,
rowOffsets.forEachIndexed { i, position ->
if (dividerStyle is DividerStyle.Full || (i > 0 && i < rowOffsets.size - 1)) {
drawLine(
if (i == 1) headerBorderColor else borderColor,
start = Offset(0f, position),
end = Offset(size.width, position),
borderStrokeWidth
)
)
}
}

// Draw vertical borders.
columnOffsets.forEach { position ->
drawLine(
if (dividerStyle is DividerStyle.Full) {
columnOffsets.forEach { position ->
drawLine(
borderColor,
Offset(position, 0f),
Offset(position, size.height),
borderStrokeWidth
)
)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ internal data class TableLayoutResult(
internal fun TableLayout(
columns: Int,
rows: List<List<@Composable () -> Unit>>,
hasHeader: Boolean,
drawDecorations: (TableLayoutResult) -> Modifier,
cellSpacing: Float,
tableMeasurer: TableMeasurer,
Expand Down Expand Up @@ -61,7 +62,14 @@ internal fun TableLayout(
if (rowIndex == 0) {
columnOffsets.add(x - cellSpacing / 2f)
}
cell.place(x.roundToInt(), y.roundToInt())

val cellY = if (hasHeader && rowIndex == 0) {
// Header is bottom-aligned
y + (measurements.rowHeights[0] - cell.height)
} else {
y
}
cell.place(x.roundToInt(), cellY.roundToInt())
x += measurements.columnWidths[columnIndex] + cellSpacing
}

Expand Down