I'm making a lock screen display on a TFT LCD with the Adafruit ST7735 library, but what I don't understand yet is how to make the text not have a background so it can follow the background on the screen and the text can still change as in the example in the image below?
in my code
uint16_t alphaBlend(uint16_t fg, uint16_t bg, uint8_t alpha) {
// Ekstrak komponen RGB
uint8_t fgR = (fg >> 11) & 0x1F;
uint8_t fgG = (fg >> 5) & 0x3F;
uint8_t fgB = fg & 0x1F;
uint8_t bgR = (bg >> 11) & 0x1F;
uint8_t bgG = (bg >> 5) & 0x3F;
uint8_t bgB = bg & 0x1F;
// Gunakan uint16_t untuk perhitungan sementara untuk menghindari overflow
uint16_t r = (fgR * alpha + bgR * (255 - alpha)) >> 8;
uint16_t g = (fgG * alpha + bgG * (255 - alpha)) >> 8;
uint16_t b = (fgB * alpha + bgB * (255 - alpha)) >> 8;
// Pastikan nilai tidak melebihi batas maksimum bit-field
r = (r > 0x1F) ? 0x1F : r;
g = (g > 0x3F) ? 0x3F : g;
b = (b > 0x1F) ? 0x1F : b;
// Kembalikan nilai RGB565
return (r << 11) | (g << 5) | b;
}
// Fungsi untuk menggambar persegi panjang dengan alpha blending
void fillRectAlpha(Adafruit_ST7735 &tft, int16_t x, int16_t y, int16_t w, int16_t h,
uint16_t color, uint8_t alpha) {
// Jika alpha = 255 (tidak transparan), gunakan fillRect biasa
if (alpha == 255) {
tft.fillRect(x, y, w, h, color);
return;
}
// Jika alpha = 0 (transparan penuh), tidak perlu melakukan apa-apa
if (alpha == 0) {
return;
}
// Buffer untuk menyimpan background
uint16_t *buffer = new uint16_t[w * h];
// Bagian ini memerlukan kemampuan readRect
// Jika kontroler TFT Anda mendukungnya:
// tft.readRect(x, y, w, h, buffer);
// Jika readRect tidak tersedia, kita perlu menyimpan background secara manual
// Ini lebih kompleks dan memerlukan penyimpanan state
// Alternatif: Untuk implementasi sederhana, kita bisa menggunakan warna background yang diketahui
for (int i = 0; i < w * h; i++) {
buffer[i] = backgroundColor;
}
// Lakukan alpha blending untuk setiap pixel
for (int j = 0; j < h; j++) {
for (int i = 0; i < w; i++) {
uint16_t blendedColor = alphaBlend(color, buffer[j * w + i], alpha);
tft.drawPixel(x + i, y + j, blendedColor);
}
}
// Hapus buffer
delete[] buffer;
}
// If you need to clear a specific area, use this
void clearTextArea(int x, int y, const String& text, uint16_t clearColor) { // Tambahkan parameter clearColor
int16_t x1, y1;
uint16_t w, h;
tft.getTextBounds(text, x, y, &x1, &y1, &w, &h);
tft.fillRect(x1, y1, w, h, clearColor); // Gunakan clearColor untuk mengisi area
}
void updateTimeAndDate() {
// Update waktu
String hourStr = (hour() < 10 ? "0" : "") + String(hour());
String minStr = (minute() < 10 ? "0" : "") + String(minute());
// Simpan data jam dan menit
String newTimeStr = hourStr + ":" + minStr;
timeStr = newTimeStr;
// Dapatkan hari dalam minggu (0-6, Minggu-Sabtu)
int dayOfWeek = weekday() - 1; // Sesuaikan jika weekday() dimulai dari 1
if (dayOfWeek < 0) dayOfWeek = 6; // Handling untuk memastikan indeks valid
// Array nama bulan
const char* monthNames[] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC"};
const char* dayNames[] = {"SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT"};
// Format tanggal baru: "WED, OCT 01"
String dayStr = String(dayNames[dayOfWeek]) + ", " +
String(monthNames[month() - 1]) + " " +
(day() < 10 ? "0" : "") + String(day());
dateStr = dayStr;
}
void displayMainTimeDate(int alignment) {
int yBase = BORDER_START_Y + 81;
// Mengatur font untuk waktu
tft.setFont(&MADE_Tommy_Soft15pt7b);
// Deklarasi variabel untuk dimensi dan posisi
int16_t digitX1, digitY1;
uint16_t digitW, digitH;
// Mendapatkan detik saat ini
int currentSecond = second();
static int lastSecond = -1;
// Mendapatkan digit-digit jam dan menit
String hourDigit1 = String(timeStr[0]);
String hourDigit2 = String(timeStr[1]);
String colonStr = ":";
String minDigit1 = String(timeStr[3]);
String minDigit2 = String(timeStr[4]);
// Mendapatkan lebar setiap digit
tft.getTextBounds("0", 0, 0, &digitX1, &digitY1, &digitW, &digitH); // Menggunakan "0" sebagai referensi lebar
// Menghitung lebar titik dua
int16_t colonX1, colonY1;
uint16_t colonW, colonH;
tft.getTextBounds(colonStr, 0, 0, &colonX1, &colonY1, &colonW, &colonH);
// Menghitung lebar total dengan spacing
const int DIGIT_SPACING = 5; // Spacing antar semua karakter = 5px
int fixedTotalWidth = (digitW * 4) + colonW + (DIGIT_SPACING * 4); // 4 digit + 1 titik dua + 4 spacing
// Menghitung posisi awal berdasarkan alignment
int startX;
switch (alignment) {
case TEXT_LEFT:
startX = BORDER_START_X + CONTENT_MARGIN;
break;
case TEXT_RIGHT:
startX = (BORDER_START_X + BORDER_WIDTH) - fixedTotalWidth - CONTENT_MARGIN;
break;
case TEXT_CENTER:
default:
startX = BORDER_START_X + (BORDER_WIDTH - fixedTotalWidth) / 2;
break;
}
int y = yBase + 43;
// Cek apakah waktu berubah untuk menggambar jam dan menit
if (timeStr != prevTimeStr) {
// Hapus seluruh area waktu dengan alpha blending (semi-transparan)
fillRectAlpha(
tft,
BORDER_START_X, // Hapus seluruh area horizontal
y + digitY1 - 4,
BORDER_WIDTH, // Lebar border penuh
digitH + 8,
backgroundColor, // Warna dasar
255 // Alpha value (0-255), 255 = tidak transparan
);
tft.setTextColor(safeColor565(255, 255, 255));
// Gambar digit pertama jam
tft.setCursor(startX, y);
tft.print(hourDigit1);
// Gambar digit kedua jam
tft.setCursor(startX + digitW + DIGIT_SPACING, y);
tft.print(hourDigit2);
// Posisi untuk titik dua
int colonX = startX + (digitW * 2) + (DIGIT_SPACING * 2);
// Gambar digit pertama menit
tft.setCursor(startX + (digitW * 2) + colonW + (DIGIT_SPACING * 3), y);
tft.print(minDigit1);
// Gambar digit kedua menit
tft.setCursor(startX + (digitW * 3) + colonW + (DIGIT_SPACING * 4), y);
tft.print(minDigit2);
prevTimeStr = timeStr;
}
// Perbarui tanda : hanya jika detik berubah
if (currentSecond != lastSecond) {
lastSecond = currentSecond;
// Posisi untuk titik dua
int colonX = startX + (digitW * 2) + (DIGIT_SPACING * 2);
int colonY = y;
// Hapus area tanda : dengan alpha blending
fillRectAlpha(
tft,
colonX + colonX1 - 2,
colonY + colonY1 - 2,
colonW + 4,
colonH + 4,
backgroundColor, // Warna dasar
255 // Alpha value (0-255), 255 = tidak transparan
);
// Menentukan visibilitas tanda : (detik genap tampil, ganjil hilang)
bool shouldShowColon = (currentSecond % 2 == 0);
// Gambar tanda : hanya jika harus terlihat
if (shouldShowColon) {
tft.setTextColor(safeColor565(255, 255, 255));
tft.setCursor(colonX, colonY);
tft.print(colonStr);
}
}
// Display date with alignment matching the time
tft.setFont(&MADE_Tommy_Soft5pt7b);
if (dateStr != prevDateStr) {
int16_t x1, y1;
uint16_t w, h;
tft.getTextBounds(dateStr, 0, 0, &x1, &y1, &w, &h);
// Hitung posisi x untuk tanggal berdasarkan alignment yang sama
int x;
switch (alignment) {
case TEXT_LEFT:
x = BORDER_START_X + CONTENT_MARGIN;
break;
case TEXT_RIGHT:
x = (BORDER_START_X + BORDER_WIDTH) - w - CONTENT_MARGIN;
break;
case TEXT_CENTER:
default:
x = BORDER_START_X + (BORDER_WIDTH - w) / 2;
break;
}
int y = yBase + 58;
const int CLEAR_PADDING = 2;
// Menggunakan alpha blending untuk area tanggal
fillRectAlpha(
tft,
BORDER_START_X, // Hapus seluruh area horizontal
y + y1 - CLEAR_PADDING,
BORDER_WIDTH, // Lebar border penuh
h + (CLEAR_PADDING * 2),
backgroundColor, // Warna dasar
255 // Alpha value (0-255), 255 = tidak transparan
);
tft.setTextColor(safeColor565(255, 255, 255));
tft.setCursor(x, y);
tft.print(dateStr);
prevDateStr = dateStr;
}
}
