Skip to content

Commit 530d0df

Browse files
committed
Handle shared display geometry in layout parser
1 parent 9134f93 commit 530d0df

File tree

1 file changed

+126
-19
lines changed

1 file changed

+126
-19
lines changed

AvdSkinToCodenameOneSkin.java

Lines changed: 126 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,10 @@ private static class LayoutParser {
274274
private final Deque<Context> contextStack = new ArrayDeque<>();
275275
private final Path skinDirectory;
276276
private final Path layoutParent;
277+
private Integer baseDisplayX;
278+
private Integer baseDisplayY;
279+
private Integer baseDisplayWidth;
280+
private Integer baseDisplayHeight;
277281

278282
LayoutParser(Path layoutFile, Path skinDirectory) {
279283
this.skinDirectory = skinDirectory;
@@ -296,10 +300,10 @@ LayoutInfo parse(String text) {
296300
}
297301
}
298302
OrientationInfo portrait = builders.containsKey(OrientationType.PORTRAIT)
299-
? builders.get(OrientationType.PORTRAIT).build(OrientationType.PORTRAIT)
303+
? builders.get(OrientationType.PORTRAIT).build(OrientationType.PORTRAIT, this)
300304
: null;
301305
OrientationInfo landscape = builders.containsKey(OrientationType.LANDSCAPE)
302-
? builders.get(OrientationType.LANDSCAPE).build(OrientationType.LANDSCAPE)
306+
? builders.get(OrientationType.LANDSCAPE).build(OrientationType.LANDSCAPE, this)
303307
: null;
304308
return new LayoutInfo(portrait, landscape);
305309
}
@@ -310,25 +314,49 @@ private void handleKeyValue(String line) {
310314
return;
311315
}
312316
OrientationType orientation = findCurrentOrientation();
313-
if (orientation == null) {
314-
return;
315-
}
316-
OrientationInfoBuilder builder = builders.computeIfAbsent(orientation, o -> new OrientationInfoBuilder());
317+
317318
String[] parts = splitKeyValue(line);
318319
if (parts == null) {
319320
return;
320321
}
321322
String key = parts[0];
322323
String value = unquote(parts[1]);
324+
325+
if (orientation == null && isInDeviceDisplayContext()) {
326+
switch (key.toLowerCase(Locale.ROOT)) {
327+
case "x" -> baseDisplayX = parseInt(value);
328+
case "y" -> baseDisplayY = parseInt(value);
329+
case "width" -> baseDisplayWidth = parseInt(value);
330+
case "height" -> baseDisplayHeight = parseInt(value);
331+
}
332+
return;
333+
}
334+
335+
if (orientation == null) {
336+
if (ctx.isPartBlock && key.equalsIgnoreCase("name")) {
337+
ctx.devicePart = value.equalsIgnoreCase("device");
338+
}
339+
return;
340+
}
341+
OrientationInfoBuilder builder = builders.computeIfAbsent(orientation, o -> new OrientationInfoBuilder());
323342
String ctxName = ctx.name.toLowerCase(Locale.ROOT);
324-
if (ctxName.contains("image") && isImageKey(key)) {
343+
if (ctx.isPartBlock && key.equalsIgnoreCase("name")) {
344+
ctx.devicePart = value.equalsIgnoreCase("device");
345+
}
346+
if (isImageKey(key) && shouldTreatAsImage(ctx, key)) {
325347
builder.considerImage(value, contextStack, this::resolveImagePath);
326348
} else if (ctxName.contains("display")) {
327349
switch (key.toLowerCase(Locale.ROOT)) {
328-
case "x" -> builder.displayX = parseInt(value);
329-
case "y" -> builder.displayY = parseInt(value);
330-
case "width" -> builder.displayWidth = parseInt(value);
331-
case "height" -> builder.displayHeight = parseInt(value);
350+
case "x" -> builder.displayXOverride = parseInt(value);
351+
case "y" -> builder.displayYOverride = parseInt(value);
352+
case "width" -> builder.displayWidthOverride = parseInt(value);
353+
case "height" -> builder.displayHeightOverride = parseInt(value);
354+
}
355+
} else if (isInDevicePartContext()) {
356+
switch (key.toLowerCase(Locale.ROOT)) {
357+
case "x" -> builder.offsetX = parseInt(value);
358+
case "y" -> builder.offsetY = parseInt(value);
359+
case "rotation" -> builder.rotation = parseInt(value);
332360
}
333361
}
334362
}
@@ -338,6 +366,23 @@ private boolean isImageKey(String key) {
338366
return lower.equals("name") || lower.equals("image") || lower.equals("filename");
339367
}
340368

