Merge changes Icd3e0c93,I8932e80c into main
* changes: TopologyScale: limit vertical padding TopologyScale values for scaling the topology pane
This commit is contained in:
committed by
Android (Google) Code Review
commit
7403db7745
@@ -19,9 +19,118 @@ package com.android.settings.connecteddevice.display
|
||||
import com.android.settings.R
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Point
|
||||
import android.graphics.PointF
|
||||
import android.graphics.RectF
|
||||
|
||||
import androidx.preference.Preference
|
||||
|
||||
import java.util.Locale
|
||||
|
||||
import kotlin.math.max
|
||||
import kotlin.math.min
|
||||
|
||||
/**
|
||||
* Contains the parameters needed for transforming global display coordinates to and from topology
|
||||
* pane coordinates. This is necessary for implementing an interactive display topology pane. The
|
||||
* pane allows dragging and dropping display blocks into place to define the topology. Conversion to
|
||||
* pane coordinates is necessary when rendering the original topology. Conversion in the other
|
||||
* direction, to display coordinates, is necessary for resolve a drag position to display space.
|
||||
*
|
||||
* The topology pane coordinates are integral and represent the relative position from the upper-
|
||||
* left corner of the pane. It uses a scale optimized for showing all displays with minimal or no
|
||||
* scrolling. The display coordinates are floating point and the origin can be in any position. In
|
||||
* practice the origin will be the upper-left coordinate of the primary display.
|
||||
*/
|
||||
class TopologyScale(paneWidth : Int, displaysPos : Collection<RectF>) {
|
||||
/** Scale of block sizes to real-world display sizes. Should be less than 1. */
|
||||
val blockRatio : Float
|
||||
|
||||
/** Height of topology pane needed to allow all display blocks to appear with some padding. */
|
||||
val paneHeight : Int
|
||||
|
||||
/** Pane's X view coordinate that corresponds with topology's X=0 coordinate. */
|
||||
val originPaneX : Int
|
||||
|
||||
/** Pane's Y view coordinate that corresponds with topology's Y=0 coordinate. */
|
||||
val originPaneY : Int
|
||||
|
||||
init {
|
||||
val displayBounds = RectF(
|
||||
Float.MAX_VALUE, Float.MAX_VALUE, Float.MIN_VALUE, Float.MIN_VALUE)
|
||||
var smallestDisplayDim = Float.MAX_VALUE
|
||||
var biggestDisplayHeight = Float.MIN_VALUE
|
||||
|
||||
// displayBounds is the smallest rect encompassing all displays, in display space.
|
||||
// smallestDisplayDim is the size of the smallest display edge, in display space.
|
||||
for (pos in displaysPos) {
|
||||
displayBounds.union(pos)
|
||||
smallestDisplayDim = minOf(smallestDisplayDim, pos.height(), pos.width())
|
||||
biggestDisplayHeight = max(biggestDisplayHeight, pos.height())
|
||||
}
|
||||
|
||||
// Set height according to the width and the aspect ratio of the display bounds.
|
||||
// 0.05 is a reasonable limit to the size of display blocks. It appears to match the
|
||||
// ratio used in the ChromeOS topology editor. It prevents blocks from being too large,
|
||||
// which would make dragging and dropping awkward.
|
||||
val rawBlockRatio = min(0.05, paneWidth.toDouble() * 0.6 / displayBounds.width())
|
||||
|
||||
// If the `ratio` is set too low because one of the displays will have an edge less than
|
||||
// 48dp long, increase it such that the smallest edge is that long. This may override the
|
||||
// 0.05 limit since it is more important than it.
|
||||
blockRatio = max(48.0 / smallestDisplayDim, rawBlockRatio).toFloat()
|
||||
|
||||
// Essentially, we just set the pane height based on the pre-determined pane width and the
|
||||
// aspect ratio of the display bounds. But we may need to increase it slightly to achieve
|
||||
// 20% padding above and below the display bounds - this is where the 0.6 comes from.
|
||||
val rawPaneHeight = max(
|
||||
paneWidth.toDouble() / displayBounds.width() * displayBounds.height(),
|
||||
displayBounds.height() * blockRatio / 0.6)
|
||||
|
||||
// It is easy for the aspect ratio to result in an excessively tall pane, since the width is
|
||||
// pre-determined and may be considerably wider than necessary. So we prevent the height
|
||||
// from growing too large here, by limiting vertical padding to the size of the tallest
|
||||
// display. This improves results for very tall display bounds.
|
||||
paneHeight = min(
|
||||
rawPaneHeight.toInt(),
|
||||
(blockRatio * (displayBounds.height() + biggestDisplayHeight * 2f)).toInt())
|
||||
|
||||
// Set originPaneXY (the location of 0,0 in display space in the pane's coordinate system)
|
||||
// such that the display bounds rect is centered in the pane.
|
||||
// It is unlikely that either of these coordinates will be negative since blockRatio has
|
||||
// been chosen to allow 20% padding around each side of the display blocks. However, the
|
||||
// a11y requirement applied above (48.0 / smallestDisplayDim) may cause the blocks to not
|
||||
// fit. This should be rare in practice, and can be worked around by moving the settings UI
|
||||
// to a larger display.
|
||||
val blockMostLeft = (paneWidth - displayBounds.width() * blockRatio) / 2
|
||||
val blockMostTop = (paneHeight - displayBounds.height() * blockRatio) / 2
|
||||
|
||||
originPaneX = (blockMostLeft - displayBounds.left * blockRatio).toInt()
|
||||
originPaneY = (blockMostTop - displayBounds.top * blockRatio).toInt()
|
||||
}
|
||||
|
||||
/** Transforms coordinates in view pane space to display space. */
|
||||
fun paneToDisplayCoor(panePos : Point) : PointF {
|
||||
return PointF(
|
||||
(panePos.x - originPaneX).toFloat() / blockRatio,
|
||||
(panePos.y - originPaneY).toFloat() / blockRatio)
|
||||
}
|
||||
|
||||
/** Transforms coordinates in display space to view pane space. */
|
||||
fun displayToPaneCoor(displayPos : PointF) : Point {
|
||||
return Point(
|
||||
(displayPos.x * blockRatio).toInt() + originPaneX,
|
||||
(displayPos.y * blockRatio).toInt() + originPaneY)
|
||||
}
|
||||
|
||||
override fun toString() : String {
|
||||
return String.format(
|
||||
Locale.ROOT,
|
||||
"{TopoScale blockRatio=%f originPaneXY=%d,%d paneHeight=%d}",
|
||||
blockRatio, originPaneX, originPaneY, paneHeight)
|
||||
}
|
||||
}
|
||||
|
||||
const val PREFERENCE_KEY = "display_topology_preference"
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user