Add screen ratio fixing
This commit is contained in:
@@ -142,11 +142,10 @@ fun TerminalView(
|
||||
showContextMenu = false
|
||||
selectionStart = null
|
||||
selectionEnd = null
|
||||
val cellWidth = size.width / cols
|
||||
val cellHeight = size.height / rows
|
||||
if (cellWidth > 0 && cellHeight > 0) {
|
||||
val col = (startPos.x / cellWidth).toInt().coerceIn(0, cols - 1)
|
||||
val row = (startPos.y / cellHeight).toInt().coerceIn(0, rows - 1)
|
||||
val metrics = calculateGridMetrics(size.width.toFloat(), size.height.toFloat(), cols, rows)
|
||||
if (metrics.cellWidth > 0 && metrics.cellHeight > 0) {
|
||||
val col = ((startPos.x - metrics.offsetX) / metrics.cellWidth).toInt().coerceIn(0, cols - 1)
|
||||
val row = ((startPos.y - metrics.offsetY) / metrics.cellHeight).toInt().coerceIn(0, rows - 1)
|
||||
var addr = row * cols + col
|
||||
|
||||
val buf = screenBuffer
|
||||
@@ -167,17 +166,26 @@ fun TerminalView(
|
||||
val activeCursorAddr = currentCursorAddr
|
||||
if (version == -1L) return@Canvas
|
||||
|
||||
val width = size.width
|
||||
val height = size.height
|
||||
val cellWidth = width / cols
|
||||
val cellHeight = height / rows
|
||||
val metrics = calculateGridMetrics(size.width, size.height, cols, rows)
|
||||
if (metrics.cellWidth <= 0f || metrics.cellHeight <= 0f) return@Canvas
|
||||
|
||||
if (cellWidth <= 0 || cellHeight <= 0) return@Canvas
|
||||
val cellWidth = metrics.cellWidth
|
||||
val cellHeight = metrics.cellHeight
|
||||
val offsetX = metrics.offsetX
|
||||
val offsetY = metrics.offsetY
|
||||
|
||||
val paint = Paint().apply {
|
||||
isAntiAlias = true
|
||||
typeface = Typeface.MONOSPACE
|
||||
textSize = cellHeight * 0.85f
|
||||
textAlign = Paint.Align.CENTER
|
||||
}
|
||||
|
||||
// Calculate optimal font size ensuring characters fit cleanly in cell without crowding
|
||||
val baseTextSize = cellHeight * 0.78f
|
||||
paint.textSize = baseTextSize
|
||||
val measuredW = paint.measureText("W")
|
||||
if (measuredW > cellWidth * 0.85f && measuredW > 0f) {
|
||||
paint.textSize = baseTextSize * (cellWidth * 0.85f / measuredW)
|
||||
}
|
||||
|
||||
val buf = screenBuffer
|
||||
@@ -194,11 +202,11 @@ fun TerminalView(
|
||||
|
||||
val start = selectionStart
|
||||
val end = selectionEnd
|
||||
if (start != null && end != null) {
|
||||
val startCol = (start.x / cellWidth).toInt().coerceIn(0, cols - 1)
|
||||
val startRow = (start.y / cellHeight).toInt().coerceIn(0, rows - 1)
|
||||
val endCol = (end.x / cellWidth).toInt().coerceIn(0, cols - 1)
|
||||
val endRow = (end.y / cellHeight).toInt().coerceIn(0, rows - 1)
|
||||
if (start != null && end != null && cellWidth > 0f && cellHeight > 0f) {
|
||||
val startCol = ((start.x - offsetX) / cellWidth).toInt().coerceIn(0, cols - 1)
|
||||
val startRow = ((start.y - offsetY) / cellHeight).toInt().coerceIn(0, rows - 1)
|
||||
val endCol = ((end.x - offsetX) / cellWidth).toInt().coerceIn(0, cols - 1)
|
||||
val endRow = ((end.y - offsetY) / cellHeight).toInt().coerceIn(0, rows - 1)
|
||||
|
||||
selMinRow = minOf(startRow, endRow)
|
||||
selMaxRow = maxOf(startRow, endRow)
|
||||
@@ -211,8 +219,8 @@ fun TerminalView(
|
||||
val addr = r * cols + c
|
||||
if (addr >= totalCells) break
|
||||
|
||||
val left = c * cellWidth
|
||||
val top = r * cellHeight
|
||||
val left = offsetX + c * cellWidth
|
||||
val top = offsetY + r * cellHeight
|
||||
|
||||
var charVal = ' '
|
||||
var fgColor: Color
|
||||
@@ -286,7 +294,7 @@ fun TerminalView(
|
||||
)
|
||||
}
|
||||
|
||||
// Highlight selected block range
|
||||
// Draw selection box highlight if selected
|
||||
val isSelected = r in selMinRow..selMaxRow && c in selMinCol..selMaxCol
|
||||
if (isSelected) {
|
||||
drawRect(
|
||||
@@ -314,7 +322,7 @@ fun TerminalView(
|
||||
val symHeight = slot.height
|
||||
val rgbArray = slot.getRgbPixels(fgColor.toArgb(), bgColor.toArgb())
|
||||
if (rgbArray != null && symWidth > 0 && symHeight > 0) {
|
||||
val bmp = android.graphics.Bitmap.createBitmap(rgbArray, symWidth, symHeight, android.graphics.Bitmap.Config.ARGB_8888)
|
||||
val bmp = android.graphics.Bitmap.createBitmap(rgbArray as IntArray, symWidth, symHeight, android.graphics.Bitmap.Config.ARGB_8888)
|
||||
drawContext.canvas.nativeCanvas.drawBitmap(
|
||||
bmp,
|
||||
null,
|
||||
@@ -330,11 +338,12 @@ fun TerminalView(
|
||||
paint.color = fgColor.toArgb()
|
||||
paint.isFakeBoldText = isBold
|
||||
val fontMetrics = paint.fontMetrics
|
||||
val textY = top + (cellHeight - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top
|
||||
val textX = left + cellWidth / 2f
|
||||
val textY = top + (cellHeight - fontMetrics.bottom + fontMetrics.top) / 2f - fontMetrics.top
|
||||
|
||||
drawContext.canvas.nativeCanvas.drawText(
|
||||
charVal.toString(),
|
||||
left + (cellWidth / 4),
|
||||
textX,
|
||||
textY,
|
||||
paint
|
||||
)
|
||||
@@ -343,8 +352,8 @@ fun TerminalView(
|
||||
if (isUnderline) {
|
||||
drawLine(
|
||||
color = fgColor,
|
||||
start = Offset(left, top + cellHeight - 2),
|
||||
end = Offset(left + cellWidth, top + cellHeight - 2),
|
||||
start = Offset(left, top + cellHeight - 2f),
|
||||
end = Offset(left + cellWidth, top + cellHeight - 2f),
|
||||
strokeWidth = 2f
|
||||
)
|
||||
}
|
||||
@@ -353,8 +362,8 @@ fun TerminalView(
|
||||
|
||||
// Draw Vector Graphics Plane overlay if present
|
||||
if (graphicsPlane != null && graphicsPlane.hasContent()) {
|
||||
val gridW = (cols * cellWidth).toInt()
|
||||
val gridH = (rows * cellHeight).toInt()
|
||||
val gridW = metrics.gridWidth.toInt()
|
||||
val gridH = metrics.gridHeight.toInt()
|
||||
if (gridW > 0 && gridH > 0) {
|
||||
graphicsPlane.resize(gridW, gridH)
|
||||
val rgb = graphicsPlane.rgbBuffer
|
||||
@@ -363,7 +372,7 @@ fun TerminalView(
|
||||
drawContext.canvas.nativeCanvas.drawBitmap(
|
||||
bmp,
|
||||
null,
|
||||
android.graphics.RectF(0f, 0f, gridW.toFloat(), gridH.toFloat()),
|
||||
android.graphics.RectF(offsetX, offsetY, offsetX + gridW.toFloat(), offsetY + gridH.toFloat()),
|
||||
null
|
||||
)
|
||||
}
|
||||
@@ -425,6 +434,57 @@ fun TerminalView(
|
||||
}
|
||||
}
|
||||
|
||||
data class TerminalGridMetrics(
|
||||
val cellWidth: Float,
|
||||
val cellHeight: Float,
|
||||
val gridWidth: Float,
|
||||
val gridHeight: Float,
|
||||
val offsetX: Float,
|
||||
val offsetY: Float
|
||||
)
|
||||
|
||||
fun calculateGridMetrics(
|
||||
viewWidth: Float,
|
||||
viewHeight: Float,
|
||||
cols: Int,
|
||||
rows: Int
|
||||
): TerminalGridMetrics {
|
||||
if (viewWidth <= 0f || viewHeight <= 0f || cols <= 0 || rows <= 0) {
|
||||
return TerminalGridMetrics(0f, 0f, 0f, 0f, 0f, 0f)
|
||||
}
|
||||
|
||||
val rawCellW = viewWidth / cols
|
||||
val rawCellH = viewHeight / rows
|
||||
val currentRatio = rawCellW / rawCellH
|
||||
|
||||
// Target terminal cell aspect ratio is roughly 0.50 to 0.60 (width / height)
|
||||
val targetMinRatio = 0.48f
|
||||
val targetMaxRatio = 0.60f
|
||||
|
||||
val cellW: Float
|
||||
val cellH: Float
|
||||
|
||||
if (currentRatio > targetMaxRatio) {
|
||||
// Screen is wider than ideal aspect ratio -> clamp width, pillarbox (equal blank bars left/right)
|
||||
cellH = rawCellH
|
||||
cellW = rawCellH * targetMaxRatio
|
||||
} else if (currentRatio < targetMinRatio) {
|
||||
// Screen is taller than ideal aspect ratio -> clamp height, letterbox (equal blank bars top/bottom)
|
||||
cellW = rawCellW
|
||||
cellH = rawCellW / targetMinRatio
|
||||
} else {
|
||||
cellW = rawCellW
|
||||
cellH = rawCellH
|
||||
}
|
||||
|
||||
val gridW = cols * cellW
|
||||
val gridH = rows * cellH
|
||||
val offX = (viewWidth - gridW) / 2f
|
||||
val offY = (viewHeight - gridH) / 2f
|
||||
|
||||
return TerminalGridMetrics(cellW, cellH, gridW, gridH, offX, offY)
|
||||
}
|
||||
|
||||
private fun copySelection(
|
||||
start: Offset?,
|
||||
end: Offset?,
|
||||
@@ -436,13 +496,15 @@ private fun copySelection(
|
||||
) {
|
||||
if (start != null && end != null && screenBuffer != null && cols > 0 && rows > 0) {
|
||||
val displayMetrics = context.resources.displayMetrics
|
||||
val cellWidth = displayMetrics.widthPixels.toFloat() / cols
|
||||
val cellHeight = displayMetrics.heightPixels.toFloat() / rows
|
||||
val viewW = displayMetrics.widthPixels.toFloat()
|
||||
val viewH = displayMetrics.heightPixels.toFloat()
|
||||
val metrics = calculateGridMetrics(viewW, viewH, cols, rows)
|
||||
if (metrics.cellWidth <= 0f || metrics.cellHeight <= 0f) return
|
||||
|
||||
val startCol = (start.x / cellWidth).toInt().coerceIn(0, cols - 1)
|
||||
val startRow = (start.y / cellHeight).toInt().coerceIn(0, rows - 1)
|
||||
val endCol = (end.x / cellWidth).toInt().coerceIn(0, cols - 1)
|
||||
val endRow = (end.y / cellHeight).toInt().coerceIn(0, rows - 1)
|
||||
val startCol = ((start.x - metrics.offsetX) / metrics.cellWidth).toInt().coerceIn(0, cols - 1)
|
||||
val startRow = ((start.y - metrics.offsetY) / metrics.cellHeight).toInt().coerceIn(0, rows - 1)
|
||||
val endCol = ((end.x - metrics.offsetX) / metrics.cellWidth).toInt().coerceIn(0, cols - 1)
|
||||
val endRow = ((end.y - metrics.offsetY) / metrics.cellHeight).toInt().coerceIn(0, rows - 1)
|
||||
|
||||
val minRow = minOf(startRow, endRow)
|
||||
val maxRow = maxOf(startRow, endRow)
|
||||
|
||||
Reference in New Issue
Block a user