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
96 changes: 72 additions & 24 deletions src/analyzer/view/AnalyzerScreenView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { ScreenView } from "scenerystack/sim";
import { AquaRadioButtonGroup, Checkbox, TextPushButton } from "scenerystack/sun";
import { Tandem } from "scenerystack/tandem";
import { bestPeriod } from "../../common/model/PDMCalculator.js";
import { FLAT_RECTANGULAR_BUTTON_OPTIONS, FLAT_RESET_ALL_BUTTON_OPTIONS } from "../../common/VSPButtonOptions.js";
import { FieldGridNode } from "../../common/view/FieldGridNode.js";
import { StarFieldNode } from "../../common/view/StarFieldNode.js";
import { StringManager } from "../../i18n/StringManager.js";
Expand Down Expand Up @@ -209,32 +210,36 @@ export class AnalyzerScreenView extends ScreenView {
spacing: 5,
children: [
new Circle(6, { stroke: VSPColors.variableStarColorProperty, lineWidth: 2 }),
new Text(strings.variableStringProperty, { font: SMALL_FONT }),
new Text(strings.variableStringProperty, { font: SMALL_FONT, fill: VSPColors.textColorProperty }),
],
}),
new HBox({
spacing: 5,
children: [
new Rectangle(-5, -5, 10, 10, { stroke: VSPColors.comparisonStarColorProperty, lineWidth: 2 }),
new Text(strings.comparisonStringProperty, { font: SMALL_FONT }),
new Text(strings.comparisonStringProperty, { font: SMALL_FONT, fill: VSPColors.textColorProperty }),
],
}),
],
});

// NOTE: this Text sits directly on the dark screen background (leftColumn is
// not wrapped in a panel), so it uses textColorProperty (light-on-dark) rather
// than mutedTextColorProperty (which is designed for light panel surfaces).
const instructions = new Text(strings.selectHintStringProperty, {
font: SMALL_FONT,
fill: VSPColors.mutedTextColorProperty,
fill: VSPColors.textColorProperty,
});
const clearButton = new TextPushButton(strings.clearSelectionStringProperty, {
font: SMALL_FONT,
baseColor: VSPColors.buttonColorProperty,
listener: () => model.clearSelections(),
accessibleName: strings.clearSelectionStringProperty,
...FLAT_RECTANGULAR_BUTTON_OPTIONS,
});
const crosshairCheckbox = new Checkbox(
showCrosshairProperty,
new Text(strings.showCrosshairsStringProperty, { font: SMALL_FONT }),
new Text(strings.showCrosshairsStringProperty, { font: SMALL_FONT, fill: VSPColors.textColorProperty }),
{ boxWidth: 14, accessibleName: strings.showCrosshairsStringProperty },
);

Expand Down Expand Up @@ -278,13 +283,16 @@ export class AnalyzerScreenView extends ScreenView {
});
const obsTickX = new TickMarkSet(obsTransform, Orientation.HORIZONTAL, 5, { edge: "min" });
const obsTickY = new TickMarkSet(obsTransform, Orientation.VERTICAL, 0.2, { edge: "min" });
// Tick labels are positioned just outside the chart rectangle (bamboo's
// TickLabelSet convention for edge="min"), so they render on the dark screen
// background rather than the chart's white fill — use textColorProperty.
const obsLabelX = new TickLabelSet(obsTransform, Orientation.HORIZONTAL, 5, {
edge: "min",
createLabel: (v: number) => new Text(v.toFixed(0), { font: TICK_FONT }),
createLabel: (v: number) => new Text(v.toFixed(0), { font: TICK_FONT, fill: VSPColors.textColorProperty }),
});
const obsLabelY = new TickLabelSet(obsTransform, Orientation.VERTICAL, 0.2, {
edge: "min",
createLabel: (v: number) => new Text(v.toFixed(2), { font: TICK_FONT }),
createLabel: (v: number) => new Text(v.toFixed(2), { font: TICK_FONT, fill: VSPColors.textColorProperty }),
});

