Дисплей

This commit is contained in:
Кобелев Андрей Андреевич
2026-03-12 00:40:06 +03:00
parent a111352dc5
commit 6253480f30
16 changed files with 400 additions and 58 deletions

View File

@@ -1,7 +1,6 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"pioarduino.pioarduino-ide",
"platformio.platformio-ide"
],
"unwantedRecommendations": [

View File

@@ -264,11 +264,6 @@ enum EpdDrawError epd_hl_update_area(
uint32_t t1 = esp_timer_get_time() / 1000;
diff_area.x = 0;
diff_area.y = 0;
diff_area.width = epd_width();
diff_area.height = epd_height();
enum EpdDrawError err = EPD_DRAW_SUCCESS;
err = epd_draw_base(
epd_full_screen(),
@@ -283,11 +278,6 @@ enum EpdDrawError epd_hl_update_area(
uint32_t t2 = esp_timer_get_time() / 1000;
diff_area.x = 0;
diff_area.y = 0;
diff_area.width = epd_width();
diff_area.height = epd_height();
int buf_width = epd_width();
for (int l = diff_area.y; l < diff_area.y + diff_area.height; l++) {

View File

@@ -469,7 +469,7 @@ EpdRect epd_difference_image_base(
break;
}
for (max_x = x_end - 1; max_x >= crop_to.x; max_x--) {
uint8_t mask = min_x % 2 ? 0xF0 : 0x0F;
uint8_t mask = max_x % 2 ? 0xF0 : 0x0F;
if ((col_dirtyness[max_x / 2] & mask) != 0)
break;
}

5
partitions.csv Normal file
View File

@@ -0,0 +1,5 @@
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
phy_init, data, phy, 0xE000, 0x1000,
factory, app, factory, 0x10000, 0x280000,
spiffs, data, spiffs, 0x290000,0x170000,
1 # Name Type SubType Offset Size Flags
2 nvs data nvs 0x9000 0x5000
3 phy_init data phy 0xE000 0x1000
4 factory app factory 0x10000 0x280000
5 spiffs data spiffs 0x290000 0x170000

View File

@@ -3,11 +3,11 @@ platform = https://github.com/pioarduino/platform-espressif32/releases/download/
board = esp32dev
framework = arduino
board_build.f_cpu = 240000000L
board_build.partitions = partitions.csv
monitor_speed = 115200
lib_deps =
gyverlibs/GyverNTP@^1.3.1
bblanchon/ArduinoJson@^7.4.3
build_flags =
-DBOARD_HAS_PSRAM
-DCONFIG_EPD_DISPLAY_TYPE_ED047TC1
-DCONFIG_EPD_BOARD_REVISION_LILYGO_T5_47

View File

@@ -76,6 +76,15 @@ void Application::run_update_cycle() {
DashboardData data;
RenderPlan plan;
if (force_full_refresh_once_) {
plan.full_refresh = true;
plan.redraw_calendar = true;
plan.redraw_weather = true;
plan.redraw_battery = true;
force_full_refresh_once_ = false;
Serial.println("Cold start: форсируем полное обновление экрана");
}
const bool wifi_ok = connectivity_.connect_wifi(kWifiConnectTimeoutMs);
if (!wifi_ok) {
Serial.println("Wi-Fi недоступен, пропускаем NTP и погоду");
@@ -125,8 +134,26 @@ void Application::run_update_cycle() {
Serial.println("Заряд не изменился");
}
const bool has_partial_redraw = !plan.full_refresh && (plan.redraw_weather || plan.redraw_battery);
if (FULL_REFRESH_EVERY_N_PARTIAL_UPDATES > 0 && has_partial_redraw &&
(partial_updates_since_full_ + 1 >= FULL_REFRESH_EVERY_N_PARTIAL_UPDATES)) {
plan.full_refresh = true;
plan.redraw_calendar = true;
plan.redraw_weather = true;
plan.redraw_battery = true;
Serial.printf("Гигиенический full refresh: достигнут порог частичных обновлений (%u)\n",
(unsigned)FULL_REFRESH_EVERY_N_PARTIAL_UPDATES);
}
if (plan.full_refresh || plan.redraw_weather || plan.redraw_battery) {
dashboard_.render_pass(data, plan);
if (plan.full_refresh) {
partial_updates_since_full_ = 0;
} else {
partial_updates_since_full_++;
Serial.printf("Частичных обновлений с последнего full refresh: %u\n", (unsigned)partial_updates_since_full_);
}
}
if (data.weather.valid && (plan.full_refresh || plan.redraw_weather)) {
@@ -149,9 +176,16 @@ void Application::setup() {
log_separator();
SleepService::print_wakeup_reason();
const esp_sleep_wakeup_cause_t wakeup_reason = esp_sleep_get_wakeup_cause();
const bool woke_by_s2_button = (wakeup_reason == ESP_SLEEP_WAKEUP_EXT0);
force_full_refresh_once_ = !g_rtc_state.initialized || woke_by_s2_button;
init_rtc_state_if_needed();
display_.begin(EPD_ROT_PORTRAIT, EPD_BUILTIN_WAVEFORM, MODE_GC16, MODE_DU);
if (woke_by_s2_button) {
Serial.println("S2 wakeup: форсируем полную перерисовку дисплея");
}
display_.begin(EPD_ROT_PORTRAIT, EPD_BUILTIN_WAVEFORM, MODE_GC16, MODE_GC16);
dashboard_.layout_pass(display_.width(), display_.height());
handle_wakeup_source();

View File

@@ -32,6 +32,8 @@ private:
WeatherService weather_service_;
BatteryService battery_service_;
ui::DashboardScreen dashboard_;
bool force_full_refresh_once_ = false;
uint16_t partial_updates_since_full_ = 0;
const gpio_num_t wake_button_pin_ = GPIO_NUM_39;
};

View File

@@ -2,11 +2,50 @@
#include <Arduino.h>
#include "settings.h"
namespace app {
namespace {
EpdRect align_area_for_partial(const EpdRect& area, const int max_w, const int max_h) {
int x0 = area.x < 0 ? 0 : area.x;
int y0 = area.y < 0 ? 0 : area.y;
int x1 = area.x + area.width;
int y1 = area.y + area.height;
if (x1 > max_w) x1 = max_w;
if (y1 > max_h) y1 = max_h;
if (x1 <= x0 || y1 <= y0) {
return {.x = x0, .y = y0, .width = 0, .height = 0};
}
// 4-bit packed framebuffer is more stable when partial regions are byte-aligned.
x0 = (x0 / 8) * 8;
x1 = ((x1 + 7) / 8) * 8;
if (x1 > max_w) x1 = max_w;
return {
.x = x0,
.y = y0,
.width = x1 - x0,
.height = y1 - y0,
};
}
} // namespace
void DisplayService::begin(EpdRotation orientation, const EpdWaveform* waveform, const EpdDrawMode full_mode,
const EpdDrawMode partial_mode) {
epd_init(&epd_board_lilygo_t5_47, &ED047TC1, EPD_LUT_64K);
#if LILYGO_T5_47_PANEL_PROFILE == 1
const EpdDisplay_t* display_profile = &ED047TC1;
const char* display_profile_name = "ED047TC1";
#elif LILYGO_T5_47_PANEL_PROFILE == 2
const EpdDisplay_t* display_profile = &ED047TC2;
const char* display_profile_name = "ED047TC2";
#else
#error "LILYGO_T5_47_PANEL_PROFILE must be 1 (TC1) or 2 (TC2)"
#endif
epd_init(&epd_board_lilygo_t5_47, display_profile, EPD_LUT_64K);
hl_ = epd_hl_init(waveform);
epd_set_rotation(orientation);
@@ -19,6 +58,7 @@ void DisplayService::begin(EpdRotation orientation, const EpdWaveform* waveform,
epd_hl_set_all_white(&hl_);
Serial.printf("Display profile: %s\n", display_profile_name);
Serial.printf("Screen(rotated): %dx%d\n", screen_width_, screen_height_);
}
@@ -55,6 +95,13 @@ void DisplayService::clear_framebuffer_area(const EpdRect& area) {
epd_fill_rect(area, 0xFF, fb_);
}
void DisplayService::hard_full_clear() {
refresh_panel_temperature();
epd_poweron();
epd_fullclear(&hl_, panel_temperature_);
epd_poweroff();
}
bool DisplayService::update_full_screen() {
refresh_panel_temperature();
@@ -77,12 +124,17 @@ bool DisplayService::update_full_screen() {
}
bool DisplayService::update_area(const EpdRect& area) {
const EpdRect aligned_area = align_area_for_partial(area, screen_width_, screen_height_);
if (aligned_area.width <= 0 || aligned_area.height <= 0) {
return true;
}
refresh_panel_temperature();
epd_poweron();
int tries = 0;
while (tries < 3) {
const EpdDrawError draw_err = epd_hl_update_area(&hl_, partial_mode_, panel_temperature_, area);
const EpdDrawError draw_err = epd_hl_update_area(&hl_, partial_mode_, panel_temperature_, aligned_area);
if (draw_err == EPD_DRAW_SUCCESS) {
epd_poweroff();
return true;

View File

@@ -17,6 +17,7 @@ public:
bool clear_area_hw(const EpdRect& area);
void clear_framebuffer_all();
void clear_framebuffer_area(const EpdRect& area);
void hard_full_clear();
bool update_full_screen();
bool update_area(const EpdRect& area);

View File

@@ -14,8 +14,7 @@ void DashboardScreen::layout_pass(int screen_width, int screen_height) {
void DashboardScreen::render_pass(const app::DashboardData& data, const app::RenderPlan& plan) {
if (plan.full_refresh) {
epd_clear();
display_.clear_framebuffer_all();
display_.hard_full_clear();
const CalendarProps calendar_props{
.valid = data.calendar.valid,
@@ -43,26 +42,30 @@ void DashboardScreen::render_pass(const app::DashboardData& data, const app::Ren
}
if (plan.redraw_weather && data.weather.valid) {
display_.clear_area_hw(weather_view_.bounds());
display_.clear_framebuffer_area(weather_view_.bounds());
const WeatherProps weather_props{
.valid = true,
.state_ru = app::WeatherService::weather_state_to_ru(data.weather.state),
.temperature = data.weather.temperature,
};
weather_view_.render(display_.framebuffer(), weather_props);
display_.update_area(weather_view_.bounds());
const EpdRect weather_area = weather_view_.dirty_bounds(weather_props, 5, 6);
if (weather_area.width > 0 && weather_area.height > 0) {
display_.clear_framebuffer_area(weather_area);
weather_view_.render(display_.framebuffer(), weather_props);
display_.update_area(weather_area);
}
}
if (plan.redraw_battery && data.battery.valid) {
display_.clear_area_hw(battery_view_.bounds());
display_.clear_framebuffer_area(battery_view_.bounds());
const BatteryProps battery_props{
.valid = true,
.percent = data.battery.percent,
};
battery_view_.render(display_.framebuffer(), battery_props);
display_.update_area(battery_view_.bounds());
const EpdRect battery_area = battery_view_.dirty_bounds(battery_props, 4, 4);
if (battery_area.width > 0 && battery_area.height > 0) {
display_.clear_framebuffer_area(battery_area);
battery_view_.render(display_.framebuffer(), battery_props);
display_.update_area(battery_area);
}
}
}

View File

@@ -6,6 +6,34 @@
namespace ui {
namespace {
EpdRect union_rect(const EpdRect& a, const EpdRect& b) {
const int left = a.x < b.x ? a.x : b.x;
const int top = a.y < b.y ? a.y : b.y;
const int right_a = a.x + a.width;
const int right_b = b.x + b.width;
const int bottom_a = a.y + a.height;
const int bottom_b = b.y + b.height;
const int right = right_a > right_b ? right_a : right_b;
const int bottom = bottom_a > bottom_b ? bottom_a : bottom_b;
return {.x = left, .y = top, .width = right - left, .height = bottom - top};
}
EpdRect clamp_to_rect(const EpdRect& rect, const EpdRect& limit) {
const int left = rect.x > limit.x ? rect.x : limit.x;
const int top = rect.y > limit.y ? rect.y : limit.y;
const int right = (rect.x + rect.width) < (limit.x + limit.width) ? (rect.x + rect.width) : (limit.x + limit.width);
const int bottom =
(rect.y + rect.height) < (limit.y + limit.height) ? (rect.y + rect.height) : (limit.y + limit.height);
if (right <= left || bottom <= top) {
return {.x = limit.x, .y = limit.y, .width = 0, .height = 0};
}
return {.x = left, .y = top, .width = right - left, .height = bottom - top};
}
} // namespace
void BatteryView::layout(int screen_width, int screen_height) {
const int margin = 14;
const int width = 120;
@@ -22,8 +50,50 @@ void BatteryView::layout(int screen_width, int screen_height) {
text_y_ = screen_height - margin;
}
void BatteryView::render(uint8_t* framebuffer, const BatteryProps& props) const {
EpdRect BatteryView::measure_text_bounds(const BatteryProps& props) const {
char text[24];
snprintf(text, sizeof(text), "%d %%", props.percent);
EpdFontProperties font_props = epd_font_properties_default();
font_props.flags = EPD_DRAW_ALIGN_RIGHT;
int x1 = 0;
int y1 = 0;
int w = 0;
int h = 0;
epd_get_text_bounds(&MartianMono12, text, &text_x_, &text_y_, &x1, &y1, &w, &h, &font_props);
return {.x = x1, .y = y1, .width = w, .height = h};
}
EpdRect BatteryView::dirty_bounds(const BatteryProps& props, const int pad_x, const int pad_y) const {
EpdRect area = {.x = bounds_.x, .y = bounds_.y, .width = 0, .height = 0};
if (has_last_text_bounds_) {
area = last_text_bounds_;
}
if (props.valid) {
const EpdRect current_bounds = measure_text_bounds(props);
area = has_last_text_bounds_ ? union_rect(area, current_bounds) : current_bounds;
}
if (area.width <= 0 || area.height <= 0) {
return area;
}
const EpdRect expanded = {
.x = area.x - pad_x,
.y = area.y - pad_y,
.width = area.width + (pad_x * 2),
.height = area.height + (pad_y * 2),
};
return clamp_to_rect(expanded, bounds_);
}
void BatteryView::render(uint8_t* framebuffer, const BatteryProps& props) {
if (!props.valid) {
has_last_text_bounds_ = false;
return;
}
@@ -36,6 +106,9 @@ void BatteryView::render(uint8_t* framebuffer, const BatteryProps& props) const
int x = text_x_;
int y = text_y_;
epd_write_string(&MartianMono12, text, &x, &y, framebuffer, &font_props);
last_text_bounds_ = measure_text_bounds(props);
has_last_text_bounds_ = (last_text_bounds_.width > 0 && last_text_bounds_.height > 0);
}
const EpdRect& BatteryView::bounds() const {

View File

@@ -12,13 +12,18 @@ struct BatteryProps {
class BatteryView {
public:
void layout(int screen_width, int screen_height);
void render(uint8_t* framebuffer, const BatteryProps& props) const;
EpdRect dirty_bounds(const BatteryProps& props, int pad_x = 4, int pad_y = 4) const;
void render(uint8_t* framebuffer, const BatteryProps& props);
const EpdRect& bounds() const;
private:
EpdRect measure_text_bounds(const BatteryProps& props) const;
EpdRect bounds_ = {0, 0, 0, 0};
int text_x_ = 0;
int text_y_ = 0;
EpdRect last_text_bounds_ = {0, 0, 0, 0};
bool has_last_text_bounds_ = false;
};
} // namespace ui

View File

@@ -1,46 +1,52 @@
#include "ui/views/calendar_view.h"
#include "MartianMono30.h"
#include "MartianMono120.h"
#include "MartianMono30.h"
namespace ui {
int CalendarView::clamp_int(int value, int min_v, int max_v) {
if (value < min_v) return min_v;
if (value > max_v) return max_v;
return value;
if (value < min_v)
return min_v;
if (value > max_v)
return max_v;
return value;
}
void CalendarView::layout(int screen_width, int screen_height) {
center_x_ = screen_width / 2;
day_y_ = (screen_height * 38) / 100;
center_x_ = screen_width / 2;
day_y_ = (screen_height * 28) / 100;
const int month_spacing = clamp_int(screen_height / 6, 72, 108);
const int week_spacing = clamp_int(screen_height / 14, 30, 54);
const int month_spacing = clamp_int(screen_height / 6, 62, 108);
const int week_spacing = clamp_int(screen_height / 14, 30, 54);
month_y_ = day_y_ + month_spacing;
week_y_ = month_y_ + week_spacing;
month_y_ = day_y_ + month_spacing;
week_y_ = month_y_ + week_spacing;
}
void CalendarView::render(uint8_t* framebuffer, const CalendarProps& props) const {
if (!props.valid) {
return;
}
void CalendarView::render(uint8_t *framebuffer,
const CalendarProps &props) const {
if (!props.valid) {
return;
}
EpdFontProperties font_props = epd_font_properties_default();
font_props.flags = EPD_DRAW_ALIGN_CENTER;
EpdFontProperties font_props = epd_font_properties_default();
font_props.flags = EPD_DRAW_ALIGN_CENTER;
int day_x = center_x_;
int day_y = day_y_;
epd_write_string(&MartianMono120, props.day, &day_x, &day_y, framebuffer, &font_props);
int day_x = center_x_;
int day_y = day_y_;
epd_write_string(&MartianMono120, props.day, &day_x, &day_y, framebuffer,
&font_props);
int month_x = center_x_;
int month_y = month_y_;
epd_write_string(&MartianMono30, props.month, &month_x, &month_y, framebuffer, &font_props);
int month_x = center_x_;
int month_y = month_y_;
epd_write_string(&MartianMono30, props.month, &month_x, &month_y, framebuffer,
&font_props);
int week_x = center_x_;
int week_y = week_y_;
epd_write_string(&MartianMono30, props.weekday, &week_x, &week_y, framebuffer, &font_props);
int week_x = center_x_;
int week_y = week_y_;
epd_write_string(&MartianMono30, props.weekday, &week_x, &week_y, framebuffer,
&font_props);
}
} // namespace ui
} // namespace ui

View File

@@ -6,6 +6,34 @@
namespace ui {
namespace {
EpdRect union_rect(const EpdRect& a, const EpdRect& b) {
const int left = a.x < b.x ? a.x : b.x;
const int top = a.y < b.y ? a.y : b.y;
const int right_a = a.x + a.width;
const int right_b = b.x + b.width;
const int bottom_a = a.y + a.height;
const int bottom_b = b.y + b.height;
const int right = right_a > right_b ? right_a : right_b;
const int bottom = bottom_a > bottom_b ? bottom_a : bottom_b;
return {.x = left, .y = top, .width = right - left, .height = bottom - top};
}
EpdRect clamp_to_rect(const EpdRect& rect, const EpdRect& limit) {
const int left = rect.x > limit.x ? rect.x : limit.x;
const int top = rect.y > limit.y ? rect.y : limit.y;
const int right = (rect.x + rect.width) < (limit.x + limit.width) ? (rect.x + rect.width) : (limit.x + limit.width);
const int bottom =
(rect.y + rect.height) < (limit.y + limit.height) ? (rect.y + rect.height) : (limit.y + limit.height);
if (right <= left || bottom <= top) {
return {.x = limit.x, .y = limit.y, .width = 0, .height = 0};
}
return {.x = left, .y = top, .width = right - left, .height = bottom - top};
}
} // namespace
void WeatherView::layout(int screen_width, int screen_height) {
const int top = (screen_height * 62) / 100;
bounds_ = {
@@ -19,8 +47,50 @@ void WeatherView::layout(int screen_width, int screen_height) {
text_y_ = top + 36;
}
void WeatherView::render(uint8_t* framebuffer, const WeatherProps& props) const {
EpdRect WeatherView::measure_text_bounds(const WeatherProps& props) const {
char text[128];
snprintf(text, sizeof(text), "%s\n%d°C", props.state_ru, props.temperature);
EpdFontProperties font_props = epd_font_properties_default();
font_props.flags = EPD_DRAW_ALIGN_CENTER;
int x1 = 0;
int y1 = 0;
int w = 0;
int h = 0;
epd_get_text_bounds(&MartianMono12, text, &text_x_, &text_y_, &x1, &y1, &w, &h, &font_props);
return {.x = x1, .y = y1, .width = w, .height = h};
}
EpdRect WeatherView::dirty_bounds(const WeatherProps& props, const int pad_x, const int pad_y) const {
EpdRect area = {.x = bounds_.x, .y = bounds_.y, .width = 0, .height = 0};
if (has_last_text_bounds_) {
area = last_text_bounds_;
}
if (props.valid) {
const EpdRect current_bounds = measure_text_bounds(props);
area = has_last_text_bounds_ ? union_rect(area, current_bounds) : current_bounds;
}
if (area.width <= 0 || area.height <= 0) {
return area;
}
const EpdRect expanded = {
.x = area.x - pad_x,
.y = area.y - pad_y,
.width = area.width + (pad_x * 2),
.height = area.height + (pad_y * 2),
};
return clamp_to_rect(expanded, bounds_);
}
void WeatherView::render(uint8_t* framebuffer, const WeatherProps& props) {
if (!props.valid) {
has_last_text_bounds_ = false;
return;
}
@@ -33,6 +103,9 @@ void WeatherView::render(uint8_t* framebuffer, const WeatherProps& props) const
int x = text_x_;
int y = text_y_;
epd_write_string(&MartianMono12, text, &x, &y, framebuffer, &font_props);
last_text_bounds_ = measure_text_bounds(props);
has_last_text_bounds_ = (last_text_bounds_.width > 0 && last_text_bounds_.height > 0);
}
const EpdRect& WeatherView::bounds() const {

View File

@@ -13,13 +13,18 @@ struct WeatherProps {
class WeatherView {
public:
void layout(int screen_width, int screen_height);
void render(uint8_t* framebuffer, const WeatherProps& props) const;
EpdRect dirty_bounds(const WeatherProps& props, int pad_x = 4, int pad_y = 4) const;
void render(uint8_t* framebuffer, const WeatherProps& props);
const EpdRect& bounds() const;
private:
EpdRect measure_text_bounds(const WeatherProps& props) const;
EpdRect bounds_ = {0, 0, 0, 0};
int text_x_ = 0;
int text_y_ = 0;
EpdRect last_text_bounds_ = {0, 0, 0, 0};
bool has_last_text_bounds_ = false;
};
} // namespace ui

94
taskfile.yml Normal file
View File

@@ -0,0 +1,94 @@
version: "3"
vars:
PIO: pio
ENV: esp32dev
PORT: ""
BAUD: "115200"
PYTHON: python3.11
EPDIY_SCRIPTS: lib/epdiy/scripts
MARTIAN_FONT: static/MartianMono-VariableFont_wdth,wght.ttf
MARTIAN_CHARS: '0123456789:;.,-+/!@\#^&*%°CABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyzАБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя'
tasks:
default:
desc: Показать список доступных задач
cmds:
- task --list
build:
desc: Сборка прошивки (ENV=esp32dev)
cmds:
- "{{.PIO}} run -e {{.ENV}}"
clean:
desc: Очистка артефактов сборки
cmds:
- "{{.PIO}} run -e {{.ENV}} -t clean"
rebuild:
desc: Полная пересборка
deps: [clean]
cmds:
- "{{.PIO}} run -e {{.ENV}}"
upload:
desc: Прошивка на устройство (опционально PORT=/dev/tty...)
cmds:
- "{{.PIO}} run -e {{.ENV}} -t upload {{if .PORT}}--upload-port {{.PORT}}{{end}}"
monitor:
desc: Serial monitor (опционально PORT=/dev/tty...)
cmds:
- "{{.PIO}} device monitor -b {{.BAUD}} {{if .PORT}}-p {{.PORT}}{{end}}"
run:
desc: Прошивка + monitor
deps: [upload]
cmds:
- "{{.PIO}} device monitor -b {{.BAUD}} {{if .PORT}}-p {{.PORT}}{{end}}"
check:
desc: Статический анализ через pio check
cmds:
- "{{.PIO}} check -e {{.ENV}}"
size:
desc: Отчёт по размеру бинарника
cmds:
- "{{.PIO}} run -e {{.ENV}} -t size"
ports:
desc: Список доступных serial-портов
cmds:
- "{{.PIO}} device list"
image:
desc: Генерация include/sun.h и include/moon.h из static/*.jpg
cmds:
- "{{.PYTHON}} {{.EPDIY_SCRIPTS}}/imgconvert.py -i static/sun.jpg -n sun -o include/sun.h"
- "{{.PYTHON}} {{.EPDIY_SCRIPTS}}/imgconvert.py -i static/moon.jpg -n moon -o include/moon.h"
font:12:
desc: Генерация MartianMono12.h
cmds:
- "{{.PYTHON}} {{.EPDIY_SCRIPTS}}/fontconvert.py --compress MartianMono12 12 {{.MARTIAN_FONT}} --string '{{.MARTIAN_CHARS}}' > lib/MartianMono/MartianMono12.h"
font:30:
desc: Генерация MartianMono30.h
cmds:
- "{{.PYTHON}} {{.EPDIY_SCRIPTS}}/fontconvert.py --compress MartianMono30 30 {{.MARTIAN_FONT}} --string '{{.MARTIAN_CHARS}}' > lib/MartianMono/MartianMono30.h"
font:120:
desc: Генерация MartianMono120.h
cmds:
- "{{.PYTHON}} {{.EPDIY_SCRIPTS}}/fontconvert.py --compress MartianMono120 120 {{.MARTIAN_FONT}} --string '0123456789' > lib/MartianMono/MartianMono120.h"
font:200:
desc: Генерация MartianMono200.h
cmds:
- "{{.PYTHON}} {{.EPDIY_SCRIPTS}}/fontconvert.py --compress MartianMono200 200 {{.MARTIAN_FONT}} --string '0123456789' > lib/MartianMono/MartianMono200.h"
font:all:
desc: Генерация всех шрифтов
deps: [font:12, font:30, font:120, font:200]