Source file: /~heha/mb-iwp/Bergwerk/fba-rpi-230421.zip/heha_tui.h

#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-80