const scatter = new ScatterPlot(obsTransform, [], { radius: 2.5, fill: VSPColors.scatterPointColorProperty });
Expand Down Expand Up @@ -457,20 +465,26 @@ export class AnalyzerScreenView extends ScreenView {
obsGridY.setSpacing(ySpacing);
obsTickY.setSpacing(ySpacing);
obsLabelY.setSpacing(ySpacing);
obsLabelY.setCreateLabel((v: number) => new Text(v.toFixed(yd), { font: TICK_FONT }));
obsLabelY.setCreateLabel(
(v: number) => new Text(v.toFixed(yd), { font: TICK_FONT, fill: VSPColors.textColorProperty }),
);

if (mode === "time") {
obsTransform.setModelXRange(OBS_TIME_RANGE.copy());
obsGridX.setSpacing(5);
obsTickX.setSpacing(5);
obsLabelX.setSpacing(5);
obsLabelX.setCreateLabel((v: number) => new Text(v.toFixed(0), { font: TICK_FONT }));
obsLabelX.setCreateLabel(
(v: number) => new Text(v.toFixed(0), { font: TICK_FONT, fill: VSPColors.textColorProperty }),
);
} else {
obsTransform.setModelXRange(new Range(0, 1));
obsGridX.setSpacing(0.25);
obsTickX.setSpacing(0.25);
obsLabelX.setSpacing(0.25);
obsLabelX.setCreateLabel((v: number) => new Text(v.toFixed(2), { font: TICK_FONT }));
obsLabelX.setCreateLabel(
(v: number) => new Text(v.toFixed(2), { font: TICK_FONT, fill: VSPColors.textColorProperty }),
);
}

updatePeriodMultipleMarkers();
Expand All @@ -488,30 +502,36 @@ export class AnalyzerScreenView extends ScreenView {
() => updateObservations(),
);

const obsTitle = new Text(strings.observationsStringProperty, { font: HEADER_FONT });
const obsTitle = new Text(strings.observationsStringProperty, {
font: HEADER_FONT,
fill: VSPColors.textColorProperty,
});
const obsYLabel = new Text(strings.differentialMagnitudeStringProperty, {
font: SMALL_FONT,
rotation: -Math.PI / 2,
fill: VSPColors.textColorProperty,
});
const obsXLabel = new Text(
new DerivedProperty(
[model.lightCurveModeProperty, strings.julianDateStringProperty, strings.phaseStringProperty],
(mode, julianDate, phase) => (mode === "time" ? julianDate : phase),
),
{ font: SMALL_FONT },
{ font: SMALL_FONT, fill: VSPColors.textColorProperty },
);

const modeRadioGroup = new AquaRadioButtonGroup<LightCurveMode>(
model.lightCurveModeProperty,
[
{
value: "time",
createNode: () => new Text(strings.timeStringProperty, { font: LABEL_FONT }),
createNode: () =>
new Text(strings.timeStringProperty, { font: LABEL_FONT, fill: VSPColors.textColorProperty }),
options: { accessibleName: strings.timeStringProperty },
},
{
value: "phase",
createNode: () => new Text(strings.phaseStringProperty, { font: LABEL_FONT }),
createNode: () =>
new Text(strings.phaseStringProperty, { font: LABEL_FONT, fill: VSPColors.textColorProperty }),
options: { accessibleName: strings.phaseStringProperty },
},
],
Expand All @@ -528,7 +548,10 @@ export class AnalyzerScreenView extends ScreenView {
model.phaseOffsetProperty,
PHASE_OFFSET_RANGE,
{
titleNodeOptions: { font: SMALL_FONT },
// titleNodeOptions has no background (unlike numberDisplayOptions, which draws
// its own white box) and this control sits directly on the dark screen
// background, so its title needs the light textColorProperty fill.
titleNodeOptions: { font: SMALL_FONT, fill: VSPColors.textColorProperty },
numberDisplayOptions: { textOptions: { font: SMALL_FONT } },
sliderOptions: { trackSize: new Dimension2(120, 3) },
layoutFunction: NumberControl.createLayoutFunction1(),
Expand All @@ -537,7 +560,7 @@ export class AnalyzerScreenView extends ScreenView {
);
const differenceToolCheckbox = new Checkbox(
showDifferenceToolProperty,
new Text(strings.showDifferenceToolStringProperty, { font: LABEL_FONT }),
new Text(strings.showDifferenceToolStringProperty, { font: LABEL_FONT, fill: VSPColors.textColorProperty }),
{ boxWidth: 16, accessibleName: strings.showDifferenceToolStringProperty },
);

Expand All @@ -546,7 +569,10 @@ export class AnalyzerScreenView extends ScreenView {
const obsModeRow = new HBox({
spacing: 8,
align: "center",
children: [new Text(strings.lightCurveStringProperty, { font: LABEL_FONT }), modeRadioGroup],
children: [
new Text(strings.lightCurveStringProperty, { font: LABEL_FONT, fill: VSPColors.textColorProperty }),
modeRadioGroup,
],
});
const obsToolRow = new HBox({
spacing: 16,
Expand Down Expand Up @@ -588,11 +614,11 @@ export class AnalyzerScreenView extends ScreenView {
const pdmTickY = new TickMarkSet(pdmTransform, Orientation.VERTICAL, 0.2, { edge: "min" });
const pdmLabelX = new TickLabelSet(pdmTransform, Orientation.HORIZONTAL, 1, {
edge: "min",
createLabel: (v: number) => new Text(v.toFixed(1), { font: TICK_FONT }),
createLabel: (v: number) => new Text(v.toFixed(1), { font: TICK_FONT, fill: VSPColors.textColorProperty }),
});
const pdmLabelY = new TickLabelSet(pdmTransform, Orientation.VERTICAL, 0.2, {
edge: "min",
createLabel: (v: number) => new Text(v.toFixed(1), { font: TICK_FONT }),
createLabel: (v: number) => new Text(v.toFixed(1), { font: TICK_FONT, fill: VSPColors.textColorProperty }),
});

const pdmLine = new LinePlot(pdmTransform, [], { stroke: VSPColors.lightCurveColorProperty, lineWidth: 1.5 });
Expand Down Expand Up @@ -685,7 +711,9 @@ export class AnalyzerScreenView extends ScreenView {
pdmGridX.setSpacing(spacing);
pdmTickX.setSpacing(spacing);
pdmLabelX.setSpacing(spacing);
pdmLabelX.setCreateLabel((v: number) => new Text(v.toFixed(xd), { font: TICK_FONT }));
pdmLabelX.setCreateLabel(
(v: number) => new Text(v.toFixed(xd), { font: TICK_FONT, fill: VSPColors.textColorProperty }),
);
};

const updatePdmData = () => {
Expand Down Expand Up @@ -714,7 +742,7 @@ export class AnalyzerScreenView extends ScreenView {
model.trialPeriodProperty,
PERIOD_RANGE,
{
titleNodeOptions: { font: LABEL_FONT },
titleNodeOptions: { font: LABEL_FONT, fill: VSPColors.textColorProperty },
numberDisplayOptions: {
textOptions: { font: LABEL_FONT },
decimalPlaces: 4,
Expand All @@ -725,42 +753,50 @@ export class AnalyzerScreenView extends ScreenView {
},
);

// This readout sits directly on the dark screen background (pdmColumn is not
// wrapped in a panel), so it uses textColorProperty rather than
// mutedTextColorProperty (designed for light panel surfaces).
const bestPeriodReadout = new Text(
new DerivedProperty([model.pdmScanResultsProperty, strings.bestPeriodPatternStringProperty], (scan, pattern) => {
const best = bestPeriod(scan);
return best === null ? "" : pattern.replace("{{value}}", best.toFixed(4));
}),
{ font: SMALL_FONT, fill: VSPColors.mutedTextColorProperty },
{ font: SMALL_FONT, fill: VSPColors.textColorProperty },
);

const zoomInButton = new TextPushButton(strings.zoomInAroundPeriodStringProperty, {
font: SMALL_FONT,
baseColor: VSPColors.buttonActiveColorProperty,
listener: () => model.zoomInAroundPeriod(),
accessibleName: strings.zoomInAroundPeriodStringProperty,
...FLAT_RECTANGULAR_BUTTON_OPTIONS,
});
const zoomOutButton = new TextPushButton(strings.zoomOutAroundPeriodStringProperty, {
font: SMALL_FONT,
baseColor: VSPColors.buttonActiveColorProperty,
listener: () => model.zoomOutAroundPeriod(),
accessibleName: strings.zoomOutAroundPeriodStringProperty,
...FLAT_RECTANGULAR_BUTTON_OPTIONS,
});
const fullButton = new TextPushButton(strings.zoomToFullStringProperty, {
font: SMALL_FONT,
baseColor: VSPColors.buttonColorProperty,
listener: () => model.zoomToFull(),
accessibleName: strings.zoomToFullStringProperty,
...FLAT_RECTANGULAR_BUTTON_OPTIONS,
});
const undoButton = new TextPushButton(strings.undoLastZoomStringProperty, {
font: SMALL_FONT,
baseColor: VSPColors.buttonColorProperty,
listener: () => model.undoLastZoom(),
accessibleName: strings.undoLastZoomStringProperty,
...FLAT_RECTANGULAR_BUTTON_OPTIONS,
});
const snapButton = new TextPushButton(strings.snapToMinStringProperty, {
font: SMALL_FONT,
baseColor: VSPColors.buttonSnapColorProperty,
accessibleName: strings.snapToMinStringProperty,
...FLAT_RECTANGULAR_BUTTON_OPTIONS,
listener: () => {
const best = bestPeriod(model.pdmScanResultsProperty.value);
if (best !== null) {
Expand All @@ -773,8 +809,15 @@ export class AnalyzerScreenView extends ScreenView {
spacing: 8,
children: [zoomInButton, zoomOutButton, fullButton, undoButton, snapButton],
});
const pdmYLabel = new Text(strings.thetaAxisStringProperty, { font: SMALL_FONT, rotation: -Math.PI / 2 });
const pdmXLabel = new Text(strings.trialPeriodAxisStringProperty, { font: SMALL_FONT });
const pdmYLabel = new Text(strings.thetaAxisStringProperty, {
font: SMALL_FONT,
rotation: -Math.PI / 2,
fill: VSPColors.textColorProperty,
});
const pdmXLabel = new Text(strings.trialPeriodAxisStringProperty, {
font: SMALL_FONT,
fill: VSPColors.textColorProperty,
});

const pdmColumn = new VBox({
spacing: 6,
Expand All @@ -783,7 +826,11 @@ export class AnalyzerScreenView extends ScreenView {
new HBox({
spacing: 20,
align: "center",
children: [new Text(strings.pdmTitleStringProperty, { font: HEADER_FONT }), periodControl, bestPeriodReadout],
children: [
new Text(strings.pdmTitleStringProperty, { font: HEADER_FONT, fill: VSPColors.textColorProperty }),
periodControl,
bestPeriodReadout,
],
}),
pdmButtonRow,
new HBox({ spacing: 4, align: "center", children: [pdmYLabel, pdmChart] }),
Expand Down Expand Up @@ -812,6 +859,7 @@ export class AnalyzerScreenView extends ScreenView {
right: this.layoutBounds.maxX - VSPConstants.LAYOUT.RESET_BUTTON_MARGIN,
bottom: this.layoutBounds.maxY - VSPConstants.LAYOUT.RESET_BUTTON_MARGIN,
tandem: tandem.createTandem("resetAllButton"),
...FLAT_RESET_ALL_BUTTON_OPTIONS,
});
this.addChild(resetAllButton);

Expand Down
9 changes: 9 additions & 0 deletions src/blink-comparator/view/BlinkComparatorScreenView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import { ScreenView } from "scenerystack/sim";
import { Checkbox, HSlider, Panel, RectangularPushButton, TextPushButton } from "scenerystack/sun";
import { Tandem } from "scenerystack/tandem";
import { OBSERVATIONS } from "../../common/model/StarFieldData.js";
import { FLAT_RECTANGULAR_BUTTON_OPTIONS, FLAT_RESET_ALL_BUTTON_OPTIONS } from "../../common/VSPButtonOptions.js";
import { FieldGridNode } from "../../common/view/FieldGridNode.js";
import { StarFieldNode } from "../../common/view/StarFieldNode.js";
import { StringManager } from "../../i18n/StringManager.js";
Expand Down Expand Up @@ -231,6 +232,7 @@ export class BlinkComparatorScreenView extends ScreenView {
font: LABEL_FONT,
baseColor: VSPColors.buttonAddColorProperty,
accessibleName: strings.addToQueueStringProperty,
...FLAT_RECTANGULAR_BUTTON_OPTIONS,
listener: () => {
const selected = model.selectedObsIndexProperty.value;
model.addSelectedToQueue();
Expand All @@ -245,6 +247,7 @@ export class BlinkComparatorScreenView extends ScreenView {
font: LABEL_FONT,
baseColor: VSPColors.buttonNeutralColorProperty,
accessibleName: strings.removeFromQueueStringProperty,
...FLAT_RECTANGULAR_BUTTON_OPTIONS,
listener: () => {
if (model.blinkQueue.length > 0) {
const obsIndex =
Expand Down Expand Up @@ -343,6 +346,7 @@ export class BlinkComparatorScreenView extends ScreenView {
yMargin: 2,
listener: () => scrollObservationList(-1),
accessibleName: a11yControls.scrollUpStringProperty,
...FLAT_RECTANGULAR_BUTTON_OPTIONS,
});
const obsScrollDownButton = new RectangularPushButton({
content: new Text("▼", { font: SMALL_FONT }),
Expand All @@ -351,6 +355,7 @@ export class BlinkComparatorScreenView extends ScreenView {
yMargin: 2,
listener: () => scrollObservationList(1),
accessibleName: a11yControls.scrollDownStringProperty,
...FLAT_RECTANGULAR_BUTTON_OPTIONS,
});

const observationTable = new HBox({
Expand Down Expand Up @@ -431,6 +436,7 @@ export class BlinkComparatorScreenView extends ScreenView {
font: LABEL_FONT,
baseColor: VSPColors.buttonNeutralColorProperty,
accessibleName: a11yControls.previousStringProperty,
...FLAT_RECTANGULAR_BUTTON_OPTIONS,
listener: () => {
if (model.blinkQueue.length > 0) {
model.queuePositionProperty.value =
Expand All @@ -442,6 +448,7 @@ export class BlinkComparatorScreenView extends ScreenView {
font: LABEL_FONT,
baseColor: VSPColors.buttonNeutralColorProperty,
accessibleName: strings.blinkStringProperty,
...FLAT_RECTANGULAR_BUTTON_OPTIONS,
listener: () => {
model.isBlinkingProperty.value = !model.isBlinkingProperty.value;
},
Expand All @@ -453,6 +460,7 @@ export class BlinkComparatorScreenView extends ScreenView {
font: LABEL_FONT,
baseColor: VSPColors.buttonNeutralColorProperty,
accessibleName: a11yControls.nextStringProperty,
...FLAT_RECTANGULAR_BUTTON_OPTIONS,
listener: () => {
if (model.blinkQueue.length > 0) {
model.queuePositionProperty.value = (model.queuePositionProperty.value + 1) % model.blinkQueue.length;
Expand Down Expand Up @@ -555,6 +563,7 @@ export class BlinkComparatorScreenView extends ScreenView {
right: this.layoutBounds.maxX - VSPConstants.LAYOUT.RESET_BUTTON_MARGIN,
bottom: this.layoutBounds.maxY - VSPConstants.LAYOUT.RESET_BUTTON_MARGIN,
tandem: tandem.createTandem("resetAllButton"),
...FLAT_RESET_ALL_BUTTON_OPTIONS,
});
this.addChild(resetAllButton);

Expand Down
22 changes: 22 additions & 0 deletions src/common/VSPButtonOptions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/**
* VSPButtonOptions.ts
*
* Shared flat button appearance for the sim. Rectangular push buttons and
* ResetAllButton default to SceneryStack's 3-D/beveled appearance; spread these
* options into a button's constructor options for a flat look everywhere. This
* does not set `baseColor` — call sites keep their existing semantic colors
* from VSPColors (buttonColorProperty, buttonAddColorProperty, etc.) and just
* layer the flat appearance strategy on top.
*/

import { ButtonNode } from "scenerystack/sun";

export const FLAT_BUTTON_APPEARANCE_OPTIONS = {
buttonAppearanceStrategy: ButtonNode.FlatAppearanceStrategy,
} as const;

/** Options for RectangularPushButton / TextPushButton. */
export const FLAT_RECTANGULAR_BUTTON_OPTIONS = FLAT_BUTTON_APPEARANCE_OPTIONS;

/** Options for ResetAllButton (extends RoundPushButton). */
export const FLAT_RESET_ALL_BUTTON_OPTIONS = FLAT_BUTTON_APPEARANCE_OPTIONS;
Loading
Loading