Skip to content

Commit 8b30494

Browse files
committed
fix: add offset column and 16-byte rows in HexView (#396)
- Changed chunked(8) to chunked(16) for standard hex viewer layout - Added offset column showing 0x00000000 format address for each row - Updated sticky header to include offset column header - Added padding for incomplete last rows Fixes #396
1 parent c3a3d43 commit 8b30494

1 file changed

Lines changed: 61 additions & 51 deletions

File tree

  • app/src/main/java/com/kyhsgeekcode/disassembler/ui/components

app/src/main/java/com/kyhsgeekcode/disassembler/ui/components/HexView.kt

Lines changed: 61 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -19,50 +19,67 @@ import androidx.compose.ui.text.style.TextAlign
1919
import androidx.compose.ui.tooling.preview.Preview
2020
import androidx.compose.ui.unit.dp
2121

22+
private const val BYTES_PER_ROW = 16
23+
private val OFFSET_WIDTH = 90.dp
24+
private val HEX_CELL_WIDTH = 25.dp
25+
private val ASCII_CELL_WIDTH = 12.dp
26+
2227
@ExperimentalFoundationApi
2328
@Composable
2429
fun HexView(bytes: ByteArray) {
25-
val splitted by remember {
26-
derivedStateOf { (bytes.toList().chunked(8)) }
30+
val rows by remember {
31+
derivedStateOf {
32+
bytes.toList().chunked(BYTES_PER_ROW).mapIndexed { idx, chunk ->
33+
Pair(idx * BYTES_PER_ROW, chunk)
34+
}
35+
}
2736
}
2837

29-
3038
LazyColumn(Modifier.horizontalScroll(rememberScrollState())) {
3139
stickyHeader {
3240
HexViewHeader()
3341
}
34-
items(splitted) { item ->
35-
HexViewRow(item)
42+
items(rows) { (offset, chunk) ->
43+
HexViewRow(offset, chunk)
3644
}
3745
}
38-
3946
}
4047

4148
@Composable
4249
fun HexViewHeader() {
4350
Row(Modifier.height(IntrinsicSize.Min)) {
44-
for (v in 0..7) {
51+
// Offset column header
52+
Text(
53+
text = "Offset",
54+
modifier = Modifier
55+
.width(OFFSET_WIDTH)
56+
.fillMaxHeight()
57+
.background(Color.White),
58+
textAlign = TextAlign.Center,
59+
fontWeight = FontWeight.ExtraBold,
60+
color = Color.DarkGray
61+
)
62+
Spacer(modifier = Modifier.width(4.dp).fillMaxHeight())
63+
// Hex column headers 00..0F
64+
for (v in 0 until BYTES_PER_ROW) {
4565
Text(
4666
text = String.format("%02X", v),
4767
modifier = Modifier
48-
.width(25.dp)
68+
.width(HEX_CELL_WIDTH)
4969
.fillMaxHeight()
5070
.background(Color.White),
5171
textAlign = TextAlign.Center,
5272
fontWeight = FontWeight.ExtraBold,
5373
color = Color.Blue
5474
)
5575
}
56-
Spacer(
57-
modifier = Modifier
58-
.fillMaxHeight()
59-
.width(10.dp)
60-
)
61-
for (v in 0..7) {
76+
Spacer(modifier = Modifier.width(8.dp).fillMaxHeight())
77+
// ASCII column headers
78+
for (v in 0 until BYTES_PER_ROW) {
6279
Text(
63-
text = String.format("%02X", v),
80+
text = String.format("%X", v),
6481
modifier = Modifier
65-
.width(20.dp)
82+
.width(ASCII_CELL_WIDTH)
6683
.fillMaxHeight()
6784
.background(Color.White),
6885
textAlign = TextAlign.Center,
@@ -71,58 +88,56 @@ fun HexViewHeader() {
7188
)
7289
}
7390
}
74-
7591
}
7692

7793
@Composable
78-
private fun HexViewRow(item: List<Byte>) {
79-
Row(
80-
Modifier.height(IntrinsicSize.Min)
81-
) {
94+
private fun HexViewRow(offset: Int, item: List<Byte>) {
95+
Row(Modifier.height(IntrinsicSize.Min)) {
96+
// Offset column
97+
Text(
98+
text = String.format("0x%08X", offset),
99+
modifier = Modifier
100+
.width(OFFSET_WIDTH)
101+
.fillMaxHeight()
102+
.background(Color.White),
103+
textAlign = TextAlign.Center,
104+
color = Color.DarkGray
105+
)
106+
Spacer(modifier = Modifier.width(4.dp).fillMaxHeight())
107+
// Hex cells
82108
for (v in item) {
83109
Text(
84110
text = String.format("%02X", v),
85111
modifier = Modifier
86-
.width(25.dp)
112+
.width(HEX_CELL_WIDTH)
87113
.fillMaxHeight()
88114
.background(Color.White),
89115
textAlign = TextAlign.Center
90116
)
91117
}
92-
for (i in 0 until 8 - item.size) {
118+
// Padding for incomplete last row
119+
for (i in 0 until BYTES_PER_ROW - item.size) {
93120
Text(
94-
text = "",
121+
text = " ",
95122
modifier = Modifier
96-
.background(Color.White)
123+
.width(HEX_CELL_WIDTH)
97124
.fillMaxHeight()
98-
.width(25.dp)
125+
.background(Color.White)
99126
)
100127
}
101-
Spacer(
102-
modifier = Modifier
103-
.fillMaxHeight()
104-
.width(10.dp)
105-
)
128+
Spacer(modifier = Modifier.width(8.dp).fillMaxHeight())
129+
// ASCII cells
106130
for (v in item) {
107131
val c = v.toInt().toChar()
108132
Text(
109133
text = if (isPrintableChar(c)) c.toString() else ".",
110134
modifier = Modifier
111-
.width(20.dp)
135+
.width(ASCII_CELL_WIDTH)
112136
.fillMaxHeight()
113137
.background(Color.White),
114138
textAlign = TextAlign.Center
115139
)
116140
}
117-
for (i in 0 until 8 - item.size) {
118-
Text(
119-
text = "",
120-
modifier = Modifier
121-
.background(Color.White)
122-
.fillMaxHeight()
123-
.width(20.dp)
124-
)
125-
}
126141
}
127142
}
128143

@@ -137,16 +152,11 @@ fun isPrintableChar(c: Char): Boolean {
137152
fun HexPreview() {
138153
HexView(
139154
bytes = byteArrayOf(
140-
0xFF.toByte(),
141-
0x12.toByte(),
142-
0x13.toByte(),
143-
0x11.toByte(),
144-
0x40.toByte(),
145-
0x33.toByte(),
146-
0x65.toByte(),
147-
0x55.toByte(),
148-
0x70.toByte(),
149-
0x59.toByte()
155+
0xFF.toByte(), 0x12.toByte(), 0x13.toByte(), 0x11.toByte(),
156+
0x40.toByte(), 0x33.toByte(), 0x65.toByte(), 0x55.toByte(),
157+
0x70.toByte(), 0x59.toByte(), 0x4A.toByte(), 0x2B.toByte(),
158+
0x1C.toByte(), 0x3D.toByte(), 0xEE.toByte(), 0x7F.toByte(),
159+
0x00.toByte(), 0xAB.toByte()
150160
)
151161
)
152162
}

0 commit comments

Comments
 (0)