|
| 1 | +// Copyright (c) 2024 The Bitcoin Core developers |
| 2 | +// Distributed under the MIT software license, see the accompanying |
| 3 | +// file COPYING or http://www.opensource.org/licenses/mit-license.php. |
| 4 | + |
| 5 | +import QtQuick 2.15 |
| 6 | +import QtQuick.Controls 2.15 |
| 7 | +import QtQuick.Layouts 1.15 |
| 8 | + |
| 9 | +import org.bitcoincore.qt 1.0 |
| 10 | + |
| 11 | +import "../../controls" |
| 12 | + |
| 13 | +Button { |
| 14 | + id: root |
| 15 | + |
| 16 | + function formatSatoshis(satoshis) { |
| 17 | + var highlightColor = Theme.color.neutral9 |
| 18 | + var zeroColor = Theme.color.neutral7 |
| 19 | + |
| 20 | + if (root.checked || root.hovered) { |
| 21 | + highlightColor = zeroColor = Theme.color.orange |
| 22 | + } |
| 23 | + |
| 24 | + // Convert satoshis to bitcoins |
| 25 | + var bitcoins = satoshis / 100000000; |
| 26 | + |
| 27 | + // Format bitcoins to a fixed 8 decimal places string |
| 28 | + var bitcoinStr = bitcoins.toFixed(8); |
| 29 | + |
| 30 | + // Split the bitcoin string into integer and fractional parts |
| 31 | + var parts = bitcoinStr.split('.'); |
| 32 | + |
| 33 | + // Add spaces for every 3 digits in the integer part |
| 34 | + parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ' '); |
| 35 | + |
| 36 | + // Highlight the first significant digit and all following digits in the integer part |
| 37 | + var significantFound = false; |
| 38 | + parts[0] = parts[0].replace(/(\d)/g, function(match) { |
| 39 | + if (!significantFound && match !== '0') { |
| 40 | + significantFound = true; |
| 41 | + } |
| 42 | + if (significantFound) { |
| 43 | + return '<font color="' + highlightColor + '">' + match + '</font>'; |
| 44 | + } |
| 45 | + return match; |
| 46 | + }); |
| 47 | + |
| 48 | + // Add spaces for every 3 digits in the decimal part |
| 49 | + parts[1] = parts[1].replace(/\B(?=(\d{3})+(?!\d))/g, ' '); |
| 50 | + if (significantFound) { |
| 51 | + parts[1] = '<font color="' + highlightColor + '">' + parts[1] + '</font>'; |
| 52 | + } else { |
| 53 | + // Highlight the first significant digit and all following digits in the fractional part |
| 54 | + significantFound = false; |
| 55 | + parts[1] = parts[1].replace(/(\d)/g, function(match) { |
| 56 | + if (!significantFound && match !== '0') { |
| 57 | + significantFound = true; |
| 58 | + } |
| 59 | + if (significantFound) { |
| 60 | + return '<font color="' + highlightColor + '">' + match + '</font>'; |
| 61 | + } |
| 62 | + return match; |
| 63 | + }); |
| 64 | + } |
| 65 | + |
| 66 | + // Concatenate the parts back together |
| 67 | + var formattedBitcoins = parts.join('.'); |
| 68 | + |
| 69 | + // Format the text with the Bitcoin symbol |
| 70 | + var formattedText = `<font color="${highlightColor}">₿</font> ${formattedBitcoins}`; |
| 71 | + |
| 72 | + // Highlight zero in a different color if satoshis are zero |
| 73 | + if (satoshis === 0) { |
| 74 | + formattedText = `<font color="${zeroColor}">₿ 0.00</font>`; |
| 75 | + } |
| 76 | + |
| 77 | + return formattedText; |
| 78 | + } |
| 79 | + |
| 80 | + property color bgActiveColor: Theme.color.neutral2 |
| 81 | + property color textColor: Theme.color.neutral7 |
| 82 | + property color textHoverColor: Theme.color.orange |
| 83 | + property color textActiveColor: Theme.color.orange |
| 84 | + property color iconColor: "transparent" |
| 85 | + property string iconSource: "" |
| 86 | + property bool showBalance: true |
| 87 | + property bool showIcon: true |
| 88 | + |
| 89 | + checkable: true |
| 90 | + hoverEnabled: AppMode.isDesktop |
| 91 | + implicitHeight: 60 |
| 92 | + implicitWidth: 220 |
| 93 | + bottomPadding: 0 |
| 94 | + topPadding: 0 |
| 95 | + clip: true |
| 96 | + |
| 97 | + contentItem: RowLayout { |
| 98 | + anchors.fill: parent |
| 99 | + anchors.leftMargin: 5 |
| 100 | + anchors.rightMargin: 5 |
| 101 | + clip: true |
| 102 | + spacing: 5 |
| 103 | + Icon { |
| 104 | + id: icon |
| 105 | + visible: root.showIcon |
| 106 | + source: "image://images/singlesig-wallet" |
| 107 | + color: Theme.color.neutral8 |
| 108 | + Layout.preferredWidth: 30 |
| 109 | + Layout.preferredHeight: 30 |
| 110 | + } |
| 111 | + ColumnLayout { |
| 112 | + spacing: 2 |
| 113 | + CoreText { |
| 114 | + horizontalAlignment: Text.AlignLeft |
| 115 | + Layout.fillWidth: true |
| 116 | + wrap: false |
| 117 | + id: buttonText |
| 118 | + font.pixelSize: 13 |
| 119 | + text: root.text |
| 120 | + color: root.textColor |
| 121 | + bold: true |
| 122 | + visible: root.text !== "" |
| 123 | + } |
| 124 | + CoreText { |
| 125 | + id: balanceText |
| 126 | + visible: root.showBalance |
| 127 | + text: formatSatoshis(12300) |
| 128 | + color: Theme.color.neutral7 |
| 129 | + } |
| 130 | + } |
| 131 | + } |
| 132 | + |
| 133 | + background: Rectangle { |
| 134 | + id: bg |
| 135 | + height: root.height |
| 136 | + width: root.width |
| 137 | + radius: 5 |
| 138 | + color: Theme.color.neutral3 |
| 139 | + visible: root.hovered || root.checked |
| 140 | + |
| 141 | + FocusBorder { |
| 142 | + visible: root.visualFocus |
| 143 | + } |
| 144 | + |
| 145 | + Behavior on color { |
| 146 | + ColorAnimation { duration: 150 } |
| 147 | + } |
| 148 | + } |
| 149 | + |
| 150 | + states: [ |
| 151 | + State { |
| 152 | + name: "CHECKED"; when: root.checked |
| 153 | + PropertyChanges { target: buttonText; color: root.textActiveColor } |
| 154 | + PropertyChanges { target: icon; color: root.textActiveColor } |
| 155 | + PropertyChanges { target: balanceText; color: root.textActiveColor } |
| 156 | + }, |
| 157 | + State { |
| 158 | + name: "HOVER"; when: root.hovered |
| 159 | + PropertyChanges { target: buttonText; color: root.textHoverColor } |
| 160 | + PropertyChanges { target: icon; color: root.textHoverColor } |
| 161 | + PropertyChanges { target: balanceText; color: root.textHoverColor } |
| 162 | + } |
| 163 | + ] |
| 164 | +} |
0 commit comments