Displeje a grafický návrhář¶
Tato stránka popisuje, jak doplněk .newblk oznámí ESP IDE rozlišení vlastního displeje. Díky tomu grafický návrhář kreslí do správné velikosti, i když projekt používá jiný panel než původní OLED 128 × 64.
Platí pro doplňky s vlastním inicializačním blokem, například pro SPI LCD, OLED nebo e-paper. Neřeší elektrické zapojení konkrétního modulu ani jeho komunikační protokol. Ty jsou součástí ovladače v MicroPythonu.
Co návrhář potřebuje vědět¶
Grafický návrhář pracuje s pixely. Než otevře plátno, musí znát alespoň:
- šířku displeje v pixelech,
- výšku displeje v pixelech,
- zda jde o monochromatický profil nebo profil označený jako
rgbčitricolor.
Tyto údaje neposílá MicroPython z desky. Poskytne je JavaScriptová část doplňku přímo v prohlížeči. ESP IDE proto před otevřením návrháře vyhledá použitý inicializační blok na Blockly ploše a ze zaregistrovaného doplňku získá jeho profil.
Důležité rozdělení rolí
Registrace rozlišení ovlivňuje pouze návrhář v ESP IDE. Neinicializuje displej na desce a nemění Python generovaný blokem. Inicializační blok musí nadále správně vytvořit skutečný ovladač displeje v MicroPythonu.
Jak se vybírá aktivní displej¶
ESP IDE poskytuje v novějších verzích globální API window.ESPIDE_DISPLAY_TARGETS.
- Doplněk zaregistruje typ svého inicializačního bloku a funkci, která vrátí profil displeje.
- IDE sleduje Blockly plochu. Do výběru zahrne jen zaregistrované inicializační bloky, které jsou opravdu vložené v projektu.
- Aktivní je naposledy vytvořený nebo změněný platný inicializační blok. Pořadí použití se ukládá do dat bloku, takže zůstane zachované i po uložení a opětovném otevření projektu.
- Když aktivní inicializační blok smažeš, IDE použije předchozí platný blok. Pokud na ploše není žádný zaregistrovaný inicializační blok, návrhář použije výchozí profil 128 × 64 monochromatický.
Pouhá přítomnost bloku v toolboxu nic nemění. Je to záměr: v toolboxu může být současně OLED 128 × 64 i několik doplňků pro jiné displeje. Návrhář se řídí až blokem, který uživatel skutečně vložil do programu.
Nejjednodušší doplněk s pevným rozlišením¶
Pro displej, který má vždy stejné rozlišení, stačí do JavaScriptové části .newblk přidat následující registraci. Patří před delimiter <!toolbox!>.
var myDisplayRoot_ = typeof window !== "undefined" ? window : this;
if (myDisplayRoot_.ESPIDE_DISPLAY_TARGETS &&
typeof myDisplayRoot_.ESPIDE_DISPLAY_TARGETS.register === "function") {
myDisplayRoot_.ESPIDE_DISPLAY_TARGETS.register(
"my_display_init", function() {
return {
profileId: "my-display-84x48",
width: 84,
height: 48,
mode: "mono",
label: "Můj displej — 84×48"
};
});
}
V tomto příkladu:
myDisplayRoot_je bezpečný odkaz na globální objekt prohlížeče. V ESP IDE je to běžněwindow.ESPIDE_DISPLAY_TARGETSje API vytvořené ESP IDE, nikoli proměnná doplňku."my_display_init"musí být přesně stejný text jako typ inicializačního bloku vBlockly.Blocks["my_display_init"]a v XML toolboxu<block type="my_display_init">.profileIdje stabilní interní identifikátor profilu. Neměň jej bez důvodu u dalších verzí stejného panelu.widthaheightjsou rozměry v pixelech, nikoli fyzické rozměry v milimetrech nebo palcích.labelse zobrazí uživateli jako název vybraného profilu.modemůže býtmono,rgbnebotricolor. Pokud jej neuvedeš nebo použiješ jinou hodnotu, API jej normalizuje namono.
Podmínka kolem register není zbytečná
Starší ESP IDE ještě ESPIDE_DISPLAY_TARGETS nezná. První část podmínky ověří, zda API existuje. Operátor && pak druhou část už nevyhodnotí, pokud první neplatí. Doplněk se proto ve starší verzi načte bez chyby, jen návrhář zůstane na starším fallbacku 128 × 64.
Nezapisuj registraci bez této ochrany přímo jako window.ESPIDE_DISPLAY_TARGETS.register(...). Ve starší verzi IDE by se doplněk při načítání zastavil chybou a jeho bloky by se nemusely přidat do toolboxu.
Doplněk s volbou více panelů¶
Jeden inicializační blok může nabízet více panelů. V takovém případě musí resolver vždy vrátit profil právě vybraného panelu. Hodnoty v dropdownu drž jako stabilní technické klíče; uživatelský překlad patří do viditelného textu položky.
var MY_DISPLAY_PROFILES_ = {
LCD_84X48: {
width: 84, height: 48,
profileId: "my-lcd-84x48",
label: "LCD 84×48"
},
EPD_400X300: {
width: 400, height: 300,
profileId: "my-epd-400x300",
label: "E-paper 400×300"
}
};
function myDisplayProfile_(key) {
return MY_DISPLAY_PROFILES_[key] || MY_DISPLAY_PROFILES_.LCD_84X48;
}
if (myDisplayRoot_.ESPIDE_DISPLAY_TARGETS &&
typeof myDisplayRoot_.ESPIDE_DISPLAY_TARGETS.register === "function") {
myDisplayRoot_.ESPIDE_DISPLAY_TARGETS.register(
"my_display_init", function(block) {
var profile = myDisplayProfile_(block.getFieldValue("PANEL"));
return {
profileId: profile.profileId,
width: profile.width,
height: profile.height,
mode: "mono",
label: profile.label
};
});
}
block.getFieldValue("PANEL") čte aktuální hodnotu pole dropdownu z konkrétního bloku na ploše. To je důvod, proč resolver dostává argument block.
Pokud změna dropdownu mění rozlišení, je vhodné po změně výslovně označit blok jako naposledy použitý. Tento malý pomocník používá stejný princip jako doplňky WeAct e-paper:
function myDisplayMarkUsedLater_(block) {
if (!myDisplayRoot_.setTimeout) return;
myDisplayRoot_.setTimeout(function() {
var targets = myDisplayRoot_.ESPIDE_DISPLAY_TARGETS;
if (targets && typeof targets.markUsed === "function") {
targets.markUsed(block);
}
}, 0);
}
Blockly.Blocks["my_display_init"] = {
init: function() {
var sourceBlock = this;
var panelField = new Blockly.FieldDropdown(
[["LCD 84×48", "LCD_84X48"], ["E-paper 400×300", "EPD_400X300"]],
function(newValue) {
myDisplayMarkUsedLater_(sourceBlock);
return newValue;
});
this.appendDummyInput().appendField(panelField, "PANEL");
// ... další vstupy inicializačního bloku ...
}
};
Odložené volání přes setTimeout(..., 0) proběhne až po dokončení změny hodnoty pole. markUsed(block) zapíše pořadí použití pouze tehdy, když resolver pro blok vrací platný profil.
Aby fungovaly bloky Display i návrhář¶
Registrace rozlišení je pouze první část. Inicializační blok musí vygenerovat proměnné, se kterými už pracují společné bloky z kategorie Display:
display = MyDisplay(...)
buffer = display.buffer
fbuf = display.fbuf
Význam proměnných:
| Proměnná | Co musí poskytovat |
|---|---|
display |
Ovladač fyzického displeje s metodou show() pro odeslání obrazu do panelu. |
buffer |
Bajtové pole framebufferu. Doporučený zdroj je display.buffer. Používá jej živý náhled návrháře. |
fbuf |
Objekt s kreslicím API MicroPythonu framebuf, například fill, pixel, line, rect, fill_rect, text, blit a scroll. |
Nejjednodušší ovladač dědí z framebuf.FrameBuffer. Pak může být fbuf přímo stejný objekt jako display:
class MyDisplay(framebuf.FrameBuffer):
def __init__(self, ...):
self.buffer = bytearray(...)
super().__init__(self.buffer, WIDTH, HEIGHT, framebuf.MONO_VLSB)
self.fbuf = self
def show(self):
# Odeslání self.buffer do skutečného displeje.
pass
Společné kreslicí bloky a kód z návrháře kreslí do fbuf. Blok pro překreslení volá display.show(). Pokud doplněk tyto proměnné nebo metodu neposkytne, profil v návrháři může mít správnou velikost, ale vygenerovaný obrázek nebude možné běžným způsobem vykreslit na panel.
Použij existující blok návrháře
Pro běžný displej není potřeba vytvářet vlastní blok pro ukládání grafické scény. Použij standardní blok espide_display_designer z kategorie Display. Při otevření automaticky převezme aktivní profil z registrovaného inicializačního bloku, zachová kompletní generátor ESP IDE včetně dynamických vrstev a podpory scene.dat.
Ruční rozlišení a zachování práce uživatele¶
V návrháři může uživatel zadat vlastní šířku a výšku. Tato volba platí pro právě upravovanou scénu, uloží se do rozšiřujících dat scény espide.adaptive-display-v1 a má přednost před aktuálním profilem displeje.
Při otevření se chování rozlišuje takto:
- prázdná dosud neupravená scéna 128 × 64 převezme rozměry aktivního inicializačního bloku;
- neprázdná scéna nebo scéna s ručně nastaveným rozlišením se sama nepřepočítá, když uživatel později změní inicializační blok;
- návrhář ukáže hodnoty scény i aktivní profil a nabízí výslovnou akci pro použití profilu displeje.
Tím se zabrání nečekanému oříznutí nebo posunu již nakreslených objektů.
Rozměr musí být v rozsahu 1 až 1024 pixelů na každé ose a framebuffer pro monochromatický profil nesmí vyžadovat více než 65 535 bajtů. IDE potřebnou velikost počítá jako šířka × ceil(výška / 8).
Vlastní blok s tlačítkem návrháře (pokročilé)¶
Používej jej jen tehdy, když doplněk opravdu potřebuje vlastní Blockly blok, který vlastní samostatnou scénu. Standardní blok espide_display_designer je pro většinu displejů lepší volba.
API umí na vlastní blok připojit ukládání scény i tlačítko:
Blockly.Blocks["my_display_scene"] = {
init: function() {
this.appendDummyInput().appendField("obrazovka vlastního displeje");
if (myDisplayRoot_.ESPIDE_DISPLAY_TARGETS &&
typeof myDisplayRoot_.ESPIDE_DISPLAY_TARGETS.attachDesigner === "function") {
myDisplayRoot_.ESPIDE_DISPLAY_TARGETS.attachDesigner(this, {
buttonLabel: "Otevřít grafický návrhář"
});
}
this.setPreviousStatement(true, null);
this.setNextStatement(true, null);
}
};
attachDesigner() zachová již existující mutation handlery bloku, uloží scénu do přidaných atributů mutation a přidá metody getDisplayDesignerScene() a setDisplayDesignerScene(). Generátor Pythonu vlastního bloku je ale stále odpovědností autora doplňku. Proto tento postup nepoužívej jen kvůli nastavení rozlišení.
Ve starším ESP IDE je i tato část chráněná podmínkou. Blok se může načíst, ale nemá adaptivní tlačítko návrháře.
Zpětná kompatibilita projektů a doplňků¶
Registrace profilu nemění typ vestavěného bloku návrháře ani základní formát scény. Novější informace o adaptivním rozlišení jsou přidány jako rozšiřující data scény.
- Starší IDE bez
ESPIDE_DISPLAY_TARGETSnačte doplněk díky ochranné podmínce, ale používá původní návrhář 128 × 64. - Starší IDE zachová neznámá rozšiřující data scény, takže projekt lze znovu otevřít v nové verzi.
- Jestliže starší IDE nezná vlastní typ bloku doplňku a doplněk v něm není nainstalovaný, tento blok nemůže načíst. To je běžné pravidlo pro každý
.newblkdoplněk, nezávisle na návrháři.
Kontrolní seznam autora doplňku pro displej¶
- Inicializační blok existuje v
Blockly.Blocks[...], generátoru Pythonu i XML toolboxu pod stejným typem. - Doplněk bezpečně registruje tento typ přes
ESPIDE_DISPLAY_TARGETS.register(...). - Resolver vrací správné
width,height, stabilníprofileIda srozumitelnýlabel. - Při více panelech resolver čte správné pole bloků a změna volby označí blok jako použitý.
- Generovaný Python vytvoří
display,bufferafbufpřed kreslicími bloky. fbufnabízí kreslicí APIframebufadisplay.show()odesílá framebuffer do skutečného displeje.- Běžně se používá vestavěný blok
espide_display_designer; vlastní scénový blok přidej jen při skutečné potřebě. - Registrace i případné
attachDesigner()jsou chráněné kontrolou existence API kvůli starším verzím ESP IDE. .newblkstále obsahuje právě jeden delimiter<!toolbox!>.