parent
f9612898ab
commit
5a991f3244
@ -0,0 +1 @@
|
||||
Error screens redesign
|
After Width: | Height: | Size: 4.7 KiB |
After Width: | Height: | Size: 9.3 KiB |
After Width: | Height: | Size: 7.4 KiB |
After Width: | Height: | Size: 5.1 KiB |
After Width: | Height: | Size: 6.3 KiB |
After Width: | Height: | Size: 9.2 KiB |
@ -0,0 +1 @@
|
||||
Bootloader redesign
|
@ -1,11 +0,0 @@
|
||||
// clang-format off
|
||||
static const uint8_t toi_icon_cancel[] = {
|
||||
// magic
|
||||
'T', 'O', 'I', 'G',
|
||||
// width (16-bit), height (16-bit)
|
||||
0x10, 0x00, 0x10, 0x00,
|
||||
// compressed data length (32-bit)
|
||||
0x52, 0x00, 0x00, 0x00,
|
||||
// compressed data
|
||||
0x45, 0x4d, 0xc1, 0x09, 0x80, 0x30, 0x10, 0x4b, 0xcf, 0x05, 0xba, 0x80, 0xd0, 0x01, 0x2c, 0xb8, 0xff, 0x47, 0x70, 0x01, 0xb1, 0x0b, 0xdc, 0x20, 0xb6, 0xc4, 0x48, 0x5b, 0x0c, 0x1c, 0x09, 0xe1, 0x92, 0xe0, 0x0c, 0x40, 0xdc, 0x90, 0x5a, 0x06, 0x8a, 0x5b, 0xa1, 0x5b, 0x6a, 0xcc, 0x0f, 0xb9, 0xde, 0xe4, 0xa1, 0xf3, 0x26, 0x9d, 0x2a, 0x85, 0xcb, 0x50, 0x3e, 0xd6, 0x6f, 0x94, 0xeb, 0xe1, 0xe7, 0xe1, 0x2b, 0x2b, 0xb8, 0xcd, 0x5c, 0xed, 0x3d, 0xd7, 0xec, 0xdd, 0xfb, 0xce, 0x82, 0xb1, 0xfb, 0x02,
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
// clang-format off
|
||||
static const uint8_t toi_icon_confirm[] = {
|
||||
// magic
|
||||
'T', 'O', 'I', 'G',
|
||||
// width (16-bit), height (16-bit)
|
||||
0x14, 0x00, 0x10, 0x00,
|
||||
// compressed data length (32-bit)
|
||||
0x69, 0x00, 0x00, 0x00,
|
||||
// compressed data
|
||||
0x63, 0x60, 0x80, 0x80, 0x48, 0x28, 0xcd, 0x30, 0xe1, 0x3f, 0x2b, 0x94, 0xf5, 0xe3, 0x7f, 0x3c, 0x84, 0xd1, 0xf0, 0xff, 0xff, 0x7a, 0x08, 0xeb, 0xfb, 0xff, 0xff, 0xdc, 0x60, 0x46, 0xc1, 0xff, 0xff, 0xfb, 0x19, 0x18, 0x1c, 0x38, 0x19, 0x18, 0xbe, 0x81, 0x85, 0xbe, 0xcc, 0x67, 0x48, 0x00, 0x0a, 0x31, 0x32, 0x38, 0xfc, 0xff, 0x2f, 0xf1, 0xec, 0xff, 0x7f, 0x69, 0x06, 0x86, 0x05, 0x40, 0xfe, 0x3f, 0x90, 0x10, 0x83, 0xc0, 0xef, 0xff, 0x40, 0xa0, 0x0d, 0xd2, 0xb7, 0x11, 0xc8, 0xd8, 0xcf, 0x04, 0x62, 0x81, 0x04, 0x75, 0x20, 0xa6, 0x6e, 0xfa, 0x7f, 0x9e, 0x19, 0xc2, 0x52, 0xf8, 0x6d, 0x03, 0x73, 0xc7, 0x62, 0x16, 0x30, 0x05, 0x00,
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
// clang-format off
|
||||
static const uint8_t toi_icon_done[] = {
|
||||
// magic
|
||||
'T', 'O', 'I', 'G',
|
||||
// width (16-bit), height (16-bit)
|
||||
0x40, 0x00, 0x40, 0x00,
|
||||
// compressed data length (32-bit)
|
||||
0xce, 0x00, 0x00, 0x00,
|
||||
// compressed data
|
||||
0x63, 0x60, 0x18, 0x05, 0x23, 0x0f, 0x4c, 0xe0, 0xc6, 0x2f, 0xff, 0xfb, 0x3e, 0x7e, 0xed, 0xff, 0xff, 0x4b, 0xe3, 0x93, 0xff, 0xf5, 0xff, 0xff, 0x79, 0xfc, 0xda, 0xff, 0xff, 0xe7, 0xc1, 0x2d, 0xff, 0x03, 0x24, 0xbf, 0x1f, 0xa7, 0xf4, 0x82, 0xff, 0x60, 0xc0, 0x89, 0x57, 0xfb, 0xff, 0xfb, 0x78, 0x6d, 0xff, 0xff, 0x5f, 0x17, 0xbf, 0xf6, 0xf7, 0x8c, 0x38, 0xa4, 0x1b, 0x88, 0xd3, 0xce, 0x84, 0x5f, 0xbb, 0x2c, 0x86, 0xab, 0xa4, 0xf1, 0x6b, 0x87, 0xc6, 0x08, 0xd4, 0xf1, 0x72, 0x58, 0x3c, 0x25, 0x03, 0xa2, 0xbf, 0x43, 0xfc, 0x8e, 0xa1, 0xfd, 0x27, 0x24, 0x46, 0xa0, 0xb6, 0xeb, 0x61, 0x0d, 0x52, 0x59, 0x98, 0xf6, 0xf7, 0xd8, 0xb4, 0x83, 0x62, 0xa4, 0x00, 0x87, 0xdf, 0xa1, 0xc6, 0xf2, 0x7d, 0x83, 0xd0, 0xcc, 0xe8, 0xf2, 0x06, 0xff, 0x20, 0xce, 0xc2, 0x61, 0x3b, 0x03, 0xc3, 0xe7, 0xff, 0x48, 0x80, 0x19, 0x53, 0xde, 0x00, 0x49, 0x5a, 0x1e, 0x5b, 0xb0, 0x3e, 0x86, 0x4b, 0xbf, 0x67, 0xc6, 0x26, 0x8f, 0x30, 0x40, 0x1f, 0x7b, 0xbc, 0x3c, 0xc5, 0xab, 0x1d, 0x61, 0x80, 0x3d, 0xae, 0x78, 0xff, 0x8a, 0xd3, 0xf1, 0xc8, 0x06, 0xd8, 0xe3, 0x4e, 0xf5, 0x9f, 0xf1, 0x6a, 0x67, 0x60, 0x08, 0x00, 0x4a, 0xfb, 0x33, 0xe0, 0x01, 0x4f, 0xfe, 0xff, 0x67, 0xc1, 0x27, 0x9f, 0x80, 0x5f, 0x3b, 0x03, 0xc3, 0x15, 0x16, 0x86, 0x51, 0x30, 0xc2, 0x00, 0x00,
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
// clang-format off
|
||||
static const uint8_t toi_icon_fail[] = {
|
||||
// magic
|
||||
'T', 'O', 'I', 'G',
|
||||
// width (16-bit), height (16-bit)
|
||||
0x40, 0x00, 0x40, 0x00,
|
||||
// compressed data length (32-bit)
|
||||
0x21, 0x01, 0x00, 0x00,
|
||||
// compressed data
|
||||
0xed, 0x52, 0x39, 0x12, 0x82, 0x40, 0x10, 0x44, 0x17, 0x88, 0x7d, 0x82, 0x1f, 0xd0, 0xe2, 0x05, 0x2e, 0x0f, 0xb0, 0x84, 0x1f, 0xc0, 0x0f, 0x7c, 0xa2, 0x89, 0xb9, 0x55, 0xfe, 0xc0, 0x23, 0xdf, 0xc0, 0x23, 0xd1, 0x62, 0x14, 0xd8, 0x65, 0xf6, 0xe8, 0x22, 0x36, 0xb0, 0xa3, 0xae, 0x69, 0x66, 0xd8, 0x9e, 0xe9, 0x28, 0xfa, 0xe3, 0x27, 0x30, 0x5f, 0x33, 0xdf, 0x4f, 0x43, 0xfd, 0x44, 0xa9, 0xa1, 0x35, 0x2d, 0xc3, 0xf6, 0x86, 0x0a, 0xc3, 0xef, 0xa4, 0x82, 0x01, 0x47, 0x22, 0x4a, 0x7a, 0x5a, 0x7e, 0xe9, 0x22, 0x6c, 0x27, 0xaa, 0x7a, 0xfe, 0xf8, 0x52, 0x7f, 0x40, 0xdb, 0x4e, 0x14, 0xb7, 0x34, 0xef, 0xa8, 0x3b, 0x60, 0xd6, 0x74, 0xc5, 0x6d, 0xcb, 0x9f, 0x1d, 0x55, 0x13, 0x5b, 0x3f, 0x13, 0x99, 0x01, 0xb9, 0xa6, 0x8e, 0x85, 0x97, 0x2e, 0x16, 0xed, 0xe3, 0x7b, 0xec, 0x6c, 0xfd, 0xa6, 0x8b, 0x94, 0xd6, 0x86, 0x49, 0x5b, 0x37, 0x43, 0xa9, 0x30, 0xed, 0xfd, 0x5b, 0x07, 0x5c, 0x74, 0x55, 0x35, 0x9a, 0xac, 0x5c, 0x7f, 0x19, 0x79, 0x10, 0xde, 0x82, 0xae, 0xae, 0xbc, 0xf1, 0xf7, 0x9b, 0x8d, 0xb7, 0xb3, 0x2f, 0xe3, 0x33, 0x18, 0xd0, 0xb0, 0xac, 0x04, 0x08, 0xc8, 0x8d, 0x75, 0x89, 0x02, 0x94, 0x0f, 0x03, 0x54, 0x0c, 0x13, 0x66, 0x76, 0xe0, 0x7b, 0x0f, 0x2c, 0x6e, 0xa0, 0x5c, 0xf3, 0xff, 0x53, 0xa4, 0xdf, 0x47, 0xed, 0xf1, 0x89, 0xc2, 0xe3, 0x44, 0x1c, 0x1b, 0x8d, 0xed, 0x78, 0x3b, 0x18, 0xf0, 0x70, 0xf5, 0xca, 0x93, 0x4b, 0xff, 0xbe, 0x31, 0x5e, 0xee, 0x90, 0x0f, 0x89, 0xdb, 0xe5, 0x70, 0x85, 0x04, 0x7a, 0x4f, 0x4a, 0xb8, 0x83, 0x77, 0x98, 0xef, 0x03, 0xfa, 0xbd, 0xe0, 0x20, 0x49, 0x90, 0xae, 0xca, 0x72, 0x2a, 0xc0, 0x6d, 0x05, 0x7f, 0x8b, 0xf2, 0x5d, 0x59, 0xab, 0x12, 0x20, 0x1c, 0x31, 0xaf, 0x7a, 0x05, 0xf2, 0x2d, 0xad, 0xd7, 0x0a, 0x10, 0xcf, 0x84, 0xb7, 0x05, 0x02, 0x9a, 0xad, 0x99, 0xef, 0x45, 0xf4, 0xc7, 0x6f, 0xe0, 0x03,
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
// clang-format off
|
||||
static const uint8_t toi_icon_info[] = {
|
||||
// magic
|
||||
'T', 'O', 'I', 'G',
|
||||
// width (16-bit), height (16-bit)
|
||||
0x20, 0x00, 0x20, 0x00,
|
||||
// compressed data length (32-bit)
|
||||
0xde, 0x00, 0x00, 0x00,
|
||||
// compressed data
|
||||
0x7d, 0x91, 0x3d, 0x0a, 0xc2, 0x40, 0x10, 0x85, 0x27, 0x10, 0xfc, 0x05, 0xe3, 0x0d, 0xbc, 0x82, 0xa0, 0x07, 0x10, 0x3c, 0x80, 0xde, 0x20, 0xf6, 0x22, 0xd8, 0x5b, 0xc4, 0xde, 0x42, 0x6f, 0x60, 0x67, 0x91, 0x46, 0x4b, 0x3b, 0xc5, 0x0b, 0xe4, 0x06, 0xba, 0x17, 0x10, 0x21, 0x10, 0x45, 0x89, 0x3e, 0x37, 0x3b, 0xbb, 0xa8, 0xab, 0x38, 0xc5, 0xce, 0x7e, 0x30, 0x3b, 0xb3, 0xf3, 0x1e, 0x91, 0x8c, 0xfa, 0xfa, 0xb8, 0x9f, 0xb8, 0x64, 0x62, 0x0c, 0x15, 0x45, 0x8d, 0x3d, 0xe8, 0x28, 0x30, 0xa7, 0xc0, 0xa8, 0xd9, 0x5e, 0x00, 0x07, 0x85, 0x02, 0xc8, 0xeb, 0xb2, 0x5a, 0x96, 0x1f, 0x28, 0x73, 0xdd, 0x0c, 0x70, 0x88, 0x56, 0x08, 0x4c, 0xdf, 0x04, 0x15, 0xa2, 0xb3, 0xaa, 0x4e, 0x96, 0xf2, 0xe8, 0x62, 0x4a, 0x84, 0x8d, 0xbc, 0x55, 0x81, 0x9c, 0x4c, 0x57, 0x38, 0x43, 0x78, 0xf2, 0xd2, 0xe2, 0xe9, 0x02, 0x45, 0xc1, 0x53, 0x01, 0x57, 0x3d, 0xf0, 0x62, 0xa8, 0x56, 0xbb, 0x81, 0x4a, 0xf0, 0x2f, 0x11, 0xbd, 0xc5, 0x6d, 0x7e, 0x0b, 0xde, 0x39, 0x89, 0x52, 0x9f, 0x5e, 0xfd, 0x29, 0x3e, 0xdd, 0x3b, 0xff, 0xd9, 0xae, 0xe7, 0x7e, 0x86, 0x93, 0x88, 0xe7, 0x19, 0xbe, 0xce, 0xf9, 0x3f, 0x86, 0xe1, 0x0b, 0xb5, 0x9e, 0x66, 0xf9, 0x5f, 0xde, 0x47, 0xb3, 0x40, 0xc9, 0xde, 0x57, 0xeb, 0x11, 0x86, 0xae, 0xd6, 0x63, 0x6b, 0xe9, 0x65, 0xeb, 0xf9, 0xa5, 0x77, 0xe6, 0x47, 0xbf, 0xd9, 0x90, 0x7e, 0x9c, 0x9c, 0x9f, 0x7e, 0xd9, 0x7e, 0x7e, 0xf8, 0xfd, 0x04,
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
// clang-format off
|
||||
static const uint8_t toi_icon_install[] = {
|
||||
// magic
|
||||
'T', 'O', 'I', 'G',
|
||||
// width (16-bit), height (16-bit)
|
||||
0x40, 0x00, 0x40, 0x00,
|
||||
// compressed data length (32-bit)
|
||||
0xb8, 0x00, 0x00, 0x00,
|
||||
// compressed data
|
||||
0x63, 0x60, 0x18, 0x05, 0xa3, 0x80, 0x58, 0xe0, 0xec, 0xe2, 0x62, 0x82, 0x4f, 0xfe, 0xcf, 0xff, 0xff, 0xe7, 0x47, 0xe5, 0xc9, 0x93, 0x3f, 0x85, 0x90, 0x5f, 0x83, 0x45, 0x7a, 0xc1, 0x7f, 0x5e, 0x98, 0xfc, 0x85, 0xff, 0x5c, 0x98, 0xf2, 0xbf, 0xfe, 0xef, 0x87, 0xc9, 0xff, 0xfe, 0xbf, 0x1e, 0x43, 0xfa, 0xc0, 0xff, 0xff, 0x40, 0x03, 0xc0, 0xf2, 0x17, 0x80, 0x4c, 0x1e, 0x74, 0x79, 0x07, 0xa0, 0xe0, 0x79, 0x46, 0x90, 0xbc, 0x00, 0x90, 0xf8, 0xcf, 0x82, 0x61, 0xc0, 0x17, 0xa0, 0xa8, 0x2e, 0x48, 0xfe, 0x12, 0x90, 0xe1, 0x8f, 0x69, 0xbf, 0x02, 0x50, 0xf8, 0xfd, 0x3f, 0x08, 0xfe, 0xcf, 0x84, 0xc5, 0x03, 0x20, 0x03, 0xa0, 0xc0, 0x1f, 0x9b, 0xff, 0x15, 0x10, 0xf2, 0x4c, 0x58, 0x03, 0xe8, 0x13, 0x4c, 0x5a, 0x1f, 0x7b, 0x00, 0x1a, 0xc0, 0xe4, 0x99, 0x71, 0x84, 0xf0, 0x63, 0x88, 0xb4, 0x1e, 0xae, 0x18, 0x50, 0x00, 0x39, 0xfd, 0xff, 0x7b, 0x26, 0x9c, 0xd1, 0x77, 0x11, 0x24, 0x2f, 0x8b, 0x3b, 0x7a, 0x05, 0xfe, 0xfe, 0xff, 0x7f, 0x9f, 0x11, 0x4f, 0xfc, 0x1f, 0xfc, 0xff, 0x5f, 0x86, 0x01, 0x6f, 0x02, 0xc1, 0x9b, 0x7c, 0x80, 0x06, 0xe0, 0xd7, 0xce, 0x20, 0xc0, 0xc8, 0x30, 0x0a, 0x46, 0x01, 0xf1, 0x00, 0x00,
|
||||
};
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,11 +0,0 @@
|
||||
// clang-format off
|
||||
static const uint8_t toi_icon_welcome[] = {
|
||||
// magic
|
||||
'T', 'O', 'I', 'G',
|
||||
// width (16-bit), height (16-bit)
|
||||
0xb4, 0x00, 0x1e, 0x00,
|
||||
// compressed data length (32-bit)
|
||||
0x32, 0x03, 0x00, 0x00,
|
||||
// compressed data
|
||||
0xc5, 0x52, 0xc1, 0x4e, 0x13, 0x51, 0x14, 0xbd, 0x50, 0xa0, 0x50, 0x2c, 0x74, 0xa7, 0x0b, 0x11, 0xbe, 0x80, 0xf2, 0x07, 0xf0, 0x07, 0xfa, 0x03, 0x06, 0x56, 0x6c, 0xdb, 0xb8, 0xc2, 0x15, 0x26, 0x2e, 0xd8, 0x90, 0x40, 0x22, 0x89, 0x1b, 0x05, 0x34, 0x26, 0xec, 0x6c, 0xf5, 0x03, 0x04, 0x75, 0xe1, 0xb2, 0xc4, 0x95, 0x3b, 0x4a, 0xe2, 0xc6, 0x28, 0x4e, 0x29, 0x50, 0x5a, 0xa0, 0x73, 0x3c, 0xf7, 0xbe, 0xe9, 0x74, 0x3a, 0x40, 0x62, 0xa4, 0x89, 0x77, 0x31, 0x73, 0xdf, 0x7b, 0xf7, 0x9c, 0x77, 0xdf, 0xb9, 0x47, 0xe4, 0x3f, 0x05, 0x30, 0x7b, 0x13, 0xf8, 0x11, 0xd0, 0xc7, 0xdf, 0x05, 0xb2, 0xfc, 0x56, 0x80, 0xc1, 0x9b, 0x31, 0x47, 0x30, 0x24, 0x4b, 0x86, 0x3b, 0x55, 0xa0, 0xbf, 0x6b, 0xcc, 0x3b, 0x40, 0x4a, 0x64, 0x06, 0xd8, 0xe0, 0xe2, 0x04, 0xe8, 0xe9, 0x1a, 0xf3, 0x2a, 0x90, 0x16, 0xc9, 0x03, 0x25, 0x2e, 0xea, 0xf0, 0xa4, 0x6b, 0xcc, 0x73, 0xc0, 0xa8, 0x48, 0x11, 0x00, 0x17, 0xe7, 0x28, 0x74, 0x8f, 0x79, 0x02, 0x98, 0x16, 0x29, 0x93, 0x39, 0x21, 0xe2, 0x63, 0xb1, 0x7b, 0xcc, 0xcc, 0x73, 0x36, 0x3a, 0x0e, 0x32, 0x63, 0xb7, 0x74, 0x8d, 0xf9, 0x5c, 0x67, 0xc7, 0xd1, 0x61, 0x58, 0xe7, 0x48, 0x65, 0xe4, 0xe9, 0x2f, 0x6f, 0x39, 0xd1, 0xae, 0x5a, 0x3b, 0xf0, 0x5e, 0x24, 0xac, 0x94, 0x07, 0x96, 0xd1, 0x4f, 0x3d, 0x6f, 0x9a, 0x7b, 0x77, 0x24, 0xf3, 0xc5, 0x7f, 0x1b, 0x1e, 0x45, 0x31, 0x16, 0x75, 0x9d, 0x5d, 0x83, 0xcc, 0x23, 0x3a, 0x47, 0x4e, 0xf3, 0x15, 0x73, 0xd3, 0xdb, 0x55, 0x7d, 0xb2, 0xa5, 0x5a, 0xe6, 0x9d, 0x66, 0xdb, 0x3d, 0xc6, 0xfc, 0x9a, 0xa9, 0x97, 0xd0, 0x86, 0x56, 0x94, 0x24, 0x86, 0x71, 0x71, 0xac, 0xb3, 0x6b, 0xa2, 0x89, 0xac, 0x6c, 0x02, 0x43, 0x92, 0x69, 0x6a, 0x15, 0xee, 0x06, 0x55, 0x53, 0xbe, 0x2d, 0xc7, 0x38, 0x11, 0x97, 0x4d, 0x1a, 0xb3, 0xe5, 0x0f, 0x6d, 0x63, 0x40, 0xe2, 0x98, 0x20, 0x0e, 0x81, 0x5e, 0x6e, 0xd4, 0xb8, 0xb5, 0xab, 0x65, 0xbb, 0x56, 0xa4, 0x0d, 0x58, 0xd5, 0xbe, 0x5b, 0x6e, 0x4b, 0xeb, 0x60, 0xcf, 0x98, 0x23, 0x31, 0x22, 0x71, 0x4c, 0x10, 0xb4, 0x45, 0x3f, 0x05, 0xfe, 0x4a, 0xb9, 0x2b, 0x7a, 0x49, 0x1d, 0x58, 0x5f, 0xf2, 0xd5, 0x2a, 0x56, 0x45, 0x9d, 0x96, 0xb7, 0x88, 0xea, 0xd3, 0x6c, 0xfd, 0xb9, 0xaf, 0xcf, 0x52, 0xe6, 0xc7, 0x3f, 0x54, 0x8f, 0x85, 0x33, 0xe0, 0xbe, 0xc4, 0x31, 0x41, 0x50, 0x82, 0xc1, 0x3c, 0xbc, 0x55, 0x36, 0x53, 0x55, 0x61, 0xac, 0xbf, 0x1d, 0x20, 0x65, 0x55, 0xb4, 0xcb, 0x86, 0x29, 0x96, 0x62, 0xc6, 0x81, 0x7c, 0x04, 0xc6, 0x95, 0x79, 0x52, 0x15, 0xc4, 0x2d, 0x99, 0x82, 0x1a, 0xb5, 0x13, 0xd3, 0x0a, 0x8e, 0x2d, 0x55, 0x44, 0xe1, 0x01, 0x59, 0x4f, 0x88, 0x9d, 0x53, 0xa8, 0x02, 0x46, 0xad, 0x2a, 0x6f, 0x76, 0xe1, 0xed, 0x69, 0x1e, 0x64, 0xed, 0x20, 0xa7, 0xcc, 0x14, 0xf7, 0x54, 0x5f, 0x48, 0xfe, 0x95, 0x38, 0xa6, 0x15, 0xdc, 0x48, 0x97, 0x91, 0x63, 0x4b, 0x7d, 0x75, 0x56, 0x6d, 0xea, 0xcd, 0xda, 0x45, 0xd6, 0xaa, 0x8a, 0xea, 0x46, 0x85, 0x8e, 0x6c, 0x6a, 0x8b, 0xca, 0x54, 0x50, 0xe6, 0x7e, 0x91, 0x9a, 0xbe, 0xd0, 0x4c, 0x1b, 0xc3, 0x44, 0xcc, 0x3d, 0x5a, 0xc5, 0xb4, 0xf8, 0x48, 0x9e, 0xbb, 0x29, 0xba, 0xb8, 0x6f, 0x55, 0x9c, 0xc2, 0xa0, 0x2b, 0xdb, 0x75, 0x59, 0x9d, 0xaa, 0x39, 0xe6, 0x93, 0x80, 0xb9, 0x10, 0xc7, 0x84, 0x71, 0x81, 0xe9, 0x1a, 0xdf, 0x71, 0x86, 0x61, 0x9f, 0x8f, 0x2a, 0xb7, 0xaa, 0x66, 0xad, 0xca, 0x3d, 0x5c, 0x83, 0x59, 0x52, 0x4c, 0x83, 0x4b, 0xcc, 0x31, 0x4c, 0x18, 0x0d, 0xe4, 0x1a, 0x7c, 0x72, 0x0d, 0xf7, 0xd4, 0x41, 0x95, 0x4b, 0xcc, 0xfd, 0x21, 0xb3, 0x66, 0x27, 0x57, 0x30, 0x57, 0xae, 0x61, 0xae, 0x61, 0xa3, 0xc9, 0x76, 0xaa, 0x58, 0x54, 0xb9, 0x2a, 0xff, 0xd0, 0xf3, 0x75, 0xcc, 0x55, 0xec, 0xa9, 0x5d, 0xcb, 0xfa, 0x4b, 0xea, 0xcb, 0x86, 0xc2, 0x01, 0xfc, 0xa5, 0xce, 0x11, 0x4c, 0x47, 0xd8, 0x8d, 0xa2, 0x2e, 0xd0, 0x0b, 0x8a, 0x2a, 0x49, 0x9b, 0xd9, 0x79, 0x63, 0x62, 0x7e, 0x7e, 0xa0, 0xe8, 0xbc, 0x71, 0x11, 0x7a, 0xa3, 0xcd, 0x1c, 0xc1, 0x74, 0x84, 0x52, 0x96, 0xcc, 0xd7, 0x5a, 0x9a, 0x57, 0xc3, 0x92, 0x6b, 0x40, 0x22, 0x7e, 0x7e, 0x42, 0x68, 0xde, 0xfc, 0x3c, 0x01, 0x2c, 0x5e, 0x62, 0x8e, 0x60, 0x3a, 0x82, 0x30, 0xfa, 0x58, 0x7d, 0xcd, 0x87, 0x4a, 0xc6, 0x3a, 0x97, 0xef, 0xb3, 0x8e, 0x39, 0x63, 0x67, 0x47, 0xec, 0x3c, 0x63, 0xf7, 0xef, 0x80, 0xfe, 0x89, 0x33, 0x47, 0x30, 0xab, 0xbf, 0x23, 0xba, 0xcc, 0xc0, 0xc9, 0xce, 0xdf, 0x86, 0x09, 0x89, 0xd2, 0xc2, 0x37, 0x2d, 0xb5, 0xed, 0x33, 0x60, 0x79, 0x0b, 0x4a, 0xd5, 0x00, 0xd6, 0x97, 0x7c, 0x95, 0x34, 0xce, 0x1c, 0xc1, 0x34, 0x8c, 0x23, 0x08, 0xbd, 0x71, 0xdc, 0x14, 0xb4, 0x37, 0xb5, 0x6c, 0x9f, 0x72, 0xcc, 0xfb, 0x6e, 0x55, 0x0a, 0x0f, 0x3c, 0xb9, 0xcc, 0xdc, 0xc6, 0xf8, 0x7a, 0x1e, 0x06, 0xfb, 0x48, 0xbb, 0x66, 0xa7, 0xf5, 0xa2, 0xa6, 0x15, 0x6d, 0x3b, 0x35, 0x4c, 0x24, 0xc6, 0x18, 0x65, 0xf4, 0x2d, 0x9b, 0xbc, 0x82, 0xb9, 0x8d, 0xe9, 0x64, 0x3e, 0x73, 0xa6, 0x39, 0xb6, 0x61, 0x51, 0x2a, 0xab, 0x4a, 0x06, 0xcc, 0xf2, 0x59, 0x57, 0x05, 0x3d, 0x78, 0x6f, 0xe8, 0xde, 0x2b, 0x98, 0xdb, 0x98, 0x0e, 0x35, 0xe4, 0x14, 0xd0, 0xa9, 0x1e, 0x3a, 0x5b, 0x89, 0x3c, 0xfa, 0x89, 0x0f, 0xb7, 0xa5, 0xc5, 0x2c, 0x6b, 0x07, 0xde, 0x72, 0xaf, 0x1d, 0x3c, 0x3b, 0xf0, 0x5e, 0xf6, 0xc9, 0x55, 0xcc, 0x21, 0x26, 0x98, 0xe0, 0x1f,
|
||||
};
|
@ -1,11 +0,0 @@
|
||||
// clang-format off
|
||||
static const uint8_t toi_icon_wipe[] = {
|
||||
// magic
|
||||
'T', 'O', 'I', 'G',
|
||||
// width (16-bit), height (16-bit)
|
||||
0x40, 0x00, 0x40, 0x00,
|
||||
// compressed data length (32-bit)
|
||||
0x2f, 0x01, 0x00, 0x00,
|
||||
// compressed data
|
||||
0xed, 0xd2, 0x31, 0x4e, 0x02, 0x41, 0x14, 0x06, 0xe0, 0xc7, 0x62, 0x58, 0x41, 0x5d, 0x48, 0xac, 0x35, 0x14, 0xf6, 0x5a, 0x98, 0x58, 0xe2, 0x0d, 0xc6, 0x1b, 0x48, 0x6d, 0x21, 0x5a, 0xd8, 0x99, 0xc8, 0x0d, 0xbc, 0x82, 0x37, 0xc0, 0x23, 0x10, 0x2f, 0x00, 0x89, 0x85, 0xa5, 0xdb, 0x6b, 0x82, 0x80, 0x68, 0x24, 0xe0, 0x73, 0xde, 0xcc, 0x12, 0x27, 0xd9, 0x7f, 0x86, 0x9a, 0x84, 0x3f, 0xd9, 0xc9, 0x66, 0xbf, 0xec, 0xec, 0xec, 0x7b, 0x8f, 0x68, 0x9d, 0xd5, 0xc9, 0xf5, 0x12, 0x1f, 0xb6, 0xc2, 0x3e, 0xe2, 0x4a, 0xd0, 0x3f, 0xb9, 0x13, 0xf4, 0x6f, 0xe6, 0xcd, 0x90, 0x4f, 0x99, 0xd5, 0x6e, 0xc0, 0x67, 0xcc, 0xbd, 0xb4, 0xe8, 0xe5, 0x3a, 0xeb, 0xdc, 0x28, 0x8f, 0x46, 0xd4, 0x14, 0x4f, 0xd8, 0xb3, 0xc1, 0x09, 0x75, 0xc5, 0xd5, 0x6c, 0x0f, 0xfb, 0x05, 0x0d, 0xc5, 0x5f, 0xa7, 0xf7, 0xd8, 0xdf, 0xe4, 0xf8, 0x3a, 0xbf, 0x9e, 0x0f, 0xf0, 0x01, 0x67, 0xd9, 0x41, 0x5c, 0xe3, 0xdb, 0x85, 0xc3, 0x3f, 0x68, 0xf3, 0x60, 0xe1, 0xb0, 0xc8, 0x7d, 0xfe, 0x4f, 0x01, 0xf8, 0xd8, 0xf1, 0x18, 0xf8, 0x8f, 0xe3, 0xdb, 0xe8, 0xf8, 0x4e, 0xaa, 0x79, 0x6e, 0xba, 0x7e, 0x98, 0xf7, 0xae, 0xeb, 0xe0, 0x07, 0x3f, 0xac, 0x5c, 0x9a, 0xb5, 0x85, 0x46, 0xcf, 0x24, 0x99, 0xc8, 0x7a, 0x97, 0xf7, 0x49, 0x56, 0xda, 0x07, 0x59, 0xcf, 0xe1, 0xe8, 0x49, 0xb6, 0x8e, 0x64, 0x6d, 0xe4, 0xfd, 0x4b, 0x9e, 0xbf, 0xf3, 0x86, 0x69, 0x62, 0x15, 0x8d, 0xb6, 0xce, 0xf3, 0xc0, 0xde, 0x80, 0x06, 0xca, 0x6c, 0x74, 0xfa, 0xca, 0xde, 0xc4, 0xb8, 0x3d, 0x8d, 0x54, 0x17, 0x36, 0xc5, 0xfd, 0x91, 0xfa, 0x25, 0xa3, 0x82, 0x71, 0x38, 0x60, 0x73, 0xe6, 0xf2, 0x31, 0x19, 0xdf, 0x27, 0xdc, 0xdf, 0x52, 0x76, 0x90, 0x08, 0xf9, 0x55, 0x76, 0xac, 0x31, 0xaa, 0x8e, 0xad, 0x60, 0xc5, 0x16, 0xaa, 0x84, 0xfd, 0xcc, 0x96, 0x65, 0xae, 0xc8, 0x93, 0x27, 0xd9, 0xf8, 0xb4, 0x17, 0xf9, 0x9c, 0x5e, 0xf4, 0xf5, 0x18, 0x7b, 0x99, 0x6a, 0xfa, 0xd5, 0x3a, 0xad, 0xb3, 0x42, 0xf9, 0x03,
|
||||
};
|
@ -0,0 +1 @@
|
||||
Bootloader redesign
|
@ -0,0 +1,11 @@
|
||||
pub fn hexlify(data: &[u8], buffer: &mut [u8]) {
|
||||
const HEX_LOWER: [u8; 16] = *b"0123456789abcdef";
|
||||
let mut i: usize = 0;
|
||||
for b in data.iter().take(buffer.len() / 2) {
|
||||
let hi: usize = ((b & 0xf0) >> 4).into();
|
||||
let lo: usize = (b & 0x0f).into();
|
||||
buffer[i] = HEX_LOWER[hi];
|
||||
buffer[i + 1] = HEX_LOWER[lo];
|
||||
i += 2;
|
||||
}
|
||||
}
|
@ -0,0 +1,195 @@
|
||||
use crate::ui::{
|
||||
component::{
|
||||
text::paragraphs::{ParagraphVecShort, Paragraphs},
|
||||
Child, Component, ComponentExt, Event, EventCtx, Label, Pad,
|
||||
},
|
||||
constant,
|
||||
constant::screen,
|
||||
display::{Color, Icon},
|
||||
geometry::{Alignment, Insets, Offset, Point, Rect, TOP_CENTER},
|
||||
model_tt::{
|
||||
bootloader::theme::{
|
||||
button_bld_menu, BUTTON_AREA_START, CLOSE, CONTENT_PADDING, CORNER_BUTTON_AREA,
|
||||
INFO_SMALL, TEXT_TITLE, TITLE_AREA,
|
||||
},
|
||||
component::{Button, ButtonMsg::Clicked},
|
||||
constant::WIDTH,
|
||||
theme::WHITE,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, ToPrimitive)]
|
||||
pub enum ConfirmMsg {
|
||||
Cancel = 1,
|
||||
Confirm = 2,
|
||||
}
|
||||
|
||||
pub struct Confirm<'a> {
|
||||
bg: Pad,
|
||||
content_pad: Pad,
|
||||
bg_color: Color,
|
||||
icon: Option<Icon>,
|
||||
title: Option<Child<Label<&'static str>>>,
|
||||
message: Child<Paragraphs<ParagraphVecShort<&'a str>>>,
|
||||
left: Child<Button<&'static str>>,
|
||||
right: Child<Button<&'static str>>,
|
||||
info_button: Option<Button<&'static str>>,
|
||||
close_button: Option<Button<&'static str>>,
|
||||
info_title: Option<Child<Label<&'static str>>>,
|
||||
info_text: Option<Paragraphs<ParagraphVecShort<&'a str>>>,
|
||||
show_info: bool,
|
||||
|
||||
confirm_left: bool,
|
||||
}
|
||||
|
||||
impl<'a> Confirm<'a> {
|
||||
pub fn new(
|
||||
bg_color: Color,
|
||||
icon: Option<Icon>,
|
||||
left: Button<&'static str>,
|
||||
right: Button<&'static str>,
|
||||
confirm_left: bool,
|
||||
confirm: (Option<&'static str>, Paragraphs<ParagraphVecShort<&'a str>>),
|
||||
info: Option<(&'static str, Paragraphs<ParagraphVecShort<&'a str>>)>,
|
||||
) -> Self {
|
||||
let mut instance = Self {
|
||||
bg: Pad::with_background(bg_color),
|
||||
content_pad: Pad::with_background(bg_color),
|
||||
bg_color,
|
||||
icon,
|
||||
message: Child::new(confirm.1),
|
||||
left: Child::new(left),
|
||||
right: Child::new(right),
|
||||
close_button: None,
|
||||
info_button: None,
|
||||
info_title: None,
|
||||
info_text: None,
|
||||
confirm_left,
|
||||
show_info: false,
|
||||
title: confirm
|
||||
.0
|
||||
.map(|title| Child::new(Label::new(title, Alignment::Start, TEXT_TITLE))),
|
||||
};
|
||||
if let Some((title, text)) = info {
|
||||
instance.info_title = Some(Child::new(Label::new(title, Alignment::Start, TEXT_TITLE)));
|
||||
instance.info_text = Some(text);
|
||||
instance.info_button = Some(
|
||||
Button::with_icon(Icon::new(INFO_SMALL))
|
||||
.styled(button_bld_menu())
|
||||
.with_expanded_touch_area(Insets::uniform(13)),
|
||||
);
|
||||
instance.close_button = Some(
|
||||
Button::with_icon(Icon::new(CLOSE))
|
||||
.styled(button_bld_menu())
|
||||
.with_expanded_touch_area(Insets::uniform(13)),
|
||||
);
|
||||
}
|
||||
instance.bg.clear();
|
||||
instance
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Component for Confirm<'a> {
|
||||
type Msg = ConfirmMsg;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.bg.place(constant::screen());
|
||||
self.content_pad.place(Rect::new(
|
||||
Point::zero(),
|
||||
Point::new(WIDTH, BUTTON_AREA_START),
|
||||
));
|
||||
let icon_height = if let Some(icon) = self.icon {
|
||||
icon.toif.height()
|
||||
} else {
|
||||
0
|
||||
};
|
||||
self.message.place(Rect::new(
|
||||
Point::new(CONTENT_PADDING, 32 + icon_height),
|
||||
Point::new(WIDTH - CONTENT_PADDING, BUTTON_AREA_START),
|
||||
));
|
||||
|
||||
let button_size = Offset::new(106, 38);
|
||||
self.left.place(Rect::from_top_left_and_size(
|
||||
Point::new(CONTENT_PADDING, BUTTON_AREA_START),
|
||||
button_size,
|
||||
));
|
||||
self.right.place(Rect::from_top_left_and_size(
|
||||
Point::new(124, BUTTON_AREA_START),
|
||||
button_size,
|
||||
));
|
||||
self.info_button.place(CORNER_BUTTON_AREA);
|
||||
self.close_button.place(CORNER_BUTTON_AREA);
|
||||
self.info_title.place(TITLE_AREA);
|
||||
self.title.place(TITLE_AREA);
|
||||
self.info_text.place(Rect::new(
|
||||
Point::new(CONTENT_PADDING, TITLE_AREA.y1),
|
||||
Point::new(WIDTH - CONTENT_PADDING, BUTTON_AREA_START),
|
||||
));
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||
if self.show_info {
|
||||
if let Some(Clicked) = self.close_button.event(ctx, event) {
|
||||
self.show_info = false;
|
||||
self.content_pad.clear();
|
||||
self.title.request_complete_repaint(ctx);
|
||||
self.message.request_complete_repaint(ctx);
|
||||
return None;
|
||||
}
|
||||
} else if let Some(Clicked) = self.info_button.event(ctx, event) {
|
||||
self.show_info = true;
|
||||
self.info_text.request_complete_repaint(ctx);
|
||||
self.info_title.request_complete_repaint(ctx);
|
||||
self.content_pad.clear();
|
||||
return None;
|
||||
}
|
||||
if let Some(Clicked) = self.left.event(ctx, event) {
|
||||
return if self.confirm_left {
|
||||
Some(Self::Msg::Confirm)
|
||||
} else {
|
||||
Some(Self::Msg::Cancel)
|
||||
};
|
||||
};
|
||||
if let Some(Clicked) = self.right.event(ctx, event) {
|
||||
return if self.confirm_left {
|
||||
Some(Self::Msg::Cancel)
|
||||
} else {
|
||||
Some(Self::Msg::Confirm)
|
||||
};
|
||||
};
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
self.content_pad.paint();
|
||||
|
||||
if self.show_info {
|
||||
self.close_button.paint();
|
||||
self.info_title.paint();
|
||||
self.info_text.paint();
|
||||
self.left.paint();
|
||||
self.right.paint();
|
||||
} else {
|
||||
self.info_button.paint();
|
||||
self.title.paint();
|
||||
self.message.paint();
|
||||
self.left.paint();
|
||||
self.right.paint();
|
||||
if let Some(icon) = self.icon {
|
||||
icon.draw(
|
||||
Point::new(screen().center().x, 32),
|
||||
TOP_CENTER,
|
||||
WHITE,
|
||||
self.bg_color,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
self.left.bounds(sink);
|
||||
self.right.bounds(sink);
|
||||
}
|
||||
}
|
@ -0,0 +1,50 @@
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never, Pad},
|
||||
constant::screen,
|
||||
display::{self, Font},
|
||||
geometry::{Offset, Rect},
|
||||
model_tt::bootloader::theme::{BLD_BG, BLD_TITLE_COLOR},
|
||||
};
|
||||
|
||||
pub struct Connect {
|
||||
bg: Pad,
|
||||
message: &'static str,
|
||||
}
|
||||
|
||||
impl Connect {
|
||||
pub fn new(message: &'static str) -> Self {
|
||||
let mut instance = Self {
|
||||
bg: Pad::with_background(BLD_BG),
|
||||
message,
|
||||
};
|
||||
|
||||
instance.bg.clear();
|
||||
instance
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Connect {
|
||||
type Msg = Never;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.bg.place(screen());
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
let font = Font::NORMAL;
|
||||
|
||||
self.bg.paint();
|
||||
display::text_center(
|
||||
screen().center() + Offset::y(font.text_height() / 2),
|
||||
self.message,
|
||||
Font::NORMAL,
|
||||
BLD_TITLE_COLOR,
|
||||
BLD_BG,
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
use crate::ui::{
|
||||
component::{
|
||||
text::paragraphs::{ParagraphVecShort, Paragraphs},
|
||||
Child, Component, Event, EventCtx, Label, Pad,
|
||||
},
|
||||
constant::screen,
|
||||
display::Icon,
|
||||
geometry::{Alignment, Insets, Point, Rect},
|
||||
model_tt::{
|
||||
bootloader::theme::{button_bld_menu, button_bld_menu_item, BLD_BG, MENU},
|
||||
component::ButtonMsg::Clicked,
|
||||
},
|
||||
};
|
||||
use heapless::String;
|
||||
|
||||
use crate::ui::model_tt::{
|
||||
bootloader::theme::{CONTENT_PADDING, CORNER_BUTTON_AREA, TEXT_TITLE, TITLE_AREA},
|
||||
component::Button,
|
||||
constant::WIDTH,
|
||||
};
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, ToPrimitive)]
|
||||
pub enum IntroMsg {
|
||||
Menu = 1,
|
||||
Host = 2,
|
||||
}
|
||||
|
||||
pub struct Intro<'a> {
|
||||
bg: Pad,
|
||||
title: Child<Label<String<32>>>,
|
||||
menu: Child<Button<&'static str>>,
|
||||
host: Child<Button<&'static str>>,
|
||||
text: Child<Paragraphs<ParagraphVecShort<&'a str>>>,
|
||||
}
|
||||
|
||||
impl<'a> Intro<'a> {
|
||||
pub fn new(bld_version: &'static str, content: Paragraphs<ParagraphVecShort<&'a str>>) -> Self {
|
||||
let mut title: String<32> = String::new();
|
||||
unwrap!(title.push_str("BOOTLOADER "));
|
||||
unwrap!(title.push_str(bld_version));
|
||||
|
||||
let mut instance = Self {
|
||||
bg: Pad::with_background(BLD_BG),
|
||||
title: Child::new(Label::new(title, Alignment::Start, TEXT_TITLE)),
|
||||
menu: Child::new(
|
||||
Button::with_icon(Icon::new(MENU))
|
||||
.styled(button_bld_menu())
|
||||
.with_expanded_touch_area(Insets::uniform(13)),
|
||||
),
|
||||
host: Child::new(Button::with_text("INSTALL FIRMWARE").styled(button_bld_menu_item())),
|
||||
text: Child::new(content),
|
||||
};
|
||||
|
||||
instance.bg.clear();
|
||||
instance
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Component for Intro<'a> {
|
||||
type Msg = IntroMsg;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
const BUTTON_AREA_START: i16 = 188;
|
||||
self.bg.place(screen());
|
||||
self.title.place(TITLE_AREA);
|
||||
self.menu.place(CORNER_BUTTON_AREA);
|
||||
self.host.place(Rect::new(
|
||||
Point::new(10, BUTTON_AREA_START),
|
||||
Point::new(10 + 220, BUTTON_AREA_START + 38),
|
||||
));
|
||||
self.text.place(Rect::new(
|
||||
Point::new(CONTENT_PADDING, 75),
|
||||
Point::new(WIDTH - CONTENT_PADDING, BUTTON_AREA_START),
|
||||
));
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||
if let Some(Clicked) = self.menu.event(ctx, event) {
|
||||
return Some(Self::Msg::Menu);
|
||||
};
|
||||
if let Some(Clicked) = self.host.event(ctx, event) {
|
||||
return Some(Self::Msg::Host);
|
||||
};
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
self.title.paint();
|
||||
self.text.paint();
|
||||
self.host.paint();
|
||||
self.menu.paint();
|
||||
}
|
||||
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
self.menu.bounds(sink);
|
||||
}
|
||||
}
|
@ -0,0 +1,106 @@
|
||||
use crate::ui::{
|
||||
component::{Child, Component, Event, EventCtx, Label, Pad},
|
||||
constant::{screen, WIDTH},
|
||||
display::Icon,
|
||||
geometry::{Alignment, Insets, Point, Rect},
|
||||
model_tt::{
|
||||
bootloader::theme::{
|
||||
button_bld_menu, button_bld_menu_item, BLD_BG, CLOSE, CONTENT_PADDING,
|
||||
CORNER_BUTTON_AREA, ERASE, REBOOT, TEXT_TITLE, TITLE_AREA,
|
||||
},
|
||||
component::{Button, ButtonMsg::Clicked, IconText},
|
||||
},
|
||||
};
|
||||
use heapless::String;
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Copy, Clone, ToPrimitive)]
|
||||
pub enum MenuMsg {
|
||||
Close = 1,
|
||||
Reboot = 2,
|
||||
FactoryReset = 3,
|
||||
}
|
||||
|
||||
pub struct Menu {
|
||||
bg: Pad,
|
||||
title: Child<Label<String<32>>>,
|
||||
close: Child<Button<&'static str>>,
|
||||
reboot: Child<Button<&'static str>>,
|
||||
reset: Child<Button<&'static str>>,
|
||||
}
|
||||
|
||||
impl Menu {
|
||||
pub fn new(bld_version: &'static str) -> Self {
|
||||
let content_reboot = IconText::new("REBOOT TREZOR", Icon::new(REBOOT));
|
||||
let content_reset = IconText::new("FACTORY RESET", Icon::new(ERASE));
|
||||
|
||||
let mut title: String<32> = String::new();
|
||||
unwrap!(title.push_str("BOOTLOADER "));
|
||||
unwrap!(title.push_str(bld_version));
|
||||
|
||||
let mut instance = Self {
|
||||
bg: Pad::with_background(BLD_BG),
|
||||
title: Child::new(Label::new(title, Alignment::Start, TEXT_TITLE)),
|
||||
close: Child::new(
|
||||
Button::with_icon(Icon::new(CLOSE))
|
||||
.styled(button_bld_menu())
|
||||
.with_expanded_touch_area(Insets::uniform(13)),
|
||||
),
|
||||
reboot: Child::new(
|
||||
Button::with_icon_and_text(content_reboot).styled(button_bld_menu_item()),
|
||||
),
|
||||
reset: Child::new(
|
||||
Button::with_icon_and_text(content_reset).styled(button_bld_menu_item()),
|
||||
),
|
||||
};
|
||||
instance.bg.clear();
|
||||
instance
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Menu {
|
||||
type Msg = MenuMsg;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.bg.place(screen());
|
||||
self.title.place(TITLE_AREA);
|
||||
self.close.place(CORNER_BUTTON_AREA);
|
||||
self.reboot.place(Rect::new(
|
||||
Point::new(CONTENT_PADDING, 64),
|
||||
Point::new(WIDTH - CONTENT_PADDING, 64 + 38),
|
||||
));
|
||||
self.reset.place(Rect::new(
|
||||
Point::new(CONTENT_PADDING, 110),
|
||||
Point::new(WIDTH - CONTENT_PADDING, 110 + 38),
|
||||
));
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, event: Event) -> Option<Self::Msg> {
|
||||
if let Some(Clicked) = self.close.event(ctx, event) {
|
||||
return Some(Self::Msg::Close);
|
||||
}
|
||||
if let Some(Clicked) = self.reboot.event(ctx, event) {
|
||||
return Some(Self::Msg::Reboot);
|
||||
}
|
||||
if let Some(Clicked) = self.reset.event(ctx, event) {
|
||||
return Some(Self::Msg::FactoryReset);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
self.title.paint();
|
||||
self.close.paint();
|
||||
self.reboot.paint();
|
||||
self.reset.paint();
|
||||
}
|
||||
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
self.close.bounds(sink);
|
||||
self.reboot.bounds(sink);
|
||||
self.reset.bounds(sink);
|
||||
}
|
||||
}
|
@ -0,0 +1,513 @@
|
||||
use crate::{
|
||||
trezorhal::io::io_touch_read,
|
||||
ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
display::{self, Font},
|
||||
event::TouchEvent,
|
||||
geometry::Point,
|
||||
model_tt::constant,
|
||||
},
|
||||
};
|
||||
use heapless::String;
|
||||
use num_traits::ToPrimitive;
|
||||
|
||||
pub mod confirm;
|
||||
mod connect;
|
||||
pub mod intro;
|
||||
pub mod menu;
|
||||
pub mod theme;
|
||||
|
||||
use crate::{
|
||||
strutil::hexlify,
|
||||
ui::{
|
||||
component::text::paragraphs::{Paragraph, ParagraphVecShort, Paragraphs, VecExt},
|
||||
constant::screen,
|
||||
display::{Color, Icon},
|
||||
geometry::{LinearPlacement, CENTER},
|
||||
model_tt::{
|
||||
bootloader::{
|
||||
connect::Connect,
|
||||
theme::{
|
||||
button_install_cancel, button_install_confirm, button_wipe_cancel,
|
||||
button_wipe_confirm, BLD_BG, BLD_FG, BLD_WIPE_COLOR, ERASE_BIG, LOGO_EMPTY,
|
||||
RECEIVE, TEXT_WIPE_BOLD, WELCOME_COLOR,
|
||||
},
|
||||
},
|
||||
component::{Button, ResultScreen},
|
||||
theme::{
|
||||
BACKLIGHT_DIM, BACKLIGHT_NORMAL, BG, BLACK, FG, GREY_DARK, ICON_SUCCESS_SMALL,
|
||||
ICON_WARN_SMALL, TEXT_ERROR_BOLD, TEXT_ERROR_NORMAL, WHITE,
|
||||
},
|
||||
},
|
||||
util::{from_c_array, from_c_str},
|
||||
},
|
||||
};
|
||||
use confirm::Confirm;
|
||||
use intro::Intro;
|
||||
use menu::Menu;
|
||||
|
||||
pub trait ReturnToC {
|
||||
fn return_to_c(self) -> u32;
|
||||
}
|
||||
|
||||
impl ReturnToC for Never {
|
||||
fn return_to_c(self) -> u32 {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ReturnToC for T
|
||||
where
|
||||
T: ToPrimitive,
|
||||
{
|
||||
fn return_to_c(self) -> u32 {
|
||||
self.to_u32().unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
fn fadein() {
|
||||
display::fade_backlight_duration(BACKLIGHT_NORMAL, 500);
|
||||
}
|
||||
|
||||
fn fadeout() {
|
||||
display::fade_backlight_duration(BACKLIGHT_DIM, 500);
|
||||
}
|
||||
|
||||
fn run<F>(frame: &mut F) -> u32
|
||||
where
|
||||
F: Component,
|
||||
F::Msg: ReturnToC,
|
||||
{
|
||||
frame.place(constant::screen());
|
||||
fadeout();
|
||||
display::sync();
|
||||
frame.paint();
|
||||
fadein();
|
||||
|
||||
loop {
|
||||
let event = touch_eval();
|
||||
if let Some(e) = event {
|
||||
let mut ctx = EventCtx::new();
|
||||
let msg = frame.event(&mut ctx, Event::Touch(e));
|
||||
|
||||
if let Some(message) = msg {
|
||||
return message.return_to_c();
|
||||
}
|
||||
display::sync();
|
||||
frame.paint();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn show<F>(frame: &mut F, fading: bool)
|
||||
where
|
||||
F: Component,
|
||||
{
|
||||
frame.place(screen());
|
||||
if fading {
|
||||
fadeout()
|
||||
};
|
||||
display::sync();
|
||||
frame.paint();
|
||||
if fading {
|
||||
fadein()
|
||||
};
|
||||
}
|
||||
|
||||
fn touch_eval() -> Option<TouchEvent> {
|
||||
let event = io_touch_read();
|
||||
if event == 0 {
|
||||
return None;
|
||||
}
|
||||
let event_type = event >> 24;
|
||||
let ex = ((event >> 12) & 0xFFF) as i16;
|
||||
let ey = (event & 0xFFF) as i16;
|
||||
|
||||
TouchEvent::new(event_type, ex as _, ey as _).ok()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_install_confirm(
|
||||
vendor_str: *const cty::c_char,
|
||||
vendor_str_len: u8,
|
||||
version: *const cty::c_char,
|
||||
fingerprint: *const cty::uint8_t,
|
||||
downgrade: bool,
|
||||
vendor: bool,
|
||||
) -> u32 {
|
||||
let text = unwrap!(unsafe { from_c_array(vendor_str, vendor_str_len as usize) });
|
||||
let version = unwrap!(unsafe { from_c_str(version) });
|
||||
|
||||
let mut fingerprint_buffer: [u8; 64] = [0; 64];
|
||||
let fingerprint_str = unsafe {
|
||||
let fingerprint_slice = core::slice::from_raw_parts(fingerprint as *const u8, 32);
|
||||
hexlify(fingerprint_slice, &mut fingerprint_buffer);
|
||||
core::str::from_utf8_unchecked(fingerprint_buffer.as_ref())
|
||||
};
|
||||
|
||||
let mut version_str: String<64> = String::new();
|
||||
unwrap!(version_str.push_str("Firmware version "));
|
||||
unwrap!(version_str.push_str(version));
|
||||
|
||||
let mut vendor_str: String<64> = String::new();
|
||||
unwrap!(vendor_str.push_str("by "));
|
||||
unwrap!(vendor_str.push_str(text));
|
||||
|
||||
let title = if downgrade {
|
||||
"DOWNGRADE FW"
|
||||
} else if vendor {
|
||||
"CHANGE FW VENDOR"
|
||||
} else {
|
||||
"UPDATE FIRMWARE"
|
||||
};
|
||||
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages.add(Paragraph::new(&theme::TEXT_NORMAL, version_str.as_ref()));
|
||||
messages.add(Paragraph::new(&theme::TEXT_NORMAL, vendor_str.as_ref()));
|
||||
|
||||
if vendor || downgrade {
|
||||
messages
|
||||
.add(Paragraph::new(&theme::TEXT_BOLD, "Seed will be erased!").with_top_padding(16));
|
||||
}
|
||||
|
||||
let message =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
messages.add(Paragraph::new(&theme::TEXT_FINGERPRINT, fingerprint_str));
|
||||
|
||||
let fingerprint =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let left = Button::with_text("CANCEL").styled(button_install_cancel());
|
||||
let right = Button::with_text("INSTALL").styled(button_install_confirm());
|
||||
|
||||
let mut frame = Confirm::new(
|
||||
BLD_BG,
|
||||
None,
|
||||
left,
|
||||
right,
|
||||
false,
|
||||
(Some(title), message),
|
||||
Some(("FW FINGERPRINT", fingerprint)),
|
||||
);
|
||||
|
||||
run(&mut frame)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_wipe_confirm() -> u32 {
|
||||
let icon = Some(Icon::new(ERASE_BIG));
|
||||
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages.add(
|
||||
Paragraph::new(
|
||||
&TEXT_ERROR_NORMAL,
|
||||
"Are you sure you want to factory reset the device?",
|
||||
)
|
||||
.centered(),
|
||||
);
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "Seed and firmware\nwill be erased!").centered());
|
||||
|
||||
let message =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let left = Button::with_text("RESET").styled(button_wipe_confirm());
|
||||
let right = Button::with_text("CANCEL").styled(button_wipe_cancel());
|
||||
|
||||
let mut frame = Confirm::new(
|
||||
BLD_WIPE_COLOR,
|
||||
icon,
|
||||
left,
|
||||
right,
|
||||
true,
|
||||
(None, message),
|
||||
None,
|
||||
);
|
||||
|
||||
run(&mut frame)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_menu(bld_version: *const cty::c_char) -> u32 {
|
||||
let bld_version = unwrap!(unsafe { from_c_str(bld_version) });
|
||||
|
||||
run(&mut Menu::new(bld_version))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_intro(
|
||||
bld_version: *const cty::c_char,
|
||||
vendor_str: *const cty::c_char,
|
||||
vendor_str_len: u8,
|
||||
version: *const cty::c_char,
|
||||
) -> u32 {
|
||||
let vendor = unwrap!(unsafe { from_c_array(vendor_str, vendor_str_len as usize) });
|
||||
let version = unwrap!(unsafe { from_c_str(version) });
|
||||
let bld_version = unwrap!(unsafe { from_c_str(bld_version) });
|
||||
|
||||
let mut fw: String<64> = String::new();
|
||||
unwrap!(fw.push_str("Firmware "));
|
||||
unwrap!(fw.push_str(version));
|
||||
|
||||
let mut vendor_: String<64> = String::new();
|
||||
unwrap!(vendor_.push_str("by "));
|
||||
unwrap!(vendor_.push_str(vendor));
|
||||
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages.add(Paragraph::new(&theme::TEXT_NORMAL, fw.as_ref()));
|
||||
messages.add(Paragraph::new(&theme::TEXT_NORMAL, vendor_.as_ref()));
|
||||
|
||||
let p = Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_start());
|
||||
|
||||
let mut frame = Intro::new(bld_version, p);
|
||||
|
||||
run(&mut frame)
|
||||
}
|
||||
|
||||
fn screen_progress(
|
||||
text: &str,
|
||||
progress: u16,
|
||||
initialize: bool,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: Option<(Icon, Color)>,
|
||||
) {
|
||||
if initialize {
|
||||
fadeout();
|
||||
display::rect_fill(constant::screen(), bg_color);
|
||||
}
|
||||
|
||||
display::text_center(
|
||||
Point::new(constant::WIDTH / 2, 214),
|
||||
text,
|
||||
Font::NORMAL,
|
||||
fg_color,
|
||||
bg_color,
|
||||
);
|
||||
display::loader(progress, -20, fg_color, bg_color, icon);
|
||||
if initialize {
|
||||
fadein();
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_install_progress(progress: u16, initialize: bool, initial_setup: bool) {
|
||||
let bg_color = if initial_setup { WELCOME_COLOR } else { BG };
|
||||
let fg_color = if initial_setup { FG } else { BLD_FG };
|
||||
|
||||
screen_progress(
|
||||
"Installing firmware...",
|
||||
progress,
|
||||
initialize,
|
||||
fg_color,
|
||||
bg_color,
|
||||
Some((Icon::new(RECEIVE), fg_color)),
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_wipe_progress(progress: u16, initialize: bool) {
|
||||
screen_progress(
|
||||
"Resetting Trezor...",
|
||||
progress,
|
||||
initialize,
|
||||
theme::BLD_FG,
|
||||
BLD_WIPE_COLOR,
|
||||
Some((Icon::new(ERASE_BIG), theme::BLD_FG)),
|
||||
)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_connect() {
|
||||
let mut frame = Connect::new("Waiting for host...");
|
||||
show(&mut frame, true);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_wipe_success() {
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "Trezor reset").centered());
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "successfully.").centered());
|
||||
|
||||
let m_top =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
messages.add(Paragraph::new(&TEXT_WIPE_BOLD, "PLEASE RECONNECT").centered());
|
||||
messages.add(Paragraph::new(&TEXT_WIPE_BOLD, "THE DEVICE").centered());
|
||||
|
||||
let m_bottom =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(
|
||||
WHITE,
|
||||
BLD_WIPE_COLOR,
|
||||
Icon::new(ICON_SUCCESS_SMALL),
|
||||
m_top,
|
||||
m_bottom,
|
||||
true,
|
||||
);
|
||||
show(&mut frame, true);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_wipe_fail() {
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "Trezor reset was").centered());
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "not successful.").centered());
|
||||
let m_top =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages.add(Paragraph::new(&TEXT_WIPE_BOLD, "PLEASE RECONNECT").centered());
|
||||
messages.add(Paragraph::new(&TEXT_WIPE_BOLD, "THE DEVICE").centered());
|
||||
let m_bottom =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(
|
||||
WHITE,
|
||||
BLD_WIPE_COLOR,
|
||||
Icon::new(ICON_WARN_SMALL),
|
||||
m_top,
|
||||
m_bottom,
|
||||
true,
|
||||
);
|
||||
show(&mut frame, true);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_boot_empty(firmware_present: bool, fading: bool) {
|
||||
if fading {
|
||||
fadeout();
|
||||
}
|
||||
|
||||
let fg = if firmware_present { GREY_DARK } else { WHITE };
|
||||
let bg = if firmware_present {
|
||||
BLACK
|
||||
} else {
|
||||
WELCOME_COLOR
|
||||
};
|
||||
display::rect_fill(constant::screen(), bg);
|
||||
let icon = Icon::new(LOGO_EMPTY);
|
||||
icon.draw(screen().center(), CENTER, fg, bg);
|
||||
|
||||
if fading {
|
||||
fadein();
|
||||
} else {
|
||||
display::set_backlight(BACKLIGHT_NORMAL);
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_install_fail() {
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
messages.add(Paragraph::new(&theme::TEXT_BOLD, "Firmware installation was").centered());
|
||||
messages.add(Paragraph::new(&theme::TEXT_BOLD, "not successful.").centered());
|
||||
|
||||
let m_top =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
messages.add(Paragraph::new(&theme::TEXT_SUBMSG, "PLEASE RECONNECT").centered());
|
||||
messages.add(Paragraph::new(&theme::TEXT_SUBMSG, "THE DEVICE").centered());
|
||||
let m_bottom =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(
|
||||
WHITE,
|
||||
BLD_BG,
|
||||
Icon::new(ICON_WARN_SMALL),
|
||||
m_top,
|
||||
m_bottom,
|
||||
true,
|
||||
);
|
||||
show(&mut frame, true);
|
||||
}
|
||||
|
||||
fn screen_install_success_bld(msg: &'static str, complete_draw: bool) {
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
messages.add(Paragraph::new(&theme::TEXT_BOLD, "Firmware installed").centered());
|
||||
messages.add(Paragraph::new(&theme::TEXT_BOLD, "successfully.").centered());
|
||||
let m_top =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
messages.add(Paragraph::new(&theme::TEXT_SUBMSG, msg).centered());
|
||||
let m_bottom =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(
|
||||
WHITE,
|
||||
BLD_BG,
|
||||
Icon::new(ICON_SUCCESS_SMALL),
|
||||
m_top,
|
||||
m_bottom,
|
||||
complete_draw,
|
||||
);
|
||||
show(&mut frame, complete_draw);
|
||||
}
|
||||
|
||||
fn screen_install_success_initial(msg: &'static str, complete_draw: bool) {
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
messages.add(Paragraph::new(&theme::TEXT_WELCOME_BOLD, "Firmware installed").centered());
|
||||
messages.add(Paragraph::new(&theme::TEXT_WELCOME_BOLD, "successfully.").centered());
|
||||
|
||||
let m_top =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
messages.add(Paragraph::new(&theme::TEXT_SUBMSG_INITIAL, msg).centered());
|
||||
|
||||
let m_bottom =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(
|
||||
FG,
|
||||
WELCOME_COLOR,
|
||||
Icon::new(ICON_SUCCESS_SMALL),
|
||||
m_top,
|
||||
m_bottom,
|
||||
complete_draw,
|
||||
);
|
||||
show(&mut frame, complete_draw);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_install_success(
|
||||
reboot_msg: *const cty::c_char,
|
||||
initial_setup: bool,
|
||||
complete_draw: bool,
|
||||
) {
|
||||
let msg = unwrap!(unsafe { from_c_str(reboot_msg) });
|
||||
if initial_setup {
|
||||
screen_install_success_initial(msg, complete_draw)
|
||||
} else {
|
||||
screen_install_success_bld(msg, complete_draw)
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_welcome() {
|
||||
fadeout();
|
||||
display::rect_fill(screen(), WELCOME_COLOR);
|
||||
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
messages.add(Paragraph::new(&theme::TEXT_WELCOME, "Get started with").centered());
|
||||
messages.add(Paragraph::new(&theme::TEXT_WELCOME, "your trezor at").centered());
|
||||
messages.add(
|
||||
Paragraph::new(&theme::TEXT_WELCOME_BOLD, "trezor.io/start")
|
||||
.centered()
|
||||
.with_top_padding(2),
|
||||
);
|
||||
let mut frame =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
show(&mut frame, false);
|
||||
fadein();
|
||||
}
|
@ -0,0 +1,304 @@
|
||||
use crate::{
|
||||
alpha,
|
||||
ui::{
|
||||
component::{text::TextStyle, LineBreaking::BreakWordsNoHyphen},
|
||||
constant::WIDTH,
|
||||
display::{Color, Font},
|
||||
geometry::{Offset, Point, Rect},
|
||||
model_tt::{
|
||||
component::{ButtonStyle, ButtonStyleSheet},
|
||||
theme::{BLACK, FG, GREY_DARK, GREY_LIGHT, GREY_MEDIUM, WHITE},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
pub const BLD_BG: Color = Color::rgb(0x00, 0x17, 0xA3);
|
||||
pub const BLD_FG: Color = WHITE;
|
||||
pub const BLD_WIPE_COLOR: Color = Color::rgb(0xAD, 0x2B, 0x2B);
|
||||
pub const BLD_WIPE_TEXT_COLOR: Color = Color::rgb(0xD6, 0x95, 0x95);
|
||||
|
||||
pub const BLD_WIPE_BTN_COLOR: Color = Color::alpha(BLD_WIPE_COLOR, alpha!(0.3));
|
||||
pub const BLD_WIPE_BTN_COLOR_ACTIVE: Color = Color::rgb(0xB9, 0x4B, 0x4B);
|
||||
pub const BLD_WIPE_CANCEL_BTN_COLOR_ACTIVE: Color = Color::rgb(0xF3, 0xDF, 0xDF);
|
||||
|
||||
pub const BLD_INSTALL_BTN_COLOR: Color = Color::alpha(BLD_BG, alpha!(0.3));
|
||||
pub const BLD_INSTALL_BTN_COLOR_ACTIVE: Color = Color::rgb(0xD9, 0xDC, 0xF1);
|
||||
pub const BLD_INSTALL_CANCEL_BTN_COLOR_ACTIVE: Color = Color::rgb(0x26, 0x3A, 0xB1);
|
||||
|
||||
pub const BLD_COLOR_SUBMSG: Color = Color::rgb(0x80, 0x8B, 0xD1);
|
||||
|
||||
pub const BLD_BTN_MENU_COLOR: Color = Color::alpha(BLD_BG, alpha!(0.22));
|
||||
pub const BLD_BTN_MENU_COLOR_ACTIVE: Color = Color::alpha(BLD_BG, alpha!(0.11));
|
||||
pub const BLD_BTN_MENUITEM_COLOR: Color = Color::alpha(BLD_BG, alpha!(0.33));
|
||||
pub const BLD_BTN_MENUITEM_COLOR_ACTIVE: Color =
|
||||
Color::rgba(BLD_BG, 0xFF, 0xFF, 0xFF, alpha!(0.11));
|
||||
pub const BLD_TITLE_COLOR: Color = Color::rgba(BLD_BG, 0xFF, 0xFF, 0xFF, alpha!(0.75));
|
||||
|
||||
pub const WELCOME_COLOR: Color = BLACK;
|
||||
|
||||
// Commonly used corner radius (i.e. for buttons).
|
||||
pub const RADIUS: u8 = 2;
|
||||
|
||||
// Commonly used constants for UI elements.
|
||||
pub const CONTENT_PADDING: i16 = 10;
|
||||
pub const TITLE_AREA: Rect = Rect::new(Point::new(15, 14), Point::new(200, 30));
|
||||
pub const CORNER_BUTTON_SIZE: i16 = 32;
|
||||
pub const CORNER_BUTTON_PADDING: i16 = 8;
|
||||
pub const CORNER_BUTTON_AREA: Rect = Rect::from_top_left_and_size(
|
||||
Point::new(
|
||||
WIDTH - CORNER_BUTTON_SIZE - CORNER_BUTTON_PADDING,
|
||||
CORNER_BUTTON_PADDING,
|
||||
),
|
||||
Offset::uniform(CORNER_BUTTON_SIZE),
|
||||
);
|
||||
pub const TITLE_AREA_HEIGHT: i16 = 16;
|
||||
pub const TITLE_AREA_START_Y: i16 = 8;
|
||||
pub const BUTTON_AREA_START: i16 = 188;
|
||||
|
||||
// UI icons.
|
||||
pub const ICON_CANCEL: &[u8] = include_res!("model_tt/res/cancel.toif");
|
||||
pub const ICON_CONFIRM: &[u8] = include_res!("model_tt/res/confirm.toif");
|
||||
|
||||
// BLD icons
|
||||
pub const CLOSE: &[u8] = include_res!("model_tt/res/close.toif");
|
||||
pub const ERASE: &[u8] = include_res!("model_tt/res/erase.toif");
|
||||
pub const ERASE_BIG: &[u8] = include_res!("model_tt/res/erase_big.toif");
|
||||
pub const REBOOT: &[u8] = include_res!("model_tt/res/reboot.toif");
|
||||
pub const MENU: &[u8] = include_res!("model_tt/res/menu.toif");
|
||||
pub const RECEIVE: &[u8] = include_res!("model_tt/res/receive.toif");
|
||||
pub const LOGO_EMPTY: &[u8] = include_res!("model_tt/res/trezor_empty.toif");
|
||||
pub const INFO_SMALL: &[u8] = include_res!("model_tt/res/info_small.toif");
|
||||
|
||||
pub fn button_install_cancel() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet {
|
||||
normal: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: WHITE,
|
||||
button_color: BLD_BTN_MENUITEM_COLOR,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
active: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: WHITE,
|
||||
button_color: BLD_INSTALL_CANCEL_BTN_COLOR_ACTIVE,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
disabled: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: GREY_LIGHT,
|
||||
button_color: GREY_DARK,
|
||||
background_color: WHITE,
|
||||
border_color: WHITE,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn button_install_confirm() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet {
|
||||
normal: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: BLD_BG,
|
||||
button_color: WHITE,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
active: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: BLD_BG,
|
||||
button_color: BLD_INSTALL_BTN_COLOR_ACTIVE,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
disabled: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: FG,
|
||||
button_color: GREY_DARK,
|
||||
background_color: FG,
|
||||
border_color: FG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn button_wipe_cancel() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet {
|
||||
normal: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: BLD_WIPE_COLOR,
|
||||
button_color: WHITE,
|
||||
background_color: BLD_WIPE_COLOR,
|
||||
border_color: BLD_WIPE_COLOR,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
active: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: BLD_WIPE_COLOR,
|
||||
button_color: BLD_WIPE_CANCEL_BTN_COLOR_ACTIVE,
|
||||
background_color: BLD_WIPE_COLOR,
|
||||
border_color: BLD_WIPE_COLOR,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
disabled: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: GREY_LIGHT,
|
||||
button_color: GREY_DARK,
|
||||
background_color: WHITE,
|
||||
border_color: WHITE,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn button_wipe_confirm() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet {
|
||||
normal: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: WHITE,
|
||||
button_color: BLD_WIPE_BTN_COLOR,
|
||||
background_color: BLD_WIPE_COLOR,
|
||||
border_color: BLD_WIPE_COLOR,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
active: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: WHITE,
|
||||
button_color: BLD_WIPE_BTN_COLOR_ACTIVE,
|
||||
background_color: BLD_WIPE_COLOR,
|
||||
border_color: BLD_WIPE_COLOR,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
disabled: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: FG,
|
||||
button_color: GREY_DARK,
|
||||
background_color: FG,
|
||||
border_color: FG,
|
||||
border_radius: RADIUS,
|
||||
border_width: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn button_bld_menu() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet {
|
||||
normal: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: BLD_FG,
|
||||
button_color: BLD_BTN_MENU_COLOR,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: 4,
|
||||
border_width: 0,
|
||||
},
|
||||
active: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: BLD_FG,
|
||||
button_color: BLD_BTN_MENU_COLOR_ACTIVE,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: 4,
|
||||
border_width: 0,
|
||||
},
|
||||
disabled: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: GREY_LIGHT,
|
||||
button_color: BLD_BTN_MENU_COLOR,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: 4,
|
||||
border_width: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn button_bld_menu_item() -> ButtonStyleSheet {
|
||||
ButtonStyleSheet {
|
||||
normal: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: BLD_FG,
|
||||
button_color: BLD_BTN_MENUITEM_COLOR,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: 4,
|
||||
border_width: 0,
|
||||
},
|
||||
active: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: BLD_FG,
|
||||
button_color: BLD_BTN_MENUITEM_COLOR_ACTIVE,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: 4,
|
||||
border_width: 0,
|
||||
},
|
||||
disabled: &ButtonStyle {
|
||||
font: Font::BOLD,
|
||||
text_color: GREY_LIGHT,
|
||||
button_color: BLD_BTN_MENUITEM_COLOR,
|
||||
background_color: BLD_BG,
|
||||
border_color: BLD_BG,
|
||||
border_radius: 4,
|
||||
border_width: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
pub const TEXT_WELCOME: TextStyle = TextStyle::new(
|
||||
Font::NORMAL,
|
||||
GREY_MEDIUM,
|
||||
WELCOME_COLOR,
|
||||
GREY_MEDIUM,
|
||||
GREY_MEDIUM,
|
||||
);
|
||||
pub const TEXT_WELCOME_BOLD: TextStyle = TextStyle::new(Font::BOLD, FG, WELCOME_COLOR, FG, FG);
|
||||
pub const TEXT_TITLE: TextStyle = TextStyle::new(
|
||||
Font::BOLD,
|
||||
BLD_TITLE_COLOR,
|
||||
BLD_BG,
|
||||
BLD_TITLE_COLOR,
|
||||
BLD_TITLE_COLOR,
|
||||
);
|
||||
pub const TEXT_SUBMSG_INITIAL: TextStyle = TextStyle::new(
|
||||
Font::BOLD,
|
||||
GREY_MEDIUM,
|
||||
WELCOME_COLOR,
|
||||
GREY_MEDIUM,
|
||||
GREY_MEDIUM,
|
||||
);
|
||||
|
||||
pub const TEXT_NORMAL: TextStyle = TextStyle::new(Font::NORMAL, BLD_FG, BLD_BG, BLD_FG, BLD_FG);
|
||||
pub const TEXT_FINGERPRINT: TextStyle =
|
||||
TextStyle::new(Font::NORMAL, BLD_FG, BLD_BG, BLD_FG, BLD_FG)
|
||||
.with_line_breaking(BreakWordsNoHyphen);
|
||||
pub const TEXT_BOLD: TextStyle = TextStyle::new(Font::BOLD, BLD_FG, BLD_BG, BLD_FG, BLD_FG);
|
||||
pub const TEXT_WIPE_BOLD: TextStyle = TextStyle::new(
|
||||
Font::BOLD,
|
||||
BLD_WIPE_TEXT_COLOR,
|
||||
BLD_WIPE_COLOR,
|
||||
BLD_WIPE_TEXT_COLOR,
|
||||
BLD_WIPE_TEXT_COLOR,
|
||||
);
|
||||
pub const TEXT_SUBMSG: TextStyle = TextStyle::new(
|
||||
Font::BOLD,
|
||||
BLD_COLOR_SUBMSG,
|
||||
BLD_BG,
|
||||
BLD_COLOR_SUBMSG,
|
||||
BLD_COLOR_SUBMSG,
|
||||
);
|
@ -0,0 +1,93 @@
|
||||
use crate::{
|
||||
alpha,
|
||||
ui::{
|
||||
component::{
|
||||
text::paragraphs::{ParagraphStrType, ParagraphVecShort, Paragraphs},
|
||||
Child, Component, Event, EventCtx, Never, Pad,
|
||||
},
|
||||
constant::screen,
|
||||
display::{self, Color, Icon},
|
||||
geometry::{Offset, Point, Rect, CENTER},
|
||||
},
|
||||
};
|
||||
|
||||
use crate::ui::model_tt::constant::{HEIGHT, WIDTH};
|
||||
|
||||
pub struct ResultScreen<T> {
|
||||
bg: Pad,
|
||||
small_pad: Pad,
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: Icon,
|
||||
message_top: Child<Paragraphs<ParagraphVecShort<T>>>,
|
||||
message_bottom: Child<Paragraphs<ParagraphVecShort<T>>>,
|
||||
}
|
||||
|
||||
impl<T: ParagraphStrType> ResultScreen<T> {
|
||||
pub fn new(
|
||||
fg_color: Color,
|
||||
bg_color: Color,
|
||||
icon: Icon,
|
||||
message_top: Paragraphs<ParagraphVecShort<T>>,
|
||||
message_bottom: Paragraphs<ParagraphVecShort<T>>,
|
||||
complete_draw: bool,
|
||||
) -> Self {
|
||||
let mut instance = Self {
|
||||
bg: Pad::with_background(bg_color),
|
||||
small_pad: Pad::with_background(bg_color),
|
||||
fg_color,
|
||||
bg_color,
|
||||
icon,
|
||||
message_top: Child::new(message_top),
|
||||
message_bottom: Child::new(message_bottom),
|
||||
};
|
||||
|
||||
if complete_draw {
|
||||
instance.bg.clear();
|
||||
} else {
|
||||
instance.small_pad.clear();
|
||||
}
|
||||
instance
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ParagraphStrType> Component for ResultScreen<T> {
|
||||
type Msg = Never;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.bg
|
||||
.place(Rect::new(Point::new(0, 0), Point::new(WIDTH, HEIGHT)));
|
||||
|
||||
self.message_top
|
||||
.place(Rect::new(Point::new(15, 59), Point::new(WIDTH - 15, 149)));
|
||||
|
||||
let bottom_area = Rect::new(Point::new(15, 151), Point::new(WIDTH - 15, HEIGHT));
|
||||
|
||||
self.small_pad.place(bottom_area);
|
||||
self.message_bottom.place(bottom_area);
|
||||
|
||||
bounds
|
||||
}
|
||||
|
||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
self.bg.paint();
|
||||
self.small_pad.paint();
|
||||
|
||||
self.icon.draw(
|
||||
Point::new(screen().center().x, 45),
|
||||
CENTER,
|
||||
self.fg_color,
|
||||
self.bg_color,
|
||||
);
|
||||
display::rect_fill(
|
||||
Rect::from_top_left_and_size(Point::new(12, 149), Offset::new(216, 1)),
|
||||
Color::alpha(self.bg_color, alpha!(0.2)),
|
||||
);
|
||||
self.message_top.paint();
|
||||
self.message_bottom.paint();
|
||||
}
|
||||
}
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,104 @@
|
||||
#[cfg(feature = "micropython")]
|
||||
use crate::micropython::buffer::StrBuffer;
|
||||
use crate::ui::{
|
||||
component::{
|
||||
text::paragraphs::{Paragraph, ParagraphVecShort, Paragraphs, VecExt},
|
||||
Component,
|
||||
},
|
||||
display::Icon,
|
||||
geometry::LinearPlacement,
|
||||
model_tt::{
|
||||
component::ResultScreen,
|
||||
constant,
|
||||
theme::{FATAL_ERROR_COLOR, ICON_WARN_SMALL, TEXT_ERROR_BOLD, TEXT_ERROR_NORMAL, WHITE},
|
||||
},
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "micropython"))]
|
||||
// SAFETY: Actually safe but see below
|
||||
unsafe fn get_str(text: &str) -> &str {
|
||||
text
|
||||
}
|
||||
#[cfg(feature = "micropython")]
|
||||
// SAFETY: The caller is responsible for ensuring that the StrBuffer does not
|
||||
// escape the lifetime of the original &str.
|
||||
unsafe fn get_str(text: &str) -> StrBuffer {
|
||||
unsafe { StrBuffer::from_ptr_and_len(text.as_ptr(), text.len()) }
|
||||
}
|
||||
|
||||
pub fn screen_fatal_error(msg: Option<&str>, file: &str) {
|
||||
// SAFETY: these will get placed into `frame` which does not outlive this
|
||||
// function
|
||||
let msg = msg.map(|s| unsafe { get_str(s) });
|
||||
let file = unsafe { get_str(file) };
|
||||
|
||||
let m_top = if let Some(msg) = msg {
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "FATAL ERROR!".into()).centered());
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_NORMAL, msg).centered());
|
||||
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center())
|
||||
} else {
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "FATAL ERROR!".into()).centered());
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_NORMAL, file).centered());
|
||||
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center())
|
||||
};
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages
|
||||
.add(Paragraph::new(&TEXT_ERROR_BOLD, "PLEASE CONTACT\nTREZOR SUPPORT".into()).centered());
|
||||
let m_bottom =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(
|
||||
WHITE,
|
||||
FATAL_ERROR_COLOR,
|
||||
Icon::new(ICON_WARN_SMALL),
|
||||
m_top,
|
||||
m_bottom,
|
||||
true,
|
||||
);
|
||||
frame.place(constant::screen());
|
||||
frame.paint();
|
||||
}
|
||||
|
||||
pub fn screen_error_shutdown(label: &str, msg: Option<&str>) {
|
||||
// SAFETY: these will get placed into `frame` which does not outlive this
|
||||
// function
|
||||
let msg = msg.map(|s| unsafe { get_str(s) });
|
||||
let label = unsafe { get_str(label) };
|
||||
|
||||
let m_top = if let Some(msg) = msg {
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, label).centered());
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_NORMAL, msg).centered());
|
||||
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center())
|
||||
} else {
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, label).centered());
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center())
|
||||
};
|
||||
let mut messages = ParagraphVecShort::new();
|
||||
|
||||
messages.add(Paragraph::new(&TEXT_ERROR_BOLD, "PLEASE UNPLUG\nTHE DEVICE".into()).centered());
|
||||
let m_bottom =
|
||||
Paragraphs::new(messages).with_placement(LinearPlacement::vertical().align_at_center());
|
||||
|
||||
let mut frame = ResultScreen::new(
|
||||
WHITE,
|
||||
FATAL_ERROR_COLOR,
|
||||
Icon::new(ICON_WARN_SMALL),
|
||||
m_top,
|
||||
m_bottom,
|
||||
true,
|
||||
);
|
||||
frame.place(constant::screen());
|
||||
frame.paint();
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
//! Reexporting the `screens` module according to the
|
||||
//! current feature (Trezor model)
|
||||
|
||||
#[cfg(all(feature = "model_tr", not(feature = "model_tt")))]
|
||||
pub use super::model_tr::screens::*;
|
||||
#[cfg(feature = "model_tt")]
|
||||
pub use super::model_tt::screens::*;
|
||||
use crate::ui::util::from_c_str;
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_fatal_error_c(msg: *const cty::c_char, file: *const cty::c_char) {
|
||||
let msg = if msg.is_null() {
|
||||
None
|
||||
} else {
|
||||
unsafe { from_c_str(msg) }
|
||||
};
|
||||
let file = if file.is_null() {
|
||||
""
|
||||
} else {
|
||||
unwrap!(unsafe { from_c_str(file) })
|
||||
};
|
||||
|
||||
screen_fatal_error(msg, file);
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
extern "C" fn screen_error_shutdown_c(msg: *const cty::c_char, file: *const cty::c_char) {
|
||||
let msg = if msg.is_null() {
|
||||
None
|
||||
} else {
|
||||
unsafe { from_c_str(msg) }
|
||||
};
|
||||
let file = if file.is_null() {
|
||||
""
|
||||
} else {
|
||||
unwrap!(unsafe { from_c_str(file) })
|
||||
};
|
||||
|
||||
screen_fatal_error(msg, file);
|
||||
}
|
Loading…
Reference in new issue