diff --git a/companion/src/firmwares/opentx/simulator/opentxsimulator.cpp b/companion/src/firmwares/opentx/simulator/opentxsimulator.cpp index 0d1141b5a..f1cf8fbfe 100644 --- a/companion/src/firmwares/opentx/simulator/opentxsimulator.cpp +++ b/companion/src/firmwares/opentx/simulator/opentxsimulator.cpp @@ -134,7 +134,7 @@ namespace NAMESPACE { #include "radio/src/trainer_input.cpp" #if defined(PCBHORUS) -#include "radio/src/bmp.cpp" +#include "radio/src/gui/horus/bitmapbuffer.cpp" #include "radio/src/gui/horus/bitmaps.cpp" #include "radio/src/gui/horus/curves.cpp" #include "radio/src/gui/horus/fonts.cpp" @@ -224,7 +224,7 @@ namespace NAMESPACE { #include "radio/src/gui/Flamenco/splash.cpp" #include "radio/src/targets/flamenco/tw8823_driver.cpp" #elif defined(PCBTARANIS) -#include "radio/src/bmp.cpp" +#include "radio/src/gui/taranis/bmp.cpp" #include "radio/src/gui/taranis/fonts.cpp" #include "radio/src/gui/taranis/widgets.cpp" #include "radio/src/gui/taranis/navigation.cpp" diff --git a/radio/sdcard/horus/THEMES/Darkblue/thumb.bmp b/radio/sdcard/horus/THEMES/Darkblue/thumb.bmp new file mode 100644 index 000000000..af5de373e Binary files /dev/null and b/radio/sdcard/horus/THEMES/Darkblue/thumb.bmp differ diff --git a/radio/sdcard/horus/THEMES/Darkblue/topmenu_opentx.bmp b/radio/sdcard/horus/THEMES/Darkblue/topmenu_opentx.bmp new file mode 100644 index 000000000..cbc7f8149 Binary files /dev/null and b/radio/sdcard/horus/THEMES/Darkblue/topmenu_opentx.bmp differ diff --git a/radio/sdcard/horus/THEMES/default_aboutbg.bmp b/radio/sdcard/horus/THEMES/Default/aboutbg.bmp similarity index 100% rename from radio/sdcard/horus/THEMES/default_aboutbg.bmp rename to radio/sdcard/horus/THEMES/Default/aboutbg.bmp diff --git a/radio/sdcard/horus/THEMES/default_bg.bmp b/radio/sdcard/horus/THEMES/Default/mainbg.bmp similarity index 100% rename from radio/sdcard/horus/THEMES/default_bg.bmp rename to radio/sdcard/horus/THEMES/Default/mainbg.bmp diff --git a/radio/sdcard/horus/THEMES/Default/sleep.bmp b/radio/sdcard/horus/THEMES/Default/sleep.bmp new file mode 100644 index 000000000..279a9b855 Binary files /dev/null and b/radio/sdcard/horus/THEMES/Default/sleep.bmp differ diff --git a/radio/sdcard/horus/THEMES/Default/thumb.bmp b/radio/sdcard/horus/THEMES/Default/thumb.bmp new file mode 100644 index 000000000..37de4998e Binary files /dev/null and b/radio/sdcard/horus/THEMES/Default/thumb.bmp differ diff --git a/radio/sdcard/horus/WIDGETS/Counter/main.lua b/radio/sdcard/horus/WIDGETS/Counter/main.lua new file mode 100644 index 000000000..86ff9bd4b --- /dev/null +++ b/radio/sdcard/horus/WIDGETS/Counter/main.lua @@ -0,0 +1,19 @@ +local options = { + { "Source", SOURCE, 1 }, + { "Min", VALUE, -1024 }, + { "Max", VALUE, 1024 }, + { "Color", COLOR, RED } +} + +local function create(zone, options) + local pie = { zone=zone, options=options, counter=0 } + print(options.Source) + return pie +end + +function refresh(pie) + pie.counter = pie.counter + 1 + lcd.drawNumber(pie.zone.x, pie.zone.y, pie.counter, LEFT + DBLSIZE + TEXT_COLOR); +end + +return { name="Counter", options=options, create=create, refresh=refresh } diff --git a/radio/src/CMakeLists.txt b/radio/src/CMakeLists.txt index 2653aa4bb..09a64d50e 100644 --- a/radio/src/CMakeLists.txt +++ b/radio/src/CMakeLists.txt @@ -70,6 +70,7 @@ if(PCB STREQUAL HORUS) file(GLOB WIDGETS_SRC RELATIVE ${RADIO_SRC_DIRECTORY}/gui/horus ${RADIO_SRC_DIRECTORY}/gui/horus/widgets/*.cpp) set(GUI_SRC ${GUI_SRC} + bitmapbuffer.cpp curves.cpp bitmaps.cpp menu_general_hardware.cpp @@ -87,7 +88,7 @@ if(PCB STREQUAL HORUS) ${LAYOUTS_SRC} ${WIDGETS_SRC} ) - set(SRC ${SRC} bmp.cpp targets/taranis/rtc_driver.cpp) + set(SRC ${SRC} targets/taranis/rtc_driver.cpp) set(TARGET_SRC ${TARGET_SRC} board_horus.cpp) set(FIRMWARE_TARGET_SRC ${FIRMWARE_TARGET_SRC} @@ -146,8 +147,7 @@ elseif(PCB STREQUAL TARANIS) add_definitions(-DPCBTARANIS) add_definitions(-DAUDIO -DVOICE -DRTCLOCK) add_definitions(-DDBLKEYS -DVIRTUALINPUTS -DLUAINPUTS -DXCURVES -DVARIO) - set(SRC ${SRC} bmp.cpp) - set(GUI_SRC ${GUI_SRC} menu_model_inputs.cpp menu_model_mixes.cpp menu_general_diagkeys.cpp menu_general_diaganas.cpp menu_general_hardware.cpp view_channels.cpp view_telemetry.cpp view_text.cpp view_about.cpp) + set(GUI_SRC ${GUI_SRC} bmp.cpp menu_model_inputs.cpp menu_model_mixes.cpp menu_general_diagkeys.cpp menu_general_diaganas.cpp menu_general_hardware.cpp view_channels.cpp view_telemetry.cpp view_text.cpp view_about.cpp) set(TARGET_SRC ${TARGET_SRC} board_taranis.cpp rtc_driver.cpp) set(FIRMWARE_SRC ${FIRMWARE_SRC} loadboot.cpp) set(FIRMWARE_TARGET_SRC @@ -767,6 +767,7 @@ foreach(FILE ${PULSES_SRC}) endforeach() add_definitions(-DCORRECT_NEGATIVE_SHIFTS) +add_definitions(-Wall -Wno-strict-aliasing -Wformat -Wreturn-type -Wunused -Wuninitialized -Wunknown-pragmas -Wno-switch -Wtype-limits) if(NOT WIN32) add_subdirectory(targets/simu) @@ -775,8 +776,6 @@ endif() set(SRC ${SRC} ${FIRMWARE_SRC}) -set(WARNING_FLAGS "-Wall -Wno-strict-aliasing -Wformat -Wreturn-type -Wunused -Wuninitialized -Wunknown-pragmas -Wno-switch -Wtype-limits") - # trick to remove the -rdynamic and --out-implib issues set(CMAKE_EXECUTABLE_SUFFIX ".elf") set(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "") @@ -798,7 +797,7 @@ if(ARCH STREQUAL ARM) set(COMMON_FLAGS "-mcpu=${MCU} -mthumb -fomit-frame-pointer -fverbose-asm -Wa,-ahlms=firmware.lst -O${OPT} -gdwarf-2 -DHSE_VALUE=${HSE_VALUE} -fno-exceptions -fdata-sections -ffunction-sections ${WARNING_FLAGS}") set(CMAKE_C_FLAGS "${COMMON_FLAGS} -Wimplicit") set(CMAKE_CXX_FLAGS "${COMMON_FLAGS}") - set(CMAKE_EXE_LINKER_FLAGS "-mcpu=${MCU} -mthumb -nostartfiles -lm -T${RADIO_SRC_DIRECTORY}/${LINKER_SCRIPT} -Wl,-Map=firmware.map,--cref,--no-warn-mismatch,--gc-sections") + set(CMAKE_EXE_LINKER_FLAGS "-mcpu=${MCU} -mthumb -lm -T${RADIO_SRC_DIRECTORY}/${LINKER_SCRIPT} -Wl,-Map=firmware.map,--cref,--no-warn-mismatch,--gc-sections") if(PCB STREQUAL TARANIS) add_subdirectory(targets/${TARGET_DIR}/bootloader) diff --git a/radio/src/Makefile b/radio/src/Makefile index 85d70de56..13d356d8d 100644 --- a/radio/src/Makefile +++ b/radio/src/Makefile @@ -979,7 +979,7 @@ ifeq ($(PCB), TARANIS) PULSESSRC = pulses/pulses_arm.cpp pulses/ppm_arm.cpp pulses/pxx_arm.cpp pulses/crossfire.cpp CPPSRC += tasks_arm.cpp audio_arm.cpp sbus.cpp telemetry/telemetry.cpp CPPSRC += targets/taranis/pulses_driver.cpp targets/taranis/keys_driver.cpp targets/taranis/adc_driver.cpp targets/taranis/trainer_driver.cpp targets/taranis/audio_driver.cpp targets/taranis/serial2_driver.cpp targets/taranis/telemetry_driver.cpp - CPPSRC += bmp.cpp gui/$(GUIDIRECTORY)/view_channels.cpp gui/$(GUIDIRECTORY)/view_about.cpp gui/$(GUIDIRECTORY)/view_text.cpp debug.cpp + CPPSRC += gui/$(GUIDIRECTORY)/bmp.cpp gui/$(GUIDIRECTORY)/view_channels.cpp gui/$(GUIDIRECTORY)/view_about.cpp gui/$(GUIDIRECTORY)/view_text.cpp debug.cpp EXTRABOARDSRC += loadboot.cpp ifeq ($(PCBREV), REV9E) CPPSRC += targets/taranis/top_lcd_driver.cpp diff --git a/radio/src/bitmaps/horus/CMakeLists.txt b/radio/src/bitmaps/horus/CMakeLists.txt index 081ae6d38..4b32dcc23 100644 --- a/radio/src/bitmaps/horus/CMakeLists.txt +++ b/radio/src/bitmaps/horus/CMakeLists.txt @@ -8,9 +8,9 @@ add_custom_target(ttf_horus_fonts DEPENDS ttf_horus_tinsize ttf_horus_smlsize tt add_bitmaps_target(horus_bitmaps "${RADIO_SRC_DIRECTORY}/bitmaps/horus/bmp_*.png" 480 5/6/5) add_bitmaps_target(horus_calibration_bitmaps "${RADIO_SRC_DIRECTORY}/bitmaps/horus/calibration/bmp_*.png" 480 5/6/5) -add_bitmaps_target(horus_button_bitmaps "${RADIO_SRC_DIRECTORY}/bitmaps/horus/button/alpha_*.png" 480 5/6/5/8) -add_bitmaps_target(horus_alpha_bitmaps "${RADIO_SRC_DIRECTORY}/bitmaps/horus/alpha_*.png" 480 5/6/5/8) -add_bitmaps_target(horus_alpha_calibration_bitmaps "${RADIO_SRC_DIRECTORY}/bitmaps/horus/calibration/alpha_*.png" 480 5/6/5/8) +add_bitmaps_target(horus_button_bitmaps "${RADIO_SRC_DIRECTORY}/bitmaps/horus/button/alpha_*.png" 480 4/4/4/4) +add_bitmaps_target(horus_alpha_bitmaps "${RADIO_SRC_DIRECTORY}/bitmaps/horus/alpha_*.png" 480 4/4/4/4) +add_bitmaps_target(horus_alpha_calibration_bitmaps "${RADIO_SRC_DIRECTORY}/bitmaps/horus/calibration/alpha_*.png" 480 4/4/4/4) add_bitmaps_target(horus_masks ${RADIO_SRC_DIRECTORY}/bitmaps/horus/mask_*.png 480 8bits) add_bitmaps_target(horus_slider_masks "${RADIO_SRC_DIRECTORY}/bitmaps/horus/slider/*.png" 480 8bits) add_bitmaps_target(horus_layouts_masks "${RADIO_SRC_DIRECTORY}/gui/horus/layouts/*.png" 480 8bits) diff --git a/radio/src/bitmaps/horus/bmp_background.png b/radio/src/bitmaps/horus/bmp_background.png deleted file mode 100644 index 02fa6695d..000000000 Binary files a/radio/src/bitmaps/horus/bmp_background.png and /dev/null differ diff --git a/radio/src/bitmaps/horus/bmp_sleep.png b/radio/src/bitmaps/horus/bmp_sleep.png deleted file mode 100644 index 70e163272..000000000 Binary files a/radio/src/bitmaps/horus/bmp_sleep.png and /dev/null differ diff --git a/radio/src/bitmaps/horus/bmp_topmenu_opentx.png b/radio/src/bitmaps/horus/bmp_topmenu_opentx.png deleted file mode 100644 index b119d2a0c..000000000 Binary files a/radio/src/bitmaps/horus/bmp_topmenu_opentx.png and /dev/null differ diff --git a/radio/src/bitmaps/horus/mask_about_headico.png b/radio/src/bitmaps/horus/mask_about_headico.png new file mode 100644 index 000000000..c7ebe7eca Binary files /dev/null and b/radio/src/bitmaps/horus/mask_about_headico.png differ diff --git a/radio/src/bmp.cpp b/radio/src/bmp.cpp deleted file mode 100644 index 8e0671d33..000000000 --- a/radio/src/bmp.cpp +++ /dev/null @@ -1,516 +0,0 @@ -/* - * Copyright (C) OpenTX - * - * Based on code named - * th9x - http://code.google.com/p/th9x - * er9x - http://code.google.com/p/er9x - * gruvin9x - http://code.google.com/p/gruvin9x - * - * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - */ - -#include "opentx.h" - -#if defined(PCBTARANIS) -uint8_t * bmpLoad(uint8_t * bmp, const char * filename, uint16_t width, uint16_t height) -{ - FIL bmpFile; - UINT read; - uint8_t palette[16]; - uint8_t bmpBuf[LCD_W]; /* maximum with LCD_W */ - uint8_t * buf = &bmpBuf[0]; - - if (width > LCD_W) { - return NULL; - } - - FRESULT result = f_open(&bmpFile, filename, FA_OPEN_EXISTING | FA_READ); - if (result != FR_OK) { - return NULL; - } - - if (f_size(&bmpFile) < 14) { - f_close(&bmpFile); - return NULL; - } - - result = f_read(&bmpFile, buf, 14, &read); - if (result != FR_OK || read != 14) { - f_close(&bmpFile); - return NULL; - } - - if (buf[0] != 'B' || buf[1] != 'M') { - f_close(&bmpFile); - return NULL; - } - - uint32_t fsize = *((uint32_t *)&buf[2]); - uint32_t hsize = *((uint32_t *)&buf[10]); /* header size */ - - uint32_t len = limit((uint32_t)4, (uint32_t)(hsize-14), (uint32_t)32); - result = f_read(&bmpFile, buf, len, &read); - if (result != FR_OK || read != len) { - f_close(&bmpFile); - return NULL; - } - - uint32_t ihsize = *((uint32_t *)&buf[0]); /* more header size */ - - /* invalid header size */ - if (ihsize + 14 > hsize) { - f_close(&bmpFile); - return NULL; - } - - /* sometimes file size is set to some headers size, set a real size in that case */ - if (fsize == 14 || fsize == ihsize + 14) - fsize = f_size(&bmpFile) - 2; - - /* declared file size less than header size */ - if (fsize <= hsize) { - f_close(&bmpFile); - return NULL; - } - - uint32_t w, h; - - switch (ihsize){ - case 40: // windib - case 56: // windib v3 - case 64: // OS/2 v2 - case 108: // windib v4 - case 124: // windib v5 - w = *((uint32_t *)&buf[4]); - h = *((uint32_t *)&buf[8]); - buf += 12; - break; - case 12: // OS/2 v1 - w = *((uint16_t *)&buf[4]); - h = *((uint16_t *)&buf[6]); - buf += 8; - break; - default: - f_close(&bmpFile); - return NULL; - } - - if (*((uint16_t *)&buf[0]) != 1) { /* planes */ - f_close(&bmpFile); - return NULL; - } - - if (w > width || h > height) { - f_close(&bmpFile); - return NULL; - } - - uint16_t depth = *((uint16_t *)&buf[2]); - - buf = &bmpBuf[0]; - - if (depth == 4) { - if (f_lseek(&bmpFile, hsize-64) != FR_OK || f_read(&bmpFile, buf, 64, &read) != FR_OK || read != 64) { - f_close(&bmpFile); - return NULL; - } - for (uint8_t i=0; i<16; i++) { - palette[i] = buf[4*i] >> 4; - } - } - else { - if (f_lseek(&bmpFile, hsize) != FR_OK) { - f_close(&bmpFile); - return NULL; - } - } - - uint8_t * dest = bmp; - - *dest++ = w; - *dest++ = h; - - memset(dest, 0, BITMAP_BUFFER_SIZE(w, h) - 2); - - uint32_t rowSize; - - switch (depth) { - case 1: - rowSize = ((w+31)/32)*4; - for (uint32_t i=0; i=0; i--) { - result = f_read(&bmpFile, buf, rowSize, &read); - if (result != FR_OK || read != rowSize) { - f_close(&bmpFile); - return NULL; - } - uint8_t * dst = dest + (i/2)*w; - for (uint32_t j=0; j> ((j & 1) ? 0 : 4)) & 0x0F; - uint8_t val = palette[index] << ((i & 1) ? 4 : 0); - *dst++ |= val ^ ((i & 1) ? 0xF0 : 0x0F); - } - } - break; - - default: - f_close(&bmpFile); - return NULL; - } - - f_close(&bmpFile); - return bmp; -} -#elif defined(PCBHORUS) -uint8_t * bmpLoad(const char * filename) -{ - FIL bmpFile; - UINT read; - uint8_t palette[16]; - uint8_t bmpBuf[LCD_W]; /* maximum with LCD_W */ - uint8_t * buf = &bmpBuf[0]; - - FRESULT result = f_open(&bmpFile, filename, FA_OPEN_EXISTING | FA_READ); - if (result != FR_OK) { - return NULL; - } - - if (f_size(&bmpFile) < 14) { - f_close(&bmpFile); - return NULL; - } - - result = f_read(&bmpFile, buf, 14, &read); - if (result != FR_OK || read != 14) { - f_close(&bmpFile); - return NULL; - } - - if (buf[0] != 'B' || buf[1] != 'M') { - f_close(&bmpFile); - return NULL; - } - - uint32_t fsize = *((uint32_t *)&buf[2]); - uint32_t hsize = *((uint32_t *)&buf[10]); /* header size */ - - uint32_t len = limit((uint32_t)4, (uint32_t)(hsize-14), (uint32_t)32); - result = f_read(&bmpFile, buf, len, &read); - if (result != FR_OK || read != len) { - f_close(&bmpFile); - return NULL; - } - - uint32_t ihsize = *((uint32_t *)&buf[0]); /* more header size */ - - /* invalid header size */ - if (ihsize + 14 > hsize) { - f_close(&bmpFile); - return NULL; - } - - /* sometimes file size is set to some headers size, set a real size in that case */ - if (fsize == 14 || fsize == ihsize + 14) - fsize = f_size(&bmpFile) - 2; - - /* declared file size less than header size */ - if (fsize <= hsize) { - f_close(&bmpFile); - return NULL; - } - - uint32_t w, h; - - switch (ihsize){ - case 40: // windib - case 56: // windib v3 - case 64: // OS/2 v2 - case 108: // windib v4 - case 124: // windib v5 - w = *((uint32_t *)&buf[4]); - h = *((uint32_t *)&buf[8]); - buf += 12; - break; - case 12: // OS/2 v1 - w = *((uint16_t *)&buf[4]); - h = *((uint16_t *)&buf[6]); - buf += 8; - break; - default: - f_close(&bmpFile); - return NULL; - } - - if (*((uint16_t *)&buf[0]) != 1) { /* planes */ - f_close(&bmpFile); - return NULL; - } - - uint16_t depth = *((uint16_t *)&buf[2]); - - buf = &bmpBuf[0]; - - if (depth == 4) { - if (f_lseek(&bmpFile, hsize-64) != FR_OK || f_read(&bmpFile, buf, 64, &read) != FR_OK || read != 64) { - f_close(&bmpFile); - return NULL; - } - for (uint8_t i=0; i<16; i++) { - palette[i] = buf[4*i]; - } - } - else { - if (f_lseek(&bmpFile, hsize) != FR_OK) { - f_close(&bmpFile); - return NULL; - } - } - - uint8_t * bmp = (uint8_t *)malloc(BITMAP_BUFFER_SIZE(w, h)); - uint16_t * dest = (uint16_t *)bmp; - if (bmp == NULL) { - f_close(&bmpFile); - return NULL; - } - - *dest++ = w; - *dest++ = h; - memset(dest, 0, BITMAP_BUFFER_SIZE(w, h) - 4); - - uint32_t rowSize; - - switch (depth) { - case 32: - for (int i=h-1; i>=0; i--) { - uint8_t * dst = ((uint8_t *)dest) + i*w*2; - for (unsigned int j=0; j>24) & 0xff, (pixel>>16) & 0xff, (pixel>>8) & 0xff); - dst += 2; - } - } - break; - - case 1: - break; - - case 4: - rowSize = ((4*w+31)/32)*4; - for (int32_t i=h-1; i>=0; i--) { - result = f_read(&bmpFile, buf, rowSize, &read); - if (result != FR_OK || read != rowSize) { - f_close(&bmpFile); - free(bmp); - return NULL; - } - uint8_t * dst = ((uint8_t *)dest) + i*w*2; - for (uint32_t j=0; j> ((j & 1) ? 0 : 4)) & 0x0F; - uint8_t val = palette[index]; - *((uint16_t *)dst) = RGB(val, val, val); - dst += 2; - // *dst++ = 0x0F; - } - } - break; - - default: - f_close(&bmpFile); - free(bmp); - return NULL; - } - - f_close(&bmpFile); - return bmp; -} -#endif - -const uint8_t bmpHeader[] = { - 0x42, 0x4d, 0xF8, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x28, 0x00, - 0x00, 0x00, 212, 0x00, 0x00, 0x00, 64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0xbc, 0x38, 0x00, 0x00, 0xbc, 0x38, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xee, 0xee, 0xee, 0x00, 0xdd, 0xdd, - 0xdd, 0x00, 0xcc, 0xcc, 0xcc, 0x00, 0xbb, 0xbb, 0xbb, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x99, 0x99, - 0x99, 0x00, 0x88, 0x88, 0x88, 0x00, 0x77, 0x77, 0x77, 0x00, 0x66, 0x66, 0x66, 0x00, 0x55, 0x55, - 0x55, 0x00, 0x44, 0x44, 0x44, 0x00, 0x33, 0x33, 0x33, 0x00, 0x22, 0x22, 0x22, 0x00, 0x11, 0x11, - 0x11, 0x00, 0x00, 0x00, 0x00, 0x00 -}; - -inline display_t getPixel(unsigned int x, unsigned int y) -{ - if (x>=LCD_W || y>=LCD_H) - return 0; - display_t * p = &displayBuf[y / 2 * LCD_W + x]; - return (y & 1) ? (*p >> 4) : (*p & 0x0F); -} - -const char *writeScreenshot() -{ - FIL bmpFile; - UINT written; - char filename[42]; // /SCREENSHOTS/screen-2013-01-01-123540.bmp - - // check and create folder here - strcpy_P(filename, SCREENSHOTS_PATH); - const char * error = sdCheckAndCreateDirectory(filename); - if (error) { - return error; - } - - char * tmp = strAppend(&filename[sizeof(SCREENSHOTS_PATH)-1], "/screen"); - tmp = strAppendDate(tmp, true); - strcpy(tmp, BITMAPS_EXT); - - FRESULT result = f_open(&bmpFile, filename, FA_CREATE_ALWAYS | FA_WRITE); - if (result != FR_OK) { - return SDCARD_ERROR(result); - } - - result = f_write(&bmpFile, bmpHeader, sizeof(bmpHeader), &written); - if (result != FR_OK || written != sizeof(bmpHeader)) { - f_close(&bmpFile); - return SDCARD_ERROR(result); - } - - for (int y=LCD_H-1; y>=0; y-=1) { - for (int x=0; x<8*((LCD_W+7)/8); x+=2) { - uint8_t byte = getPixel(x+1, y) + (getPixel(x, y) << 4); - f_write(&bmpFile, &byte, 1, &written); - if (result != FR_OK || written != 1) { - f_close(&bmpFile); - return SDCARD_ERROR(result); - } - } - } - - f_close(&bmpFile); - - return NULL; -} - -#if defined(PCBHORUS) - - -#define STB_IMAGE_IMPLEMENTATION -#define STBI_ONLY_PNG -#define STBI_ONLY_JPEG -#define STBI_ONLY_BMP -#define STBI_NO_STDIO -#include "thirdparty/Stb/stb_image.h" - - -// fill 'data' with 'size' bytes. return number of bytes actually read -int stbc_read(void *user, char *data, int size) -{ - FIL * fp = (FIL *)user; - UINT br = 0; - FRESULT res = f_read(fp, data, size, &br); - if (res == FR_OK) { - return (int)br; - } - return 0; -} - -// skip the next 'n' bytes, or 'unget' the last -n bytes if negative -void stbc_skip(void *user, int n) -{ - FIL * fp = (FIL *)user; - f_lseek(fp, f_tell(fp) + n); -} - -// returns nonzero if we are at end of file/data -int stbc_eof(void *user) -{ - FIL * fp = (FIL *)user; - return f_eof(fp); -} - -// callbacks for stb-image -const stbi_io_callbacks stbCallbacks = { - stbc_read, - stbc_skip, - stbc_eof -}; - - -const char * imgLoad(uint8_t * bmp, const char * filename, uint16_t width, uint16_t height) -{ - FIL imgFile; - - // if (width > LCD_W) { - // return STR_INCOMPATIBLE; - // } - - FRESULT result = f_open(&imgFile, filename, FA_OPEN_EXISTING | FA_READ); - if (result != FR_OK) { - return SDCARD_ERROR(result); - } - - // if (f_size(&bmpFile) < 14) { - // f_close(&bmpFile); - // return STR_INCOMPATIBLE; - // } - - int x,y,n; - unsigned char *data = stbi_load_from_callbacks(&stbCallbacks, &imgFile, &x, &y, &n, 3); - f_close(&imgFile); - - if (!data) { - return "stb error"; - } - - //convert to 565 fromat - // todo use dma2d for conversion from 888 to 565 - unsigned char *p = data; - uint16_t * dest = (uint16_t *)bmp; - - *dest++ = min(width, x); - *dest++ = min(height, y); - - for(int row = 0; row < min(height, y); ++row) { - unsigned char *l = p; - for(int col = 0; col < min(width, x); ++col) { - *dest = RGB(l[0], l[1], l[2]); - ++dest; - l += 3; - } - p += 3 * x; - } - stbi_image_free(data); - return 0; -} - -#endif // if defined(PCBHORUS) diff --git a/radio/src/gui/gui_helpers.h b/radio/src/gui/gui_helpers.h index 0ce944586..9c1238055 100644 --- a/radio/src/gui/gui_helpers.h +++ b/radio/src/gui/gui_helpers.h @@ -2,7 +2,7 @@ * Copyright (C) OpenTX * * Based on code named - * th9x - http://code.google.com/p/th9x + * th9x - http://code.google.com/p/th9x * er9x - http://code.google.com/p/er9x * gruvin9x - http://code.google.com/p/gruvin9x * @@ -23,7 +23,7 @@ typedef bool (*IsValueAvailable)(int); -int circularIncDec(int current, int inc, int min, int max, IsValueAvailable isValueAvailable); +int circularIncDec(int current, int inc, int min, int max, IsValueAvailable isValueAvailable=NULL); int getFirstAvailable(int min, int max, IsValueAvailable isValueAvailable); #if defined(VIRTUALINPUTS) diff --git a/radio/src/gui/horus/bitmapbuffer.cpp b/radio/src/gui/horus/bitmapbuffer.cpp new file mode 100644 index 000000000..7a29728a9 --- /dev/null +++ b/radio/src/gui/horus/bitmapbuffer.cpp @@ -0,0 +1,640 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include +#include "opentx.h" + +void BitmapBuffer::drawAlphaPixel(display_t * p, uint8_t opacity, uint16_t color) +{ + if (opacity == OPACITY_MAX) { + drawPixel(p, color); + } + else if (opacity != 0) { + uint8_t bgWeight = OPACITY_MAX - opacity; + COLOR_SPLIT(color, red, green, blue); + COLOR_SPLIT(*p, bgRed, bgGreen, bgBlue); + uint16_t r = (bgRed * bgWeight + red * opacity) / OPACITY_MAX; + uint16_t g = (bgGreen * bgWeight + green * opacity) / OPACITY_MAX; + uint16_t b = (bgBlue * bgWeight + blue * opacity) / OPACITY_MAX; + drawPixel(p, COLOR_JOIN(r, g, b)); + } +} + +void BitmapBuffer::drawHorizontalLine(coord_t x, coord_t y, coord_t w, uint8_t pat, LcdFlags att) +{ + if (y >= height) return; + if (x+w > width) { w = width - x; } + + display_t * p = getPixelPtr(x, y); + display_t color = lcdColorTable[COLOR_IDX(att)]; + uint8_t opacity = 0x0F - (att >> 24); + + if (pat == SOLID) { + while (w--) { + drawAlphaPixel(p, opacity, color); + p++; + } + } + else { + while (w--) { + if (pat & 1) { + drawAlphaPixel(p, opacity, color); + pat = (pat >> 1) | 0x80; + } + else { + pat = pat >> 1; + } + p++; + } + } +} + +void BitmapBuffer::drawVerticalLine(coord_t x, coord_t y, coord_t h, uint8_t pat, LcdFlags att) +{ + if (x >= width) return; + if (y >= height) return; + if (h<0) { y+=h; h=-h; } + if (y<0) { h+=y; y=0; if (h<=0) return; } + if (y+h > height) { h = height - y; } + + display_t color = lcdColorTable[COLOR_IDX(att)]; + uint8_t opacity = 0x0F - (att >> 24); + + if (pat == SOLID) { + while (h--) { + drawAlphaPixel(x, y, opacity, color); + y++; + } + } + else { + if (pat==DOTTED && !(y%2)) { + pat = ~pat; + } + while (h--) { + if (pat & 1) { + drawAlphaPixel(x, y, opacity, color); + pat = (pat >> 1) | 0x80; + } + else { + pat = pat >> 1; + } + y++; + } + } +} + +void BitmapBuffer::drawFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t pat, LcdFlags att) +{ + for (coord_t i=y; i= 360 || endAngle <= 0) + return false; + + if (startAngle == 0) { + slopes[1] = 100000; + slopes[2] = -100000; + } + else { + float angle1 = float(startAngle) * PI / 180; + if (startAngle >= 180) { + slopes[1] = -100000; + slopes[2] = cos(angle1) * 100 / sin(angle1); + } + else { + slopes[1] = cos(angle1) * 100 / sin(angle1); + slopes[2] = -100000; + } + } + + if (endAngle == 360) { + slopes[0] = -100000; + slopes[3] = 100000; + } + else { + float angle2 = float(endAngle) * PI / 180; + if (endAngle >= 180) { + slopes[0] = -100000; + slopes[3] = -cos(angle2) * 100 / sin(angle2); + } + else { + slopes[0] = cos(angle2) * 100 / sin(angle2); + slopes[3] = -100000; + } + } + + return true; +} + +void BitmapBuffer::drawPie(int x0, int y0, int radius, int startAngle, int endAngle) +{ + int slopes[4]; + if (!evalSlopes(slopes, startAngle, endAngle)) + return; + + for (int y=0; y<=radius; y++) { + for (int x=0; x<=radius; x++) { + if (x*x+y*y <= radius*radius) { + int slope = (x==0 ? (y<0 ? -99000 : 99000) : y*100/x); + if (slope >= slopes[0] && slope < slopes[1]) { + drawPixel(x0+x, y0-y, WHITE); + } + if (-slope >= slopes[0] && -slope < slopes[1]) { + drawPixel(x0+x, y0+y, WHITE); + } + if (slope >= slopes[2] && slope < slopes[3]) { + drawPixel(x0-x, y0-y, WHITE); + } + if (-slope >= slopes[2] && -slope < slopes[3]) { + drawPixel(x0-x, y0+y, WHITE); + } + } + } + } +} + +void BitmapBuffer::drawBitmapPattern(coord_t x, coord_t y, const uint8_t * bmp, LcdFlags flags, coord_t offset, coord_t width) +{ + coord_t w = *((uint16_t *)bmp); + coord_t height = *(((uint16_t *)bmp)+1); + + if (!width || width > w) { + width = w; + } + + if (x+width > this->width) { + width = this->width-x; + } + + display_t color = lcdColorTable[COLOR_IDX(flags)]; + + for (coord_t row=0; row 0) drawBitmapPattern(x, y, font, flags, offset, width); + lcdNextPos = x + width; +} + +void BitmapBuffer::drawSizedText(coord_t x, coord_t y, const pm_char * s, uint8_t len, LcdFlags flags) +{ + int width = getTextWidth(s, len, flags); + int height = getFontHeight(flags); + int fontindex = FONTSIZE(flags) >> 8; + const pm_uchar * font = fontsTable[fontindex]; + const uint16_t * fontspecs = fontspecsTable[fontindex]; + + if (flags & RIGHT) + x -= width; + else if (flags & CENTERED) + x -= width/2; + + if ((flags&INVERS) && ((~flags & BLINK) || BLINK_ON_PHASE)) { + flags = TEXT_INVERTED_COLOR | (flags & 0x0ffff); + if (FONTSIZE(flags) == TINSIZE) + drawSolidFilledRect(x-INVERT_HORZ_MARGIN+2, y-INVERT_VERT_MARGIN+2, width+2*INVERT_HORZ_MARGIN-5, INVERT_LINE_HEIGHT-7, TEXT_INVERTED_BGCOLOR); + else if (FONTSIZE(flags) == SMLSIZE) + drawSolidFilledRect(x-INVERT_HORZ_MARGIN+1, y-INVERT_VERT_MARGIN, width+2*INVERT_HORZ_MARGIN-2, INVERT_LINE_HEIGHT, TEXT_INVERTED_BGCOLOR); + else + drawSolidFilledRect(x-INVERT_HORZ_MARGIN, y/*-INVERT_VERT_MARGIN*/, width+2*INVERT_HORZ_MARGIN, INVERT_LINE_HEIGHT, TEXT_INVERTED_BGCOLOR); + } + + char str[256]; + if (flags & ZCHAR) + strcat_zchar(str, s, len); + else + strAppend(str, s, len); + + const coord_t orig_x = x; + bool setx = false; + while (len--) { + unsigned char c; + if (flags & ZCHAR) + c = idx2char(*s); + else + c = pgm_read_byte(s); + if (setx) { + x = c; + setx = false; + } + else if (!c) { + break; + } + else if (c >= 0x20) { + drawFontPattern(x, y, font, fontspecs, getMappedChar(c), flags); + x = lcdNextPos; + } + else if (c == 0x1F) { // X-coord prefix + setx = true; + } + else if (c == 0x1E) { + x = orig_x; + y += height; + } + else if (c == 1) { + x += 1; + } + else { + x += 2*(c-1); + } + s++; + } + lcdNextPos = x; +} + +void BitmapBuffer::drawBitmapPie(int x0, int y0, const uint16_t * img, int startAngle, int endAngle) +{ + const uint16_t * q = img; + coord_t width = *q++; + coord_t height = *q++; + + int slopes[4]; + if (!evalSlopes(slopes, startAngle, endAngle)) + return; + + int w2 = width/2; + int h2 = height/2; + + for (int y=h2-1; y>=0; y--) { + for (int x=w2-1; x>=0; x--) { + int slope = (x==0 ? (y<0 ? -99000 : 99000) : y*100/x); + if (slope >= slopes[0] && slope < slopes[1]) { + *getPixelPtr(x0+w2+x, y0+h2-y) = q[(h2-y)*width + w2+x]; + } + if (-slope >= slopes[0] && -slope < slopes[1]) { + *getPixelPtr(x0+w2+x, y0+h2+y) = q[(h2+y)*width + w2+x]; + } + if (slope >= slopes[2] && slope < slopes[3]) { + *getPixelPtr(x0+w2-x, y0+h2-y) = q[(h2-y)*width + w2-x]; + } + if (-slope >= slopes[2] && -slope < slopes[3]) { + *getPixelPtr(x0+w2-x, y0+h2+y) = q[(h2+y)*width + w2-x]; + } + } + } +} + +void BitmapBuffer::drawBitmapPatternPie(coord_t x0, coord_t y0, const uint8_t * img, LcdFlags flags, int startAngle, int endAngle) +{ + coord_t width = *((uint16_t *)img); + coord_t height = *(((uint16_t *)img)+1); + const uint8_t * q = img+4; + + int slopes[4]; + if (!evalSlopes(slopes, startAngle, endAngle)) + return; + + display_t color = lcdColorTable[COLOR_IDX(flags)]; + + int w2 = width/2; + int h2 = height/2; + + for (int y=h2-1; y>=0; y--) { + for (int x=w2-1; x>=0; x--) { + int slope = (x==0 ? (y<0 ? -99000 : 99000) : y*100/x); + if (slope >= slopes[0] && slope < slopes[1]) { + drawAlphaPixel(x0+w2+x, y0+h2-y, q[(h2-y)*width + w2+x], color); + } + if (-slope >= slopes[0] && -slope < slopes[1]) { + drawAlphaPixel(x0+w2+x, y0+h2+y, q[(h2+y)*width + w2+x], color); + } + if (slope >= slopes[2] && slope < slopes[3]) { + drawAlphaPixel(x0+w2-x, y0+h2-y, q[(h2-y)*width + w2-x], color); + } + if (-slope >= slopes[2] && -slope < slopes[3]) { + drawAlphaPixel(x0+w2-x, y0+h2+y, q[(h2+y)*width + w2-x], color); + } + } + } +} + +BitmapBuffer * BitmapBuffer::load(const char * filename) +{ + FIL bmpFile; + UINT read; + uint8_t palette[16]; + uint8_t bmpBuf[LCD_W]; /* maximum with LCD_W */ + uint8_t * buf = &bmpBuf[0]; + + FRESULT result = f_open(&bmpFile, filename, FA_OPEN_EXISTING | FA_READ); + if (result != FR_OK) { + return NULL; + } + + if (f_size(&bmpFile) < 14) { + f_close(&bmpFile); + return NULL; + } + + result = f_read(&bmpFile, buf, 14, &read); + if (result != FR_OK || read != 14) { + f_close(&bmpFile); + return NULL; + } + + if (buf[0] != 'B' || buf[1] != 'M') { + f_close(&bmpFile); + return NULL; + } + + uint32_t fsize = *((uint32_t *)&buf[2]); + uint32_t hsize = *((uint32_t *)&buf[10]); /* header size */ + + uint32_t len = limit((uint32_t)4, (uint32_t)(hsize-14), (uint32_t)32); + result = f_read(&bmpFile, buf, len, &read); + if (result != FR_OK || read != len) { + f_close(&bmpFile); + return NULL; + } + + uint32_t ihsize = *((uint32_t *)&buf[0]); /* more header size */ + + /* invalid header size */ + if (ihsize + 14 > hsize) { + f_close(&bmpFile); + return NULL; + } + + /* sometimes file size is set to some headers size, set a real size in that case */ + if (fsize == 14 || fsize == ihsize + 14) + fsize = f_size(&bmpFile) - 2; + + /* declared file size less than header size */ + if (fsize <= hsize) { + f_close(&bmpFile); + return NULL; + } + + uint32_t w, h; + + switch (ihsize){ + case 40: // windib + case 56: // windib v3 + case 64: // OS/2 v2 + case 108: // windib v4 + case 124: // windib v5 + w = *((uint32_t *)&buf[4]); + h = *((uint32_t *)&buf[8]); + buf += 12; + break; + case 12: // OS/2 v1 + w = *((uint16_t *)&buf[4]); + h = *((uint16_t *)&buf[6]); + buf += 8; + break; + default: + f_close(&bmpFile); + return NULL; + } + + if (*((uint16_t *)&buf[0]) != 1) { /* planes */ + f_close(&bmpFile); + return NULL; + } + + uint16_t depth = *((uint16_t *)&buf[2]); + + buf = &bmpBuf[0]; + + if (depth == 4) { + if (f_lseek(&bmpFile, hsize-64) != FR_OK || f_read(&bmpFile, buf, 64, &read) != FR_OK || read != 64) { + f_close(&bmpFile); + return NULL; + } + for (uint8_t i=0; i<16; i++) { + palette[i] = buf[4*i]; + } + } + else { + if (f_lseek(&bmpFile, hsize) != FR_OK) { + f_close(&bmpFile); + return NULL; + } + } + + BitmapBuffer * bmp = new BitmapBuffer(w, h); + if (bmp == NULL) { + f_close(&bmpFile); + return NULL; + } + + uint16_t * dest = bmp->data; + uint32_t rowSize; + + switch (depth) { + case 32: + for (int i=h-1; i>=0; i--) { + uint8_t * dst = ((uint8_t *)dest) + i*w*2; + for (unsigned int j=0; j>24) & 0xff, (pixel>>16) & 0xff, (pixel>>8) & 0xff); + dst += 2; + } + } + break; + + case 1: + break; + + case 4: + rowSize = ((4*w+31)/32)*4; + for (int32_t i=h-1; i>=0; i--) { + result = f_read(&bmpFile, buf, rowSize, &read); + if (result != FR_OK || read != rowSize) { + f_close(&bmpFile); + free(bmp); + return NULL; + } + uint8_t * dst = ((uint8_t *)dest) + i*w*2; + for (uint32_t j=0; j> ((j & 1) ? 0 : 4)) & 0x0F; + uint8_t val = palette[index]; + *((uint16_t *)dst) = RGB(val, val, val); + dst += 2; + // *dst++ = 0x0F; + } + } + break; + + default: + f_close(&bmpFile); + free(bmp); + return NULL; + } + + f_close(&bmpFile); + return bmp; +} + + +#define STB_IMAGE_IMPLEMENTATION +#define STBI_ONLY_PNG +#define STBI_ONLY_JPEG +#define STBI_ONLY_BMP +#define STBI_NO_STDIO +#include "thirdparty/Stb/stb_image.h" + + +// fill 'data' with 'size' bytes. return number of bytes actually read +int stbc_read(void *user, char *data, int size) +{ + FIL * fp = (FIL *)user; + UINT br = 0; + FRESULT res = f_read(fp, data, size, &br); + if (res == FR_OK) { + return (int)br; + } + return 0; +} + +// skip the next 'n' bytes, or 'unget' the last -n bytes if negative +void stbc_skip(void *user, int n) +{ + FIL * fp = (FIL *)user; + f_lseek(fp, f_tell(fp) + n); +} + +// returns nonzero if we are at end of file/data +int stbc_eof(void *user) +{ + FIL * fp = (FIL *)user; + return f_eof(fp); +} + +// callbacks for stb-image +const stbi_io_callbacks stbCallbacks = { + stbc_read, + stbc_skip, + stbc_eof +}; + +const char * imgLoad(uint8_t * bmp, const char * filename, uint16_t width, uint16_t height) +{ + FIL imgFile; + + FRESULT result = f_open(&imgFile, filename, FA_OPEN_EXISTING | FA_READ); + if (result != FR_OK) { + return SDCARD_ERROR(result); + } + + int x,y,n; + unsigned char *data = stbi_load_from_callbacks(&stbCallbacks, &imgFile, &x, &y, &n, 3); + f_close(&imgFile); + + if (!data) { + return "stb error"; + } + + //convert to 565 fromat + // todo use dma2d for conversion from 888 to 565 + unsigned char *p = data; + uint16_t * dest = (uint16_t *)bmp; + + *dest++ = min(width, x); + *dest++ = min(height, y); + + for(int row = 0; row < min(height, y); ++row) { + unsigned char *l = p; + for(int col = 0; col < min(width, x); ++col) { + *dest = RGB(l[0], l[1], l[2]); + ++dest; + l += 3; + } + p += 3 * x; + } + stbi_image_free(data); + return 0; +} + +float getBitmapScale(const BitmapBuffer * bitmap, int width, int height) +{ + float widthScale = float(width) / bitmap->getWidth(); + float heightScale = float(height) / bitmap->getHeight(); + return min(widthScale, heightScale); +} diff --git a/radio/src/gui/horus/bitmapbuffer.h b/radio/src/gui/horus/bitmapbuffer.h new file mode 100644 index 000000000..a70d8eff3 --- /dev/null +++ b/radio/src/gui/horus/bitmapbuffer.h @@ -0,0 +1,242 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _BITMAP_BUFFER_H_ +#define _BITMAP_BUFFER_H_ + +#include +#include "colors.h" + +// TODO should go to lcd.h again +typedef int coord_t; +typedef uint32_t LcdFlags; +typedef uint16_t display_t; + +inline int getBitmapScaledSize(int size, float scale) +{ + if (scale == 0.0) + return size; + else + return (0.5 + size) * scale; +} + +template +class BitmapBufferBase +{ + public: + BitmapBufferBase(int width, int height, T * data): + width(width), + height(height), + data(data) + { + } + + int getWidth() const + { + return width; + } + + int getHeight() const + { + return height; + } + + protected: + int width; + int height; + + public: // TODO protected + T * data; +}; + +typedef BitmapBufferBase Bitmap; + +class BitmapBuffer: public BitmapBufferBase +{ + public: + + BitmapBuffer(int width, int height): + BitmapBufferBase(width, height, NULL) + { + data = (uint16_t *)malloc(width*height*sizeof(uint16_t)); + } + + BitmapBuffer(int width, int height, uint16_t * data): + BitmapBufferBase(width, height, data) + { + } + + ~BitmapBuffer() + { + free(data); + } + + inline void clear() + { + drawSolidFilledRect(0, 0, width, height, 0); + } + + inline void drawPixel(display_t * p, display_t value) + { + *p = value; + } + + inline display_t * getPixelPtr(coord_t x, coord_t y) + { + return &data[y*width + x]; + } + + inline void drawPixel(coord_t x, coord_t y, display_t value) + { + display_t * p = getPixelPtr(x, y); + drawPixel(p, value); + } + + void drawAlphaPixel(display_t * p, uint8_t opacity, uint16_t color); + + inline void drawAlphaPixel(coord_t x, coord_t y, uint8_t opacity, uint16_t color) + { + display_t * p = getPixelPtr(x, y); + drawAlphaPixel(p, opacity, color); + } + + void drawHorizontalLine(coord_t x, coord_t y, coord_t w, uint8_t pat, LcdFlags att); + + void drawVerticalLine(coord_t x, coord_t y, coord_t h, uint8_t pat, LcdFlags att); + + inline void drawSolidFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, LcdFlags flags) + { + DMAFillRect(data, width, x, y, w, h, lcdColorTable[COLOR_IDX(flags)]); + } + + void drawFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t pat, LcdFlags att); + + void invertRect(coord_t x, coord_t y, coord_t w, coord_t h, LcdFlags att); + + void drawCircle(int x0, int y0, int radius); + + void drawPie(int x0, int y0, int radius, int startAngle, int endAngle); + + void drawBitmapPie(int x0, int y0, const uint16_t * img, int startAngle, int endAngle); + + void drawBitmapPatternPie(coord_t x0, coord_t y0, const uint8_t * img, LcdFlags flags, int startAngle, int endAngle); + + static BitmapBuffer * load(const char * filename); + + void drawBitmapPattern(coord_t x, coord_t y, const uint8_t * bmp, LcdFlags flags, coord_t offset=0, coord_t width=0); + + void drawFontPattern(coord_t x, coord_t y, const uint8_t * font, const uint16_t * spec, int index, LcdFlags flags); + + void drawSizedText(coord_t x, coord_t y, const pm_char * s, uint8_t len, LcdFlags flags); + + template + void drawBitmap(coord_t x, coord_t y, const T * bmp, coord_t srcx=0, coord_t srcy=0, coord_t w=0, coord_t h=0, float scale=0) + { + int srcw = bmp->getWidth(); + int srch = bmp->getHeight(); + + if (w == 0) + w = srcw; + if (h == 0) + h = srch; + if (srcx+w > srcw) + w = srcw - srcx; + if (srcy+h > srch) + h = srch - srcy; + + if (scale == 0) { + if (x + w > width) { + w = width - x; + } + if (y + h > height) { + h = height - y; + } + if (srcw == w) { + DMACopyBitmap(data, width, x, y, &bmp->data[srcw*srcy], srcw, h); + } + else { + for (int i=0; idata[srcw*(srcy+i)+srcx], w, 1); + } + } + } + else { + int scaledw = w * scale; + int scaledh = h * scale; + + if (x + scaledw > width) + scaledw = width - x; + if (y + scaledh > height) + scaledh = height - y; + + for (int i = 0; i < scaledh; i++) { + uint16_t * p = &data[(y + i) * width + x]; + const uint16_t * qstart = &bmp->data[(srcy + int(i / scale)) * bmp->getWidth() + srcx]; + for (int j = 0; j < scaledw; j++) { + const uint16_t * q = qstart + int(j / scale); + *p = *q; + p++; + } + } + } + } + + template + void drawScaledBitmap(const T * bitmap, coord_t x, coord_t y, coord_t w, coord_t h) + { + coord_t bitmapWidth = bitmap->getWidth(); + + float scale = float(h) / bitmap->getHeight(); + int width = getBitmapScaledSize(bitmapWidth, scale); + if (width > w) { + int ww = (0.5 + w) / scale; + drawBitmap(x, y, bitmap, (bitmapWidth - ww)/2, 0, ww, 0, scale); + } + else { + drawBitmap(x+(w-width)/2, y, bitmap, 0, 0, 0, 0, scale); + } + } + + template + void drawAlphaBitmap(coord_t x, coord_t y, const T * bmp) + { + int width = bmp->getWidth(); + int height = bmp->getHeight(); + + if (width == 0 || height == 0) { + return; + } + + for (coord_t line=0; linedata) + line*width*2; + for (coord_t col=0; col> 4, ((q[1] & 0x0f) << 12) + ((q[0] & 0xf0) << 3) + ((q[0] & 0x0f) << 1)); + p++; q+=2; + } + } + } +}; + +float getBitmapScale(const BitmapBuffer * bitmap, int width, int height); + +extern BitmapBuffer * lcd; + +#endif // _BITMAP_BUFFER_H_ diff --git a/radio/src/gui/horus/bitmaps.cpp b/radio/src/gui/horus/bitmaps.cpp index ff628a8d8..9a96bfb65 100644 --- a/radio/src/gui/horus/bitmaps.cpp +++ b/radio/src/gui/horus/bitmaps.cpp @@ -18,7 +18,7 @@ * GNU General Public License for more details. */ -#include "../../opentx.h" +#include "opentx.h" /* * Header bitmaps @@ -268,30 +268,10 @@ const uint8_t LBM_STAR1[] = { #include "mask_library_star_1.lbm" }; -/* - * Calibration screen - */ - -const uint8_t LBM_HORUS[] = { -#include "alpha_horus.lbm" -}; - -const uint8_t LBM_STICK_BACKGROUND[] = { -#include "alpha_stick_background.lbm" -}; - -const uint8_t LBM_STICK_POINTER[] = { -#include "alpha_stick_pointer.lbm" -}; - /* * Other */ -const uint8_t LBM_ASTERISK[] = { -#include "alpha_asterisk.lbm" -}; - const uint8_t LBM_POINT[] = { #include "mask_point.lbm" }; @@ -308,14 +288,6 @@ const uint8_t LBM_CURVE_COORD_SHADOW[] = { #include "mask_coord_shadow.lbm" }; -const uint8_t LBM_SHUTDOWN[] = { -#include "alpha_shutdown.lbm" -}; - -const uint8_t LBM_SLEEP[] __ALIGNED = { -#include "bmp_sleep.lbm" -}; - const uint8_t LBM_SHUTDOWN_CIRCLE[] = { #include "mask_shutdown_circle.lbm" }; @@ -348,14 +320,6 @@ const uint8_t LBM_CARROUSSEL_RIGHT[] = { #include "mask_carroussel_right.lbm" }; -const uint8_t LBM_BUTTON_ON[] = { -#include "alpha_button_on.lbm" -}; - -const uint8_t LBM_BUTTON_OFF[] = { -#include "alpha_button_off.lbm" -}; - const uint8_t LBM_SWIPE_CIRCLE[] = { #include "mask_swipe_circle.lbm" }; @@ -367,4 +331,3 @@ const uint8_t LBM_SWIPE_LEFT[] = { const uint8_t LBM_SWIPE_RIGHT[] = { #include "mask_swipe_right.lbm" }; - diff --git a/radio/src/gui/horus/bitmaps.h b/radio/src/gui/horus/bitmaps.h index bcb4d9f25..e85aea784 100644 --- a/radio/src/gui/horus/bitmaps.h +++ b/radio/src/gui/horus/bitmaps.h @@ -65,20 +65,12 @@ extern const uint8_t LBM_SCORE1[]; extern const uint8_t LBM_STAR0[]; extern const uint8_t LBM_STAR1[]; -// Calibration screen -extern const uint8_t LBM_HORUS[]; -extern const uint8_t LBM_STICK_BACKGROUND[]; -extern const uint8_t LBM_STICK_POINTER[]; - // Other icons extern const uint8_t LBM_SPLASH[]; -extern const uint8_t LBM_ASTERISK[]; extern const uint8_t LBM_POINT[]; extern const uint8_t LBM_CURVE_POINT[]; extern const uint8_t LBM_CURVE_POINT_CENTER[]; extern const uint8_t LBM_CURVE_COORD_SHADOW[]; -extern const uint8_t LBM_SHUTDOWN[]; -extern const uint8_t LBM_SLEEP[]; extern const uint8_t LBM_SHUTDOWN_CIRCLE[]; // Slider bitmaps @@ -92,10 +84,6 @@ extern const uint8_t LBM_SLIDER_POINT_IN[]; extern const uint8_t LBM_CARROUSSEL_LEFT[]; extern const uint8_t LBM_CARROUSSEL_RIGHT[]; -// Button bitmaps -extern const uint8_t LBM_BUTTON_ON[]; -extern const uint8_t LBM_BUTTON_OFF[]; - extern const uint8_t LBM_SWIPE_CIRCLE[]; extern const uint8_t LBM_SWIPE_LEFT[]; extern const uint8_t LBM_SWIPE_RIGHT[]; diff --git a/radio/src/gui/horus/colors.h b/radio/src/gui/horus/colors.h new file mode 100644 index 000000000..c64f89188 --- /dev/null +++ b/radio/src/gui/horus/colors.h @@ -0,0 +1,116 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _COLORS_H_ +#define _COLORS_H_ + +// remove windows default definitions +#undef OPAQUE +#undef RGB + +#define TO5BITS(x) ((x) >> 3) +#define TO6BITS(x) ((x) >> 2) +#define RGB(r, g, b) ((TO5BITS(r) << 11) + (TO6BITS(g) << 5) + (TO5BITS(b) << 0)) +#define WHITE RGB(0xFF, 0xFF, 0xFF) +#define BLACK RGB(0, 0, 0) +#define YELLOW RGB(0xF0, 0xD0, 0x10) +#define BLUE RGB(0x30, 0xA0, 0xE0) +#define GREY RGB(96, 96, 96) +#define DARKGREY RGB(64, 64, 64) +#define LIGHTGREY RGB(180, 180, 180) +#define RED RGB(229, 32, 30) +#define DARKRED RGB(160, 0, 6) + +#define OPACITY_MAX 0x0F +#define OPACITY(x) ((x)<<24) + +enum LcdColorIndex +{ + TEXT_COLOR_INDEX, + TEXT_BGCOLOR_INDEX, + TEXT_INVERTED_COLOR_INDEX, + TEXT_INVERTED_BGCOLOR_INDEX, + LINE_COLOR_INDEX, + SCROLLBOX_COLOR_INDEX, + MENU_TITLE_BGCOLOR_INDEX, + MENU_TITLE_COLOR_INDEX, + MENU_TITLE_DISABLE_COLOR_INDEX, + HEADER_COLOR_INDEX, + ALARM_COLOR_INDEX, + WARNING_COLOR_INDEX, + TEXT_DISABLE_COLOR_INDEX, + CURVE_AXIS_COLOR_INDEX, + CURVE_COLOR_INDEX, + CURVE_CURSOR_COLOR_INDEX, + HEADER_BGCOLOR_INDEX, + HEADER_ICON_BGCOLOR_INDEX, + HEADER_CURRENT_BGCOLOR_INDEX, + TITLE_BGCOLOR_INDEX, + TRIM_BGCOLOR_INDEX, + TRIM_SHADOW_COLOR_INDEX, + MAINVIEW_PANES_COLOR_INDEX, + MAINVIEW_GRAPHICS_COLOR_INDEX, + OVERLAY_COLOR_INDEX, + CUSTOM_COLOR_INDEX, + LCD_COLOR_COUNT +}; + +extern uint16_t lcdColorTable[LCD_COLOR_COUNT]; + +#define COLOR(index) ((index) << 16) +#define COLOR_IDX(att) uint8_t((att) >> 16) + +#define TEXT_COLOR COLOR(TEXT_COLOR_INDEX) +#define TEXT_BGCOLOR COLOR(TEXT_BGCOLOR_INDEX) +#define TEXT_INVERTED_COLOR COLOR(TEXT_INVERTED_COLOR_INDEX) +#define TEXT_INVERTED_BGCOLOR COLOR(TEXT_INVERTED_BGCOLOR_INDEX) +#define LINE_COLOR COLOR(LINE_COLOR_INDEX) +#define SCROLLBOX_COLOR COLOR(SCROLLBOX_COLOR_INDEX) +#define HEADER_SEPARATOR_COLOR COLOR(HEADER_SEPARATOR_COLOR_INDEX) +#define MENU_TITLE_BGCOLOR COLOR(MENU_TITLE_BGCOLOR_INDEX) +#define MENU_TITLE_COLOR COLOR(MENU_TITLE_COLOR_INDEX) +#define MENU_TITLE_DISABLE_COLOR COLOR(MENU_TITLE_DISABLE_COLOR_INDEX) +#define HEADER_COLOR COLOR(HEADER_COLOR_INDEX) +#define ALARM_COLOR COLOR(ALARM_COLOR_INDEX) +#define WARNING_COLOR COLOR(WARNING_COLOR_INDEX) +#define TEXT_DISABLE_COLOR COLOR(TEXT_DISABLE_COLOR_INDEX) +#define CURVE_AXIS_COLOR COLOR(CURVE_AXIS_COLOR_INDEX) +#define CURVE_COLOR COLOR(CURVE_COLOR_INDEX) +#define CURVE_CURSOR_COLOR COLOR(CURVE_CURSOR_COLOR_INDEX) +#define TITLE_BGCOLOR COLOR(TITLE_BGCOLOR_INDEX) +#define TRIM_BGCOLOR COLOR(TRIM_BGCOLOR_INDEX) +#define TRIM_SHADOW_COLOR COLOR(TRIM_SHADOW_COLOR_INDEX) +#define HEADER_BGCOLOR COLOR(HEADER_BGCOLOR_INDEX) +#define HEADER_ICON_BGCOLOR COLOR(HEADER_ICON_BGCOLOR_INDEX) +#define HEADER_CURRENT_BGCOLOR COLOR(HEADER_CURRENT_BGCOLOR_INDEX) +#define MAINVIEW_PANES_COLOR COLOR(MAINVIEW_PANES_COLOR_INDEX) +#define MAINVIEW_GRAPHICS_COLOR COLOR(MAINVIEW_GRAPHICS_COLOR_INDEX) +#define OVERLAY_COLOR COLOR(OVERLAY_COLOR_INDEX) +#define CUSTOM_COLOR COLOR(CUSTOM_COLOR_INDEX) + +#define COLOR_SPLIT(color, r, g, b) \ + uint16_t r = ((color) & 0xF800) >> 11; \ + uint16_t g = ((color) & 0x07E0) >> 5; \ + uint16_t b = ((color) & 0x001F) + +#define COLOR_JOIN(r, g, b) \ + (((r) << 11) + ((g) << 5) + (b)) + +#endif // _COLORS_H_ diff --git a/radio/src/gui/horus/lcd.cpp b/radio/src/gui/horus/lcd.cpp index 63dadf370..52ac733b9 100644 --- a/radio/src/gui/horus/lcd.cpp +++ b/radio/src/gui/horus/lcd.cpp @@ -26,6 +26,7 @@ display_t displayBuf[DISPLAY_BUFFER_SIZE]; #endif + uint16_t lcdColorTable[LCD_COLOR_COUNT]; coord_t lcdNextPos; @@ -52,31 +53,6 @@ int getCharWidth(char c, const uint16_t * spec) return getFontPatternWidth(spec, getMappedChar(c)); } -void lcdDrawBitmapPattern(coord_t x, coord_t y, const uint8_t * img, LcdFlags flags, coord_t offset, coord_t width) -{ - coord_t w = *((uint16_t *)img); - coord_t height = *(((uint16_t *)img)+1); - - if (!width || width > w) { - width = w; - } - - if (x+width > LCD_W) { - width = LCD_W-x; - } - - display_t color = lcdColorTable[COLOR_IDX(flags)]; - - for (coord_t row=0; row> 8]; } -float getBitmapScale(const uint8_t * bmp, int dstWidth, int dstHeight) -{ - int bmpWidth = getBitmapWidth(bmp); - int bmpHeight = getBitmapHeight(bmp); - - if (bmpWidth == 0 || bmpHeight == 0) - return 0; - - float widthScale = float(dstWidth) / bmpWidth; - float heightScale = float(dstHeight) / bmpHeight; - - return min(widthScale, heightScale); -} - int getTextWidth(const char * s, int len, LcdFlags flags) { const uint16_t * specs = fontspecsTable[FONTSIZE(flags) >> 8]; @@ -142,79 +104,12 @@ int getTextWidth(const char * s, int len, LcdFlags flags) return result; } -void lcdDrawSizedText(coord_t x, coord_t y, const pm_char * s, uint8_t len, LcdFlags flags) -{ - int width = getTextWidth(s, len, flags); - int height = getFontHeight(flags); - int fontindex = FONTSIZE(flags) >> 8; - const pm_uchar * font = fontsTable[fontindex]; - const uint16_t * fontspecs = fontspecsTable[fontindex]; - - if ((flags&INVERS) && ((~flags & BLINK) || BLINK_ON_PHASE)) { - flags = TEXT_INVERTED_COLOR | (flags & 0x0ffff); - if (FONTSIZE(flags) == TINSIZE) - lcdDrawSolidFilledRect(x-INVERT_HORZ_MARGIN+2, y-INVERT_VERT_MARGIN+2, width+2*INVERT_HORZ_MARGIN-5, INVERT_LINE_HEIGHT-7, TEXT_INVERTED_BGCOLOR); - else if (FONTSIZE(flags) == SMLSIZE) - lcdDrawSolidFilledRect(x-INVERT_HORZ_MARGIN+1, y-INVERT_VERT_MARGIN, width+2*INVERT_HORZ_MARGIN-2, INVERT_LINE_HEIGHT, TEXT_INVERTED_BGCOLOR); - else - lcdDrawSolidFilledRect(x-INVERT_HORZ_MARGIN, y/*-INVERT_VERT_MARGIN*/, width+2*INVERT_HORZ_MARGIN, INVERT_LINE_HEIGHT, TEXT_INVERTED_BGCOLOR); - } - - char str[256]; - if (flags & ZCHAR) - strcat_zchar(str, s, len); - else - strAppend(str, s, len); - - const coord_t orig_x = x; - bool setx = false; - while (len--) { - unsigned char c; - if (flags & ZCHAR) - c = idx2char(*s); - else - c = pgm_read_byte(s); - if (setx) { - x = c; - setx = false; - } - else if (!c) { - break; - } - else if (c >= 0x20) { - lcdPutFontPattern(x, y, font, fontspecs, getMappedChar(c), flags); - x = lcdNextPos; - } - else if (c == 0x1F) { // X-coord prefix - setx = true; - } - else if (c == 0x1E) { - x = orig_x; - y += height; - } - else if (c == 1) { - x += 1; - } - else { - x += 2*(c-1); - } - s++; - } - lcdNextPos = x; -} - void lcdDrawText(coord_t x, coord_t y, const pm_char * s, LcdFlags flags) { lcdDrawSizedText(x, y, s, 255, flags); } -void lcd_putsCenter(coord_t y, const pm_char * s, LcdFlags attr) -{ - int x = (LCD_W - getTextWidth(s)) / 2; - lcdDrawText(x, y, s, attr); -} - -void lcdDrawTextAtIndex(coord_t x, coord_t y, const pm_char * s,uint8_t idx, LcdFlags flags) +void lcdDrawTextAtIndex(coord_t x, coord_t y, const pm_char * s, uint8_t idx, LcdFlags flags) { uint8_t length; length = pgm_read_byte(s++); @@ -230,10 +125,6 @@ void lcdDrawHexNumber(coord_t x, coord_t y, uint32_t val, LcdFlags flags) val >>= 4; } s[4] = '\0'; - if (!(flags & LEFT)) - x -= getTextWidth(s); - else - flags -= LEFT; lcdDrawText(x, y, s, flags); } @@ -261,8 +152,7 @@ void lcdDrawNumber(coord_t x, coord_t y, int32_t val, LcdFlags flags, uint8_t le } } while (val!=0 || mode>0 || (mode==MODE(LEADING0) && idx= LCD_H) return; - if (x+w > LCD_W) { w = LCD_W - x; } - - display_t * p = PIXEL_PTR(x, y); - display_t color = lcdColorTable[COLOR_IDX(att)]; - uint8_t opacity = 0x0F - (att >> 24); - - if (pat == SOLID) { - while (w--) { - lcdDrawAlphaPixel(p, opacity, color); - p++; - } - } - else { - while (w--) { - if (pat & 1) { - lcdDrawAlphaPixel(p, opacity, color); - pat = (pat >> 1) | 0x80; - } - else { - pat = pat >> 1; - } - p++; - } - } -} - -void lcdDrawVerticalLine(coord_t x, coord_t y, coord_t h, uint8_t pat, LcdFlags att) -{ - if (x >= LCD_W) return; - if (y >= LCD_H) return; - if (h<0) { y+=h; h=-h; } - if (y<0) { h+=y; y=0; if (h<=0) return; } - if (y+h > LCD_H) { h = LCD_H - y; } - - display_t color = lcdColorTable[COLOR_IDX(att)]; - uint8_t opacity = 0x0F - (att >> 24); - - if (pat == SOLID) { - while (h--) { - lcdDrawAlphaPixel(x, y, opacity, color); - y++; - } - } - else { - if (pat==DOTTED && !(y%2)) { - pat = ~pat; - } - while (h--) { - if (pat & 1) { - lcdDrawAlphaPixel(x, y, opacity, color); - pat = (pat >> 1) | 0x80; - } - else { - pat = pat >> 1; - } - y++; - } - } -} - -#if defined(SIMU) -inline void lcdDrawBitmapDMA(coord_t x, coord_t y, coord_t width, coord_t height, const uint8_t * img) -{ - lcdDrawBitmap(x, y, img-4, 0, 0, 1.0); -} -#endif - -#if !defined(BOOT) -void lcdDrawAlphaBitmap(coord_t x, coord_t y, const uint8_t * bmp) -{ - int width = getBitmapWidth(bmp); - int height = getBitmapHeight(bmp); - - if (width == 0 || height == 0) { - return; - } - - for (coord_t line=0; line>4, *((uint16_t *)q)); - p++; q+=3; - } - } -} - -void lcdDrawBitmap(coord_t x, coord_t y, const uint8_t * bmp, coord_t offset, coord_t height, float scale) -{ - int width = getBitmapWidth(bmp); - int h = getBitmapHeight(bmp); - - if (!height || height > h) { - height = h; - } - - if (x+height > LCD_W) { - height = LCD_W-x; - } - - if (width == 0 || height == 0) { - return; - } - - if (scale == 0) { - lcdDrawBitmapDMA(x, y, width, height, bmp + 4 + offset * width * 2); - } - else { - int dstwidth = width * scale; - int dstheight = height * scale; - for (coord_t i=0; i= 360 || endAngle <= 0) - return false; - - if (startAngle == 0) { - slopes[1] = 100000; - slopes[2] = -100000; - } - else { - float angle1 = float(startAngle) * PI / 180; - if (startAngle >= 180) { - slopes[1] = -100000; - slopes[2] = cos(angle1) * 100 / sin(angle1); - } - else { - slopes[1] = cos(angle1) * 100 / sin(angle1); - slopes[2] = -100000; - } - } - - if (endAngle == 360) { - slopes[0] = -100000; - slopes[3] = 100000; - } - else { - float angle2 = float(endAngle) * PI / 180; - if (endAngle >= 180) { - slopes[0] = -100000; - slopes[3] = -cos(angle2) * 100 / sin(angle2); - } - else { - slopes[0] = cos(angle2) * 100 / sin(angle2); - slopes[3] = -100000; - } - } - - return true; -} - -void lcdDrawPie(int x0, int y0, int radius, int startAngle, int endAngle) -{ - int slopes[4]; - if (!evalSlopes(slopes, startAngle, endAngle)) - return; - - for (int y=0; y<=radius; y++) { - for (int x=0; x<=radius; x++) { - if (x*x+y*y <= radius*radius) { - int slope = (x==0 ? (y<0 ? -99000 : 99000) : y*100/x); - if (slope >= slopes[0] && slope < slopes[1]) { - lcdDrawPixel(x0+x, y0-y, WHITE); - } - if (-slope >= slopes[0] && -slope < slopes[1]) { - lcdDrawPixel(x0+x, y0+y, WHITE); - } - if (slope >= slopes[2] && slope < slopes[3]) { - lcdDrawPixel(x0-x, y0-y, WHITE); - } - if (-slope >= slopes[2] && -slope < slopes[3]) { - lcdDrawPixel(x0-x, y0+y, WHITE); - } - } - } - } -} - -void lcdDrawBitmapPie(int x0, int y0, const uint16_t * img, int startAngle, int endAngle) -{ - const uint16_t * q = img; - coord_t width = *q++; - coord_t height = *q++; - - int slopes[4]; - if (!evalSlopes(slopes, startAngle, endAngle)) - return; - - int w2 = width/2; - int h2 = height/2; - - for (int y=h2-1; y>=0; y--) { - for (int x=w2-1; x>=0; x--) { - int slope = (x==0 ? (y<0 ? -99000 : 99000) : y*100/x); - if (slope >= slopes[0] && slope < slopes[1]) { - displayBuf[(y0+h2-y)*LCD_W + x0+w2+x] = q[(h2-y)*width + w2+x]; - } - if (-slope >= slopes[0] && -slope < slopes[1]) { - displayBuf[(y0+h2+y)*LCD_W + x0+w2+x] = q[(h2+y)*width + w2+x]; - } - if (slope >= slopes[2] && slope < slopes[3]) { - displayBuf[(y0+h2-y)*LCD_W + x0+w2-x] = q[(h2-y)*width + w2-x]; - } - if (-slope >= slopes[2] && -slope < slopes[3]) { - displayBuf[(y0+h2+y)*LCD_W + x0+w2-x] = q[(h2+y)*width + w2-x]; - } - } - } -} - -void lcdDrawBitmapPatternPie(coord_t x0, coord_t y0, const uint8_t * img, LcdFlags flags, int startAngle, int endAngle) -{ - coord_t width = *((uint16_t *)img); - coord_t height = *(((uint16_t *)img)+1); - const uint8_t * q = img+4; - - int slopes[4]; - if (!evalSlopes(slopes, startAngle, endAngle)) - return; - - display_t color = lcdColorTable[COLOR_IDX(flags)]; - - int w2 = width/2; - int h2 = height/2; - - for (int y=h2-1; y>=0; y--) { - for (int x=w2-1; x>=0; x--) { - int slope = (x==0 ? (y<0 ? -99000 : 99000) : y*100/x); - if (slope >= slopes[0] && slope < slopes[1]) { - lcdDrawAlphaPixel(x0+w2+x, y0+h2-y, q[(h2-y)*width + w2+x], color); - } - if (-slope >= slopes[0] && -slope < slopes[1]) { - lcdDrawAlphaPixel(x0+w2+x, y0+h2+y, q[(h2+y)*width + w2+x], color); - } - if (slope >= slopes[2] && slope < slopes[3]) { - lcdDrawAlphaPixel(x0+w2-x, y0+h2-y, q[(h2-y)*width + w2-x], color); - } - if (-slope >= slopes[2] && -slope < slopes[3]) { - lcdDrawAlphaPixel(x0+w2-x, y0+h2+y, q[(h2+y)*width + w2-x], color); - } - } + for (int i=0; i> 4) +#define ZCHAR 0x10 + /* rect, square flags */ #define ROUND 0x04 @@ -69,109 +70,14 @@ #define TIMEHOUR 0x2000 #define STREXPANDED 0x4000 -// remove windows default definitions -#undef OPAQUE -#undef RGB - -#define TO5BITS(x) ((x) >> 3) -#define TO6BITS(x) ((x) >> 2) -#define RGB(r, g, b) ((TO5BITS(r) << 11) + (TO6BITS(g) << 5) + (TO5BITS(b) << 0)) -#define WHITE RGB(0xFF, 0xFF, 0xFF) -#define BLACK RGB(0, 0, 0) -#define YELLOW RGB(0xF0, 0xD0, 0x10) -#define BLUE RGB(0x30, 0xA0, 0xE0) -#define GREY RGB(96, 96, 96) -#define DARKGREY RGB(64, 64, 64) -#define LIGHTGREY RGB(180, 180, 180) -#define RED RGB(229, 32, 30) -#define DARKRED RGB(160, 0, 6) - -#define LcdFlags uint32_t - -#define OPACITY_MAX 0x0F -#define OPACITY(x) ((x)<<24) - -enum LcdColorIndex -{ - TEXT_COLOR_INDEX, - TEXT_BGCOLOR_INDEX, - TEXT_INVERTED_COLOR_INDEX, - TEXT_INVERTED_BGCOLOR_INDEX, - LINE_COLOR_INDEX, - SCROLLBOX_COLOR_INDEX, - MENU_TITLE_BGCOLOR_INDEX, - MENU_TITLE_COLOR_INDEX, - MENU_TITLE_DISABLE_COLOR_INDEX, - HEADER_COLOR_INDEX, - ALARM_COLOR_INDEX, - WARNING_COLOR_INDEX, - TEXT_DISABLE_COLOR_INDEX, - CURVE_AXIS_COLOR_INDEX, - CURVE_COLOR_INDEX, - CURVE_CURSOR_COLOR_INDEX, - HEADER_BGCOLOR_INDEX, - HEADER_ICON_BGCOLOR_INDEX, - HEADER_CURRENT_BGCOLOR_INDEX, - TITLE_BGCOLOR_INDEX, - TRIM_BGCOLOR_INDEX, - TRIM_SHADOW_COLOR_INDEX, - MAINVIEW_PANES_COLOR_INDEX, - MAINVIEW_GRAPHICS_COLOR_INDEX, - OVERLAY_COLOR_INDEX, - CUSTOM_COLOR_INDEX, - LCD_COLOR_COUNT -}; - -extern uint16_t lcdColorTable[LCD_COLOR_COUNT]; - -#define COLOR(index) ((index) << 16) -#define COLOR_IDX(att) uint8_t((att) >> 16) - -#define TEXT_COLOR COLOR(TEXT_COLOR_INDEX) -#define TEXT_BGCOLOR COLOR(TEXT_BGCOLOR_INDEX) -#define TEXT_INVERTED_COLOR COLOR(TEXT_INVERTED_COLOR_INDEX) -#define TEXT_INVERTED_BGCOLOR COLOR(TEXT_INVERTED_BGCOLOR_INDEX) -#define LINE_COLOR COLOR(LINE_COLOR_INDEX) -#define SCROLLBOX_COLOR COLOR(SCROLLBOX_COLOR_INDEX) -#define HEADER_SEPARATOR_COLOR COLOR(HEADER_SEPARATOR_COLOR_INDEX) -#define MENU_TITLE_BGCOLOR COLOR(MENU_TITLE_BGCOLOR_INDEX) -#define MENU_TITLE_COLOR COLOR(MENU_TITLE_COLOR_INDEX) -#define MENU_TITLE_DISABLE_COLOR COLOR(MENU_TITLE_DISABLE_COLOR_INDEX) -#define HEADER_COLOR COLOR(HEADER_COLOR_INDEX) -#define ALARM_COLOR COLOR(ALARM_COLOR_INDEX) -#define WARNING_COLOR COLOR(WARNING_COLOR_INDEX) -#define TEXT_DISABLE_COLOR COLOR(TEXT_DISABLE_COLOR_INDEX) -#define CURVE_AXIS_COLOR COLOR(CURVE_AXIS_COLOR_INDEX) -#define CURVE_COLOR COLOR(CURVE_COLOR_INDEX) -#define CURVE_CURSOR_COLOR COLOR(CURVE_CURSOR_COLOR_INDEX) -#define TITLE_BGCOLOR COLOR(TITLE_BGCOLOR_INDEX) -#define TRIM_BGCOLOR COLOR(TRIM_BGCOLOR_INDEX) -#define TRIM_SHADOW_COLOR COLOR(TRIM_SHADOW_COLOR_INDEX) -#define HEADER_BGCOLOR COLOR(HEADER_BGCOLOR_INDEX) -#define HEADER_ICON_BGCOLOR COLOR(HEADER_ICON_BGCOLOR_INDEX) -#define HEADER_CURRENT_BGCOLOR COLOR(HEADER_CURRENT_BGCOLOR_INDEX) -#define MAINVIEW_PANES_COLOR COLOR(MAINVIEW_PANES_COLOR_INDEX) -#define MAINVIEW_GRAPHICS_COLOR COLOR(MAINVIEW_GRAPHICS_COLOR_INDEX) -#define OVERLAY_COLOR COLOR(OVERLAY_COLOR_INDEX) -#define CUSTOM_COLOR COLOR(CUSTOM_COLOR_INDEX) - -#define COLOR_SPLIT(color, r, g, b) \ - uint16_t r = ((color) & 0xF800) >> 11; \ - uint16_t g = ((color) & 0x07E0) >> 5; \ - uint16_t b = ((color) & 0x001F) - -#define COLOR_JOIN(r, g, b) \ - (((r) << 11) + ((g) << 5) + (b)) - -#define display_t uint16_t +#include "colors.h" #define DISPLAY_PIXELS_COUNT (LCD_W*LCD_H) #define DISPLAY_BUFFER_SIZE (sizeof(display_t)*DISPLAY_PIXELS_COUNT) #if defined(SIMU) extern display_t displayBuf[DISPLAY_BUFFER_SIZE]; #else -extern uint8_t * CurrentFrameBuffer; -#define displayBuf ((uint16_t *)CurrentFrameBuffer) +#define displayBuf lcd->data #endif #define lcdRefreshWait() @@ -184,9 +90,17 @@ extern coord_t lcdNextPos; void lcdDrawChar(coord_t x, coord_t y, const unsigned char c, LcdFlags attr=0); void lcdDrawText(coord_t x, coord_t y, const pm_char * s, LcdFlags attr=0); void lcdDrawTextAtIndex(coord_t x, coord_t y, const pm_char * s, uint8_t idx, LcdFlags attr=0); -void lcdDrawSizedText(coord_t x, coord_t y, const pm_char * s, uint8_t len, LcdFlags attr=0); -void lcdDrawSizedText(coord_t x, coord_t y, const pm_char * s, unsigned char len); -void lcd_putsCenter(coord_t y, const pm_char * s, LcdFlags attr=0); + +inline void lcdClear() +{ + lcd->clear(); +} + +inline void lcdDrawSizedText(coord_t x, coord_t y, const pm_char * s, uint8_t len, LcdFlags attr=0) +{ + lcd->drawSizedText(x, y, s, len, attr); +} + void lcdDrawHexNumber(coord_t x, coord_t y, uint32_t val, LcdFlags mode=0); void lcdDrawNumber(coord_t x, coord_t y, int32_t val, LcdFlags flags=0, uint8_t len=0, const char * prefix=NULL, const char * suffix=NULL); @@ -220,21 +134,18 @@ void putsTimer(coord_t x, coord_t y, putstime_t tme, LcdFlags att=0); #define PIXEL_PTR(x, y) &displayBuf[(y)*LCD_W + (x)] -inline void lcdDrawPixel(display_t * p, display_t value) -{ - *p = value; -} - -inline void lcdDrawPixel(coord_t x, coord_t y, display_t value) -{ - display_t * p = PIXEL_PTR(x, y); - lcdDrawPixel(p, value); -} - void lcdDrawAlphaPixel(display_t * p, uint8_t opacity, uint16_t color); void lcdDrawPoint(coord_t x, coord_t y, LcdFlags att=0); -void lcdDrawHorizontalLine(coord_t x, coord_t y, coord_t w, uint8_t pat, LcdFlags att=0); -void lcdDrawVerticalLine(coord_t x, coord_t y, coord_t h, uint8_t pat, LcdFlags att=0); +inline void lcdDrawHorizontalLine(coord_t x, coord_t y, coord_t w, uint8_t pat, LcdFlags att=0) +{ + lcd->drawHorizontalLine(x, y, w, pat, att); +} + +inline void lcdDrawVerticalLine(coord_t x, coord_t y, coord_t h, uint8_t pat, LcdFlags att=0) +{ + lcd->drawVerticalLine(x, y, h, pat, att); +} + void lcdDrawLine(coord_t x1, coord_t y1, coord_t x2, coord_t y2, uint8_t pat=SOLID, LcdFlags att=0); inline void lcdDrawAlphaPixel(coord_t x, coord_t y, uint8_t opacity, uint16_t color) @@ -246,7 +157,7 @@ inline void lcdDrawAlphaPixel(coord_t x, coord_t y, uint8_t opacity, uint16_t co #if !defined(SIMU) inline void lcdDrawSolidFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, LcdFlags flags) { - lcdDrawSolidFilledRectDMA(x, y, w, h, lcdColorTable[COLOR_IDX(flags)]); + DMAFillRect(lcd->data, LCD_W, x, y, w, h, lcdColorTable[COLOR_IDX(flags)]); } #else void lcdDrawSolidFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, LcdFlags flags); @@ -257,13 +168,6 @@ inline void lcdSetColor(uint16_t color) lcdColorTable[CUSTOM_COLOR_INDEX] = color; } -inline void lcdClear() -{ - lcdDrawSolidFilledRect(0, 0, LCD_W, LCD_H, 0); -} - -void lcdInvertRect(coord_t x, coord_t y, coord_t w, coord_t h, LcdFlags flags); - inline void lcdDrawSolidHorizontalLine(coord_t x, coord_t y, coord_t w, LcdFlags att) { lcdDrawSolidFilledRect(x, y, w, 1, att); @@ -283,13 +187,21 @@ inline void lcdDrawSolidRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t lcdDrawSolidFilledRect(x, y+h-thickness, w, thickness, att); } -void lcdDrawFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t pat, LcdFlags att=0); +inline void lcdDrawFilledRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t pat, LcdFlags att=0) +{ + lcd->drawFilledRect(x, y, w, h, pat, att); +} + void lcdDrawBlackOverlay(); void lcdDrawRect(coord_t x, coord_t y, coord_t w, coord_t h, uint8_t thickness=1, uint8_t pat=SOLID, LcdFlags att=0); void lcdDrawCircle(int x0, int y0, int radius); void lcdDrawPie(int x0, int y0, int radius, int angle1=0, int angle2=360); void lcdDrawBitmapPie(int x0, int y0, const uint16_t * img, int startAngle, int endAngle); -void lcdDrawBitmapPatternPie(coord_t x0, coord_t y0, const uint8_t * img, LcdFlags flags=0, int startAngle=0, int endAngle=360); + +inline void lcdDrawBitmapPatternPie(coord_t x0, coord_t y0, const uint8_t * bmp, LcdFlags flags=0, int startAngle=0, int endAngle=360) +{ + lcd->drawBitmapPatternPie(x0, y0, bmp, flags, startAngle, endAngle); +} inline void lcdDrawSquare(coord_t x, coord_t y, coord_t w, LcdFlags att=0) { @@ -306,27 +218,19 @@ inline int getBitmapHeight(const uint8_t * bmp) return *(((const uint16_t *)bmp)+1); } -inline int getBitmapScaledSize(int size, float scale) -{ - if (scale == 0.0) - return size; - else - return size * scale; -} - -float getBitmapScale(const uint8_t * bmp, int dstWidth, int dstHeight); +char getMappedChar(unsigned char c); +int getFontHeight(LcdFlags flags); int getTextWidth(const pm_char *s, int len=0, LcdFlags flags=0); -void lcdDrawBitmap(coord_t x, coord_t y, const uint8_t * img, coord_t offset=0, coord_t height=0, float scale=0); -void lcdDrawBitmapPattern(coord_t x, coord_t y, const uint8_t * img, LcdFlags flags=0, coord_t offset=0, coord_t width=0); -void lcdDrawAlphaBitmap(coord_t x, coord_t y, const uint8_t * bmp); + +inline void lcdDrawBitmapPattern(coord_t x, coord_t y, const uint8_t * img, LcdFlags flags=0, coord_t offset=0, coord_t width=0) +{ + lcd->drawBitmapPattern(x, y, img, flags, offset, width); +} #define lcdSetRefVolt(...) void lcdSetContrast(); #define lcdOff(...) -uint8_t * bmpLoad(const char * filename); -const char * imgLoad(uint8_t * dest, const char * filename, uint16_t width, uint16_t height); - #if defined(BOOT) #define BLINK_ON_PHASE (0) #else diff --git a/radio/src/gui/horus/menu_general_calib.cpp b/radio/src/gui/horus/menu_general_calib.cpp index 404dd5ae6..3523b1b9b 100644 --- a/radio/src/gui/horus/menu_general_calib.cpp +++ b/radio/src/gui/horus/menu_general_calib.cpp @@ -18,7 +18,7 @@ * GNU General Public License for more details. */ -#include "../../opentx.h" +#include "opentx.h" #define XPOT_DELTA 10 #define XPOT_DELAY 10 /* cycles */ @@ -55,6 +55,8 @@ void drawPots() OPTION_SLIDER_SQUARE_BUTTON); } +#include "alpha_horus.lbm" + bool menuCommonCalib(evt_t event) { drawScreenTemplate(NULL, LBM_CALIBRATION_ICON, OPTION_MENU_NO_FOOTER); @@ -182,7 +184,7 @@ bool menuCommonCalib(evt_t event) break; } - lcdDrawAlphaBitmap((LCD_W-206)/2, LCD_H-220, LBM_HORUS); + lcd->drawAlphaBitmap((LCD_W-206)/2, LCD_H-220, &ALPHA_HORUS); drawSticks(); drawPots(); diff --git a/radio/src/gui/horus/menu_general_sdmanager.cpp b/radio/src/gui/horus/menu_general_sdmanager.cpp index d619a6682..d07b872f0 100644 --- a/radio/src/gui/horus/menu_general_sdmanager.cpp +++ b/radio/src/gui/horus/menu_general_sdmanager.cpp @@ -27,7 +27,7 @@ #define IS_FILE(fname) ((bool)(NODE_TYPE(fname))) int currentBitmapIndex = 0; -uint8_t * currentBitmap = NULL; +BitmapBuffer * currentBitmap = NULL; bool menuGeneralSdManagerInfo(evt_t event) { @@ -365,12 +365,12 @@ bool menuGeneralSdManager(evt_t _event) if (ext && (!strcasecmp(ext, BITMAPS_EXT) || !strcasecmp(ext, PNG_EXT) || !strcasecmp(ext, JPG_EXT))) { if (currentBitmapIndex != menuVerticalPosition) { currentBitmapIndex = menuVerticalPosition; - free(currentBitmap); - currentBitmap = bmpLoad(reusableBuffer.sdmanager.lines[index]); + delete currentBitmap; + currentBitmap = BitmapBuffer::load(reusableBuffer.sdmanager.lines[index]); + // TODO scale in case of a too large bitmap } if (currentBitmap) { - // TODO scale in case of a too large bitmap - lcdDrawBitmap(LCD_W / 2, LCD_H / 2, currentBitmap); + lcd->drawBitmap(LCD_W / 2, LCD_H / 2, currentBitmap); } } diff --git a/radio/src/gui/horus/menu_general_setup.cpp b/radio/src/gui/horus/menu_general_setup.cpp index 1c690e33b..a9b804f04 100644 --- a/radio/src/gui/horus/menu_general_setup.cpp +++ b/radio/src/gui/horus/menu_general_setup.cpp @@ -18,7 +18,7 @@ * GNU General Public License for more details. */ -#include "../../opentx.h" +#include "opentx.h" #define RADIO_SETUP_2ND_COLUMN 220 #define YEAR_SEPARATOR_OFFSET 42 diff --git a/radio/src/gui/horus/menu_general_trainer.cpp b/radio/src/gui/horus/menu_general_trainer.cpp index 946db75d7..737602fc0 100644 --- a/radio/src/gui/horus/menu_general_trainer.cpp +++ b/radio/src/gui/horus/menu_general_trainer.cpp @@ -2,7 +2,7 @@ * Copyright (C) OpenTX * * Based on code named - * th9x - http://code.google.com/p/th9x + * th9x - http://code.google.com/p/th9x * er9x - http://code.google.com/p/er9x * gruvin9x - http://code.google.com/p/gruvin9x * @@ -33,7 +33,7 @@ bool menuGeneralTrainer(evt_t event) MENU(STR_MENUTRAINER, LBM_RADIO_ICONS, menuTabGeneral, e_Trainer, (slave ? 0 : 6), { 2, 2, 2, 2, 0/*, 0*/ }); if (slave) { - lcd_putsCenter(5*FH, STR_SLAVE, TEXT_COLOR); + // TODO lcd_putsCenter(5*FH, STR_SLAVE, TEXT_COLOR); return true; } diff --git a/radio/src/gui/horus/menu_model_curves.cpp b/radio/src/gui/horus/menu_model_curves.cpp index 7dd682e3e..49017544c 100644 --- a/radio/src/gui/horus/menu_model_curves.cpp +++ b/radio/src/gui/horus/menu_model_curves.cpp @@ -238,9 +238,9 @@ bool menuModelCurveOne(evt_t event) if (crv.type==CURVE_TYPE_CUSTOM && i>0 && i<5+crv.points-1) x = points[5+crv.points+i-1]; if (i>=pointsOfs && ifadeIn = checkIncDec(event, p->fadeIn, 0, DELAY_MAX, EE_MODEL|NO_INCDEC_MARKS); - lcdDrawNumber(FLIGHT_MODES_FADEIN_COLUMN, y, (10/DELAY_STEP)*p->fadeIn, attr|PREC1); + lcdDrawNumber(FLIGHT_MODES_FADEIN_COLUMN, y, (10/DELAY_STEP)*p->fadeIn, attr|PREC1|RIGHT); break; case ITEM_FLIGHT_MODES_FADE_OUT: if (active) p->fadeOut = checkIncDec(event, p->fadeOut, 0, DELAY_MAX, EE_MODEL|NO_INCDEC_MARKS); - lcdDrawNumber(FLIGHT_MODES_FADEOUT_COLUMN, y, (10/DELAY_STEP)*p->fadeOut, attr|PREC1); + lcdDrawNumber(FLIGHT_MODES_FADEOUT_COLUMN, y, (10/DELAY_STEP)*p->fadeOut, attr|PREC1|RIGHT); break; } diff --git a/radio/src/gui/horus/menu_model_gvars.cpp b/radio/src/gui/horus/menu_model_gvars.cpp index 17011a646..c24756e66 100644 --- a/radio/src/gui/horus/menu_model_gvars.cpp +++ b/radio/src/gui/horus/menu_model_gvars.cpp @@ -2,7 +2,7 @@ * Copyright (C) OpenTX * * Based on code named - * th9x - http://code.google.com/p/th9x + * th9x - http://code.google.com/p/th9x * er9x - http://code.google.com/p/er9x * gruvin9x - http://code.google.com/p/gruvin9x * @@ -76,9 +76,9 @@ bool menuModelGVars(evt_t event) } else { if (abs(v) >= 1000) - lcdDrawNumber(x, y+1, v, TINSIZE|attr); + lcdDrawNumber(x, y+1, v, TINSIZE|attr|RIGHT); else - lcdDrawNumber(x, y, v, attr); + lcdDrawNumber(x, y, v, attr|RIGHT); vmin = -GVAR_MAX; vmax = GVAR_MAX; } if (attr) { diff --git a/radio/src/gui/horus/menu_model_inputs.cpp b/radio/src/gui/horus/menu_model_inputs.cpp index 5fa6f188a..069cec51b 100644 --- a/radio/src/gui/horus/menu_model_inputs.cpp +++ b/radio/src/gui/horus/menu_model_inputs.cpp @@ -295,7 +295,7 @@ bool menuModelExpoOne(evt_t event) #define _STR_MAX(x) PSTR("/" #x) #define STR_MAX(x) _STR_MAX(x) -#define EXPO_LINE_WEIGHT_POS 92 +#define EXPO_LINE_WEIGHT_POS 110 #define EXPO_LINE_SRC_POS 115 #define EXPO_LINE_CURVE_POS 162 #define EXPO_LINE_SWITCH_POS 210 @@ -527,7 +527,7 @@ bool menuModelExposAll(evt_t event) if (cur-menuVerticalOffset >= 0 && cur-menuVerticalOffset < NUM_BODY_LINES) { LcdFlags attr = ((s_copyMode || sub != cur) ? 0 : INVERS); - GVAR_MENU_ITEM(EXPO_LINE_WEIGHT_POS, y, ed->weight, MIN_EXPO_WEIGHT, 100, attr | (isExpoActive(i) ? BOLD : 0), 0, 0); + GVAR_MENU_ITEM(EXPO_LINE_WEIGHT_POS, y, ed->weight, MIN_EXPO_WEIGHT, 100, RIGHT | attr | (isExpoActive(i) ? BOLD : 0), 0, 0); displayExpoLine(y, ed); if (s_copyMode) { diff --git a/radio/src/gui/horus/menu_model_limits.cpp b/radio/src/gui/horus/menu_model_limits.cpp index 2d885732e..799b7b20b 100644 --- a/radio/src/gui/horus/menu_model_limits.cpp +++ b/radio/src/gui/horus/menu_model_limits.cpp @@ -169,9 +169,9 @@ bool menuModelLimits(evt_t event) } #if defined(PPM_UNIT_US) - lcdDrawNumber(LIMITS_OFFSET_POS, y, ((int32_t)ld->offset*128) / 25, attr|PREC1); + lcdDrawNumber(LIMITS_OFFSET_POS, y, ((int32_t)ld->offset*128) / 25, attr|PREC1|RIGHT); #else - lcdDrawNumber(LIMITS_OFFSET_POS, y, ld->offset, attr|PREC1); + lcdDrawNumber(LIMITS_OFFSET_POS, y, ld->offset, attr|PREC1|RIGHT); #endif if (active) { ld->offset = checkIncDec(event, ld->offset, -1000, 1000, EE_MODEL, NULL, stops1000); @@ -187,7 +187,7 @@ bool menuModelLimits(evt_t event) ld->min = GVAR_MENU_ITEM(LIMITS_MIN_POS, y, ld->min, -LIMIT_EXT_MAX, LIMIT_EXT_MAX, attr|PREC1, 0, event); break; } - lcdDrawNumber(LIMITS_MIN_POS, y, MIN_MAX_DISPLAY(ld->min-LIMITS_MIN_MAX_OFFSET), attr|PREC1); + lcdDrawNumber(LIMITS_MIN_POS, y, MIN_MAX_DISPLAY(ld->min-LIMITS_MIN_MAX_OFFSET), attr|PREC1|RIGHT); if (active) ld->min = LIMITS_MIN_MAX_OFFSET + checkIncDec(event, ld->min-LIMITS_MIN_MAX_OFFSET, -limit, 0, EE_MODEL, NULL, stops1000); break; @@ -196,7 +196,7 @@ bool menuModelLimits(evt_t event) ld->max = GVAR_MENU_ITEM(LIMITS_MAX_POS, y, ld->max, -LIMIT_EXT_MAX, LIMIT_EXT_MAX, attr|PREC1, 0, event); break; } - lcdDrawNumber(LIMITS_MAX_POS, y, MIN_MAX_DISPLAY(ld->max+LIMITS_MIN_MAX_OFFSET), attr|PREC1); + lcdDrawNumber(LIMITS_MAX_POS, y, MIN_MAX_DISPLAY(ld->max+LIMITS_MIN_MAX_OFFSET), attr|PREC1|RIGHT); if (active) ld->max = -LIMITS_MIN_MAX_OFFSET + checkIncDec(event, ld->max+LIMITS_MIN_MAX_OFFSET, 0, +limit, EE_MODEL, NULL, stops1000); break; @@ -231,7 +231,7 @@ bool menuModelLimits(evt_t event) #if defined(PPM_CENTER_ADJUSTABLE) case ITEM_LIMITS_PPM_CENTER: - lcdDrawNumber(LIMITS_PPM_CENTER_POS, y, PPM_CENTER+ld->ppmCenter, attr); + lcdDrawNumber(LIMITS_PPM_CENTER_POS, y, PPM_CENTER+ld->ppmCenter, attr|RIGHT); if (active) { CHECK_INCDEC_MODELVAR(event, ld->ppmCenter, -PPM_CENTER_MAX, +PPM_CENTER_MAX); } diff --git a/radio/src/gui/horus/menu_model_mixes.cpp b/radio/src/gui/horus/menu_model_mixes.cpp index 22713ac09..28dd2e1b5 100644 --- a/radio/src/gui/horus/menu_model_mixes.cpp +++ b/radio/src/gui/horus/menu_model_mixes.cpp @@ -270,7 +270,7 @@ bool menuModelMixOne(evt_t event) #define _STR_MAX(x) PSTR("/" #x) #define STR_MAX(x) _STR_MAX(x) -#define MIX_LINE_WEIGHT_POS 92 +#define MIX_LINE_WEIGHT_POS 110 #define MIX_LINE_SRC_POS 115 #define MIX_LINE_CURVE_POS 162 #define MIX_LINE_SWITCH_POS 210 @@ -502,7 +502,7 @@ bool menuModelMixAll(evt_t event) putsMixerSource(MIX_LINE_SRC_POS, y, md->srcRaw); - gvarWeightItem(MIX_LINE_WEIGHT_POS, y, md, attr | (isMixActive(i) ? BOLD : 0), event); + gvarWeightItem(MIX_LINE_WEIGHT_POS, y, md, RIGHT | attr | (isMixActive(i) ? BOLD : 0), event); displayMixLine(y, md); diff --git a/radio/src/gui/horus/menu_model_select.cpp b/radio/src/gui/horus/menu_model_select.cpp index 21f8ed660..f58eead3d 100644 --- a/radio/src/gui/horus/menu_model_select.cpp +++ b/radio/src/gui/horus/menu_model_select.cpp @@ -61,10 +61,11 @@ void drawModel(coord_t x, coord_t y, const char * name, bool selected) for (int i=0; i<4; i++) { lcdDrawBitmapPattern(x+104+i*11, y+25, LBM_SCORE0, TITLE_BGCOLOR); } - uint8_t * bitmap = bmpLoad(header.bitmap); + GET_FILENAME(filename, BITMAPS_PATH, header.bitmap, BITMAPS_EXT); + const BitmapBuffer * bitmap = BitmapBuffer::load(filename); if (bitmap) { - lcdDrawBitmap(x+5, y+24, bitmap, 0, 0, getBitmapScale(bitmap, 64, 32)); - free(bitmap); + lcd->drawScaledBitmap(bitmap, x+5, y+24, 64, 32); + delete bitmap; } else { lcdDrawBitmapPattern(x+5, y+23, LBM_LIBRARY_SLOT, TEXT_COLOR); diff --git a/radio/src/gui/horus/menu_model_setup.cpp b/radio/src/gui/horus/menu_model_setup.cpp index 916df74af..c6b9a773c 100644 --- a/radio/src/gui/horus/menu_model_setup.cpp +++ b/radio/src/gui/horus/menu_model_setup.cpp @@ -612,7 +612,7 @@ bool menuModelSetup(evt_t event) if (IS_MODULE_PPM(moduleIdx)) { lcdDrawText(MENUS_MARGIN_LEFT, y, STR_PPMFRAME); lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, (int16_t)moduleData.ppmFrameLength*5 + 225, (menuHorizontalPosition<=0 ? attr : 0) | PREC1|LEFT, 0, NULL, STR_MS); - lcdDrawNumber(MODEL_SETUP_2ND_COLUMN+90, y, (moduleData.ppmDelay*50)+300, (CURSOR_ON_LINE() || menuHorizontalPosition==1) ? attr : 0, 0, NULL, "us"); + lcdDrawNumber(MODEL_SETUP_2ND_COLUMN+90, y, (moduleData.ppmDelay*50)+300, (CURSOR_ON_LINE() || menuHorizontalPosition==1) ? attr|RIGHT : RIGHT, 0, NULL, "us"); lcdDrawText(MODEL_SETUP_2ND_COLUMN+120, y, moduleData.ppmPulsePol ? "+" : "-", (CURSOR_ON_LINE() || menuHorizontalPosition==2) ? attr : 0); if (attr && s_editMode>0) { @@ -641,7 +641,7 @@ bool menuModelSetup(evt_t event) lcdDrawText(MENUS_MARGIN_LEFT, y, STR_RXNUM); } if (IS_MODULE_XJT(moduleIdx) || IS_MODULE_DSM2(moduleIdx)) { - if (xOffsetBind) lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], (l_posHorz==0 ? attr : 0) | LEADING0|LEFT, 2); + if (xOffsetBind) lcdDrawNumber(MODEL_SETUP_2ND_COLUMN, y, g_model.header.modelId[moduleIdx], (l_posHorz==0 ? attr : 0) | LEADING0 | LEFT, 2); if (attr && l_posHorz==0 && s_editMode>0) { CHECK_INCDEC_MODELVAR_ZERO(event, g_model.header.modelId[moduleIdx], IS_MODULE_DSM2(moduleIdx) ? 20 : 63); } @@ -770,13 +770,13 @@ bool menuModelFailsafe(evt_t event) } #if defined(PPM_UNIT_US) uint8_t wbar = (longNames ? SLIDER_W-10 : SLIDER_W); - lcdDrawNumber(x+COL_W-4-wbar-ofs, y, PPM_CH_CENTER(ch)+val/2, flags); + lcdDrawNumber(x+COL_W-4-wbar-ofs, y, PPM_CH_CENTER(ch)+val/2, flags|RIGHT); #elif defined(PPM_UNIT_PERCENT_PREC1) uint8_t wbar = (longNames ? SLIDER_W-16 : SLIDER_W-6); - lcdDrawNumber(x+COL_W-4-wbar-ofs, y, calcRESXto1000(val), PREC1|flags); + lcdDrawNumber(x+COL_W-4-wbar-ofs, y, calcRESXto1000(val), PREC1|flags|RIGHT); #else uint8_t wbar = (longNames ? SLIDER_W-10 : SLIDER_W); - lcdDrawNumber(x+COL_W-4-wbar-ofs, y, calcRESXto1000(val)/10, flags); + lcdDrawNumber(x+COL_W-4-wbar-ofs, y, calcRESXto1000(val)/10, flags|RIGHT); #endif // Gauge diff --git a/radio/src/gui/horus/menu_model_telemetry.cpp b/radio/src/gui/horus/menu_model_telemetry.cpp index 216f332e3..b17c5b6bd 100644 --- a/radio/src/gui/horus/menu_model_telemetry.cpp +++ b/radio/src/gui/horus/menu_model_telemetry.cpp @@ -2,7 +2,7 @@ * Copyright (C) OpenTX * * Based on code named - * th9x - http://code.google.com/p/th9x + * th9x - http://code.google.com/p/th9x * er9x - http://code.google.com/p/er9x * gruvin9x - http://code.google.com/p/gruvin9x * @@ -334,7 +334,7 @@ bool menuModelSensor(evt_t event) lcdDrawText(MENUS_MARGIN_LEFT, y, STR_AUTOOFFSET); sensor->autoOffset = editCheckBox(sensor->autoOffset, SENSOR_2ND_COLUMN, y, attr, event); break; - + case SENSOR_FIELD_ONLYPOSITIVE: lcdDrawText(MENUS_MARGIN_LEFT, y, STR_ONLYPOSITIVE); sensor->onlyPositive = editCheckBox(sensor->onlyPositive, SENSOR_2ND_COLUMN, y, attr, event); @@ -344,7 +344,7 @@ bool menuModelSensor(evt_t event) lcdDrawText(MENUS_MARGIN_LEFT, y, STR_FILTER); sensor->filter = editCheckBox(sensor->filter, SENSOR_2ND_COLUMN, y, attr, event); break; - + case SENSOR_FIELD_PERSISTENT: lcdDrawText(MENUS_MARGIN_LEFT, y, NO_INDENT(STR_PERSISTENT)); sensor->persistent = editCheckBox(sensor->persistent, SENSOR_2ND_COLUMN, y, attr, event); @@ -381,7 +381,7 @@ void onSensorMenu(const char *result) } else if (result == STR_COPY) { int newIndex = availableTelemetryIndex(); - + if (newIndex >= 0) { TelemetrySensor & sourceSensor = g_model.telemetrySensors[index]; TelemetrySensor & newSensor = g_model.telemetrySensors[newIndex]; @@ -390,7 +390,7 @@ void onSensorMenu(const char *result) TelemetryItem & newItem = telemetryItems[newIndex]; newItem = sourceItem; storageDirty(EE_MODEL); - } + } else { POPUP_WARNING(STR_TELEMETRYFULL); } @@ -406,7 +406,7 @@ bool menuModelTelemetry(evt_t event) delTelemetryIndex(i); } } - + MENU(STR_MENUTELEMETRY, LBM_MODEL_ICONS, menuTabModel, e_Telemetry, ITEM_TELEMETRY_MAX, { TELEMETRY_TYPE_ROWS RSSI_ROWS SENSORS_ROWS VARIO_ROWS }); for (int i=0; idrawMessageBox("", "", "", MESSAGEBOX_TYPE_WARNING); + // lcdDrawSolidFilledRect(POPUP_X, POPUP_Y, POPUP_W, POPUP_H, TEXT_BGCOLOR); + // lcdDrawSolidRect(POPUP_X, POPUP_Y, POPUP_W, POPUP_H, 2, ALARM_COLOR); // lcdDrawBitmap(POPUP_X+15, POPUP_Y+20, LBM_WARNING); } void displayMessageBox() { - lcdDrawSolidFilledRect(POPUP_X, POPUP_Y, POPUP_W, POPUP_H, TEXT_BGCOLOR); - lcdDrawSolidRect(POPUP_X, POPUP_Y, POPUP_W, POPUP_H, 2, WARNING_COLOR); + // theme->drawMessageBox("", "", "", MESSAGEBOX_TYPE_INFO); + // lcdDrawSolidFilledRect(POPUP_X, POPUP_Y, POPUP_W, POPUP_H, TEXT_BGCOLOR); + // lcdDrawSolidRect(POPUP_X, POPUP_Y, POPUP_W, POPUP_H, 2, WARNING_COLOR); // lcdDrawBitmap(POPUP_X+15, POPUP_Y+20, LBM_MESSAGE); } @@ -75,11 +77,12 @@ void displayPopup(const char * title) void displayWarning(evt_t event) { warningResult = false; + if (warningType == WARNING_TYPE_INPUT) - displayMessageBox(); + theme->drawMessageBox(warningText, "", "", MESSAGEBOX_TYPE_INFO); else - displayWarningBox(); - lcdDrawSizedText(WARNING_LINE_X, WARNING_LINE_Y, warningText, WARNING_LINE_LEN, DBLSIZE | (warningType == WARNING_TYPE_INPUT ? WARNING_COLOR : ALARM_COLOR)); + theme->drawMessageBox(warningText, "", "", MESSAGEBOX_TYPE_WARNING); + if (warningInfoText) { lcdDrawSizedText(WARNING_LINE_X, WARNING_INFOLINE_Y, warningInfoText, warningInfoLength, WARNING_INFO_FLAGS); } diff --git a/radio/src/gui/horus/screens_setup.cpp b/radio/src/gui/horus/screens_setup.cpp index c0d8dab15..8e73b808e 100644 --- a/radio/src/gui/horus/screens_setup.cpp +++ b/radio/src/gui/horus/screens_setup.cpp @@ -57,6 +57,16 @@ void onZoneOptionFileSelectionMenu(const char * result) } } +int getZoneOptionColumns(const ZoneOption * option) +{ + if (option->type == ZoneOption::Color) { + return 2; + } + else { + return 0; + } +} + void editZoneOption(coord_t y, const ZoneOption * option, ZoneOptionValue * value, LcdFlags attr, uint32_t i_flags, evt_t event) { lcdDrawText(MENUS_MARGIN_LEFT, y, option->name); @@ -115,11 +125,29 @@ void editZoneOption(coord_t y, const ZoneOption * option, ZoneOptionValue * valu } } else if (option->type == ZoneOption::Color) { + COLOR_SPLIT(value->unsignedValue, r, g, b); + lcdSetColor(value->unsignedValue); - lcdDrawSolidRect(SCREENS_SETUP_2ND_COLUMN, y, 40, 15, 1, attr ? TEXT_INVERTED_BGCOLOR : TEXT_COLOR); - lcdDrawSolidFilledRect(SCREENS_SETUP_2ND_COLUMN + 1, y + 1, 38, 13, CUSTOM_COLOR); - if (attr) { - value->unsignedValue = checkIncDec(event, value->unsignedValue, i_flags, 65535, 0); + lcdDrawSolidFilledRect(SCREENS_SETUP_2ND_COLUMN-1, y-1, 42, 17, TEXT_COLOR); + lcdDrawSolidFilledRect(SCREENS_SETUP_2ND_COLUMN, y, 40, 15, CUSTOM_COLOR); + + lcdDrawText(SCREENS_SETUP_2ND_COLUMN + 50, y, "R:", TEXT_COLOR); + lcdDrawNumber(SCREENS_SETUP_2ND_COLUMN + 70, y, r << 3, LEFT|TEXT_COLOR|((attr && menuHorizontalPosition == 0) ? attr : 0)); + if (attr && menuHorizontalPosition == 0) { + r = checkIncDec(event, r, 0, (1<<5)-1, i_flags); + } + lcdDrawText(SCREENS_SETUP_2ND_COLUMN + 110, y, "G:", TEXT_COLOR); + lcdDrawNumber(SCREENS_SETUP_2ND_COLUMN + 130, y, g << 2, LEFT|TEXT_COLOR|((attr && menuHorizontalPosition == 1) ? attr : 0)); + if (attr && menuHorizontalPosition == 1) { + g = checkIncDec(event, g, 0, (1<<6)-1, i_flags); + } + lcdDrawText(SCREENS_SETUP_2ND_COLUMN + 170, y, "B:", TEXT_COLOR); + lcdDrawNumber(SCREENS_SETUP_2ND_COLUMN + 190, y, b << 3, LEFT|TEXT_COLOR|((attr && menuHorizontalPosition == 2) ? attr : 0)); + if (attr && menuHorizontalPosition == 2) { + b = checkIncDec(event, b, 0, (1<<5)-1, i_flags); + } + if (attr && checkIncDec_Ret) { + value->unsignedValue = COLOR_JOIN(r, g, b); } } } @@ -155,11 +183,6 @@ bool menuWidgetSettings(evt_t event) return menuSettings("Widget settings", currentWidget, EE_MODEL, event); } -bool menuThemeSettings(evt_t event) -{ - return menuSettings("Theme settings", theme, EE_GENERAL, event); -} - bool menuWidgetChoice(evt_t event) { static Widget * previousWidget; @@ -328,7 +351,7 @@ T * editThemeChoice(coord_t x, coord_t y, T * array[], uint8_t count, T * curren } if (attr) { if (menuHorizontalPosition < 0) { - lcdDrawSolidFilledRect(x-3, y-2, min(4, count)*56+1, 2*FH-5, TEXT_INVERTED_BGCOLOR); + lcdDrawSolidFilledRect(x-3, y-1, min(4, count)*56+1, 2*FH-5, TEXT_INVERTED_BGCOLOR); } else { if (needsOffsetCheck) { @@ -345,15 +368,15 @@ T * editThemeChoice(coord_t x, coord_t y, T * array[], uint8_t count, T * curren unsigned int last = min(menuHorizontalOffset + 4, count); for (unsigned int i=menuHorizontalOffset, pos=x; idrawThumb(pos, y, current == element ? ((attr && menuHorizontalPosition < 0) ? TEXT_INVERTED_COLOR : TEXT_INVERTED_BGCOLOR) : LINE_COLOR); + element->drawThumb(pos, y+1, current == element ? ((attr && menuHorizontalPosition < 0) ? TEXT_INVERTED_COLOR : TEXT_INVERTED_BGCOLOR) : LINE_COLOR); } if (count > 4) { - lcdDrawBitmapPattern(x - 12, y, LBM_CARROUSSEL_LEFT, menuHorizontalOffset > 0 ? LINE_COLOR : CURVE_AXIS_COLOR); - lcdDrawBitmapPattern(x + 4 * 56, y, LBM_CARROUSSEL_RIGHT, last < countRegisteredLayouts ? LINE_COLOR : CURVE_AXIS_COLOR); + lcdDrawBitmapPattern(x - 12, y+1, LBM_CARROUSSEL_LEFT, menuHorizontalOffset > 0 ? LINE_COLOR : CURVE_AXIS_COLOR); + lcdDrawBitmapPattern(x + 4 * 56, y+1, LBM_CARROUSSEL_RIGHT, last < countRegisteredLayouts ? LINE_COLOR : CURVE_AXIS_COLOR); } if (attr && menuHorizontalPosition >= 0) { - lcdDrawSolidRect(x + (menuHorizontalPosition - menuHorizontalOffset) * 56 - 3, y - 2, 57, 35, 1, TEXT_INVERTED_BGCOLOR); - if (menuHorizontalPosition != currentIndex && event == EVT_KEY_BREAK(KEY_ENTER)) { + lcdDrawSolidRect(x + (menuHorizontalPosition - menuHorizontalOffset) * 56 - 3, y - 1, 57, 35, 1, TEXT_INVERTED_BGCOLOR); + if (event == EVT_KEY_BREAK(KEY_ENTER)) { s_editMode = 0; return array[menuHorizontalPosition]; } @@ -361,19 +384,39 @@ T * editThemeChoice(coord_t x, coord_t y, T * array[], uint8_t count, T * curren return NULL; } +int getOptionsCount(const ZoneOption * options) +{ + if (options == NULL) { + return 0; + } + else { + int count = 0; + for (const ZoneOption * option = options; option->name; option++) { + count++; + } + return count; + } +} + enum menuScreensThemeItems { ITEM_SCREEN_SETUP_THEME, - ITEM_SCREEN_SETUP_THEME_SETTINGS = ITEM_SCREEN_SETUP_THEME+2, - ITEM_SCREEN_SETUP_TOPBAR, - ITEM_SCREEN_SETUP_MAX + ITEM_SCREEN_SETUP_THEME_OPTION1 = ITEM_SCREEN_SETUP_THEME+2 }; bool menuScreensTheme(evt_t event) { bool needsOffsetCheck = (menuVerticalPosition != 0 || menuHorizontalPosition < 0); + const ZoneOption * options = theme->getOptions(); + int optionsCount = getOptionsCount(options); + linesCount = ITEM_SCREEN_SETUP_THEME_OPTION1 + optionsCount + 1; menuPageCount = updateMainviewsMenu(); - MENU_WITH_OPTIONS("User interface", LBM_SCREENS_SETUP_ICONS, menuTabScreensSetup, menuPageCount, 0, ITEM_SCREEN_SETUP_MAX, { uint8_t(NAVIGATION_LINE_BY_LINE|uint8_t(countRegisteredThemes-1)), ORPHAN_ROW, 0, 0, 0, 0 }); + uint8_t mstate_tab[2 + MAX_THEME_OPTIONS + 1] = { uint8_t(NAVIGATION_LINE_BY_LINE|uint8_t(countRegisteredThemes-1)), ORPHAN_ROW }; + for (int i=0; i(SCREENS_SETUP_2ND_COLUMN, y, registeredThemes, countRegisteredThemes, theme, needsOffsetCheck, attr, event); + Theme * new_theme = editThemeChoice(SCREENS_SETUP_2ND_COLUMN, y, registeredThemes, countRegisteredThemes, theme, needsOffsetCheck, attr, event); if (new_theme) { new_theme->init(); loadTheme(new_theme); @@ -393,31 +436,35 @@ bool menuScreensTheme(evt_t event) break; } - case ITEM_SCREEN_SETUP_THEME_SETTINGS: - drawButton(SCREENS_SETUP_2ND_COLUMN, y, "Theme settings", attr); - if (attr && event == EVT_KEY_BREAK(KEY_ENTER) && theme->getOptions()) { - s_editMode = 0; - pushMenu(menuThemeSettings); - } + case ITEM_SCREEN_SETUP_THEME+1: break; - case ITEM_SCREEN_SETUP_TOPBAR: - lcdDrawText(MENUS_MARGIN_LEFT, y, "Top bar"); - drawButton(SCREENS_SETUP_2ND_COLUMN, y, "Setup", attr); - if (attr && event == EVT_KEY_BREAK(KEY_ENTER)) { - currentScreen = customScreens[0]; - currentContainer = topbar; - pushMenu(menuWidgetsSetup); + default: + { + uint8_t index = k - ITEM_SCREEN_SETUP_THEME_OPTION1; + if (index < optionsCount) { + const ZoneOption * option = &options[index]; + ZoneOptionValue * value = theme->getOptionValue(index); + editZoneOption(y, option, value, attr, EE_GENERAL, event); + } + else if (index == optionsCount) { + lcdDrawText(MENUS_MARGIN_LEFT, y, "Top bar"); + drawButton(SCREENS_SETUP_2ND_COLUMN, y, "Setup", attr); + if (attr && event == EVT_KEY_BREAK(KEY_ENTER)) { + currentScreen = customScreens[0]; + currentContainer = topbar; + pushMenu(menuWidgetsSetup); + } } break; - + } } } return true; } -enum menuScreenSetup { +enum MenuScreenSetupItems { ITEM_SCREEN_SETUP_LAYOUT, ITEM_SCREEN_SETUP_WIDGETS_SETUP = ITEM_SCREEN_SETUP_LAYOUT+2, ITEM_SCREEN_SETUP_LAYOUT_OPTION1, @@ -433,16 +480,20 @@ bool menuScreenSetup(int index, evt_t event) currentContainer = currentScreen; bool needsOffsetCheck = (menuVerticalPosition != 0 || menuHorizontalPosition < 0); - linesCount = ITEM_SCREEN_SETUP_LAYOUT_OPTION1; const ZoneOption * options = currentScreen->getFactory()->getOptions(); - for (const ZoneOption * option = options; option->name; option++) { - linesCount++; - } + int optionsCount = getOptionsCount(options); + linesCount = ITEM_SCREEN_SETUP_LAYOUT_OPTION1 + optionsCount; char title[] = "Main view X"; title[sizeof(title)-2] = '1' + index; menuPageCount = updateMainviewsMenu(); - MENU_WITH_OPTIONS(title, LBM_SCREENS_SETUP_ICONS, menuTabScreensSetup, menuPageCount, index+1, linesCount, { uint8_t(NAVIGATION_LINE_BY_LINE|uint8_t(countRegisteredLayouts-1)), ORPHAN_ROW, 0, 0, 0, 0 }); + + uint8_t mstate_tab[2 + MAX_LAYOUT_OPTIONS] = { uint8_t(NAVIGATION_LINE_BY_LINE|uint8_t(countRegisteredLayouts-1)), ORPHAN_ROW }; + for (int i=0; igetOptionValue(index); editZoneOption(y, option, value, attr, EE_MODEL, event); } break; + } } } diff --git a/radio/src/gui/horus/splash.cpp b/radio/src/gui/horus/splash.cpp index 94164d7b4..1bebd12fd 100644 --- a/radio/src/gui/horus/splash.cpp +++ b/radio/src/gui/horus/splash.cpp @@ -18,18 +18,14 @@ * GNU General Public License for more details. */ -#include "../../opentx.h" - -const uint8_t LBM_SPLASH[] __ALIGNED = { +#include "opentx.h" #include "bmp_splash.lbm" -}; #if defined(SPLASH) void drawSplash() { - lcdClear(); - - lcdDrawBitmap((LCD_W-256)/2, (LCD_H-256)/2, LBM_SPLASH); + lcd->clear(); + lcd->drawBitmap((LCD_W-BMP_SPLASH.getWidth())/2, (LCD_H-BMP_SPLASH.getHeight())/2, &BMP_SPLASH); #if MENUS_LOCK == 1 if (readonly == false) { diff --git a/radio/src/gui/horus/theme.cpp b/radio/src/gui/horus/theme.cpp index b503c7226..c9b926343 100644 --- a/radio/src/gui/horus/theme.cpp +++ b/radio/src/gui/horus/theme.cpp @@ -37,9 +37,29 @@ ZoneOptionValue * Theme::getOptionValue(unsigned int index) const return &g_eeGeneral.themeData.options[index]; } -void Theme::drawThumb(uint16_t x, uint16_t y, uint32_t flags) const +const char * Theme::getFilePath(const char * filename) const { - lcdDrawBitmap(x, y, bitmap); + static char path[_MAX_LFN+1] = THEMES_PATH "/"; + strcpy(path + sizeof(THEMES_PATH), getName()); + int len = sizeof(THEMES_PATH) + strlen(path + sizeof(THEMES_PATH)); + path[len] = '/'; + strcpy(path+len+1, filename); + return path; +} + +void Theme::drawThumb(uint16_t x, uint16_t y, uint32_t flags) +{ + #define THUMB_WIDTH 51 + #define THUMB_HEIGHT 31 + if (!thumb) { + thumb = BitmapBuffer::load(getFilePath("thumb.bmp")); + } + if (thumb) { + lcd->drawBitmap(x, y, thumb); + } + if (flags == LINE_COLOR) { + lcdDrawFilledRect(x, y, THUMB_WIDTH, THUMB_HEIGHT, SOLID, OVERLAY_COLOR | OPACITY(10)); + } } void Theme::drawBackground() const @@ -47,6 +67,13 @@ void Theme::drawBackground() const lcdDrawSolidFilledRect(0, 0, LCD_W, LCD_H, TEXT_BGCOLOR); } +void Theme::drawAboutBackground() const +{ + drawBackground(); +} + +#include "alpha_asterisk.lbm" + void Theme::drawMessageBox(const char * title, const char * text, const char * action, uint32_t flags) const { //if (flags & MESSAGEBOX_TYPE_ALERT) { @@ -55,7 +82,10 @@ void Theme::drawMessageBox(const char * title, const char * text, const char * a //} if ((flags & MESSAGEBOX_TYPE_ALERT) || (flags & MESSAGEBOX_TYPE_WARNING)) { - lcdDrawAlphaBitmap(POPUP_X-80, POPUP_Y+12, LBM_ASTERISK); + lcd->drawAlphaBitmap(POPUP_X-80, POPUP_Y+12, &ALPHA_ASTERISK); + } + else { + lcd->drawAlphaBitmap(POPUP_X-80, POPUP_Y+12, &ALPHA_ASTERISK); } #if defined(TRANSLATIONS_FR) || defined(TRANSLATIONS_IT) || defined(TRANSLATIONS_CZ) @@ -79,9 +109,9 @@ void Theme::drawMessageBox(const char * title, const char * text, const char * a } } -const Theme * registeredThemes[MAX_REGISTERED_THEMES]; // TODO dynamic +Theme * registeredThemes[MAX_REGISTERED_THEMES]; // TODO dynamic unsigned int countRegisteredThemes = 0; -void registerTheme(const Theme * theme) +void registerTheme(Theme * theme) { if (countRegisteredThemes < MAX_REGISTERED_THEMES) { TRACE("register theme %s", theme->getName()); @@ -89,10 +119,10 @@ void registerTheme(const Theme * theme) } } -const Theme * getTheme(const char * name) +Theme * getTheme(const char * name) { for (unsigned int i=0; igetName())) { return theme; } @@ -100,7 +130,7 @@ const Theme * getTheme(const char * name) return NULL; } -void loadTheme(const Theme * new_theme) +void loadTheme(Theme * new_theme) { TRACE("load theme %s", new_theme->getName()); theme = new_theme; @@ -112,7 +142,7 @@ void loadTheme() char name[sizeof(g_eeGeneral.themeName)+1]; memset(name, 0, sizeof(name)); strncpy(name, g_eeGeneral.themeName, sizeof(g_eeGeneral.themeName)); - const Theme * new_theme = getTheme(name); + Theme * new_theme = getTheme(name); if (new_theme) { loadTheme(new_theme); } diff --git a/radio/src/gui/horus/theme.h b/radio/src/gui/horus/theme.h index cc50a4ad1..f80ea8960 100644 --- a/radio/src/gui/horus/theme.h +++ b/radio/src/gui/horus/theme.h @@ -21,10 +21,12 @@ #ifndef _THEME_H_ #define _THEME_H_ +#include "bitmapbuffer.h" + #define MAX_THEME_OPTIONS 5 class Theme; -void registerTheme(const Theme * theme); +void registerTheme(Theme * theme); #define MESSAGEBOX_TYPE_INFO 0 #define MESSAGEBOX_TYPE_QUESTION 1 @@ -38,10 +40,10 @@ class Theme ZoneOptionValue options[MAX_THEME_OPTIONS]; }; - Theme(const char * name, const uint8_t * bitmap, const ZoneOption * options=NULL): + Theme(const char * name, const ZoneOption * options=NULL): name(name), - bitmap(bitmap), - options(options) + options(options), + thumb(NULL) { registerTheme(this); } @@ -51,6 +53,10 @@ class Theme return name; } + const char * getFilePath(const char * filename) const; + + void drawThumb(uint16_t x, uint16_t y, uint32_t flags); + inline const ZoneOption * getOptions() const { return options; @@ -60,31 +66,36 @@ class Theme ZoneOptionValue * getOptionValue(unsigned int index) const; - virtual void drawThumb(uint16_t x, uint16_t y, uint32_t flags) const; - virtual void load() const = 0; virtual void drawBackground() const; + virtual void drawAboutBackground() const; + virtual void drawTopbarBackground(const uint8_t * icon) const = 0; virtual void drawMessageBox(const char * title, const char * text, const char * action, uint32_t flags) const; protected: const char * name; - const uint8_t * bitmap; const ZoneOption * options; + BitmapBuffer * thumb; }; -extern const Theme * theme; +extern Theme * theme; + +inline const char * getThemePath(const char * filename) +{ + return theme->getFilePath(filename); +} #define MAX_REGISTERED_THEMES 10 extern unsigned int countRegisteredThemes; -void registerTheme(const Theme * theme); -extern const Theme * registeredThemes[MAX_REGISTERED_THEMES]; // TODO dynamic +void registerTheme(Theme * theme); +extern Theme * registeredThemes[MAX_REGISTERED_THEMES]; // TODO dynamic -const Theme * getTheme(const char * name); -void loadTheme(const Theme * theme); +Theme * getTheme(const char * name); +void loadTheme(Theme * theme); void loadTheme(); #endif // _THEME_H_ diff --git a/radio/src/gui/horus/themes/bmp_darkblue.png b/radio/src/gui/horus/themes/bmp_darkblue.png deleted file mode 100644 index 108b4c007..000000000 Binary files a/radio/src/gui/horus/themes/bmp_darkblue.png and /dev/null differ diff --git a/radio/src/gui/horus/themes/bmp_default.png b/radio/src/gui/horus/themes/bmp_default.png deleted file mode 100644 index a4b9d77ef..000000000 Binary files a/radio/src/gui/horus/themes/bmp_default.png and /dev/null differ diff --git a/radio/src/gui/horus/themes/darkblue.cpp b/radio/src/gui/horus/themes/darkblue.cpp index 6c4e8e200..c47ff7bb6 100644 --- a/radio/src/gui/horus/themes/darkblue.cpp +++ b/radio/src/gui/horus/themes/darkblue.cpp @@ -20,19 +20,11 @@ #include "opentx.h" -const uint8_t LBM_TOPMENU_BMP_OPENTX[] __ALIGNED = { -#include "bmp_topmenu_opentx.lbm" -}; - -const uint8_t LBM_THEME_DARKBLUE[] __ALIGNED = { -#include "bmp_darkblue.lbm" -}; - class DarkblueTheme: public Theme { public: DarkblueTheme(): - Theme("Darkblue", LBM_THEME_DARKBLUE) + Theme("Darkblue") { } @@ -74,11 +66,12 @@ class DarkblueTheme: public Theme lcdDrawBitmapPattern(5, 7, icon, MENU_TITLE_COLOR); } else { - lcdDrawBitmap(5, 7, LBM_TOPMENU_BMP_OPENTX); + static BitmapBuffer * thumb = BitmapBuffer::load(getFilePath("topmenu_opentx.bmp")); + lcd->drawBitmap(5, 7, thumb); } drawTopbarDatetime(); } }; -DarkblueTheme darkblueTheme; +const DarkblueTheme darkblueTheme; diff --git a/radio/src/gui/horus/themes/default.cpp b/radio/src/gui/horus/themes/default.cpp index 3918e8840..eab0edd47 100644 --- a/radio/src/gui/horus/themes/default.cpp +++ b/radio/src/gui/horus/themes/default.cpp @@ -24,17 +24,7 @@ const uint8_t LBM_TOPMENU_MASK_OPENTX[] = { #include "mask_topmenu_opentx.lbm" }; -const uint8_t LBM_MAINVIEW_BACKGROUND[] __ALIGNED = { -#include "bmp_background.lbm" -}; - -const uint8_t LBM_THEME_DEFAULT[] __ALIGNED = { -#include "bmp_default.lbm" -}; - const ZoneOption OPTIONS_THEME_DEFAULT[] = { - { "Default background", ZoneOption::Bool, { .boolValue = 1 } }, - { "Background file", ZoneOption::File, { .stringValue = "\0\0\0\0\0\0\0" } }, { "Background color", ZoneOption::Color, { .unsignedValue = WHITE } }, { NULL, ZoneOption::Bool } }; @@ -43,7 +33,7 @@ class DefaultTheme: public Theme { public: DefaultTheme(): - Theme("Default", LBM_THEME_DEFAULT, OPTIONS_THEME_DEFAULT) + Theme("Default", OPTIONS_THEME_DEFAULT) { } @@ -78,15 +68,24 @@ class DefaultTheme: public Theme virtual void drawBackground() const { - if (g_eeGeneral.themeData.options[0].boolValue) { - lcdDrawBitmap(0, 0, LBM_MAINVIEW_BACKGROUND); + static BitmapBuffer * backgroundBitmap = BitmapBuffer::load(getThemePath("mainbg.bmp")); + if (backgroundBitmap) { + lcd->drawBitmap(0, 0, backgroundBitmap); } else { - lcdSetColor(g_eeGeneral.themeData.options[2].unsignedValue); + lcdSetColor(g_eeGeneral.themeData.options[0].unsignedValue); lcdDrawSolidFilledRect(0, 0, LCD_W, LCD_H, CUSTOM_COLOR); } } + virtual void drawAboutBackground() const + { + static BitmapBuffer * backgroundBitmap = BitmapBuffer::load(getThemePath("aboutbg.bmp")); + if (backgroundBitmap) { + lcd->drawBitmap(0, 0, backgroundBitmap); + } + } + virtual void drawTopbarBackground(const uint8_t * icon) const { lcdDrawSolidFilledRect(0, 0, LCD_W, MENU_HEADER_HEIGHT, HEADER_BGCOLOR); @@ -103,5 +102,5 @@ class DefaultTheme: public Theme } }; -const DefaultTheme defaultTheme; -const Theme * theme = &defaultTheme; +DefaultTheme defaultTheme; +Theme * theme = &defaultTheme; diff --git a/radio/src/gui/horus/view_about.cpp b/radio/src/gui/horus/view_about.cpp index ae6e86a1d..1fc350b89 100644 --- a/radio/src/gui/horus/view_about.cpp +++ b/radio/src/gui/horus/view_about.cpp @@ -62,7 +62,8 @@ bool menuAboutView(evt_t event) break; } - drawScreenTemplate("About", NULL); + theme->drawAboutBackground(); + theme->drawTopbarBackground(NULL); uint8_t screenDuration = 150; diff --git a/radio/src/gui/horus/view_main.cpp b/radio/src/gui/horus/view_main.cpp index 6dcf2346d..7ed03682c 100644 --- a/radio/src/gui/horus/view_main.cpp +++ b/radio/src/gui/horus/view_main.cpp @@ -18,7 +18,7 @@ * GNU General Public License for more details. */ -#include "../../opentx.h" +#include "opentx.h" #define TRIM_LH_X 10 #define TRIM_LV_X 24 @@ -80,14 +80,6 @@ void drawTrims(uint8_t flightMode) } } -bool isViewAvailable(int index) -{ - if (index <= VIEW_CHANNELS) - return true; - else - return TELEMETRY_SCREEN_TYPE(index-VIEW_TELEM1) != TELEMETRY_SCREEN_TYPE_NONE; -} - void onMainViewMenu(const char *result) { if (result == STR_MODEL_SELECT) { @@ -129,6 +121,16 @@ void onMainViewMenu(const char *result) } } +int getMainViewsCount() +{ + for (int index=1; indexrefresh(); + if (customScreens[g_eeGeneral.view]) { + customScreens[g_eeGeneral.view]->refresh(); } return true; diff --git a/radio/src/gui/horus/view_statistics.cpp b/radio/src/gui/horus/view_statistics.cpp index a3b475e90..32fad0900 100644 --- a/radio/src/gui/horus/view_statistics.cpp +++ b/radio/src/gui/horus/view_statistics.cpp @@ -2,7 +2,7 @@ * Copyright (C) OpenTX * * Based on code named - * th9x - http://code.google.com/p/th9x + * th9x - http://code.google.com/p/th9x * er9x - http://code.google.com/p/er9x * gruvin9x - http://code.google.com/p/gruvin9x * @@ -140,7 +140,7 @@ bool menuStatisticsDebug(evt_t event) lcdDrawText(MENU_DEBUG_COL1_OFS+120, MENU_DEBUG_Y_RTOS+1, "[Audio]", HEADER_COLOR|SMLSIZE); lcdDrawNumber(MENU_DEBUG_COL1_OFS+150, MENU_DEBUG_Y_RTOS, audioStack.available(), LEFT); - lcd_putsCenter(7*FH+1, STR_MENUTORESET); + // TODO lcd_putsCenter(7*FH+1, STR_MENUTORESET); // lcdInvertLastLine(); return true; diff --git a/radio/src/gui/horus/widget.h b/radio/src/gui/horus/widget.h index da75647ce..509743581 100644 --- a/radio/src/gui/horus/widget.h +++ b/radio/src/gui/horus/widget.h @@ -22,6 +22,7 @@ #define _WIDGET_H_ #include +#include #define MAX_WIDGET_OPTIONS 5 diff --git a/radio/src/gui/horus/widgets.cpp b/radio/src/gui/horus/widgets.cpp index 94e2c0d3a..813cb78d2 100644 --- a/radio/src/gui/horus/widgets.cpp +++ b/radio/src/gui/horus/widgets.cpp @@ -31,7 +31,7 @@ const char * const STR_MONTHS[] = { "Jan", "Fev", "Mar", "Apr", "May", "Jun", "J #define DATETIME_SEPARATOR_X 425 #define DATETIME_LINE1 9 #define DATETIME_LINE2 23 -#define DATETIME_LEFT(s) (LCD_W+DATETIME_SEPARATOR_X+8-getTextWidth(s, SMLSIZE))/2 +#define DATETIME_MIDDLE (LCD_W+DATETIME_SEPARATOR_X+8)/2 void drawTopbarDatetime() { @@ -41,19 +41,24 @@ void drawTopbarDatetime() gettime(&t); char str[10]; sprintf(str, "%d %s", t.tm_mday, STR_MONTHS[t.tm_mon]); - lcdDrawText(DATETIME_LEFT(str), DATETIME_LINE1, str, SMLSIZE|TEXT_INVERTED_COLOR); + lcdDrawText(DATETIME_MIDDLE, DATETIME_LINE1, str, SMLSIZE|TEXT_INVERTED_COLOR|CENTERED); getTimerString(str, getValue(MIXSRC_TX_TIME)); - lcdDrawText(DATETIME_LEFT(str), DATETIME_LINE2, str, SMLSIZE|TEXT_INVERTED_COLOR); + lcdDrawText(DATETIME_MIDDLE, DATETIME_LINE2, str, SMLSIZE|TEXT_INVERTED_COLOR|CENTERED); } +#include "alpha_stick_background.lbm" +#include "alpha_stick_pointer.lbm" #define STICK_PANEL_WIDTH 68 void drawStick(coord_t x, coord_t y, int16_t xval, int16_t yval) { - lcdDrawAlphaBitmap(x, y, LBM_STICK_BACKGROUND); - lcdDrawAlphaBitmap(x + 2 + STICK_PANEL_WIDTH/2 + STICK_PANEL_WIDTH/2 * xval/RESX, y + 2 + STICK_PANEL_WIDTH/2 - STICK_PANEL_WIDTH/2 * yval/RESX, LBM_STICK_POINTER); + lcd->drawAlphaBitmap(x, y, &ALPHA_STICK_BACKGROUND); + lcd->drawAlphaBitmap(x + 2 + STICK_PANEL_WIDTH/2 + STICK_PANEL_WIDTH/2 * xval/RESX, y + 2 + STICK_PANEL_WIDTH/2 - STICK_PANEL_WIDTH/2 * yval/RESX, &ALPHA_STICK_POINTER); } +#include "alpha_button_on.lbm" +#include "alpha_button_off.lbm" + void drawButton(coord_t x, coord_t y, const char * label, LcdFlags attr) { int width = getTextWidth(label, 0, attr); @@ -70,9 +75,9 @@ void drawButton(coord_t x, coord_t y, const char * label, LcdFlags attr) lcdDrawText(x+padding+8, y, label, TEXT_COLOR); } if (attr & BUTTON_OFF) - lcdDrawAlphaBitmap(x-6, y+3, LBM_BUTTON_OFF); + lcd->drawAlphaBitmap(x-6, y+3, &ALPHA_BUTTON_OFF); else if (attr & BUTTON_ON) - lcdDrawAlphaBitmap(x-6, y+3, LBM_BUTTON_ON); + lcd->drawAlphaBitmap(x-6, y+3, &ALPHA_BUTTON_ON); } void drawCheckBox(coord_t x, coord_t y, uint8_t value, LcdFlags attr) @@ -383,11 +388,6 @@ int16_t editGVarFieldValue(coord_t x, coord_t y, int16_t value, int16_t min, int } if (GV_IS_GV_VALUE(value, min, max)) { - if (attr & LEFT) - attr -= LEFT; /* because of ZCHAR */ - else - x -= 20; - attr &= ~PREC1; int8_t idx = (int16_t) GV_INDEX_CALC_DELTA(value, delta); @@ -421,25 +421,26 @@ int16_t editGVarFieldValue(coord_t x, coord_t y, int16_t value, int16_t min, int } #endif -#define SLEEP_BITMAP_WIDTH 150 -#define SLEEP_BITMAP_HEIGHT 150 void drawSleepBitmap() { - lcdClear(); - lcdDrawBitmap((LCD_W-SLEEP_BITMAP_WIDTH)/2, (LCD_H-SLEEP_BITMAP_HEIGHT)/2, LBM_SLEEP); + lcd->clear(); + const BitmapBuffer * bitmap = BitmapBuffer::load(getThemePath("sleep.bmp")); + if (bitmap) { + lcd->drawBitmap((LCD_W-bitmap->getWidth())/2, (LCD_H-bitmap->getHeight())/2, bitmap); + } lcdRefresh(); } -#define SHUTDOWN_BITMAP_WIDTH 110 -#define SHUTDOWN_BITMAP_HEIGHT 110 +#include "alpha_shutdown.lbm" + #define SHUTDOWN_CIRCLE_DIAMETER 150 void drawShutdownBitmap(uint32_t index) { static uint32_t last_index = 0xffffffff; if (index < last_index) { - lcdDrawBlackOverlay(); - lcdDrawAlphaBitmap((LCD_W-SHUTDOWN_BITMAP_WIDTH)/2, (LCD_H-SHUTDOWN_BITMAP_HEIGHT)/2, LBM_SHUTDOWN); + theme->drawBackground(); + lcd->drawAlphaBitmap((LCD_W-ALPHA_SHUTDOWN.getWidth())/2, (LCD_H-ALPHA_SHUTDOWN.getHeight())/2, &ALPHA_SHUTDOWN); lcdStoreBackupBuffer(); } else { diff --git a/radio/src/gui/horus/widgets/gauge.cpp b/radio/src/gui/horus/widgets/gauge.cpp index d33896c20..000243c4f 100644 --- a/radio/src/gui/horus/widgets/gauge.cpp +++ b/radio/src/gui/horus/widgets/gauge.cpp @@ -64,8 +64,8 @@ void GaugeWidget::refresh() // Gauge lcdSetColor(color); lcdDrawSolidFilledRect(zone.x, zone.y + 16, zone.w, 16, TEXT_INVERTED_COLOR); - lcdDrawNumber((percent >= 100 ? 20 : (percent >= 10 ? 10 : 0)) + zone.x+zone.w/2, zone.y + 17, percent, SMLSIZE | CUSTOM_COLOR, 0, NULL, "%"); - lcdInvertRect(zone.x + w, zone.y + 16, zone.w - w, 16, CUSTOM_COLOR); + lcdDrawNumber(zone.x+zone.w/2, zone.y + 17, percent, SMLSIZE | CUSTOM_COLOR | CENTERED, 0, NULL, "%"); + lcd->invertRect(zone.x + w, zone.y + 16, zone.w - w, 16, CUSTOM_COLOR); } BaseWidgetFactory gaugeWidget("Gauge", GaugeWidget::options); diff --git a/radio/src/gui/horus/widgets/modelbmp.cpp b/radio/src/gui/horus/widgets/modelbmp.cpp index cc8226058..02e2dc199 100644 --- a/radio/src/gui/horus/widgets/modelbmp.cpp +++ b/radio/src/gui/horus/widgets/modelbmp.cpp @@ -25,57 +25,60 @@ class ModelBitmapWidget: public Widget public: ModelBitmapWidget(const WidgetFactory * factory, const Zone & zone, Widget::PersistentData * persistentData): Widget(factory, zone, persistentData), - bitmap(NULL) + buffer(NULL) { - memset(bitmapFilename, 0, sizeof(bitmapFilename)); - } - - void loadBitmap() - { - char filename[] = BITMAPS_PATH "/xxxxxxxxxx.bmp"; - strncpy(filename+sizeof(BITMAPS_PATH), g_model.header.bitmap, sizeof(g_model.header.bitmap)); - strcat(filename+sizeof(BITMAPS_PATH), BITMAPS_EXT); - bitmap = bmpLoad(filename); - memcpy(bitmapFilename, g_model.header.bitmap, sizeof(g_model.header.bitmap)); - // TODO rescale the bitmap here instead of every refresh! + memset(bitmapFilename, 255, sizeof(bitmapFilename)); } virtual ~ModelBitmapWidget() { - free(bitmap); + delete buffer; } - virtual void refresh(); +#define DRAW_SCALED_BITMAP_FIT_WIDTH 1 +#define DRAW_SCALED_BITMAP_FIT_HEIGHT 2 + + void refreshBuffer() + { + delete buffer; + buffer = new BitmapBuffer(zone.w, zone.h); + if (buffer) { + buffer->drawBitmap(0, 0, lcd, zone.x, zone.y, zone.w, zone.h); + GET_FILENAME(filename, BITMAPS_PATH, g_model.header.bitmap, BITMAPS_EXT); + BitmapBuffer * bitmap = BitmapBuffer::load(filename); + if (zone.h >= 96 && zone.w >= 120) { + buffer->drawFilledRect(0, 0, zone.w, zone.h, SOLID, MAINVIEW_PANES_COLOR | OPACITY(5)); + buffer->drawBitmapPattern(6, 4, LBM_MODEL_ICON, MAINVIEW_GRAPHICS_COLOR); + buffer->drawSizedText(45, 10, g_model.header.name, LEN_MODEL_NAME, ZCHAR | SMLSIZE); + buffer->drawSolidFilledRect(39, 27, zone.w - 48, 2, MAINVIEW_GRAPHICS_COLOR); + if (bitmap) { + buffer->drawScaledBitmap(bitmap, 0, 38, zone.w, zone.h - 38); + } + } + else { + if (bitmap) { + buffer->drawScaledBitmap(bitmap, 0, 0, zone.w, zone.h); + } + } + delete bitmap; + } + } + + virtual void refresh() + { + if (memcmp(bitmapFilename, g_model.header.bitmap, sizeof(g_model.header.bitmap)) != 0) { + refreshBuffer(); + memcpy(bitmapFilename, g_model.header.bitmap, sizeof(g_model.header.bitmap)); + } + + if (buffer) { + lcd->drawBitmap(zone.x, zone.y, buffer); + } + } protected: char bitmapFilename[sizeof(g_model.header.bitmap)]; - uint8_t * bitmap; + BitmapBuffer * buffer; }; -void ModelBitmapWidget::refresh() -{ - if (memcmp(bitmapFilename, g_model.header.bitmap, sizeof(g_model.header.bitmap)) != 0) { - loadBitmap(); - } - - if (zone.h >= 96) { - lcdDrawFilledRect(zone.x, zone.y, zone.w, zone.h, SOLID, MAINVIEW_PANES_COLOR | OPACITY(5)); - lcdDrawBitmapPattern(zone.x + 6, zone.y + 4, LBM_MODEL_ICON, MAINVIEW_GRAPHICS_COLOR); - lcdDrawSizedText(zone.x + 45, zone.y + 10, g_model.header.name, LEN_MODEL_NAME, ZCHAR | SMLSIZE); - lcdDrawSolidFilledRect(zone.x + 39, zone.y + 27, zone.w - 48, 2, MAINVIEW_GRAPHICS_COLOR); - if (bitmap) { - float scale = getBitmapScale(bitmap, zone.w, zone.h - 25); - int width = getBitmapScaledSize(getBitmapWidth(bitmap), scale); - int height = getBitmapScaledSize(getBitmapHeight(bitmap), scale); - lcdDrawBitmap(zone.x + (zone.w - width) / 2, zone.y + zone.h - height / 2 - height / 2, bitmap, 0, 0, scale); - } - } - else if (bitmap) { - float scale = getBitmapScale(bitmap, 1000, zone.h); - int width = getBitmapScaledSize(getBitmapWidth(bitmap), scale); - int height = getBitmapScaledSize(getBitmapHeight(bitmap), scale); - lcdDrawBitmap(zone.x + (zone.w - width) / 2, zone.y + (zone.h - height) / 2, bitmap, 0, 0, scale); - } -} - BaseWidgetFactory modelBitmapWidget("ModelBmp", NULL); diff --git a/radio/src/gui/taranis/bmp.cpp b/radio/src/gui/taranis/bmp.cpp new file mode 100644 index 000000000..96e4d5ff0 --- /dev/null +++ b/radio/src/gui/taranis/bmp.cpp @@ -0,0 +1,252 @@ +/* + * Copyright (C) OpenTX + * + * Based on code named + * th9x - http://code.google.com/p/th9x + * er9x - http://code.google.com/p/er9x + * gruvin9x - http://code.google.com/p/gruvin9x + * + * License GPLv2: http://www.gnu.org/licenses/gpl-2.0.html + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include "opentx.h" + +uint8_t * lcdLoadBitmap(uint8_t * bmp, const char * filename, uint16_t width, uint16_t height) +{ + FIL bmpFile; + UINT read; + uint8_t palette[16]; + uint8_t bmpBuf[LCD_W]; /* maximum with LCD_W */ + uint8_t * buf = &bmpBuf[0]; + + if (width > LCD_W) { + return NULL; + } + + FRESULT result = f_open(&bmpFile, filename, FA_OPEN_EXISTING | FA_READ); + if (result != FR_OK) { + return NULL; + } + + if (f_size(&bmpFile) < 14) { + f_close(&bmpFile); + return NULL; + } + + result = f_read(&bmpFile, buf, 14, &read); + if (result != FR_OK || read != 14) { + f_close(&bmpFile); + return NULL; + } + + if (buf[0] != 'B' || buf[1] != 'M') { + f_close(&bmpFile); + return NULL; + } + + uint32_t fsize = *((uint32_t *)&buf[2]); + uint32_t hsize = *((uint32_t *)&buf[10]); /* header size */ + + uint32_t len = limit((uint32_t)4, (uint32_t)(hsize-14), (uint32_t)32); + result = f_read(&bmpFile, buf, len, &read); + if (result != FR_OK || read != len) { + f_close(&bmpFile); + return NULL; + } + + uint32_t ihsize = *((uint32_t *)&buf[0]); /* more header size */ + + /* invalid header size */ + if (ihsize + 14 > hsize) { + f_close(&bmpFile); + return NULL; + } + + /* sometimes file size is set to some headers size, set a real size in that case */ + if (fsize == 14 || fsize == ihsize + 14) + fsize = f_size(&bmpFile) - 2; + + /* declared file size less than header size */ + if (fsize <= hsize) { + f_close(&bmpFile); + return NULL; + } + + uint32_t w, h; + + switch (ihsize){ + case 40: // windib + case 56: // windib v3 + case 64: // OS/2 v2 + case 108: // windib v4 + case 124: // windib v5 + w = *((uint32_t *)&buf[4]); + h = *((uint32_t *)&buf[8]); + buf += 12; + break; + case 12: // OS/2 v1 + w = *((uint16_t *)&buf[4]); + h = *((uint16_t *)&buf[6]); + buf += 8; + break; + default: + f_close(&bmpFile); + return NULL; + } + + if (*((uint16_t *)&buf[0]) != 1) { /* planes */ + f_close(&bmpFile); + return NULL; + } + + if (w > width || h > height) { + f_close(&bmpFile); + return NULL; + } + + uint16_t depth = *((uint16_t *)&buf[2]); + + buf = &bmpBuf[0]; + + if (depth == 4) { + if (f_lseek(&bmpFile, hsize-64) != FR_OK || f_read(&bmpFile, buf, 64, &read) != FR_OK || read != 64) { + f_close(&bmpFile); + return NULL; + } + for (uint8_t i=0; i<16; i++) { + palette[i] = buf[4*i] >> 4; + } + } + else { + if (f_lseek(&bmpFile, hsize) != FR_OK) { + f_close(&bmpFile); + return NULL; + } + } + + uint8_t * dest = bmp; + + *dest++ = w; + *dest++ = h; + + memset(dest, 0, BITMAP_BUFFER_SIZE(w, h) - 2); + + uint32_t rowSize; + + switch (depth) { + case 1: + rowSize = ((w+31)/32)*4; + for (uint32_t i=0; i=0; i--) { + result = f_read(&bmpFile, buf, rowSize, &read); + if (result != FR_OK || read != rowSize) { + f_close(&bmpFile); + return NULL; + } + uint8_t * dst = dest + (i/2)*w; + for (uint32_t j=0; j> ((j & 1) ? 0 : 4)) & 0x0F; + uint8_t val = palette[index] << ((i & 1) ? 4 : 0); + *dst++ |= val ^ ((i & 1) ? 0xF0 : 0x0F); + } + } + break; + + default: + f_close(&bmpFile); + return NULL; + } + + f_close(&bmpFile); + return bmp; +} + +const uint8_t bmpHeader[] = { + 0x42, 0x4d, 0xF8, 0x1A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x28, 0x00, + 0x00, 0x00, 212, 0x00, 0x00, 0x00, 64, 0x00, 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x02, 0x04, 0x00, 0x00, 0xbc, 0x38, 0x00, 0x00, 0xbc, 0x38, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0xee, 0xee, 0xee, 0x00, 0xdd, 0xdd, + 0xdd, 0x00, 0xcc, 0xcc, 0xcc, 0x00, 0xbb, 0xbb, 0xbb, 0x00, 0xaa, 0xaa, 0xaa, 0x00, 0x99, 0x99, + 0x99, 0x00, 0x88, 0x88, 0x88, 0x00, 0x77, 0x77, 0x77, 0x00, 0x66, 0x66, 0x66, 0x00, 0x55, 0x55, + 0x55, 0x00, 0x44, 0x44, 0x44, 0x00, 0x33, 0x33, 0x33, 0x00, 0x22, 0x22, 0x22, 0x00, 0x11, 0x11, + 0x11, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +inline display_t getPixel(unsigned int x, unsigned int y) +{ + if (x>=LCD_W || y>=LCD_H) + return 0; + display_t * p = &displayBuf[y / 2 * LCD_W + x]; + return (y & 1) ? (*p >> 4) : (*p & 0x0F); +} + +const char * writeScreenshot() +{ + FIL bmpFile; + UINT written; + char filename[42]; // /SCREENSHOTS/screen-2013-01-01-123540.bmp + + // check and create folder here + strcpy_P(filename, SCREENSHOTS_PATH); + const char * error = sdCheckAndCreateDirectory(filename); + if (error) { + return error; + } + + char * tmp = strAppend(&filename[sizeof(SCREENSHOTS_PATH)-1], "/screen"); + tmp = strAppendDate(tmp, true); + strcpy(tmp, BITMAPS_EXT); + + FRESULT result = f_open(&bmpFile, filename, FA_CREATE_ALWAYS | FA_WRITE); + if (result != FR_OK) { + return SDCARD_ERROR(result); + } + + result = f_write(&bmpFile, bmpHeader, sizeof(bmpHeader), &written); + if (result != FR_OK || written != sizeof(bmpHeader)) { + f_close(&bmpFile); + return SDCARD_ERROR(result); + } + + for (int y=LCD_H-1; y>=0; y-=1) { + for (int x=0; x<8*((LCD_W+7)/8); x+=2) { + uint8_t byte = getPixel(x+1, y) + (getPixel(x, y) << 4); + f_write(&bmpFile, &byte, 1, &written); + if (result != FR_OK || written != 1) { + f_close(&bmpFile); + return SDCARD_ERROR(result); + } + } + } + + f_close(&bmpFile); + + return NULL; +} diff --git a/radio/src/gui/taranis/gui.h b/radio/src/gui/taranis/gui.h index 159742fa9..f7a540617 100644 --- a/radio/src/gui/taranis/gui.h +++ b/radio/src/gui/taranis/gui.h @@ -54,7 +54,6 @@ struct MenuItem { const MenuHandlerFunc action; }; -int circularIncDec(int current, int inc, int min, int max, IsValueAvailable isValueAvailable=NULL); void drawSplash(); void drawScreenIndex(uint8_t index, uint8_t count, uint8_t attr); void drawVerticalScrollbar(coord_t x, coord_t y, coord_t h, uint16_t offset, uint16_t count, uint8_t visible); diff --git a/radio/src/gui/taranis/lcd.h b/radio/src/gui/taranis/lcd.h index 4cea7e3f7..a751dc026 100644 --- a/radio/src/gui/taranis/lcd.h +++ b/radio/src/gui/taranis/lcd.h @@ -220,7 +220,7 @@ void lcdSetContrast(); void lcdRefresh(); #endif -uint8_t * bmpLoad(uint8_t * dest, const char * filename, uint16_t width, uint16_t height); +uint8_t * lcdLoadBitmap(uint8_t * dest, const char * filename, uint16_t width, uint16_t height); const char * writeScreenshot(); #if defined(BOOT) diff --git a/radio/src/gui/taranis/menu_general_sdmanager.cpp b/radio/src/gui/taranis/menu_general_sdmanager.cpp index 1660b4394..ebc551804 100644 --- a/radio/src/gui/taranis/menu_general_sdmanager.cpp +++ b/radio/src/gui/taranis/menu_general_sdmanager.cpp @@ -458,7 +458,7 @@ void menuGeneralSdManager(evt_t _event) char * ext = getFileExtension(reusableBuffer.sdmanager.lines[index], SD_SCREEN_FILE_LENGTH+1); if (ext && !strcasecmp(ext, BITMAPS_EXT)) { if (lastPos != menuVerticalPosition) { - if (!bmpLoad(modelBitmap, reusableBuffer.sdmanager.lines[index], MODEL_BITMAP_WIDTH, MODEL_BITMAP_HEIGHT)) { + if (!lcdLoadBitmap(modelBitmap, reusableBuffer.sdmanager.lines[index], MODEL_BITMAP_WIDTH, MODEL_BITMAP_HEIGHT)) { memcpy(modelBitmap, logo_taranis, MODEL_BITMAP_SIZE); } } diff --git a/radio/src/lua/api_lcd.cpp b/radio/src/lua/api_lcd.cpp index 7c6a03b9e..3de14fca6 100644 --- a/radio/src/lua/api_lcd.cpp +++ b/radio/src/lua/api_lcd.cpp @@ -355,11 +355,11 @@ static int luaLcdDrawPixmap(lua_State *L) #if defined(PCBTARANIS) uint8_t bitmap[BITMAP_BUFFER_SIZE(LCD_W/2, LCD_H)]; // width max is LCD_W/2 pixels for saving stack and avoid a malloc here - if (bmpLoad(bitmap, filename, LCD_W/2, LCD_H)) { + if (lcdLoadBitmap(bitmap, filename, LCD_W/2, LCD_H)) { lcdDrawBitmap(x, y, bitmap); } #else - uint8_t * bitmap = bmpLoad(filename); + uint8_t * bitmap = lcdLoadBitmap(filename); if (bitmap) { lcdDrawBitmap(x, y, bitmap); free(bitmap); diff --git a/radio/src/lua/interface.cpp b/radio/src/lua/interface.cpp index a026ee881..58e58dcec 100644 --- a/radio/src/lua/interface.cpp +++ b/radio/src/lua/interface.cpp @@ -781,7 +781,7 @@ ZoneOption * createOptionsArray(int reference) if (reference == 0) { return NULL; } - + int count = 0; lua_rawgeti(L, LUA_REGISTRYINDEX, reference); for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { @@ -829,8 +829,8 @@ class LuaTheme: public Theme friend void luaLoadThemeCallback(); public: - LuaTheme(const char * name, const uint8_t * bitmap, int options): - Theme(name, bitmap, createOptionsArray(options)), + LuaTheme(const char * name, int options): + Theme(name, createOptionsArray(options)), loadFunction(0), drawBackgroundFunction(0), drawTopbarBackgroundFunction(0), @@ -870,7 +870,7 @@ class LuaTheme: public Theme void luaLoadThemeCallback() { - const char * name=NULL, * bitmap=NULL; + const char * name=NULL; int themeOptions=0, loadFunction=0, drawBackgroundFunction=0, drawTopbarBackgroundFunction=0; luaL_checktype(L, -1, LUA_TTABLE); @@ -880,9 +880,6 @@ void luaLoadThemeCallback() if (!strcmp(key, "name")) { name = luaL_checkstring(L, -1); } - else if (!strcmp(key, "bitmap")) { - bitmap = luaL_checkstring(L, -1); - } else if (!strcmp(key, "options")) { themeOptions = luaL_ref(L, LUA_REGISTRYINDEX); lua_pushnil(L); @@ -901,12 +898,8 @@ void luaLoadThemeCallback() } } - if (name && bitmap) { - char path[LUA_FULLPATH_MAXLEN+1]; - strcpy(path, THEMES_PATH "/"); - strcpy(path+sizeof(THEMES_PATH), bitmap); - uint8_t * bitmap = bmpLoad(path/*, 51, 31*/); // TODO rescale - LuaTheme * theme = new LuaTheme(name, bitmap, themeOptions); + if (name) { + LuaTheme * theme = new LuaTheme(name, themeOptions); theme->loadFunction = loadFunction; theme->drawBackgroundFunction = drawBackgroundFunction; theme->drawTopbarBackgroundFunction = drawTopbarBackgroundFunction; @@ -1070,21 +1063,24 @@ void luaLoadFiles(const char * directory, void (*callback)()) fno.lfsize = sizeof(lfn); strcpy(path, directory); - int pathlen = strlen(path); FRESULT res = f_opendir(&dir, path); /* Open the directory */ if (res == FR_OK) { + int pathlen = strlen(path); path[pathlen++] = '/'; for (;;) { res = f_readdir(&dir, &fno); /* Read a directory item */ if (res != FR_OK || fno.fname[0] == 0) break; /* Break on error or end of dir */ fn = * fno.lfname ? fno.lfname : fno.fname; uint8_t len = strlen(fn); - // Eliminates directories / non scripts files - if (len < 5 || strcasecmp(fn+len-4, SCRIPTS_EXT) || (fno.fattrib & AM_DIR)) continue; - strcpy(&path[pathlen], fn); - luaLoadFile(path, callback); + if (len > 0 && fn[0]!='.' && (fno.fattrib & AM_DIR)) { + strcpy(&path[pathlen], fn); + strcat(&path[pathlen], "/main.lua"); + if (isFileAvailable(path)) { + luaLoadFile(path, callback); + } + } } } else { diff --git a/radio/src/opentx.cpp b/radio/src/opentx.cpp index 0e24d59dc..c95c002b6 100644 --- a/radio/src/opentx.cpp +++ b/radio/src/opentx.cpp @@ -38,7 +38,7 @@ bool loadModelBitmap(char * name, uint8_t * bitmap) char lfn[] = BITMAPS_PATH "/xxxxxxxxxx.bmp"; strncpy(lfn+sizeof(BITMAPS_PATH), name, len); strcpy(lfn+sizeof(BITMAPS_PATH)+len, BITMAPS_EXT); - if (bmpLoad(bitmap, lfn, MODEL_BITMAP_WIDTH, MODEL_BITMAP_HEIGHT)) { + if (lcdLoadBitmap(bitmap, lfn, MODEL_BITMAP_WIDTH, MODEL_BITMAP_HEIGHT)) { return true; } } @@ -2606,7 +2606,7 @@ int main(void) // lcdSetRefVolt(25); #endif -#if defined(PCBTARANIS) +#if defined(PCBTARANIS) || defined(PCBHORUS) drawSplash(); #endif diff --git a/radio/src/opentx.h b/radio/src/opentx.h index ec78f0d87..667e417f4 100644 --- a/radio/src/opentx.h +++ b/radio/src/opentx.h @@ -203,7 +203,11 @@ #define ROTARY_ENCODER_NAVIGATION #endif -#define __ALIGNED __attribute__((aligned(32))) +#if defined(SIMU) + #define __ALIGNED +#else + #define __ALIGNED __attribute__((aligned(32))) +#endif #if defined(SIMU) #define __DMA @@ -213,7 +217,7 @@ #define __DMA __ALIGNED #endif -#if defined(PCBHORUS) +#if defined(PCBHORUS) && !defined(SIMU) #define __SDRAM __attribute__((section(".sdram"), aligned(32))) #else #define __SDRAM __DMA diff --git a/radio/src/sdcard.h b/radio/src/sdcard.h index 9e817bd21..a19e29491 100644 --- a/radio/src/sdcard.h +++ b/radio/src/sdcard.h @@ -36,9 +36,9 @@ #define EEPROMS_PATH ROOT_PATH "EEPROMS" #define SCRIPTS_PATH ROOT_PATH "SCRIPTS" #define WIZARD_PATH SCRIPTS_PATH "/WIZARD" -#define THEMES_PATH SCRIPTS_PATH "/THEMES" -#define LAYOUTS_PATH SCRIPTS_PATH "/LAYOUTS" -#define WIDGETS_PATH SCRIPTS_PATH "/WIDGETS" +#define THEMES_PATH ROOT_PATH "THEMES" +#define LAYOUTS_PATH ROOT_PATH "LAYOUTS" +#define WIDGETS_PATH ROOT_PATH "WIDGETS" #define WIZARD_NAME "wizard.lua" #define TEMPLATES_PATH SCRIPTS_PATH "/TEMPLATES" #define SCRIPTS_MIXES_PATH SCRIPTS_PATH "/MIXES" @@ -57,6 +57,13 @@ #define EEPROM_EXT ".bin" #define SPORT_FIRMWARE_EXT ".frk" +#define GET_FILENAME(filename, path, var, ext) \ + char filename[sizeof(path) + sizeof(var) + sizeof(ext)]; \ + memcpy(filename, path, sizeof(path) - 1); \ + filename[sizeof(path) - 1] = '/'; \ + memcpy(&filename[sizeof(path)], var, sizeof(var)); \ + strcat(&filename[sizeof(path)], ext) + extern FATFS g_FATFS_Obj; extern FIL g_oLogFile; diff --git a/radio/src/syscalls.c b/radio/src/syscalls.c index 08b9d0a4e..eb5e995c8 100644 --- a/radio/src/syscalls.c +++ b/radio/src/syscalls.c @@ -147,7 +147,7 @@ extern int _getpid ( void ) return -1 ; } -void _init (void) -{ +//void _init (void) +//{ -} +//} diff --git a/radio/src/targets/horus/board_horus.h b/radio/src/targets/horus/board_horus.h index d47fa33fb..227f6194d 100644 --- a/radio/src/targets/horus/board_horus.h +++ b/radio/src/targets/horus/board_horus.h @@ -259,8 +259,8 @@ void ledBlue(void); // LCD driver void lcdInit(void); void lcdRefresh(void); -void lcdDrawSolidFilledRectDMA(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color); -void lcdDrawBitmapDMA(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t * bitmap); +void DMAFillRect(uint16_t * dest, uint16_t destw, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color); +void DMACopyBitmap(uint16_t * dest, uint16_t destw, uint16_t x, uint16_t y, const uint16_t * src, uint16_t srcw, uint16_t h); void lcdStoreBackupBuffer(void); int lcdRestoreBackupBuffer(void); diff --git a/radio/src/targets/horus/lcd_driver.cpp b/radio/src/targets/horus/lcd_driver.cpp index 38280a756..9da6039f4 100644 --- a/radio/src/targets/horus/lcd_driver.cpp +++ b/radio/src/targets/horus/lcd_driver.cpp @@ -2,7 +2,7 @@ * Copyright (C) OpenTX * * Based on code named - * th9x - http://code.google.com/p/th9x + * th9x - http://code.google.com/p/th9x * er9x - http://code.google.com/p/er9x * gruvin9x - http://code.google.com/p/gruvin9x * @@ -41,7 +41,6 @@ uint8_t LCD_FIRST_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM; uint8_t LCD_SECOND_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM; uint8_t LCD_BACKUP_FRAME_BUFFER[DISPLAY_BUFFER_SIZE] __SDRAM; -uint8_t * CurrentFrameBuffer = LCD_FIRST_FRAME_BUFFER; uint32_t CurrentLayer = LCD_FIRST_LAYER; #define NRST_LOW() do { LCD_GPIO_NRST->BSRRH = LCD_GPIO_PIN_NRST; } while(0) @@ -381,6 +380,10 @@ void LCD_Init(void) LCD_ControlLight(100); } +BitmapBuffer lcdBuffer1(LCD_W, LCD_H, (uint16_t *)LCD_FIRST_FRAME_BUFFER); +BitmapBuffer lcdBuffer2(LCD_W, LCD_H, (uint16_t *)LCD_SECOND_FRAME_BUFFER); +BitmapBuffer * lcd = &lcdBuffer1; + /** * @brief Sets the LCD Layer. * @param Layerx: specifies the Layer foreground or background. @@ -389,11 +392,11 @@ void LCD_Init(void) void LCD_SetLayer(uint32_t Layerx) { if (Layerx == LCD_FIRST_LAYER) { - CurrentFrameBuffer = LCD_FIRST_FRAME_BUFFER; + lcd = &lcdBuffer1; CurrentLayer = LCD_FIRST_LAYER; } else { - CurrentFrameBuffer = LCD_SECOND_FRAME_BUFFER; + lcd = &lcdBuffer2; CurrentLayer = LCD_SECOND_LAYER; } } @@ -428,31 +431,26 @@ void lcdInit(void) LCD_SetLayer(LCD_FIRST_LAYER); // lcdClear(); LCD_SetTransparency(0); - + /* Set Foreground layer */ LCD_SetLayer(LCD_SECOND_LAYER); - lcdClear(); + lcd->clear(); LCD_SetTransparency(255); } -void lcdDrawSolidFilledRectDMA(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color) +void DMAFillRect(uint16_t * dest, uint16_t destw, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t color) { - uint32_t addr = (uint32_t)CurrentFrameBuffer + 2*(LCD_W*y + x); - uint8_t red = (0xF800 & color) >> 11; - uint8_t blue = 0x001F & color; - uint8_t green = (0x07E0 & color) >> 5; - DMA2D_DeInit(); DMA2D_InitTypeDef DMA2D_InitStruct; DMA2D_InitStruct.DMA2D_Mode = DMA2D_R2M; DMA2D_InitStruct.DMA2D_CMode = DMA2D_RGB565; - DMA2D_InitStruct.DMA2D_OutputGreen = green; - DMA2D_InitStruct.DMA2D_OutputBlue = blue; - DMA2D_InitStruct.DMA2D_OutputRed = red; + DMA2D_InitStruct.DMA2D_OutputGreen = (0x07E0 & color) >> 5; + DMA2D_InitStruct.DMA2D_OutputBlue = 0x001F & color; + DMA2D_InitStruct.DMA2D_OutputRed = (0xF800 & color) >> 11; DMA2D_InitStruct.DMA2D_OutputAlpha = 0x0F; - DMA2D_InitStruct.DMA2D_OutputMemoryAdd = addr; - DMA2D_InitStruct.DMA2D_OutputOffset = (LCD_W - w); + DMA2D_InitStruct.DMA2D_OutputMemoryAdd = CONVERT_PTR_UINT(dest) + 2*(destw*y + x); + DMA2D_InitStruct.DMA2D_OutputOffset = (destw - w); DMA2D_InitStruct.DMA2D_NumberOfLine = h; DMA2D_InitStruct.DMA2D_PixelPerLine = w; DMA2D_Init(&DMA2D_InitStruct); @@ -464,31 +462,26 @@ void lcdDrawSolidFilledRectDMA(uint16_t x, uint16_t y, uint16_t w, uint16_t h, u while (DMA2D_GetFlagStatus(DMA2D_FLAG_TC) == RESET); } -void lcdDrawBitmapDMA(uint16_t x, uint16_t y, uint16_t w, uint16_t h, const uint8_t * bitmap) +void DMACopyBitmap(uint16_t * dest, uint16_t destw, uint16_t x, uint16_t y, const uint16_t * src, uint16_t srcw, uint16_t h) { - if ((uint32_t(bitmap) & 0x03) != 0) - return; - - uint32_t addr = (uint32_t)CurrentFrameBuffer + 2*(LCD_W*y + x); - DMA2D_DeInit(); DMA2D_InitTypeDef DMA2D_InitStruct; DMA2D_InitStruct.DMA2D_Mode = DMA2D_M2M; DMA2D_InitStruct.DMA2D_CMode = DMA2D_RGB565; - DMA2D_InitStruct.DMA2D_OutputMemoryAdd = addr; + DMA2D_InitStruct.DMA2D_OutputMemoryAdd = CONVERT_PTR_UINT(dest) + 2*(destw*y + x); DMA2D_InitStruct.DMA2D_OutputGreen = 0; DMA2D_InitStruct.DMA2D_OutputBlue = 0; DMA2D_InitStruct.DMA2D_OutputRed = 0; DMA2D_InitStruct.DMA2D_OutputAlpha = 0; - DMA2D_InitStruct.DMA2D_OutputOffset = (LCD_W - w); + DMA2D_InitStruct.DMA2D_OutputOffset = (destw - srcw); DMA2D_InitStruct.DMA2D_NumberOfLine = h; - DMA2D_InitStruct.DMA2D_PixelPerLine = w; + DMA2D_InitStruct.DMA2D_PixelPerLine = srcw; DMA2D_Init(&DMA2D_InitStruct); DMA2D_FG_InitTypeDef DMA2D_FG_InitStruct; DMA2D_FG_StructInit(&DMA2D_FG_InitStruct); - DMA2D_FG_InitStruct.DMA2D_FGMA = CONVERT_PTR_UINT(bitmap); + DMA2D_FG_InitStruct.DMA2D_FGMA = CONVERT_PTR_UINT(src); DMA2D_FG_InitStruct.DMA2D_FGO = 0; DMA2D_FG_InitStruct.DMA2D_FGCM = CM_RGB565; DMA2D_FG_InitStruct.DMA2D_FGPFC_ALPHA_MODE = NO_MODIF_ALPHA_VALUE; @@ -537,12 +530,12 @@ void DMAcopy(void * src, void * dest, int len) void lcdStoreBackupBuffer() { - DMAcopy(CurrentFrameBuffer, LCD_BACKUP_FRAME_BUFFER, DISPLAY_BUFFER_SIZE); + DMAcopy(lcd->data, LCD_BACKUP_FRAME_BUFFER, DISPLAY_BUFFER_SIZE); } int lcdRestoreBackupBuffer() { - DMAcopy(LCD_BACKUP_FRAME_BUFFER, CurrentFrameBuffer, DISPLAY_BUFFER_SIZE); + DMAcopy(LCD_BACKUP_FRAME_BUFFER, lcd->data, DISPLAY_BUFFER_SIZE); return 1; } diff --git a/radio/src/tests/lcd.cpp b/radio/src/tests/lcd.cpp index 703dfea57..b5ebb93c7 100644 --- a/radio/src/tests/lcd.cpp +++ b/radio/src/tests/lcd.cpp @@ -296,7 +296,7 @@ TEST(Lcd, BMPWrapping) { lcdClear(); uint8_t bitmap[2+40*40/2]; - bmpLoad(bitmap, TESTS_PATH "/tests/plane.bmp", 40, 40); + lcdLoadBitmap(bitmap, TESTS_PATH "/tests/plane.bmp", 40, 40); lcdDrawBitmap(200, 0, bitmap); lcdDrawBitmap(200, 60, bitmap); lcdDrawBitmap(240, 60, bitmap); // x too big @@ -365,31 +365,31 @@ TEST(Lcd, lcdDrawBitmapLoadAndDisplay) // Test proper BMP files, they should display correctly { TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(7, 32)); - EXPECT_TRUE(bmpLoad(bitmap.buffer(), TESTS_PATH "/tests/4b_7x32.bmp", 7, 32) != NULL); + EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/4b_7x32.bmp", 7, 32) != NULL); bitmap.leakCheck(); lcdDrawBitmap(10, 2, bitmap.buffer()); } { TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(6, 32)); - EXPECT_TRUE(bmpLoad(bitmap.buffer(), TESTS_PATH "/tests/1b_6x32.bmp", 6, 32) != NULL); + EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/1b_6x32.bmp", 6, 32) != NULL); bitmap.leakCheck(); lcdDrawBitmap(20, 2, bitmap.buffer()); } { TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(31, 31)); - EXPECT_TRUE(bmpLoad(bitmap.buffer(), TESTS_PATH "/tests/4b_31x31.bmp", 31, 31) != NULL); + EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/4b_31x31.bmp", 31, 31) != NULL); bitmap.leakCheck(); lcdDrawBitmap(30, 2, bitmap.buffer()); } { TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(39, 32)); - EXPECT_TRUE(bmpLoad(bitmap.buffer(), TESTS_PATH "/tests/1b_39x32.bmp", 39, 32) != NULL); + EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/1b_39x32.bmp", 39, 32) != NULL); bitmap.leakCheck(); lcdDrawBitmap(70, 2, bitmap.buffer()); } { TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(20, 20)); - EXPECT_TRUE(bmpLoad(bitmap.buffer(), TESTS_PATH "/tests/4b_20x20.bmp", 20, 20) != NULL); + EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/4b_20x20.bmp", 20, 20) != NULL); bitmap.leakCheck(); lcdDrawBitmap(120, 2, bitmap.buffer()); } @@ -398,12 +398,12 @@ TEST(Lcd, lcdDrawBitmapLoadAndDisplay) // Test various bad BMP files, they should not display { TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(LCD_W+1, 32)); - EXPECT_TRUE(bmpLoad(bitmap.buffer(), "", LCD_W+1, 32) == NULL) << "to wide"; + EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), "", LCD_W+1, 32) == NULL) << "to wide"; bitmap.leakCheck(); } { TestBuffer<1000> bitmap(BITMAP_BUFFER_SIZE(10, 10)); - EXPECT_TRUE(bmpLoad(bitmap.buffer(), TESTS_PATH "/tests/1b_39x32.bmp", 10, 10) == NULL) << "to small buffer"; + EXPECT_TRUE(lcdLoadBitmap(bitmap.buffer(), TESTS_PATH "/tests/1b_39x32.bmp", 10, 10) == NULL) << "to small buffer"; bitmap.leakCheck(); } } diff --git a/radio/src/translations/en.h.txt b/radio/src/translations/en.h.txt index d069b009e..e08298acb 100644 --- a/radio/src/translations/en.h.txt +++ b/radio/src/translations/en.h.txt @@ -873,10 +873,17 @@ #define TR_DELAY "Delay" #define TR_SD_CARD "SD CARD" #define TR_SDHC_CARD "SD-HC CARD" +#if defined(COLORLCD) +#define TR_NO_SOUNDS_ON_SD "No Sounds" +#define TR_NO_MODELS_ON_SD "No Models" +#define TR_NO_BITMAPS_ON_SD "No Bitmaps" +#define TR_NO_SCRIPTS_ON_SD "No Scripts" +#else #define TR_NO_SOUNDS_ON_SD "No Sounds" BREAKSPACE "on SD" #define TR_NO_MODELS_ON_SD "No Models" BREAKSPACE "on SD" #define TR_NO_BITMAPS_ON_SD "No Bitmaps" BREAKSPACE "on SD" #define TR_NO_SCRIPTS_ON_SD "No Scripts" BREAKSPACE "on SD" +#endif #define TR_SCRIPT_SYNTAX_ERROR "Script syntax error" #define TR_SCRIPT_PANIC "Script panic" #define TR_SCRIPT_KILLED "Script killed" diff --git a/radio/util/img2lbm.py b/radio/util/img2lbm.py index dd88a8eca..b23b15a6e 100755 --- a/radio/util/img2lbm.py +++ b/radio/util/img2lbm.py @@ -41,29 +41,32 @@ with open(sys.argv[2], "w") as f: f.write("0x%02x," % value) f.write("\n") elif what == "4/4/4/4": - colors = [] - f.write("%d,%d,\n" % (width, height)) + constant = sys.argv[2].upper()[:-4] + values = [] for y in range(height): for x in range(width): pixel = image.pixel(x, y) - f.write("0x%1x%1x%1x%1x," % (Qt.qAlpha(pixel) // 16, Qt.qRed(pixel) // 16, Qt.qGreen(pixel) // 16, Qt.qBlue(pixel) // 16)) - f.write("\n") + val = ((Qt.qAlpha(pixel) // 16) << 12) + ((Qt.qRed(pixel) // 16) << 8) + ((Qt.qGreen(pixel) // 16) << 4) + ((Qt.qBlue(pixel) // 16) << 0) + values.append(str(val)) + f.write("const uint16_t __%s[] __ALIGNED = { %s };\n" % (constant, ",".join(values))) + f.write("const Bitmap %s(%d, %d, __%s);\n" % (constant, width, height, constant)) elif what == "5/6/5": - colors = [] - writeSize(f, width, height) + constant = sys.argv[2].upper()[:-4] + values = [] for y in range(height): for x in range(width): pixel = image.pixel(x, y) val = ((Qt.qRed(pixel) >> 3) << 11) + ((Qt.qGreen(pixel) >> 2) << 5) + ((Qt.qBlue(pixel) >> 3) << 0) - f.write("%d,%d," % (val % 256, val // 256)) - f.write("\n") + values.append(str(val)) + f.write("const uint16_t __%s[] __ALIGNED = { %s };\n" % (constant, ",".join(values))) + f.write("const Bitmap %s(%d, %d, __%s);\n" % (constant, width, height, constant)) elif what == "5/6/5/8": colors = [] writeSize(f, width, height) for y in range(height): for x in range(width): pixel = image.pixel(x, y) - val = ((Qt.qRed(pixel) >> 3) << 11) + ((Qt.qGreen(pixel) >> 2) << 5) + ((Qt.qBlue(pixel) >> 3) << 0) + val = ((Qt.qRed(pixel) >> 4) << 12) + ((Qt.qGreen(pixel) >> 4) << 7) + ((Qt.qBlue(pixel) >> 4) << 1) f.write("%d,%d,%d," % (val % 256, val // 256, Qt.qAlpha(pixel))) f.write("\n") elif what == "4bits":