mirror of
https://github.com/wownero/wowlet.git
synced 2026-10-17 07:11:29 +02:00
fix(send): the scene sits in the middle of the space below the form
It was butted straight up against the Clear/Send row, so a band of night sky touched a button and read as part of the form. Now there is a fixed 14px gap under the buttons and a stretch either side of the scene, which centres it in whatever space the form leaves. And the coins come in handfuls. One at a time reads as a metronome, so Send now has three of them: usually one goes past, sometimes two, and about one time in seven all three, staggered by a beat so they arrive together rather than in a rank. Each rolls its own height, size, duration and spin direction. Claude-Session: https://claude.ai/code/session_01VLQ5DsgKv23osGANoFT3zF
This commit is contained in:
+9
-2
@@ -29,10 +29,17 @@ SendWidget::SendWidget(Wallet *wallet, QWidget *parent)
|
||||
// wowlet: the form only needs the top of the tab — give the rest of it to
|
||||
// the ambient scene. A layout item under the form, never an overlay: the
|
||||
// send form itself stays untouched.
|
||||
//
|
||||
// Centred in the space below the form rather than stacked straight under
|
||||
// it: butted up against the Clear/Send row the scene reads as part of the
|
||||
// form, and a band of night sky touching a button looks like a mistake.
|
||||
auto *scene = new SceneWidget(this, SceneWidget::Night, SceneWidget::Money);
|
||||
scene->setMinimumHeight(160);
|
||||
scene->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
ui->verticalLayoutOuter->addWidget(scene, 1);
|
||||
scene->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
ui->verticalLayoutOuter->addSpacing(14); // never touches the Send row
|
||||
ui->verticalLayoutOuter->addStretch(1);
|
||||
ui->verticalLayoutOuter->addWidget(scene);
|
||||
ui->verticalLayoutOuter->addStretch(1);
|
||||
|
||||
QString amount_rx = R"(^\d{0,8}[\.,]\d{0,12}|(all)$)";
|
||||
QRegularExpression rx;
|
||||
|
||||
+51
-21
@@ -477,22 +477,41 @@ Rectangle {
|
||||
property real sparkT: 1.0
|
||||
NumberAnimation { id: sparkAnim; target: scene; property: "sparkT"; from: 0; to: 1; duration: 520 }
|
||||
|
||||
// A coin sails past on the Send screen — money going somewhere.
|
||||
AnimatedImage {
|
||||
id: flyingCoin
|
||||
property real t: 1.0
|
||||
property real band: 0.3
|
||||
source: "qrc:/scene/goldcoin.gif"
|
||||
playing: scene.live && visible
|
||||
visible: !scene.reducedMotion && scene.moneyMode && t < 1.0
|
||||
width: 26; height: 26
|
||||
x: -width + t * (scene.width + width * 2)
|
||||
// A shallow arc rather than a flat line, so it reads as thrown.
|
||||
y: scene.height * band - Math.sin(t * Math.PI) * scene.height * 0.16
|
||||
rotation: t * 540
|
||||
opacity: Math.min(1, Math.sin(t * Math.PI) * 3)
|
||||
NumberAnimation { id: flyingCoinAnim; target: flyingCoin; property: "t"
|
||||
from: 0; to: 1; duration: 2600 }
|
||||
// Coins sail past on the Send screen — money going somewhere. Three of
|
||||
// them, because one at a time reads as a metronome; a handful crossing
|
||||
// together with a beat between them reads as a payment going out.
|
||||
Repeater {
|
||||
id: flyingCoins
|
||||
model: 3
|
||||
AnimatedImage {
|
||||
id: coinFly
|
||||
property real t: 1.0
|
||||
property real band: 0.3
|
||||
property real spin: 540
|
||||
source: "qrc:/scene/goldcoin.gif"
|
||||
playing: scene.live && visible
|
||||
visible: !scene.reducedMotion && scene.moneyMode && t < 1.0
|
||||
width: 22 + index * 5; height: width
|
||||
x: -width + t * (scene.width + width * 2)
|
||||
// A shallow arc rather than a flat line, so it reads as thrown.
|
||||
y: scene.height * band - Math.sin(t * Math.PI) * scene.height * 0.16
|
||||
rotation: t * spin
|
||||
opacity: Math.min(1, Math.sin(t * Math.PI) * 3)
|
||||
|
||||
NumberAnimation { id: coinFlyAnim; target: coinFly; property: "t"
|
||||
from: 0; to: 1; duration: 2600 }
|
||||
Timer { id: coinFlyTimer; repeat: false; onTriggered: coinFlyAnim.restart() }
|
||||
|
||||
function launch(delayMs) {
|
||||
coinFlyAnim.stop();
|
||||
coinFly.t = 1.0; // hidden until it starts
|
||||
coinFly.band = 0.14 + Math.random() * 0.32;
|
||||
coinFly.spin = (Math.random() < 0.5 ? -1 : 1) * (360 + Math.random() * 540);
|
||||
coinFlyAnim.duration = 2000 + Math.floor(Math.random() * 2400);
|
||||
coinFlyTimer.interval = Math.max(1, delayMs);
|
||||
coinFlyTimer.restart();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ...and one lands in the field on the Receive screen. A coin arriving is
|
||||
@@ -561,10 +580,18 @@ Rectangle {
|
||||
function ambientEvent() {
|
||||
var roll = Math.random();
|
||||
if (scene.moneyMode) {
|
||||
if (roll < 0.62) {
|
||||
flyingCoin.band = 0.16 + Math.random() * 0.30;
|
||||
flyingCoinAnim.duration = 2100 + Math.floor(Math.random() * 2200);
|
||||
flyingCoinAnim.restart();
|
||||
if (roll < 0.68) {
|
||||
// One coin most of the time, two now and then, occasionally
|
||||
// three — staggered by a beat so they arrive as a handful
|
||||
// rather than a rank.
|
||||
var n = 1;
|
||||
if (Math.random() < 0.38) n = 2;
|
||||
if (Math.random() < 0.14) n = 3;
|
||||
for (var i = 0; i < n; ++i) {
|
||||
var item = flyingCoins.itemAt(i);
|
||||
if (item)
|
||||
item.launch(i * (120 + Math.floor(Math.random() * 380)));
|
||||
}
|
||||
} else if (scene.night) {
|
||||
shootingStar.p = 1.0;
|
||||
starAnim.restart();
|
||||
@@ -877,7 +904,10 @@ Rectangle {
|
||||
scene.hopY = 0.0;
|
||||
scene.sparkT = 1.0;
|
||||
scene.sitterHop = 0.0;
|
||||
flyingCoin.t = 1.0;
|
||||
for (var ci = 0; ci < 3; ++ci) {
|
||||
var c = flyingCoins.itemAt(ci);
|
||||
if (c) c.t = 1.0;
|
||||
}
|
||||
giftCoin.t = 1.0;
|
||||
|
||||
if (!scene.live)
|
||||
|
||||
Reference in New Issue
Block a user