#pragma once
#include "heha_print.h"
typedef unsigned char byte;
#define nobreak [[fallthrough]]
#include <cstring> // strlen(), strncpy()
#include <vector>
/*****************
* ncurses-light *
*****************/
inline void csiqh(unsigned param) {heha::print("\e[?%uh",param);}
inline void csiql(unsigned param) {heha::print("\e[?%ul",param);}
inline void hidecursor() {csiql(25);}
inline void showcursor() {csiqh(25);}
void vcsi(char t, unsigned n, va_list va);
void vcsi(char t, unsigned n, unsigned*va);
// umgekehrtes oder universelles CSI
void ucsi(char t, unsigned n, ...);
inline void csi(char t) {ucsi(t,0);}
inline void csi(unsigned p1, char t) {ucsi(t,1,p1);}
inline void csi(unsigned p1, unsigned p2, char t) {ucsi(t,2,p1,p2);}
inline void csi(unsigned p1, unsigned p2, unsigned p3, char t) {ucsi(t,3,p1,p2,p3);}
byte csidecode(const char*&s,byte*argv,byte argc);
byte cursorpos(byte*x=0); // liefert Zeile (y) im Returnwert, 0 wenn's schiefging
//extern byte line, maxline;
void nextline();
void cursortop();
void onSizeChange(int=0);
//Zeichenfarbe, bestehend aus Vorder- und Hintergrundfarbe
struct ChrColor{
ChrColor(byte _f=7,byte _b=0):f(_f),b(_b) {}
byte f,b; // f = Vordergrund, b = Hintergrund
void out() const;
static void clr() {csi('m'); current.f=7; current.b=0;}
private:
static ChrColor current;
};
// Farbpalette für MiniEdit
extern const ChrColor pal0[4];
// Bit 0 = rot, Bit 1 = grün, Bit 2 = blau, Bit 3 = Intensität
// 0b0111 = hellgrau, 0b1000 = dunkelgrau
extern const ChrColor pal1[4];
/****************
* Mausposition *
****************/
struct Mouse{
byte x,y; // mehr als 1..255 ist nicht vorgesehen
struct Buttons{
byte L:1, // Bit 0 = linke Maustaste
R:1, // Bit 1 = rechte Maustaste
M:1, // Bit 2 = mittlere Maustaste (In dieser Reihenfolge Windows-kompatibel)
S:1, // Bit 3 = Shift-Taste
A:1, // Bit 4 = Alt-Taste
C:1, // Bit 5 = Strg-Taste (In dieser Reihenfolge so wie's von XTerm und Nachfolgern kommt)
Z:2; // Bit 7:6 = Klickzähler
operator byte&() {return *(byte*)this;}
operator byte() const {return *(const byte*)this;}
bool AC() const {return A||C;}
void clrModKeys() {(operator byte&()) &=~fModKeys;}
void orModKeys(byte k) {(operator byte&()) |= (k&7)<<3;}
Buttons(byte init=0) {(operator byte&()) = init;}
}buttons; // im Hilfetext CASMRL genannt (= Tastenbelegung der Bits)
enum{
fButtons = 7, // Maustasten
fModKeys = 7<<3, // Modifiziertasten
fClicks = 3<<6, // Klickzähler
};
byte code; // Aktionskode vom Mauskommando ESC [ M oder F-Tastenkode
};
/*******************
* Windows-Nachbau *
*******************/
struct Window{
byte x,y,w,h; // Position auf Bildschirm, x/y nullbasiert, w>=4, h>=1
static Window*focus,*capture;
Window*next,*prev,*parent,*sub;
enum{
VISIBLE,
CLIPSIBLINGS,
CLIPCHILDREN,
OVERLAPPED, // sonst POPUP
CHILD, // niemals Menü, stattdessen ID
SHADOW, // macht Fenster höher und breiter
BORDER, // erstmal ungenutzt
SYSMENU, // nur bei BORDER
MAXIMIZEBOX, // nur bei BORDER
HSCROLL, // nur bei BORDER
VSCROLL, // nur bei BORDER
MAXIMIZED,
DISABLED, // nicht fokussierbar
WINDOW_BITS,
};
unsigned style;
struct Menu{
// enum{
// VISIBLE,
// MENUBAR,
// };
// unsigned style;
struct Item{
enum{
CHECKED,
RADIOCHECK,
POPUP,
OWNERDRAW,
};
unsigned style;
union{
unsigned id;
Menu*submenu;
};
const char*text;
};
private:
Window*wnd; // (temporäres) Menü-Fenster (mit eigener Tastatur- und Mausbehandlung)
public:
std::vector<Item>items;
};
union{
unsigned id;
Menu*menu;
};
typedef Window*HWND;
typedef unsigned UINT;
typedef unsigned long WPARAM,LPARAM;
typedef LPARAM(*WndProc)(HWND,UINT,WPARAM,LPARAM);
WndProc wndproc; // TODO: Einzige virtuelle Funktion
// CreateWindow()
Window(byte x, byte y, byte w, byte h,Window*,unsigned,Menu* =0);
HWND find(const Mouse&) const; // Maus-Treffertest, findet ggf. Subfenster
LPARAM parentNotify(UINT msg);
virtual bool onKey(const char*) {return false;}
virtual void onMouse(const Mouse&) {}
// Die Fokusumschaltung (Tastaturbesitz) muss ggf. sichtbar sein!
virtual void setFocus() {if (focus) focus->killFocus(); focus=this;}
virtual void killFocus() {focus=0;}
// Die Captureumschaltung (Mausbesitz) ebenso!
virtual void setCapture() {if (capture) capture->releaseCapture(); capture=this;}
virtual void releaseCapture() {capture=0;}
virtual void paint() {};
bool visible() const {return style&1<<VISIBLE;}
bool disabled() const {return style&1<<DISABLED;}
bool focusable() const {return visible() && !disabled();}
};
extern struct Screen:public Window{
Screen():Window(0,0,0,0,0,1<<VISIBLE|1<<CLIPCHILDREN),paintAll(true) {}
// nur für <x>,<y>,<w>,<h> und <sub>, als <parent> für MiniEdit
bool onKey(const char*) override;
void onMouse(const Mouse&) override;
bool paintAll;
bool mousehelp;
Mouse mouse; // Letzte Mauskoordinaten und -Aktion
private:
static void checkDblClk(Mouse&);
}screen;
struct MiniEdit:public Window{ // Einzeilen-Editfeld (UTF-8 ohne BiDi, ohne Modifizierer)
MiniEdit(unsigned id, byte _x,byte _y, byte _w=5, byte _h=1, const char*_text=0,const ChrColor*pal=pal0)
:Window(_x,_y,_w,_h,&screen,
1<<VISIBLE|1<<CHILD,
reinterpret_cast<Window::Menu*>(id)),colors(pal) {
if (_text) {strncpy(text,_text,sizeof text-1); text[sizeof text-1]=0;}
else text[0]=0;
onNewText();
}
bool onKey(const char*) override;
void onMouse(const Mouse&) override;
char text[64];
char left; // Index in <text> für linkes Zeichen, negativ wenn rechtsbündig
char tlen; // svw. strlen(text)
enum{
LEFTALIGN=WINDOW_BITS, // sonst RIGHTALIGN (bissel blöd durch Evolution)
};
struct{
char sel1,sel2;
char begin() const {return sel1<sel2?sel1:sel2;}
char end() const {return sel1>sel2?sel1:sel2;}
bool empty() const {return sel1==sel2;}
}sel; // Index in <text> für Cursorposition
const ChrColor*colors; // Farbpaletten-Zeiger (besser: von DISABLE abhängig machen)
void paint() override; // Hier: Startposition bereits korrekt!
void onNewText(); // setzt sel.begin()=0, sel.end=tlen=strlen(text), left: rechtsbündig wenn kurz, linksbündig wenn lang
char expandsel(char); // Nur sel.sel2 wird gesetzt
char setsel(char); // Liefert Byte-Index in UTF8-String
void clearSel();
void keepCursorVis();
enum{
EN_UP = 0x840,
EN_DOWN,
EN_ENTER, // Nachricht an Elternfenster bei ENTER
};
private:
char charLeft(char pos) const; // hier: alle <char> nichtnegativ
char charRight(char pos) const;
char wordLeft(char pos) const;
char wordRight(char pos) const;
void moveLeft();
void moveRight();
};
// Begrenzt UTF8-Ausgabe auf Terminal-Zeichenzellen <ccells>
// rückt Zeiger <s> vor und reduziert <n>
void utf8print(const char*&s, const char*e, char&n);
struct Terminal{
Terminal();
virtual void onSize(char w,char h) {}
virtual void start();
virtual void stop();
virtual ~Terminal();
private:
const unsigned dragreport=1002;
const unsigned movereport=1003;
void* otio;
};
Detected encoding: UTF-8 | 0
|