✨ MarlinUI for Ender 3 v2 DWIN LCD (#22594)
Co-Authored-By: Taylor Talkington <taylor.talkington@gmail.com>x301
parent
d51e70083d
commit
73ef26a106
@ -0,0 +1,470 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/********************************************************************************
|
||||
* @file lcd/e3v2/marlinui/dwin_lcd.cpp
|
||||
* @brief DWIN screen control functions
|
||||
********************************************************************************/
|
||||
|
||||
#include "../../../inc/MarlinConfigPre.h"
|
||||
|
||||
#if IS_DWIN_MARLINUI
|
||||
|
||||
#include "../../../inc/MarlinConfig.h"
|
||||
|
||||
#include "dwin_lcd.h"
|
||||
#include <string.h> // for memset
|
||||
|
||||
//#define DEBUG_OUT 1
|
||||
#include "../../../core/debug_out.h"
|
||||
|
||||
// Make sure DWIN_SendBuf is large enough to hold the largest string plus draw command and tail.
|
||||
// Assume the narrowest (6 pixel) font and 2-byte gb2312-encoded characters.
|
||||
uint8_t DWIN_SendBuf[11 + DWIN_WIDTH / 6 * 2] = { 0xAA };
|
||||
uint8_t DWIN_BufTail[4] = { 0xCC, 0x33, 0xC3, 0x3C };
|
||||
uint8_t databuf[26] = { 0 };
|
||||
uint8_t receivedType;
|
||||
|
||||
int recnum = 0;
|
||||
|
||||
inline void DWIN_Byte(size_t &i, const uint16_t bval) {
|
||||
DWIN_SendBuf[++i] = bval;
|
||||
}
|
||||
|
||||
inline void DWIN_Word(size_t &i, const uint16_t wval) {
|
||||
DWIN_SendBuf[++i] = wval >> 8;
|
||||
DWIN_SendBuf[++i] = wval & 0xFF;
|
||||
}
|
||||
|
||||
inline void DWIN_Long(size_t &i, const uint32_t lval) {
|
||||
DWIN_SendBuf[++i] = (lval >> 24) & 0xFF;
|
||||
DWIN_SendBuf[++i] = (lval >> 16) & 0xFF;
|
||||
DWIN_SendBuf[++i] = (lval >> 8) & 0xFF;
|
||||
DWIN_SendBuf[++i] = lval & 0xFF;
|
||||
}
|
||||
|
||||
inline void DWIN_String(size_t &i, char * const string) {
|
||||
const size_t len = _MIN(sizeof(DWIN_SendBuf) - i, strlen(string));
|
||||
memcpy(&DWIN_SendBuf[i+1], string, len);
|
||||
i += len;
|
||||
}
|
||||
|
||||
inline void DWIN_String(size_t &i, const __FlashStringHelper * string) {
|
||||
if (!string) return;
|
||||
const size_t len = strlen_P((PGM_P)string); // cast it to PGM_P, which is basically const char *, and measure it using the _P version of strlen.
|
||||
if (len == 0) return;
|
||||
memcpy(&DWIN_SendBuf[i+1], string, len);
|
||||
i += len;
|
||||
}
|
||||
|
||||
// Send the data in the buffer and the packet end
|
||||
inline void DWIN_Send(size_t &i) {
|
||||
++i;
|
||||
LOOP_L_N(n, i) { LCD_SERIAL.write(DWIN_SendBuf[n]); delayMicroseconds(1); }
|
||||
LOOP_L_N(n, 4) { LCD_SERIAL.write(DWIN_BufTail[n]); delayMicroseconds(1); }
|
||||
}
|
||||
|
||||
/*-------------------------------------- System variable function --------------------------------------*/
|
||||
|
||||
// Handshake (1: Success, 0: Fail)
|
||||
bool DWIN_Handshake(void) {
|
||||
#ifndef LCD_BAUDRATE
|
||||
#define LCD_BAUDRATE 115200
|
||||
#endif
|
||||
LCD_SERIAL.begin(LCD_BAUDRATE);
|
||||
const millis_t serial_connect_timeout = millis() + 1000UL;
|
||||
while (!LCD_SERIAL.connected() && PENDING(millis(), serial_connect_timeout)) { /*nada*/ }
|
||||
|
||||
size_t i = 0;
|
||||
DWIN_Byte(i, 0x00);
|
||||
DWIN_Send(i);
|
||||
|
||||
while (LCD_SERIAL.available() > 0 && recnum < (signed)sizeof(databuf)) {
|
||||
databuf[recnum] = LCD_SERIAL.read();
|
||||
// ignore the invalid data
|
||||
if (databuf[0] != FHONE) { // prevent the program from running.
|
||||
if (recnum > 0) {
|
||||
recnum = 0;
|
||||
ZERO(databuf);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
delay(10);
|
||||
recnum++;
|
||||
}
|
||||
|
||||
return ( recnum >= 3
|
||||
&& databuf[0] == FHONE
|
||||
&& databuf[1] == '\0'
|
||||
&& databuf[2] == 'O'
|
||||
&& databuf[3] == 'K' );
|
||||
}
|
||||
|
||||
void DWIN_Startup(void) {
|
||||
DEBUG_ECHOPGM("\r\nDWIN handshake ");
|
||||
delay(750); // Delay here or init later in the boot process
|
||||
const bool success = DWIN_Handshake();
|
||||
if (success) DEBUG_ECHOLNPGM("ok."); else DEBUG_ECHOLNPGM("error.");
|
||||
DWIN_Frame_SetDir(TERN(DWIN_MARLINUI_LANDSCAPE, 0, 1));
|
||||
DWIN_Frame_Clear(Color_Bg_Black); // MarlinUI handles the bootscreen so just clear here
|
||||
DWIN_UpdateLCD();
|
||||
}
|
||||
|
||||
// Set the backlight luminance
|
||||
// luminance: (0x00-0xFF)
|
||||
void DWIN_Backlight_SetLuminance(const uint8_t luminance) {
|
||||
size_t i = 0;
|
||||
DWIN_Byte(i, 0x30);
|
||||
DWIN_Byte(i, _MAX(luminance, 0x1F));
|
||||
DWIN_Send(i);
|
||||
}
|
||||
|
||||
// Set screen display direction
|
||||
// dir: 0=0°, 1=90°, 2=180°, 3=270°
|
||||
void DWIN_Frame_SetDir(uint8_t dir) {
|
||||
size_t i = 0;
|
||||
DWIN_Byte(i, 0x34);
|
||||
DWIN_Byte(i, 0x5A);
|
||||
DWIN_Byte(i, 0xA5);
|
||||
DWIN_Byte(i, dir);
|
||||
DWIN_Send(i);
|
||||
}
|
||||
|
||||
// Update display
|
||||
void DWIN_UpdateLCD(void) {
|
||||
size_t i = 0;
|
||||
DWIN_Byte(i, 0x3D);
|
||||
DWIN_Send(i);
|
||||
}
|
||||
|
||||
/*---------------------------------------- Drawing functions ----------------------------------------*/
|
||||
|
||||
// Clear screen
|
||||
// color: Clear screen color
|
||||
void DWIN_Frame_Clear(const uint16_t color) {
|
||||
size_t i = 0;
|
||||
DWIN_Byte(i, 0x01);
|
||||
DWIN_Word(i, color);
|
||||
DWIN_Send(i);
|
||||
}
|
||||
|
||||
// Draw a point
|
||||
// width: point width 0x01-0x0F
|
||||
// height: point height 0x01-0x0F
|
||||
// x,y: upper left point
|
||||
void DWIN_Draw_Point(uint16_t color, uint8_t width, uint8_t height, uint16_t x, uint16_t y) {
|
||||
size_t i = 0;
|
||||
DWIN_Byte(i, 0x02);
|
||||
DWIN_Word(i, color);
|
||||
DWIN_Byte(i, width);
|
||||
DWIN_Byte(i, height);
|
||||
DWIN_Word(i, x);
|
||||
DWIN_Word(i, y);
|
||||
DWIN_Send(i);
|
||||
}
|
||||
|
||||
// Draw a line
|
||||
// color: Line segment color
|
||||
// xStart/yStart: Start point
|
||||
// xEnd/yEnd: End point
|
||||
void DWIN_Draw_Line(uint16_t color, uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd) {
|
||||
size_t i = 0;
|
||||
DWIN_Byte(i, 0x03);
|
||||
DWIN_Word(i, color);
|
||||
DWIN_Word(i, xStart);
|
||||
DWIN_Word(i, yStart);
|
||||
DWIN_Word(i, xEnd);
|
||||
DWIN_Word(i, yEnd);
|
||||
DWIN_Send(i);
|
||||
}
|
||||
|
||||
// Draw a rectangle
|
||||
// mode: 0=frame, 1=fill, 2=XOR fill
|
||||
// color: Rectangle color
|
||||
// xStart/yStart: upper left point
|
||||
// xEnd/yEnd: lower right point
|
||||
void DWIN_Draw_Rectangle(uint8_t mode, uint16_t color,
|
||||
uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd) {
|
||||
size_t i = 0;
|
||||
DWIN_Byte(i, 0x05);
|
||||
DWIN_Byte(i, mode);
|
||||
DWIN_Word(i, color);
|
||||
DWIN_Word(i, xStart);
|
||||
DWIN_Word(i, yStart);
|
||||
DWIN_Word(i, xEnd);
|
||||
DWIN_Word(i, yEnd);
|
||||
DWIN_Send(i);
|
||||
}
|
||||
|
||||
// Move a screen area
|
||||
// mode: 0, circle shift; 1, translation
|
||||
// dir: 0=left, 1=right, 2=up, 3=down
|
||||
// dis: Distance
|
||||
// color: Fill color
|
||||
// xStart/yStart: upper left point
|
||||
// xEnd/yEnd: bottom right point
|
||||
void DWIN_Frame_AreaMove(uint8_t mode, uint8_t dir, uint16_t dis,
|
||||
uint16_t color, uint16_t xStart, uint16_t yStart, uint16_t xEnd, uint16_t yEnd) {
|
||||
size_t i = 0;
|
||||
DWIN_Byte(i, 0x09);
|
||||
DWIN_Byte(i, (mode << 7) | dir);
|
||||
DWIN_Word(i, dis);
|
||||
DWIN_Word(i, color);
|
||||
DWIN_Word(i, xStart);
|
||||
DWIN_Word(i, yStart);
|
||||
DWIN_Word(i, xEnd);
|
||||
DWIN_Word(i, yEnd);
|
||||
DWIN_Send(i);
|
||||
}
|
||||
|
||||
/*---------------------------------------- Text related functions ----------------------------------------*/
|
||||
|
||||
// Draw a string
|
||||
// bShow: true=display background color; false=don't display background color
|
||||
// size: Font size
|
||||
// color: Character color
|
||||
// bColor: Background color
|
||||
// x/y: Upper-left coordinate of the string
|
||||
// *string: The string
|
||||
void DWIN_Draw_String(bool bShow, uint8_t size, uint16_t color, uint16_t bColor, uint16_t x, uint16_t y, char *string) {
|
||||
uint8_t widthAdjust = 0;
|
||||
size_t i = 0;
|
||||
DWIN_Byte(i, 0x11);
|
||||
// Bit 7: widthAdjust
|
||||
// Bit 6: bShow
|
||||
// Bit 5-4: Unused (0)
|
||||
// Bit 3-0: size
|
||||
DWIN_Byte(i, (widthAdjust * 0x80) | (bShow * 0x40) | size);
|
||||
DWIN_Word(i, color);
|
||||
DWIN_Word(i, bColor);
|
||||
DWIN_Word(i, x);
|
||||
DWIN_Word(i, y);
|
||||
DWIN_String(i, string);
|
||||
DWIN_Send(i);
|
||||
}
|
||||
|
||||
// Draw a positive integer
|
||||
// bShow: true=display background color; false=don't display background color
|
||||
// zeroFill: true=zero fill; false=no zero fill
|
||||
// zeroMode: 1=leading 0 displayed as 0; 0=leading 0 displayed as a space
|
||||
// size: Font size
|
||||
// color: Character color
|
||||
// bColor: Background color
|
||||
// iNum: Number of digits
|
||||
// x/y: Upper-left coordinate
|
||||
// value: Integer value
|
||||
void DWIN_Draw_IntValue(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color,
|
||||
uint16_t bColor, uint8_t iNum, uint16_t x, uint16_t y, uint16_t value) {
|
||||
size_t i = 0;
|
||||
DWIN_Byte(i, 0x14);
|
||||
// Bit 7: bshow
|
||||
// Bit 6: 1 = signed; 0 = unsigned number;
|
||||
// Bit 5: zeroFill
|
||||
// Bit 4: zeroMode
|
||||
// Bit 3-0: size
|
||||
DWIN_Byte(i, (bShow * 0x80) | (zeroFill * 0x20) | (zeroMode * 0x10) | size);
|
||||
DWIN_Word(i, color);
|
||||
DWIN_Word(i, bColor);
|
||||
DWIN_Byte(i, iNum);
|
||||
DWIN_Byte(i, 0); // fNum
|
||||
DWIN_Word(i, x);
|
||||
DWIN_Word(i, y);
|
||||
#if 0
|
||||
for (char count = 0; count < 8; count++) {
|
||||
DWIN_Byte(i, value);
|
||||
value >>= 8;
|
||||
if (!(value & 0xFF)) break;
|
||||
}
|
||||
#else
|
||||
// Write a big-endian 64 bit integer
|
||||
const size_t p = i + 1;
|
||||
for (char count = 8; count--;) { // 7..0
|
||||
++i;
|
||||
DWIN_SendBuf[p + count] = value;
|
||||
value >>= 8;
|
||||
}
|
||||
#endif
|
||||
|
||||
DWIN_Send(i);
|
||||
}
|
||||
|
||||
// Draw a floating point number
|
||||
// bShow: true=display background color; false=don't display background color
|
||||
// zeroFill: true=zero fill; false=no zero fill
|
||||
// zeroMode: 1=leading 0 displayed as 0; 0=leading 0 displayed as a space
|
||||
// size: Font size
|
||||
// color: Character color
|
||||
// bColor: Background color
|
||||
// iNum: Number of whole digits
|
||||
// fNum: Number of decimal digits
|
||||
// x/y: Upper-left point
|
||||
// value: Float value
|
||||
void DWIN_Draw_FloatValue(uint8_t bShow, bool zeroFill, uint8_t zeroMode, uint8_t size, uint16_t color,
|
||||
uint16_t bColor, uint8_t iNum, uint8_t fNum, uint16_t x, uint16_t y, long value) {
|
||||
//uint8_t *fvalue = (uint8_t*)&value;
|
||||
size_t i = 0;
|
||||
DWIN_Byte(i, 0x14);
|
||||
DWIN_Byte(i, (bShow * 0x80) | (zeroFill * 0x20) | (zeroMode * 0x10) | size);
|
||||
DWIN_Word(i, color);
|
||||
DWIN_Word(i, bColor);
|
||||
DWIN_Byte(i, iNum);
|
||||
DWIN_Byte(i, fNum);
|
||||
DWIN_Word(i, x);
|
||||
DWIN_Word(i, y);
|
||||
DWIN_Long(i, value);
|
||||
/*
|
||||
DWIN_Byte(i, fvalue[3]);
|
||||
DWIN_Byte(i, fvalue[2]);
|
||||
DWIN_Byte(i, fvalue[1]);
|
||||
DWIN_Byte(i, fvalue[0]);
|
||||
*/
|
||||
DWIN_Send(i);
|
||||
}
|
||||
|
||||
/*---------------------------------------- Picture related functions ----------------------------------------*/
|
||||
|
||||
// Draw JPG and cached in #0 virtual display area
|
||||
// id: Picture ID
|
||||
void DWIN_JPG_ShowAndCache(const uint8_t id) {
|
||||
size_t i = 0;
|
||||
DWIN_Word(i, 0x2200);
|
||||
DWIN_Byte(i, id);
|
||||
DWIN_Send(i); // AA 23 00 00 00 00 08 00 01 02 03 CC 33 C3 3C
|
||||
}
|
||||
|
||||
// Draw an Icon
|
||||
// libID: Icon library ID
|
||||
// picID: Icon ID
|
||||
// x/y: Upper-left point
|
||||
void DWIN_ICON_Show(uint8_t libID, uint8_t picID, uint16_t x, uint16_t y) {
|
||||
NOMORE(x, DWIN_WIDTH - 1);
|
||||
NOMORE(y, DWIN_HEIGHT - 1); // -- ozy -- srl
|
||||
size_t i = 0;
|
||||
DWIN_Byte(i, 0x23);
|
||||
DWIN_Word(i, x);
|
||||
DWIN_Word(i, y);
|
||||
DWIN_Byte(i, 0x80 | libID);
|
||||
//DWIN_Byte(i, libID);
|
||||
DWIN_Byte(i, picID);
|
||||
DWIN_Send(i);
|
||||
}
|
||||
|
||||
// Unzip the JPG picture to a virtual display area
|
||||
// n: Cache index
|
||||
// id: Picture ID
|
||||
void DWIN_JPG_CacheToN(uint8_t n, uint8_t id) {
|
||||
size_t i = 0;
|
||||
DWIN_Byte(i, 0x25);
|
||||
DWIN_Byte(i, n);
|
||||
DWIN_Byte(i, id);
|
||||
DWIN_Send(i);
|
||||
}
|
||||
|
||||
// Copy area from virtual display area to current screen
|
||||
// cacheID: virtual area number
|
||||
// xStart/yStart: Upper-left of virtual area
|
||||
// xEnd/yEnd: Lower-right of virtual area
|
||||
// x/y: Screen paste point
|
||||
void DWIN_Frame_AreaCopy(uint8_t cacheID, uint16_t xStart, uint16_t yStart,
|
||||
uint16_t xEnd, uint16_t yEnd, uint16_t x, uint16_t y) {
|
||||
size_t i = 0;
|
||||
DWIN_Byte(i, 0x27);
|
||||
DWIN_Byte(i, 0x80 | cacheID);
|
||||
DWIN_Word(i, xStart);
|
||||
DWIN_Word(i, yStart);
|
||||
DWIN_Word(i, xEnd);
|
||||
DWIN_Word(i, yEnd);
|
||||
DWIN_Word(i, x);
|
||||
DWIN_Word(i, y);
|
||||
DWIN_Send(i);
|
||||
}
|
||||
|
||||
// Animate a series of icons
|
||||
// animID: Animation ID; 0x00-0x0F
|
||||
// animate: true on; false off;
|
||||
// libID: Icon library ID
|
||||
// picIDs: Icon starting ID
|
||||
// picIDe: Icon ending ID
|
||||
// x/y: Upper-left point
|
||||
// interval: Display time interval, unit 10mS
|
||||
void DWIN_ICON_Animation(uint8_t animID, bool animate, uint8_t libID, uint8_t picIDs, uint8_t picIDe, uint16_t x, uint16_t y, uint16_t interval) {
|
||||
NOMORE(x, DWIN_WIDTH - 1);
|
||||
NOMORE(y, DWIN_HEIGHT - 1); // -- ozy -- srl
|
||||
size_t i = 0;
|
||||
DWIN_Byte(i, 0x28);
|
||||
DWIN_Word(i, x);
|
||||
DWIN_Word(i, y);
|
||||
// Bit 7: animation on or off
|
||||
// Bit 6: start from begin or end
|
||||
// Bit 5-4: unused (0)
|
||||
// Bit 3-0: animID
|
||||
DWIN_Byte(i, (animate * 0x80) | 0x40 | animID);
|
||||
DWIN_Byte(i, libID);
|
||||
DWIN_Byte(i, picIDs);
|
||||
DWIN_Byte(i, picIDe);
|
||||
DWIN_Byte(i, interval);
|
||||
DWIN_Send(i);
|
||||
}
|
||||
|
||||
// Animation Control
|
||||
// state: 16 bits, each bit is the state of an animation id
|
||||
void DWIN_ICON_AnimationControl(uint16_t state) {
|
||||
size_t i = 0;
|
||||
DWIN_Byte(i, 0x29);
|
||||
DWIN_Word(i, state);
|
||||
DWIN_Send(i);
|
||||
}
|
||||
|
||||
/*---------------------------------------- Memory functions ----------------------------------------*/
|
||||
// The LCD has an additional 32KB SRAM and 16KB Flash
|
||||
|
||||
// Data can be written to the sram and save to one of the jpeg page files
|
||||
|
||||
// Write Data Memory
|
||||
// command 0x31
|
||||
// Type: Write memory selection; 0x5A=SRAM; 0xA5=Flash
|
||||
// Address: Write data memory address; 0x000-0x7FFF for SRAM; 0x000-0x3FFF for Flash
|
||||
// Data: data
|
||||
//
|
||||
// Flash writing returns 0xA5 0x4F 0x4B
|
||||
|
||||
// Read Data Memory
|
||||
// command 0x32
|
||||
// Type: Read memory selection; 0x5A=SRAM; 0xA5=Flash
|
||||
// Address: Read data memory address; 0x000-0x7FFF for SRAM; 0x000-0x3FFF for Flash
|
||||
// Length: leangth of data to read; 0x01-0xF0
|
||||
//
|
||||
// Response:
|
||||
// Type, Address, Length, Data
|
||||
|
||||
// Write Picture Memory
|
||||
// Write the contents of the 32KB SRAM data memory into the designated image memory space
|
||||
// Issued: 0x5A, 0xA5, PIC_ID
|
||||
// Response: 0xA5 0x4F 0x4B
|
||||
//
|
||||
// command 0x33
|
||||
// 0x5A, 0xA5
|
||||
// PicId: Picture Memory location, 0x00-0x0F
|
||||
//
|
||||
// Flash writing returns 0xA5 0x4F 0x4B
|
||||
|
||||
#endif // IS_DWIN_MARLINUI
|
@ -0,0 +1,180 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../inc/MarlinConfig.h"
|
||||
|
||||
#if IS_DWIN_MARLINUI
|
||||
|
||||
#include "dwin_string.h"
|
||||
//#include "../../fontutils.h"
|
||||
|
||||
uint8_t DWIN_String::data[];
|
||||
uint16_t DWIN_String::span;
|
||||
uint8_t DWIN_String::len;
|
||||
|
||||
void DWIN_String::set() {
|
||||
//*data = 0x00;
|
||||
memset(data, 0x00, sizeof(data));
|
||||
span = 0;
|
||||
len = 0;
|
||||
}
|
||||
|
||||
uint8_t read_byte(uint8_t *byte) { return *byte; }
|
||||
|
||||
/**
|
||||
* Add a string, applying substitutions for the following characters:
|
||||
*
|
||||
* = displays '0'....'10' for indexes 0 - 10
|
||||
* ~ displays '1'....'11' for indexes 0 - 10
|
||||
* * displays 'E1'...'E11' for indexes 0 - 10 (By default. Uses LCD_FIRST_TOOL)
|
||||
*/
|
||||
void DWIN_String::add(uint8_t *string, int8_t index, uint8_t *itemString) {
|
||||
wchar_t wchar;
|
||||
|
||||
while (*string) {
|
||||
string = get_utf8_value_cb(string, read_byte, &wchar);
|
||||
if (wchar > 255) wchar |= 0x0080;
|
||||
uint8_t ch = uint8_t(wchar & 0x00FF);
|
||||
|
||||
if (ch == '=' || ch == '~' || ch == '*') {
|
||||
if (index >= 0) {
|
||||
int8_t inum = index + ((ch == '=') ? 0 : LCD_FIRST_TOOL);
|
||||
if (ch == '*') add_character('E');
|
||||
if (inum >= 10) { add_character('0' + (inum / 10)); inum %= 10; }
|
||||
add_character('0' + inum);
|
||||
}
|
||||
else {
|
||||
add(index == -2 ? GET_TEXT(MSG_CHAMBER) : GET_TEXT(MSG_BED));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else if (ch == '$' && itemString) {
|
||||
add(itemString);
|
||||
continue;
|
||||
}
|
||||
|
||||
add_character(ch);
|
||||
}
|
||||
eol();
|
||||
}
|
||||
|
||||
void DWIN_String::add(uint8_t *string, uint8_t max_len) {
|
||||
wchar_t wchar;
|
||||
while (*string && max_len) {
|
||||
string = get_utf8_value_cb(string, read_byte, &wchar);
|
||||
/*
|
||||
if (wchar > 255) wchar |= 0x0080;
|
||||
uint8_t ch = uint8_t(wchar & 0x00FF);
|
||||
add_character(ch);
|
||||
*/
|
||||
add(wchar);
|
||||
max_len--;
|
||||
}
|
||||
eol();
|
||||
}
|
||||
|
||||
void DWIN_String::add(wchar_t character) {
|
||||
int ret;
|
||||
size_t idx = 0;
|
||||
dwin_charmap_t pinval;
|
||||
dwin_charmap_t *copy_address = nullptr;
|
||||
pinval.uchar = character;
|
||||
pinval.idx = -1;
|
||||
|
||||
// For 8-bit ASCII just print the single character
|
||||
char str[] = { '?', 0 };
|
||||
if (character < 255) {
|
||||
str[0] = (char)character;
|
||||
}
|
||||
else {
|
||||
copy_address = nullptr;
|
||||
ret = pf_bsearch_r((void *)g_dwin_charmap_device, COUNT(g_dwin_charmap_device), pf_bsearch_cb_comp_dwinmap_pgm, (void *)&pinval, &idx);
|
||||
if (ret >= 0) {
|
||||
copy_address = (dwin_charmap_t*)(g_dwin_charmap_device + idx);
|
||||
}
|
||||
else {
|
||||
ret = pf_bsearch_r((void *)g_dwin_charmap_common, COUNT(g_dwin_charmap_common), pf_bsearch_cb_comp_dwinmap_pgm, (void *)&pinval, &idx);
|
||||
if (ret >= 0)
|
||||
copy_address = (dwin_charmap_t*)(g_dwin_charmap_common + idx);
|
||||
}
|
||||
if (ret >= 0) {
|
||||
dwin_charmap_t localval;
|
||||
memcpy_P(&localval, copy_address, sizeof(localval));
|
||||
str[0] = localval.idx;
|
||||
str[1] = localval.idx2;
|
||||
}
|
||||
}
|
||||
if (str[0]) add_character(str[0]);
|
||||
if (str[1]) add_character(str[1]);
|
||||
}
|
||||
|
||||
void DWIN_String::add_character(uint8_t character) {
|
||||
if (len < MAX_STRING_LENGTH) {
|
||||
data[len] = character;
|
||||
len++;
|
||||
//span += glyph(character)->DWidth;
|
||||
}
|
||||
}
|
||||
|
||||
void DWIN_String::rtrim(uint8_t character) {
|
||||
while (len) {
|
||||
if (data[len - 1] == 0x20 || data[len - 1] == character) {
|
||||
len--;
|
||||
//span -= glyph(data[length])->DWidth;
|
||||
eol();
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void DWIN_String::ltrim(uint8_t character) {
|
||||
uint16_t i, j;
|
||||
for (i = 0; (i < len) && (data[i] == 0x20 || data[i] == character); i++) {
|
||||
//span -= glyph(data[i])->DWidth;
|
||||
}
|
||||
if (i == 0) return;
|
||||
for (j = 0; i < len; data[j++] = data[i++]);
|
||||
len = j;
|
||||
eol();
|
||||
}
|
||||
|
||||
void DWIN_String::trim(uint8_t character) {
|
||||
rtrim(character);
|
||||
ltrim(character);
|
||||
}
|
||||
|
||||
/* return v1 - v2 */
|
||||
int dwin_charmap_compare(dwin_charmap_t *v1, dwin_charmap_t *v2) {
|
||||
return (v1->uchar < v2->uchar) ? -1 : (v1->uchar > v2->uchar) ? 1 : 0;
|
||||
}
|
||||
|
||||
int pf_bsearch_cb_comp_dwinmap_pgm(void *userdata, size_t idx, void * data_pin) {
|
||||
dwin_charmap_t localval;
|
||||
dwin_charmap_t *p_dwin_charmap = (dwin_charmap_t *)userdata;
|
||||
memcpy_P(&localval, p_dwin_charmap + idx, sizeof(localval));
|
||||
return dwin_charmap_compare(&localval, (dwin_charmap_t *)data_pin);
|
||||
}
|
||||
|
||||
DWIN_String dwin_string;
|
||||
|
||||
#endif // IS_DWIN_MARLINUI
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,193 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* lcd/e3v2/marlinui/lcdprint_dwin.cpp
|
||||
*
|
||||
* Due to DWIN hardware limitations simplified characters are used
|
||||
*/
|
||||
|
||||
#include "../../../inc/MarlinConfigPre.h"
|
||||
|
||||
#if IS_DWIN_MARLINUI
|
||||
|
||||
#include "lcdprint_dwin.h"
|
||||
#include "dwin_lcd.h"
|
||||
#include "dwin_string.h"
|
||||
|
||||
#include "../../marlinui.h"
|
||||
#include "../../../MarlinCore.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
cursor_t cursor;
|
||||
|
||||
extern dwin_font_t dwin_font;
|
||||
|
||||
void lcd_moveto_xy(const lcd_uint_t x, const lcd_uint_t y) { cursor.x = x; cursor.y = y; }
|
||||
|
||||
void lcd_moveto(const lcd_uint_t col, const lcd_uint_t row) {
|
||||
cursor.x = col * dwin_font.width;
|
||||
cursor.y = (row * (dwin_font.height + EXTRA_ROW_HEIGHT)) + (EXTRA_ROW_HEIGHT / 2);
|
||||
}
|
||||
|
||||
inline void lcd_advance_cursor() { cursor.x += dwin_font.width; }
|
||||
|
||||
void lcd_put_int(const int i) {
|
||||
// TODO: Draw an int at the cursor position, advance the cursor
|
||||
}
|
||||
|
||||
int lcd_put_dwin_string() {
|
||||
DWIN_Draw_String(dwin_font.solid, dwin_font.index, dwin_font.fg, dwin_font.bg, cursor.x, cursor.y, (char*)dwin_string.string());
|
||||
cursor.x += dwin_string.length() * dwin_font.width;
|
||||
return dwin_string.length();
|
||||
}
|
||||
|
||||
// return < 0 on error
|
||||
// return the advanced cols
|
||||
int lcd_put_wchar_max(wchar_t c, pixel_len_t max_length) {
|
||||
dwin_string.set();
|
||||
dwin_string.add(c);
|
||||
dwin_string.truncate(max_length);
|
||||
// Draw the char(s) at the cursor and advance the cursor
|
||||
DWIN_Draw_String(dwin_font.solid, dwin_font.index, dwin_font.fg, dwin_font.bg, cursor.x, cursor.y, (char*)dwin_string.string());
|
||||
cursor.x += dwin_string.length() * dwin_font.width;
|
||||
return dwin_string.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Draw a UTF-8 string
|
||||
*
|
||||
* @param utf8_str : the UTF-8 string
|
||||
* @param cb_read_byte : the callback function to read one byte from the utf8_str (from RAM or ROM)
|
||||
* @param max_length : the pixel length of the string allowed (or number of slots in HD44780)
|
||||
*
|
||||
* @return the number of pixels advanced
|
||||
*
|
||||
* Draw a UTF-8 string
|
||||
*/
|
||||
static int lcd_put_u8str_max_cb(const char * utf8_str, uint8_t (*cb_read_byte)(uint8_t * str), pixel_len_t max_length) {
|
||||
uint8_t *p = (uint8_t *)utf8_str;
|
||||
dwin_string.set();
|
||||
while (dwin_string.length() < max_length) {
|
||||
wchar_t ch = 0;
|
||||
p = get_utf8_value_cb(p, cb_read_byte, &ch);
|
||||
if (!ch) break;
|
||||
dwin_string.add(ch);
|
||||
}
|
||||
DWIN_Draw_String(dwin_font.solid, dwin_font.index, dwin_font.fg, dwin_font.bg, cursor.x, cursor.y, (char*)dwin_string.string());
|
||||
cursor.x += dwin_string.length() * dwin_font.width;
|
||||
return dwin_string.length();
|
||||
}
|
||||
|
||||
int lcd_put_u8str_max(const char * utf8_str, pixel_len_t max_length) {
|
||||
return lcd_put_u8str_max_cb(utf8_str, read_byte_ram, max_length);
|
||||
}
|
||||
|
||||
int lcd_put_u8str_max_P(PGM_P utf8_str_P, pixel_len_t max_length) {
|
||||
return lcd_put_u8str_max_cb(utf8_str_P, read_byte_rom, max_length);
|
||||
}
|
||||
|
||||
lcd_uint_t lcd_put_u8str_ind_P(PGM_P const pstr, const int8_t ind, PGM_P const inStr/*=nullptr*/, const lcd_uint_t maxlen/*=LCD_WIDTH*/) {
|
||||
dwin_string.set();
|
||||
dwin_string.add((uint8_t*)pstr, ind, (uint8_t*)inStr);
|
||||
dwin_string.truncate(maxlen);
|
||||
DWIN_Draw_String(dwin_font.solid, dwin_font.index, dwin_font.fg, dwin_font.bg, cursor.x, cursor.y, (char*)dwin_string.string());
|
||||
cursor.x += dwin_string.length() * dwin_font.width;
|
||||
return dwin_string.length();
|
||||
}
|
||||
|
||||
#if ENABLED(DEBUG_LCDPRINT)
|
||||
|
||||
int test_dwin_charmap(dwin_charmap_t *data, size_t size, char *name, char flg_show_contents) {
|
||||
int ret;
|
||||
size_t idx = 0;
|
||||
dwin_charmap_t preval = { 0, 0, 0 };
|
||||
dwin_charmap_t pinval = { 0, 0, 0 };
|
||||
char flg_error = 0;
|
||||
|
||||
int i;
|
||||
|
||||
TRACE("Test %s\n", name);
|
||||
|
||||
for (i = 0; i < size; i ++) {
|
||||
memcpy_P(&pinval, &(data[i]), sizeof(pinval));
|
||||
|
||||
if (flg_show_contents) {
|
||||
#if 1
|
||||
TRACE("[% 4d] % 6" PRIu32 "(0x%04" PRIX32 ") --> 0x%02X,0x%02X%s\n", i, pinval.uchar, pinval.uchar, (unsigned int)(pinval.idx), (unsigned int)(pinval.idx2), (preval.uchar < pinval.uchar?"":" <--- ERROR"));
|
||||
#else
|
||||
TRACE("[% 4d]", i);
|
||||
TRACE("% 6" PRIu32 "(0x%04" PRIX32 "),", pinval.uchar, pinval.uchar);
|
||||
TRACE("0x%02X,", (unsigned int)(pinval.idx));
|
||||
TRACE("0x%02X,", (unsigned int)(pinval.idx2));
|
||||
TRACE("%s", (preval.uchar < pinval.uchar?"":" <--- ERROR"));
|
||||
#endif
|
||||
}
|
||||
if (preval.uchar >= pinval.uchar) {
|
||||
flg_error = 1;
|
||||
//TRACE("Error: out of order in array %s: idx=%d, val=%d(0x%x)\n", name, i, pinval.uchar, pinval.uchar);
|
||||
//return -1;
|
||||
}
|
||||
memcpy(&preval, &pinval, sizeof(pinval));
|
||||
|
||||
ret = pf_bsearch_r((void *)data, size, pf_bsearch_cb_comp_dwinmap_pgm, (void *)&pinval, &idx);
|
||||
if (ret < 0) {
|
||||
flg_error = 1;
|
||||
TRACE("Error: not found item in array %s: idx=%d, val=%d(0x%x)\n", name, i, pinval.uchar, pinval.uchar);
|
||||
//return -1;
|
||||
}
|
||||
if (idx != i) {
|
||||
flg_error = 1;
|
||||
TRACE("Error: wrong index found item in array %s: idx=%d, val=%d(0x%x)\n", name, i, pinval.uchar, pinval.uchar);
|
||||
//return -1;
|
||||
}
|
||||
}
|
||||
if (flg_error) {
|
||||
TRACE("\nError: in array %s\n\n", name);
|
||||
return -1;
|
||||
}
|
||||
TRACE("\nPASS array %s\n\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test_dwin_charmap_all() {
|
||||
int flg_error = 0;
|
||||
if (test_dwin_charmap(g_dwin_charmap_device, COUNT(g_dwin_charmap_device), "g_dwin_charmap_device", 0) < 0) {
|
||||
flg_error = 1;
|
||||
test_dwin_charmap(g_dwin_charmap_device, COUNT(g_dwin_charmap_device), "g_dwin_charmap_device", 1);
|
||||
}
|
||||
if (test_dwin_charmap(g_dwin_charmap_common, COUNT(g_dwin_charmap_common), "g_dwin_charmap_common", 0) < 0) {
|
||||
flg_error = 1;
|
||||
test_dwin_charmap(g_dwin_charmap_common, COUNT(g_dwin_charmap_common), "g_dwin_charmap_common", 1);
|
||||
}
|
||||
if (flg_error) {
|
||||
TRACE("\nFAILED in dwin tests!\n");
|
||||
return -1;
|
||||
}
|
||||
TRACE("\nPASS in dwin tests.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif // DEBUG_LCDPRINT
|
||||
|
||||
#endif // IS_DWIN_MARLINUI
|
@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "../../lcdprint.h"
|
||||
|
||||
typedef struct { int16_t x, y; } cursor_t;
|
||||
extern cursor_t cursor;
|
||||
|
||||
int lcd_put_dwin_string();
|
||||
void lcd_moveto_xy(const lcd_uint_t, const lcd_uint_t);
|
@ -0,0 +1,146 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
/**
|
||||
* lcd/e3v2/marlinui/lcdprint_dwin.h
|
||||
*/
|
||||
|
||||
#include "../../../inc/MarlinConfigPre.h"
|
||||
#include "dwin_lcd.h"
|
||||
|
||||
typedef uint16_t dwin_coord_t; // Screen can be pretty big
|
||||
typedef uint16_t lcd_uint_t;
|
||||
typedef int16_t lcd_int_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t index, width, height;
|
||||
uint16_t fg, bg;
|
||||
bool solid;
|
||||
} dwin_font_t;
|
||||
|
||||
extern dwin_font_t dwin_font;
|
||||
|
||||
// Only Western languages support big / small fonts
|
||||
//#if DISABLED(DISPLAY_CHARSET_ISO10646_1)
|
||||
// #undef USE_BIG_EDIT_FONT
|
||||
// #undef USE_SMALL_INFOFONT
|
||||
//#endif
|
||||
|
||||
#if ENABLED(USE_BIG_EDIT_FONT)
|
||||
#define DWIN_FONT_EDIT font10x20
|
||||
#else
|
||||
#define DWIN_FONT_EDIT font8x16
|
||||
#endif
|
||||
|
||||
#define DWIN_FONT_INFO font8x16
|
||||
|
||||
#if DWIN_FONT_MENU == font6x12
|
||||
#define MENU_FONT_WIDTH 6
|
||||
#define MENU_FONT_ASCENT 10
|
||||
#define MENU_FONT_DESCENT 2
|
||||
#elif DWIN_FONT_MENU == font8x16
|
||||
#define MENU_FONT_WIDTH 8
|
||||
#define MENU_FONT_ASCENT 13
|
||||
#define MENU_FONT_DESCENT 3
|
||||
#elif DWIN_FONT_MENU == font10x20
|
||||
#define MENU_FONT_WIDTH 10
|
||||
#define MENU_FONT_ASCENT 16
|
||||
#define MENU_FONT_DESCENT 4
|
||||
#endif
|
||||
#define MENU_FONT_HEIGHT (MENU_FONT_ASCENT + MENU_FONT_DESCENT)
|
||||
|
||||
#define EXTRA_ROW_HEIGHT 8
|
||||
#define MENU_LINE_HEIGHT (MENU_FONT_HEIGHT + EXTRA_ROW_HEIGHT)
|
||||
|
||||
#if DWIN_FONT_EDIT == font6x12
|
||||
#define EDIT_FONT_WIDTH 6
|
||||
#define EDIT_FONT_ASCENT 10
|
||||
#define EDIT_FONT_DESCENT 2
|
||||
#elif DWIN_FONT_EDIT == font8x16
|
||||
#define EDIT_FONT_WIDTH 8
|
||||
#define EDIT_FONT_ASCENT 13
|
||||
#define EDIT_FONT_DESCENT 3
|
||||
#elif DWIN_FONT_EDIT == font10x20
|
||||
#define EDIT_FONT_WIDTH 10
|
||||
#define EDIT_FONT_ASCENT 16
|
||||
#define EDIT_FONT_DESCENT 4
|
||||
#endif
|
||||
#define EDIT_FONT_HEIGHT (EDIT_FONT_ASCENT + EDIT_FONT_DESCENT)
|
||||
|
||||
#if DWIN_FONT_INFO == font6x12
|
||||
#define INFO_FONT_WIDTH 6
|
||||
#define INFO_FONT_ASCENT 10
|
||||
#define INFO_FONT_DESCENT 2
|
||||
#elif DWIN_FONT_INFO == font8x16
|
||||
#define INFO_FONT_WIDTH 8
|
||||
#define INFO_FONT_ASCENT 13
|
||||
#define INFO_FONT_DESCENT 3
|
||||
#elif DWIN_FONT_INFO == font10x20
|
||||
#define INFO_FONT_WIDTH 10
|
||||
#define INFO_FONT_ASCENT 16
|
||||
#define INFO_FONT_DESCENT 4
|
||||
#endif
|
||||
#define INFO_FONT_HEIGHT (INFO_FONT_ASCENT + INFO_FONT_DESCENT)
|
||||
|
||||
#if DWIN_FONT_STAT == font6x12
|
||||
#define STAT_FONT_WIDTH 6
|
||||
#define STAT_FONT_ASCENT 10
|
||||
#define STAT_FONT_DESCENT 2
|
||||
#elif DWIN_FONT_STAT == font8x16
|
||||
#define STAT_FONT_WIDTH 8
|
||||
#define STAT_FONT_ASCENT 13
|
||||
#define STAT_FONT_DESCENT 3
|
||||
#elif DWIN_FONT_STAT == font10x20
|
||||
#define STAT_FONT_WIDTH 10
|
||||
#define STAT_FONT_ASCENT 16
|
||||
#define STAT_FONT_DESCENT 4
|
||||
#elif DWIN_FONT_STAT == font12x24
|
||||
#define STAT_FONT_WIDTH 12
|
||||
#define STAT_FONT_ASCENT 19
|
||||
#define STAT_FONT_DESCENT 5
|
||||
#elif DWIN_FONT_STAT == font14x28
|
||||
#define STAT_FONT_WIDTH 14
|
||||
#define STAT_FONT_ASCENT 22
|
||||
#define STAT_FONT_DESCENT 6
|
||||
#elif DWIN_FONT_STAT == font16x32
|
||||
#define STAT_FONT_WIDTH 16
|
||||
#define STAT_FONT_ASCENT 26
|
||||
#define STAT_FONT_DESCENT 6
|
||||
#elif DWIN_FONT_STAT == font20x40
|
||||
#define STAT_FONT_WIDTH 20
|
||||
#define STAT_FONT_ASCENT 32
|
||||
#define STAT_FONT_DESCENT 8
|
||||
#elif DWIN_FONT_STAT == font24x48
|
||||
#define STAT_FONT_WIDTH 24
|
||||
#define STAT_FONT_ASCENT 38
|
||||
#define STAT_FONT_DESCENT 10
|
||||
#elif DWIN_FONT_STAT == font28x56
|
||||
#define STAT_FONT_WIDTH 28
|
||||
#define STAT_FONT_ASCENT 44
|
||||
#define STAT_FONT_DESCENT 12
|
||||
#elif DWIN_FONT_STAT == font32x64
|
||||
#define STAT_FONT_WIDTH 32
|
||||
#define STAT_FONT_ASCENT 50
|
||||
#define STAT_FONT_DESCENT 14
|
||||
#endif
|
||||
#define STAT_FONT_HEIGHT (STAT_FONT_ASCENT + STAT_FONT_DESCENT)
|
@ -0,0 +1,595 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../inc/MarlinConfigPre.h"
|
||||
|
||||
#if IS_DWIN_MARLINUI
|
||||
|
||||
#include "marlinui_dwin.h"
|
||||
#include "dwin_lcd.h"
|
||||
#include "dwin_string.h"
|
||||
|
||||
//#include "../../lcdprint.h"
|
||||
#include "lcdprint_dwin.h"
|
||||
#include "../../fontutils.h"
|
||||
#include "../../../libs/numtostr.h"
|
||||
#include "../../marlinui.h"
|
||||
|
||||
#include "../../../sd/cardreader.h"
|
||||
#include "../../../module/motion.h"
|
||||
#include "../../../module/temperature.h"
|
||||
#include "../../../module/printcounter.h"
|
||||
|
||||
#if ENABLED(SDSUPPORT)
|
||||
#include "../../../libs/duration_t.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
||||
#include "../../../feature/bedlevel/bedlevel.h"
|
||||
#endif
|
||||
|
||||
// DWIN printing specifies the font on each string operation
|
||||
// but we'll make the font modal for Marlin
|
||||
dwin_font_t dwin_font = { font8x16, 8, 16, Color_White, Color_Bg_Black, true };
|
||||
void MarlinUI::set_font(const uint8_t font_nr) {
|
||||
if (font_nr != dwin_font.index) {
|
||||
dwin_font.index = font_nr;
|
||||
uint8_t w, h;
|
||||
switch (font_nr) {
|
||||
default:
|
||||
case font6x12: w = 6; h = 12; break;
|
||||
case font8x16: w = 8; h = 16; break;
|
||||
case font10x20: w = 10; h = 20; break;
|
||||
case font12x24: w = 12; h = 24; break;
|
||||
case font14x28: w = 14; h = 28; break;
|
||||
case font16x32: w = 16; h = 32; break;
|
||||
case font20x40: w = 20; h = 40; break;
|
||||
case font24x48: w = 24; h = 48; break;
|
||||
case font28x56: w = 28; h = 56; break;
|
||||
case font32x64: w = 32; h = 64; break;
|
||||
}
|
||||
dwin_font.width = w;
|
||||
dwin_font.height = h;
|
||||
// TODO: Array with dimensions, auto fit menu items,
|
||||
// update char width / height of the screen based on
|
||||
// new (fixed-width) font size.
|
||||
}
|
||||
}
|
||||
|
||||
// This display is always detected
|
||||
bool MarlinUI::detected() { return true; }
|
||||
|
||||
// Initialize or re-initialize the LCD
|
||||
void MarlinUI::init_lcd() {
|
||||
DWIN_Startup();
|
||||
|
||||
// Load the assets JPG (currently just the status screen 'icon')
|
||||
DWIN_JPG_CacheToN(1, DWIN_MarlinUI_Assets);
|
||||
}
|
||||
|
||||
// This LCD should clear where it will draw anew
|
||||
void MarlinUI::clear_lcd() {
|
||||
DWIN_ICON_AnimationControl(0x0000); // disable all icon animations
|
||||
DWIN_Frame_Clear(Color_Bg_Black);
|
||||
DWIN_UpdateLCD();
|
||||
|
||||
did_first_redraw = false;
|
||||
}
|
||||
|
||||
#if ENABLED(SHOW_BOOTSCREEN)
|
||||
|
||||
void MarlinUI::show_bootscreen() {
|
||||
clear_lcd();
|
||||
dwin_string.set(F(SHORT_BUILD_VERSION));
|
||||
|
||||
#if ENABLED(DWIN_MARLINUI_PORTRAIT)
|
||||
#define LOGO_CENTER ((LCD_PIXEL_WIDTH) / 2)
|
||||
#define INFO_CENTER LOGO_CENTER
|
||||
#define VERSION_Y 330
|
||||
DWIN_ICON_Show(BOOT_ICON, ICON_MarlinBoot, LOGO_CENTER - 266 / 2, 15);
|
||||
DWIN_ICON_Show(BOOT_ICON, ICON_OpenSource, LOGO_CENTER - 174 / 2, 280);
|
||||
DWIN_ICON_Show(BOOT_ICON, ICON_GitHubURL, LOGO_CENTER - 180 / 2, 420);
|
||||
DWIN_ICON_Show(BOOT_ICON, ICON_MarlinURL, LOGO_CENTER - 100 / 2, 440);
|
||||
DWIN_ICON_Show(BOOT_ICON, ICON_Copyright, LOGO_CENTER - 126 / 2, 460);
|
||||
#else
|
||||
#define LOGO_CENTER (280 / 2)
|
||||
#define INFO_CENTER ((LCD_PIXEL_WIDTH) - 200 / 2)
|
||||
#define VERSION_Y 84
|
||||
DWIN_ICON_Show(BOOT_ICON, ICON_MarlinBoot, LOGO_CENTER - 266 / 2, 15);
|
||||
DWIN_ICON_Show(BOOT_ICON, ICON_OpenSource, INFO_CENTER - 174 / 2, 60);
|
||||
DWIN_ICON_Show(BOOT_ICON, ICON_GitHubURL, INFO_CENTER - 180 / 2, 130);
|
||||
DWIN_ICON_Show(BOOT_ICON, ICON_MarlinURL, INFO_CENTER - 100 / 2, 152);
|
||||
DWIN_ICON_Show(BOOT_ICON, ICON_Copyright, INFO_CENTER - 126 / 2, 200);
|
||||
#endif
|
||||
|
||||
DWIN_Draw_String(false, font10x20, Color_Yellow, Color_Bg_Black, INFO_CENTER - (dwin_string.length() * 10) / 2, VERSION_Y, S(dwin_string.string()));
|
||||
DWIN_UpdateLCD();
|
||||
}
|
||||
|
||||
void MarlinUI::bootscreen_completion(const millis_t sofar) {
|
||||
if ((BOOTSCREEN_TIMEOUT) > sofar) safe_delay((BOOTSCREEN_TIMEOUT) - sofar);
|
||||
clear_lcd();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// The kill screen is displayed for unrecoverable conditions
|
||||
void MarlinUI::draw_kill_screen() {
|
||||
set_font(DWIN_FONT_ALERT);
|
||||
DWIN_Frame_Clear(Color_Bg_Black);
|
||||
dwin_font.fg = Color_Error_Red;
|
||||
dwin_font.solid = false;
|
||||
DWIN_Draw_Rectangle(1, Color_Bg_Window, 20, 20, LCD_PIXEL_WIDTH - 20, LCD_PIXEL_HEIGHT - 20);
|
||||
// make the frame a few pixels thick
|
||||
DWIN_Draw_Rectangle(0, Color_Yellow, 20, 20, LCD_PIXEL_WIDTH - 20, LCD_PIXEL_HEIGHT - 20);
|
||||
DWIN_Draw_Rectangle(0, Color_Yellow, 21, 21, LCD_PIXEL_WIDTH - 21, LCD_PIXEL_HEIGHT - 21);
|
||||
DWIN_Draw_Rectangle(0, Color_Yellow, 22, 22, LCD_PIXEL_WIDTH - 22, LCD_PIXEL_HEIGHT - 22);
|
||||
|
||||
uint8_t cx = (LCD_PIXEL_WIDTH / dwin_font.width / 2),
|
||||
cy = (LCD_PIXEL_HEIGHT / dwin_font.height / 2);
|
||||
|
||||
#if ENABLED(DWIN_MARLINUI_LANDSCAPE)
|
||||
cx += (96 / 2 / dwin_font.width);
|
||||
DWIN_ICON_Show(ICON, ICON_Halted, 40, (LCD_PIXEL_HEIGHT - 96) / 2);
|
||||
#else
|
||||
DWIN_ICON_Show(ICON, ICON_Halted, (LCD_PIXEL_WIDTH - 96) / 2, 40);
|
||||
#endif
|
||||
|
||||
uint8_t slen = utf8_strlen(status_message);
|
||||
lcd_moveto(cx - (slen / 2), cy - 1);
|
||||
lcd_put_u8str(status_message);
|
||||
|
||||
slen = utf8_strlen(S(GET_TEXT_F(MSG_HALTED)));
|
||||
lcd_moveto(cx - (slen / 2), cy);
|
||||
lcd_put_u8str_P((const char*)GET_TEXT_F(MSG_HALTED));
|
||||
|
||||
slen = utf8_strlen(S(GET_TEXT_F(MSG_HALTED)));
|
||||
lcd_moveto(cx - (slen / 2), cy + 1);
|
||||
lcd_put_u8str_P((const char*)GET_TEXT_F(MSG_HALTED));
|
||||
}
|
||||
|
||||
//
|
||||
// Status Message
|
||||
//
|
||||
void MarlinUI::draw_status_message(const bool blink) {
|
||||
set_font(DWIN_FONT_STAT);
|
||||
dwin_font.solid = true;
|
||||
dwin_font.fg = Color_White;
|
||||
dwin_font.bg = Color_Bg_Black;
|
||||
lcd_moveto_xy(0, LCD_PIXEL_HEIGHT - (STAT_FONT_HEIGHT) - 1);
|
||||
|
||||
constexpr uint8_t max_status_chars = (LCD_PIXEL_WIDTH) / (STAT_FONT_WIDTH);
|
||||
|
||||
auto status_changed = []{
|
||||
static uint16_t old_hash = 0x0000;
|
||||
uint16_t hash = 0x0000;
|
||||
for (uint8_t i = 0; i < MAX_MESSAGE_LENGTH; i++) {
|
||||
const char c = ui.status_message[i];
|
||||
if (!c) break;
|
||||
hash = ((hash << 1) | (hash >> 15)) ^ c;
|
||||
}
|
||||
const bool hash_changed = hash != old_hash;
|
||||
old_hash = hash;
|
||||
return hash_changed || !ui.did_first_redraw;
|
||||
};
|
||||
|
||||
#if ENABLED(STATUS_MESSAGE_SCROLLING)
|
||||
static bool last_blink = false;
|
||||
|
||||
// Get the UTF8 character count of the string
|
||||
uint8_t slen = utf8_strlen(status_message);
|
||||
|
||||
// If the string fits into the LCD, just print it and do not scroll it
|
||||
if (slen <= max_status_chars) {
|
||||
|
||||
if (status_changed()) {
|
||||
|
||||
// The string isn't scrolling and may not fill the screen
|
||||
lcd_put_u8str(status_message);
|
||||
|
||||
// Fill the rest with spaces
|
||||
while (slen < max_status_chars) { lcd_put_wchar(' '); ++slen; }
|
||||
}
|
||||
}
|
||||
else {
|
||||
// String is larger than the available line space
|
||||
|
||||
// Get a pointer to the next valid UTF8 character
|
||||
// and the string remaining length
|
||||
uint8_t rlen;
|
||||
const char *stat = status_and_len(rlen);
|
||||
lcd_put_u8str_max(stat, max_status_chars);
|
||||
|
||||
// If the string doesn't completely fill the line...
|
||||
if (rlen < max_status_chars) {
|
||||
lcd_put_wchar('.'); // Always at 1+ spaces left, draw a dot
|
||||
uint8_t chars = max_status_chars - rlen; // Amount of space left in characters
|
||||
if (--chars) { // Draw a second dot if there's space
|
||||
lcd_put_wchar('.');
|
||||
if (--chars)
|
||||
lcd_put_u8str_max(status_message, chars); // Print a second copy of the message
|
||||
}
|
||||
}
|
||||
|
||||
if (last_blink != blink) {
|
||||
last_blink = blink;
|
||||
advance_status_scroll();
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
UNUSED(blink);
|
||||
|
||||
if (status_changed()) {
|
||||
// Get the UTF8 character count of the string
|
||||
uint8_t slen = utf8_strlen(status_message);
|
||||
|
||||
// Just print the string to the LCD
|
||||
lcd_put_u8str_max(status_message, max_status_chars);
|
||||
|
||||
// Fill the rest with spaces if there are missing spaces
|
||||
while (slen < max_status_chars) { lcd_put_wchar(' '); ++slen; }
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#if HAS_LCD_MENU
|
||||
|
||||
#include "../../menu/menu.h"
|
||||
|
||||
#if ENABLED(ADVANCED_PAUSE_FEATURE)
|
||||
|
||||
void MarlinUI::draw_hotend_status(const uint8_t row, const uint8_t extruder) {
|
||||
|
||||
dwin_font.solid = false;
|
||||
dwin_font.fg = Color_White;
|
||||
dwin_string.set("E");
|
||||
dwin_string.add('1' + extruder);
|
||||
dwin_string.add(' ');
|
||||
dwin_string.add(i16tostr3rj(thermalManager.degHotend(extruder)));
|
||||
dwin_string.add('/');
|
||||
if (get_blink() || !thermalManager.heater_idle[thermalManager.idle_index_for_id(extruder)].timed_out)
|
||||
dwin_string.add(i16tostr3rj(thermalManager.degTargetHotend(extruder)));
|
||||
else
|
||||
dwin_string.add(PSTR(" "));
|
||||
|
||||
lcd_moveto(LCD_WIDTH - dwin_string.length(), row);
|
||||
lcd_put_dwin_string();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// Set the colors for a menu item based on whether it is selected
|
||||
static bool mark_as_selected(const uint8_t row, const bool sel, const bool is_static=false) {
|
||||
const dwin_coord_t y = row * (MENU_LINE_HEIGHT) + 1;
|
||||
if (y >= LCD_PIXEL_HEIGHT) return false;
|
||||
|
||||
if (is_static && sel)
|
||||
DWIN_Draw_Box(1, Color_Bg_Heading, 0, y, LCD_PIXEL_WIDTH, MENU_LINE_HEIGHT - 1);
|
||||
else {
|
||||
#if ENABLED(MENU_HOLLOW_FRAME)
|
||||
DWIN_Draw_Box(1, Color_Bg_Black, 0, y, LCD_PIXEL_WIDTH, MENU_LINE_HEIGHT - 1);
|
||||
if (sel) DWIN_Draw_Box(0, Select_Color, 0, y, LCD_PIXEL_WIDTH, MENU_LINE_HEIGHT - 1);
|
||||
#else
|
||||
DWIN_Draw_Box(1, sel ? Select_Color : Color_Bg_Black, 0, y, LCD_PIXEL_WIDTH, MENU_LINE_HEIGHT - 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Draw a static line of text in the same idiom as a menu item
|
||||
|
||||
void MenuItem_static::draw(const uint8_t row, PGM_P const pstr, const uint8_t style/*=SS_DEFAULT*/, const char * const vstr/*=nullptr*/) {
|
||||
// Call mark_as_selected to draw a bigger selection box
|
||||
// and draw the text without a background
|
||||
if (mark_as_selected(row, (bool)(style & SS_INVERT), true)) {
|
||||
ui.set_font(DWIN_FONT_MENU);
|
||||
dwin_font.solid = false;
|
||||
dwin_font.fg = Color_White;
|
||||
|
||||
dwin_string.set();
|
||||
const int8_t plen = pstr ? utf8_strlen_P(pstr) : 0,
|
||||
vlen = vstr ? utf8_strlen(vstr) : 0;
|
||||
if (style & SS_CENTER) {
|
||||
int8_t pad = (LCD_WIDTH - 1 - plen - vlen) / 2;
|
||||
while (--pad) dwin_string.add(' ');
|
||||
}
|
||||
|
||||
if (plen) dwin_string.add((uint8_t*)pstr, itemIndex, (uint8_t*)itemString);
|
||||
if (vlen) dwin_string.add((uint8_t*)vstr);
|
||||
if (style & SS_CENTER) {
|
||||
int8_t pad = (LCD_WIDTH - 1 - plen - vlen) / 2;
|
||||
while (--pad) dwin_string.add(' ');
|
||||
}
|
||||
|
||||
lcd_moveto(1, row);
|
||||
lcd_put_dwin_string();
|
||||
}
|
||||
}
|
||||
|
||||
// Draw a generic menu item
|
||||
void MenuItemBase::_draw(const bool sel, const uint8_t row, PGM_P const pstr, const char, const char post_char) {
|
||||
if (mark_as_selected(row, sel)) {
|
||||
ui.set_font(DWIN_FONT_MENU);
|
||||
dwin_font.solid = false;
|
||||
dwin_font.fg = Color_White;
|
||||
|
||||
dwin_string.set(pstr, itemIndex, itemString);
|
||||
|
||||
pixel_len_t n = LCD_WIDTH - 1 - dwin_string.length();
|
||||
while (--n > 1) dwin_string.add(' ');
|
||||
|
||||
dwin_string.add(post_char);
|
||||
|
||||
lcd_moveto(1, row);
|
||||
lcd_put_dwin_string();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Draw a menu item with an editable value
|
||||
//
|
||||
void MenuEditItemBase::draw(const bool sel, const uint8_t row, PGM_P const pstr, const char* const data, const bool pgm) {
|
||||
if (mark_as_selected(row, sel)) {
|
||||
ui.set_font(DWIN_FONT_MENU);
|
||||
dwin_font.solid = false;
|
||||
dwin_font.fg = Color_White;
|
||||
|
||||
const uint8_t vallen = (pgm ? utf8_strlen_P(data) : utf8_strlen(S(data)));
|
||||
|
||||
dwin_string.set(pstr, itemIndex, itemString);
|
||||
if (vallen) dwin_string.add(':');
|
||||
|
||||
lcd_moveto(1, row);
|
||||
lcd_put_dwin_string();
|
||||
|
||||
if (vallen) {
|
||||
dwin_font.fg = Color_Yellow;
|
||||
dwin_string.set(data);
|
||||
lcd_moveto(LCD_WIDTH - vallen - 1, row);
|
||||
lcd_put_dwin_string();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Draw an edit screen with label and current value
|
||||
//
|
||||
void MenuEditItemBase::draw_edit_screen(PGM_P const pstr, const char* const value/*=nullptr*/) {
|
||||
ui.encoder_direction_normal();
|
||||
|
||||
const dwin_coord_t labellen = utf8_strlen_P(pstr), vallen = utf8_strlen(value);
|
||||
|
||||
dwin_string.set();
|
||||
dwin_string.add((uint8_t*)pstr, itemIndex);
|
||||
if (vallen) dwin_string.add(':'); // If a value is included, add a colon
|
||||
|
||||
// Assume the label is alpha-numeric (with a descender)
|
||||
const uint16_t row = (LCD_HEIGHT / 2) - 1;
|
||||
|
||||
dwin_font.fg = Color_White;
|
||||
dwin_font.solid = true;
|
||||
lcd_moveto((LCD_WIDTH - labellen + !!vallen) / 2, row);
|
||||
lcd_put_dwin_string();
|
||||
|
||||
// If a value is included, print the value in larger text below the label
|
||||
if (vallen) {
|
||||
dwin_string.set();
|
||||
dwin_string.add(value);
|
||||
|
||||
const dwin_coord_t by = (row * MENU_LINE_HEIGHT) + MENU_FONT_HEIGHT + EXTRA_ROW_HEIGHT / 2;
|
||||
DWIN_Draw_String(true, font16x32, Color_Yellow, Color_Bg_Black, (LCD_PIXEL_WIDTH - vallen * 16) / 2, by, S(dwin_string.string()));
|
||||
|
||||
extern screenFunc_t _manual_move_func_ptr;
|
||||
if (ui.currentScreen != _manual_move_func_ptr && !ui.external_control) {
|
||||
|
||||
const dwin_coord_t slider_length = LCD_PIXEL_WIDTH - TERN(DWIN_MARLINUI_LANDSCAPE, 120, 20),
|
||||
slider_height = 16,
|
||||
slider_x = (LCD_PIXEL_WIDTH - slider_length) / 2,
|
||||
slider_y = by + 32 + 4,
|
||||
amount = ui.encoderPosition * slider_length / maxEditValue;
|
||||
|
||||
DWIN_Draw_Rectangle(1, Color_Bg_Window, slider_x - 1, slider_y - 1, slider_x - 1 + slider_length + 2 - 1, slider_y - 1 + slider_height + 2 - 1);
|
||||
if (amount > 0)
|
||||
DWIN_Draw_Box(1, BarFill_Color, slider_x, slider_y, amount, slider_height);
|
||||
if (amount < slider_length)
|
||||
DWIN_Draw_Box(1, Color_Bg_Black, slider_x + amount, slider_y, slider_length - amount, slider_height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void draw_boxed_string(const bool yesopt, PGM_P const pstr, const bool inv) {
|
||||
const uint8_t len = utf8_strlen_P(pstr),
|
||||
mar = TERN(DWIN_MARLINUI_PORTRAIT, 1, 4),
|
||||
col = yesopt ? LCD_WIDTH - mar - len : mar,
|
||||
row = (LCD_HEIGHT >= 8 ? LCD_HEIGHT / 2 + 3 : LCD_HEIGHT - 1);
|
||||
lcd_moveto(col, row);
|
||||
DWIN_Draw_Box(1, inv ? Select_Color : Color_Bg_Black, cursor.x - dwin_font.width, cursor.y + 1, dwin_font.width * (len + 2), dwin_font.height + 2);
|
||||
lcd_put_u8str_P(col, row, pstr);
|
||||
}
|
||||
|
||||
void MenuItem_confirm::draw_select_screen(
|
||||
PGM_P const yes, PGM_P const no, const bool yesno,
|
||||
PGM_P const pref, const char * const string/*=nullptr*/, PGM_P const suff/*=nullptr*/
|
||||
) {
|
||||
ui.set_font(DWIN_FONT_MENU);
|
||||
dwin_font.solid = false;
|
||||
dwin_font.fg = Color_White;
|
||||
ui.draw_select_screen_prompt(pref, string, suff);
|
||||
draw_boxed_string(false, no, !yesno);
|
||||
draw_boxed_string(true, yes, yesno);
|
||||
}
|
||||
|
||||
#if ENABLED(SDSUPPORT)
|
||||
|
||||
void MenuItem_sdbase::draw(const bool sel, const uint8_t row, PGM_P const, CardReader &theCard, const bool isDir) {
|
||||
if (mark_as_selected(row, sel)) {
|
||||
dwin_string.set();
|
||||
|
||||
uint8_t maxlen = LCD_WIDTH - 1;
|
||||
if (isDir) {
|
||||
dwin_string.add(LCD_STR_FOLDER " ");
|
||||
maxlen -= 2;
|
||||
}
|
||||
|
||||
dwin_string.add((uint8_t*)ui.scrolled_filename(theCard, maxlen, row, sel), maxlen);
|
||||
uint8_t n = maxlen - dwin_string.length();
|
||||
while (n > 0) { dwin_string.add(' '); --n; }
|
||||
lcd_moveto(1, row);
|
||||
lcd_put_dwin_string();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SDSUPPORT
|
||||
|
||||
#if ENABLED(AUTO_BED_LEVELING_UBL)
|
||||
|
||||
/**
|
||||
* UBL LCD "radar" map data
|
||||
*/
|
||||
#define MAP_UPPER_LEFT_CORNER_X 5 // These probably should be moved to the .h file But for now,
|
||||
#define MAP_UPPER_LEFT_CORNER_Y 5 // it is easier to play with things having them here
|
||||
#define MAP_MAX_PIXELS_X 262 // 272 - 10
|
||||
#define MAP_MAX_PIXELS_Y 262
|
||||
|
||||
void MarlinUI::ubl_plot(const uint8_t x_plot, const uint8_t y_plot) {
|
||||
// Scale the box pixels appropriately
|
||||
dwin_coord_t x_map_pixels = ((MAP_MAX_PIXELS_X - 4) / (GRID_MAX_POINTS_X)) * (GRID_MAX_POINTS_X),
|
||||
y_map_pixels = ((MAP_MAX_PIXELS_Y - 4) / (GRID_MAX_POINTS_Y)) * (GRID_MAX_POINTS_Y),
|
||||
|
||||
pixels_per_x_mesh_pnt = x_map_pixels / (GRID_MAX_POINTS_X),
|
||||
pixels_per_y_mesh_pnt = y_map_pixels / (GRID_MAX_POINTS_Y),
|
||||
|
||||
x_offset = MAP_UPPER_LEFT_CORNER_X + 1 + (MAP_MAX_PIXELS_X - x_map_pixels - 2) / 2,
|
||||
y_offset = MAP_UPPER_LEFT_CORNER_Y + 1 + (MAP_MAX_PIXELS_Y - y_map_pixels - 2) / 2;
|
||||
|
||||
// Clear the Mesh Map
|
||||
|
||||
// First draw the bigger box in White so we have a border around the mesh map box
|
||||
DWIN_Draw_Rectangle(1, Color_White, x_offset - 2, y_offset - 2, x_offset + 2 + x_map_pixels, y_offset + 2 + y_map_pixels);
|
||||
// Now actually clear the mesh map box
|
||||
DWIN_Draw_Rectangle(1, Color_Bg_Black, x_offset, y_offset, x_offset + x_map_pixels, y_offset + y_map_pixels);
|
||||
|
||||
// Fill in the Specified Mesh Point
|
||||
|
||||
const uint8_t y_plot_inv = (GRID_MAX_POINTS_Y - 1) - y_plot; // The origin is typically in the lower right corner. We need to
|
||||
// invert the Y to get it to plot in the right location.
|
||||
|
||||
const dwin_coord_t by = y_offset + y_plot_inv * pixels_per_y_mesh_pnt;
|
||||
DWIN_Draw_Rectangle(1, Select_Color,
|
||||
x_offset + (x_plot * pixels_per_x_mesh_pnt), by,
|
||||
x_offset + (x_plot * pixels_per_x_mesh_pnt) + pixels_per_x_mesh_pnt, by + pixels_per_y_mesh_pnt
|
||||
);
|
||||
|
||||
// Display Mesh Point Locations
|
||||
const dwin_coord_t sx = x_offset + pixels_per_x_mesh_pnt / 2;
|
||||
dwin_coord_t y = y_offset + pixels_per_y_mesh_pnt / 2;
|
||||
for (uint8_t j = 0; j < GRID_MAX_POINTS_Y; j++, y += pixels_per_y_mesh_pnt)
|
||||
for (uint8_t i = 0, x = sx; i < GRID_MAX_POINTS_X; i++, x += pixels_per_x_mesh_pnt)
|
||||
DWIN_Draw_Point(Color_White, 1, 1, x, y);
|
||||
|
||||
// Put Relevant Text on Display
|
||||
|
||||
// Show X and Y positions at top of screen
|
||||
dwin_font.fg = Color_White;
|
||||
dwin_font.solid = true;
|
||||
const xy_pos_t pos = { ubl.mesh_index_to_xpos(x_plot), ubl.mesh_index_to_ypos(y_plot) },
|
||||
lpos = pos.asLogical();
|
||||
|
||||
lcd_moveto(
|
||||
TERN(DWIN_MARLINUI_LANDSCAPE, ((x_offset + x_map_pixels) / MENU_FONT_WIDTH) + 2, 1),
|
||||
TERN(DWIN_MARLINUI_LANDSCAPE, 1, ((y_offset + y_map_pixels) / MENU_LINE_HEIGHT) + 1)
|
||||
);
|
||||
lcd_put_u8str_P(X_LBL);
|
||||
lcd_put_u8str(ftostr52(lpos.x));
|
||||
lcd_moveto(
|
||||
TERN(DWIN_MARLINUI_LANDSCAPE, ((x_offset + x_map_pixels) / MENU_FONT_WIDTH) + 2, 1),
|
||||
TERN(DWIN_MARLINUI_LANDSCAPE, 3, ((y_offset + y_map_pixels) / MENU_LINE_HEIGHT) + 2)
|
||||
);
|
||||
lcd_put_u8str_P(Y_LBL);
|
||||
lcd_put_u8str(ftostr52(lpos.y));
|
||||
|
||||
// Print plot position
|
||||
dwin_string.set("(");
|
||||
dwin_string.add(i8tostr3rj(x_plot));
|
||||
dwin_string.add(",");
|
||||
dwin_string.add(i8tostr3rj(y_plot));
|
||||
dwin_string.add(")");
|
||||
lcd_moveto(
|
||||
TERN(DWIN_MARLINUI_LANDSCAPE, ((x_offset + x_map_pixels) / MENU_FONT_WIDTH) + 2, LCD_WIDTH - dwin_string.length()),
|
||||
TERN(DWIN_MARLINUI_LANDSCAPE, LCD_HEIGHT - 2, ((y_offset + y_map_pixels) / MENU_LINE_HEIGHT) + 1)
|
||||
);
|
||||
lcd_put_dwin_string();
|
||||
|
||||
// Show the location value
|
||||
dwin_string.set(Z_LBL);
|
||||
if (!isnan(ubl.z_values[x_plot][y_plot]))
|
||||
dwin_string.add(ftostr43sign(ubl.z_values[x_plot][y_plot]));
|
||||
else
|
||||
dwin_string.add(PSTR(" -----"));
|
||||
lcd_moveto(
|
||||
TERN(DWIN_MARLINUI_LANDSCAPE, ((x_offset + x_map_pixels) / MENU_FONT_WIDTH) + 2, LCD_WIDTH - dwin_string.length()),
|
||||
TERN(DWIN_MARLINUI_LANDSCAPE, LCD_HEIGHT - 1, ((y_offset + y_map_pixels) / MENU_LINE_HEIGHT) + 2)
|
||||
);
|
||||
lcd_put_dwin_string();
|
||||
}
|
||||
|
||||
#endif // AUTO_BED_LEVELING_UBL
|
||||
|
||||
#if ANY(BABYSTEP_ZPROBE_GFX_OVERLAY, MESH_EDIT_GFX_OVERLAY, BABYSTEP_GFX_OVERLAY)
|
||||
|
||||
void _lcd_zoffset_overlay_gfx(const float zvalue) {
|
||||
// Determine whether the user is raising or lowering the nozzle.
|
||||
static int8_t dir;
|
||||
static float old_zvalue;
|
||||
if (zvalue != old_zvalue) {
|
||||
dir = zvalue ? zvalue < old_zvalue ? -1 : 1 : 0;
|
||||
old_zvalue = zvalue;
|
||||
}
|
||||
|
||||
const int rot_up = TERN(OVERLAY_GFX_REVERSE, ICON_RotateCCW, ICON_RotateCW),
|
||||
rot_down = TERN(OVERLAY_GFX_REVERSE, ICON_RotateCW, ICON_RotateCCW);
|
||||
|
||||
const int nozzle = (LCD_PIXEL_WIDTH / 2) - 20;
|
||||
|
||||
// Draw a representation of the nozzle
|
||||
DWIN_Draw_Box(1, Color_Bg_Black, nozzle + 3, 8, 48, 52); // 'clear' the area where the nozzle is drawn in case it was moved up/down
|
||||
DWIN_ICON_Show(ICON, ICON_HotendOff, nozzle + 3, 10 - dir);
|
||||
DWIN_ICON_Show(ICON, ICON_BedLine, nozzle, 10 + 36);
|
||||
|
||||
// Draw cw/ccw indicator and up/down arrows
|
||||
const int arrow_y = LCD_PIXEL_HEIGHT / 2 - 24;
|
||||
DWIN_ICON_Show(ICON, ICON_DownArrow, 0, arrow_y - dir);
|
||||
DWIN_ICON_Show(ICON, rot_down, 48, arrow_y);
|
||||
|
||||
DWIN_ICON_Show(ICON, ICON_UpArrow, LCD_PIXEL_WIDTH - 10 - (48*2), arrow_y - dir);
|
||||
DWIN_ICON_Show(ICON, rot_up, LCD_PIXEL_WIDTH - 10 - 48, arrow_y);
|
||||
}
|
||||
|
||||
#endif // BABYSTEP_ZPROBE_GFX_OVERLAY || MESH_EDIT_GFX_OVERLAY
|
||||
|
||||
#endif // HAS_LCD_MENU
|
||||
|
||||
#endif // IS_DWIN_MARLINUI
|
@ -0,0 +1,391 @@
|
||||
/**
|
||||
* Marlin 3D Printer Firmware
|
||||
* Copyright (c) 2021 MarlinFirmware [https://github.com/MarlinFirmware/Marlin]
|
||||
*
|
||||
* Based on Sprinter and grbl.
|
||||
* Copyright (c) 2011 Camiel Gubbels / Erik van der Zalm
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../../../inc/MarlinConfigPre.h"
|
||||
|
||||
#if IS_DWIN_MARLINUI
|
||||
|
||||
#include "marlinui_dwin.h"
|
||||
#include "dwin_lcd.h"
|
||||
#include "dwin_string.h"
|
||||
#include "lcdprint_dwin.h"
|
||||
|
||||
#include "../../fontutils.h"
|
||||
#include "../../../libs/numtostr.h"
|
||||
#include "../../marlinui.h"
|
||||
|
||||
#include "../../../sd/cardreader.h"
|
||||
#include "../../../module/motion.h"
|
||||
#include "../../../module/temperature.h"
|
||||
#include "../../../module/printcounter.h"
|
||||
|
||||
#if ENABLED(SDSUPPORT)
|
||||
#include "../../../libs/duration_t.h"
|
||||
#endif
|
||||
|
||||
#if ENABLED(LCD_SHOW_E_TOTAL)
|
||||
#include "../../../MarlinCore.h" // for printingIsActive
|
||||
#endif
|
||||
|
||||
#define STATUS_HEATERS_X 15
|
||||
#define STATUS_HEATERS_Y 56
|
||||
#define STATUS_HEATERS_XSPACE 64
|
||||
#define STATUS_FAN_WIDTH 48
|
||||
#define STATUS_FAN_HEIGHT 48
|
||||
#define STATUS_FAN_Y STATUS_HEATERS_Y + 22
|
||||
#define STATUS_CHR_WIDTH 14
|
||||
#define STATUS_CHR_HEIGHT 28
|
||||
|
||||
//
|
||||
// Before homing, blink '123' <-> '???'.
|
||||
// Homed but unknown... '123' <-> ' '.
|
||||
// Homed and known, display constantly.
|
||||
//
|
||||
FORCE_INLINE void _draw_axis_value(const AxisEnum axis, const char *value, const bool blink, const uint16_t x, const uint16_t y) {
|
||||
uint8_t vallen = utf8_strlen(value);
|
||||
|
||||
if (!ui.did_first_redraw) {
|
||||
dwin_string.set();
|
||||
dwin_string.add('X' + axis);
|
||||
DWIN_Draw_String(true, font16x32, Color_IconBlue, Color_Bg_Black, x + (vallen * 14 - 14) / 2, y + 2, S(dwin_string.string()));
|
||||
}
|
||||
|
||||
dwin_string.set();
|
||||
if (blink)
|
||||
dwin_string.add(value);
|
||||
else {
|
||||
if (!TEST(axis_homed, axis))
|
||||
while (const char c = *value++) dwin_string.add(c <= '.' ? c : '?');
|
||||
else {
|
||||
#if NONE(HOME_AFTER_DEACTIVATE, DISABLE_REDUCED_ACCURACY_WARNING)
|
||||
if (!TEST(axis_trusted, axis))
|
||||
dwin_string.add(TERN1(DWIN_MARLINUI_PORTRAIT, axis == Z_AXIS) ? PSTR(" ") : PSTR(" "));
|
||||
else
|
||||
#endif
|
||||
dwin_string.add(value);
|
||||
}
|
||||
}
|
||||
|
||||
// For E_TOTAL there may be some characters to cover up
|
||||
if (BOTH(DWIN_MARLINUI_PORTRAIT, LCD_SHOW_E_TOTAL) && axis == X_AXIS)
|
||||
dwin_string.add(" ");
|
||||
|
||||
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, x, y + 32, S(dwin_string.string()));
|
||||
}
|
||||
|
||||
#if ENABLED(LCD_SHOW_E_TOTAL)
|
||||
|
||||
FORCE_INLINE void _draw_e_value(const_float_t value, const uint16_t x, const uint16_t y) {
|
||||
const uint8_t scale = value >= 100000.0f ? 10 : 1; // show cm after 99,999mm
|
||||
|
||||
if (!ui.did_first_redraw) {
|
||||
// Extra spaces so we don't have to clear the 'Y' label separately
|
||||
dwin_string.set("E ");
|
||||
DWIN_Draw_String(true, font16x32, Color_IconBlue, Color_Bg_Black, x + (4 * 14 / 2) - 7, y + 2, S(dwin_string.string()));
|
||||
}
|
||||
|
||||
dwin_string.set(ui16tostr5rj(value / scale));
|
||||
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, x, y + 32, S(dwin_string.string()));
|
||||
|
||||
// Extra spaces so we don't have to clear out the Y value separately
|
||||
DWIN_Draw_String(true, font14x28, Color_IconBlue, Color_Bg_Black, x + (5 * 14), y + 32, S(scale == 1 ? "mm " : "cm "));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// Fan Icon and Percentage
|
||||
//
|
||||
FORCE_INLINE void _draw_fan_status(const uint16_t x, const uint16_t y) {
|
||||
const uint16_t fanx = (4 * STATUS_CHR_WIDTH - STATUS_FAN_WIDTH) / 2;
|
||||
const uint8_t fan_pct = thermalManager.scaledFanSpeedPercent(0);
|
||||
const bool fan_on = !!fan_pct;
|
||||
if (fan_on) {
|
||||
DWIN_ICON_Animation(0, fan_on, ICON, ICON_Fan0, ICON_Fan3, x + fanx, y, 25);
|
||||
dwin_string.set(i8tostr3rj(fan_pct));
|
||||
dwin_string.add('%');
|
||||
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, x, y + STATUS_FAN_HEIGHT, S(dwin_string.string()));
|
||||
}
|
||||
else {
|
||||
DWIN_ICON_Show(ICON, ICON_Fan0, x + fanx, y);
|
||||
dwin_string.set(PSTR(" "));
|
||||
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, x, y + STATUS_FAN_HEIGHT, S(dwin_string.string()));
|
||||
}
|
||||
}
|
||||
|
||||
#if HOTENDS > 2
|
||||
#define HOTEND_STATS 3
|
||||
#elif HOTENDS > 1
|
||||
#define HOTEND_STATS 2
|
||||
#elif HAS_HOTEND
|
||||
#define HOTEND_STATS 1
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Draw a single heater icon with current and target temperature, at the given XY
|
||||
*/
|
||||
FORCE_INLINE void _draw_heater_status(const heater_id_t heater, const uint16_t x, const uint16_t y) {
|
||||
|
||||
#if HAS_HOTEND
|
||||
static celsius_t old_temp[HOTEND_STATS] = ARRAY_N_1(HOTEND_STATS, 500),
|
||||
old_target[HOTEND_STATS] = ARRAY_N_1(HOTEND_STATS, 500);
|
||||
static bool old_on[HOTEND_STATS] = ARRAY_N_1(HOTEND_STATS, false);
|
||||
#endif
|
||||
|
||||
#if HAS_HEATED_BED
|
||||
static celsius_t old_bed_temp = 500, old_bed_target = 500;
|
||||
static bool old_bed_on = false;
|
||||
#endif
|
||||
|
||||
#if HAS_HOTEND && HAS_HEATED_BED
|
||||
const bool isBed = heater < 0;
|
||||
const float tc = (isBed ? thermalManager.degBed() : thermalManager.degHotend(heater)),
|
||||
tt = (isBed ? thermalManager.degTargetBed() : thermalManager.degTargetHotend(heater));
|
||||
const uint8_t ta = isBed ? thermalManager.isHeatingBed() : thermalManager.isHeatingHotend(heater);
|
||||
const bool c_draw = tc != (isBed ? old_bed_temp : old_temp[heater]),
|
||||
t_draw = tt != (isBed ? old_bed_target : old_target[heater]),
|
||||
i_draw = ta != (isBed ? old_bed_on : old_on[heater]);
|
||||
if (isBed) { old_bed_temp = tc; old_bed_target = tt; old_bed_on = ta; }
|
||||
else { old_temp[heater] = tc; old_target[heater] = tt; old_on[heater] = ta; }
|
||||
#elif HAS_HOTEND
|
||||
constexpr bool isBed = false;
|
||||
const float tc = thermalManager.degHotend(heater), tt = thermalManager.degTargetHotend(heater);
|
||||
const uint8_t ta = thermalManager.isHeatingHotend(heater);
|
||||
const bool c_draw = tc != old_bed_temp, t_draw = tt != old_bed_target, i_draw = ta != old_bed_on;
|
||||
old_temp[heater] = tc; old_target[heater] = tt; old_on[heater] = ta;
|
||||
#elif HAS_HEATED_BED
|
||||
constexpr bool isBed = true;
|
||||
const float tc = thermalManager.degBed(), tt = thermalManager.degTargetBed();
|
||||
const uint8_t ta = thermalManager.isHeatingBed();
|
||||
const bool c_draw = tc != old_temp[heater], t_draw = tt != old_target[heater], i_draw = ta != old_on[heater];
|
||||
old_bed_temp = tc; old_bed_target = tt; old_bed_on = ta;
|
||||
#endif
|
||||
|
||||
if (!ui.did_first_redraw || t_draw) {
|
||||
dwin_string.set(i16tostr3rj(tt + 0.5));
|
||||
dwin_string.add(LCD_STR_DEGREE);
|
||||
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, x, y, S(dwin_string.string()));
|
||||
}
|
||||
|
||||
if (!ui.did_first_redraw || i_draw)
|
||||
DWIN_ICON_Show(ICON, (isBed ? ICON_BedOff : ICON_HotendOff) + ta, x, y + STATUS_CHR_HEIGHT + 2);
|
||||
|
||||
if (!ui.did_first_redraw || c_draw) {
|
||||
dwin_string.set(i16tostr3rj(tc + 0.5));
|
||||
dwin_string.add(LCD_STR_DEGREE);
|
||||
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, x, y + 70, S(dwin_string.string()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the current "feed rate" percentage preceded by the >> character
|
||||
*/
|
||||
FORCE_INLINE void _draw_feedrate_status(const char *value, uint16_t x, uint16_t y) {
|
||||
if (!ui.did_first_redraw) {
|
||||
dwin_string.set(LCD_STR_FEEDRATE);
|
||||
DWIN_Draw_String(true, font14x28, Color_IconBlue, Color_Bg_Black, x, y, S(dwin_string.string()));
|
||||
}
|
||||
|
||||
dwin_string.set(value);
|
||||
dwin_string.add(PSTR("%"));
|
||||
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, x + 14, y, S(dwin_string.string()));
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the MarlinUI Status Screen for Ender 3 V2
|
||||
*/
|
||||
void MarlinUI::draw_status_screen() {
|
||||
const bool blink = get_blink();
|
||||
|
||||
// Draw elements that never change
|
||||
if (!ui.did_first_redraw) {
|
||||
// Logo/Status Icon
|
||||
#define STATUS_LOGO_WIDTH 128
|
||||
#define STATUS_LOGO_HEIGHT 40
|
||||
DWIN_ICON_Show(ICON, ICON_LOGO_Marlin, (LCD_PIXEL_WIDTH - (STATUS_LOGO_WIDTH)) / 2, ((STATUS_HEATERS_Y - 4) - (STATUS_LOGO_HEIGHT)) / 2);
|
||||
|
||||
// Draw a frame around the x/y/z values
|
||||
#if ENABLED(DWIN_MARLINUI_PORTRAIT)
|
||||
DWIN_Draw_Rectangle(0, Select_Color, 0, 193, LCD_PIXEL_WIDTH, 260);
|
||||
#else
|
||||
//DWIN_Draw_Rectangle(0, Select_Color, LCD_PIXEL_WIDTH - 106, 50, LCD_PIXEL_WIDTH - 1, 230);
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t hx = STATUS_HEATERS_X;
|
||||
#if HAS_HOTEND
|
||||
_draw_heater_status(H_E0, hx, STATUS_HEATERS_Y);
|
||||
hx += STATUS_HEATERS_XSPACE;
|
||||
#endif
|
||||
#if HAS_MULTI_HOTEND
|
||||
_draw_heater_status(H_E1, hx, STATUS_HEATERS_Y);
|
||||
hx += STATUS_HEATERS_XSPACE;
|
||||
#endif
|
||||
#if HAS_HEATED_BED
|
||||
_draw_heater_status(H_BED, hx, STATUS_HEATERS_Y);
|
||||
#endif
|
||||
|
||||
#if HAS_FAN
|
||||
// Fan display, pinned to the right side
|
||||
#if ENABLED(DWIN_MARLINUI_PORTRAIT)
|
||||
_draw_fan_status(LCD_PIXEL_WIDTH - STATUS_CHR_WIDTH * 4, STATUS_FAN_Y);
|
||||
#else
|
||||
_draw_fan_status(212, STATUS_FAN_Y);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Axis values
|
||||
const xyz_pos_t lpos = current_position.asLogical();
|
||||
const bool show_e_total = TERN0(LCD_SHOW_E_TOTAL, printingIsActive()); UNUSED(show_e_total);
|
||||
#if ENABLED(DWIN_MARLINUI_PORTRAIT)
|
||||
constexpr int16_t cpy = 195;
|
||||
if (show_e_total) {
|
||||
TERN_(LCD_SHOW_E_TOTAL, _draw_e_value(e_move_accumulator, 6, cpy));
|
||||
}
|
||||
else {
|
||||
_draw_axis_value(X_AXIS, ftostr4sign(lpos.x), blink, 6, cpy);
|
||||
TERN_(HAS_Y_AXIS, _draw_axis_value(Y_AXIS, ftostr4sign(lpos.y), blink, 95, cpy));
|
||||
}
|
||||
TERN_(HAS_Z_AXIS, _draw_axis_value(Z_AXIS, ftostr52sp(lpos.z), blink, 165, cpy));
|
||||
#else
|
||||
constexpr int16_t cpx = LCD_PIXEL_WIDTH - 104;
|
||||
_draw_axis_value(X_AXIS, ftostr52sp(lpos.x), blink, cpx, STATUS_HEATERS_Y);
|
||||
TERN_(HAS_Y_AXIS, _draw_axis_value(Y_AXIS, ftostr52sp(lpos.y), blink, cpx, STATUS_HEATERS_Y + 59));
|
||||
TERN_(HAS_Z_AXIS, _draw_axis_value(Z_AXIS, ftostr52sp(lpos.z), blink, cpx, STATUS_HEATERS_Y + 118));
|
||||
#endif
|
||||
|
||||
// Feedrate
|
||||
static uint16_t old_fp = 0;
|
||||
if (!ui.did_first_redraw || old_fp != feedrate_percentage) {
|
||||
old_fp = feedrate_percentage;
|
||||
_draw_feedrate_status(i16tostr3rj(feedrate_percentage),
|
||||
#if ENABLED(DWIN_MARLINUI_PORTRAIT)
|
||||
5, 290
|
||||
#else
|
||||
294, STATUS_HEATERS_Y
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
//
|
||||
// Elapsed time
|
||||
//
|
||||
char buffer[14];
|
||||
duration_t time;
|
||||
|
||||
#if ENABLED(DWIN_MARLINUI_PORTRAIT)
|
||||
|
||||
// Portrait mode only shows one value at a time, and will rotate if ROTATE_PROGRESS_DISPLAY
|
||||
dwin_string.set();
|
||||
char prefix = ' ';
|
||||
#if ENABLED(SHOW_REMAINING_TIME)
|
||||
if (TERN1(ROTATE_PROGRESS_DISPLAY, blink) && print_job_timer.isRunning()) {
|
||||
time = get_remaining_time();
|
||||
prefix = 'R';
|
||||
}
|
||||
else
|
||||
#endif
|
||||
time = print_job_timer.duration();
|
||||
|
||||
time.toDigital(buffer);
|
||||
dwin_string.add(prefix);
|
||||
dwin_string.add(buffer);
|
||||
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, (LCD_PIXEL_WIDTH - ((dwin_string.length() + 1) * 14)), 290, S(dwin_string.string()));
|
||||
|
||||
#else
|
||||
|
||||
// landscape mode shows both elapsed and remaining (if SHOW_REMAINING_TIME)
|
||||
time = print_job_timer.duration();
|
||||
time.toDigital(buffer);
|
||||
dwin_string.set(" ");
|
||||
dwin_string.add(buffer);
|
||||
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, 280, 100, S(dwin_string.string()));
|
||||
|
||||
#if ENABLED(LCD_SHOW_E_TOTAL)
|
||||
if (show_e_total && TERN1(SHOW_REMAINING_TIME, !blink)) { // if SHOW_REMAINING_TIME is also
|
||||
const uint8_t escale = e_move_accumulator >= 100000.0f ? 10 : 1; // show cm after 99,000mm
|
||||
|
||||
DWIN_Draw_String(true, font14x28, Color_IconBlue, Color_Bg_Black, 249, 135, S("E"));
|
||||
dwin_string.set(ui16tostr5rj(e_move_accumulator * escale));
|
||||
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, 263, 135, S(dwin_string.string()));
|
||||
DWIN_Draw_String(true, font14x28, Color_IconBlue, Color_Bg_Black, 333, 135, S(escale==1 ? "mm" : "cm"));
|
||||
}
|
||||
#endif
|
||||
#if ENABLED(SHOW_REMAINING_TIME)
|
||||
if (!show_e_total || blink) {
|
||||
DWIN_Draw_String(true, font14x28, Color_IconBlue, Color_Bg_Black, 249, 135, S(" R "));
|
||||
time = get_remaining_time();
|
||||
time.toDigital(buffer);
|
||||
dwin_string.set(buffer);
|
||||
DWIN_Draw_String(true, font14x28, Color_White, Color_Bg_Black, 291, 135, S(dwin_string.string()));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//
|
||||
// Progress Bar
|
||||
//
|
||||
constexpr int16_t pb_margin = 5, pb_left = pb_margin, pb_height = 60,
|
||||
pb_right = LCD_PIXEL_WIDTH - TERN(DWIN_MARLINUI_PORTRAIT, 0, 107) - pb_margin,
|
||||
pb_bottom = TERN(DWIN_MARLINUI_PORTRAIT, 410, 230),
|
||||
pb_top = pb_bottom - pb_height,
|
||||
pb_width = pb_right - pb_left;
|
||||
|
||||
const progress_t progress = TERN(HAS_PRINT_PROGRESS_PERMYRIAD, get_progress_permyriad, get_progress_percent)();
|
||||
|
||||
if (!ui.did_first_redraw)
|
||||
DWIN_Draw_Rectangle(0, Select_Color, pb_left, pb_top, pb_right, pb_bottom); // Outline
|
||||
|
||||
static uint16_t old_solid = 50;
|
||||
const uint16_t pb_solid = (pb_width - 2) * (progress / (PROGRESS_SCALE)) * 0.01f;
|
||||
const bool p_draw = !ui.did_first_redraw || old_solid != pb_solid;
|
||||
|
||||
if (p_draw) {
|
||||
//if (pb_solid)
|
||||
DWIN_Draw_Rectangle(1, Select_Color, pb_left + 1, pb_top + 1, pb_left + pb_solid, pb_bottom - 1); // Fill the solid part
|
||||
|
||||
//if (pb_solid < old_solid)
|
||||
DWIN_Draw_Rectangle(1, Color_Bg_Black, pb_left + 1 + pb_solid, pb_top + 1, pb_right - 1, pb_bottom - 1); // Erase the rest
|
||||
|
||||
#if ENABLED(SHOW_SD_PERCENT)
|
||||
dwin_string.set(TERN(PRINT_PROGRESS_SHOW_DECIMALS, permyriadtostr4(progress), ui8tostr3rj(progress / (PROGRESS_SCALE))));
|
||||
dwin_string.add(PSTR("%"));
|
||||
DWIN_Draw_String(
|
||||
false, font16x32, Percent_Color, Color_Bg_Black,
|
||||
pb_left + (pb_width - dwin_string.length() * 16) / 2,
|
||||
pb_top + (pb_height - 32) / 2,
|
||||
S(dwin_string.string())
|
||||
);
|
||||
#endif
|
||||
|
||||
old_solid = pb_solid;
|
||||
}
|
||||
|
||||
//
|
||||
// Status Message
|
||||
//
|
||||
draw_status_message(blink);
|
||||
|
||||
ui.did_first_redraw = true;
|
||||
}
|
||||
|
||||
#endif // IS_DWIN_MARLINUI
|
@ -0,0 +1,64 @@
|
||||
# Generate a 'HZK' font file for the T5UIC1 DWIN LCD
|
||||
# from multiple bdf font files.
|
||||
# Note: the 16x16 glyphs are not produced
|
||||
# Author: Taylor Talkington
|
||||
# License: GPL
|
||||
|
||||
import bdflib.reader
|
||||
import math
|
||||
|
||||
def glyph_bits(size_x, size_y, font, glyph_ord):
|
||||
asc = font[b'FONT_ASCENT']
|
||||
desc = font[b'FONT_DESCENT']
|
||||
bits = [0 for y in range(size_y)]
|
||||
|
||||
glyph_bytes = math.ceil(size_x / 8)
|
||||
try:
|
||||
glyph = font[glyph_ord]
|
||||
for y, row in enumerate(glyph.data):
|
||||
v = row
|
||||
rpad = size_x - glyph.bbW
|
||||
if rpad < 0: rpad = 0
|
||||
if glyph.bbW > size_x: v = v >> (glyph.bbW - size_x) # some glyphs are actually too wide to fit!
|
||||
v = v << (glyph_bytes * 8) - size_x + rpad
|
||||
v = v >> glyph.bbX
|
||||
bits[y + desc + glyph.bbY] |= v
|
||||
except KeyError:
|
||||
pass
|
||||
|
||||
bits.reverse()
|
||||
return bits
|
||||
|
||||
def marlin_font_hzk():
|
||||
fonts = [
|
||||
[6,12,'marlin-6x12-3.bdf'],
|
||||
[8,16,'marlin-8x16.bdf'],
|
||||
[10,20,'marlin-10x20.bdf'],
|
||||
[12,24,'marlin-12x24.bdf'],
|
||||
[14,28,'marlin-14x28.bdf'],
|
||||
[16,32,'marlin-16x32.bdf'],
|
||||
[20,40,'marlin-20x40.bdf'],
|
||||
[24,48,'marlin-24x48.bdf'],
|
||||
[28,56,'marlin-28x56.bdf'],
|
||||
[32,64,'marlin-32x64.bdf']
|
||||
]
|
||||
|
||||
with open('marlin_fixed.hzk','wb') as output:
|
||||
for f in fonts:
|
||||
with open(f[2], 'rb') as file:
|
||||
print(f'{f[0]}x{f[1]}')
|
||||
font = bdflib.reader.read_bdf(file)
|
||||
for glyph in range(128):
|
||||
bits = glyph_bits(f[0], f[1], font, glyph)
|
||||
glyph_bytes = math.ceil(f[0]/8)
|
||||
|
||||
for b in bits:
|
||||
try:
|
||||
z = b.to_bytes(glyph_bytes, 'big')
|
||||
output.write(z)
|
||||
except OverflowError:
|
||||
print('Overflow')
|
||||
print(f'{glyph}')
|
||||
print(font[glyph])
|
||||
for b in bits: print(f'{b:0{f[0]}b}')
|
||||
return
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue