v4k-git-backup/engine/split/3rd_lite_sys.h

276 lines
10 KiB
C

// lite editor, platform details
// - rlyeh, public domain
#define LT_DATAPATH "/lite"
#define lt_assert(x) ASSERT(x)
#define lt_realpath(p, q) file_pathabs(p)
#define lt_realpath_free(p)
#define lt_malloc(n) MALLOC(n)
#define lt_calloc(n,m) CALLOC(n,m)
#define lt_free(p) FREE(p)
#define lt_memcpy(d,s,c) memcpy(d,s,c)
#define lt_memset(p,ch,c) memset(p,ch,c)
#define lt_time_ms() time_ms()
#define lt_sleep_ms(ms) sleep_ms(ms)
#define lt_getclipboard(w) window_clipboard()
#define lt_setclipboard(w,s) window_setclipboard(s)
#define lt_window() window_handle()
#define lt_setwindowmode(m) window_fullscreen(m == 2), (m < 2 && (window_maximize(m),1)) // 0:normal,1:maximized,2:fullscreen
#define lt_setwindowtitle(t) //window_title(t)
#define lt_haswindowfocus() window_has_focus()
#define lt_setcursor(shape) window_cursor_shape(lt_events & (1<<31) ? CURSOR_SW_AUTO : shape+1) // 0:arrow,1:ibeam,2:sizeh,3:sizev,4:hand
#define lt_prompt(msg,title) ifndef(win32, 0, (MessageBoxA(0, msg, title, MB_YESNO | MB_ICONWARNING) == IDYES))
unsigned lt_events = ~0u;
int lt_mx = 0, lt_my = 0, lt_wx = 0, lt_wy = 0, lt_ww = 0, lt_wh = 0;
typedef struct lt_surface {
unsigned w, h;
void *pixels;
texture_t t;
} lt_surface;
typedef struct lt_rect {
int x, y, width, height;
} lt_rect;
lt_surface *lt_getsurface(void *window) {
static lt_surface s = {0};
return &s;
}
void lt_updatesurfacerects(lt_surface *s, lt_rect* rects, unsigned count) {
if(0)
for( int i = 0; i < count; ++i ) {
memset( (unsigned*)s->pixels + (rects[i].x + rects[i].y * s->w), 0xFF, rects[i].width*4 );
memset( (unsigned*)s->pixels + (rects[i].x + (rects[i].y + (rects[i].height-1)) * s->w), 0xFF, rects[i].width*4 );
for( int y = 1; y < (rects[i].height-1); ++y ) {
((unsigned*)s->pixels)[ rects[i].x + y * s->w ] =
((unsigned*)s->pixels)[ rects[i].x + (rects[i].width-1) + y * s->w ] = 0xFFFFFFFF;
}
}
// update contents
texture_update(&s->t, s->w, s->h, 4, s->pixels, TEXTURE_LINEAR|TEXTURE_BGRA);
}
void ren_set_clip_rect(struct lt_rect rect);
void rencache_invalidate(void);
int lt_resizesurface(lt_surface *s, int ww, int wh) {
s->w = ww, s->h = wh;
if( s->t.id == 0 || s->w != s->t.w || s->h != s->t.h ) {
// invalidate tiles
ren_set_clip_rect( (lt_rect) { 0, 0, s->w, s->h } );
rencache_invalidate();
// texture clear
if( !s->t.id ) s->t = texture_create(1, 1, 4, " ", TEXTURE_LINEAR|TEXTURE_RGBA|TEXTURE_BYTE );
s->pixels = REALLOC(s->pixels, s->w * s->h * 4);
memset(s->pixels, 0, s->w * s->h * 4);
// texture update
lt_updatesurfacerects(s,0,0);
return 1; // resized
}
return 0; // unchanged
}
void *lt_load_file(const char *filename, int *size) {
int datalen; char *data = file_load(filename, &datalen);
if( !data || !datalen ) {
filename = (const char *)file_normalize(filename);
if( strbegi(filename, app_path()) ) filename += strlen(app_path());
data = vfs_load(filename, &datalen);
}
if (size) *size = 0;
if (!data) { return NULL; }
if (size) *size = datalen;
// return permanent buffers here, as file_load() and vfs_load() do return temporaries
data = memcpy(MALLOC(datalen+1), data, datalen);
data[datalen] = 0;
return data;
}
const char* lt_button_name(int button) {
if(button == GLFW_MOUSE_BUTTON_LEFT) return "left";
if(button == GLFW_MOUSE_BUTTON_RIGHT) return "right";
if(button == GLFW_MOUSE_BUTTON_MIDDLE) return "middle";
return "?";
}
char* lt_key_name(char *dst, int key, int vk, int mods) {
// @todo: "altgr" -> left ctrl + right alt
if( key == GLFW_KEY_UP ) return "up";
if( key == GLFW_KEY_DOWN ) return "down";
if( key == GLFW_KEY_LEFT ) return "left";
if( key == GLFW_KEY_RIGHT ) return "right";
if( key == GLFW_KEY_LEFT_ALT ) return "left alt";
if( key == GLFW_KEY_RIGHT_ALT ) return "right alt";
if( key == GLFW_KEY_LEFT_SHIFT ) return "left shift";
if( key == GLFW_KEY_RIGHT_SHIFT ) return "right shift";
if( key == GLFW_KEY_LEFT_CONTROL ) return "left ctrl";
if( key == GLFW_KEY_RIGHT_CONTROL ) return "right ctrl";
if( key == GLFW_KEY_LEFT_SUPER ) return "left windows";
if( key == GLFW_KEY_RIGHT_SUPER ) return "left windows";
if( key == GLFW_KEY_MENU ) return "menu";
if( key == GLFW_KEY_ESCAPE ) return "escape";
if( key == GLFW_KEY_BACKSPACE ) return "backspace";
if( key == GLFW_KEY_ENTER ) return "return";
if( key == GLFW_KEY_KP_ENTER ) return "keypad enter";
if( key == GLFW_KEY_TAB ) return "tab";
if( key == GLFW_KEY_CAPS_LOCK ) return "capslock";
if( key == GLFW_KEY_HOME ) return "home";
if( key == GLFW_KEY_END ) return "end";
if( key == GLFW_KEY_INSERT ) return "insert";
if( key == GLFW_KEY_DELETE ) return "delete";
if( key == GLFW_KEY_PAGE_UP ) return "pageup";
if( key == GLFW_KEY_PAGE_DOWN ) return "pagedown";
if( key == GLFW_KEY_F1 ) return "f1";
if( key == GLFW_KEY_F2 ) return "f2";
if( key == GLFW_KEY_F3 ) return "f3";
if( key == GLFW_KEY_F4 ) return "f4";
if( key == GLFW_KEY_F5 ) return "f5";
if( key == GLFW_KEY_F6 ) return "f6";
if( key == GLFW_KEY_F7 ) return "f7";
if( key == GLFW_KEY_F8 ) return "f8";
if( key == GLFW_KEY_F9 ) return "f9";
if( key == GLFW_KEY_F10 ) return "f10";
if( key == GLFW_KEY_F11 ) return "f11";
if( key == GLFW_KEY_F12 ) return "f12";
const char *name = glfwGetKeyName(key, vk);
strcpy(dst, name ? name : "");
char *p = dst;
while (*p) {
*p = tolower(*p);
p++;
}
return dst;
}
void lt_globpath(struct lua_State*L, const char *path) {
unsigned j = 0;
if(!strend(path, "/")) path = (const char *)va("%s/", path);
for( dir *d = dir_open(path, ""); d; dir_close(d), d = 0 ) {
for( unsigned i = 0, end = dir_count(d); i < end; ++i ) {
char *name = dir_name(d,i);
char *last = name + strlen(name) - 1;
if( *last == '/' ) *last = '\0';
name = file_name(name);
lua_pushstring(L, name);
lua_rawseti(L, -2, ++j);
}
}
for( const char *section = strstri(path, LT_DATAPATH); section && section[sizeof(LT_DATAPATH)-1] == '/'; section = 0) {
array(char*) list = vfs_list("**");
for( unsigned i = 0, end = array_count(list); i < end; ++i ) {
char *name = list[i];
if( !strstri(name, section+1) ) continue;
lua_pushstring(L, file_name(name));
lua_rawseti(L, -2, ++j);
}
if( array_count(list) ) return;
}
}
int lt_emit_event(lua_State *L, const char *event_name, const char *event_fmt, ...) {
int count = 0;
lua_pushstring(L, event_name);
if( event_fmt ) {
va_list va;
va_start(va, event_fmt);
for( ; event_fmt[count]; ++count ) {
/**/ if( event_fmt[count] == 'd' ) { int d = va_arg(va, int); lua_pushnumber(L, d); }
else if( event_fmt[count] == 'f' ) { double f = va_arg(va, double); lua_pushnumber(L, f); }
else if( event_fmt[count] == 's' ) { const char *s = va_arg(va, const char *); lua_pushstring(L, s); }
}
va_end(va);
}
return 1+count;
}
int printi(int i) {
// printf("clicks: %d\n", i);
return i;
}
static const char* codepoint_to_utf8_(unsigned c);
int lt_poll_event(lua_State *L) { // init.lua > core.step() wakes on mousemoved || inputtext
int rc = 0;
char buf[16];
static int prevx = 0, prevy = 0;
static unsigned clicks_time = 0, clicks = 0;
if( (lt_time_ms() - clicks_time) > 400 ) clicks = 0;
//
for( GLEQevent e; gleqNextEvent(&e); gleqFreeEvent(&e) )
if( lt_events & e.type )
switch (e.type) {
default:
break; case GLEQ_WINDOW_CLOSED: // it used to be ok. depends on window_swap() flow
rc += lt_emit_event(L, "quit", NULL);
return rc;
break; case GLEQ_WINDOW_MOVED:
lt_wx = e.pos.x;
lt_wy = e.pos.y;
break; case GLEQ_WINDOW_RESIZED:
rc += lt_emit_event(L, "resized", "dd", lt_ww = e.size.width, lt_wh = e.size.height);
lt_resizesurface(lt_getsurface(lt_window()), lt_ww, lt_wh);
break; case GLEQ_WINDOW_REFRESH:
rc += lt_emit_event(L, "exposed", NULL);
rencache_invalidate();
break; case GLEQ_FILE_DROPPED:
rc += lt_emit_event(L, "filedropped", "sdd", e.file.paths[0], lt_mx, lt_my);
break; case GLEQ_KEY_PRESSED:
case GLEQ_KEY_REPEATED:
rc += lt_emit_event(L, "keypressed", "s", lt_key_name(buf, e.keyboard.key, e.keyboard.scancode, e.keyboard.mods));
goto bottom;
break; case GLEQ_KEY_RELEASED:
rc += lt_emit_event(L, "keyreleased", "s", lt_key_name(buf, e.keyboard.key, e.keyboard.scancode, e.keyboard.mods));
goto bottom;
break; case GLEQ_CODEPOINT_INPUT:
rc += lt_emit_event(L, "textinput", "s", codepoint_to_utf8_(e.codepoint));
break; case GLEQ_BUTTON_PRESSED:
rc += lt_emit_event(L, "mousepressed", "sddd", lt_button_name(e.mouse.button), lt_mx, lt_my, printi(1 + clicks));
break; case GLEQ_BUTTON_RELEASED:
clicks += e.mouse.button == GLFW_MOUSE_BUTTON_1;
clicks_time = lt_time_ms();
rc += lt_emit_event(L, "mousereleased", "sdd", lt_button_name(e.mouse.button), lt_mx, lt_my);
break; case GLEQ_CURSOR_MOVED:
lt_mx = e.pos.x - lt_wx, lt_my = e.pos.y - lt_wy;
rc += lt_emit_event(L, "mousemoved", "dddd", lt_mx, lt_my, lt_mx - prevx, lt_my - prevy);
prevx = lt_mx, prevy = lt_my;
break; case GLEQ_SCROLLED:
rc += lt_emit_event(L, "mousewheel", "f", e.scroll.y);
}
bottom:;
return rc;
}