369+
private boolean shouldTreatAsImage(Context ctx, String key) {
370+
if (!key.equalsIgnoreCase("name")) {
371+
return true;
372+
}
373+
String ctxName = ctx.name.toLowerCase(Locale.ROOT);
374+
return ctxName.contains("image")
375+
|| ctxName.contains("background")
376+
|| ctxName.contains("foreground")
377+
|| ctxName.contains("frame")
378+
|| ctxName.contains("skin")
379+
|| ctxName.contains("device")
380+
|| ctxName.contains("phone")
381+
|| ctxName.contains("tablet")
382+
|| ctxName.contains("onion")
383+
|| ctxName.contains("overlay");
384+
}
385+
341386
private void pushContext(String name) {
342387
name = name.trim();
343388
if (name.isEmpty()) {
@@ -432,14 +477,53 @@ private OrientationType detectOrientation(String name) {
432477
return null;
433478
}
434479

435-
private record Context(String name, OrientationType orientation) {}
480+
private boolean isInDeviceDisplayContext() {
481+
Iterator<Context> it = contextStack.iterator();
482+
if (!it.hasNext()) {
483+
return false;
484+
}
485+
Context top = it.next();
486+
if (!top.name.equalsIgnoreCase("display")) {
487+
return false;
488+
}
489+
if (!it.hasNext()) {
490+
return false;
491+
}
492+
Context parent = it.next();
493+
return parent.name.equalsIgnoreCase("device");
494+
}
495+
496+
private boolean isInDevicePartContext() {
497+
for (Context ctx : contextStack) {
498+
if (ctx.isPartBlock && ctx.devicePart) {
499+
return true;
500+
}
501+
}
502+
return false;
503+
}
504+
505+
private static final class Context {
506+
final String name;
507+
final OrientationType orientation;
508+
final boolean isPartBlock;
509+
boolean devicePart;
510+
511+
Context(String name, OrientationType orientation) {
512+
this.name = name;
513+
this.orientation = orientation;
514+
this.isPartBlock = name != null && name.toLowerCase(Locale.ROOT).startsWith("part");
515+
}
516+
}
436517

437518
private static class OrientationInfoBuilder {
438519
ImageCandidate selectedImage;
439-
Integer displayX;
440-
Integer displayY;
441-
Integer displayWidth;
442-
Integer displayHeight;
520+
Integer displayXOverride;
521+
Integer displayYOverride;
522+
Integer displayWidthOverride;
523+
Integer displayHeightOverride;
524+
Integer offsetX;
525+
Integer offsetY;
526+
Integer rotation;
443527

444528
void considerImage(String name, Deque<Context> contexts, java.util.function.Function<String, Path> resolver) {
445529
ImageCandidate candidate = ImageCandidate.from(name, contexts, resolver);
@@ -448,11 +532,34 @@ void considerImage(String name, Deque<Context> contexts, java.util.function.Func
448532
}
449533
}
450534

451-
OrientationInfo build(OrientationType type) {
452-
if (selectedImage == null || displayX == null || displayY == null || displayWidth == null || displayHeight == null) {
535+
OrientationInfo build(OrientationType type, LayoutParser parser) {
536+
if (selectedImage == null) {
453537
throw new IllegalStateException("Layout definition for " + type + " is incomplete");
454538
}
455-
return new OrientationInfo(type, selectedImage.name(), new DisplayArea(displayX, displayY, displayWidth, displayHeight));
539+
int baseX = parser.baseDisplayX != null ? parser.baseDisplayX : 0;
540+
int baseY = parser.baseDisplayY != null ? parser.baseDisplayY : 0;
541+
Integer widthSource = displayWidthOverride != null ? displayWidthOverride : parser.baseDisplayWidth;
542+
Integer heightSource = displayHeightOverride != null ? displayHeightOverride : parser.baseDisplayHeight;
543+
if (widthSource == null || heightSource == null) {
544+
throw new IllegalStateException("Layout definition for " + type + " is missing display dimensions");
545+
}
546+
int finalWidth = widthSource;
547+
int finalHeight = heightSource;
548+
int normalizedRotation = rotation != null ? Math.floorMod(rotation, 4) : 0;
549+
if ((normalizedRotation & 1) == 1) {
550+
int tmp = finalWidth;
551+
finalWidth = finalHeight;
552+
finalHeight = tmp;
553+
}
554+
int finalX = displayXOverride != null ? displayXOverride : baseX;
555+
int finalY = displayYOverride != null ? displayYOverride : baseY;
556+
if (offsetX != null) {
557+
finalX += offsetX;
558+
}
559+
if (offsetY != null) {
560+
finalY += offsetY;
561+
}
562+
return new OrientationInfo(type, selectedImage.name(), new DisplayArea(finalX, finalY, finalWidth, finalHeight));
456563
}
457564
}
458565

0 commit comments

Comments
 (0)