/* * LaGUI: A graphical application framework. * Copyright (C) 2022-2023 Wu Yiming * * 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 . */ #if defined(LA_USE_GLES) || defined(LAGUI_ANDROID) #define NANOVG_GLES3_IMPLEMENTATION #else #define NANOVG_GL3_IMPLEMENTATION #endif #include "la_5.h" #include #include #include #include #ifdef LA_LINUX #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif #ifdef _WIN32 #include #include #include #endif #ifdef LAGUI_ANDROID #include #include #include #include #include #include #include #include #include #include #include FILE *funopen(const void *cookie, int (*readfn)(void *, char *, int), int (*writefn)(void *, const char *, int), fpos_t (*seekfn)(void *, fpos_t, int), int (*closefn)(void *)); static int android_read(void *cookie, char *buf, int size); static int android_write(void *cookie, const char *buf, int size); static fpos_t android_seek(void *cookie, fpos_t offset, int whence); static int android_close(void *cookie); void la_InitAndroidPlatform(struct android_app *app); static void la_AndroidCommandCallback(struct android_app *app, int32_t cmd); static int32_t la_AndroidInputCallback(struct android_app *app, AInputEvent *event); void la_InitAndroidPlatform(struct android_app *app); #endif LA MAIN={0}; extern tnsMain *T; int deb = 0; laOperator *DEB; laColumn *DEBUG_C; #ifdef _WIN32 #define LA_GUI_WNDCLASS_NAME L"NUL4_GUI_CLASS" #else #define LA_GUI_WNDCLASS_NAME "NUL4_GUI_CLASS" #endif #ifdef LA_LINUX typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*);\ typedef void (*glXSwapIntervalEXTProc)(Display *dpy, GLXDrawable drawable, int interval); glXCreateContextAttribsARBProc glXCreateContextAttribsF; glXSwapIntervalEXTProc glXSwapIntervalEXTF; #endif #ifdef LA_LINUX static void la_PrintWacomValuators(Display *display, XIAnyClassInfo **classes, int num_classes){ int i; for (i = 0; i < num_classes; i++) { if (classes[i]->type == XIValuatorClass) { XIValuatorClassInfo *v = (XIValuatorClassInfo*)classes[i]; logPrint(" Valuator %d: '%s'\n", v->number, (v->label) ? XGetAtomName(display, v->label) : "No label"); logPrint(" Range: %f - %f\n", v->min, v->max); logPrint(" Resolution: %d units/m\n", v->resolution); logPrint(" Mode: %s\n", v->mode == XIModeAbsolute ? "absolute": "relative"); if (v->mode == XIModeAbsolute) logPrint(" Current value: %f\n", v->value); } } } static void la_RegisterWacomEventMasks(Display *display, int deviceid, real* max_pressure) { XIDeviceInfo *info, *dev; int i, ndevices; dev = XIQueryDevice(display, deviceid, &ndevices); XIEventMask *mask=memAcquireSimple(sizeof(XIEventMask)); mask->deviceid = deviceid; mask->mask_len = XIMaskLen(XI_RawMotion); mask->mask=memAcquireSimple(mask->mask_len); memset(mask->mask, 0, mask->mask_len); XISetMask(mask->mask, XI_RawMotion); XISelectEvents(display, DefaultRootWindow(display), mask, 1); int FoundMax=0; for (i = 0; i < dev->num_classes; i++) { if (dev->classes[i]->type == XIValuatorClass) { XIValuatorClassInfo *v = (XIValuatorClassInfo*)dev->classes[i]; if(v->number==2){ *max_pressure=v->max; FoundMax=1; break; } } } if(!FoundMax){*max_pressure=65535;} logPrint(" Device Name: '%s' (%d)\n", dev->name, dev->deviceid); //la_PrintWacomValuators(display, dev->classes, dev->num_classes); XIFreeDeviceInfo(dev); } int la_DeviceProbablyHasPressure(XIDeviceInfo* dev){ int axis=0; for (int i = 0; i < dev->num_classes; i++) { if (dev->classes[i]->type == XIValuatorClass){ axis++; } } return axis>=3; } #define LA_G_STYLUS(dev) \ (la_DeviceProbablyHasPressure(dev)&&(!MAIN.WacomDeviceStylus)) #define LA_G_ERASER \ (!MAIN.WacomDeviceEraser) void la_ScanWacomDevices(Display *display, int deviceid){ XIDeviceInfo *info, *dev; int ndevices; int i; char * word; int _event, _error; if (!XQueryExtension(MAIN.dpy, "XInputExtension", &MAIN.xi_opcode, &_event, &_error)) { logPrint("X Input extension not available, wacom pressure events are not available.\n"); return; } info = XIQueryDevice(display, deviceid, &ndevices); for(i = 0; i < ndevices; i++) { dev = &info[i]; strToLower(dev->name); if (strstr(dev->name, "pen pen")){ if(LA_G_STYLUS(dev)) MAIN.WacomDeviceStylus = dev->deviceid; } // some wacom tablets "wacom bamboo connect pen pen" elif (strstr(dev->name, "stylus pen")){ if(LA_G_STYLUS(dev)) MAIN.WacomDeviceStylus = dev->deviceid; } // some huion ones "HUION 256C PEN STYLUS Pen" int is_ipts=0; if(strstr(dev->name, "ipts")){ is_ipts=1; } word = strtok (dev->name," "); while (1) { word = strtok (NULL, " "); if (!word) break; if (strcmp("stylus", word) == 0){ if(LA_G_STYLUS(dev)) MAIN.WacomDeviceStylus = dev->deviceid; }// wacom elif (strcmp("eraser", word) == 0){ if(LA_G_ERASER) MAIN.WacomDeviceEraser = dev->deviceid; }// wacom elif (is_ipts && strcmp("pen", word) == 0){ if(LA_G_STYLUS(dev)) MAIN.WacomDeviceStylus = dev->deviceid; }// surface ipts elif (is_ipts && strcmp("eraser", word) == 0){ if(LA_G_ERASER) MAIN.WacomDeviceEraser = dev->deviceid; }// surface ipts elif (strcmp("pen", word) == 0){ if(LA_G_STYLUS(dev)) MAIN.WacomDeviceStylus = dev->deviceid; }// generic pen } } if(MAIN.WacomDeviceStylus || MAIN.WacomDeviceEraser){ logPrintNew("Found wacom devices:\n"); if(MAIN.WacomDeviceStylus) la_RegisterWacomEventMasks(display, MAIN.WacomDeviceStylus,&MAIN.StylusMaxPressure); if(MAIN.WacomDeviceEraser) la_RegisterWacomEventMasks(display, MAIN.WacomDeviceEraser,&MAIN.EraserMaxPressure); }else{ logPrintNew("No wacom pen device connected.\n"); } XIFreeDeviceInfo(info); } void laHideCursor(){ if(!MAIN.CurrentWindow) return; XFixesHideCursor(MAIN.dpy, MAIN.CurrentWindow->win); } void laShowCursor(){ if(!MAIN.CurrentWindow) return; XFixesShowCursor(MAIN.dpy, MAIN.CurrentWindow->win); } void la_XErrorHandler(Display *display, XErrorEvent *event){ char buf[512]; XGetErrorText(display, event->error_code, buf, sizeof(buf)); printf("X Error:\n%s\n",buf); } SYSWINDOW la_CreateWindowX11(int x, int y, int w, int h, char *title, int SyncToVBlank, GLXContext* r_glc, void* egl_surf){ XSetWindowAttributes swa; XWindowAttributes wa; swa.event_mask = KeyPressMask|KeyReleaseMask|StructureNotifyMask|SubstructureNotifyMask| ButtonMotionMask|ButtonPressMask|ButtonReleaseMask|ExposureMask|PointerMotionMask; swa.colormap = MAIN.cmap; SYSWINDOW root = DefaultRootWindow(MAIN.dpy); SYSWINDOW win = XCreateWindow(MAIN.dpy, root, x,y, w, h, 0, MAIN.xvi->depth, InputOutput, MAIN.xvi->visual, CWColormap | CWEventMask, &swa); XSetWMProtocols(MAIN.dpy , win, &MAIN.MsgDelWindow, 1); if(x>0||y>0){ XSizeHints my_hints = {0}; my_hints.flags = PPosition; my_hints.x = x; my_hints.y = y; XSetNormalHints(MAIN.dpy, win, &my_hints); } XStoreName(MAIN.dpy, win, title); #ifdef LA_USE_GLES static const EGLint ctx_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE }; (*r_glc)=eglCreateContext(MAIN.egl_dpy, MAIN.BestFBC, MAIN.glc, ctx_attribs ); if (!(*r_glc)){ printf("\n\tcannot create gl context\n\n"); exit(0); } EGLSurface* surf=egl_surf; (*surf)=eglCreateWindowSurface(MAIN.egl_dpy, MAIN.BestFBC, win, NULL); if (!(*surf)) { printf("Error: eglCreateWindowSurface failed %d\n",eglGetError()); exit(1); } tnsContextMakeCurrent((*r_glc),win,(*surf)); #else int attribs[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, MAIN.GLMajor, GLX_CONTEXT_MINOR_VERSION_ARB, MAIN.GLMinor, 0}; if (((*r_glc) = glXCreateContextAttribsF(MAIN.dpy, MAIN.BestFBC, MAIN.glc, GL_TRUE, attribs)) == NULL){ printf("\n\tcannot create gl context\n\n"); exit(0); } tnsContextMakeCurrent((*r_glc),win,0); int sync=SyncToVBlank?1:0; glXSwapIntervalEXTF(MAIN.dpy, win, sync); #endif XSetLocaleModifiers(""); MAIN.im = XOpenIM(MAIN.dpy, NULL, NULL, NULL); if(!MAIN.im){ XSetLocaleModifiers("@im=local"); MAIN.im = XOpenIM(MAIN.dpy, NULL, NULL, NULL); } if(!MAIN.im){ XSetLocaleModifiers("@im=none"); MAIN.im = XOpenIM(MAIN.dpy, NULL, NULL, NULL); } if(!MAIN.im){ XSetLocaleModifiers("@im="); MAIN.im = XOpenIM(MAIN.dpy, NULL, NULL, NULL); } if(!MAIN.im){ logPrint("Can't open a input method.\n"); } if(MAIN.im){ MAIN.ic = XCreateIC(MAIN.im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, win, NULL); XSetICFocus(MAIN.ic); } XClassHint ch; ch.res_name = "LAGUI_WINDOW"; ch.res_class = "LAGUI_WINDOW"; XSetClassHint(MAIN.dpy, win, &ch); #define _NET_WM_STATE_ADD 1 if(w<0&&h<0){ XEvent xev; Atom wm_state = XInternAtom(MAIN.dpy, "_NET_WM_STATE", False); Atom max_horz = XInternAtom(MAIN.dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", False); Atom max_vert = XInternAtom(MAIN.dpy, "_NET_WM_STATE_MAXIMIZED_VERT", False); memset(&xev, 0, sizeof(xev)); xev.type = ClientMessage; xev.xclient.window = win; xev.xclient.message_type = wm_state; xev.xclient.format = 32; xev.xclient.data.l[0] = _NET_WM_STATE_ADD; xev.xclient.data.l[1] = max_horz; xev.xclient.data.l[2] = max_vert; XSendEvent(MAIN.dpy, DefaultRootWindow(MAIN.dpy), False, SubstructureNotifyMask, &xev); } return win; }; void la_DestroySystemWindowX11(laWindow* w) { tnsContextMakeCurrent(0,0,0); tnsDeleteContext(w->glc); #ifdef LA_USE_GLES eglDestroySurface(MAIN.egl_dpy, w->egl_surf); #endif XDestroyWindow(MAIN.dpy, w->win); }; #endif //linux #ifdef _WIN32 #include #include #include #define PACKETDATA (PK_X | PK_Y | PK_Z | PK_STATUS | PK_BUTTONS | PK_NORMAL_PRESSURE | PK_TANGENT_PRESSURE | PK_ORIENTATION | PK_TIME | PK_CURSOR) #define PACKETMODE PK_BUTTONS #include void la_OpenWacomWinTab(HWND hwnd){ if((!MAIN.WinTabAvailable)||(MAIN.WinTabOpened)) return; static LOGCONTEXT glogContext = { 0 }; HCTX hctx = NULL; UINT wDevice = 0; UINT wExtX = 0; UINT wExtY = 0; UINT wWTInfoRetVal = 0; AXIS TabletX = { 0 }; AXIS TabletY = { 0 }; AXIS TabletZ = { 0 }; glogContext.lcOptions |= CXO_SYSTEM; wWTInfoRetVal = gpWTInfoA(WTI_DEFSYSCTX, 0, &glogContext); assert(wWTInfoRetVal == sizeof(LOGCONTEXT)); assert(glogContext.lcOptions & CXO_SYSTEM); wsprintf(glogContext.lcName, "PrsTest Digitizing %p", MAIN.hinstance); glogContext.lcOptions |= CXO_MESSAGES|CXO_CSRMESSAGES; glogContext.lcPktData = PACKETDATA; glogContext.lcPktMode = PACKETMODE; glogContext.lcMoveMask = PACKETDATA; glogContext.lcBtnUpMask = glogContext.lcBtnDnMask; wWTInfoRetVal = gpWTInfoA(WTI_DEVICES + 0, DVC_X, &TabletX); assert(wWTInfoRetVal == sizeof(AXIS)); wWTInfoRetVal = gpWTInfoA(WTI_DEVICES, DVC_Y, &TabletY); assert(wWTInfoRetVal == sizeof(AXIS)); wWTInfoRetVal = gpWTInfoA(WTI_DEVICES, DVC_Z, &TabletZ); if (wWTInfoRetVal) { assert(wWTInfoRetVal == sizeof(AXIS)); MAIN.WinTabMaxHover = TabletZ.axMax; } AXIS tabletPressure = { 0 }; gpWTInfoA(WTI_DEVICES, DVC_NPRESSURE, &tabletPressure); MAIN.WinTabMaxPenPressure = tabletPressure.axMax + 1; //glogContext.lcInOrgX = 0; //glogContext.lcInOrgY = 0; //glogContext.lcInExtX = TabletX.axMax; //glogContext.lcInExtY = TabletY.axMax; gpWTInfoA(WTI_DEFSYSCTX, CTX_INORGX, &glogContext.lcInOrgX); gpWTInfoA(WTI_DEFSYSCTX, CTX_INORGY, &glogContext.lcInOrgY); gpWTInfoA(WTI_DEFSYSCTX, CTX_INEXTX, &glogContext.lcInExtX); gpWTInfoA(WTI_DEFSYSCTX, CTX_INEXTY, &glogContext.lcInExtY); gpWTInfoA(WTI_DEFSYSCTX, CTX_OUTORGX, &glogContext.lcOutOrgX); gpWTInfoA(WTI_DEFSYSCTX, CTX_OUTORGY, &glogContext.lcOutOrgY); gpWTInfoA(WTI_DEFSYSCTX, CTX_OUTEXTX, &glogContext.lcOutExtX); gpWTInfoA(WTI_DEFSYSCTX, CTX_OUTEXTY, &glogContext.lcOutExtY); gpWTInfoA(WTI_DEFSYSCTX, CTX_SYSORGX, &glogContext.lcSysOrgX); gpWTInfoA(WTI_DEFSYSCTX, CTX_SYSORGY, &glogContext.lcSysOrgY); gpWTInfoA(WTI_DEFSYSCTX, CTX_SYSEXTX, &glogContext.lcSysExtX); gpWTInfoA(WTI_DEFSYSCTX, CTX_SYSEXTY, &glogContext.lcSysExtY); //printf("%d %d\n", glogContext.lcInOrgX, glogContext.lcInOrgY); //printf("%d %d\n", glogContext.lcInExtX, glogContext.lcInExtY); //printf("%d %d\n", glogContext.lcOutOrgX, glogContext.lcOutOrgY); //printf("%d %d\n", glogContext.lcOutExtX, glogContext.lcOutExtY); //printf("%d %d\n", glogContext.lcSysOrgX, glogContext.lcSysOrgY); //printf("%d %d\n", glogContext.lcSysExtX, glogContext.lcSysExtY); glogContext.lcOutOrgX = GetSystemMetrics(SM_XVIRTUALSCREEN); glogContext.lcOutOrgY = GetSystemMetrics(SM_YVIRTUALSCREEN); glogContext.lcOutExtX = GetSystemMetrics(SM_CXVIRTUALSCREEN); //SM_CXSCREEN); glogContext.lcOutExtY = -GetSystemMetrics(SM_CYVIRTUALSCREEN); // lower left to upper left. SM_CYSCREEN); //printf("%d %d\n", glogContext.lcOutOrgX, glogContext.lcOutOrgY); //printf("%d %d\n", glogContext.lcOutExtX, glogContext.lcOutExtY); hctx = gpWTOpenA(hwnd, &glogContext, FALSE); if (!hctx)return; gpWTEnable(hctx, 1); MAIN.WinTabOpened = 1; logPrintNew("Successfully opened Wacom input device via WinTab.\n"); } void laHideCursor() { if (!MAIN.CurrentWindow) return; //impl } void laShowCursor() { if (!MAIN.CurrentWindow) return; //impl } static PIXELFORMATDESCRIPTOR cpfd = { sizeof(PIXELFORMATDESCRIPTOR),1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_SWAP_COPY | PFD_DOUBLEBUFFER, PFD_TYPE_RGBA, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 8, 0, 0, 0, 0, 0, 0 }; void la_SetupPxlFormat(HDC hdc, int* nRegularFormat, int* nMSFormat) { int nBestMS = 0; int i; int iResults[9]; int iAttributes[9] = { WGL_SUPPORT_OPENGL_ARB, // 0 WGL_ACCELERATION_ARB, // 1 WGL_DRAW_TO_WINDOW_ARB, // 2 WGL_DOUBLE_BUFFER_ARB, // 3 WGL_PIXEL_TYPE_ARB, // 4 WGL_DEPTH_BITS_ARB, // 5 WGL_STENCIL_BITS_ARB, // 6 WGL_SAMPLE_BUFFERS_ARB, // 7 WGL_SAMPLES_ARB }; // 8 // How many pixelformats are there? int nFormatCount[] = { 0 }; int attrib[] = { WGL_NUMBER_PIXEL_FORMATS_ARB }; if (!wglGetPixelFormatAttribivARB) wglGetPixelFormatAttribivARB = (PFNWGLGETPIXELFORMATATTRIBIVARBPROC) wglGetProcAddress("wglGetPixelFormatAttribivARB"); wglGetPixelFormatAttribivARB(hdc, 1, 0, 1, attrib, nFormatCount); for (i = 0; i < nFormatCount[0]; i++){ wglGetPixelFormatAttribivARB(hdc, i + 1, 0, 9, iAttributes, iResults); if (iResults[0] == 1 && iResults[1] == WGL_FULL_ACCELERATION_ARB && iResults[2] == 1) if (iResults[3] == 1) // Double buffered if (iResults[4] == WGL_TYPE_RGBA_ARB) // Full Color if (iResults[5] >= 24) // Any Depth greater than 16 if (iResults[6] > 0) { *nRegularFormat = i; break; } } SetPixelFormat(hdc, *nRegularFormat, &cpfd); }; void la_SetupGLEnviornment(laWindow* window, HWND hwnd, int Sync) { GLint Attrib[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, MAIN.GLMajor, WGL_CONTEXT_MINOR_VERSION_ARB, MAIN.GLMinor, WGL_CONTEXT_PROFILE_MASK_ARB,WGL_CONTEXT_CORE_PROFILE_BIT_ARB, //WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, GL_TRUE, 0 }; HGLRC hglrc = 0; HDC hdc = 0; int a, b; hdc = GetDC(hwnd); la_SetupPxlFormat(hdc, &a, &b); hglrc = wglCreateContextAttribsARB(hdc, MAIN.glc, Attrib); if (!hglrc) SEND_PANIC_ERROR("Can't Create Opengl Context!\n", ); tnsContextMakeCurrent(hglrc, hdc,0); //int sync = Sync ? 1 : 0; wglSwapIntervalEXT(sync); wglSwapIntervalEXT(-1); window->win = hwnd; window->glc = hglrc; window->hdc = hdc; }; SYSWINDOW la_CreateWindowWin32(int x, int y, int w, int h, char* title, int SyncToVBlank, SYSGLCONTEXT* r_glc) { HINSTANCE* inst = &MAIN.hinstance; HWND hwnd = CreateWindowW(LA_GUI_WNDCLASS_NAME, title, WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, x, y, w, h, 0, 0, *inst, 0); if (!hwnd) { int a = GetLastError(); printf("%d", a); return 0; } if (!MAIN.WinTabOpened) { la_OpenWacomWinTab(hwnd); } return hwnd; }; void la_DestroySystemWindowWin32(laWindow* w) { tnsContextMakeCurrent(0,0,0); tnsDeleteContext(w->glc); ReleaseDC(w->win, w->hdc); DestroyWindow(w->win); }; #endif #ifdef LAGUI_ANDROID SYSWINDOW la_CreateWindowAndroid(){ return 0; }; void laShowCursor(){} void laHideCursor(){} #endif #ifdef LA_LINUX void la_HandlerSIGSEGV(int sig) { void *array[30]; size_t sz; sz = backtrace(array, 30); fprintf(stdout, "LaGUI recieved error signal %d:\n The program terminated unexpectedly.\n", sig); backtrace_symbols_fd(array, sz, STDERR_FILENO); exit(1); } #endif void la_glDebugOutput(GLenum source, GLenum type, unsigned int id, GLenum severity, GLsizei length, const char* message, const void* userParam) { //#ifndef LAGUI_ANDROID // ignore non-significant error/warning codes if (id==131169 || id==131185 || id==131218 || id==131204 || id==131076 || id==7||id==8) return; logPrint("GL %d: %s\n", id, message); char* strsource="",*strtype="",*strseverity=""; switch (source) { case GL_DEBUG_SOURCE_API: strsource = "API"; break; case GL_DEBUG_SOURCE_WINDOW_SYSTEM: strsource = "Window System"; break; case GL_DEBUG_SOURCE_SHADER_COMPILER: strsource = "Shader Compiler"; break; case GL_DEBUG_SOURCE_THIRD_PARTY: strsource = "Third Party"; break; case GL_DEBUG_SOURCE_APPLICATION: strsource = "Application"; break; case GL_DEBUG_SOURCE_OTHER: strsource = "Other"; break; } switch (type) { case GL_DEBUG_TYPE_ERROR: strtype = "Error"; break; case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: strtype = "Deprecated Behaviour"; break; case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: strtype = "Undefined Behaviour"; break; case GL_DEBUG_TYPE_PORTABILITY: strtype = "Portability"; break; case GL_DEBUG_TYPE_PERFORMANCE: strtype = "Performance"; break; case GL_DEBUG_TYPE_MARKER: strtype = "Marker"; break; case GL_DEBUG_TYPE_PUSH_GROUP: strtype = "Push Group"; break; case GL_DEBUG_TYPE_POP_GROUP: strtype = "Pop Group"; break; case GL_DEBUG_TYPE_OTHER: strtype = "Other"; break; } switch (severity) { case GL_DEBUG_SEVERITY_HIGH: strseverity = "High"; break; case GL_DEBUG_SEVERITY_MEDIUM: strseverity = "Medium"; break; case GL_DEBUG_SEVERITY_LOW: strseverity = "Low"; break; case GL_DEBUG_SEVERITY_NOTIFICATION: strseverity = "Notification"; break; } logPrint("%s | %s | %s\n\n", strsource,strtype,strseverity); //#endif } void la_SetCurrentGLContextDebug(){ //#ifndef LAGUI_ANDROID int force=MAIN.InitArgs.GLDebug; if(MAIN.EnableGLDebug || force){ glEnable(GL_DEBUG_OUTPUT); }else{ glDisable(GL_DEBUG_OUTPUT); } if(MAIN.GLDebugSync || force){ glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); }else{ glDisable(GL_DEBUG_OUTPUT_SYNCHRONOUS); } glDebugMessageCallback(la_glDebugOutput, 0); int sev=GL_DONT_CARE; if(!force){ switch(MAIN.GLDebugLevel){ default: sev=GL_DONT_CARE; break; case 1: sev=GL_DEBUG_SEVERITY_NOTIFICATION; break; case 2: sev=GL_DEBUG_SEVERITY_LOW; break; case 3: sev=GL_DEBUG_SEVERITY_MEDIUM; break; case 4: sev=GL_DEBUG_SEVERITY_HIGH; break; } } glDebugMessageControl(GL_DONT_CARE, GL_DONT_CARE, sev, 0, 0, GL_TRUE); //#endif } void la_NotifyGLDebugChanges(){ MAIN.GLDebugNeedsUpdate=1; for(laWindow* w=MAIN.Windows.pFirst;w;w=w->Item.pNext){ w->GLDebugNeedsUpdate=1; } } void la_SetupWindowGLStates(laWindow* w){ tnsBindVertexArray(w->vao); tnsUnbindTexture(); tnsUseImmShader(); tnsEnableShaderv(T->immShader); if(w->GLDebugNeedsUpdate){ tnsContextMakeWindowCurrent(w); la_SetCurrentGLContextDebug(); w->GLDebugNeedsUpdate=0; } } int la_CreateSystemWindow(laWindow *window, int SyncToVBlank){ SYSGLCONTEXT glc; #ifdef LA_LINUX void* egl_surf=0; #ifdef LA_USE_GLES egl_surf=&window->egl_surf; #endif SYSWINDOW hwnd = la_CreateWindowX11(window->X, window->Y, window->W, window->H, window->Title->Ptr, SyncToVBlank, &glc, egl_surf); #endif #ifdef _WIN32 SYSWINDOW hwnd = la_CreateWindowWin32(window->X, window->Y, window->W, window->H, window->Title->Ptr, SyncToVBlank, &glc); #endif #ifdef LAGUI_ANDROID la_CreateWindowAndroid(); window->win = 1; window->glc = MAIN.glc; #else window->win = hwnd; window->glc = glc; #endif #ifdef _WIN32 la_SetupGLEnviornment(window, hwnd, SyncToVBlank); RECT rc; GetClientRect(window->win, &rc); window->CW = rc.right - rc.left; window->CH = rc.bottom - rc.top; #endif #ifdef LA_LINUX XWindowAttributes attr; XGetWindowAttributes(MAIN.dpy, window->win, &attr); window->CW =attr.width; window->CH = attr.height; #endif la_SetCurrentGLContextDebug(); glGenVertexArrays(1,&window->vao); tnsBindVertexArray(window->vao); la_SetupWindowGLStates(window); #if defined(LA_USE_GLES) || defined(LAGUI_ANDROID) window->nvg=nvgCreateGLES3(NVG_STENCIL_STROKES|NVG_DEBUG|NVG_ANTIALIAS); #else window->nvg=nvgCreateGL3(NVG_STENCIL_STROKES|NVG_DEBUG|NVG_ANTIALIAS); #endif window->OutputShowStripes=1; window->Redraw=1; window->GLDebugNeedsUpdate=1; window->UseComposing=0; window->ComposingGamma=1.0; window->ComposingBlackpoint=0.0; return 1; }; int la_DestroySystemWindow(laWindow* wnd){ #if defined(LA_USE_GLES) || defined(LAGUI_ANDROID) nvgDeleteGLES3(wnd->nvg); #else nvgDeleteGL3(wnd->nvg); #endif #ifdef LA_LINUX la_DestroySystemWindowX11(wnd); #endif #ifdef _WIN32 la_DestroySystemWindowWin32(wnd); #endif } void la_DestroyWindow(laWindow *wnd){ laLayout *l; laPanel *p; if (!wnd) return; tnsSwitchToCurrentWindowContext(wnd); tnsBindVertexArray(0); glDeleteVertexArrays(1,&wnd->vao); la_StopAllOperators(); strSafeDestroy(&wnd->Title); //la_PrintUserList(wnd); //printf("----\n"); while (p = lstPopItem(&wnd->Panels)){ laDestroySinglePanel(p,1); } while (l = lstPopItem(&wnd->Layouts)){ laDestroyBlocksRecursive(l->FirstBlock); //la_PrintUserList(l); //printf("%x %s\n", l, l->ID->Ptr); strSafeDestroy(&l->ID); memFree(l); //la_PrintUserList(wnd); //printf("----\n"); } //printf("----\n%x\n",wnd); //la_PrintUserList(wnd); la_DestroySystemWindow(wnd); lstRemoveItem(&MAIN.Windows, wnd); memFree(wnd); MAIN.CurrentWindow=MAIN.Windows.pFirst; } void laRenameWindow(laWindow* wnd, char* name){ if((!wnd)||MAIN.IsReadingUDF) return; strSafeSet(&wnd->Title, name); if(!wnd->win) return; #ifdef LA_LINUX XStoreName(MAIN.dpy, wnd->win, name); #endif #ifdef _WIN32 //wchar_t buf[128]; MultiByteToWideChar(CP_UTF8, 0, name, -1, buf, 128); SetWindowTextW(wnd->win, name); #endif } #ifdef LA_LINUX const char* la_ConvertCursorID(int id){ switch (id) { case LA_ARROW: return "arrow"; case LA_CROSS: return "cross"; case LA_LEFT_AND_RIGHT: return "sb_h_double_arrow"; case LA_UP_AND_DOWN: return "sb_v_double_arrow"; case LA_MOVE: return "diamond_cross"; case LA_HAND: return "hand1"; case LA_CORNER: return "bottom_right_corner"; } return "arrow"; } #endif #ifdef _WIN32 HCURSOR la_ConvertCursorID(int id){ switch (id){ case LA_ARROW: return LoadCursor(0,IDC_ARROW); case LA_CROSS: return LoadCursor(0,IDC_CROSS); case LA_LEFT_AND_RIGHT: return LoadCursor(0,IDC_SIZEWE); case LA_UP_AND_DOWN: return LoadCursor(0, IDC_SIZENS); case LA_MOVE: return LoadCursor(0, IDC_SIZEALL); case LA_HAND: return LoadCursor(0, IDC_HAND); case LA_CORNER: return LoadCursor(0, IDC_SIZENWSE); } return LoadCursor(0, IDC_ARROW);; } #endif void la_InitThreadEnviornment(){ //pthread_spin_init(&MAIN.csNotifier, //pthread_PROCESS_PRIVATE); } laLogEntry* logEnsure(int Create){ if(!MAIN.Logs.pFirst || Create){ laLogEntry* le=memAcquireSimple(sizeof(laLogEntry)); lstAppendItem(&MAIN.Logs, le); } return MAIN.Logs.pLast; } void logPrintTV(int Continued, char* format, va_list v){ if(!format || !format[0]) return; laLogEntry* le=logEnsure(Continued); if(MAIN.EnableLogStdOut){ va_list v1; va_copy(v1,v); vprintf(format,v1); } strSafePrintV(&le->Content, format, v); #ifdef LAGUI_ANDROID __android_log_print(ANDROID_LOG_DEBUG, "LAGUI", "%s",SSTR(le->Content)); #endif laNotifyUsers("la.logs"); } void logPrintT(int Continued, char* format, ...){ if(!format || !format[0]) return; laLogEntry* le=logEnsure(Continued); va_list aptr; va_start(aptr, format); strSafePrint(&le->Content, format, aptr); va_end(aptr); #ifdef LAGUI_ANDROID __android_log_print(ANDROID_LOG_DEBUG, "LAGUI", "%s",SSTR(le->Content)); #endif laNotifyUsers("la.logs"); } void logPrint(char* format, ...){ va_list aptr; va_start(aptr, format); logPrintTV(0, format, aptr); va_end(aptr); } void logPrintNew(char* format, ...){ logEnsure(1); va_list aptr; va_start(aptr, format); logPrintTV(0, format, aptr); va_end(aptr); } void logClear(){ laLogEntry*l; while(l=lstPopItem(&MAIN.Logs)){ strSafeDestroy(&l->Content); memFree(l); } laNotifyUsers("la.logs"); } laSafeString** la_PerfEnsure(){ MAIN.NextPerfCounter++; if(MAIN.NextPerfCounter>=32){ MAIN.NextPerfCounter=0; } return &MAIN.PerfLogs[MAIN.NextPerfCounter]; } void la_PerfClear(){ if(!MAIN.ShowPerf){ return; } MAIN.NextPerfCounter=0; MAIN.NextPerfGroup++; if(MAIN.NextPerfGroup>=32){ MAIN.NextPerfGroup=0; } memset(&MAIN.PerfCounter[MAIN.NextPerfGroup],0,32*sizeof(real)); for(int i=0;i<32;i++){ strSafeDestroy(&MAIN.PerfLogs[i]); } } void laPerfRecordV(char* format, va_list v){ if(!format || !format[0]) return; laSafeString** ss=la_PerfEnsure(); strSafePrintV(ss, format, v); laTimeRecorder tm; laRecordTime(&tm); MAIN.PerfCounter[MAIN.NextPerfGroup][MAIN.NextPerfCounter] = laTimeElapsedSecondsf(&tm, &MAIN.FrameStartTime); } void laPerfRecord(char* format, ...){ if(!format || !format[0]) return; laSafeString** ss=la_PerfEnsure(); va_list aptr; va_start(aptr, format); strSafePrintV(ss, format, aptr); va_end(aptr); laTimeRecorder tm; laRecordTime(&tm); MAIN.PerfCounter[MAIN.NextPerfGroup][MAIN.NextPerfCounter] = laTimeElapsedSecondsf(&tm, &MAIN.FrameStartTime); } void la_PerfDraw(){ tnsScale3d(0.75,0.75,0.75); int sy=0; laBoxedTheme* bt=_LA_THEME_LABEL; real* color=laThemeColor(bt,LA_BT_TEXT); int sl=LA_RH*4; char buf[16]; real totval=0; real vals[32]; for(int i=0;i<32;i++){ if(MAIN.PerfLogs[i]){ real value = MAIN.PerfCounter[MAIN.NextPerfGroup][i]-(i>0?MAIN.PerfCounter[MAIN.NextPerfGroup][i-1]:0); sprintf(buf,"%0.2lf",value*1000); totval+=value; vals[i]=value; tnsDrawStringAuto(buf,color,0,10000,sy,LA_TEXT_SHADOW); tnsDrawStringAuto(SSTR(MAIN.PerfLogs[i]),color,sl,10000,sy,LA_TEXT_SHADOW); sy+=LA_RH; } } real SL=LA_RH*2,SR=LA_RH*3.5; sy=0; tnsColor4dv(color); tnsUseNoTexture(); for(int i=0;i<32;i++){ if(MAIN.PerfLogs[i]){ real r=vals[i]/totval; real use_r=tnsInterpolate(SL,SR,r); tnsVertex2d(SL,sy); tnsVertex2d(SL,sy+LA_RH); tnsVertex2d(use_r,sy+LA_RH); tnsVertex2d(use_r,sy); tnsPackAs(GL_TRIANGLE_FAN); sy+=LA_RH; } } tnsFlush(); } laScreen* la_EnsureScreen(char* Name, int mmw, int mmh, int x, int y, int w, int h,int dpi){ if(!Name || !Name[0]) return 0; for(laScreen* s=MAIN.Screens.pFirst;s;s=s->Item.pNext){ if(strSame(SSTR(s->Name),Name)){ s->x=x;s->y=y;s->w=w;s->h=h; return s; } } laScreen* s=memAcquire(sizeof(laScreen)); lstAppendItem(&MAIN.Screens,s); strSafeSet(&s->Name,Name); strSafePrint(&s->Description,"%dmm x %dmm with %dx%d ~%ddpi",mmw,mmh,w,h,dpi); s->RoughDPI=dpi; s->x=x;s->y=y;s->w=w;s->h=h; laNotifyUsers("la.user_preferences.screens"); return s; } void la_RemoveScreen(laScreen*s){ strSafeDestroy(&s->Description); strSafeDestroy(&s->Name); lstRemoveItem(&MAIN.Screens,s); memFree(s); } void la_RemoveDuplicatedScreenConf(){ laScreen* NextS; for(laScreen* s=MAIN.Screens.pFirst;s;s=NextS){ NextS = s->Item.pNext; for(laScreen* fs=s->Item.pNext;fs;fs=fs->Item.pNext){ if(strSame(SSTR(fs->Name),SSTR(s->Name))){ fs->x=s->x;fs->y=s->y;fs->w=s->w;fs->h=s->h; la_RemoveScreen(s); break; } } } } laScreen* laGetWindowScreen(laWindow* w){ int l,r,u,b; int area=-1; laScreen* maxs=0; for(laScreen* s=MAIN.Screens.pFirst;s;s=s->Item.pNext){ l=TNS_MAX2(s->x,w->X); r=TNS_MIN2(s->x+s->w,w->X+w->W); u=TNS_MAX2(s->y,w->Y); b=TNS_MIN2(s->y+s->h,w->Y+w->H); int w=(r-l); if(w<0){w=0;} int h=(b-u); if(h<0){h=0;} int a=w*h; if(a>area){ maxs = s; area = a; } } return maxs; } #ifdef LA_LINUX int la_GetDPI(Window* root_win){ XRRScreenResources *screen; XRROutputInfo *info; XRRCrtcInfo *crtc_info; XRRCrtcInfo *crtc; int iscres, icrtc, dpi=0; screen=XRRGetScreenResources(MAIN.dpy, root_win); for(iscres=0;iscresnoutput;iscres++){ info=XRRGetOutputInfo(MAIN.dpy,screen,screen->outputs[iscres]); if(!info->mm_width || !info->mm_height){ continue; } logPrint(" Xrandr reported output size: %dmm x %dmm\n",info->mm_width,info->mm_height); crtc=XRRGetCrtcInfo(MAIN.dpy,screen,info->crtc); dpi=(real)crtc->width/(real)info->mm_width*25.4; logPrint(" CRTC: %d x %d, around %ddpi\n",crtc->width,crtc->height,dpi); laScreen* s=la_EnsureScreen(info->name,info->mm_width,info->mm_height,crtc->x,crtc->y,crtc->width,crtc->height,dpi); XRRFreeCrtcInfo(crtc); //if(info->connection==RR_Connected){ // for (icrtc=0;icrtcncrtc;icrtc++) { // crtc_info=XRRGetCrtcInfo(MAIN.dpy,screen,screen->crtcs[icrtc]); // printf("==> %d,%d + %dx%d\n", crtc_info->x, crtc_info->y, crtc_info->width, crtc_info->height); // XRRFreeCrtcInfo(crtc_info); // } //} XRRFreeOutputInfo(info); } XRRFreeScreenResources(screen); return dpi; } #endif #ifdef _WIN32 typedef struct laWin32MonitorEnumData { int id; }laWin32MonitorEnumData; static BOOL CALLBACK la_Win32MonitorEnum(HMONITOR hMon, HDC hdc, LPRECT lprcMonitor, LPARAM pData){ laWin32MonitorEnumData* data = pData; char str[32]; sprintf(str, "Display %d", data->id); data->id++; laScreen* s = la_EnsureScreen(str, 0,0, lprcMonitor->left, lprcMonitor->top, lprcMonitor->right-lprcMonitor->left, lprcMonitor->bottom-lprcMonitor->top, 0); return TRUE; } int la_GetDPI(HWND win){ laWin32MonitorEnumData data = { 0 }; EnumDisplayMonitors(0, 0, la_Win32MonitorEnum, (LPARAM)&data); return GetDpiForWindow(win); return 144; } #endif #define PROGRESSW (LA_RH*15) void laShowProgress(real p1, real p2){ laSpinLock(&MAIN.OpsLock); laBoxedTheme *bt = _LA_THEME_TAB; real* fg=laThemeColor(bt,LA_BT_TEXT); real* bg=laThemeColor(bt,LA_BT_NORMAL); if(!MAIN.Progress.Called){ laRecordTime(&MAIN.Progress.TimeCalled); MAIN.Progress.Called=1; }else{ laTimeRecorder tm; laRecordTime(&tm); real t=laTimeElapsedSecondsf(&tm,&MAIN.Progress.TimeCalled); if(t<0.1){ laSpinUnlock(&MAIN.OpsLock); return; } memcpy(&MAIN.Progress.TimeCalled,&tm,sizeof(laTimeRecorder)); if(!MAIN.Progress.Shown){ int ww=PROGRESSW+LA_RH*2; #ifdef LA_LINUX int w=XDisplayWidth(MAIN.dpy, 0),h=XDisplayHeight(MAIN.dpy, 0); XMoveResizeWindow(MAIN.dpy,MAIN.Progress.w,w/2-ww/2,h/2-LA_RH*2/2,ww,LA_RH*2); long a=LA_COLOR3_TO_HEX(bg); XSetForeground(MAIN.dpy,MAIN.Progress.gc,LA_COLOR3_TO_HEX(fg)); XSetBackground(MAIN.dpy,MAIN.Progress.gc,LA_COLOR3_TO_HEX(bg)); XSetWindowBackground(MAIN.dpy,MAIN.Progress.w,LA_COLOR3_TO_HEX(bg)); if(MAIN.CurrentWindow) XSetTransientForHint(MAIN.dpy,MAIN.Progress.w,MAIN.CurrentWindow->win); XMapWindow(MAIN.dpy,MAIN.Progress.w); #endif #ifdef _WIN32 int w=GetSystemMetrics(SM_CXFULLSCREEN), h=GetSystemMetrics(SM_CYFULLSCREEN); SetWindowPos(MAIN.Progress.w, MAIN.CurrentWindow->win,w/2-ww/2,h/2-LA_RH*2/2,ww,LA_RH*2,0); ShowWindow(MAIN.Progress.w,SW_SHOW); #endif MAIN.Progress.Shown = 1; } } if(p1>=0) MAIN.Progress.p1=p1; if(p2>=0) MAIN.Progress.p2=p2; #ifdef LA_LINUX XClearWindow(MAIN.dpy,MAIN.Progress.w); XFillRectangle(MAIN.dpy,MAIN.Progress.w,MAIN.Progress.gc,LA_RH*2,0,PROGRESSW*MAIN.Progress.p1,LA_RH); XFillRectangle(MAIN.dpy,MAIN.Progress.w,MAIN.Progress.gc,LA_RH*2,LA_RH,PROGRESSW*MAIN.Progress.p2,LA_RH); tnsDrawLCD7_ProgressSystem(LA_RH*1.5,0,MAIN.Progress.p1); tnsDrawLCD7_ProgressSystem(LA_RH*1.5,LA_RH,MAIN.Progress.p2); XSync(MAIN.dpy, 1); XFlush(MAIN.dpy); #endif #ifdef _WIN32 InvalidateRect(MAIN.Progress.w,0,1); if(!MAIN.Progress.brush_bg){ MAIN.Progress.brush_bg=CreateSolidBrush(LA_COLOR3_TO_RGB(bg)); } if(!MAIN.Progress.brush_fg){ MAIN.Progress.brush_fg=CreateSolidBrush(LA_COLOR3_TO_RGB(fg)); } if(!MAIN.Progress.pen_fg){ MAIN.Progress.pen_fg=CreatePen(PS_SOLID, 2, LA_COLOR3_TO_RGB(fg)); } RECT rect; GetClientRect(MAIN.Progress.w, &rect); PAINTSTRUCT ps; BeginPaint(MAIN.Progress.w,&ps); SelectObject(MAIN.Progress.hdc, MAIN.Progress.brush_bg); Rectangle(MAIN.Progress.hdc, 0, 0, rect.right, rect.bottom); SelectObject(MAIN.Progress.hdc, MAIN.Progress.brush_fg); Rectangle(MAIN.Progress.hdc,LA_RH*2,0,LA_RH*2+PROGRESSW*MAIN.Progress.p1,LA_RH); Rectangle(MAIN.Progress.hdc,LA_RH*2,LA_RH,LA_RH*2+PROGRESSW*MAIN.Progress.p2,LA_RH+LA_RH); SelectObject(MAIN.Progress.hdc, MAIN.Progress.pen_fg); tnsDrawLCD7_ProgressSystem(LA_RH*1.5,0,MAIN.Progress.p1); tnsDrawLCD7_ProgressSystem(LA_RH*1.5,LA_RH,MAIN.Progress.p2); EndPaint(MAIN.Progress.w,&ps); MSG msg; while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)){ TranslateMessage(&msg); DispatchMessage(&msg); }; #endif laSpinUnlock(&MAIN.OpsLock); } void laHideProgress(){ laSpinLock(&MAIN.OpsLock); if(!MAIN.Progress.Shown){ MAIN.Progress.Called=0; laSpinUnlock(&MAIN.OpsLock); return; } laTimeRecorder tm; laRecordTime(&tm); real t=laTimeElapsedSecondsf(&tm,&MAIN.Progress.TimeCalled); if(t<0.2){ usleep((TNS_MIN2(0.2-t,0.2))*1000000); } MAIN.Progress.Called = MAIN.Progress.Shown = 0; #ifdef LA_LINUX XUnmapWindow(MAIN.dpy,MAIN.Progress.w); XSync(MAIN.dpy, 1); XFlush(MAIN.dpy); #endif #ifdef _WIN32 ShowWindow(MAIN.Progress.w,SW_HIDE); if(MAIN.CurrentWindow) UpdateWindow(MAIN.CurrentWindow->win); #endif laSpinUnlock(&MAIN.OpsLock); } //======================= void la_InitProgressWindow(){ #ifdef LA_LINUX MAIN.Progress.w=XCreateSimpleWindow(MAIN.dpy, RootWindow(MAIN.dpy, 0), 0, 0, PROGRESSW+LA_RH*2, LA_RH*2, 0, BlackPixel(MAIN.dpy, 0), WhitePixel(MAIN.dpy, 0)); if(!MAIN.Progress.w) return; Atom window_type = XInternAtom(MAIN.dpy, "_NET_WM_WINDOW_TYPE", False); long value = XInternAtom(MAIN.dpy, "_NET_WM_WINDOW_TYPE_DOCK", False); XChangeProperty(MAIN.dpy, MAIN.Progress.w, window_type,XA_ATOM, 32, PropModeReplace, (unsigned char *) &value,1 ); MAIN.Progress.gc=XCreateGC(MAIN.dpy,MAIN.Progress.w,0,&MAIN.Progress.gc_values); if(MAIN.Progress.gc<0) return; XSetFillStyle(MAIN.dpy, MAIN.Progress.gc, FillSolid); XSetLineAttributes(MAIN.dpy, MAIN.Progress.gc, 2, LineSolid, CapButt, JoinBevel); XSync(MAIN.dpy,0); #endif #ifdef _WIN32 WNDCLASSW wc; wc.hInstance = MAIN.hinstance; wc.lpfnWndProc = LA_ProgressWindowProc; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); wc.cbWndExtra = 0; wc.cbClsExtra = 0; wc.lpszClassName = L"_LAGUIPROGRESS"; wc.lpszMenuName = NULL; wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; if (!RegisterClassW(&wc)){ return; } MAIN.Progress.w=CreateWindowW(L"_LAGUIPROGRESS",L"Progress", WS_POPUP, 0,0,PROGRESSW+LA_RH*2,LA_RH*2,0,0,MAIN.hinstance,0); MAIN.Progress.hdc=GetDC(MAIN.Progress.w); #endif } void laSetFontFolderPath(char* absolute){ strcpy(MAIN.SysFontDir,absolute); int len=strlen(MAIN.SysFontDir); if(MAIN.SysFontDir[len-1]!='/'){ MAIN.SysFontDir[len]='/'; MAIN.SysFontDir[len+1]=0; } } void laSetDefaultInitArguments(laInitArguments* ia){ ia->GLMajor=3; ia->GLMinor=3; ia->BufferSamples=0; ia->UseColorManagement=0; ia->HasWorldObjects=0; ia->HasAction=0; ia->HasTextureInspector=0; ia->HasHistories=0; ia->HasTerminal=1; ia->HasAudio=0; } void laSetCompleteInitArguments(laInitArguments* ia){ ia->GLMajor=3; ia->GLMinor=3; ia->BufferSamples=0; ia->UseColorManagement=1; ia->HasWorldObjects=1; ia->HasAction=1; ia->HasTextureInspector=1; ia->HasHistories=1; ia->HasTerminal=1; ia->HasAudio=1; } void laProcessInitArguments(int argc, char* argv[],laInitArguments* ia) { MAIN.GLMajor=MAIN.GLMinor=-1; char* arg = 0; printf("Initializing LaGUI...\n",argc); for(int i=0;iGLMajor,ia->GLMinor); } continue; } if(strSame(argv[i], "--gl-debug")){ ia->GLDebug=1; printf("Enabled OpenGL Debug.\n"); } if(strSame(argv[i], "--log")){ ia->EnableLogStdOut=1; printf("Enabled log output to stdout.\n"); } } } int laGetReadyWith(laInitArguments* ia){ #ifdef LA_LINUX //signal(SIGSEGV,la_HandlerSIGSEGV); #endif laSpinInit(&MAIN.MemLock); laSpinInit(&MAIN.OpsLock); memcpy(&MAIN.InitArgs,ia,sizeof(laInitArguments)); if(MAIN.InitArgs.GLMajor>4||MAIN.InitArgs.GLMajor<1){ MAIN.InitArgs.GLMajor=3; } if(MAIN.InitArgs.GLMinor<1){ MAIN.InitArgs.GLMinor=3; } if(MAIN.InitArgs.GLESMajor>3||MAIN.InitArgs.GLESMajor<2){ MAIN.InitArgs.GLESMajor=3; } if(MAIN.InitArgs.GLESMinor<0){ MAIN.InitArgs.GLESMinor=0; } if(MAIN.BufferSamples==1){ MAIN.BufferSamples=0; } tnsInit(); #ifdef LA_LINUX SYSWINDOW root, win; GLint att[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None}; XSetWindowAttributes swa={0}; XWindowAttributes wa={0}; XEvent xev; logPrintNew("Initializing LaGUI...\n"); setlocale(LC_CTYPE, "zh_CN.utf8"); XSetErrorHandler(la_XErrorHandler); int i; if ((MAIN.dpy = XOpenDisplay(NULL)) == NULL){ printf("\n\tcannot connect to x server\n\n"); exit(0); } la_ScanWacomDevices(MAIN.dpy,XIAllDevices); MAIN.GLMajor=MAIN.InitArgs.GLMajor; MAIN.GLMinor=MAIN.InitArgs.GLMinor; MAIN.BufferSamples=MAIN.InitArgs.BufferSamples; MAIN.GLESMajor=MAIN.InitArgs.GLESMajor; MAIN.GLESMinor=MAIN.InitArgs.GLESMinor; #ifdef LA_USE_GLES logPrint("Chosen OpenGL version %d.%d\n",MAIN.GLESMajor,MAIN.GLESMinor); #else logPrint("Chosen OpenGL version %d.%d\n",MAIN.GLMajor,MAIN.GLMinor); #endif #ifdef LA_USE_GLES MAIN.egl_dpy=eglGetDisplay(MAIN.dpy); if(!MAIN.egl_dpy){ printf("Error: eglGetDisplay() failed\n"); exit(1); } EGLint egl_major, egl_minor; if (!eglInitialize(MAIN.egl_dpy, &egl_major, &egl_minor)) { printf("Error: eglInitialize() failed\n"); return -1; } int scrnum; XSetWindowAttributes attr; XVisualInfo *visInfo, visTemplate; int num_visuals; EGLContext ctx; EGLint num_configs; EGLint vid; static const EGLint attribs[] = { EGL_RED_SIZE, 8, EGL_GREEN_SIZE, 8, EGL_BLUE_SIZE, 8, EGL_DEPTH_SIZE, 1, EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE }; if (!eglChooseConfig(MAIN.egl_dpy, attribs, &MAIN.BestFBC, 1, &num_configs)) { printf("Error: couldn't get an EGL visual config\n"); exit(1); } if (!eglGetConfigAttrib(MAIN.egl_dpy, MAIN.BestFBC, EGL_NATIVE_VISUAL_ID, &vid)) { printf("Error: eglGetConfigAttrib() failed\n"); exit(1); } visTemplate.visualid = vid; visInfo = XGetVisualInfo(MAIN.dpy, VisualIDMask, &visTemplate, &num_visuals); if (!visInfo) { printf("Error: couldn't get X visual\n"); exit(1); } MAIN.xvi=visInfo; root = DefaultRootWindow(MAIN.dpy); if ((MAIN.cmap = XCreateColormap(MAIN.dpy, root, MAIN.xvi->visual, AllocNone)) == 0){ printf("\n\tcannot create colormap\n\n"); exit(1); } eglBindAPI(EGL_OPENGL_ES_API); EGLint ctx_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, MAIN.GLESMajor, EGL_CONTEXT_MINOR_VERSION, MAIN.GLESMinor, EGL_NONE }; MAIN.glc = eglCreateContext(MAIN.egl_dpy, MAIN.BestFBC, EGL_NO_CONTEXT, ctx_attribs); if (!MAIN.glc) { printf("Error: eglCreateContext failed\n"); exit(1); } eglMakeCurrent(MAIN.egl_dpy,EGL_NO_SURFACE,EGL_NO_SURFACE,MAIN.glc); #else int visual_attribs[] = { GLX_X_RENDERABLE , True, GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, GLX_RENDER_TYPE , GLX_RGBA_BIT, GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR, GLX_RED_SIZE , 8, GLX_GREEN_SIZE , 8, GLX_BLUE_SIZE , 8, GLX_ALPHA_SIZE , 8, GLX_DEPTH_SIZE , 24, //GLX_STENCIL_SIZE , 8, GLX_DOUBLEBUFFER , True, GLX_SAMPLE_BUFFERS , MAIN.BufferSamples?1:0, GLX_SAMPLES , MAIN.BufferSamples?MAIN.BufferSamples:0, None }; int fbcount = -1; GLXFBConfig* fbconfig = glXChooseFBConfig(MAIN.dpy, DefaultScreen(MAIN.dpy), visual_attribs, &fbcount ); logPrint("glXChooseFBConfig matched %d\n",fbcount); if (!fbcount){ printf("\n\tno matching visual\n\n"); exit(0); } MAIN.BestFBC = fbconfig[0]; int sample_buf,samples; glXGetFBConfigAttrib(MAIN.dpy, MAIN.BestFBC, GLX_SAMPLE_BUFFERS, &sample_buf); glXGetFBConfigAttrib(MAIN.dpy, MAIN.BestFBC, GLX_SAMPLES, &samples); logPrint(" Chosen framebuffer with: %s %d samples\n",sample_buf?"Multisample":"-",samples); MAIN.xvi=glXGetVisualFromFBConfig(MAIN.dpy, MAIN.BestFBC); free(fbconfig); root = DefaultRootWindow(MAIN.dpy); if ((MAIN.cmap = XCreateColormap(MAIN.dpy, root, MAIN.xvi->visual, AllocNone)) == 0){ printf("\n\tcannot create colormap\n\n"); exit(0); } swa.colormap = MAIN.cmap; root = DefaultRootWindow(MAIN.dpy); win = XCreateWindow(MAIN.dpy, root, 0, 0, 100, 100, 0, MAIN.xvi->depth, InputOutput, MAIN.xvi->visual, CWBackPixel | CWBorderPixel|CWColormap | CWEventMask, &swa); MAIN.win=win; int attribs[] = { GLX_CONTEXT_MAJOR_VERSION_ARB, MAIN.GLMajor, GLX_CONTEXT_MINOR_VERSION_ARB, MAIN.GLMinor, 0}; glXCreateContextAttribsF = (glXCreateContextAttribsARBProc) glXGetProcAddressARB( (const GLubyte *) "glXCreateContextAttribsARB" ); if ((MAIN.glc = glXCreateContextAttribsF(MAIN.dpy, MAIN.BestFBC, NULL, GL_TRUE, attribs)) == NULL){ printf("\n\tcannot create gl context\n\n"); exit(0); } glXSwapIntervalEXTF = (glXSwapIntervalEXTProc) glXGetProcAddressARB( (const GLubyte *) "glXSwapIntervalEXT" ); tnsContextMakeCurrent(MAIN.glc,win,0); int major,minor; glGetIntegerv(GL_MAJOR_VERSION, &major); glGetIntegerv(GL_MINOR_VERSION, &minor); logPrint(" OpenGL Version: %d.%d\n",major,minor); logPrint(" OpenGL Renderer: %s\n",glGetString(GL_RENDERER)); int err=0; if((err=glewInit())!=GLEW_OK){ printf("%d\n",err); printf("%s\n",glewGetErrorString(err)); }; #endif /* gles or glx */ glGenVertexArrays(1,&MAIN.TempVAO); tnsBindVertexArray(MAIN.TempVAO); la_SetCurrentGLContextDebug(); MAIN.MsgDelWindow = XInternAtom(MAIN.dpy, "WM_DELETE_WINDOW", 0); MAIN.bufid = XInternAtom(MAIN.dpy, "CLIPBOARD", False), MAIN.fmtid = XInternAtom(MAIN.dpy, "UTF8_STRING", False), MAIN.propid = XInternAtom(MAIN.dpy, "XSEL_DATA", False), MAIN.incrid = XInternAtom(MAIN.dpy, "INCR", False); MAIN.targets_atom = XInternAtom(MAIN.dpy, "TARGETS",0); MAIN.text_atom = XInternAtom(MAIN.dpy, "TEXT", 0); MAIN.UTF8 = XInternAtom(MAIN.dpy, "UTF8_STRING", 1); MAIN.selection = XInternAtom(MAIN.dpy, "CLIPBOARD", 0); if(MAIN.UTF8 == None) MAIN.UTF8 = XA_STRING; MAIN.wmstate=XInternAtom(MAIN.dpy,"_NET_WM_STATE",1); MAIN.wmfullscr=XInternAtom(MAIN.dpy,"_NET_WM_STATE_FULLSCREEN",0); MAIN.wmfullscroff=XInternAtom(MAIN.dpy,"_NET_WM_STATE_FULLSCREEN",0); #endif //linux #ifdef _WIN32 logPrintNew("Initializing LaGUI...\n"); SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); setlocale(LC_ALL, "zh_CN.utf8"); MAIN.hinstance = GetModuleHandle(NULL); HINSTANCE* hInst = &MAIN.hinstance; WNDCLASSEXW wt; wt.cbSize = sizeof(WNDCLASSEXW); wt.cbClsExtra = 0; wt.cbWndExtra = 0; wt.hbrBackground = 0; wt.hCursor = LoadCursor(0, IDC_ARROW); wt.hIcon = LoadIcon(*hInst, IDI_WINLOGO); wt.hIconSm = LoadIcon(*hInst, IDI_WINLOGO); wt.hInstance = *hInst; wt.lpfnWndProc = LA_WindowProc; wt.lpszClassName = LA_GUI_WNDCLASS_NAME; wt.lpszMenuName = 0; wt.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; if (!RegisterClassExW(&wt)) return 0; MAIN.GLMajor=MAIN.InitArgs.GLMajor; MAIN.GLMinor=MAIN.InitArgs.GLMinor; MAIN.BufferSamples=MAIN.InitArgs.BufferSamples; logPrint("Chosen OpenGL version %d.%d\n", MAIN.GLMajor, MAIN.GLMinor); SetProcessDPIAware(); GLenum err; PIXELFORMATDESCRIPTOR pfd; HINSTANCE* hinst = &MAIN.hinstance; HWND hwnd = CreateWindowExW(WS_EX_ACCEPTFILES, LA_GUI_WNDCLASS_NAME, "Temp Window For Accessing GLEW!", WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 100, 100, 0, 0, *hinst, 0); HDC hdc = GetDC(hwnd); HGLRC hglrc = 0; SetPixelFormat(hdc, 1, &cpfd); hglrc = wglCreateContext(hdc); tnsContextMakeCurrent(hglrc, hdc,0); //MAIN.hdc = hdc; // MAIN.tWND = hwnd; MAIN.glc = hglrc; int major, minor; glGetIntegerv(GL_MAJOR_VERSION, &major); glGetIntegerv(GL_MINOR_VERSION, &minor); logPrint(" OpenGL Version: %d.%d\n", major, minor); logPrint(" OpenGL Renderer: %s\n", glGetString(GL_RENDERER)); if (err = glewInit()) { printf("Init Glew Failed\n"); printf("glewGetErrorString: %s\n", glewGetErrorString(err)); return 0; } logPrint("Trying to load WinTab for stylus input...\n"); int WtAvailable=1; if (!LoadWintab()){ logPrint("WinTab not available.\n"); WtAvailable=0; } elif (!gpWTInfoA(0, 0, NULL)){ logPrint("WinTab service is not available. (gpWTInfoA() returns 0).\n"); WtAvailable=0; } if (WtAvailable){ MAIN.WinTabAvailable=1; logPrint("WinTab service is available.\n"); } #endif la_GetWorkingDirectoryInternal(); MAIN.SavePreferenceOnExit=1; MAIN.FontSize = 0.6; int dpi=64; #ifdef _WIN32 dpi=la_GetDPI(hwnd); #endif #ifdef LA_LINUX dpi = la_GetDPI(DefaultRootWindow(MAIN.dpy)); #endif #ifdef LAGUI_ANDROID dpi = 144; #endif if((!dpi) || dpi<144){ dpi=144; } if(dpi>300){ dpi=300; } int UiSize=(int)(tnsLinearItp(16.0f,24.0f,tnsGetRatiod(96,144,dpi))+0.5); MAIN.UiRowHeight = MAIN.ScaledUiRowHeight =UiSize; MAIN.UiScale=1; MAIN.MarginSize = 1; MAIN.ColorPickerGamma=1.5; MAIN.EnableColorManagement=MAIN.InitArgs.UseColorManagement; MAIN.ViewportHalftoneFactor=0.5; MAIN.ViewportHalftoneSize=3.7; tnsInitRenderKernel(64); tnsInitBuiltinShaders(); tnsSetuptnsFontManager(); #define LOAD_FONT(font) \ if(!tnsLoadSystemFont(MAIN.SysFontDir, font)) printf("Can't load font \"" font "\"\n"); LOAD_FONT("NotoSansCJK-Regular.ttc"); LOAD_FONT("NotoEmoji-Regular.ttf"); LOAD_FONT("NotoSansSymbols-Regular.ttf"); LOAD_FONT("NotoSansSymbols2-Regular.ttf"); //LOAD_FONT("NotoMusic-Regular.ttf"); //LOAD_FONT("NotoSansEgyptianHieroglyphs-Regular.ttf); if(!tnsLoadSystemFontMono(MAIN.SysFontDir, "NotoSansMono-Regular.ttf")) logPrintNew("Can't load font \"NotoSansMono-Regular.ttf\"\n");; arrEnsureLength(&MAIN.InputBuf,0,&MAIN.InputBufMax,sizeof(char)); arrEnsureLength(&MAIN.InputBufU,0,&MAIN.InputBufUMax,sizeof(uint32_t)); arrEnsureLength(&MAIN.NodeTypes,0,&MAIN.NodeTypeMax,sizeof(laBaseNode*)); MAIN.InputMapping=memAcquire(sizeof(laInputMappingBundle)); MAIN.Animation=memAcquire(sizeof(laAnimation)); MAIN.Audio=memAcquire(sizeof(laAudio)); #ifdef LA_WITH_LUAJIT // starting lua logPrint("Starting luajit...\n"); MAIN.L = lua_open(); la_luaLoadLibs(MAIN.L); la_luaPrintStatus(MAIN.L); tnsLuaInit(MAIN.L); #endif //interactions: MAIN.TopFramerate = 60; MAIN.ValuatorThreshold = 8; MAIN.ScrollingSpeed = 3; MAIN.AnimationSpeed = 0.4; MAIN.PanelAnimationSpeed = 0.4; MAIN.ZoomSpeed2D = 0.01; MAIN.IdleTime = 0.75; MAIN.TooltipCloseDistance = 30; MAIN.InkOrWinTab = 1; /* Default use wacom wintab input. */ //display: MAIN.FloatingAlpha = 0.35; MAIN.SolidShadowLength = 20; MAIN.WireColorSlices = 16; MAIN.WireThickness = 5; MAIN.WireSaggyness = 0.5; #ifdef LAGUI_ANDROID laAddResourceFolder(""); #else laAddResourceFolder("."); #endif laSetMenuBarTemplates(laui_DefaultMenuButtons, laui_DefaultMenuExtras, "🧩LaGUI 2022"); laAddExtraExtension(LA_FILETYPE_UDF,"udf",0ll); la_InitProgressWindow(); la_MakeTranslations_es_ES(); la_MakeTranslations_zh_hans(); //tns_RegisterResourcesForSoftwareRender(); la_RegisterDefaultSignals(); la_RegisterGeneralProps(); la_RegisterBuiltinTemplates(); la_RegisterMainThemes(); la_RegisterMainOperators(); la_RegisterMainUiTypes(); la_RegisterModellingOperators(); la_RegisterShapeOperators(); la_RegisterInternalProps(); la_RegisterAnimationResources(); la_RegisterWindowKeys(); if(MAIN.InitArgs.HasAudio) laInitAudio(); laFinalizeUiTemplates(); laFinalizeOperators(); la_RegisterControllerProps(); la_RefreshControllers(); la_RegisterBasicNodes(); tns_RegisterNodes(); la_InitThreadEnviornment(); laSetRootInstance(&MAIN); if(!MAIN.DBInstMemLeft){ hsh65536Init(&MAIN.DBInstMemLeft); } laPushDifferences(0, 0); la_MakeDummyManagedUDF(); la_RegenerateWireColors(); laAnimationRegisterHolderPath("tns.world.root_objects_as_root"); if(MAIN.InitArgs.EnableLogStdOut){ MAIN.EnableLogStdOut=1; } logPrintNew("Initialization Completed\n"); MAIN.InitDone=1; return 1; } int laGetReady(){ laInitArguments ia={0}; laSetDefaultInitArguments(&ia); return laGetReadyWith(&ia); } void la_DestroyUiType(laUiType* uit); void la_FreeKeyMapItem(laKeyMapItem* kmi); void laShutoff(int SavePrefereces){ if(MAIN.SavePreferenceOnExit && SavePrefereces){ laSaveUserPreferences(); } //for(laPropContainer* pc=MAIN.PropContainers.pFirst;pc;pc=pc->Item.pNext){ // transLate(pc->Description); // for(laProp* p=pc->Props.pFirst;p;p=p->Item.pNext){ // transLate(p->Description); // } //} transDumpMissMatchRecord("TranslationDump.txt"); if(MAIN.Cleanup) MAIN.Cleanup(); if(MAIN.InitArgs.HasAudio) laDeinitAudio(); strSafeDestroy(&MAIN.WorkingDirectory); strSafeDestroy(&MAIN.example_string); la_NoLongerRecordUndo(); //XXX: it's not reliable yet, we need to only remove steps that are consistent with current data structure // (Must undo/redo to desired position or delete from back/front without moving target head. This can be done but this is of lower priority. ) laWindow* wi; while(wi=lstPopItem(&MAIN.Windows)){ la_DestroyWindow(wi); } laUiTemplate* uit; while(uit=lstPopItem(&MAIN.PanelTemplates)){ la_DestroyUiTemplate(uit); } laCanvasTemplate* u2t; while(u2t=lstPopItem(&MAIN.View2DTemplates)){ la_DestroyCanvasTemplate(u2t); } laUiType* uit1; while(uit1=lstPopItem(&MAIN.UiTypes)){ la_DestroyUiType(uit1); } laOperatorType* at; for(int i=0;i<256;i++){ while(at=lstPopItem(&MAIN.OperatorTypeHash.Entries[i])) la_DestroyOperatorType(at); } laSharedTypeItem* sti; while(sti=lstPopItem(&MAIN.SharedTypePointerSync)){ memFree(sti); } laKeyMapItem* kmi; while(kmi=lstPopItem(&MAIN.KeyMap.Items)){ la_FreeKeyMapItem(kmi); } laTheme* t; while(t=lstPopItem(&MAIN.Themes)){ la_DestroyTheme(t); } arrFree(&MAIN.InputBuf,&MAIN.InputBufNext); arrFree(&MAIN.InputBufU,&MAIN.InputBufUNext); strSafeDestroy(&MAIN.CopyPending); la_ClearUDFRegistryAndFolders(); laClearManagedUDF(); laClearSaveProp(); logClear(); tnsBindVertexArray(0); glDeleteVertexArrays(1,&MAIN.TempVAO); #ifdef LA_LINUX tnsContextMakeCurrent(0,0,0); tnsDeleteContext(MAIN.glc); #ifdef LA_USE_GLES eglTerminate(MAIN.egl_dpy); #endif #endif #ifdef _WIN32 tnsContextMakeCurrent(0,0,0); tnsDeleteContext(MAIN.glc); UnloadWintab(); #endif tnsQuit(); laPropContainer* pc; while(pc=lstPopItem(&MAIN.PropContainers)){ la_FreePropertyContainer(pc); } //laPanel* p; while(p=lstPopItem(&MAIN.WastedPanels)){ memFree(p); } strSafeDump(); hshFree(&MAIN.DBInstMemLeft); memNoLonger(); laSpinDestroy(&MAIN.MemLock); laSpinDestroy(&MAIN.OpsLock); #ifdef LA_WITH_LUAJIT lua_close(MAIN.L); #endif printf("LaGUI has cleaned up.\n"); } int laRestoreFactorySettings(){ char path[1024]; #ifdef LAGUI_ANDROID sprintf(path,"%s","preferences.udf"); #else sprintf(path,"%s%s",SSTR(MAIN.WorkingDirectory),"preferences.udf"); #endif if(remove(path)){ return 0; } return 1; } void laSaveUserPreferences(){ char path[1024]; #ifdef LAGUI_ANDROID sprintf(path,"%s","preferences.udf"); #else sprintf(path,"%s%s",SSTR(MAIN.WorkingDirectory),"preferences.udf"); #endif laUDF* udf=laPrepareUDF(path); laWriteProp(udf,"la.windows"); laWriteProp(udf,"la.user_preferences"); laWriteProp(udf,"la.input_mapping"); laWriteProp(udf,"la.controllers"); for(laListItemPointer* lip=MAIN.ExtraPreferencePaths.pFirst;lip;lip=lip->pNext){ laWriteProp(udf,lip->p); } laPackUDF(udf,0,0); } void laEnsureUserPreferences(){ char path[1024]; #ifdef LAGUI_ANDROID sprintf(path,"%s/%s",MAIN.InternalDataPath,"preferences.udf"); #else sprintf(path,"%s%s",SSTR(MAIN.WorkingDirectory),"preferences.udf"); #endif laUDFRegistry* r=laFindUDFRegistry(path); if(!r){ laSaveUserPreferences(); return; } laUDF* udf=laOpenUDF(SSTR(r->Path),1,0,0); if(!udf){ logPrint("Can't read preferences on %s. Using default settings.",SSTR(r->Path)); return; } laClearUDFRegistries(); while(MAIN.ResourceFolders.pFirst){ laRemoveResourceFolder(MAIN.ResourceFolders.pFirst); } while(MAIN.InputMapping->InputMappings.pFirst){ laRemoveInputMapping(MAIN.InputMapping->InputMappings.pFirst); } laExtractUDF(udf,0,LA_UDF_MODE_OVERWRITE); laCloseUDF(udf); la_RemoveDuplicatedScreenConf(); la_RemoveDuplicatedControllers(); laRefreshUDFRegistries(); //restore forced settings if(MAIN.InitArgs.EnableLogStdOut){ MAIN.EnableLogStdOut=1; } } void laAddExtraExtension(int FileType, ...){ va_list list; va_start(list,FileType); char* ext; while(ext=va_arg(list,char*)){ if(!ext) break; laExtensionType* et=memAcquireSimple(sizeof(laExtensionType)); et->FileType=FileType; et->Extension=ext; lstAppendItem(&MAIN.ExtraExtensions, et); logPrintNew("add ext %s",ext); } va_end(list); } void laAddExtraPreferencePath(const char* path){ if(!path) return; lstAppendPointer(&MAIN.ExtraPreferencePaths, path); } void laAddExtraPreferencePage(const char* name, laUiDefineFunc Func){ if(!name || !Func) return; laExtraPreferencePage*epp=memAcquireSimple(sizeof(laExtraPreferencePage)); epp->Name=name; epp->Func=Func; lstAppendItem(&MAIN.ExtraPreferencePages,epp); } void laSetMenuBarTemplates(laUiDefineFunc MenuButtons, laUiDefineFunc MenuExtras, const char* ProgramName){ MAIN.MenuButtons=MenuButtons; MAIN.MenuExtras=MenuExtras; MAIN.MenuProgramName=ProgramName; } void laSetAboutTemplates(laUiDefineFunc AboutContent, laUiDefineFunc AboutVersion, laUiDefineFunc AboutAuthor){ MAIN.AboutAuthor=AboutAuthor; MAIN.AboutVersion=AboutVersion; MAIN.AboutContent=AboutContent; } void laSetPreferenceTemplates(laUiDefineFunc PreferencePageDisplay, laUiDefineFunc PreferencePageInput, laUiDefineFunc PreferencePageResource, laUiDefineFunc PreferencePageTheme){ MAIN.PreferencePageDisplay=PreferencePageDisplay; MAIN.PreferencePageInput=PreferencePageInput; MAIN.PreferencePageResource=PreferencePageResource; MAIN.PreferencePageTheme=PreferencePageTheme; } void la_InputMappingGetKeyName(int key, int special, char* name){ char *_next=name; name[0]=0; if(special&LA_KEY_CTRL){ strcat(name,"Ctrl+"); } if(special&LA_KEY_SHIFT){ strcat(name,"Shift+"); } if(special&LA_KEY_ALT){ strcat(name,"Shift+"); } switch(key){ case ' ': strcat(name,"Space"); break; case LA_KEY_BACKSPACE: strcat(name,"Backspace"); break; case LA_KEY_ESCAPE: strcat(name,"Escape"); break; case LA_KEY_ENTER: strcat(name,"Enter"); break; case LA_KEY_ARRLEFT: strcat(name,"Left"); break; case LA_KEY_ARRRIGHT: strcat(name,"Right"); break; case LA_KEY_ARRUP: strcat(name,"Up"); break; case LA_KEY_ARRDOWN: strcat(name,"Down"); break; case LA_KEY_SHIFT: case LA_KEY_CTRL: case LA_KEY_ALT: break; case LA_KEY_DELETE: strcat(name,"Delete"); break; case LA_KEY_TAB: strcat(name,"Tab"); break; case LA_KEY_NUM1: strcat(name,"Num1"); break; case LA_KEY_NUM2: strcat(name,"Num2"); break; case LA_KEY_NUM3: strcat(name,"Num3"); break; case LA_KEY_NUM4: strcat(name,"Num4"); break; case LA_KEY_NUM5: strcat(name,"Num5"); break; case LA_KEY_NUM6: strcat(name,"Num6"); break; case LA_KEY_NUM7: strcat(name,"Num7"); break; case LA_KEY_NUM8: strcat(name,"Num8"); break; case LA_KEY_NUM9: strcat(name,"Num9"); break; case LA_KEY_NUM0: strcat(name,"Num0"); break; case LA_KEY_NUMPLUS: strcat(name,"NumPlus"); break; case LA_KEY_NUMMINUS: strcat(name,"NumMinus"); break; case LA_KEY_NUMMULT: strcat(name,"NumMult"); break; case LA_KEY_NUMDIVIDE: strcat(name,"NumDivide"); break; case LA_KEY_NUMDOT: strcat(name,"NumDot"); break; case LA_KEY_NUMENTER: strcat(name,"NumEnter"); break; case LA_KEY_F1: strcat(name,"F1"); break; case LA_KEY_F2: strcat(name,"F2"); break; case LA_KEY_F3: strcat(name,"F3"); break; case LA_KEY_F4: strcat(name,"F4"); break; case LA_KEY_F5: strcat(name,"F5"); break; case LA_KEY_F6: strcat(name,"F6"); break; case LA_KEY_F7: strcat(name,"F7"); break; case LA_KEY_F8: strcat(name,"F8"); break; case LA_KEY_F9: strcat(name,"F9"); break; case LA_KEY_F10: strcat(name,"F10"); break; case LA_KEY_F11: strcat(name,"F11"); break; case LA_KEY_F12: strcat(name,"F12"); break; default: name = name+strlen(name); _next=name; laToUTF8(key,name,&_next); *_next=0; break; } } int la_InputMappingGetKeyFromName(char* name, int* special){ if(!name ||name[0]==0){ *special=0; return 0; } *special=0; if(strstr(name,"Ctrl")) *special|=LA_KEY_CTRL; if(strstr(name,"Shift")) *special|=LA_KEY_SHIFT; if(strstr(name,"Alt")) *special|=LA_KEY_ALT; char* p=name+strlen(name)-1; while(*p!='+'){ p--; if(p<=name){p=name; break;} } while(*p=='+' || *p==' '){ p++; } if(strSame(p,"Space")) return ' '; if(strSame(p,"Backspace")) return LA_KEY_BACKSPACE; if(strSame(p,"Escape")) return LA_KEY_ESCAPE; if(strSame(p,"Enter")) return LA_KEY_ENTER; if(strSame(p,"Left")) return LA_KEY_ARRLEFT; if(strSame(p,"Right")) return LA_KEY_ARRRIGHT; if(strSame(p,"Up")) return LA_KEY_ARRUP; if(strSame(p,"Down")) return LA_KEY_ARRDOWN; if(strSame(p,"Delete")) return LA_KEY_DELETE; if(strSame(p,"Tab")) return LA_KEY_TAB; if(strSame(p,"Num1")) return LA_KEY_NUM1; if(strSame(p,"Num2")) return LA_KEY_NUM2; if(strSame(p,"Num3")) return LA_KEY_NUM3; if(strSame(p,"Num4")) return LA_KEY_NUM4; if(strSame(p,"Num5")) return LA_KEY_NUM5; if(strSame(p,"Num6")) return LA_KEY_NUM6; if(strSame(p,"Num7")) return LA_KEY_NUM7; if(strSame(p,"Num8")) return LA_KEY_NUM8; if(strSame(p,"Num9")) return LA_KEY_NUM9; if(strSame(p,"Num0")) return LA_KEY_NUM0; if(strSame(p,"NumPlus")) return LA_KEY_NUMPLUS; if(strSame(p,"NumMinus")) return LA_KEY_NUMMINUS; if(strSame(p,"NumMult")) return LA_KEY_NUMMULT; if(strSame(p,"NumDivide")) return LA_KEY_NUMDIVIDE; if(strSame(p,"NumDot")) return LA_KEY_NUMDOT; if(strSame(p,"NumEnter")) return LA_KEY_NUMENTER; if(strSame(p,"F1")) return LA_KEY_F1; if(strSame(p,"F2")) return LA_KEY_F2; if(strSame(p,"F3")) return LA_KEY_F3; if(strSame(p,"F4")) return LA_KEY_F4; if(strSame(p,"F5")) return LA_KEY_F5; if(strSame(p,"F6")) return LA_KEY_F6; if(strSame(p,"F7")) return LA_KEY_F7; if(strSame(p,"F8")) return LA_KEY_F8; if(strSame(p,"F9")) return LA_KEY_F9; if(strSame(p,"F10")) return LA_KEY_F10; if(strSame(p,"F11")) return LA_KEY_F11; if(strSame(p,"F12")) return LA_KEY_F12; int adv; return laToUnicode(p,&adv); } laCustomSignal* laFindSignal(char* Name){ for(laCustomSignal* cs=MAIN.CustomSignals.pFirst;cs;cs=cs->Item.pNext){ if(strSame(SSTR(cs->Name),Name)) return cs; } return 0; } laCustomSignal* laFindSignalByID(int ID){ for(laCustomSignal* cs=MAIN.CustomSignals.pFirst;cs;cs=cs->Item.pNext){ if(ID==cs->Signal) return cs; } return 0; } void laInputMappingUpdateSignal(laInputMappingEntry* ime){ if(ime->DeviceType == LA_INPUT_DEVICE_KEYBOARD){ char* str=SSTR(ime->Key); if(str&&str[0]){ int adv; ime->KeyValue=la_InputMappingGetKeyFromName(str,&ime->SpecialKeyBits); }else{ ime->KeyValue=0; } }elif(ime->DeviceType == LA_INPUT_DEVICE_JOYSTICK){ int key=0; sscanf(SSTR(ime->Key),"%d",&key); ime->KeyValue=key; } char* signal = SSTR(ime->Signal); laCustomSignal *cs=laFindSignal(signal); if(cs){ ime->SignalValue=cs->Signal; }else{ ime->SignalValue=0;} } laInputMapping* laNewInputMapping(char* Name){ laInputMapping* im=memAcquireHyper(sizeof(laInputMapping)); lstAppendItem(&MAIN.InputMapping->InputMappings,im); memAssignRef(MAIN.InputMapping,&MAIN.InputMapping->CurrentInputMapping,im); strSafeSet(&im->Name,Name); return im; } laInputMappingEntry* laNewInputMappingEntry(laInputMapping* im, int DeviceType, int JoystickDevice, char* Key, int SpecialKeyBit, char* Signal){ laInputMappingEntry* e=memAcquire(sizeof(laInputMappingEntry)); lstAppendItem(&im->Entries,e); e->DeviceType = DeviceType; e->JoystickDevice=JoystickDevice; e->SpecialKeyBits=SpecialKeyBit; memAssignRef(e,&e->Parent,im); if(Signal){ strSafeSet(&e->Signal,Signal); } if(Key){ strSafeSet(&e->Key,Key); } laInputMappingUpdateSignal(e); e->SpecialKeyBits=SpecialKeyBit; char buf[64],*_next=buf; la_InputMappingGetKeyName(e->KeyValue,e->SpecialKeyBits,buf); strSafeSet(&e->Key,buf); } laInputMappingEntry* laNewInputMappingEntryP(laInputMapping* im, int DeviceType, int JoystickDevice, char* Key, int SpecialKeyBit, int Signal){ laCustomSignal* cs; if(!(cs=laFindSignalByID(Signal))) return 0; laNewInputMappingEntry(im,DeviceType,JoystickDevice,Key,SpecialKeyBit,SSTR(cs->Name)); } void laRemoveInputMappingEntry(laInputMapping* im, laInputMappingEntry* e){ memAssignRef(e,&e->Parent,0); lstRemoveItem(&im->Entries,e); strSafeDestroy(&e->Signal); strSafeDestroy(&e->Key); memFree(e); } void laRemoveInputMapping(laInputMapping* im){ laInputMappingEntry* e; while(e=im->Entries.pFirst){ laRemoveInputMappingEntry(im,e); } laInputMapping* use=im->Item.pNext?im->Item.pNext:im->Item.pPrev; memAssignRef(MAIN.InputMapping,&MAIN.InputMapping->CurrentInputMapping,use); lstRemoveItem(&MAIN.InputMapping->InputMappings,im); strSafeDestroy(&im->Name); memFree(im); } laCustomSignal* laNewCustomSignal(char* Name, int Signal){ laCustomSignal* cs=memAcquire(sizeof(laCustomSignal)); lstAppendItem(&MAIN.CustomSignals,cs); strSafeSet(&cs->Name,Name); cs->Signal = Signal; return cs; } void laRemoveCustomSignal(laCustomSignal* cs){ strSafeDestroy(&cs->Name); lstRemoveItem(&MAIN.CustomSignals,cs); memFree(cs); } void la_SendSignalEvent(SYSWINDOW* hwnd, int signal); void la_SendSignalsFromEvent(laEvent* e){ laInputMapping* im = MAIN.InputMapping->CurrentInputMapping; if(!im){return;} for(laInputMappingEntry* ime = im->Entries.pFirst;ime;ime=ime->Item.pNext){ if(e->type==LA_KEY_DOWN && ime->DeviceType == LA_INPUT_DEVICE_KEYBOARD){ if(e->key == ime->KeyValue && e->SpecialKeyBit == ime->SpecialKeyBits){ la_SendSignalEvent(e->window->win,ime->SignalValue); } } } } //MSG==================================================== int la_IsThisSysWindow(laWindow *wnd, SYSWINDOW hwnd){ if (wnd->win == hwnd) return 1; else return 0; }; void la_EnsurePanelSnapping(laPanel *p, int CW, int CH){ if (p->SL){ int s=p->SL<0?0:p->SL; if (p->TX != s) laRecalcPanel(p); p->TX = s; } if (p->SR){ int s=p->SR<0?0:p->SR; if (p->TW != CW - p->TX - s) laRecalcPanel(p); p->TW = CW - p->TX - s; } if (p->ST){ int s=p->ST<0?0:p->ST; if (p->TY != s) laRecalcPanel(p); p->TY = s; } if (p->SB){ int s=p->SB<0?0:p->SB; if (p->TH != CH - p->TY - s) laRecalcPanel(p); p->TH = CH - p->TY - s; } } void la_RecalcBlockRecursive(laBlock *b, int X, int Y, int W, int H){ laPanel *p = 0; b->X = X; b->Y = Y; b->W = W; b->H = H; if (b->B1){ int SplitWidth; if (b->Vertical){ SplitWidth = H * b->SplitRatio; la_RecalcBlockRecursive(b->B1, X, Y, W, SplitWidth); la_RecalcBlockRecursive(b->B2, X, Y + SplitWidth, W, H - SplitWidth); }else{ SplitWidth = W * b->SplitRatio; la_RecalcBlockRecursive(b->B1, X, Y, SplitWidth, H); la_RecalcBlockRecursive(b->B2, X + SplitWidth, Y, W - SplitWidth, H); } } //if (!b->CurrentPanel)b->CurrentPanel = b->Panels.pFirst; for(p=b->Panels.pFirst;p;p=p->Item.pNext){ p->TitleWidth = tnsStringGetWidth(transLate(p->Title->Ptr), 0, 0); } if (p = b->CurrentPanel){ int TitleGap=b->Folded?0:LA_RH; p->X = X + LA_SEAM_W; p->Y = Y + LA_SEAM_W + TitleGap; p->TX = X + LA_SEAM_W; p->TY = Y + LA_SEAM_W + TitleGap; p->TW = W - LA_SEAM_W*2; p->TH = H - LA_SEAM_W*2 - TitleGap; laRecalcPanel(p); } } void la_UpdateUiPlacement(laWindow *w){ laLayout *l; laPanel *p; int CW = w->CW; int CH = w->CH; laBoxedTheme* bt = _LA_THEME_FLOATING_PANEL; int MenuHeight=(bt->TM+bt->BM)*2+LA_RH; if(w->MaximizedUi && w->MaximizedUiPanel){ laRecalcPanel(w->MaximizedUiPanel); }elif(w->MaximizedBlock){ la_RecalcBlockRecursive(w->MaximizedBlock, -LA_SEAM_W, MenuHeight, CW+LA_SEAM_W*2, CH-MenuHeight+LA_SEAM_W); }else{ for (l = w->Layouts.pFirst; l; l = l->Item.pNext){ la_RecalcBlockRecursive(l->FirstBlock, -LA_SEAM_W, MenuHeight, CW+LA_SEAM_W*2, CH-MenuHeight+LA_SEAM_W); } } for (p = w->Panels.pFirst; p; p = p->Item.pNext){ if(p->IsMenuPanel){ p->TH=p->H=MenuHeight; } la_EnsurePanelSnapping(p, CW, CH); laRecalcPanel(p); } } void la_CommandResizeWindow(SYSWINDOW hwnd, int x, int y, int w, int h){ laWindow *window; #ifdef LAGUI_ANDROID window = MAIN.Windows.pFirst; if (!window) return; window->X=x;window->Y=y;window->W=w;window->H=h; window->CW=w;window->CH=h; la_UpdateUiPlacement(window); return; #endif window = lstFindItem(hwnd, la_IsThisSysWindow, &MAIN.Windows); if (!window) return; #ifdef _WIN32 RECT rcc; GetClientRect(window->win, &rcc); RECT rcw; GetWindowRect(window->win, &rcw); window->CW = rcc.right - rcc.left; window->CH = rcc.bottom - rcc.top; window->W = rcw.right - rcw.left; window->H = rcw.bottom - rcw.top; window->X = rcw.left; window->Y = rcw.top; if (MAIN.AutoSwitchColorSpace) { laScreen* s = laGetWindowScreen(window); if (s) { window->OutputColorSpace = s->ColorSpace; } } #endif #ifdef LA_LINUX XWindowAttributes attr; XGetWindowAttributes(MAIN.dpy, window->win, &attr); window->CW = w; window->CH = h; window->W = w; window->H = h; window->X = x; window->Y = y; if(MAIN.AutoSwitchColorSpace){ laScreen* s = laGetWindowScreen(window); if(s){ window->OutputColorSpace = s->ColorSpace; } } #endif la_UpdateUiPlacement(window); } int la_OnWindowDestroy(SYSWINDOW wnd){ laListHandle *hlst = &MAIN.Windows; laWindow *w = lstFindItem(wnd, la_IsThisSysWindow, hlst); if (!w) return 0; if (MAIN.Windows.pFirst==MAIN.Windows.pLast){ int empty=0; int mod=laRegisterModifications(1,1,&empty,0); if(mod || empty){ laInvoke(0, "LA_managed_save", 0,0,"on_exit=true;",0); return 0; } laShutoff(1); return 1; } laListHandle h={0};laLayout*l=0; while(l=lstPopItem(&w->Layouts)){ lstAppendItem(&h, l); } la_DestroyWindow(w); int done=0; for(laWindow* w=MAIN.Windows.pFirst;w;w=w->Item.pNext){ #ifdef LA_LINUX if(done) glXSwapIntervalEXTF(MAIN.dpy, w->win, 0); else { glXSwapIntervalEXTF(MAIN.dpy, w->win, 1); done = 1; } #endif while (l = lstPopItem(&h)) { lstAppendItem(&w->Layouts, l); } } return 0; } void la_MakeSpecialKeyBit(SYSWINDOW hwnd,laWindow*wnd,laEvent *e,int use_last_pos){ laListHandle *el = &wnd->EventList; laEvent* last_e=el->pLast; SYSWINDOW root_ret, win_ret; int rrx=0,rry=0,rx=e->x,ry=e->y,rmask=0; #ifdef LA_LINUX XQueryPointer(MAIN.dpy, wnd->win, &root_ret,&win_ret,&rrx,&rry,&rx,&ry,&rmask); e->SpecialKeyBit = ((rmask&ShiftMask)?LA_KEY_SHIFT:0)|((rmask&ControlMask)?LA_KEY_CTRL:0)|((rmask&Mod1Mask)?LA_KEY_ALT:0); #endif #ifdef _WIN32 e->SpecialKeyBit = ((GetKeyState(VK_SHIFT)&0x8000)?LA_KEY_SHIFT:0)|((GetKeyState(VK_CONTROL)&0x8000)?LA_KEY_CTRL:0)|((GetKeyState(VK_MENU)&0x8000)?LA_KEY_ALT:0); #endif } void laMappingRequestEval(); void la_SaveEvent(SYSWINDOW hwnd, laEvent *e, int use_last_pos){ laListHandle *wl = &MAIN.Windows; laWindow* wnd; #ifdef LAGUI_ANDROID wnd = MAIN.Windows.pFirst; #else wnd = lstFindItem(hwnd, la_IsThisSysWindow, wl); #endif if (!wnd){ memFree(e); return; } laListHandle *el = &wnd->EventList; la_MakeSpecialKeyBit(hwnd,wnd,e,use_last_pos); if(use_last_pos){ e->x=MAIN.evLastX; e->y=MAIN.evLastY; } e->window = wnd; e->Twist=MAIN.StylusTwist; e->HasTwist = MAIN.StylusHasTwist; e->Pressure=MAIN.IsPen?(MAIN.PointerIsEraser?MAIN.EraserPressure:MAIN.StylusPressure):0.5f; e->Orientation=MAIN.PointerIsEraser?MAIN.EraserOrientation:MAIN.StylusOrientation; e->Deviation=MAIN.PointerIsEraser?MAIN.EraserDeviation:MAIN.StylusDeviation; e->IsEraser=MAIN.PointerIsEraser; e->Hover=MAIN.StylusHover; e->GoodPressure=MAIN.IsPen; lstAppendItem(el, (laListItem *)e); laMappingRequestEval(); }; void la_SendKeyboardEvent(SYSWINDOW hwnd, int type, int key){ laEvent *e = memAcquireSimple(sizeof(laEvent)); e->type = type; e->key = tolowerGuarded(key); la_SaveEvent(hwnd, e, 1); }; void la_SendInputEvent(SYSWINDOW hwnd, uint32_t Input){ laEvent *e = memAcquireSimple(sizeof(laEvent)); e->type = LA_INPUT; e->Input=Input; la_SaveEvent(hwnd, e, 1); } void la_SendEmptyEvent(SYSWINDOW hwnd){ laEvent *e = memAcquireSimple(sizeof(laEvent)); e->type = LA_EMPTY; la_SaveEvent(hwnd, e, 1); } void laSendOperatorTriggerEvent(){ if (MAIN.ReTriggerOperators) la_SendEmptyEvent(MAIN.CurrentWindow->win); MAIN.ReTriggerOperators = 0; } int la_TranslateSpecialKey(int keysym){ #ifdef LA_LINUX switch(keysym){ case XK_Return: return LA_KEY_ENTER; case XK_BackSpace: return LA_KEY_BACKSPACE; case XK_Delete: return LA_KEY_DELETE; case XK_Escape: return LA_KEY_ESCAPE; case XK_Tab: return LA_KEY_TAB; case XK_Left: return LA_KEY_ARRLEFT; case XK_Right: return LA_KEY_ARRRIGHT; case XK_Up: return LA_KEY_ARRUP; case XK_Down: return LA_KEY_ARRDOWN; case XK_Control_L: return LA_KEY_CTRL; case XK_Control_R: return LA_KEY_CTRL; case XK_Shift_L: return LA_KEY_SHIFT; case XK_Shift_R: return LA_KEY_SHIFT; case XK_Alt_L: return LA_KEY_ALT; case XK_Alt_R: return LA_KEY_ALT; case XK_KP_1: return LA_KEY_NUM1; case XK_KP_2: return LA_KEY_NUM2; case XK_KP_3: return LA_KEY_NUM3; case XK_KP_4: return LA_KEY_NUM4; case XK_KP_5: return LA_KEY_NUM5; case XK_KP_6: return LA_KEY_NUM6; case XK_KP_7: return LA_KEY_NUM7; case XK_KP_8: return LA_KEY_NUM8; case XK_KP_9: return LA_KEY_NUM9; case XK_KP_0: return LA_KEY_NUM0; case XK_KP_Add: return LA_KEY_NUMPLUS; case XK_KP_Subtract: return LA_KEY_NUMMINUS; case XK_KP_Divide: return LA_KEY_NUMDIVIDE; case XK_KP_Multiply: return LA_KEY_NUMMULT; case XK_KP_Decimal: return LA_KEY_NUMDOT; case XK_KP_Enter: return LA_KEY_NUMENTER; default: return keysym; } #endif #ifdef _WIN32 switch (keysym) { case VK_RETURN: return LA_KEY_ENTER; case VK_ESCAPE: return LA_KEY_ESCAPE; case VK_TAB: return LA_KEY_TAB; case VK_LEFT: return LA_KEY_ARRLEFT; case VK_RIGHT: return LA_KEY_ARRRIGHT; case VK_UP: return LA_KEY_ARRUP; case VK_DOWN: return LA_KEY_ARRDOWN; case VK_CONTROL: return LA_KEY_CTRL; case VK_SHIFT: return LA_KEY_SHIFT; case VK_MENU: return LA_KEY_ALT; case VK_F1: return LA_KEY_F1; case VK_F2: return LA_KEY_F2; case VK_F3: return LA_KEY_F3; case VK_F4: return LA_KEY_F4; case VK_F5: return LA_KEY_F5; case VK_F6: return LA_KEY_F6; case VK_F7: return LA_KEY_F7; case VK_F8: return LA_KEY_F8; case VK_F9: return LA_KEY_F9; case VK_F10: return LA_KEY_F10; case VK_F11: return LA_KEY_F11; case VK_F12: return LA_KEY_F12; case VK_NUMPAD0: return LA_KEY_NUM0; case VK_NUMPAD1: return LA_KEY_NUM1; case VK_NUMPAD2: return LA_KEY_NUM2; case VK_NUMPAD3: return LA_KEY_NUM3; case VK_NUMPAD4: return LA_KEY_NUM4; case VK_NUMPAD5: return LA_KEY_NUM5; case VK_NUMPAD6: return LA_KEY_NUM6; case VK_NUMPAD7: return LA_KEY_NUM7; case VK_NUMPAD8: return LA_KEY_NUM8; case VK_NUMPAD9: return LA_KEY_NUM9; case VK_MULTIPLY: return LA_KEY_NUMMULT; case VK_DIVIDE: return LA_KEY_NUMDIVIDE; case VK_ADD: return LA_KEY_NUMPLUS; case VK_SUBTRACT: return LA_KEY_NUMMINUS; case VK_DECIMAL: return LA_KEY_NUMDOT; case VK_OEM_1: return ';'; case VK_OEM_2: return '/'; case VK_OEM_3: return '`'; case VK_OEM_4: return '['; case VK_OEM_5: return '\\'; case VK_OEM_6: return ']'; case VK_OEM_7: return '\''; case VK_OEM_COMMA: return ','; case VK_OEM_PERIOD: return '.'; case VK_OEM_PLUS: return '+'; case VK_OEM_MINUS: return '-'; default: return keysym; } #endif } void la_SendMouseEvent(SYSWINDOW hwnd, int type, int x, int y){ //if((type&LA_STATE_DOWN)&&(x!=MAIN.evLastX || y!=MAIN.evLastY)){ // laEvent *e = memAcquireSimple(sizeof(laEvent)); // e->Type = LA_MOUSEMOVE; e->x = x; e->y = y; // la_SaveEvent(hwnd, e, 0); //} laEvent *e = memAcquireSimple(sizeof(laEvent)); e->type = type; e->x = x; e->y = y; la_SaveEvent(hwnd, e, 0); MAIN.evLastX=x; MAIN.evLastY=y; }; void la_SendTimerEvent(SYSWINDOW hwnd, int type){ laEvent *e = memAcquireSimple(sizeof(laEvent)); e->type = type; la_SaveEvent(hwnd, e, 1); }; void la_SendSignalEvent(SYSWINDOW* hwnd, int signal){ laEvent *e = memAcquireSimple(sizeof(laEvent)); e->type = LA_SIGNAL_EVENT; e->key = signal; la_SaveEvent(hwnd, e, 1); }; void laRetriggerOperators(){ MAIN.ReTriggerOperators = 1; } void laSetFrameCallbacks(laPreFrameF PreFrame, laPreDrawF PreDraw, laPostFrameF PostFrame){ MAIN.PreFrame=PreFrame; MAIN.PreDraw=PreDraw; MAIN.PostFrame=PostFrame; } void laSetCleanupCallback(laCleanupF Cleanup){ MAIN.Cleanup=Cleanup; } void laSetInputProcessCallback(laInputProcessF InputProcess){ MAIN.InputProcess=InputProcess; } //==================================================================================================== void la_DestroyTheme(laTheme* t){ laBoxedTheme*bt; while(bt=lstPopItem(&t->BoxedThemes)){ strSafeDestroy(&bt->Name); *bt->BackRef=0; memFree(bt); } strSafeDestroy(&t->Name); strSafeDestroy(&t->Author); } laTheme *laDesignTheme(const char *Name, const char *AuthorName){ laTheme *t = memAcquireHyper(sizeof(laTheme)); strSafeSet(&t->Name, Name); strSafeSet(&t->Author, AuthorName); lstAppendItem(&MAIN.Themes, t); MAIN.CurrentTheme = t; return t; } laBoxedTheme *laDesignBoxedTheme(laTheme *t, const char *Name, laBoxedTheme** BackRef, real NormalY,real ActiveY,real BorderY,real TextY,real TextActiveY, real Alpha, real LeftMargin, real RightMargin, real TopMargin, real BottomMargin, real LeftPadding, real RightPadding, real TopPadding, real BottomPadding){ laBoxedTheme *bt = memAcquire(sizeof(laBoxedTheme)); strSafeSet(&bt->Name, Name); bt->NormalY=NormalY; bt->ActiveY=ActiveY; bt->BorderY=BorderY; bt->TextY=TextY; bt->TextActiveY=TextActiveY; bt->Alpha = Alpha; bt->Margins[0] = LeftMargin; bt->Margins[1] = RightMargin; bt->Margins[2] = TopMargin; bt->Margins[3] = BottomMargin; bt->Paddings[0] = LeftPadding; bt->Paddings[1] = RightPadding; bt->Paddings[2] = TopPadding; bt->Paddings[3] = BottomPadding; bt->BackRef = BackRef; lstAppendItem(&t->BoxedThemes, bt); return bt; } laTheme *laGetTheme(const char *ThemeName){ laTheme *t = MAIN.Themes.pFirst; for (t; t; t = t->Item.pNext){ if (strSame(t->Name->Ptr, ThemeName)) return t; } return 0; } laBoxedTheme *laGetBoxedTheme(const char *ThemeName, const char *BoxName){ laTheme *t = MAIN.Themes.pFirst; for (t; t; t = t->Item.pNext){ laBoxedTheme *bt; if (!strSame(t->Name->Ptr, ThemeName)) continue; bt = t->BoxedThemes.pFirst; for (bt; bt; bt = bt->Item.pNext){ if (strSame(bt->Name->Ptr, BoxName)) return bt; } } return 0; } real* laThemeColor(laBoxedTheme* bt, int which){ switch(which){ default: case LA_BT_NORMAL: return bt->Normal; case LA_UI_EDITING: case LA_BT_ACTIVE: return bt->Active; case LA_BT_BORDER: return bt->Border; case LA_BT_TEXT: return bt->Text; break; case LA_BT_TEXT_ACTIVE: return bt->TextActive; break; case LA_BT_DISABLED: return bt->Inactive; break; case LA_BT_DISABLED|LA_BT_TEXT: return bt->TextInactive; break; } return bt->Normal; } real* laAccentColor(int which){ switch(which){ default: case LA_BT_NORMAL: case LA_UI_EDITING: case LA_BT_ACTIVE: return MAIN.CurrentTheme->SelectionColor; case LA_BT_WARNING: return MAIN.CurrentTheme->WarningColor; case LA_BT_BORDER: case LA_BT_TEXT: case LA_BT_TEXT_ACTIVE: return MAIN.CurrentTheme->CursorColor; case LA_BT_VERTEX: return MAIN.CurrentTheme->VertexColor; case LA_BT_FACE: case LA_BT_EDGE: return MAIN.CurrentTheme->EdgeColor; case LA_BT_SVERTEX: return MAIN.CurrentTheme->SVertexColor; case LA_BT_SEDGE: return MAIN.CurrentTheme->SEdgeColor; case LA_BT_SFACE: return MAIN.CurrentTheme->SFaceColor; case LA_BT_SHADOW: return MAIN.CurrentTheme->ShadowColor; } return MAIN.CurrentTheme->SelectionColor; } void la_RefreshBoxedThemeColor(laBoxedTheme* bt){ real hcy[3]; tnsRGB2HCY(MAIN.CurrentTheme->Color,hcy); hcy[2]=bt->NormalY; tnsHCY2RGB(hcy, bt->Normal); bt->Normal[3]=bt->Alpha; hcy[2]=bt->ActiveY; tnsHCY2RGB(hcy, bt->Active); bt->Active[3]=bt->Alpha; hcy[2]=bt->BorderY; tnsHCY2RGB(hcy, bt->Border); bt->Border[3]=1; hcy[2]=bt->TextY; tnsHCY2RGB(hcy, bt->Text); bt->Text[3]=1; hcy[2]=bt->TextActiveY; tnsHCY2RGB(hcy, bt->TextActive); bt->TextActive[3]=1; int *tm=&bt->LM,*tp=&bt->LP; for(int i=0;i<4;i++){ tm[i]=(real)bt->Margins[i]*LA_RH*MAIN.MarginSize/10+0.5; tp[i]=(real)bt->Paddings[i]*LA_RH*MAIN.MarginSize/10+0.5; } } void la_RefreshThemeColorSelf(laTheme* th){ tnsVectorCopy3d(th->AccentColor, th->CursorColor); th->CursorColor[3]=th->CursorAlpha; tnsVectorCopy3d(th->AccentColor, th->SelectionColor);th->SelectionColor[3]=th->SelectionAlpha; th->WarningColor[3]=th->SelectionAlpha; real hcy[3], usehcy[3]; tnsRGB2HCY(th->Color,hcy); tnsVectorCopy3d(hcy,usehcy); usehcy[2]=th->VertexBrightness; tnsHCY2RGB(usehcy, th->VertexColor); th->VertexColor[3]=th->VertexTransparency; usehcy[2]=th->EdgeBrightness; tnsHCY2RGB(usehcy, th->EdgeColor); th->EdgeColor[3]=th->EdgeTransparency; tnsVectorCopy3d(th->AccentColor, th->SVertexColor); th->SVertexColor[3]=th->SelectedVertexTransparency; tnsVectorCopy3d(th->AccentColor, th->SEdgeColor); th->SEdgeColor[3]=th->SelectedEdgeTransparency; tnsVectorCopy3d(th->AccentColor, th->SFaceColor); th->SFaceColor[3]=th->SelectedFaceTransparency; tnsVectorCopy3d(th->Color, th->ShadowColor); th->ShadowColor[3]=th->CursorAlpha; } void la_RefreshThemeColor(laTheme* th){ real hcy[3], usehcy[3], normalhcy[3]; tnsRGB2HCY(th->Color,hcy); la_RefreshThemeColorSelf(th); for(laBoxedTheme* bt = th->BoxedThemes.pFirst;bt;bt=bt->Item.pNext){ la_RefreshBoxedThemeColor(bt); (*bt->BackRef) = bt; tnsRGB2HCY(bt->Text, usehcy); usehcy[1]*=th->InactiveSaturation; tnsHCY2RGB(usehcy, bt->TextInactive); bt->TextInactive[3]=th->InactiveMix; tnsRGB2HCY(bt->Normal, normalhcy); normalhcy[1]*=th->InactiveSaturation; tnsHCY2RGB(normalhcy, bt->Inactive); bt->Inactive[3]=bt->Alpha*th->InactiveMix; } } //I FUCKING HATE THIS STUPID FUNCTION int la_SetUpUiListMatrix(laUiListDraw *uild, laUiList *Target, int _L, int _R, int LimH, int PanelH, int GlobalX, int GlobalY){ laUiListDrawItem *uildi = memAcquireSimple(sizeof(laUiListDrawItem)); laUiListDrawItem *last = uild->Items.pFirst; int LimW=_R-_L; int SL, SR, SU, SB; int Target__B = Target->B; int Target__R = Target->R; uildi->Target = Target; //if (Target__B - Target->U > LimH) Target__B = Target->U + LimH; if (Target__R - Target->L > LimW) Target__R = Target->L + LimW; uildi->XP = last ? last->XP + Target->PanX : Target->PanX; uildi->YP = last ? last->YP + Target->PanY : Target->PanY; uildi->L = last ? Target->L - last->XP : Target->L; uildi->R = last ? Target__R - last->XP : Target__R; uildi->U = last ? Target->U - last->YP : Target->U; uildi->B = last ? Target__B - last->YP : Target__B; if (uildi->B - uildi->U > LimH) uildi->B = Target->U + LimH; uildi->L -= GlobalX; uildi->R -= GlobalX; uildi->U -= GlobalY; uildi->B -= GlobalY; SL = last ? (uildi->L < last->L ? last->L : uildi->L) : uildi->L; SR = last ? (uildi->R > last->R ? last->R : uildi->R) : uildi->R; SU = last ? (uildi->U < last->U ? last->U : uildi->U) : uildi->U; SB = last ? (uildi->B > last->B ? last->B : uildi->B) : uildi->B; uildi->DifX = SL - uildi->L; uildi->DifY = SU - uildi->U; uildi->L = SL; uildi->R = SR+uildi->DifX; uildi->U = SU; uildi->B = SB;//+uildi->DifY; if(uildi->R>_R){ uildi->R=_R; } if(uildi->B-SU>LimH){ uildi->B=SU+LimH; } //printf("py %f %d lb %d b %d limh %d sb%d\n",Target->PanY,uildi->U,last?last->B:0,uildi->B,LimH,SB); if(uildi->R - uildi->L<=0 || uildi->B - uildi->U<=0){ memFree(uildi); return 0; } tnsViewportWithScissor(uildi->L-1, PanelH - uildi->B, uildi->R - uildi->L+1, uildi->B - uildi->U-1); tnsOrtho(Target->L + Target->PanX + uildi->DifX-1, Target->L + Target->PanX + uildi->DifX+1+ (uildi->R - uildi->L), Target->U + Target->PanY + uildi->DifY+ (uildi->B - uildi->U), Target->U + Target->PanY + uildi->DifY+1, -100, 100); lstPushItem(&uild->Items, uildi); return 1; } void la_SetUpUiListMatrixInLine(laUiListDraw *uild, int L, int R, int U, int B, int PanX, int PanY, int LimH, int PanelH){ laUiListDrawItem *uildi = memAcquireSimple(sizeof(laUiListDrawItem)); laUiListDrawItem *last = uild->Items.pFirst; int SL, SR, SU, SB; if (B - U > LimH) B = U + LimH; uildi->XP = last ? last->XP + PanX : PanX; uildi->YP = last ? last->YP + PanY : PanY; uildi->L = last ? L - last->XP : L; uildi->R = last ? R - last->XP : R; uildi->U = last ? U - last->YP : U; uildi->B = last ? B - last->YP : B; SL = last ? (uildi->L < last->L ? last->L : uildi->L) : uildi->L; SR = last ? (uildi->R > last->R ? last->R : uildi->R) : uildi->R; SU = last ? (uildi->U < last->U ? last->U : uildi->U) : uildi->U; SB = last ? (uildi->B > last->B ? last->B : uildi->B) : uildi->B; uildi->DifX = SL - uildi->L; uildi->DifY = SU - uildi->U; uildi->L = SL; uildi->R = SR; uildi->U = SU; uildi->B = SB; tnsViewportWithScissor(uildi->L, PanelH - uildi->B, uildi->R - uildi->L, uildi->B - uildi->U); tnsOrtho(L + PanX + uildi->DifX, L + PanX + uildi->DifX + (uildi->R - uildi->L), U + PanY + uildi->DifY + (uildi->B - uildi->U), U + PanY + uildi->DifY, -100, 100); lstPushItem(&uild->Items, uildi); } void la_DoUiScissor(laUiItem* ui, int* savex, int* savey, int* savew, int* saveh, int* savel, int* saver, int* saveu, int* saveb){ laPanel* panel=MAIN.PropMatcherContextP; int PW=panel->W, PH=panel->H; *savex=T->vsx;*savey=T->vsy;*savew=T->vsw;*saveh=T->vsh; *savel=T->vol;*saver=T->vor;*saveu=T->vou;*saveb=T->vob; real p[3]={0}, tp[3]={0}; tnsMatrix44d m; tnsGetMVPMatrix(m); real x,y,w,h; x=TNS_MAX2(ui->L,T->vsx); y=TNS_MAX2(PH-ui->B,T->vsy); w=TNS_MIN2(ui->R-ui->L,T->vsw); h=TNS_MIN2(ui->B-ui->U,T->vsh); tnsViewportWithScissor(x,y,w,h); tnsOrtho(ui->L,ui->R,ui->B,ui->U,-100,100); } void la_RebuildCurrentUiListMatrix(laUiListDraw *uild, laUiList *Target, int LimH, int PanelH){ laUiListDrawItem *uildi = uild->Items.pFirst; tnsViewportWithScissor(uildi->L-1, PanelH - uildi->B-1, uildi->R - uildi->L+2, uildi->B - uildi->U+2); tnsOrtho(Target->L + Target->PanX + uildi->DifX -1, Target->L + Target->PanX + uildi->DifX +1 + (uildi->R - uildi->L), Target->U + Target->PanY + uildi->DifY +1 + (uildi->B - uildi->U), Target->U + Target->PanY + uildi->DifY -1, -100, 100); } void la_RestoreLastUiListMatrix(laUiListDraw *uild, int PanelH){ laUiListDrawItem *uildi = lstPopItem(uild); laUiList *Target; memFree(uildi); uildi = uild->Items.pFirst; if (!uildi || !uildi->Target){ if (uild->Items.pFirst) la_RestoreLastUiListMatrix(uild, PanelH); return; } Target = uildi->Target; tnsViewportWithScissor(uildi->L-1, PanelH - uildi->B-1, uildi->R - uildi->L+2, uildi->B - uildi->U+2); tnsOrtho(Target->L + Target->PanX + uildi->DifX -1, Target->L + Target->PanX + uildi->DifX +1 + (uildi->R - uildi->L), Target->U + Target->PanY + uildi->DifY +1 + (uildi->B - uildi->U), Target->U + Target->PanY + uildi->DifY -1, -100, 100); } void la_SetupUiListLimitMatrix(laUiListDraw *uild, int L, int R, int U, int B, int PanelH){ laUiListDrawItem *uildi = memAcquireSimple(sizeof(laUiListDrawItem)); uildi->L = L; uildi->R = R; uildi->U = U; uildi->B = B; tnsViewportWithScissor(uildi->L, PanelH - uildi->B, uildi->R - uildi->L, uildi->B - uildi->U); tnsOrtho(L, R, B, U, -100, 100); lstPushItem(&uild->Items, uildi); } void la_ClearUiListMatrix(laUiListDraw *uild){ laUiListDrawItem *uildi; while (uildi = lstPopItem(uild)){ memFree(uildi); } } int la_UpdateUiListRecursive(laUiList *uil, int U, int L, int R, int B, int Fast, laPanel *ParentPanel); int la_DrawUiListRecursive(laUiListDraw *uild, laUiList *uil, int L, int R, int U, int B, int LimH, int ConditionStackLevel, int GlobalX, int GlobalY, int RegisterNodes); void la_DestroyUiList(laUiList *uil, int NoFree, int RemoveUsers, int OnlyRemoveUser); void la_DrawUiListScrollerV(laUiList *uil, int DisplayOffset, int TotalH, int DisplayH, int UiR); int la_TestUiListMinumWidth(laUiList *uil); void la_PanelValidateWidth(laPanel *p, laUiList *ui){ if (ui){ if (p->MaxW && p->TW > p->MaxW) p->TW = p->MaxW; if (p->MinW && p->TW < p->MinW) p->TW = p->MinW; la_EnsurePanelSnapping(p, MAIN.CurrentWindow->CW, MAIN.CurrentWindow->CH); p->X = p->TX; p->Y = p->TY; p->W = p->TW; } } void laEnsurePanelInBound(laPanel *p, laUiList *uil){ int cw = MAIN.CurrentWindow->CW; int ch = MAIN.CurrentWindow->CH; int PH = p->TH; laBoxedTheme*bt = *p->BT; int uih=uil->B + bt->BM; if (p->BoundUi && !(p->SB||p->ST)) PH = TNS_MAX2(uih, p->MinH); if (p->MaxH && PH > p->MaxH) p->TH = p->MaxH; else if (p->MinH && PH < p->MinH) p->TH = p->MinH; else p->TH = PH; p->H = p->TH; if(p->BoundUi){ if ((p->X + p->W) > cw) p->X -= (p->X + p->W - cw); if ((p->Y + p->H) > ch) p->Y -= (p->Y + p->H - ch); if (p->X < 0) p->X = 0; if (p->Y < 0) p->Y = 0; if ((p->X + p->W) > cw){ p->W -= (p->X + p->W - cw); } if ((p->Y + p->H) > ch){ p->H -= (p->Y + p->H - ch); } }else{ if (p->Y < 0) p->Y = 0; if ((!p->Block)&&(!p->IsMenuPanel)){ int cw2=cw-LA_RH*2,ch2=ch-LA_RH*2; if (p->X + p->W < LA_RH * 5) p->X = LA_RH * 5 - +p->W; if (p->X > cw2){ p->X = cw2; } if (p->Y > ch2){ p->Y = ch2; } if (p->W > cw2){ p->W = cw2; } if (p->H > ch2){ p->H = ch2; } } } if((!p->IsMenuPanel) && (p->Mode!=LA_PANEL_FLOATING_PASSIVE)){ if(p->WW=LA_RH*4; if(p->HH=LA_RH*2; } if (p->ST) p->TY = p->ST; if (p->SB && p->TH != ch - p->TY - p->SB) laRecalcPanel(p); if (p->SB) p->TH = ch - p->TY - p->SB; if(p->CloseWhenMovedOut==2){ p->X=(cw-p->W)/2; p->Y=(ch-p->H)/2; } p->TX = p->X; p->TY = p->Y; p->TW = p->W; p->TH = p->H; } void laPlacePanelForCreation(laPanel *p){ int cw = MAIN.CurrentWindow->CW; int ch = MAIN.CurrentWindow->CH; int PH = p->TH; if ((!p->Block)&&(!p->IsMenuPanel)&&(!p->Parent)){ if (p->X+p->W > cw-LA_RH){ p->X = cw-LA_RH-p->W; } if (p->Y+p->H > ch-LA_RH){ p->Y = ch-LA_RH-p->H; } if (p->X < LA_RH){ p->X = LA_RH; } if (p->Y < LA_RH){ p->Y = LA_RH; } p->TX=p->X; p->TY=p->Y; } } void la_SetPanelMatrix(laPanel *p, laBoxedTheme *bt){ tnsDrawToOffscreen(p->OffScr, 1, 0); tnsViewportWithScissor(0, 0, p->W, p->H); //tnsMatrixMode(TNS_PROJECTION_MATRIX); tnsOrtho(0, p->W, p->H, 0, -100, 100); } void la_SetPanelMatrixDrawWindow(laPanel *p, laBoxedTheme *bt){ tnsDrawToScreen(); tnsViewportWithScissor(p->X, MAIN.CurrentWindow->CH - p->H - p->Y, p->W, p->H); tnsOrtho(0, p->W, p->H, 0, -100, 100); } void la_SetPanelMatrixLRTB(int PW, int PH, int LPadding, int RPadding, int TPadding, int BPadding, int XOffset, int YOffset){ tnsViewportWithScissor(LPadding, BPadding, PW - LPadding - RPadding, PH - TPadding - BPadding); tnsOrtho(XOffset, XOffset + PW - LPadding - RPadding, YOffset + PH - BPadding, YOffset + TPadding, -100, 100); } void la_PanelBackgroundInit(laPanel *p, laBoxedTheme *bt){ glClearColor(LA_COLOR4(laThemeColor(bt,LA_BT_NORMAL))); tnsClearAll(); } void la_PanelDrawDescendBorder(laPanel* Panel, laBoxedTheme* bt, int Width, real Alpha); void la_PanelDrawToWindow(laPanel *p, laWindow *w){ real Color[] = {1, 1, 1, 1}; real L, W, U, H; tnsUseImmShader(); tnsEnableShaderv(T->immShader); if(MAIN.EnableColorManagement){ tnsUniformOutputColorSpace(T->immShader,w->OutputColorSpace); tnsUniformShowColorOverflowStripes(T->immShader,w->OutputShowStripes); tnsUniformColorComposing(T->immShader,w->UseComposing,w->ComposingGamma,w->ComposingBlackpoint); }else{ tnsUniformOutputColorSpace(T->immShader,0); tnsUniformShowColorOverflowStripes(T->immShader,0); tnsUniformColorComposing(T->immShader,0,0,0); } if (p->Mode && (!p->AnimationMode || (p->AnimationMode && p->AnimationRatio > 0.99) || p->AnimationMode==LA_PANEL_ANIMATION_FLASH)){ tnsUseNoTexture(); if (!p->IsMenuPanel){ la_PanelDrawDescendBorder(p, (*p->BT), MAIN.SolidShadowLength, MAIN.FloatingAlpha); } tnsFlush(); } if(p->ParentOperator){ tnsUseNoTexture(); tnsColor4d(LA_COLOR3(MAIN.CurrentTheme->Color),0.7*(p->AnimationMode==LA_PANEL_ANIMATION_FLASH?1.0f:p->AnimationRatio)); tnsVertex2d(0,0); tnsVertex2d(w->CW,0); tnsVertex2d(w->CW,w->CH); tnsVertex2d(0,w->CH); tnsPackAs(GL_TRIANGLE_FAN); tnsFlush(); } switch (p->AnimationMode){ case 0: /* and */ case LA_PANEL_ANIMATION_FLASH: tnsDraw2DTextureDirectly(p->OffScr->pColor[0], p->X, p->Y, p->W, p->H); if(!(p->SR || p->SB || p->Parent || p->Block || p->IsMenuPanel)){ real* color=laThemeColor(_LA_THEME_PANEL,LA_BT_TEXT); tnsColor4d(LA_COLOR3(color),color[3]*(p->ShowCorner?1:0.8)); int len=LA_RH/(p->ShowCorner?1:2); tnsUseNoTexture(); int px=p->X+p->W,py=p->Y+p->H; tnsVertex2d(px,py); tnsVertex2d(px-len,py); tnsVertex2d(px,py-len); tnsPackAs(GL_TRIANGLES); tnsColor4dv(laThemeColor(_LA_THEME_PANEL,LA_BT_NORMAL)); tnsVertex2d(px-len,py); tnsVertex2d(px,py-len); tnsLineWidth(2); tnsPackAs(GL_LINES); tnsLineWidth(1); } if(p->AnimationMode==LA_PANEL_ANIMATION_FLASH){ p->AnimationRatio += MAIN.PanelAnimationSpeed * 0.1 * MAIN.LastFrameTime * 60; if((int)(p->AnimationRatio*6)%2){ tnsUseNoTexture(); tnsColor4dv(laAccentColor(LA_BT_SELECTED)); tnsVertex2d(p->X,p->Y); tnsVertex2d(p->X+p->W,p->Y); tnsVertex2d(p->X+p->W,p->Y+p->H); tnsVertex2d(p->X,p->Y+p->H); tnsPackAs(GL_TRIANGLE_FAN); tnsFlush(); } if (p->AnimationRatio > 0.99) p->AnimationMode = 0; laRefreshWindow(); } break; case LA_PANEL_ANIMATION_DROP_DOWN: tnsVectorMultiSelf4d(Color, p->AnimationRatio); tnsDraw2DTextureArg( p->OffScr->pColor[0], p->X, p->Y, p->W, p->H * p->AnimationRatio, Color, 0, 0, 1 - p->AnimationRatio, 0); p->AnimationRatio += (1 - p->AnimationRatio) * MAIN.PanelAnimationSpeed * MAIN.LastFrameTime * 60; if (p->AnimationRatio > 0.99) p->AnimationMode = 0; laRefreshWindow(); break; case LA_PANEL_ANIMATION_EXPAND: L = tnsLinearItp(p->X, p->X + p->W, 0.3); U = tnsLinearItp(p->Y, p->Y + p->H, 0.3); W = tnsLinearItp(0, p->W, 0.4); H = tnsLinearItp(0, p->H, 0.4); tnsVectorMultiSelf4d(Color, p->AnimationRatio); tnsDraw2DTextureArg( p->OffScr->pColor[0], tnsLinearItp(L, p->X, p->AnimationRatio), tnsLinearItp(U, p->Y, p->AnimationRatio), tnsLinearItp(W, p->W, p->AnimationRatio), tnsLinearItp(H, p->H, p->AnimationRatio), Color, 0, 0, 0, 0); p->AnimationRatio += (1 - p->AnimationRatio) * MAIN.PanelAnimationSpeed * MAIN.LastFrameTime * 60; if (p->AnimationRatio > 0.99) p->AnimationMode = 0; laRefreshWindow(); break; case LA_PANEL_ANIMATION_DISSOVE: L = tnsLinearItp(p->X, p->X + p->W, -0.2); U = tnsLinearItp(p->Y, p->Y + p->H, -0.2); W = tnsLinearItp(0, p->W, 1.4); H = tnsLinearItp(0, p->H, 1.4); tnsVectorMultiSelf4d(Color, (p->AnimationRatio)); if (p->OffScr) tnsDraw2DTextureArg( p->OffScr->pColor[0], tnsLinearItp(L, p->X, p->AnimationRatio), tnsLinearItp(U, p->Y, p->AnimationRatio), tnsLinearItp(W, p->W, p->AnimationRatio), tnsLinearItp(H, p->H, p->AnimationRatio), Color, 0, 0, 0, 0); p->AnimationRatio -= (p->AnimationRatio) * MAIN.PanelAnimationSpeed * MAIN.LastFrameTime * 60; if (p->AnimationRatio < 0.01) p->AnimationMode = 0; laRefreshWindow(); break; case LA_PANEL_ANIMATION_COLLAPSE: L = tnsLinearItp(p->X, p->X + p->W, 0.3); U = tnsLinearItp(p->Y, p->Y + p->H, 0.3); W = tnsLinearItp(0, p->W, 0.4); H = tnsLinearItp(0, p->H, 0.4); tnsVectorMultiSelf4d(Color, p->AnimationRatio); if (p->OffScr) tnsDraw2DTextureArg( p->OffScr->pColor[0], tnsLinearItp(L, p->X, p->AnimationRatio), tnsLinearItp(U, p->Y, p->AnimationRatio), tnsLinearItp(W, p->W, p->AnimationRatio), tnsLinearItp(H, p->H, p->AnimationRatio), Color, 0, 0, 0, 0); p->AnimationRatio -= p->AnimationRatio * MAIN.PanelAnimationSpeed * MAIN.LastFrameTime * 60; if (p->AnimationRatio < 0.01) p->AnimationMode = 0; laRefreshWindow(); break; case LA_PANEL_ANIMATION_MINIMIZE: L = tnsLinearItp(0, p->X, 0.3); U = tnsLinearItp(w->H, p->Y + p->H, 0.3); W = tnsLinearItp(0, p->W, 0.4); H = tnsLinearItp(0, p->H, 0.4); tnsVectorMultiSelf4d(Color, p->AnimationRatio); tnsDraw2DTextureArg( p->OffScr->pColor[0], tnsLinearItp(L, p->X, p->AnimationRatio), tnsLinearItp(U, p->Y, p->AnimationRatio), tnsLinearItp(W, p->W, p->AnimationRatio), tnsLinearItp(H, p->H, p->AnimationRatio), Color, 0, 0, 0, 0); p->AnimationRatio -= p->AnimationRatio * MAIN.PanelAnimationSpeed * MAIN.LastFrameTime * 60; if (p->AnimationRatio < 0.01) p->AnimationMode = 0; laRefreshWindow(); break; } tnsFlush(); tnsUniformOutputColorSpace(T->immShader,0); tnsUniformShowColorOverflowStripes(T->immShader,0); tnsUniformColorComposing(T->immShader,0,0,0); } void la_PanelDrawToOffsceen(laPanel *p, laUiList *uil){ if (p->OffScr){ tnsEnsureOffscreenStatus(p->OffScr, p->W,p->H); } else{ int GLFormat=(p->PanelTemplate&&p->PanelTemplate->DefaultGLFormat)?p->PanelTemplate->DefaultGLFormat:LA_PANEL_DEFAULT_GL_FORMAT; p->OffScr = tnsCreate2DOffscreen(GLFormat, p->W, p->H, MAIN.PanelMultisample, 0,0); } tnsDrawToOffscreen(p->OffScr, 1, 0); } void la_PanelRefreshDetachedProp(laPanel *panel){ laProp *p; for (p = panel->PropLinkContainer->Props.pFirst; p; p = p->Item.pNext){ la_StepPropPack(&p->DetachedPP); la_UsePropPack(&p->DetachedPP, 0); //if (p->DetachedPP.LastPs && p->DetachedPP.LastPs->p->Container ? p->DetachedPP.LastPs->p->Container->Hyper : 0){ // laUseDataBlock( // p->DetachedPP.LastPs->UseInstance, // p->DetachedPP.LastPs->p, // MAIN.PropMatcherContextP->FrameDistinguish, // MAIN.PropMatcherContextP, // la_PropPanelUserRemover, 0); //} } } void la_PanelDrawDescendBorder(laPanel *Panel, laBoxedTheme *bt, int Width, real Alpha){ real* color=laThemeColor(bt,LA_BT_BORDER); tnsColor4d(0,0,0,Alpha); tnsVertex2d(Panel->X + Width, Panel->Y + Panel->H); tnsVertex2d(Panel->X + Width, Panel->Y + Panel->H + Width); tnsVertex2d(Panel->X + Panel->W, Panel->Y + Panel->H); tnsVertex2d(Panel->X + Panel->W + Width, Panel->Y + Panel->H + Width); tnsVertex2d(Panel->X + Panel->W, Panel->Y + Width); tnsVertex2d(Panel->X + Panel->W + Width, Panel->Y + Width); tnsPackAs(GL_TRIANGLE_STRIP); tnsColor4dv(laThemeColor(bt,LA_BT_BORDER)); tnsVertex2d(Panel->X-1, Panel->Y-1); tnsVertex2d(Panel->X-1, Panel->Y + Panel->H+1); tnsVertex2d(Panel->X+1 + Panel->W, Panel->Y + Panel->H+1); tnsVertex2d(Panel->X+1 + Panel->W, Panel->Y-1); tnsLineWidth(2.0); tnsPackAs(GL_LINE_LOOP); tnsLineWidth(1.0); } int la_AnimateUiListRecursive(laUiList *uil); void la_PanelDefDraw(laWindow *w, laPanel *p, laBoxedTheme *bt){ int DrawState_ = 0; laUiListDraw uild = {0}; int orig_refresh=p->Refresh; if (p->Show){ la_SetPropMathcerContext(p); MAIN.CurrentPanel = p; //if(p->Refresh&(LA_TAG_REDRAW|LA_TAG_RECALC)){ // printf("Draw %0xld (%s)\n", p, p->Title?p->Title->Ptr:0); //} if (p->Refresh & LA_TAG_RECALC){ laRecalcPanelImmediate(p); } if (!p->MenuRefer){ if(!p->OffScr){ la_PanelDrawToOffsceen(p,&p->UI); p->Refresh|=LA_TAG_REDRAW; laRefreshWindow(); } if (p->Refresh || !p->OffScr){ la_PanelDrawToOffsceen(p, &p->UI); la_SetupUiListLimitMatrix(&uild, 0, p->W, 0, p->H, p->H); la_PanelBackgroundInit(p, bt); int extrap=(p->Mode && (!p->IsMenuPanel))?p->TitleBar.B:0; la_DrawUiListScrollerV(&p->UI, p->UI.PanY, p->UI.B-p->UI.U, p->H-bt->BM-bt->TM-extrap, p->W); tnsFlush(); if(((p->UI.B>p->H) && (!p->UI.ScrollerShownV))|| ((p->UI.B<=p->H) && p->UI.ScrollerShownV)){ p->UI.ScrollerShownV=!p->UI.ScrollerShownV; DrawState_++; } if(p->UI.PanY && p->UI.B-p->UI.PanYH-bt->BM ){ p->UI.PanY = (p->UI.B-p->H/*-bt->BM-bt->TM*/-p->TitleBar.B); if(p->UI.PanY<0){p->UI.PanY=0;} DrawState_++; } if(p->Refresh&LA_TAG_RECALC_SCROLLER) DrawState_++; if (!la_AnimateUiListRecursive(&p->TitleBar)) p->Refresh = 0; else { p->Refresh = LA_TAG_ANIMATION; laRefreshWindow(); } if (!la_AnimateUiListRecursive(&p->UI)){ p->Refresh = p->Refresh; if(p->Refresh){ laRefreshWindow(); } } else { p->Refresh = LA_TAG_ANIMATION; laRefreshWindow(); } DrawState_ += la_DrawUiListRecursive(&uild, &p->TitleBar, 0, p->W, 0, p->H, 10000, -1, 0, 0, 0); if(p!=w->MaximizedUiPanel){ DrawState_ += la_DrawUiListRecursive(&uild, &p->UI, 0, p->W, 0, p->H, 10000, -1, 0, 0, 0); }else{ tnsViewportWithScissor(0,0,p->W,p->H); tnsOrtho(0,p->W,p->H,0,-100,100); tnsDrawStringAutoM("Canvas is maximized",0,laThemeColor(bt,LA_BT_TEXT), bt->LM,p->W-bt->RM,(p->H - p->TitleBar.B)/2+LA_RH2,LA_TEXT_ALIGN_CENTER|LA_TEXT_LINE_WRAP); tnsFlush(); } if (DrawState_){ p->Refresh = LA_TAG_RECALC; laRefreshWindow(); } } }else{ if (p->Refresh || !p->OffScr){ la_PanelDrawToOffsceen(p, p->MenuRefer); la_SetupUiListLimitMatrix(&uild, 0, p->W, 0, p->H, p->H); la_PanelBackgroundInit(p, bt); la_DrawUiListScrollerV(p->MenuRefer, p->MenuRefer->PanY, p->MenuRefer->B-p->MenuRefer->U-bt->TM-bt->BM, p->H-bt->TM-bt->BM*2, p->W); tnsFlush(); if(((p->MenuRefer->TB>p->H-bt->BP) && (!p->MenuRefer->ScrollerShownV))|| ((p->MenuRefer->TB<=p->H-bt->BP) && p->MenuRefer->ScrollerShownV)){ p->MenuRefer->ScrollerShownV=!p->MenuRefer->ScrollerShownV; DrawState_++; } if(p->UI.PanY && p->MenuRefer->B-p->MenuRefer->PanYH-bt->BM){ p->MenuRefer->PanY = (p->MenuRefer->B-p->H-bt->BM); if(p->MenuRefer->PanY<0){p->MenuRefer->PanY=0;} DrawState_++; } if(p->Refresh&LA_TAG_RECALC_SCROLLER) DrawState_++; if (!la_AnimateUiListRecursive(p->MenuRefer)) p->Refresh = 0; else { p->Refresh = LA_TAG_ANIMATION; laRefreshWindow(); } DrawState_ += la_DrawUiListRecursive(&uild, p->MenuRefer, 0, p->W, 0, p->H, 10000, -1, 0, 0, 0); if (DrawState_){ p->Refresh = LA_TAG_RECALC; laRefreshWindow(); } } } tnsDrawToScreen(); tnsViewportWithScissor(0, 0, w->CW, w->CH); tnsOrtho(0, w->CW, w->CH, 0, -100, 100); la_PanelDrawToWindow(p, w); }elif (p->AnimationMode){ la_PanelDrawToWindow(p, w); } laPerfRecord("%s [%s]",(orig_refresh&LA_TAG_RECALC)?"🌑": ((orig_refresh&LA_TAG_REDRAW)?"🌓": ((orig_refresh&LA_TAG_ANIMATION)?"🌔":"🌕")), SSTR(p->Title)); } void la_AttachedPanelDefDraw(laWindow* w, laPanel* p, laBoxedTheme* bt){ if(!p->Show && p!=w->MaximizedUiPanel) return; if (p->SubPanels.pLast && (p->LaterDestroy ? !p->AnimationMode : 1)){ laPanel *pi, *PrevPI; for (pi = p->SubPanels.pLast; pi; pi = PrevPI){ PrevPI = pi->Item.pPrev; if (pi->AnimationMode && pi->LaterDestroy){ lstRemoveItem(&p->SubPanels, pi); lstAppendItem(&MAIN.CurrentWindow->FadingPanels, pi); continue; } la_PanelDefDraw(w, pi, _LA_THEME_FLOATING_PANEL); la_AttachedPanelDefDraw(w,pi,bt); } } } void la_BlockDrawDropLocations(laBlock *b, int CH, real *BorderColor4dV, real *FillColor4dv){ real PanelSquare[] = { b->X + 2, CH - (b->Y + 2 + LA_RH), b->X + 2, CH - (b->Y + b->H - 4), b->X + b->W - 4, CH - (b->Y + b->H - 4), b->X + b->W - 4, CH - (b->Y + 2 + LA_RH)}; real Center[] = { tnsLinearItp(PanelSquare[0], PanelSquare[4], 0.5), tnsLinearItp(PanelSquare[1], PanelSquare[5], 0.5)}; real DraggingPlot[] = { tnsLinearItp(PanelSquare[0], Center[0], 0.5), tnsLinearItp(PanelSquare[1], Center[1], 0.5), PanelSquare[0], PanelSquare[1], tnsLinearItp(PanelSquare[2], Center[0], 0.5), tnsLinearItp(PanelSquare[3], Center[1], 0.5), PanelSquare[2], PanelSquare[3], tnsLinearItp(PanelSquare[4], Center[0], 0.5), tnsLinearItp(PanelSquare[5], Center[1], 0.5), PanelSquare[4], PanelSquare[5], tnsLinearItp(PanelSquare[6], Center[0], 0.5), tnsLinearItp(PanelSquare[7], Center[1], 0.5), PanelSquare[6], PanelSquare[7], }; real Square[] = { tnsLinearItp(PanelSquare[0], Center[0], 0.5), tnsLinearItp(PanelSquare[1], Center[1], 0.5), tnsLinearItp(PanelSquare[2], Center[0], 0.5), tnsLinearItp(PanelSquare[3], Center[1], 0.5), tnsLinearItp(PanelSquare[4], Center[0], 0.5), tnsLinearItp(PanelSquare[5], Center[1], 0.5), tnsLinearItp(PanelSquare[6], Center[0], 0.5), tnsLinearItp(PanelSquare[7], Center[1], 0.5), }; real PlotColor[] = {LA_COLOR3(BorderColor4dV), 0.8, LA_COLOR3(BorderColor4dV), 0, LA_COLOR3(BorderColor4dV), 0.8, LA_COLOR3(BorderColor4dV), 0, LA_COLOR3(BorderColor4dV), 0.8, LA_COLOR3(BorderColor4dV), 0, LA_COLOR3(BorderColor4dV), 0.8, LA_COLOR3(BorderColor4dV), 0, }; real FillColor[] = {LA_COLOR3(FillColor4dv), 0.8, LA_COLOR3(FillColor4dv), 0, LA_COLOR3(FillColor4dv), 0.8, LA_COLOR3(FillColor4dv), 0, LA_COLOR3(FillColor4dv), 0.8, LA_COLOR3(FillColor4dv), 0, LA_COLOR3(FillColor4dv), 0.8, LA_COLOR3(FillColor4dv), 0, }; tnsUseNoTexture(); if (MAIN.CurrentWindow->CurrentLayout->DropToBlock == b){ int Index[4]; tnsVertexArray2d(DraggingPlot, 8); tnsColorArray4d(FillColor, 8); switch (MAIN.CurrentWindow->CurrentLayout->DropLocation){ case 0: Index[0] = 0; Index[1] = 2; Index[2] = 4; Index[3] = 6; break; case LA_BLOCK_DROP_LOCATION_L: Index[0] = 0; Index[1] = 1; Index[2] = 3; Index[3] = 2; break; case LA_BLOCK_DROP_LOCATION_R: Index[0] = 4; Index[1] = 5; Index[2] = 7; Index[3] = 6; break; case LA_BLOCK_DROP_LOCATION_U: Index[0] = 0; Index[1] = 1; Index[2] = 7; Index[3] = 6; break; case LA_BLOCK_DROP_LOCATION_B: Index[0] = 4; Index[1] = 5; Index[2] = 3; Index[3] = 2; break; } //glDisable(GL_CULL_FACE); tnsIndexArray(Index, 4); tnsPackAs(GL_TRIANGLE_FAN); //tnsFlush(); } tnsVertexArray2d(DraggingPlot, 8); tnsColorArray4d(PlotColor, 8); tnsPackAs(GL_LINES); tnsVertexArray2d(Square, 4); tnsColor4dv(BorderColor4dV); tnsPackAs(GL_LINE_LOOP); glLineWidth(LA_SEAM_W); tnsFlush(); glLineWidth(1); } void la_BlockDefDrawSelf(laBlock *b, int CH){ laBoxedTheme *bt = _LA_THEME_TAB; laPanel *p; real v[] = { b->X, CH - b->Y, b->X + LA_SEAM_W, CH - b->Y , b->X, CH - (b->Y + b->H), b->X + LA_SEAM_W, CH - (b->Y + b->H - LA_SEAM_W), b->X + b->W, CH - (b->Y + b->H), b->X + b->W - LA_SEAM_W, CH - (b->Y + b->H - LA_SEAM_W), b->X + b->W, CH - b->Y, b->X + b->W - LA_SEAM_W, CH - b->Y}; real tv[8]; real ratio = 1.0001f; int tw = 0; int L = LA_RH+LA_SEAM_W; tnsUseImmShader(); tnsEnableShaderv(T->immShader); if(MAIN.EnableColorManagement){ tnsUniformOutputColorSpace(T->immShader,MAIN.CurrentWindow->OutputColorSpace); tnsUniformColorComposing(T->immShader,MAIN.CurrentWindow->UseComposing,MAIN.CurrentWindow->ComposingGamma,MAIN.CurrentWindow->ComposingBlackpoint); }else{ tnsUniformOutputColorSpace(T->immShader,0); tnsUniformColorComposing(T->immShader,0,0,0); } for (p = b->Panels.pFirst; p; p = p->Item.pNext){ tw += p->TitleWidth + LA_SEAM_W*2; } if (tw > b->W - LA_SEAM_W*2 - LA_RH) ratio = (real)(b->W - LA_SEAM_W*2 - LA_RH) / (real)tw; tnsUseNoTexture(); tnsColor4dv(laThemeColor(bt,LA_BT_ACTIVE)); tnsVertexArray2d(v, 8); tnsPackAs(GL_TRIANGLE_STRIP); int TitleGap=b->Folded?0:LA_RH; tnsMakeQuad2d(tv, b->X, (CH - b->Y), b->X + b->W, (CH - b->Y), b->X + b->W, (CH - b->Y - TitleGap), b->X, (CH - b->Y - TitleGap)); tnsColor4dv(laThemeColor(bt,LA_BT_ACTIVE)); tnsVertexArray2d(tv, 4); tnsPackAs(GL_TRIANGLE_FAN); tnsMakeQuad2d(tv,b->X + LA_SEAM_W, (CH - b->Y - TitleGap), b->X + b->W - LA_SEAM_W, (CH - b->Y - TitleGap), b->X + b->W - LA_SEAM_W, (CH - b->Y - TitleGap - LA_SEAM_W), b->X + LA_SEAM_W, (CH - b->Y - TitleGap- LA_SEAM_W)); tnsColor4dv(laThemeColor(bt,LA_BT_BORDER)); tnsVertexArray2d(tv, 4); tnsPackAs(GL_TRIANGLE_FAN); if(b->Folded){ real Color[4]; tnsVectorCopy4d(laThemeColor(bt,LA_BT_BORDER), Color); Color[3]*=b->OnButton==2?1:(b->OnButton==1?0.3:0); tnsDrawStringAuto("⯆",Color, b->X+LA_SEAM_W,b->X+LA_SEAM_W+LA_RH, CH-b->Y, LA_TEXT_REVERT_Y|LA_TEXT_ALIGN_CENTER); tnsDrawStringAuto("⮼",Color, b->X+LA_SEAM_W+LA_RH,b->X+LA_SEAM_W+LA_2RH, CH-b->Y, LA_TEXT_REVERT_Y|LA_TEXT_ALIGN_CENTER); tnsFlush(); return; } int LT=0,RT=0; for (p = b->Panels.pFirst; p; p = p->Item.pNext){ RT = LT + p->TitleWidth + LA_SEAM_W*2; tnsMakeQuad2d(tv,b->X + L+LT * ratio, (CH - b->Y), b->X + L+RT * ratio, (CH - b->Y), b->X + L+RT * ratio, (CH - b->Y - LA_RH), b->X + L+LT * ratio, (CH - b->Y - LA_RH)); if (p == b->CurrentPanel){ tnsUseNoTexture(); tnsColor4dv(laThemeColor(bt,LA_BT_BORDER)); tnsVertexArray2d(tv, 4); tnsPackAs(GL_TRIANGLE_FAN); tnsDrawStringAuto(transLate(p->Title->Ptr), laThemeColor(bt,LA_BT_TEXT_ACTIVE), b->X + L +LT* ratio + LA_SEAM_W, b->X + L +RT* ratio, CH - b->Y, LA_TEXT_REVERT_Y); }else{ tnsDrawStringAuto(transLate(p->Title->Ptr), laThemeColor(bt,LA_BT_TEXT), b->X + L +LT* ratio + LA_SEAM_W, b->X + L +RT* ratio, CH - b->Y, LA_TEXT_REVERT_Y); } LT =RT; } tnsDrawStringAuto("🔻",laThemeColor(bt,LA_BT_BORDER), b->X+LA_SEAM_W,b->X+b->W, CH-b->Y, LA_TEXT_REVERT_Y); tnsFlush(); tnsUniformOutputColorSpace(T->immShader,0); tnsUniformColorComposing(T->immShader,0,0,0); } void la_BlockDefDrawSelfEmpty(laBlock *b, int CH){ laBoxedTheme *bt = _LA_THEME_PANEL; real tv[8]; tnsUseImmShader(); tnsEnableShaderv(T->immShader); if(MAIN.EnableColorManagement){ tnsUniformOutputColorSpace(T->immShader,MAIN.CurrentWindow->OutputColorSpace); tnsUniformColorComposing(T->immShader,MAIN.CurrentWindow->UseComposing,MAIN.CurrentWindow->ComposingGamma,MAIN.CurrentWindow->ComposingBlackpoint); }else{ tnsUniformOutputColorSpace(T->immShader,0); tnsUniformColorComposing(T->immShader,0,0,0); } tnsUseNoTexture(); tnsMakeQuad2d(tv, b->X, (CH - b->Y), b->X + b->W, (CH - b->Y), b->X + b->W, (CH - b->Y-b->H), b->X, (CH - b->Y-b->H)); tnsVertexArray2d(tv, 4); tnsColor4dv(laThemeColor(bt,LA_BT_NORMAL)); tnsPackAs(GL_TRIANGLE_FAN); tnsDrawStringAuto(transLate("Dock some panels here."), laThemeColor(bt,LA_BT_TEXT), b->X+LA_SEAM_W,b->X+b->W-LA_SEAM_W, CH-b->Y-b->H/2+LA_RH2, LA_TEXT_ALIGN_CENTER|LA_TEXT_REVERT_Y|LA_TEXT_USE_NEWLINE|LA_TEXT_LINE_WRAP); tnsFlush(); tnsUniformOutputColorSpace(T->immShader,0); tnsUniformColorComposing(T->immShader,0,0,0); } void la_BlockDefDrawRecursive(laWindow *w, laBoxedTheme *bt, laBlock *b){ if (b->B1){ la_BlockDefDrawRecursive(w, bt, b->B1); la_BlockDefDrawRecursive(w, bt, b->B2); }elif (b->CurrentPanel /*&& b->CurrentPanel->Refresh*/){ if (!b->CurrentPanel->BT) b->CurrentPanel->BT = &_LA_THEME_PANEL; la_PanelDefDraw(w, b->CurrentPanel, *b->CurrentPanel->BT); tnsViewportWithScissor(0, 0, w->CW, w->CH); tnsOrtho(0, w->CW, 0, w->CH, -100, 100); la_BlockDefDrawSelf(b, w->CH); }else{ tnsViewportWithScissor(0, 0, w->CW, w->CH); tnsOrtho(0, w->CW, 0, w->CH, -100, 100); la_BlockDefDrawSelfEmpty(b, w->CH); } if(b==MAIN.CurrentWindow->CurrentLayout->MovingBlock){ tnsUseNoTexture(); int at; real tv[8]; if (b->Vertical){ at = b->H * b->SplitRatio + b->Y; tnsMakeQuad2d(tv,b->X, (w->CH - at + LA_SEAM_W), b->X + b->W, (w->CH - at + LA_SEAM_W), b->X + b->W, (w->CH - at - LA_SEAM_W), b->X, (w->CH - at - LA_SEAM_W)); }else{ at = b->X + b->W * b->SplitRatio; tnsMakeQuad2d(tv,at+ LA_SEAM_W, (w->CH - b->Y), at- LA_SEAM_W, (w->CH - b->Y), at- LA_SEAM_W, (w->CH - b->Y - b->H), at+ LA_SEAM_W, (w->CH - b->Y - b->H)); } tnsColor4dv(laThemeColor(_LA_THEME_TAB,LA_BT_BORDER)); tnsVertexArray2d(tv, 4); tnsPackAs(GL_TRIANGLE_FAN); } //la_SetPanelMatrixDrawWindow(b->CurrentPanel, *b->CurrentPanel->BT); tnsFlush(); } void la_BlockDefDrawAttachedRecursive(laWindow *w, laBoxedTheme *bt, laBlock *b){ if (b->B1){ la_BlockDefDrawAttachedRecursive(w, bt, b->B1); la_BlockDefDrawAttachedRecursive(w, bt, b->B2); }elif (b->CurrentPanel /*&& b->CurrentPanel->Refresh*/){ la_AttachedPanelDefDraw(w,b->CurrentPanel,*b->CurrentPanel->BT); } tnsFlush(); } void la_ClearBlockFramebuffersRecursive(laBlock* b, int AlsoClearCurrent){ if(b->B1)la_ClearBlockFramebuffersRecursive(b->B1,AlsoClearCurrent); if(b->B2)la_ClearBlockFramebuffersRecursive(b->B2,AlsoClearCurrent); for(laPanel* p=b->Panels.pFirst;p;p=p->Item.pNext){ if(!AlsoClearCurrent && p==b->CurrentPanel) continue; if(p->OffScr){ tnsDelete2DOffscreen(p->OffScr); p->OffScr=0; } } } void la_ClearUnusedFramebuffers(laWindow* w){ for(laLayout* l = w->Layouts.pFirst;l;l=l->Item.pNext){ la_ClearBlockFramebuffersRecursive(l->FirstBlock, l!=w->CurrentLayout); } for(laPanel* p=w->Panels.pFirst;p;p=p->Item.pNext){ if(p->Show || p->AnimationMode) continue; if(p->OffScr){ tnsDelete2DOffscreen(p->OffScr); p->OffScr=0; } } } void laDeferredDestroyPanel(laPanel* p, int immediate); void la_WindowDefDraw(laWindow *w, laBoxedTheme *bt){ laPanel *p, *NextP; laLayout *l = w->CurrentLayout; if (!w->CH || !w->CW) return; la_ClearUnusedFramebuffers(w); tnsDrawToScreen(); tnsViewportWithScissor(0, 0, w->CW, w->CH); glClearColor(0.2, 0.2, 0.3, 1.0); tnsClearAll(); tnsUseNoTexture(); if (l->Draw) l->Draw(w, l); tnsResetModelMatrix();tnsResetProjectionMatrix();tnsResetViewMatrix(); glEnable(GL_BLEND); //lBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA,GL_ONE,GL_ONE_MINUS_SRC_ALPHA); laUiItem* ui; if((ui=w->MaximizedUi) && w->MaximizedUiPanel && ui->Type->Draw && ui->CanvasTemplate->SecondDraw){ MAIN.CurrentPanel=w->MaximizedUiPanel; laPanel* p=w->MaximizedUiPanel; int DrawState_=0; la_SetPropMathcerContext(p); if(p->Refresh){ if (!p->BT) p->BT = &_LA_THEME_PANEL; tnsUseShader(T->immShader);tnsEnableShaderv(T->immShader); if(MAIN.EnableColorManagement){ tnsUniformOutputColorSpace(T->immShader,w->OutputColorSpace); tnsUniformColorComposing(T->immShader,w->UseComposing,w->ComposingGamma,w->ComposingBlackpoint); }else{ tnsUniformOutputColorSpace(T->immShader,0); tnsUniformColorComposing(T->immShader,0,0,0); } if(p->Refresh&LA_TAG_RECALC){ laRecalcPanelImmediate(p); } ui->Type->Draw(ui, LA_RH); tnsFlush(); if (!la_AnimateUiListRecursive(&p->UI)) p->Refresh = 0; else { p->Refresh|=LA_TAG_ANIMATION; laRefreshWindow(); } } tnsDrawToScreen(); tnsResetViewMatrix(); tnsViewportWithScissor(0, 0, w->CW, w->CH); tnsOrtho(0, w->CW, w->CH, 0, -100, 100); ui->CanvasTemplate->SecondDraw(ui, LA_RH); tnsFlush(); if(!(ui->Flags&LA_UI_FLAGS_NO_OVERLAY)){ laUiListDraw uild = {0}; for (laUiList* sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){ tnsFlush(); DrawState_+=la_DrawUiListRecursive(&uild, sub, ui->L, ui->R, ui->U, ui->B, 10000, 0, 0, 0, 0); } } if (DrawState_){ p->Refresh = LA_TAG_RECALC; laRefreshWindow(); } la_AttachedPanelDefDraw(w,p,*p->BT); }else{ laBlock* RootBlock= w->MaximizedBlock?w->MaximizedBlock:l->FirstBlock; la_BlockDefDrawRecursive(w, bt, RootBlock); la_BlockDefDrawAttachedRecursive(w,bt, RootBlock); } for (p = w->Panels.pLast; p; p = NextP){ NextP = p->Item.pPrev; if (!p->BT) p->BT = &_LA_THEME_FLOATING_PANEL; if (p->AnimationMode && p->LaterDestroy){ lstRemoveItem(&w->Panels, p); lstAppendItem(&MAIN.CurrentWindow->FadingPanels, p); continue; } la_PanelDefDraw(w, p, *p->BT); } for(laPanel* p=w->Panels.pFirst;p;p=p->Item.pNext){ la_AttachedPanelDefDraw(w,p,*p->BT); } if (MAIN.CurrentWindow->CurrentLayout->DropToBlock){ laBoxedTheme* ubt=_LA_THEME_TAB;tnsUseNoTexture(); tnsViewportWithScissor(0, 0, w->CW, w->CH); tnsOrtho(0, w->CW, 0, w->CH, -100, 100); la_BlockDrawDropLocations(MAIN.CurrentWindow->CurrentLayout->DropToBlock, MAIN.CurrentWindow->CH, laThemeColor(ubt,LA_BT_ACTIVE), laThemeColor(ubt,LA_BT_BORDER)); tnsFlush(); } for (p = w->FadingPanels.pLast; p; p = NextP){ NextP = p->Item.pPrev; if (!p->AnimationMode){ lstRemoveItem(&w->FadingPanels, p); p->AnimationMode = LA_PANEL_ANIMATION_DESTROY; laRefreshWindow(); laDeferredDestroyPanel(p, 0); }else la_PanelDrawToWindow(p, w); } if(MAIN.ShowPerf){ la_PerfDraw(); } } int laStartWindow(laWindow *w){ #ifdef LA_LINUX XMapWindow(MAIN.dpy,w->win); tnsContextMakeWindowCurrent(w); #endif #ifdef _WIN32 ShowWindow(w->win, SW_SHOWNORMAL); #endif MAIN.CurrentWindow = w; if(!w->CurrentLayout){ if(!w->Layouts.pFirst){laDesignLayout(w, "Empty Layout");} memAssignRef(w, &w->CurrentLayout, w->Layouts.pFirst); } laRedrawCurrentWindow(); laInvokeUi(0, "LA_window_operator", 0, w, 0, 0); w->Shown = 1; } void la_AssignWindowPP(laWindow* w){ w->PP.EndInstance = w; w->PP.LastPs = &w->FakePS; w->PP.LastPs->p = _LA_PROP_WINDOW; w->PP.LastPs->UseInstance = w; w->PP.LastPs->Type = U'.'; } laWindow *laDesignWindow(int X, int Y, int W, int H){ #ifdef LAGUI_ANDROID if(MAIN.Windows.pFirst){ return MAIN.Windows.pFirst; } #endif laWindow *n = memAcquire(sizeof(laWindow)); strSafeSet(&n->Title, "Empty SYSWINDOW"); n->X = X; n->Y = Y; n->W = W; n->H = H; #ifdef LAGUI_ANDROID n->X=0; n->Y=0; n->W=MAIN.AppWidth; n->H=MAIN.AppHeight; #endif la_CreateSystemWindow(n, MAIN.Windows.pFirst!=0); lstAppendItem(&MAIN.Windows, n); MAIN.CurrentWindow = n; la_AssignWindowPP(n); laui_DefaultMenuBar(n); return n; } void laSetWindowCursor(int id){ MAIN.CurrentCursor = id; #ifdef LA_LINUX Cursor c = XcursorLibraryLoadCursor(MAIN.dpy, la_ConvertCursorID(id)); XDefineCursor(MAIN.dpy, MAIN.CurrentWindow->win, c); #endif #ifdef _WIN32 SetCursor(la_ConvertCursorID(id)); #endif }; void la_AssignBlockPP(laBlock* b){ b->PP.EndInstance = b; b->PP.LastPs = &b->FakePS; b->PP.LastPs->p = _LA_PROP_BLOCK; b->PP.LastPs->UseInstance = b; b->PP.LastPs->Type = U'.'; } void laDestroyLayout(laWindow *w, laLayout* l){ if((!l->Item.pPrev) && (!l->Item.pNext)) return; laDestroyBlocksRecursive(l->FirstBlock); strSafeDestroy(&l->ID); if(w->CurrentLayout==l){ memAssignRef(w, &w->CurrentLayout, l->Item.pPrev?l->Item.pPrev:l->Item.pNext); } lstRemoveItem(&w->Layouts,l); memFree(l); } laLayout *laDesignLayout(laWindow *w, char *Title){ laLayout *l = memAcquire(sizeof(laLayout)); l->FirstBlock = memAcquire(sizeof(laBlock)); la_AssignBlockPP(l->FirstBlock); lstAppendItem(&w->Layouts, l); strSafeSet(&l->ID, Title); memAssignRef(w, &w->CurrentLayout, l); laRenameWindow(w, Title); return l; } void laFoldBlockTitle(laBlock* b){ if(b->B1) return; b->Folded=1; la_RecalcBlockRecursive(b,b->X,b->Y,b->W,b->H); } void laUnfoldBlockTitle(laBlock* b){ if(b->B1) return; b->Folded=0; b->OnButton=0; la_RecalcBlockRecursive(b,b->X,b->Y,b->W,b->H); } void laMaximizeBlock(laBlock* b){ if(b->B1) return; laWindow* w=MAIN.CurrentWindow; if(w->MaximizedBlock==b){laRestoreToLayout(); return;} w->MaximizedBlock=b; la_UpdateUiPlacement(w); laNotifyUsers("la.windows.maximized_block"); } void laRestoreToLayout(){ laWindow* w=MAIN.CurrentWindow; if(!w->MaximizedBlock) return; w->MaximizedBlock=0; la_UpdateUiPlacement(w); laNotifyUsers("la.windows.maximized_block"); } void laMaximizeCanvasUI(laUiItem* ui, laPanel* UiParentPanel){ laRestoreCanvasUI(); if(!ui->Type||(!(ui->Type->Tag&LA_UI_TAG_IS_OFFSCREEN))||!UiParentPanel) return; la_StopUiOperatorService(UiParentPanel); la_StopUiOperatorService(ui); laRetriggerOperators(); laWindow* w=MAIN.CurrentWindow; w->MaximizedUi=ui; w->MaximizedUiPanel=UiParentPanel; laRecalcPanel(UiParentPanel); UiParentPanel->Show=0; laNotifyUsers("la.windows.maximized_ui"); laHideMenuBar(); } void laRestoreCanvasUI(){ laWindow* w=MAIN.CurrentWindow; if(!w->MaximizedUi || !w->MaximizedUiPanel) return; la_StopUiOperatorService(w->MaximizedUi); laRetriggerOperators(); w->MaximizedUiPanel->Show=1; laRecalcPanel(w->MaximizedUiPanel); w->MaximizedUi=0; w->MaximizedUiPanel=0; la_UpdateUiPlacement(w); laNotifyUsers("la.windows.maximized_ui"); laShowMenuBar(); } void laHideMenuBar(){ laWindow* w=MAIN.CurrentWindow; if(!w->MaximizedUi || !w->MaximizedUiPanel) return; for(laPanel* p=MAIN.CurrentWindow->Panels.pFirst;p;p=p->Item.pNext){ if(p->IsMenuPanel){ p->Show=0; laRefreshWindow(); break; } } } void laShowMenuBar(){ for(laPanel* p=MAIN.CurrentWindow->Panels.pFirst;p;p=p->Item.pNext){ if(p->IsMenuPanel){ p->Show=1; laRefreshWindow(); break; } } } void laSplitBlockHorizon(laBlock *b, real Percentage){ laPanel *p; b->SplitRatio = Percentage; b->Vertical = 0; b->B1 = memAcquire(sizeof(laBlock)); la_AssignBlockPP(b->B1); b->B1->Folded=b->Folded; b->B2 = memAcquire(sizeof(laBlock)); la_AssignBlockPP(b->B2); for (p = b->Panels.pFirst; p; p = p->Item.pNext){ p->Block = b->B1; } b->B1->Panels.pFirst = b->Panels.pFirst; b->B1->Panels.pLast = b->Panels.pLast; b->B1->CurrentPanel = b->CurrentPanel; b->B1->parent = b->B2->parent=b; b->Panels.pFirst = 0; b->Panels.pLast = 0; b->CurrentPanel = 0; la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H); } void laSplitBlockVertical(laBlock *b, real Percentage){ laPanel *p; b->SplitRatio = Percentage; b->Vertical = 1; b->B1 = memAcquire(sizeof(laBlock)); la_AssignBlockPP(b->B1); b->B1->Folded=b->Folded; b->B2 = memAcquire(sizeof(laBlock)); la_AssignBlockPP(b->B2); for (p = b->Panels.pFirst; p; p = p->Item.pNext){ p->Block = b->B1; } b->B1->Panels.pFirst = b->Panels.pFirst; b->B1->Panels.pLast = b->Panels.pLast; b->B1->CurrentPanel = b->CurrentPanel; b->B1->parent = b->B2->parent=b; b->Panels.pFirst = 0; b->Panels.pLast = 0; b->CurrentPanel = 0; la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H); } void laCombineChildBlocks(laBlock *b){ laPanel *p; if(!b) return; if (!b->B1->B1 && !b->B2->B1){ lstCombineLists(&b->Panels, &b->B1->Panels); lstCombineLists(&b->Panels, &b->B2->Panels); for (p = b->Panels.pFirst; p; p = p->Item.pNext){ p->Block = b; } b->CurrentPanel = b->B1->CurrentPanel?b->B1->CurrentPanel:b->B2->CurrentPanel; memFree(b->B1); memFree(b->B2); b->B1 = 0; b->B2 = 0; la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H); }elif(!b->B1->B1){ laBlock* b1 = b->B2->B1; laBlock* b2 = b->B2->B2; b->Vertical = b->B2->Vertical; for (p = b->B1->Panels.pFirst; p; p = p->Item.pNext){ p->Block = b1; } lstCombineLists(&b1->Panels, &b->B1->Panels); memFree(b->B1); memFree(b->B2); b->B1 = b1; b->B2 = b2; b1->parent = b; b2->parent = b; la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H); }elif(!b->B2->B1){ laBlock* b1 = b->B1->B1;laBlock* b2 = b->B1->B2; b->Vertical = b->B1->Vertical; for (p = b->B2->Panels.pFirst; p; p = p->Item.pNext){ p->Block = b1; } lstCombineLists(&b1->Panels, &b->B2->Panels); memFree(b->B1); memFree(b->B2); b->B1 = b1; b->B2 = b2; b1->parent = b; b2->parent = b; la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H); } } laBlock *laBlock1(laBlock *b){ return b->B1; } laBlock *laBlock2(laBlock *b){ return b->B2; } laBlock *laSwapSubBlocks(laBlock *b){ laBlock *tB; tB = b->B2; b->B2 = b->B1; b->B1 = tB; b->SplitRatio = 1 - b->SplitRatio; la_RecalcBlockRecursive(b, b->X, b->Y, b->W, b->H); } void laDestroyBlocksRecursive(laBlock *Root){ laPanel *p; if (Root->B1){ laDestroyBlocksRecursive(Root->B1); laDestroyBlocksRecursive(Root->B2); }else{ while (p = lstPopItem(&Root->Panels)){ laDestroySinglePanel(p, 1); } } memFree(Root); } laPanel* laTearOffPanel(laBlock* b, laPanel* p_if_set){ if(!b->CurrentPanel ) return 0; laPanel* p = p_if_set?p_if_set:b->CurrentPanel; b->CurrentPanel = p->Item.pNext?p->Item.pNext:p->Item.pPrev; lstRemoveItem(&b->Panels, p); if(!b->CurrentPanel && b->parent){ b=b->parent; laCombineChildBlocks(b); } if(!p->TitleBar.UiItems.pFirst){ laui_DefaultPanelTitleBar(&p->TitleBar, &p->PP, &p->PropLinkPP, p->PanelTemplate?p->PanelTemplate->Header:0); } p->Mode = LA_PANEL_FLOATING_TOP; p->TY-=LA_RH; p->TH+=LA_RH; p->W=p->TW=(p->PanelTemplate?p->PanelTemplate->DefaultW_RH:20)*LA_RH; p->W=p->TH=(p->PanelTemplate?p->PanelTemplate->DefaultH_RH:20)*LA_RH; p->Block = 0; laEnsurePanelInBound(p,&p->UI); laPlacePanelForCreation(p); laRecalcPanel(p); la_RecalcBlockRecursive(b, b->X,b->Y,b->W,b->H); p->BT = &_LA_THEME_FLOATING_PANEL; lstPushItem(&MAIN.CurrentWindow->Panels, p); laNotifyUsers("la.windows.panels"); return b->CurrentPanel; } void laDockPanel(laWindow* from, laBlock* b, laPanel* p){ if(!b||!p||p->Mode!=LA_PANEL_FLOATING_TOP||b->B1||b->B2) return; lstRemoveItem(&from->Panels, p); la_DestroyUiList(&p->TitleBar, 1, 1, 0); p->Mode = LA_PANEL_NORMAL; p->Block=b; b->CurrentPanel = p; lstPushItem(&b->Panels, p); laRecalcPanel(p); p->BT = &_LA_THEME_PANEL; la_RecalcBlockRecursive(b, b->X,b->Y,b->W,b->H); tnsFlush(); laNotifyUsers("la.windows.panels"); } void laPopPanel(laPanel *p){ if (p->Mode == LA_PANEL_FLOATING_PASSIVE){ lstRemoveItem(&p->Parent->SubPanels, p); lstPushItem(&p->Parent->SubPanels, p); }else if (p->Mode == LA_PANEL_FLOATING_TOP){ lstRemoveItem(&MAIN.CurrentWindow->Panels, p); lstPushItem(&MAIN.CurrentWindow->Panels, p); laNotifyUsers("la.windows.panels"); } } void la_EnsurePanelExtras(laPanel *p){ laUiTemplate* uit=p->PanelTemplate; p->PropLinkContainer = memAcquire(sizeof(laPropContainer)); p->PropLinkFakeProp = memAcquire(sizeof(laSubProp)); p->PropLinkFakeProp->Base.Identifier = "LA_UI_FAKE_PROP_PLACEHOLDER"; p->PropLinkFakeProp->Base.PropertyType = LA_PROP_SUB; p->PropLinkFakeProp->Base.SubProp = p->PropLinkContainer; p->PropLinkFakeProp->Base.Offset = 0; p->PropLinkFakeProp->Base.OffsetIsPointer = 1; p->PropLinkPP.EndInstance = p; p->PropLinkPP.LastPs = &p->PropLinkFakePS; p->PropLinkPP.LastPs->Type = U'.'; p->PropLinkFakePS.p = p->PropLinkFakeProp; } laPanel* la_GivePanelNode(){ laPanel* p; if(p=lstPopItem(&MAIN.WastedPanels)) return p; return memAcquire(sizeof(laPanel)); } void la_ReturnPanelNode(laPanel* p){ memset(p,0,sizeof(laPanel)); lstRemovePointer(&MAIN.DeferredRedrawList,p); lstAppendItem(&MAIN.WastedPanels, p); } laPanel *la_NewPanel(laUiTemplate* uit, int X, int Y, int W, int H, int MaxW, int MaxH, int MinW, int MinH, int SnapL, int SnapR, int SnapT, int SnapB){ laPanel *p = la_GivePanelNode(); int CW = MAIN.CurrentWindow->CW; int CH = MAIN.CurrentWindow->CH; p->PanelTemplate = uit; if((!W) && uit)W=uit->DefaultW_RH*LA_RH; if((!H) && uit)H=uit->DefaultH_RH*LA_RH; if (!MaxW) MaxW = 10000; if (!MaxH) MaxH = 10000; if (W > MaxW) W = MaxW; if (H > MaxH) H = MaxH; if (W < MinW) W = MinW; if (H < MinH) H = MinH; if(uit) { strSafeSet(&p->Title, uit->Title->Ptr); } p->X = p->TX = (X < 0 ? 0 : X); p->Y = p->TY = (Y < 0 ? 0 : Y); p->W = p->TW = (W < 0 ? CW + W - p->X : W); p->H = p->TH = (H < 0 ? CH + H - p->Y : H); p->MaxW = MaxW; p->MaxH = MaxH; p->MinW = MinW; p->MinH = MinH; p->SL = SnapL; p->ST = SnapT; p->SR = SnapR; p->SB = SnapB; if (p->SR) p->X = CW - p->W - p->SR; if (p->SB) p->Y = CH - p->H - p->SB; la_EnsurePanelSnapping(p, CW, CH); p->Show = 1; p->PP.EndInstance = p; p->PP.LastPs = &p->FakePS; p->PP.LastPs->p = _LA_PROP_PANEL; p->PP.LastPs->UseInstance = p; p->PP.LastPs->Type = U'.'; la_EnsurePanelExtras(p); laRecalcPanel(p); p->FrameDistinguish = 100; //greater than 1 is ok if(uit&&uit->PropFunc){ uit->PropFunc(p); } if(uit){uit->Define(&p->UI, &p->PP, &p->PropLinkPP, 0, 0);} return p; } laPanel *laCreatePanelT(laBlock *b, laUiTemplate* uit){ if(!uit) return 0; laPanel *p = memAcquireHyper(sizeof(laPanel)); strSafeSet(&p->Title, uit->Title->Ptr); p->PanelTemplate = uit; p->Show = 1; p->PP.EndInstance = p; p->PP.LastPs = &p->FakePS; p->PP.LastPs->p = _LA_PROP_PANEL; p->PP.LastPs->UseInstance = p; p->PP.LastPs->Type = U'.'; la_EnsurePanelExtras(p); laRecalcPanel(p); p->FrameDistinguish = 100; //greater than 1 is ok p->TitleWidth = tnsStringGetWidth(transLate(SSTR(p->Title)), 0, 0); while (b->B1){ b = b->B1; } lstPushItem(&b->Panels, p); p->Block = b; b->CurrentPanel = p; if(uit->PropFunc){ uit->PropFunc(p); } uit->Define(&p->UI, &p->PP, &p->PropLinkPP, 0, 0); laNotifyUsers("la.windows.panels"); return p; } laPanel *laCreatePanel(laBlock *b, char *template_id){ laUiTemplate* uit=laFindUiTemplate(template_id); return laCreatePanelT(b, uit); } laPanel *laCreateTopPanel(laWindow *w, char *template_id, int X, int Y, int W, int H, int MaxW, int MaxH, int MinW, int MinH, int SnapL, int SnapR, int SnapT, int SnapB){ laUiTemplate* uit=0; if(template_id) uit=laFindUiTemplate(template_id); laPanel *p = la_NewPanel(uit, X, Y, W, H, MaxW, MaxH, MinW, MinH, SnapL, SnapR, SnapT, SnapB); p->Mode = LA_PANEL_FLOATING_TOP; laPlacePanelForCreation(p); if(uit){ laui_DefaultPanelTitleBar(&p->TitleBar, &p->PP, &p->PropLinkPP, p->PanelTemplate->Header); } if (w) lstPushItem(&w->Panels, p); return p; } void laShowPanel(laPanel *p){ p->Show = 1; laNotifyUsers("la.windows.panels_hidden"); } void laShowPanelWithDropDownEffect(laPanel *p){ laShowPanel(p); p->AnimationMode = LA_PANEL_ANIMATION_DROP_DOWN; laRefreshWindow(); p->AnimationRatio = 0; } void laShowPanelWithExpandEffect(laPanel *p){ laShowPanel(p); p->AnimationMode = LA_PANEL_ANIMATION_EXPAND; laRefreshWindow(); p->AnimationRatio = 0; } void laHidePanel(laPanel *p){ if (!p->Mode) return; p->Show = 0; laNotifyUsers("la.windows.panels_hidden"); } void laHidePanelWithDissoveEffect(laPanel *p){ if (!p->Mode) return; laHidePanel(p); p->AnimationMode = LA_PANEL_ANIMATION_DISSOVE; laRefreshWindow(); p->AnimationRatio = 1; } void laHidePanelWithCollapseEffect(laPanel *p){ if (!p->Mode) return; laHidePanel(p); p->AnimationMode = LA_PANEL_ANIMATION_COLLAPSE; laRefreshWindow(); p->AnimationRatio = 1; } void laHidePanelWithMinimizeEffect(laPanel *p){ if (!p->Mode) return; laHidePanel(p); p->AnimationMode = LA_PANEL_ANIMATION_MINIMIZE; laRefreshWindow(); p->AnimationRatio = 1; } void laActivatePanel(char* TemplateID, int x, int y){ laUiTemplate* uit = laFindUiTemplate(TemplateID); laPanel *p = la_FindFreePanelByTemplate(MAIN.CurrentWindow, uit); if (!p){ p=laCreateTopPanel(MAIN.CurrentWindow, TemplateID, x, y, 0,0, 0, 0, 0, 0, 0, 0, 0, 0); } laShowPanelWithExpandEffect(p); laPopPanel(p); } void laPanPanel(laPanel *p, int DeltaX, int DeltaY){ p->UI.PanX += DeltaX; p->UI.PanY += DeltaY; } int laPanUiListFree(laUiList *uil, int X, int Y){ uil->PanX+=X; uil->PanY+=Y; } int laPanUiList(laUiList *uil, int X, int Y, int L, int R, int U, int B){ if(uil->ScrollerShownH && !uil->ScrollerShownV){ if(Y){X+=Y;Y=0;} } if (Y > 0){ if (uil->B - uil->PanY <= B) return 0; else{ uil->PanY += Y; if (uil->B - uil->PanY <= B){ uil->PanY = uil->B - B; return 1; } } } if (Y < 0){ if (uil->U - uil->PanY >= U) return 0; else{ uil->PanY += Y; if (uil->U - uil->PanY >= U){ uil->PanY = uil->U - U; return 1; } } } if(uil->AllowScale){ laPanUiListFree(uil, X, 0); }else{ if (X > 0){ if (uil->R - uil->PanX <= R) return 0; else{ uil->PanX += X; if (uil->R - uil->PanX <= R){ uil->PanX = uil->R - R; return 1; } } } if (X < 0){ if (uil->L - uil->PanX >= L) return 0; else{ uil->PanX += X; if (uil->L - uil->PanX >= L){ uil->PanX = uil->L - L; return 1; } } } } return 1; } int laScaleUiList(laUiList *uil, real factor, int L, int R, int U, int B){ int ret=1; if(!uil->AllowScale){ return 0; } real NewScale=uil->Scale*factor; if(NewScale<0.2){NewScale=0.2; ret=0;} if(NewScale>5) {NewScale=5; ret=0;} if(NewScale>1-1e-4 && NewScale<1+1e-4){NewScale=1;} factor=NewScale/uil->Scale; uil->Scale=NewScale; real mx=(L+R)/2,my=(U+B)/2; real dx= (mx+uil->PanX)*factor; real dy= (my+uil->PanY)*factor; uil->PanX=dx-mx; uil->PanY=dy-my; MAIN.CurrentPanel->FrameDistinguish=100; return ret; } int laPanUiListAuto(laUiList *uil, int X, int Y, int L, int R, int U, int B){ if(uil->AllowScale) return 0; return laPanUiList(uil,X,Y,L,R,U,B); } laPanel *laDesignPropPanel(char *Title, int X, int Y, int W, int H, laUiDefineFunc Define, laPropPack *This, laPropPack *OperatorProps){ laPanel *p = la_NewPanel(0, X, Y, W, H, 0, H, 0, 0, 0, 0, 0, 0); strSafeSet(&p->Title, Title); if (Define){ Define(laPrepareUi(p), This, OperatorProps, NULL, 0); } //laui_DefaultOperatorPanelTitleBar(&p->TitleBar, &p->PP, OperatorProps, 0, 0); p->BT= &_LA_THEME_FLOATING_PANEL; p->Mode = LA_PANEL_FLOATING_PASSIVE; p->BoundUi = 1; return p; } laPanel *laDesignOperatorPanel(char *Title, int X, int Y, int W, int H, int MaxW, int MaxH, int MinW, int MinH, int SnapL, int SnapR, int SnapT, int SnapB, laUiDefineFunc Define, laPropPack *This, laPropPack *OperatorProps){ laPanel *p = la_NewPanel(0, X, Y, W, H, MaxW, MaxH, MinW, MinH, SnapL, SnapR, SnapT, SnapB); strSafeSet(&p->Title, Title); if (Define){ Define(laPrepareUi(p), This, OperatorProps, NULL, 0); } laui_DefaultOperatorPanelTitleBar(&p->TitleBar, &p->PP, OperatorProps, 0, 0); p->BT= &_LA_THEME_FLOATING_PANEL; p->Mode = LA_PANEL_FLOATING_TOP; p->BoundUi = 1; return p; } void laDeferredDestroyPanel(laPanel *p, int immediate){ laPanel *ip; tnsDelete2DOffscreen(p->OffScr); p->OffScr = 0; strSafeDestroy(&p->Title); if (!p->AnimationMode){ if (p->Parent) lstRemoveItem(&p->Parent->SubPanels, p); else if (p->Mode == LA_PANEL_FLOATING_TOP){ lstRemoveItem(&MAIN.CurrentWindow->Panels, p); }else if (p->Mode == LA_PANEL_NO_PARENT_MENU){ lstRemoveItem(&MAIN.CurrentWindow->Panels, p); }else if (p->Block){ lstRemoveItem(&p->Block->Panels, p); if (p->Block->CurrentPanel == p) p->Block->CurrentPanel = p->Block->Panels.pFirst; } laNotifyUsers("la.windows.panels"); } for (ip = p->SubPanels.pFirst; ip; ip = ip->Item.pNext){ //lstRemoveItem(&p->SubPanels, ip); laDestroySinglePanel(ip, immediate); laNotifyUsers("la.windows.panels"); } la_ClearDetachedProp(p); memFree(p->PropLinkContainer); memFree(p->PropLinkFakeProp); la_ReturnPanelNode(p); } void laDestroySinglePanel(laPanel *p, int immediate){ la_SetPropMathcerContext(p); if (p->PropLinkPP.LastPs&&p->PropLinkPP.LastPs->p->SubProp->Props.pFirst){ for(laProp* prop=p->PropLinkPP.LastPs->p->SubProp->Props.pFirst;prop;prop=prop->Item.pNext){ { /* la_StopUsingPropPack(&prop->DetachedPP); */ } //laStopUsingDataBlock(prop->DetachedPP.LastPs->UseInstance, prop->DetachedPP.LastPs->p,MAIN.PropMatcherContextP); } } if(MAIN.CurrentWindow&&p==MAIN.CurrentWindow->MaximizedUiPanel){ laRestoreCanvasUI(); } la_DestroyUiList(&p->UI, 1, 1, 0); la_DestroyUiList(&p->TitleBar, 1, 1, 0); //la_DestroyUiList(p->MenuRefer, 0, 1, 1); if (p->Mode){ p->AnimationMode = LA_PANEL_ANIMATION_DISSOVE; laRefreshWindow(); p->AnimationRatio = p->CloseWhenMovedOut?0.0:1.0; } if (p->ParentOperator && la_UiOperatorExists(p)) ((laOperator *)p->ParentOperator)->OperatorPanel = 0; if (la_UiStillInService(p)){ la_StopUiOperatorService(p); } if ((!p->AnimationMode) || immediate){ laDeferredDestroyPanel(p, immediate); }else{ p->LaterDestroy = 1; } } int laEnclosePanelContent(laPanel *p, laUiList *uil){ laBoxedTheme *bt = _LA_THEME_FLOATING_PANEL; int MinW,MinWt=0; int TitleReserve=p->Mode==LA_PANEL_FLOATING_TOP?LA_RH:0; int CW = MAIN.CurrentWindow->CW; if(p->SL && p->SR){return 0;} la_SetPropMathcerContext(p); la_UpdateUiListRecursive(&p->TitleBar, bt->TM, bt->LM, p->TW - bt->LM-bt->RM, p->TH, 0, p); la_UpdateUiListRecursive(uil, bt->TM+p->TitleBar.B, 0, 1000, 0, 0, p); MinWt = la_TestUiListMinumWidth(&p->TitleBar); MinW = la_TestUiListMinumWidth(uil); if (MinWScrollerShownV?(LA_SCROLL_W+bt->RM):0); if (MinW > 20){ p->TW = MinW + bt->LM + bt->RM+ScrollerW; } la_PanelValidateWidth(p,uil); laEnsurePanelInBound(p,uil); if(p->TW>CW){ p->TW=CW; } la_UpdateUiListRecursive(&p->TitleBar, bt->TM, bt->LM, p->TW - bt->LM-bt->RM, p->TH, 0, p); la_UpdateUiListRecursive(uil, bt->TM+p->TitleBar.B, bt->LM, p->TW - bt->RM - ScrollerW, 0, 0, p); laRedrawPanel(p); return 1; } laPanel *laEnableIdlePanel(laPanel *Attachment, laOperator *a, laPropPack *OperatorProps, laUiDefineFunc ReplaceUiDefine, laPropPack *This, int L, int R, int B, int MaxGH, int MaxW, laEvent *e){ laOperator *ai = a; laPanel *p; int GX, GY, GW, t = 0; int b; laUiDefineFunc def = ReplaceUiDefine; int MinW; if (!def){ def=laui_DefaultPropDetails; } GX = L; GY = B; GW = (R - L) > MaxW ? MaxW : (R - L); p = laDesignPropPanel("TMP", GX, GY, GW, MaxGH, def, This, OperatorProps); laEnclosePanelContent(p, &p->UI); laSetOperatorLocalizer(p); p->CloseWhenMovedOut=1; laInvokeUi(a, "LA_menu_panel_operator", e, p, 0, 1); //laShowPanelWithDropDownEffect(p); if(!Attachment){ Attachment=MAIN.CurrentWindow->MaximizedUiPanel; } if(Attachment){ p->Parent = Attachment; lstAppendItem(&Attachment->SubPanels, p); } return p; } laPanel *laEnableSplashPanel(laUiDefineFunc ReplaceUiDefine, int L, int R, int B, int MaxGH, int MaxW, laEvent* e){ laPanel *p; int GX, GY, GW, t = 0; int b; laUiDefineFunc def = ReplaceUiDefine; int MinW; if (!def) return 0; GX = L; GY = B; GW = (R - L) > MaxW ? MaxW : (R - L); p = laDesignPropPanel("TMP", GX, GY, GW, MaxGH, def, 0, 0); p->Mode = LA_PANEL_FLOATING_TOP; p->CloseWhenMovedOut=2; MAIN.PendingSplash=p; laEnclosePanelContent(p, &p->UI); if(MAIN.CurrentWindow->Operators.pFirst){ laSetOperatorLocalizer(MAIN.PendingSplash); laInvokeUi(0, "LA_panel_operator", e, MAIN.PendingSplash, 0, 1); MAIN.PendingSplash=0; } //laShowPanelWithExpandEffect(p); lstPushItem(&MAIN.CurrentWindow->Panels, p); return p; } laPanel *laEnablePropertyPanel(laPanel *Attachment, laOperator *a, laPropPack *OperatorProps, laUiDefineFunc ReplaceUiDefine, laUiDefineFunc FallBackUiDefine, laPropPack *This, int L, int R, int B, int MaxGH, int MaxW, laEvent *e){ laOperator *ai = a; laPanel *p; laPropContainer* sub; int GX, GY, GW, t = 0; int b; laUiDefineFunc def = ReplaceUiDefine; int MinW; if (!def){ if (This && This->LastPs->p){ if(This->LastPs->p->UiDefine) def = This->LastPs->p->UiDefine; elif(This->LastPs->p->SubProp&&This->LastPs->p->SubProp->MenuUiDefine) def = This->LastPs->p->SubProp->MenuUiDefine; } if((!def) && (sub=la_EnsureSubTarget(This->LastPs->p,This->EndInstance)) && sub->MenuUiDefine) def=sub->MenuUiDefine; if(!def) def = FallBackUiDefine?FallBackUiDefine:laui_DefaultPropUiDefine; } GX = L; GY = B; GW = (R - L) > MaxW ? MaxW : (R - L); p = laDesignPropPanel("TMP", GX, GY, GW, MaxGH, def, This, OperatorProps); laEnclosePanelContent(p, &p->UI); laSetOperatorLocalizer(p); laInvokeUi(a, "LA_menu_panel_operator", e, p, 0, 1); laShowPanelWithDropDownEffect(p); if(!Attachment){ Attachment=MAIN.CurrentWindow->MaximizedUiPanel; } if(Attachment){ p->Parent = Attachment; lstAppendItem(&Attachment->SubPanels, p); } return p; } laPanel *laEnableEmptyPropertyPanel(laPanel *Attachment, laOperator *a, int L, int R, int U, int MaxGH, laEvent *e){ laPanel *p; int t = 0; int b; //laLocalToWindow(0, Attachment, &L, &t); //laLocalToWindow(0, Attachment, &R, &U); p = laDesignPropPanel("TMP", L, U, R - L, MaxGH, 0, 0, 0); laSetOperatorLocalizer(p); laInvokeUi(a, "LA_menu_panel_operator", e, p, 0, 1); laShowPanelWithDropDownEffect(p); p->Parent = Attachment; lstPushItem(&Attachment->SubPanels, p); return p; } laPanel *laEnableMenuPanel(laPanel *Attachment, laOperator *a, laUiList *MenuRefer, laPropPack *This, int L, int R, int B, int MaxGH, int MaxW, laEvent *e){ laOperator *ai = a; laPanel *p; laBoxedTheme *bt = _LA_THEME_FLOATING_PANEL; int GX, GY, GW, t = 0; int b; int MinW; //laLocalToWindow(0,Attachment, &L, &t); //laLocalToWindow(0,Attachment, &R, &B); GX = L; GY = B; GW = (R - L) > MaxW ? MaxW : (R - L); p = laDesignPropPanel("TMP", GX, GY, GW, MaxGH, 0, 0, 0); p->MenuRefer = MenuRefer; laEnclosePanelContent(p, MenuRefer); laSetOperatorLocalizer(p); laInvokeUi(a, "LA_menu_panel_operator", e, p, 0, 1); laShowPanelWithDropDownEffect(p); p->Parent = Attachment; lstPushItem(&Attachment->SubPanels, p); return p; } laPanel *laDefineAndEnableMenuPanel(laPanel *Attachment, laOperator *a, laPropPack *This, int L, int B, int MaxGH, int MaxW, laEvent *e){ laOperator *ai = a; laPanel *p; int GX, GY, GW, t = 0; int b; GX = L; GY = B; GW = MaxW; p = laDesignPropPanel("TMP", GX, GY, GW, MaxGH, 0, 0, 0); p->MenuRefer = &p->UI; p->Mode = LA_PANEL_NO_PARENT_MENU; laSetOperatorLocalizer(p); laInvokeUi(a, "LA_menu_panel_operator", e, p, 0, 1); laShowPanelWithDropDownEffect(p); if (Attachment){ p->Parent = Attachment; lstPushItem(&Attachment->SubPanels, p); }else{ lstPushItem(&MAIN.CurrentWindow->Panels, p); } return p; } laPanel *laEnableOperatorPanel(laOperator *For, laPropPack *This, int X, int Y, int W, int H, int MaxW, int MaxH, int MinW, int MinH, int SnapL, int SnapR, int SnapT, int SnapB, laEvent *e){ laOperator *ai = For; laPanel *p; int b; laUiDefineFunc def = 0; if (ai->Type->UiDefine) def = ai->Type->UiDefine; else def = laui_DefaultPropUiDefine; For->PP.EndInstance = For->CustomData; p = laDesignOperatorPanel(ai->Type->Name, X, Y, W, H, MaxW, MaxH, MinW, MinH, SnapL, SnapR, SnapT, SnapB, def, This, &For->PP); laEnclosePanelContent(p, &p->UI); MAIN.ToPanel = p; laShowPanelWithExpandEffect(p); lstPushItem(&MAIN.CurrentWindow->Panels, p); ai->OperatorPanel = p; p->ParentOperator = For; laInvokeUi(For, "LA_modal_panel_operator", 0, p, 0, 1); return p; } laPanel *laEnableYesNoPanel(laOperator *a, laPanel *Attachment, char *Title, char *Message, int X, int Y, int W, laEvent *e){ laPanel *p; int b; laUiList *uil; laColumn* col; p = la_NewPanel(0, X, Y, W, 0, 1000, 500, 50, 0, 0, 0, 0, 0); strSafeSet(&p->Title, Title); p->BoundUi = 1; p->Mode = LA_PANEL_FLOATING_TOP; p->BT = &_LA_THEME_FLOATING_PANEL; MAIN.ToPanel = p; laui_DefaultOperatorPanelTitleBar(&p->TitleBar, &p->PP, &p->PropLinkPP, 0, 0); uil = laPrepareUi(p); col = laFirstColumn(uil); laShowLabel(uil, col, Message, 0, 0)->Flags|=LA_TEXT_USE_NEWLINE|LA_TEXT_LINE_WRAP; laUiItem* r=laBeginRow(uil,col,0,0); laShowSeparator(uil,col)->Expand=1; laShowItem(uil,col,0,"LA_confirm")->Flags|=LA_UI_FLAGS_HIGHLIGHT|LA_TEXT_ALIGN_CENTER; laEndRow(uil,r); laEnclosePanelContent(p,uil); laShowPanelWithExpandEffect(p); lstPushItem(&MAIN.CurrentWindow->Panels, p); laSetOperatorLocalizer(p); laInvokeUi(a, "LA_modal_panel_operator", e, p, 0, 1); return p; } laPanel *laEnableMessagePanel(laOperator *a, laPanel *Attachment, char *Title, char *Message, int X, int Y, int W, laEvent *e){ laPanel *p; int b; laUiList *uil; laColumn* col; p = la_NewPanel(0, X, Y, W, 0, 1000, 0, 100, 0, 0, 0, 0, 0); strSafeSet(&p->Title, Title); p->BoundUi = 1; p->Mode = LA_PANEL_FLOATING_TOP; p->BT = &_LA_THEME_FLOATING_PANEL; MAIN.ToPanel = p; laui_DefaultOperatorPanelTitleBar(&p->TitleBar, &p->PP, &p->PropLinkPP, 0, 0); uil = laPrepareUi(p); col = laFirstColumn(uil); laShowLabel(uil, col, Message, 0, 0)->Flags|=LA_TEXT_USE_NEWLINE|LA_TEXT_LINE_WRAP; laUiItem* r = laBeginRow(uil,col,0,0); laShowSeparator(uil,col)->Expand=1; laShowItemFull(uil,col,0,"LA_confirm",0,"text=Okay;",0,0)->Flags|=LA_UI_FLAGS_HIGHLIGHT; laEndRow(uil, r); laEnclosePanelContent(p,uil); laShowPanelWithExpandEffect(p); lstPushItem(&MAIN.CurrentWindow->Panels, p); laSetOperatorLocalizer(p); laInvokeUi(a, "LA_modal_panel_operator", e, p, 0, 1); return p; } void laOperatorModalOver(laOperator* For){ For->ModalOver = 1; } void laDeferredRedraw(laPanel* p){ for(laListItemPointer* lip=MAIN.DeferredRedrawList.pFirst;lip;lip=lip->pNext){ if(lip->p==p) return; } lstAppendPointer(&MAIN.DeferredRedrawList, p); } void laRedrawAllWindows(){ if((!MAIN.CurrentWindow) || (!MAIN.CurrentWindow->win)) return; laWindow* cur=MAIN.CurrentWindow; for(laWindow* w=MAIN.Windows.pFirst;w;w=w->Item.pNext){ MAIN.CurrentWindow=w; la_UpdateUiPlacement(w); } MAIN.CurrentWindow=cur; } void laRedrawCurrentWindow(){ if((!MAIN.CurrentWindow) || (!MAIN.CurrentWindow->win)) return; if (MAIN.CurrentWindow) la_UpdateUiPlacement(MAIN.CurrentWindow); } void laRefreshWindow(){ MAIN.CurrentWindow->Redraw=1; } void laRedrawPanel(laPanel* p){ p->Refresh |= LA_TAG_REDRAW; MAIN.CurrentWindow->Redraw=1; } void laRecalcPanel(laPanel* p){ p->Refresh |= LA_TAG_RECALC; MAIN.CurrentWindow->Redraw=1; } void laRedrawCurrentPanel(){ if (MAIN.CurrentPanel) laRedrawPanel(MAIN.CurrentPanel); elif (MAIN.CurrentWindow->MaximizedUiPanel) laRedrawPanel(MAIN.CurrentWindow->MaximizedUiPanel); } void laRecalcCurrentPanel(){ if (MAIN.CurrentPanel) laRecalcPanel(MAIN.CurrentPanel); elif (MAIN.CurrentWindow->MaximizedUiPanel) laRecalcPanel(MAIN.CurrentWindow->MaximizedUiPanel); } void laRecalcPanelImmediate(laPanel* p){ p->FrameDistinguish++; laBoxedTheme* bt = (*p->BT); int scrollw=p->UI.ScrollerShownV?bt->RM*2+LA_SCROLL_W:0; la_PanelRefreshDetachedProp(p); int enclosed=0; if(p->BoundUi || p->MenuRefer){ if(p->MenuRefer) enclosed=laEnclosePanelContent(p, p->MenuRefer); else enclosed=laEnclosePanelContent(p, &p->UI); } if(!enclosed){ la_PanelValidateWidth(p,&p->UI); laEnsurePanelInBound(p,p->MenuRefer?p->MenuRefer:&p->UI); la_UpdateUiListRecursive(&p->TitleBar, bt->TM, bt->LM, p->TW-bt->RM, p->TH-bt->BM, 0, p); int UseB=p->TitleBar.TB; if((!p->Mode)||(p->Mode==LA_PANEL_FLOATING_PASSIVE)){ UseB=0; } la_UpdateUiListRecursive(&p->UI, UseB+bt->TM, bt->LM, p->TW-bt->RM-scrollw, p->TH-bt->BM, 0, p); } laWindow* w=MAIN.CurrentWindow; if(w->MaximizedUiPanel==p&&w->MaximizedUi){ int CW = w->CW; int CH = w->CH; laUiItem* ui=w->MaximizedUi; ui->TU=ui->U=0; ui->TB=ui->B=CH; ui->TL=ui->L=0; ui->TR=ui->R=CW; if(!ui->Page) return; laBoxedTheme* bt=(*ui->Type->Theme); la_UpdateUiListRecursive(ui->Page, ui->TU+bt->TM, ui->TL+bt->LM, ui->TR-bt->RM, ui->TB, 0, w->MaximizedUiPanel); } } void laRecalcCurrentPanelImmediate(){ laRecalcPanelImmediate(MAIN.CurrentPanel); } int laNonFixedPanelExists(laPanel *p){ laPanel *ip; if (!p) return 0; //for (ip = MAIN.CurrentWindow->CurrentLayout->Panels.pLast; ip; ip = ip->Item.pPrev) { // if (ip == p) return 1; //} for (ip = MAIN.CurrentWindow->Panels.pLast; ip; ip = ip->Item.pPrev){ if (ip == p) return 1; } return 0; } int laIsInPanel(laPanel *p, int PanelX, int PanelY){ if (PanelX < 0 || PanelY < 0 || PanelY > p->H || PanelX > p->W) return 0; return 1; } int laIsCloseToPanel(laPanel *p, int PanelX, int PanelY){ int tt=MAIN.TooltipCloseDistance; if (PanelX < -tt || PanelY < -tt || PanelY > p->H+tt || PanelX > p->W+tt) return 0; return 1; } int laPanelOverlappingEachOther(laPanel *p1, laPanel *p2){ if (p1->X > p2->X + p2->W || p1->X + p1->W < p2->X || p1->Y > p2->Y + p2->H || p1->Y + p1->H < p2->Y) return 0; return 1; } void laUnlinkSharedPanel(laPanel *p){ laWindow *w; laPanel *ip; for (w = MAIN.Windows.pFirst; w; w = w->Item.pNext){ for (ip = w->Panels.pFirst; ip; ip = ip->Item.pNext){ if (ip == p){ lstRemoveItem(&w->Panels, ip); return; } } } } int laIsPanelCovered(laPanel *p){ //laLayout* l = MAIN.CurrentWindow->CurrentLayout; laPanel *ip; laPanel *resp; int in1 = 0, in2 = 0, in3 = 0; laPanel *d1 = 0, *d2 = 0, *d3 = 0; //for (ip = MAIN.CurrentWindow->CurrentLayout->Panels.pLast; ip; ip = ip->Item.pPrev) { // if (ip == p) { in1 = 1; d1 = 0; continue; } // if (ip->Show && laPanelOverlappingEachOther(ip, p)) d1 = ip; //} for (ip = MAIN.CurrentWindow->Panels.pLast; ip; ip = ip->Item.pPrev){ if (ip == p){ in3 = 1; d3 = 0; continue; } if (ip->Show && laPanelOverlappingEachOther(ip, p)) d3 = ip; } if (!in2 && !in3) in1 = 1; if (in1){ if (d1 || d2 || d3) return 1; }else{ if (in2){ if (d2 || d3) return 1; }else if (in3) if (d3) return 1; } return 0; } int laIsTopPanel(laPanel *p){ //if (!p->Item.pPrev) return 1; //else { if (!laIsPanelCovered(p)){ //laPopPanel(p); return 1; } return 0; //} return 0; } void laWindowToLocal(laOperator *a, laPanel *p, int *x, int *y){ if(!p) return; int ix = *x, iy = *y; laListItemPointer *lip; laOperator *ai = a; (*x) = ix - ((MAIN.CurrentWindow->MaximizedUiPanel==p)?0: p->X); (*y) = iy - ((MAIN.CurrentWindow->MaximizedUiPanel==p)?0: p->Y); if (a){ for (lip = ai->LocalUiLists.pFirst; lip; lip = lip->pNext){ laUiList *uil = lip->p; (*x) += uil->PanX; (*y) += uil->PanY; } } } void laPanelToLocal(laOperator *a, int *x, int *y){ int ix = *x, iy = *y; laListItemPointer *lip; if (a){ for (lip = a->LocalUiLists.pFirst; lip; lip = lip->pNext){ laUiList *uil = lip->p; (*x) += uil->PanX; (*y) += uil->PanY; } } } void laLocalToWindow(laOperator *a, laPanel *p, int *x, int *y){ if(!p) return; int ix = *x, iy = *y; laListItemPointer *lip; (*x) = ix + ((MAIN.CurrentWindow->MaximizedUiPanel==p)?0: p->X); (*y) = iy + ((MAIN.CurrentWindow->MaximizedUiPanel==p)?0: p->Y); if (a){ for (lip = a->LocalUiLists.pFirst; lip; lip = lip->pNext){ laUiList *uil = lip->p; (*x) -= uil->PanX; (*y) -= uil->PanY; } } } void laPanelToWindow(laPanel *p, int *x, int *y){ int ix = *x, iy = *y; laListItemPointer *lip; (*x) = ix + ((MAIN.CurrentWindow->MaximizedUiPanel==p)?0: p->X); (*y) = iy + ((MAIN.CurrentWindow->MaximizedUiPanel==p)?0: p->Y); } void laLocalToPanel(laOperator *a, int *x, int *y){ int ix = *x, iy = *y; laListItemPointer *lip; if (a){ for (lip = a->LocalUiLists.pFirst; lip; lip = lip->pNext){ laUiList *uil = lip->p; (*x) -= uil->PanX; (*y) -= uil->PanY; } } } void laSetNextMenuPos(int X, int Y, int W, int H){ MAIN.NextX = X; MAIN.NextY = Y; MAIN.NextW = W; MAIN.NextH = H; } int laIsInBlock(laBlock *b, int X, int Y){ if (X >= b->X && X <= b->X + b->W && Y >= b->Y && Y <= b->Y + b->H) return 1; return 0; } int laIsInBlockHeader(laBlock *b, int X, int Y){ if (X >= b->X && X <= b->X + b->W && Y >= b->Y && Y <= b->Y + LA_RH) return 1; return 0; } int laIsInBlockBotton1(laBlock *b, int X, int Y){ if (X >= b->X && X <= b->X + LA_RH && Y >= b->Y && Y <= b->Y + LA_RH) return 1; return 0; } int laIsInBlockBotton2(laBlock *b, int X, int Y){ if (X >= b->X+LA_RH && X <= b->X+LA_2RH && Y >= b->Y && Y <= b->Y + LA_RH) return 1; return 0; } laBlock *laClearBlockButtonRecursive(laBlock *b, laBlock *except){ if(b->B1){laClearBlockButtonRecursive(b->B1,except);} if(b->B2){laClearBlockButtonRecursive(b->B2,except);} if (!b->B1 && !b->B2){ if(b!=except && b->OnButton){ b->OnButton=0; laRefreshWindow(); } } } laBlock *laDetectBlockRecursive(laBlock *b, int X, int Y){ laPanel *p; laBlock *sb = 0; if (!laIsInBlock(b, X, Y)) return 0; if (!b->B1 && !b->B2) return b; if (sb = laDetectBlockRecursive(b->B1, X, Y)) return sb; return laDetectBlockRecursive(b->B2, X, Y); } laPanel *laDetectPanel(int X, int Y){ laPanel *p; laBlock *b; for (p = MAIN.CurrentWindow->Panels.pFirst; p; p = p->Item.pNext){ int x = X, y = Y; laWindowToLocal(0, p, &x, &y); if (p->Show && laIsInPanel(p, x, y)){ return p; } } if(MAIN.CurrentWindow->MaximizedUiPanel){return 0;} laBlock* RootBlock=MAIN.CurrentWindow->MaximizedBlock?MAIN.CurrentWindow->MaximizedBlock:MAIN.CurrentWindow->CurrentLayout->FirstBlock; if (b = laDetectBlockRecursive(RootBlock, X, Y)) return b->CurrentPanel; return 0; } laUiList *laPrepareUi(laPanel *p){ return &p->UI; } laColumn *laFirstColumn(laUiList *uil){ if (uil->Columns.pFirst) return uil->Columns.pFirst; else{ laColumn *c = memAcquireSimple(sizeof(laColumn)); c->SP = 1; c->PreWidth = 1; lstAppendItem(&uil->Columns, c); c->Top = c; return uil->Columns.pFirst; } } laColumn *laSplitColumn(laUiList *uil, laColumn *c, real Percent){ laColumn *lc, *rc; if (c->LS || c->RS) return c; lc = memAcquireSimple(sizeof(laColumn)); rc = memAcquireSimple(sizeof(laColumn)); c->LS = lc; c->RS = rc; c->LS->SP = Percent; c->RS->SP = Percent; c->LS->Top = c->Top; c->RS->Top = c->Top; if (uil){ lstAppendItem(&uil->Columns, lc); lstAppendItem(&uil->Columns, rc); } if (c->LS && c->RS->MaxW == 0){ c->LS->PreWidth = c->PreWidth * c->LS->SP; c->RS->PreWidth = c->PreWidth * (1 - c->RS->SP); }else if (c->RS && c->LS->MaxW == 0){ c->LS->PreWidth = c->PreWidth * c->LS->SP; c->RS->PreWidth = c->PreWidth * (1 - c->RS->SP); } return c; } laColumn *laLeftColumn(laColumn *c, int MaxWidth){ if (c->LS && MaxWidth) c->LS->MaxW = MaxWidth; return c->LS; } laColumn *laRightColumn(laColumn *c, int MaxWidth){ if (c->LS && c->LS->MaxW && MaxWidth) return c->RS; if (MaxWidth) c->RS->MaxW = MaxWidth; return c->RS; } void la_DestroyColumnRecursive(laListHandle *List, laColumn *c){ lstRemoveItem(List, c); if (c->LS) la_DestroyColumnRecursive(List, c->LS); if (c->RS) la_DestroyColumnRecursive(List, c->RS); memFree(c); } int laCheckAndMergeSubColumnsUiList(laUiList *TopUil, laColumn *c, int DoMerge){ laUiList *uil = TopUil; laUiList *sub; laUiItem *ui; laColumn *cc, *NextCC = 0; int Occupied = 0; int Removed = 0; if (!c->LS) return 0; else{ laCheckAndMergeSubColumnsUiList(TopUil, c->LS, DoMerge); laCheckAndMergeSubColumnsUiList(TopUil, c->RS, DoMerge); } for (ui = TopUil->UiItems.pFirst; ui; ui = ui->Item.pNext){ if (ui->C == c->LS || ui->C == c->RS){ if (DoMerge){ ui->C = c; Occupied = 1; }else return 1; } if (ui->Subs.pFirst){ for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){ laCheckAndMergeSubColumnsUiList(sub, c, DoMerge); } } } if (!Removed){ for (cc = uil->Columns.pFirst; cc; cc = cc->Item.pNext){ if (cc == c){ if (c->LS) la_DestroyColumnRecursive(&uil->Columns, c->LS); if (c->RS) la_DestroyColumnRecursive(&uil->Columns, c->RS); c->LS = 0; c->RS = 0; Removed = 1; break; } } } return Occupied; } laPropContainer* laUiHasExtraProps(laUiType *ut, int size, int Hyper){ ut->ExtraProps = laAddPropertyContainer(ut->Identifier, 0,0,U'◳',0,size,0,0,Hyper); ut->FakeProp = memAcquire(sizeof(laSubProp)); ut->FakeProp->Base.SubProp = ut->ExtraProps; ut->FakeProp->Base.Identifier = ut->Identifier; ut->FakeProp->Base.PropertyType = LA_PROP_SUB; ut->FakeProp->Base.Offset = offsetof(laUiItem, Extra); ut->FakeProp->Base.OffsetIsPointer = 1; //ut->FakeProp->Base.Container = ut->ExtraProps; return ut->ExtraProps; } laPropContainer* laCanvasHasExtraProps(laCanvasTemplate *ct, int size, int Hyper){ ct->ExtraProps = laAddPropertyContainer(ct->Identifier->Ptr, 0,0,U'◳',0,size,0,0,Hyper); ct->FakeProp = memAcquire(sizeof(laSubProp)); ct->FakeProp->Base.SubProp = ct->ExtraProps; ct->FakeProp->Base.Identifier = ct->Identifier->Ptr; ct->FakeProp->Base.PropertyType = LA_PROP_SUB; ct->FakeProp->Base.Offset = offsetof(laUiItem, Extra); ct->FakeProp->Base.OffsetIsPointer = 1; //ut->FakeProp->Base.Container = ut->ExtraProps; return ct->ExtraProps; } void la_DestroyUiType(laUiType* uit){ laKeyMapItem* kmi; while(kmi=lstPopItem(&uit->KeyMapper.Items)){ la_FreeKeyMapItem(kmi); } memFree(uit); } laUiType *la_RegisterUiType(const char *Identifer, int ForType, const char *UseOperator, laBoxedTheme **bt, laUiDrawFunc *Draw, laUiGetHeightFunc GetHeight, laUiInitFunc Init, laUiDestroyFunc Destroy){ laUiType *ut = memAcquire(sizeof(laUiType)); ut->Identifier = Identifer; ut->OperatorID = UseOperator; ut->Draw = Draw; ut->Theme = bt; ut->ForType = ForType; ut->OperatorType = laGetOperatorType(UseOperator); ut->GetHeight = GetHeight; ut->Init = Init; ut->Destroy = Destroy; la_UDFAppendSharedTypePointer(Identifer, ut); lstAppendItem(&MAIN.UiTypes, ut); return ut; } laUiType *la_GetUiTypeFromProperty(laProp *P){ laUiType *ut = MAIN.UiTypes.pFirst; if (!P) return 0; if (P->DefaultUiType) return P->DefaultUiType; if (P->SubProp == LA_PC_SOCKET_IN || P->SubProp == LA_PC_SOCKET_OUT) return _LA_UI_NODE_SOCKET; if (P->PropertyType == LA_PROP_SUB) return _LA_UI_COLLECTION; for (ut; ut; ut = ut->Item.pNext){ if ((ut->ForType&LA_PROP_GENERIC_BITS) == (P->PropertyType&LA_PROP_GENERIC_BITS)){ return ut; } } return 0; } laUiType *la_GetUiButtonType(){ laUiType *ut = MAIN.UiTypes.pFirst; for (ut; ut; ut = ut->Item.pNext){ if (ut->ForType == LA_PROP_OPERATOR) return ut; } return 0; } laCanvasTemplate *la_GetCanvasTemplate(char* TargetContainerID, char* TemplateID){ laCanvasTemplate *vdt; for (vdt = MAIN.View2DTemplates.pFirst; vdt; vdt = vdt->Item.pNext){ if (strSame(TemplateID, vdt->Identifier->Ptr) || strSame(TargetContainerID, vdt->TargetContainerID)) return vdt; } return 0; } void la_AssignPropExtras(laUiItem* ui){ if(!ui->Type || !ui->Type->FakeProp) return; ui->FakePs.p = ui->Type->FakeProp; ui->FakePs.Type = U'.'; ui->FakePs.UseInstance = ui; ui->ExtraPP.LastPs = &ui->FakePs; } void la_AssignCanvasPropExtras(laUiItem* ui){ if(!ui->CanvasTemplate || !ui->CanvasTemplate->FakeProp) return; laCanvasTemplate*ct=ui->CanvasTemplate; ui->FakePs.p = ct->FakeProp; ui->FakePs.Type = U'.'; ui->FakePs.UseInstance = ui; ui->ExtraPP.EndInstance = ui->Extra; ui->ExtraPP.LastPs = &ui->FakePs; } laUiItem *la_UpdatePropDisplay(laUiItem *ui, laPropPack *Base, const char *Path, laUiDefineFunc Template, laWidget* Widget, char* instructions){ int result; if (!ui) return 0; laUiType* OverrideType=Widget&&Widget->Type?Widget->Type:0; if (Path){ result = la_GetPropFromPath(&ui->PP, Base, Path, 0); if (!result){ ui->AT = laGetOperatorType(Path); if (!ui->AT /* && !OverrideType*/) return la_UpdatePropDisplay(ui, 0, "la.unknown_prop", 0, 0, instructions); ui->Type = la_GetUiButtonType(); if (OverrideType && (OverrideType->ForType == LA_PROP_OPERATOR)) ui->Type = OverrideType; }else{ ui->Type = (OverrideType && ((!OverrideType->ForType)|| (OverrideType->ForType&&OverrideType->ForType == ui->PP.LastPs->p->PropertyType)|| (OverrideType->TargetSub && !strcmp(OverrideType->TargetSub, ui->PP.LastPs->p->Identifier)))) ? OverrideType : la_GetUiTypeFromProperty(ui->PP.LastPs->p); ui->Flags|=ui->PP.LastPs->p->DefaultFlags; } if (Base){ ui->PP.RawThis = Base; } }else if (Base){ ui->PP.LastPs = Base->LastPs; ui->Type = (OverrideType && ((!OverrideType->ForType)|| (OverrideType->ForType&&OverrideType->ForType == ui->PP.LastPs->p->PropertyType)|| (OverrideType->TargetSub && !strcmp(OverrideType->TargetSub, ui->PP.LastPs->p->SubProp->Identifier)))) ? OverrideType : la_GetUiTypeFromProperty(ui->PP.LastPs->p); ui->PP.RawThis = Base; //HACK! Not Unified For Prop Access!!!<<<----------?????????? ui->Flags|=ui->PP.LastPs->p->DefaultFlags; } la_AssignPropExtras(ui); if(Widget){ ui->Flags|= Widget->Flags; } if(Template) ui->Template = Template; ui->State = LA_UI_NORMAL; if(!ui->Type) ui->Type = Widget?Widget->Type:0; if(instructions) strSafeSet(&ui->ExtraInstructions, instructions); return ui; } laUiItem *la_UpdateLabelDisplay(laUiItem *ui, laUiDefineFunc Template, char *Content){ ui->Type = _LA_UI_LABEL; ui->Template = Template; ui->State = LA_UI_NORMAL; strSafeSet(&ui->Display, Content); la_AssignPropExtras(ui); return ui; } laUiItem *la_CreateGroupHandle(laWidget* Widget){ laUiItem *ui = memAcquireSimple(sizeof(laUiItem)); ui->Type = (Widget&&Widget->Type)?Widget->Type : _LA_UI_FIXED_GROUP; ui->State = LA_UI_NORMAL; la_AssignPropExtras(ui); return ui; } laUiItem *laShowLabel(laUiList *uil, laColumn *c, const char *Content, laUiDefineFunc Template, laWidget* Widget){ laUiItem *ui = memAcquireSimple(sizeof(laUiItem)); transLate(Content); la_UpdateLabelDisplay(ui, Template, Content); ui->C = c; if (ui->Type->Init) ui->Type->Init(ui); ui->ExtraPP.EndInstance = ui->Extra; lstAppendItem(&uil->UiItems, ui); return ui; } laUiItem *laShowLabelDynamic(laUiList *uil, laColumn *c, const char *Content, laUiDefineFunc Template, laWidget* Widget){ laUiItem *ui = memAcquireSimple(sizeof(laUiItem)); la_UpdateLabelDisplay(ui, Template, Content); ui->C = c; if (ui->Type->Init) ui->Type->Init(ui); ui->ExtraPP.EndInstance = ui->Extra; lstAppendItem(&uil->UiItems, ui); return ui; } laUiItem *laShowIcon(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, laWidget* Widget){ laUiItem *ui = memAcquireSimple(sizeof(laUiItem)); la_UpdatePropDisplay(ui, Base, Path, 0, Widget, 0); ui->Flags |= LA_UI_FLAGS_INT_ICON; ui->C = c; if (ui->Type->Init) ui->Type->Init(ui); ui->ExtraPP.EndInstance = ui->Extra; lstAppendItem(&uil->UiItems, ui); return ui; } laUiItem *laShowInvisibleItem(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path){ laWidget wg={&_LA_UI_INVISIBLE, 0}; return laShowItemFull(uil,c,Base,Path,&wg,0,0,0); } laUiItem *laShowItem(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path){ return laShowItemFull(uil,c,Base,Path,0,0,0,0); } laUiItem *laShowItemFull(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, laWidget* Widget, char* instructions, laUiDefineFunc Template, int TemplateContext){ laUiItem *ui = memAcquireSimple(sizeof(laUiItem)); la_UpdatePropDisplay(ui, Base, Path, Template, Widget, instructions); ui->C = c; ui->TemplateContext = TemplateContext; if (ui->Type->Init) ui->Type->Init(ui); ui->ExtraPP.EndInstance = ui->Extra; lstAppendItem(&uil->UiItems, ui); return ui; } laUiItem *laShowImage(laUiList *uil, laColumn *c, tnsImage* Image, int Height){ laUiItem *ui = memAcquire(sizeof(laUiItem)); ui->C = c; memAssignRef(ui,&ui->Extra,Image); ui->Type=_LA_UI_IMAGE; ui->Type->Init(ui); ui->SymbolID=Height; lstAppendItem(&uil->UiItems, ui); return ui; } laUiItem *laShowNodeSocket(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, char* instructions){ return laShowItemFull(uil,c,Base,Path,LA_WIDGET_NODE_SOCKET,instructions,0,0); } laUiItem *laShowHeightAdjuster(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, char* instructions){ return laShowItemFull(uil,c,Base,Path,LA_WIDGET_HEIGHT_ADJUSTER,instructions,0,0); } laUiItem *laShowCanvas(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, const char *id2DTemplate, int Height){ laUiItem *ui = memAcquireSimple(sizeof(laUiItem)); ui->Type = _LA_UI_CANVAS; ui->State = LA_UI_NORMAL; ui->C = c; la_GetPropFromPath(&ui->PP, Base, Path, 0); if (id2DTemplate) ui->CanvasTemplate = la_GetCanvasTemplate(0, id2DTemplate); else{ if(!ui->PP.LastPs || ui->PP.LastPs->p->PropertyType!=LA_PROP_SUB){ la_FreePropStepCache(ui->PP.Go); memFree(ui); return laShowItem(uil,c,Base,Path); } laSubProp* sp=ui->PP.LastPs->p; ui->PP.LastPs->p->SubProp=la_EnsureSubTarget(sp,0); ui->CanvasTemplate = la_GetCanvasTemplate(sp->TargetID, 0); if(!ui->CanvasTemplate){ la_FreePropStepCache(ui->PP.Go); memFree(ui); return laShowItem(uil,c,Base,Path); } } if (ui->Type->Init) ui->Type->Init(ui); la_AssignCanvasPropExtras(ui); if (Height) ui->Expand=Height; else ui->Expand=6; lstAppendItem(&uil->UiItems, ui); return ui; } laUiItem *laShow3DCanvasCombo(laUiList *uil, laColumn *c, laPropPack *Base, const char *Path, int Height, laPropPack* Detached){ laUiItem* ui=0; #define ADD_CANVAS \ laUiItem* b=laBeginRow(uil,cr,0,0);\ laUiItem* b3=laOnConditionThat(uil,cr,laPropExpression(&rb->PP,"active"));{\ laShowLabel(uil,cr,"⯈",0,0); laShowItem(uil,cr,&rb->PP,"active.name")->Flags|=LA_UI_FLAGS_NO_DECAL;\ }laEndCondition(uil,b3);\ laEndRow(uil,b); if(Detached){ laColumn* cl,*cll,*clr,*cr; laSplitColumn(uil,c,0.35); cl=laLeftColumn(c,7); cr=laRightColumn(c,0); laSplitColumn(uil,cl,0.4); cll=laLeftColumn(cl,1); clr=laRightColumn(cl,0); laShowItemFull(uil,cll,Detached,"detached",0,0,0,0)->Flags|=LA_UI_FLAGS_HIGHLIGHT|LA_UI_FLAGS_ICON; laUiItem* b2=laOnConditionThat(uil,c,laPropExpression(Detached,"detached"));{ laUiItem* rb=laShowItemFull(uil,clr,Detached,"root_object",LA_WIDGET_COLLECTION_SELECTOR,0,laui_IdentifierOnly,0); ADD_CANVAS ui=laShowCanvas(uil,c,Detached,"root_object",0,Height); laDefault3DViewOverlay(ui); }laElse(uil,b2);{ laUiItem* rb=laShowItemFull(uil,clr,0,"tns.world.active_root",LA_WIDGET_COLLECTION_SELECTOR,0,laui_IdentifierOnly,0); ADD_CANVAS ui=laShowCanvas(uil,c,0,"tns.world.active_root",0,Height); laDefault3DViewOverlay(ui); }laEndCondition(uil,b2); }else{ ui=laShowCanvas(uil,c,Base,Path,0,Height); laDefault3DViewOverlay(ui); } #undef ADD_CANVAS } laUiItem *laShowColumnAdjuster(laUiList *uil, laColumn *c){ laUiItem *ui = memAcquireSimple(sizeof(laUiItem)); laCanvasExtra *e; ui->Type = _LA_UI_COLUMN_ADJUSTER; ui->Flags |= LA_WIDGET_COLUMN_ADJUSTER->Flags; ui->C = c; if (ui->Type->Init) ui->Type->Init(ui); ui->ExtraPP.EndInstance = ui->Extra; lstAppendItem(&uil->UiItems, ui); return ui; } laUiItem *laShowSymbol(laUiList *uil, laColumn *c, int SymbolID, int Height){ laUiItem *ui = memAcquireSimple(sizeof(laUiItem)); ui->Type = _LA_UI_SYMBOL; ui->SymbolID = SymbolID; if (Height) ui->State = Height; ui->C = c; if (ui->Type->Init) ui->Type->Init(ui); ui->ExtraPP.EndInstance = ui->Extra; lstAppendItem(&uil->UiItems, ui); return ui; } laPropPack* laShowCompoundValue(laUiItem* ui, int slot, laPropPack *Base, const char *Path){ laPropPack PP={0}; int result; if (Path){ result = la_GetPropFromPath(&PP, Base, Path, 0); if (!result){ return 0; } if (Base){ PP.RawThis = Base; } }else if (Base){ PP.LastPs = Base->LastPs; PP.RawThis = Base; //HACK! Not Unified For Prop Access!!!<<<----------?????????? } laCompoundPP* CPP = memAcquire(sizeof(laCompoundPP)); CPP->Slot = slot; memcpy(&CPP->PP, &PP, sizeof(laPropPack)); lstAppendItem(&ui->CompoundPPs,CPP); return &CPP->PP; } laUiItem *laBeginRow(laUiList *uil, laColumn *c, int Expand, int Even){ laUiItem *ui = memAcquireSimple(sizeof(laUiItem)); ui->Type = &_LA_UI_ROW_BEGIN; ui->State=Expand; ui->Flags=Even; ui->C = c; if (ui->Type->Init) ui->Type->Init(ui); ui->ExtraPP.EndInstance = ui->Extra; lstAppendItem(&uil->UiItems, ui); return ui; } laUiItem *laEndRow(laUiList *uil, laUiItem* Begin){ laUiItem *ui = memAcquireSimple(sizeof(laUiItem)); ui->Type = &_LA_UI_ROW_END; ui->C = Begin->C; ui->Page = (laUiList*)Begin; if (ui->Type->Init) ui->Type->Init(ui); ui->ExtraPP.EndInstance = ui->Extra; lstAppendItem(&uil->UiItems, ui); return ui; } void la_ConditionerInit(laUiItem *ui, laUiConditionNode *Expression){ laConditionUiExtraData *e = CreateNew(laConditionUiExtraData); e->Expression = Expression; ui->Extra = e; la_AssignPropExtras(ui); } laUiItem *laMakeGroup(laUiList *uil, laColumn *c, const char *Name, laWidget* Widget){ laUiItem *ui = la_CreateGroupHandle(Widget); laUiList *nuil; ui->C = c; lstAppendItem(&uil->UiItems, ui); nuil = memAcquireSimple(sizeof(laUiList)); strSafeSet(&nuil->TabName, Name); ui->Page = nuil; lstAppendItem(&ui->Subs, nuil); if (ui->Type->Init) ui->Type->Init(ui); ui->ExtraPP.EndInstance = ui->Extra; return ui; } laUiItem *laMakeFoldableGroup(laUiList *uil, laColumn *c, const char *Name, laWidget* Widget, int DefaultFolded, int ButtonFlags){ laUiItem *SubUi = laMakeGroup(uil, c, Name, Widget?Widget:0); laUiList *sub = SubUi->Page; laColumn *s = laFirstColumn(sub); SubUi->State = LA_UI_ACTIVE; laUiItem *b1 = laOnConditionToggle(sub, s, 0, 0, 0, 0, 0); strSafePrint(&b1->ExtraInstructions, "text=… %s", Name); if(!DefaultFolded) b1->State=LA_UI_ACTIVE; if(ButtonFlags)b1->Flags|=ButtonFlags; else b1->Flags|=LA_UI_FLAGS_NO_DECAL; laShowSeparator(sub, s); return SubUi; } laUiItem *laMakeEmptyGroup(laUiList *uil, laColumn *c, const char *Name, laWidget* Widget){ laUiItem *SubUi = laMakeGroup(uil, c, Name, Widget?Widget->Type:0); laUiList *sub = SubUi->Page; laColumn *s = laFirstColumn(sub); SubUi->State = LA_UI_ACTIVE; return SubUi; } void laEndFoldableGroup(laUiList *sub, laUiItem *group){ laEndCondition(sub, sub->UiItems.pFirst); } laUiItem *laMakeTab(laUiList *uil, laColumn *c, laWidget* Widget){ laUiItem *ui = la_CreateGroupHandle(Widget?Widget:LA_WIDGET_TAB); laUiList *nuil; ui->C = c; lstAppendItem(&uil->UiItems, ui); if (ui->Type->Init) ui->Type->Init(ui); ui->ExtraPP.EndInstance = ui->Extra; return ui; } laUiList *laAddTabPage(laUiItem *ui, const char *Name){ laUiList *uil = memAcquireSimple(sizeof(laUiList)); if (!ui->Page) ui->Page = uil; lstAppendItem(&ui->Subs, uil); strSafeSet(&uil->TabName, Name); laFirstColumn(uil); //laFirstColumn(uil); return uil; } laUiList *la_AddInstancePage(laUiItem *ui, void *Instance, laWidget* Widget){ laUiList *uil = memAcquireSimple(sizeof(laUiList)); /*if (!ui->Page) */ ui->Page = uil; lstAppendItem(&ui->Subs, uil); uil->Instance = Instance; ui->PP.EndInstance=Instance; return uil; } laUiConditionNode *laTrue(){ laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode)); ucn->Type = LA_CONDITION_TRUE; return ucn; } laUiConditionNode *laFalse(){ laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode)); ucn->Type = LA_CONDITION_FALSE; return ucn; } laUiConditionNode *laPropExpression(laPropPack *Base, char *Prop){ laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode)); ucn->Type = LA_CONDITION_PROP; la_GetPropFromPath(&ucn->PP, Base, Prop, 0); strSafeSet(&ucn->String, Prop); return ucn; } laUiConditionNode *laIntExpression(int Value){ laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode)); ucn->Type = LA_CONDITION_INT; ucn->IntValue = Value; return ucn; } laUiConditionNode *laFloatExpression(real Value){ laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode)); ucn->Type = LA_CONDITION_FLOAT; ucn->FloatValue = Value; return ucn; } laUiConditionNode *laStringExpression(char *Content){ laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode)); ucn->Type = LA_CONDITION_STRING; strSafeSet(&ucn->String, Content); return ucn; } laUiConditionNode *laAnd(laUiConditionNode *Expression1, laUiConditionNode *Expression2){ laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode)); ucn->Type = LA_CONDITION_AND; ucn->Expression1 = Expression1; ucn->Expression2 = Expression2; return ucn; } laUiConditionNode *laOr(laUiConditionNode *Expression1, laUiConditionNode *Expression2){ laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode)); ucn->Type = LA_CONDITION_OR; ucn->Expression1 = Expression1; ucn->Expression2 = Expression2; return ucn; } laUiConditionNode *laNot(laUiConditionNode *Expression1){ laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode)); ucn->Type = LA_CONDITION_NOT; ucn->Expression1 = Expression1; return ucn; } laUiConditionNode *laEqual(laUiConditionNode *Expression1, laUiConditionNode *Expression2){ laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode)); ucn->Type = LA_CONDITION_EQ; ucn->Expression1 = Expression1; ucn->Expression2 = Expression2; return ucn; } laUiConditionNode *laGreaterThan(laUiConditionNode *Expression1, laUiConditionNode *Expression2){ laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode)); ucn->Type = LA_CONDITION_GT; ucn->Expression1 = Expression1; ucn->Expression2 = Expression2; return ucn; } laUiConditionNode *laLessThan(laUiConditionNode *Expression1, laUiConditionNode *Expression2){ laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode)); ucn->Type = LA_CONDITION_LT; ucn->Expression1 = Expression1; ucn->Expression2 = Expression2; return ucn; } laUiConditionNode *laGreaterEqual(laUiConditionNode *Expression1, laUiConditionNode *Expression2){ laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode)); ucn->Type = LA_CONDITION_GE; ucn->Expression1 = Expression1; ucn->Expression2 = Expression2; return ucn; } laUiConditionNode *laLessEqual(laUiConditionNode *Expression1, laUiConditionNode *Expression2){ laUiConditionNode *ucn = memAcquireSimple(sizeof(laUiConditionNode)); ucn->Type = LA_CONDITION_LE; ucn->Expression1 = Expression1; ucn->Expression2 = Expression2; return ucn; } int la_GetIntConditionValue(laUiConditionNode *Expression){ if (Expression->Type != LA_CONDITION_INT) return 0; return Expression->IntValue; } real la_GetFloatConditionValue(laUiConditionNode *Expression){ if (Expression->Type != LA_CONDITION_FLOAT) return 0; return Expression->FloatValue; } char *la_GetStringConditionValue(laUiConditionNode *Expression){ return Expression->String->Ptr; } int la_DoCompare(int CompMode, int Mode1, int i1, real f1, char *s1, void *p1, int Mode2, int i2, real f2, char *s2, void *p2){ switch (Mode1){ case LA_PROP_ENUM: case LA_PROP_INT: case LA_CONDITION_INT: switch (Mode2){ case LA_PROP_ENUM: case LA_PROP_INT: case LA_CONDITION_INT: switch (CompMode){ case LA_CONDITION_GE: return (i1 >= i2); case LA_CONDITION_GT: return (i1 > i2); case LA_CONDITION_EQ: return (i1 == i2); case LA_CONDITION_LT: return (i1 < i2); case LA_CONDITION_LE: return (i1 <= i2); } case LA_PROP_FLOAT: case LA_CONDITION_FLOAT: switch (CompMode){ case LA_CONDITION_GE: return ((real)i1 >= f2); case LA_CONDITION_GT: return ((real)i1 > f2); case LA_CONDITION_EQ: return ((real)i1 >= f2 - 0.0001 && (real)i1 <= f2 + 0.0001); case LA_CONDITION_LT: return ((real)i1 < f2); case LA_CONDITION_LE: return ((real)i1 <= f2); } case LA_PROP_SUB: if (CompMode == LA_CONDITION_EQ) return i1 == (int)p2; default: return 0; } case LA_PROP_FLOAT: case LA_CONDITION_FLOAT: switch (Mode2){ case LA_PROP_INT: case LA_PROP_ENUM: case LA_CONDITION_INT: switch (CompMode){ case LA_CONDITION_GE: return (f1 >= (real)i2); case LA_CONDITION_GT: return (f1 > (real)i2); case LA_CONDITION_EQ: return (f1 + 0.0001 >= (real)i2 && f1 - 0.0001 <= (real)i2); case LA_CONDITION_LT: return (f1 < (real)i2); case LA_CONDITION_LE: return (f1 <= (real)i2); } case LA_PROP_FLOAT: case LA_CONDITION_FLOAT: switch (CompMode){ case LA_CONDITION_GE: return (f1 >= f2); case LA_CONDITION_GT: return (f1 > f2); case LA_CONDITION_EQ: return (f1 == f2); case LA_CONDITION_LT: return (f1 < f2); case LA_CONDITION_LE: return (f1 <= f2); } default: return 0; } case LA_PROP_STRING: case LA_CONDITION_STRING: switch (Mode2){ case LA_PROP_STRING: case LA_CONDITION_STRING: return strSame(s1, s2); default: return 0; } case LA_PROP_SUB: switch (Mode2){ case LA_PROP_SUB: return p1 == p2; case LA_CONDITION_INT: case LA_PROP_INT: case LA_PROP_ENUM: return (int)p1 == i2; default: return 0; } default: switch (CompMode){ case LA_CONDITION_GE: return (i1 >= i2); case LA_CONDITION_GT: return (i1 > i2); case LA_CONDITION_EQ: return (i1 == i2); case LA_CONDITION_LT: return (i1 < i2); case LA_CONDITION_LE: return (i1 <= i2); } } } int la_DoExpression(laUiConditionNode *Expression, int *IResult, real *FResult, char *_StrResult, void **PtrResult){ void *Instance = 0; int IValue1 = 0, IValue2 = 0; real FValue1 = 0, FValue2 = 0; void *Ptr1 = 0, *Ptr2 = 0; char Str1[128], Str2[128]={0}; char* StrResult=_StrResult; int Result1, Result2; laEnumItem *ei; laSubProp*sp; if (!Expression) return 0; Str1[0] = 0; Str2[0] = 0; laPropIterator pi = {0}; switch (Expression->Type){ case LA_CONDITION_PROP: if (!Expression->PP.LastPs){ (*IResult) = 0; return 0; } switch (Expression->PP.LastPs->p->PropertyType){ case LA_PROP_INT: *IResult = laGetInt(&Expression->PP); if (*IResult) return LA_CONDITION_INT; else return 0; case LA_PROP_FLOAT: *FResult = laGetFloat(&Expression->PP); if (*FResult) return 1; else return 0; break; case LA_PROP_STRING: laGetString(&Expression->PP, _StrResult, &StrResult); if (StrResult[0]) return 1; else return 0; break; case LA_PROP_ENUM: ei = laGetEnum(&Expression->PP); if (!ei) return 0; /*if(ei) */ *IResult = ei->Index; if (*IResult) return LA_CONDITION_INT; else return 0; break; case LA_PROP_SUB: sp=Expression->PP.LastPs->p; //if (sp->IsDetached){ *PtrResult = sp->Detached; if (sp->Detached) return 1; else return 0; } if (!Expression->PP.Go) Instance = Expression->PP.EndInstance; else Instance = laGetActiveInstance(Expression->PP.LastPs->p, Expression->PP.LastPs->UseInstance, &pi); if(!Instance){ Expression->PP.LastPs->p; if((!sp->GetActive) && (sp->Base.Offset<=0)){ Instance=laGetInstance(sp,Expression->PP.LastPs->UseInstance, &pi); } } *PtrResult = Instance; if (Instance) return 1; break; default: return 0; } break; case LA_CONDITION_INT: *IResult = Expression->IntValue; if (*IResult) return 1; else return 0; case LA_CONDITION_FLOAT: *FResult = Expression->FloatValue; if (*FResult) return 1; else return 0; case LA_CONDITION_STRING: if (Expression->String){ strCopyFull(StrResult, Expression->String->Ptr); return 1; }else return 0; case LA_CONDITION_TRUE: if (*IResult) *IResult = 1; return 1; case LA_CONDITION_FALSE: if (*IResult) *IResult = 0; return 0; default: Result1 = la_DoExpression(Expression->Expression1, &IValue1, &FValue1, &Str1, &Ptr1); switch (Expression->Type){ case LA_CONDITION_AND: if (Result1){ Result2 = la_DoExpression(Expression->Expression2, &IValue2, &FValue2, &Str2, &Ptr2); if (Result2) *IResult = 1; return (Result2); }else return 0; case LA_CONDITION_OR: if (!Result1){ Result2 = la_DoExpression(Expression->Expression2, &IValue2, &FValue2, &Str2, &Ptr2); if (Result2) *IResult = 1; return (Result2); }else return 1; case LA_CONDITION_NOT: return !Result1; default: Result2 = la_DoExpression(Expression->Expression2, &IValue2, &FValue2, &Str2, &Ptr2); return la_DoCompare(Expression->Type, (Expression->Expression1->Type == LA_CONDITION_PROP && Expression->Expression1->PP.LastPs) ? Expression->Expression1->PP.LastPs->p->PropertyType : Expression->Expression1->Type, IValue1, FValue1, Str1, Ptr1, (Expression->Expression2->Type == LA_CONDITION_PROP && Expression->Expression2->PP.LastPs) ? Expression->Expression2->PP.LastPs->p->PropertyType : Expression->Expression2->Type, IValue2, FValue2, Str2, Ptr2); } break; } return 0; } int la_DoSingleExpression(laUiConditionNode *Expression){ int a; real b; char c[128]={0}; void *p; if (!Expression) return 1; c[0] = 0; return la_DoExpression(Expression, &a, &b, c, &p); } void la_StepExpression(laUiConditionNode *e){ if (!e) return; switch (e->Type){ case LA_CONDITION_AND: case LA_CONDITION_OR: case LA_CONDITION_GE: case LA_CONDITION_GT: case LA_CONDITION_EQ: case LA_CONDITION_LT: case LA_CONDITION_LE: la_StepExpression(e->Expression1); la_StepExpression(e->Expression2); break; case LA_CONDITION_NOT: la_StepExpression(e->Expression1); break; case LA_CONDITION_PROP: la_StepPropPack(&e->PP); //if (e->PP.LastPs && e->PP.LastPs->p->Container && e->PP.LastPs->p->Container->Hyper){ // doesn't seem needed now with getuser la_UsePropPack(&e->PP, 1); //laUseDataBlock(e->PP.Go ? e->PP.LastPs->UseInstance : e->PP.EndInstance, e->PP.LastPs->p, MAIN.PropMatcherContextP->FrameDistinguish, MAIN.PropMatcherContextP, la_PropPanelUserRemover,1); //} break; default: break; } } void la_ConditionNodeFreeRecursive(laUiConditionNode *ucn){ if (!ucn) return; la_ConditionNodeFreeRecursive(ucn->Expression1); la_ConditionNodeFreeRecursive(ucn->Expression2); if (ucn->PP.LastPs) la_FreePropStepCache(ucn->PP.Go); if (ucn->String) strSafeDestroy(&ucn->String); if (ucn) memFree(ucn); } laUiItem *laOnConditionThat(laUiList *uil, laColumn *c, laUiConditionNode *Expression){ laUiItem *ui = memAcquireSimple(sizeof(laUiItem)); ui->C = c; ui->Type = &_LA_UI_CONDITION; la_ConditionerInit(ui, Expression); lstAppendItem(&uil->UiItems, ui); return ui; } laUiItem *laElse(laUiList *uil, laUiItem *Beginner){ laUiItem *ui = memAcquireSimple(sizeof(laUiItem)); laConditionUiExtraData *cued; ui->Type = &_LA_UI_CONDITION_ELSE; la_ConditionerInit(ui, 0); cued = ui->Extra; cued->EndUi = Beginner; ((laConditionUiExtraData *)Beginner->Extra)->ElseUi = ui; ui->C = Beginner->C; lstAppendItem(&uil->UiItems, ui); return ui; } laUiItem *laOnConditionToggle(laUiList *uil, laColumn *col, laUiDefineFunc define, int Remove, laPropPack *ExtraBase, laPropPack *ExtraThis, laWidget* Widget){ laUiItem *ui = memAcquireSimple(sizeof(laUiItem)); laConditionUiExtraData *cued; ui->Template = define; ui->C = col; ui->PP.RawThis = ExtraBase; ui->Page = ExtraThis; ui->Type = Widget? Widget->Type : _LA_UI_CONDITION_TOGGLE; la_ConditionerInit(ui, 0); cued = ui->Extra; //cued->Remove = Remove; ui->State = LA_UI_NORMAL; lstAppendItem(&uil->UiItems, ui); return ui; } laUiItem *laEndCondition(laUiList *uil, laUiItem *Beginner){ laUiItem *ui = memAcquireSimple(sizeof(laUiItem)); laConditionUiExtraData *cued; ui->Type = &_LA_UI_CONDITION_END; la_ConditionerInit(ui, 0); cued = ui->Extra; cued->EndUi = Beginner; ((laConditionUiExtraData *)Beginner->Extra)->EndUi = ui; ui->C = Beginner->C; lstAppendItem(&uil->UiItems, ui); return ui; } laUiList* laMakeMenuPageEx(laUiList* uil, laColumn* c, const char* Title, int flags) { laUiItem* ui = memAcquireSimple(sizeof(laUiItem)); laUiList* muil = memAcquireSimple(sizeof(laUiList)); ui->Type = _LA_UI_MENU_ROOT; strSafeSet(&ui->Display, Title); ui->State = LA_UI_NORMAL; ui->Flags|=LA_TEXT_ALIGN_CENTER; ui->C = c; ui->Flags|=flags; lstAppendItem(&uil->UiItems, ui); lstAppendItem(&ui->Subs, muil); return muil; } laUiList* laMakeMenuPage(laUiList* uil, laColumn* c, const char* Title) { return laMakeMenuPageEx(uil,c,Title,0); } laUiItem *laShowSeparator(laUiList *uil, laColumn *widest){ laUiItem *ui = memAcquireSimple(sizeof(laUiItem)); ui->Type = _LA_UI_ALIGN; ui->C = widest; lstAppendItem(&uil->UiItems, ui); return ui; } void laFixHeight(laUiList *uil, short Rows){ if (!uil) return; uil->HeightCoeff = Rows; } void laMakeUiListFromTemplate(laUiList *Into, laUiDefineFunc Template, laPropPack *PanelPP, laPropPack *PanelExtraPP, laPropPack *Base, laPropPack *Operator, laListHandle *ExtraColumns, int Context){ if (!ExtraColumns) return; Template(Into, Base, Operator, ExtraColumns->pFirst, Context); } laUiTemplate *laFindUiTemplate(char *Identifier){ laUiTemplate *uit; for (uit = MAIN.PanelTemplates.pFirst; uit; uit = uit->Item.pNext){ if (!strcmp(uit->Identifier->Ptr, Identifier)) return uit; } for (uit = MAIN.InitPanelTemplates.pFirst; uit; uit = uit->Item.pNext){ if (!strcmp(uit->Identifier->Ptr, Identifier)) return uit; } return 0; } void la_DestroyUiTemplate(laUiTemplate* uit){ strSafeDestroy(&uit->Identifier); strSafeDestroy(&uit->Title); laKeyMapItem* kmi; while(kmi=lstPopItem(&uit->KeyMap.Items)){ la_FreeKeyMapItem(kmi); } memFree(uit); } void la_DestroyCanvasTemplate(laCanvasTemplate* uit){ strSafeDestroy(&uit->Identifier); laKeyMapItem* kmi; while(kmi=lstPopItem(&uit->KeyMapper.Items)){ la_FreeKeyMapItem(kmi); } memFree(uit); } laUiTemplate *laRegisterUiTemplate(char *Identifier, char* Title, laUiDefineFunc func,laPanelDetachedPropFunc PropFunc, laUiDefineFunc header, char* NewCategory, int DefaultGLFormat, int DefaultW_RH, int DefaultH_RH){ laUiTemplate *uit = memAcquire(sizeof(laUiTemplate)); strSafeSet(&uit->Identifier, Identifier); strSafeSet(&uit->Title, Title); strSafeSet(&uit->CategoryName, NewCategory); uit->Define = func; uit->Header = header; uit->PropFunc = PropFunc; uit->DefaultGLFormat=DefaultGLFormat; uit->DefaultH_RH=DefaultH_RH?abs(DefaultH_RH):15; uit->DefaultW_RH=DefaultW_RH?abs(DefaultW_RH):15; if(MAIN.InitDone) lstAppendItem(&MAIN.PanelTemplates, uit); else lstAppendItem(&MAIN.InitPanelTemplates, uit); la_UDFAppendSharedTypePointer(Identifier, uit); return uit; } laCanvasTemplate *laRegisterCanvasTemplate(char *Identifier, char *ForContainer, laModalFunc ExtraModal, laCanvasDrawFunc Func, laUiDrawFunc SecondDraw, laUiInitFunc CustomInit, laUiDestroyFunc CustomDestroy){ laCanvasTemplate *t = memAcquire(sizeof(laCanvasTemplate)); strSafeSet(&t->Identifier, Identifier); t->Draw = Func; t->SecondDraw = SecondDraw; t->TargetContainerID = ForContainer; t->ExtraModal=ExtraModal; t->Init = CustomInit; t->Destroy = CustomDestroy; lstAppendItem(&MAIN.View2DTemplates, t); la_UDFAppendSharedTypePointer(Identifier, t); return t; } void laFinalizeUiTemplates(){ laUiTemplate *uit; laCanvasTemplate *u2d; for (u2d = MAIN.View2DTemplates.pFirst; u2d; u2d = u2d->Item.pNext){ if (u2d->TargetContainerID) u2d->TargetContainer = la_ContainerLookup(u2d->TargetContainerID); } } laPanel *la_FindFreePanelByTemplate(laWindow *w, const laUiTemplate *uit){ laPanel *p; for (p=w->Panels.pFirst; p; p = p->Item.pNext){ if (p->PanelTemplate==uit){ return p; } } return 0; } void la_DestroyUiItem(laUiItem *ui, int RemoveUsers){ laUiList *uil, *NextUil; for (uil = ui->Subs.pFirst; uil; uil = NextUil){ NextUil = uil->Item.pNext; lstRemoveItem(&ui->Subs, uil); la_DestroyUiList(uil, 0, RemoveUsers, 0); } la_StopUiOperatorService(ui); strSafeDestroy(&ui->ExtraInstructions);strDestroyStringSplitor(&ui->Instructions); strSafeDestroy(&ui->Display); //if (RemoveUsers && ui->PP.LastPs && ui->PP.LastPs->p->Container->Hyper) // { /*la_StopUsingPropPack(&ui->PP);*/ } //laStopUsingDataBlock(ui->PP.LastPs->UseInstance,ui->PP.LastPs->p,MAIN.PropMatcherContextP); la_FreePropStepCache(ui->PP.Go); //-------[Up Here], instance already been freed.XXXXXXXXXXXX!!!!!!!!!!1 if (ui->CompoundPPs.pFirst){laCompoundPP* CPP; while(CPP = lstPopItem(&ui->CompoundPPs)){ la_FreePropStepCache(CPP->PP.Go); memFree(CPP); } } if (ui->Type->Destroy) ui->Type->Destroy(ui); memFree(ui); } void la_DestroyUiList(laUiList *uil, int NoFree, int RemoveUsers, int OnlyRemoveUser){ laUiItem *ui, *NextUi; laColumn *col, *NextCol; if (!uil) return; for (ui = uil->UiItems.pFirst; ui; ui = NextUi){ NextUi = ui->Item.pNext; if(OnlyRemoveUser && RemoveUsers){ if (ui->PP.LastPs && ui->PP.LastPs->p->Container->Hyper) { /*la_StopUsingPropPack(&ui->PP);*/ } //laStopUsingDataBlock(ui->PP.LastPs->UseInstance,ui->PP.LastPs->p,MAIN.PropMatcherContextP); continue; } lstRemoveItem(&uil->UiItems, ui); la_DestroyUiItem(ui, RemoveUsers); } if(OnlyRemoveUser){ return; } for (col = uil->Columns.pFirst; col; col = NextCol){ NextCol = col->Item.pNext; lstRemoveItem(&uil->Columns, col); memFree(col); } strSafeDestroy(&uil->TabName); if (!NoFree) memFree(uil); } void la_DestroyTabPage(laUiItem *ui, laUiList *Tab, int RemoveUsers){ if(ui) lstRemoveItem(&ui->Subs, Tab); la_DestroyUiList(Tab, 1, RemoveUsers, 0); } void la_CreateUiAfter(laUiList *uil, laUiItem *after, laUiDefineFunc Define, laPropPack *Base, laPropPack *This, laColumn **ExtraColums){ laUiItem *Next = after->Item.pNext; laUiItem *Last = uil->UiItems.pLast; after->Item.pNext = 0; uil->UiItems.pLast = after; Define(uil, Base, This, ExtraColums, 0); if (Next) Next->Item.pPrev = uil->UiItems.pLast; ((laUiItem *)uil->UiItems.pLast)->Item.pNext = Next; if (Next != Last) uil->UiItems.pLast = Last; } //void la_RefreshExtraColumns(laUiItem* ui, int B,int FromL,int ToL,int FromR,int ToR){ // int i = 0; // int FromW=FromR-FromL, ToW=ToR-ToL; // if (!ui->ExtraColums) return; // for (i; ui->ExtraColums[i]; i++) { // laColumn* c = ui->ExtraColums[i]; // c->B = B; // c->IL = (c->IL - FromL) / FromW*ToW + ToL; // c->IR = (c->IR - FromL) / FromW*ToW + ToL; // } //} void la_PropPanelUserRemover(void* this_UNUSED, laItemUserLinker* iul){ laPanel* p = iul->Pointer.p; if(p->FrameDistinguish == iul->FrameDistinguish){ laRecalcPanel(p); } } void la_CalcUiItemInfluence(laListHandle *lst, laUiItem *ui){ laColumn *c = ui->C; laColumn *ic = lst->pFirst; c->B = ui->TB + (*ui->Type->Theme)->BP; for (ic; ic; ic = ic->Item.pNext){ if (((ic->IR > c->IL) && (ic->IL < c->IR)) || ((ic->IL < c->IR) && (ic->IR > c->IL))){ ic->B = ic->B < c->B ? c->B : ic->B; } } ic = ui->C; while (ic->Item.pPrev && (ic = ic->Item.pPrev)) ; for (ic; ic; ic = ic->Item.pNext){ if (((ic->IR > c->IL) && (ic->IL < c->IR)) || ((ic->IL < c->IR) && (ic->IR > c->IL))){ ic->B = ic->B < c->B ? c->B : ic->B; } } } void la_CalcUiTopInfluence(laListHandle *lst, laUiItem *ui){ laColumn *c = ui->C; laColumn *ic = lst->pFirst; c->B = ui->TB + (*ui->Type->Theme)->TP; for (ic; ic; ic = ic->Item.pNext){ if (((ic->IR > c->IL) && (ic->IL < c->IR)) || ((ic->IL < c->IR) && (ic->IR > c->IL))){ ic->B = ic->B < c->B ? c->B : ic->B; } } ic = ui->C; while (ic->Item.pPrev && (ic = ic->Item.pPrev)) ; for (ic; ic; ic = ic->Item.pNext){ if (((ic->IR > c->IL) && (ic->IL < c->IR)) || ((ic->IL < c->IR) && (ic->IR > c->IL))){ ic->B = ic->B < c->B ? c->B : ic->B; } } } int la_ResetUiColum(laColumn *c, laColumn *Top, int U, int L, int R, int LR, int repos){ //1=L,2=R int rep; int sp; int rev; int M=_LA_THEME_PANEL->LM+_LA_THEME_PANEL->RM; if (!c) return 0; sp = (c->SP * (R - L)) + L; rev = sp; /*if (U)*/ c->B = U; if (LR == 1){ c->IL = L; c->IR = sp; if (repos){ c->IR = repos; }else if (c->MaxW*LA_RH && c->IR - c->IL > c->MaxW*LA_RH+M){ c->IR = c->IL + c->MaxW*LA_RH+M; rev = c->IR; } }else if (LR == 2){ c->IL = sp; c->IR = R; if (repos){ c->IL = repos; }else if (c->MaxW*LA_RH && c->IR - c->IL > c->MaxW*LA_RH+M){ c->IL = c->IR - c->MaxW*LA_RH-M; rev = c->IL; } }else if (LR == 0){ c->IL = L; c->IR = R; } if (c->LS && c->RS->MaxW == 0){ rep = la_ResetUiColum(c->LS, Top, U, c->IL, c->IR, 1, 0); la_ResetUiColum(c->RS, Top, U, c->IL, c->IR, 2, rep); c->LS->PreWidth = c->PreWidth * c->LS->SP; c->RS->PreWidth = c->PreWidth * (1 - c->RS->SP); }else if (c->RS && c->LS->MaxW == 0){ rep = la_ResetUiColum(c->RS, Top, U, c->IL, c->IR, 2, 0); la_ResetUiColum(c->LS, Top, U, c->IL, c->IR, 1, rep); c->LS->PreWidth = c->PreWidth * c->LS->SP; c->RS->PreWidth = c->PreWidth * (1 - c->RS->SP); } return rev; } STRUCTURE(laRowInfo){ int MaxW; int MinW; int UnitMinW; int NonExpandW; int TotalPadding; int Expand, Even; int ExpandAccum; int CountElements; int U,MaxB,L; laListHandle Elements; int LastNoHeight; }; STRUCTURE(laRowNode){ laListItem Item; laUiItem* ui; int GotW, LP, RP, H; int Expand; int UseLast; int WaitAnimation; }; int la_InitRowNode(laRowInfo* ri, laUiItem* ui, laBoxedTheme* bt){ ri->MaxW = ui->TR-ui->TL;//row node does not use margin ri->UnitMinW=LA_RH; ri->Expand=ui->State?1:0; ri->Even=ui->Flags?1:0; ri->U=ui->TU; ri->L=ui->TL; ri->MaxB=ui->TU; } void la_AddRowNode(laRowInfo* ri, laUiItem* ui, laBoxedTheme* bt, int H, int WaitAnimation){ laRowNode* rn=CreateNew(laRowNode); rn->LP=bt->LP;rn->RP=bt->RP; rn->GotW = (ui->Type->GetMinWidth?ui->Type->GetMinWidth(ui):(LA_RH)); rn->ui=ui; rn->H=H; rn->Expand=ui->Expand; rn->WaitAnimation=WaitAnimation; lstAppendItem(&ri->Elements, rn); if(ri->LastNoHeight){ ri->LastNoHeight=0; rn->UseLast=1; return; } if(ui->Flags&LA_UI_FLAGS_UNDERNEATH){ ri->LastNoHeight=1; }; if(!ri->UnitMinW){ri->UnitMinW=LA_RH;} ri->TotalPadding += (bt->LP+bt->RP); ri->MinW+=ri->UnitMinW; ri->NonExpandW+=rn->GotW; ri->ExpandAccum+=ui->Expand; ri->CountElements++; if(ui->Expand){ri->Expand=1;} if(ri->U+H+bt->BP>ri->MaxB){ri->MaxB=ri->U+H+bt->BP;} } int la_ShrinkableRowElements(laRowInfo* ri){ int count=0; for(laRowNode* rn=ri->Elements.pFirst;rn;rn=rn->Item.pNext){ if(rn->GotW<=ri->UnitMinW || rn->UseLast) continue; count++; } return count; } void la_RecordSocketRuntimePosition(laUiItem* ui); int la_CalculateRowExpand(laRowInfo* ri, laUiItem* ui_end){ int Available=ri->MaxW-ri->NonExpandW-ri->TotalPadding; int ShareCount=0, Additional=0, AdditionalRemaining=0, Shrinkable=0; real NodeAddFraction=0; if(Available<0){ ShareCount=1;// Shrinkable=la_ShrinkableRowElements(ri); Additional=(ri->MaxW-ri->MinW-ri->TotalPadding)/ri->CountElements; AdditionalRemaining = (ri->MaxW-ri->MinW-ri->TotalPadding)-Additional*ri->CountElements; }else{ if(!ri->Expand && Available>0){Available=0;} ShareCount=ri->ExpandAccum?ri->ExpandAccum:ri->CountElements; } if(!ShareCount) return 0; int PerNode = Available/ShareCount; int Remaining = Available-PerNode*ShareCount; int L = ri->L; int i=0; laRowNode* rn; for(rn=ri->Elements.pFirst;rn;rn=rn->Item.pNext){ laUiItem* ui=rn->ui; int NodeAdd, Node=rn->GotW; if(rn->UseLast){ laRowNode* prevrn=rn->Item.pPrev; laUiItem* prevui=prevrn->ui; rn->ui->TL=prevui->TL;rn->ui->TR=prevui->TR;rn->ui->TU=prevui->TU;rn->ui->TB=prevui->TB; continue; } if(Available>=0){ NodeAdd=ri->ExpandAccum?(PerNode*rn->Expand):PerNode; NodeAdd+=(iMaxW>=ri->MinW+ri->TotalPadding) { NodeAddFraction+=((rn->GotW>ri->UnitMinW)?(real)Available*(real)(rn->GotW-ri->UnitMinW)/(real)(ri->NonExpandW-ri->MinW):0); NodeAdd=(int)NodeAddFraction; NodeAddFraction-=NodeAdd; }else{ Node=ri->UnitMinW; NodeAdd=Additional+(i<-AdditionalRemaining?-1:0);i++; } } ui->TL = L + rn->LP; ui->TR = ui->TL + Node+NodeAdd; ui->TB = ui->TU + rn->H; L=ui->TR+rn->RP; if (!rn->WaitAnimation){ ui->L = ui->TL; ui->R = ui->TR; ui->U = ui->TU; ui->B = ui->TB; } if(ui->Type==_LA_UI_NODE_SOCKET){ la_RecordSocketRuntimePosition(ui); } } ui_end->TB = ui_end->Flags&LA_UI_FLAGS_UNDERNEATH?ri->U:ri->MaxB; while(rn=lstPopItem(&ri->Elements)){ FreeMem(rn); } memset(ri, 0, sizeof(laRowInfo)); } void la_RecordSocketRuntimePosition(laUiItem* ui){ laProp* p=ui->PP.LastPs->p; laPropContainer* pc=la_EnsureSubTarget(p,0); int sl,sr,su,sb; if(ui->Flags&LA_UI_SOCKET_LABEL_N){ sl=ui->TL; sr=ui->TR; su=ui->TU+LA_RH; } elif(ui->Flags&LA_UI_SOCKET_LABEL_S){ sl=ui->TL; sr=ui->TR; su=ui->TU; } elif(ui->Flags&LA_UI_SOCKET_LABEL_W){ sl=ui->TL+LA_2RH; sr=ui->TR; su=ui->TU; } elif(ui->Flags&LA_UI_SOCKET_LABEL_E){ sl=ui->TL; sr=ui->TR-LA_2RH; su=ui->TU; } else{ sl=ui->TL; su=ui->TU; sr=ui->TR; } sb=su+LA_RH; if(pc==LA_PC_SOCKET_OUT){ laNodeOutSocket* s=ui->PP.EndInstance; s->RuntimeX=(sl+sr)/2; s->RuntimeY=(su+sb)/2; }else{ laNodeInSocket* s=ui->PP.EndInstance; s->RuntimeX=(sl+sr)/2; s->RuntimeY=(su+sb)/2; laUseDataBlock(s, LA_PROP_SOCKET_SOURCE, MAIN.PropMatcherContextP->FrameDistinguish, MAIN.PropMatcherContextP, la_PropPanelUserRemover, 0); } } laUiList* la_GiveExistingPage(laListHandle* from, void* instance){ for(laUiList* uil=from->pFirst;uil;uil=uil->Item.pNext){ if(uil->Instance == instance){ lstRemoveItem(from,uil); return uil; } } return 0; } void la_SwitchThemeQuick(laTheme* t, laTheme* DefaultTheme); int la_UpdateUiListRecursive(laUiList *uil, int U, int L, int R, int B, int Fast, laPanel *ParentPanel){ laUiItem *ui; laListHandle TempPages={0}; laUiList* FoundUil; laBoxedTheme *bt; int Lowest = 0; int HyperValue = 0; int WaitAnimation; int RowMode=0; laRowInfo ri={0}; laBoxedTheme* pt=*(ParentPanel->BT); int _PL=-pt->LM,_PR=-pt->RM,_PT=-pt->TM,_PB=-pt->BM; int MaxR=0; if(!uil->Scale){uil->Scale=1;} uil->SaveScale=MAIN.UiScale; MAIN.UiScale*=uil->Scale; MAIN.ScaledUiRowHeight=MAIN.UiRowHeight*MAIN.UiScale; uil->TU = U;uil->TL = L;uil->TR = R;uil->TB = uil->TU; WaitAnimation = 0; if (!uil->Columns.pFirst && !uil->UiItems.pFirst) return U; la_ResetUiColum(uil->Columns.pFirst, uil->Columns.pFirst, U, L, R, 0, 0); for (ui = uil->UiItems.pFirst; ui;){ int SubB = 0; int H; WaitAnimation = 0; int NoGap=ui->Flags&LA_UI_FLAGS_NO_GAP; int NoHeight=ui->Flags&LA_UI_FLAGS_UNDERNEATH; //if (Fast && ui->C->B > B) { // //la_CalcUiItemInfluence(&uil->Colums, ui); // ui = ui->Item.pNext; // continue; //} if (!ui->Instructions){ if (ui->ExtraInstructions) strMakeInstructions(&ui->Instructions, ui->ExtraInstructions->Ptr); if (ui->AT && ui->AT->ExtraInstructions) strMakeInstructions(&ui->Instructions, ui->AT->ExtraInstructions); if (ui->PP.LastPs && ui->PP.LastPs->p->PropertyType == LA_PROP_OPERATOR){ laOperatorProp *ap = ui->PP.LastPs->p; if (!ap->OperatorType) ap->OperatorType = laGetOperatorType(ap->OperatorID); if (ap->OperatorType&&ap->OperatorType->ExtraInstructions) strMakeInstructions(&ui->Instructions, ap->OperatorType->ExtraInstructions); } } if (ui->PP.LastPs){ la_StepPropPack(&ui->PP); } la_UsePropPack(&ui->PP, 0); if (ui->CompoundPPs.pFirst){ for(laCompoundPP* CPP=ui->CompoundPPs.pFirst;CPP;CPP=CPP->Item.pNext){ la_StepPropPack(&CPP->PP); la_UsePropPack(&CPP->PP, 0); } } if(ui->Type==&_LA_UI_INVISIBLE){ ui=ui->Item.pNext; continue; } //if (ui->PP.LastPs && (HyperValue = ui->PP.LastPs->p->Container ? ui->PP.LastPs->p->Container->Hyper : 0)){ // laUseDataBlock(ui->PP.Go ? ui->PP.LastPs->UseInstance : ui->PP.RawThis->LastPs->UseInstance, ui->PP.LastPs->p, MAIN.PropMatcherContextP->FrameDistinguish, MAIN.PropMatcherContextP, la_PropPanelUserRemover, 0); //} if ((ui->AnimationDistinguish + 1) == ParentPanel->FrameDistinguish){ ParentPanel->Refresh |= LA_TAG_ANIMATION; laRefreshWindow(); WaitAnimation = 1; } ui->AnimationDistinguish = ParentPanel->FrameDistinguish; bt = (*ui->Type->Theme); if (ui->Type == &_LA_UI_CONDITION){ laConditionUiExtraData *cued = ui->Extra; la_StepExpression(cued->Expression); cued->IsTrue = la_DoSingleExpression(cued->Expression); if (!cued->IsTrue){ ui = cued->ElseUi ? cued->ElseUi : cued->EndUi; }else{ ui = ui->Item.pNext; } continue; }else if (ui->Type == &_LA_UI_CONDITION_END){ ui = ui->Item.pNext; continue; }else if (ui->Type == &_LA_UI_CONDITION_ELSE){ laConditionUiExtraData *cued = ((laConditionUiExtraData *)ui->Extra)->EndUi->Extra; if (cued->IsTrue) ui = cued->EndUi; else ui = ui->Item.pNext; continue; }else if (ui->Type == _LA_UI_CONDITION_TOGGLE){ laConditionUiExtraData *cued = ui->Extra; ui->TL = ui->C->IL + bt->LP; ui->TR = ui->C->IR - bt->RP; ui->TU = ui->C->B + bt->TP; ui->TB = ui->TU+LA_RH; if (!WaitAnimation){ ui->L = ui->TL; ui->R = ui->TR; ui->U = ui->TU; ui->B = ui->TB; } if(!RowMode){ la_CalcUiItemInfluence(&uil->Columns, ui); }else{ H = ui->Type->GetHeight ? ui->Type->GetHeight(ui) : 1; la_AddRowNode(&ri, ui, bt, H*LA_RH,WaitAnimation); } if (ui->State == LA_UI_NORMAL){ cued->IsTrue = 0; //if(cued->Remove && (ui->Item.pNext != cued->EndUi)) // la_DestroyUiRange(uil, ui->Item.pNext, cued->ElseUi?cued->ElseUi->Item.pPrev:cued->EndUi->Item.pPrev); ui = cued->ElseUi ? cued->ElseUi : cued->EndUi; }else{ cued->IsTrue = 1; //if (cued->Remove && (ui->Item.pNext == cued->EndUi || ui->Item.pNext==cued->ElseUi)) { // la_CreateUiAfter(uil, ui, ui->Template, ui->PP.RawThis, ui->Page, uil->Columns.pFirst); //} ui = ui->Item.pNext; } continue; } if (ui->Type == _LA_UI_ALIGN){ ui->TU = ui->C->B + bt->TP; ui->TB = ui->TU+LA_RH/5; ui->TL = ui->C->IL; ui->TR = ui->C->IR; if (ui->TB > Lowest) Lowest = ui->TB; if (!WaitAnimation){ ui->L = ui->TL; ui->R = ui->TR; ui->U = ui->TU; ui->B = ui->TB; } if(!RowMode){ la_CalcUiItemInfluence(&uil->Columns, ui); }else{ ui->Flags|=LA_UI_FLAGS_TRANSPOSE; H = ui->Type->GetHeight ? ui->Type->GetHeight(ui) : 1; la_AddRowNode(&ri, ui, bt, H*LA_RH,WaitAnimation); } ui = ui->Item.pNext; continue; } if (ui->Type == &_LA_UI_ROW_BEGIN){ ui->TU = ui->C->B; ui->TL = ui->C->IL; ui->TR = ui->C->IR; la_InitRowNode(&ri, ui, bt); RowMode=1; ui=ui->Item.pNext; continue; } if (ui->Type == &_LA_UI_ROW_END){ la_CalculateRowExpand(&ri, ui); la_CalcUiItemInfluence(&uil->Columns, ui); RowMode=0; ui=ui->Item.pNext; continue; } if(!RowMode){ ui->TL = ui->C->IL + (NoGap?_PL:bt->LP); ui->TR = ui->C->IR - (NoGap?_PR:bt->RP); } int GB=0; if (ui->Type == _LA_UI_FIXED_GROUP && ui->Page->HeightCoeff < 0 && ui->Flags&LA_UI_FLAGS_PREFER_BOTTOM){ GB=ui->Page->TB-ui->Page->PanY; } H = ui->Type->GetHeight ? ui->Type->GetHeight(ui) : 1; ui->TU = ui->C->B + (NoGap?_PT:bt->TP); if (H < 0){ if(B){ H = B + (H+1) * LA_RH - ui->TU+_PB+((H<-1)?_PT:0); } else{ H=LA_RH; } } else H *= LA_RH; ui->TB = ui->TU; int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL; if (ui->Type->ForType == LA_PROP_SUB && ui->PP.LastPs && ui->PP.LastPs->p && ui->PP.LastPs->p->PropertyType == LA_PROP_SUB && ui->Type != _LA_UI_CANVAS){ //DynamicCreation laPropIterator pi = {0}; laSubProp* uisp=ui->PP.LastPs->p; if (ui->Type == _LA_UI_COLLECTION){ //void* TInstance = ui->PP.Go?laGetInstance(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, &pi):ui->PP.EndInstance; void *TInstance = laGetInstance(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, &pi); ui->PP.EndInstance = TInstance; laUiList *iuil = ui->Subs.pFirst; laUiList *puil = iuil; int Row = 0, Col = 0, RowPriority = ui->SymbolID > 0 ? 1 : 0, ElementLimit = ui->SymbolID ? abs(ui->SymbolID) : 0; int Spread=ui->Expand>2?ui->Expand:0; if(Spread){ RowPriority=0; ElementLimit=0; } laUiDefineFunc Template = ui->Template ? ui->Template : laGetPropertyUiDefine(&ui->PP, TInstance); int Begin = ui->TB; int EL = ui->TL, ER = Spread?(Spread*LA_RH+ui->TL):ui->TR; int ElementB = ui->TU; real ElementWidth = ElementLimit ? 1.0f / ElementLimit : 1.0; int MaxB = ElementB; int CanGetTheme = laCanGetTheme(ui->PP.LastPs->p);laTheme* OriginalTheme=MAIN.CurrentTheme; int CanGetGap= laCanGetGap(ui->PP.LastPs->p); int Gap=0; int CanGetCategory= laCanGetCategory(ui->PP.LastPs->p); char _cat[256]; char* cat=_cat; int GotCategory=0,FirstIn=1; if (!ElementLimit) RowPriority = 0; if (!TInstance){ while (iuil){ puil = iuil->Item.pNext; la_DestroyTabPage(ui, iuil, 0); iuil = puil; } } while (TInstance){ if(uisp->UiFilter && (!uisp->UiFilter(ui->PP.LastPs->UseInstance, TInstance))){ TInstance = laGetNextInstance(ui->PP.LastPs->p, TInstance, &pi); Template = ui->Template?ui->Template:laGetPropertyUiDefine(&ui->PP, TInstance); ui->PP.EndInstance = TInstance; continue; } if(CanGetTheme){ laTheme* t=laGetUiTheme(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, ui->PP.EndInstance); la_SwitchThemeQuick(t, OriginalTheme); } if(CanGetGap){ int g=laGetUiGap(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, ui->PP.EndInstance); g=g<0?0:g; Gap=g*LA_RH; }else Gap=0; if(CanGetCategory){ _cat[0]=0; cat=_cat; GotCategory=0; laGetCategory(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, ui->PP.EndInstance, _cat, &cat); if(cat[0]) GotCategory=1; }else GotCategory=0; if(GotCategory){ Begin+=LA_RH*(FirstIn?1:1.5)+bt->TM; if (RowPriority){ Row += 1; Col=0; Begin = ElementB+bt->TM+LA_RH*(FirstIn?1:1.5)+bt->TM; } } FirstIn=0; if (ElementLimit){ EL = tnsInterpolate(ui->TL, ui->TR, (Col)*ElementWidth); ER = tnsInterpolate(ui->TL, ui->TR, (Col + 1) * ElementWidth); } while (iuil && iuil->Instance != TInstance){ if(FoundUil=la_GiveExistingPage(&TempPages, TInstance)){ lstInsertItemBefore(&ui->Subs, FoundUil, iuil); puil = FoundUil; }else{ puil = iuil->Item.pNext; lstRemoveItem(&ui->Subs, iuil); lstAppendItem(&TempPages, iuil); } iuil = puil; } if(!iuil){ if(FoundUil=la_GiveExistingPage(&TempPages, TInstance)){ lstAppendItem(&ui->Subs, FoundUil); iuil = FoundUil; } } if (!iuil){ la_AddInstancePage(ui, TInstance, 0); if(GotCategory){ strSafeSet(&ui->Page->TabName,cat); } la_CalcUiTopInfluence(&uil->Columns, ui); if (Template) laMakeUiListFromTemplate(ui->Page, Template, &ParentPanel->PP, &ParentPanel->PropLinkPP, &ui->PP, 0, &uil->Columns, ui->TemplateContext); SubB = la_UpdateUiListRecursive(ui->Page, Gap+Begin+(NoDecal?0:bt->TM), EL+(NoDecal?0:bt->LM), ER-(NoDecal?0:bt->RM), B, Fast, ParentPanel) +(NoDecal?0:bt->TM); ElementB = RowPriority ? (SubB > ElementB ? SubB : ElementB) : SubB; iuil = ui->Page->Item.pNext; }else{ la_CalcUiTopInfluence(&uil->Columns, ui); if(GotCategory){ strSafeSet(&iuil->TabName,cat); } SubB = la_UpdateUiListRecursive(iuil, Gap+Begin+(NoDecal?0:bt->TM), EL+(NoDecal?0:bt->LM), ER-(NoDecal?0:bt->RM), B, Fast, ParentPanel) + (NoDecal?0:bt->TM); ElementB = RowPriority ? (SubB > ElementB ? SubB : ElementB) : SubB; la_CalcUiItemInfluence(&uil->Columns, ui); iuil = iuil->Item.pNext; } TInstance = laGetNextInstance(ui->PP.LastPs->p, TInstance, &pi); Template = ui->Template?ui->Template:laGetPropertyUiDefine(&ui->PP, TInstance); ui->PP.EndInstance = TInstance; if(CanGetTheme){ la_SwitchThemeQuick(0, OriginalTheme); } if (RowPriority){ Col += 1; if (Col >= ElementLimit){ Col = 0; Row += 1; Begin = ElementB + bt->TM; } }elif(Spread){ EL+=Spread*LA_RH; ER+=Spread*LA_RH; }else{ Row += 1; Begin = ElementB + bt->TM; if (ElementLimit && Row >= ElementLimit){ Row = 0; Col += 1; Begin = ui->TU + bt->TM; } } ui->TB = ElementB; MaxB = MaxB < ElementB ? ElementB : MaxB; } while (iuil){ puil = iuil->Item.pNext; la_DestroyTabPage(ui, iuil, 0); iuil = puil; } while (iuil=lstPopItem(&TempPages)){ la_DestroyTabPage(0, iuil, 0); } ui->PP.EndInstance = laGetActiveInstance(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, &pi); ui->TB = MaxB; if(Spread){ ui->TR=ER-Spread*LA_RH; if(ui->TR>MaxR) MaxR=ui->TR; } if (!WaitAnimation){ ui->L = ui->TL; ui->R = ui->TR; ui->U = ui->TU; ui->B = ui->TB = MaxB; } }else if (ui->Type == _LA_UI_COLLECTION_SELECTOR || ui->Type == _LA_UI_COLLECTION_SINGLE){ if(ui->Flags&LA_UI_COLLECTION_SIMPLE_SELECTOR){ ui->TB=ui->TU+LA_RH; }else{ void *TInstance = laGetActiveInstanceStrict(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance); ui->PP.EndInstance = TInstance; laUiTemplate *Template = ui->Template ? ui->Template : laGetPropertyUiDefine(&ui->PP, TInstance); if(!Template) Template=laui_SubPropInfoDefault; //ui->Template = Template; int EraseWidth=(ui->Type == _LA_UI_COLLECTION_SELECTOR)?LA_RH:0; if (!ui->Subs.pFirst && TInstance){ la_AddInstancePage(ui, TInstance, 0); la_CalcUiTopInfluence(&uil->Columns, ui); laMakeUiListFromTemplate(ui->Page, Template, &ParentPanel->PP, &ParentPanel->PropLinkPP, &ui->PP, 0, &uil->Columns, ui->TemplateContext); SubB = la_UpdateUiListRecursive(ui->Page, ui->TB+(NoDecal?0:bt->TM), ui->TL+(NoDecal?0:bt->LM), ui->TR-(NoDecal?0:bt->RM)-EraseWidth, B, Fast, ParentPanel); ui->TB = SubB + (NoDecal?0:bt->BM); }else if (ui->Subs.pFirst){ if (!TInstance || TInstance != ui->Page->Instance){ la_DestroyTabPage(ui, ui->Subs.pFirst, 0); ui->Page = 0; if (TInstance){ la_AddInstancePage(ui, TInstance, 0); la_CalcUiTopInfluence(&uil->Columns, ui); laMakeUiListFromTemplate(ui->Page, Template, &ParentPanel->PP, &ParentPanel->PropLinkPP, &ui->PP, 0, &uil->Columns, ui->TemplateContext); SubB = la_UpdateUiListRecursive(ui->Page, ui->TB+(NoDecal?0:bt->TM), ui->TL+(NoDecal?0:bt->LM), ui->TR-(NoDecal?0:bt->RM)-EraseWidth, B, Fast, ParentPanel); ui->TB = SubB + (NoDecal?0:bt->TM); }else ui->TB = ui->TU + LA_RH + bt->BM; }else{ SubB = la_UpdateUiListRecursive(ui->Page, ui->TB+(NoDecal?0:bt->TM), ui->TL+(NoDecal?0:bt->LM), ui->TR-(NoDecal?0:bt->RM)-EraseWidth, B, Fast, ParentPanel); ui->TB = SubB + (NoDecal?0:bt->BM); } } if(ui->Type == _LA_UI_COLLECTION_SELECTOR && (ui->TB>(ui->TU+LA_RH*0.9))&&(ui->TBTU+(LA_RH*1.1))){ ui->TB=ui->TU+LA_RH; } } if (ui->TB-ui->TUTB = ui->TU + LA_RH; if (!WaitAnimation){ ui->L = ui->TL; ui->R = ui->TR; ui->U = ui->TU; ui->B = ui->TB; } } }else{ if (ui->Type != _LA_UI_COLLECTION && (ui->Subs.pFirst || ui->Page) && ui->Type != _LA_UI_MENU_ROOT){ if (ui->Type != _LA_UI_CANVAS){ int scrollw=ui->Page->ScrollerShownV?bt->RP*2+LA_SCROLL_W:0; la_CalcUiTopInfluence(&uil->Columns, ui); int first_in=((ui->Flags&LA_UI_FLAGS_PREFER_BOTTOM) && ui->Page->B==0); SubB = la_UpdateUiListRecursive(ui->Page, ui->TB + (ui->State == LA_UI_ACTIVE ? 0 : LA_RH)+(NoDecal?0:bt->TM), ui->TL+(NoDecal?0:bt->LM), ui->TR-(NoDecal?0:bt->RM)-scrollw, B, Fast, ParentPanel); ui->TB = (ui->Page->HeightCoeff > 0 ? ui->TU + ui->Page->HeightCoeff * LA_RH : (ui->Page->HeightCoeff < 0 ? B + (ui->Page->HeightCoeff+1) * LA_RH + (_PB+_PT)+(ui->Page->HeightCoeff==-2?_PB:0) : SubB)) + (NoDecal?0:bt->BM); int subh = ui->TB-ui->TU-LA_RH-bt->TM-bt->BM; if((ui->Page->TR>ui->TR-(NoDecal?0:bt->RM) && (!ui->Page->ScrollerShownH)) || (ui->Page->TR<=ui->TR-(NoDecal?0:bt->RM) && ui->Page->ScrollerShownH)){ ui->Page->ScrollerShownH=!ui->Page->ScrollerShownH; } if(ui->Page->AllowScale){ui->Page->ScrollerShownH=1;} if(ui->Page->ScrollerShownH){subh-=LA_SCROLL_W-bt->BM;} if((GB && ui->TB >= GB)||first_in){ ui->Page->PanY=(SubB-ui->TB-bt->BM); if(ui->Page->PanY<0)ui->Page->PanY=0; } if(ui->Page->HeightCoeff){ if((subhPage->TB-ui->Page->TU && (!ui->Page->ScrollerShownV)) || (subh>=ui->Page->TB-ui->Page->TU && ui->Page->ScrollerShownV)){ ui->Page->ScrollerShownV=!ui->Page->ScrollerShownV; ParentPanel->Refresh|=LA_TAG_RECALC_SCROLLER; laRefreshWindow(); } if(SubB-ui->Page->PanYTB-bt->BM-(ui->Page->ScrollerShownH?LA_SCROLL_W+bt->BM:0)){ ui->Page->PanY = (SubB-ui->TB-bt->BM+(ui->Page->ScrollerShownH?LA_SCROLL_W+bt->BM:0)); if(ui->Page->PanY<0){ui->Page->PanY=0;} //ParentPanel->Refresh|=LA_TAG_RECALC_SCROLLER; } } if(ui->Page->ScrollerShownH && !ui->Page->HeightCoeff){ ui->TB+=(bt->BP*2+LA_SCROLL_W); } }else{ laUiList *suil; if(!MAIN.CurrentWindow->MaximizedUi || ui!=MAIN.CurrentWindow->MaximizedUi){ la_CalcUiTopInfluence(&uil->Columns, ui); for (suil = ui->Subs.pFirst; suil; suil = suil->Item.pNext){ SubB = la_UpdateUiListRecursive(suil, ui->TB+(NoDecal?0:bt->TM), ui->TL+(NoDecal?0:bt->LM), ui->TR-(NoDecal?0:bt->RM), ui->TU+H, Fast, ParentPanel); } } ui->TB = ui->TU + H; } }else ui->TB = ui->TU + H; } if (ui->TB > Lowest && (!NoHeight)) Lowest = ui->TB + (bt ? (NoGap?_PB:bt->BP) : 0); if(!RowMode){ if(!NoHeight) la_CalcUiItemInfluence(&uil->Columns, ui); }else{ la_AddRowNode(&ri, ui, bt, H, WaitAnimation); } if (!WaitAnimation){ ui->L = ui->TL; ui->R = ui->TR; ui->U = ui->TU; ui->B = ui->TB; } if(ui->Type==_LA_UI_NODE_SOCKET){ la_RecordSocketRuntimePosition(ui); } ui = ui->Item.pNext; } uil->TR=MaxR>uil->TR?MaxR:uil->TR; if (uil->Columns.pFirst) uil->TB = ((laColumn *)uil->Columns.pFirst)->B; else uil->TB = Lowest; if (!WaitAnimation){ uil->L = uil->TL; uil->R = uil->TR; uil->U = uil->TU; uil->B = uil->TB; } MAIN.UiScale=uil->SaveScale; MAIN.ScaledUiRowHeight=MAIN.UiRowHeight*MAIN.UiScale; return uil->TB; } int la_AnimateSingleUiSize(int To, int *Now){ int Delta; if (To != *Now){ Delta = (To - (*Now)) * (MAIN.AnimationSpeed) * MAIN.LastFrameTime * 60; if (!Delta) Delta = To > (*Now) ? 1 : -1; *Now += Delta; return 1; }else return 0; } int la_AnimateUiListRecursive(laUiList *uil){ laUiItem *ui; int Again = 0; for (ui = uil->UiItems.pFirst; ui; ui = ui->Item.pNext){ int TB = ui->B, TU = ui->U, TL = ui->L, TR = ui->R, SB, SU, SL, SR; Again += (la_AnimateSingleUiSize(ui->TB, &ui->B) + la_AnimateSingleUiSize(ui->TU, &ui->U) + la_AnimateSingleUiSize(ui->TL, &ui->L) + la_AnimateSingleUiSize(ui->TR, &ui->R)); if (ui->Type == _LA_UI_COLLECTION_SELECTOR || ui->Type == _LA_UI_COLLECTION_SINGLE || (ui->PP.LastPs && ui->PP.LastPs->p && ui->PP.LastPs->p->PropertyType == LA_PROP_SUB && ui->Type != _LA_UI_CANVAS)){ laUiList *suil; for (suil = ui->Subs.pFirst; suil; suil = suil->Item.pNext){ Again += la_AnimateUiListRecursive(suil); } }else if (ui->Type != _LA_UI_COLLECTION && ui->Type != &_LA_UI_ROW_END && (ui->Subs.pFirst || ui->Page) && ui->Type != _LA_UI_MENU_ROOT){ Again += la_AnimateUiListRecursive(ui->Page); } } Again += (la_AnimateSingleUiSize(uil->TB, &uil->B) + la_AnimateSingleUiSize(uil->TU, &uil->U) + la_AnimateSingleUiSize(uil->TL, &uil->L) + la_AnimateSingleUiSize(uil->TR, &uil->R)); return Again; } int la_DrawUiItem(laUiItem *ui){ tnsUseNoTexture(); tnsColor4d(1, 1, 1, 1); tnsVertex2d(ui->L, ui->U); tnsVertex2d(ui->R, ui->U); tnsVertex2d(ui->R, ui->B); tnsVertex2d(ui->L, ui->B); tnsPackAs(GL_LINE_LOOP); } int la_DrawActiveUiItemOverlay(laUiItem *ui){ tnsUseNoTexture(); tnsColor4d(1, 1, 1, 1); tnsVertex2d(ui->L - 1, ui->U - 1); tnsVertex2d(ui->R + 1, ui->U - 1); tnsVertex2d(ui->R + 1, ui->B + 1); tnsVertex2d(ui->L - 1, ui->B + 1); tnsPackAs(GL_LINE_LOOP); } int la_UiInBound(laUiItem *ui, int L, int R, int U, int B){ if (ui->R <= L || ui->L >= R || ui->U >= B || ui->B <= U) return 0; return 1; } int la_UiInBoundEx(laUiItem *ui, laUiListDraw *uild){ laUiListDrawItem *uildi = uild->Items.pFirst; laUiList *Target = uildi->Target; int L, R, U, B; if (!Target) return la_UiInBound(ui, uildi->L, uildi->R, uildi->U, uildi->B); L = Target->L + Target->PanX + uildi->DifX; R = Target->L + Target->PanX + uildi->DifX + (uildi->R - uildi->L); B = Target->U + Target->PanY + uildi->DifY + (uildi->B - uildi->U); U = Target->U + Target->PanY + uildi->DifY; return la_UiInBound(ui, L, R, U, B); } int la_UiListInBoundEx(laUiList *uil, laUiListDraw *uild){ laUiListDrawItem *uildi = uild->Items.pFirst; laUiList *Target = uildi->Target; int L, R, U, B; if (Target){ L = Target->L + Target->PanX + uildi->DifX; R = Target->L + Target->PanX + uildi->DifX + (uildi->R - uildi->L); B = Target->U + Target->PanY + uildi->DifY + (uildi->B - uildi->U); U = Target->U + Target->PanY + uildi->DifY; if (uil->R <= L || uil->L >= R || uil->U >= B || uil->B <= U) return 0; return 1; }else{ if (uil->R <= uildi->L || uil->L >= uildi->R || uil->U >= uildi->B || uil->B <= uildi->U) return 0; return 1; } } laUiItem *la_FindUiWithMark(laUiList *uil, char *mark){ laUiItem *ui = uil->UiItems.pFirst; while (!strGetArgument(ui->Instructions, mark)) ui = ui->Item.pNext; return ui; } laUiList *la_FindSubListWithInstance(laUiItem *ui, void *Instance){ laUiList *uil; for (uil = ui->Subs.pFirst; uil; uil = uil->Item.pNext){ if (uil->Instance == Instance) return uil; } return uil; } void la_DrawUiListArrows(laUiList *uil, int L, int R, int U, int B, real* color){ int mx=(L+R)/2; int my=(U+B)/2; if(uil->R-uil->PanX>R){ tnsDrawStringAuto("▷", color, R-LA_RH, R, my-LA_RH2, LA_TEXT_ALIGN_RIGHT); } if(uil->L-uil->PanXU-uil->PanYB-uil->PanY>B){ tnsDrawStringAuto("▽", color, mx-LA_RH2, mx+LA_RH2, B-LA_RH, LA_TEXT_ALIGN_CENTER); } tnsFlush(); } void la_DrawUiListScrollerV(laUiList *uil, int DisplayOffset, int TotalH, int DisplayH, int UiR){ if(!uil->ScrollerShownV) return; int W = LA_SCROLL_W, RM=_LA_THEME_PANEL->RM; int Len = (int)((real)DisplayH / (real)TotalH * (real)DisplayH); int Offset = (int)((real)DisplayOffset / (real)TotalH * (real)DisplayH); int U = uil->U + Offset; int B = U + Len; int L = UiR - RM*2 - W; int R = L + W; if (B > U + DisplayH) B = U + DisplayH; if (U < uil->U) U = uil->U; if (B <= uil->U || U >= uil->B) return; if (B > uil->U + DisplayH) B = uil->U + DisplayH; if (U < uil->U) U = uil->U; tnsUseNoTexture(); laBoxedTheme* bt=_LA_THEME_PANEL; real* color=laThemeColor(bt, LA_BT_TEXT); tnsColor4d(LA_COLOR3(color), 0.2); tnsVertex2d(R-RM, uil->U); tnsVertex2d(L+RM, uil->U); tnsVertex2d(L+RM, uil->U + DisplayH); tnsVertex2d(R-RM, uil->U + DisplayH); tnsPackAs(GL_TRIANGLE_FAN); tnsColor4d(LA_COLOR3(color), 0.5); tnsVertex2d(R-RM, uil->U); tnsVertex2d(L+RM, uil->U); tnsVertex2d(L+RM, uil->U + DisplayH); tnsVertex2d(R-RM, uil->U + DisplayH); tnsPackAs(GL_LINE_LOOP); tnsColor4d(LA_COLOR3(color), 1); tnsVertex2d(R, U); tnsVertex2d(L, U); tnsVertex2d(L, B); tnsVertex2d(R, B); tnsPackAs(GL_TRIANGLE_FAN); int HU=(U+B)/2+LA_RH2; tnsDrawStringAuto("☰",laThemeColor(bt, LA_BT_BORDER),L-100,R+100,HU,LA_TEXT_REVERT_Y|LA_TEXT_ALIGN_CENTER); tnsFlush(); } void la_DrawUiListScrollerH(laUiList *uil, int DisplayOffset, int TotalW, int DisplayW, int UiB){ if(!uil->ScrollerShownH) return; int W = LA_SCROLL_W,RM=_LA_THEME_PANEL->RM; int Len = (int)((real)DisplayW / (real)TotalW * (real)DisplayW); int Offset = (int)((real)DisplayOffset / (real)TotalW * (real)DisplayW); int L = uil->L + Offset; int R = L + Len; int U = UiB - RM - W; int B = U + W; if (B > U + DisplayW) B = U + DisplayW; if (U < uil->U) U = uil->U; if (R <= uil->L || L >= uil->R) return; if (R > uil->L + DisplayW) R = uil->L + DisplayW; if (L < uil->L) L = uil->L; tnsUseNoTexture(); laBoxedTheme* bt=_LA_THEME_PANEL; real* color=laThemeColor(bt, LA_BT_TEXT); tnsColor4d(LA_COLOR3(color), 0.2); tnsVertex2d(uil->L,U+RM); tnsVertex2d(uil->L,B-RM); tnsVertex2d(uil->L + DisplayW,B-RM); tnsVertex2d(uil->L + DisplayW,U+RM); tnsPackAs(GL_TRIANGLE_FAN); tnsColor4d(LA_COLOR3(color), 0.5); tnsVertex2d(uil->L,U+RM); tnsVertex2d(uil->L,B-RM); tnsVertex2d(uil->L + DisplayW,B-RM); tnsVertex2d(uil->L + DisplayW,U+RM); tnsPackAs(GL_LINE_LOOP); tnsColor4d(LA_COLOR3(color), 1); tnsVertex2d(R, U); tnsVertex2d(L, U); tnsVertex2d(L, B); tnsVertex2d(R, B); tnsPackAs(GL_TRIANGLE_FAN); int HU=(U+B)/2+LA_RH2; tnsDrawStringAuto("↔",laThemeColor(bt, LA_BT_BORDER),L-100,R+100,HU,LA_TEXT_REVERT_Y|LA_TEXT_ALIGN_CENTER); tnsFlush(); } void la_DrawInstanceBkg(laUiList *uil, real* color, int LP, int RP){ tnsUseNoTexture(); tnsColor4dv(color); tnsVertex2d(uil->L-LP, uil->U); tnsVertex2d(uil->R+RP, uil->U); tnsVertex2d(uil->R+RP, uil->B); tnsVertex2d(uil->L-LP, uil->B); tnsPackAs(GL_TRIANGLE_FAN); } void la_InitSocketRecord(laUiListDraw* uild, laUiList* container){ laSocketRecord* sr; while(sr=lstPopItem(&uild->SocketRecord)){ memFree(sr); } uild->WiresContainer=container; } void la_GetUiListOffsetUntil(laUiListDraw* uild, int* X, int* Y){ *X=*Y=0; for(laUiListDrawItem* lip=uild->Items.pLast;lip&&lip->Target;lip=lip->Item.pPrev){ if(lip->Target==uild->WiresContainer) break; laUiList* uil=lip->Target; *X+=uil->PanX; *Y+=uil->PanY; } } void la_RecordSocket(laUiListDraw* uild, laUiList* uil, laUiItem* ui){ laProp* p=ui->PP.LastPs->p; laPropContainer* pc=la_EnsureSubTarget(p,0); int PanX, PanY; if(pc==LA_PC_SOCKET_OUT){ laNodeOutSocket* s=ui->PP.EndInstance; la_GetUiListOffsetUntil(uild, &s->RuntimePX, &s->RuntimePY); }else{ laNodeInSocket* s=ui->PP.EndInstance; if(!s->Source) return; laSocketRecord* sr=memAcquireSimple(sizeof(laSocketRecord)); sr->In=s; sr->Out=s->Source; lstAppendItem(&uild->SocketRecord, sr); } } void la_RegenerateWireColors(){ if(MAIN.WireColorCache) free(MAIN.WireColorCache); laTheme* t=MAIN.CurrentTheme; MAIN.WireColorCache = calloc(1, sizeof(real)*4*MAIN.WireColorSlices); real hsl[]={0.0,0.8,0.6}; hsl[1]=t->WireSaturation; hsl[2]=t->WireBrightness; for(int i=0;iWireTransparency; } } void la_SendWireVerts(real x1, real y1, real x2, real y2, real circle_r){ tnsVector2d v1,vi,v2,v1s,v2s; real dist=0; v1[0]=x1; v1[1]=y1; v2[0]=x2; v2[1]=y2; tnsInterpolate2dv(v1,v2,0.5,vi); if(MAIN.WireSaggyness>0.01){ dist=tnsDist2dv(v1,v2); vi[1]+=dist*MAIN.WireSaggyness; } tnsVectorMinus2d(v1s,vi,v1); if(tnsLength2d(v1s)<1e-3){ v1s[0]=-1; v1s[1]=0; }else{ tnsNormalizeSelf2d(v1s); } tnsVectorMultiSelf2d(v1s,circle_r); tnsVectorMinus2d(v2s,vi,v2); if(tnsLength2d(v2s)<1e-3){ v2s[0]=1; v2s[1]=0; }else{ tnsNormalizeSelf2d(v2s); } tnsVectorMultiSelf2d(v2s,circle_r); tnsVectorAccum2d(v1, v1s); tnsVectorAccum2d(v2, v2s); if(MAIN.WireSaggyness<0.01){ tnsVertex2d(v1[0],v1[1]); tnsVertex2d(v2[0],v2[1]); return; } int seglen=3, steps=dist/seglen+1; real step=1.0f/steps; tnsVertex2d(v1[0],v1[1]); for(int i=1;i<=steps;i++){ real ratio=i==steps?1.0f:step*i; tnsInterpolateTripple2d(v1,vi,v2,ratio, v1s); tnsVertex2d(v1s[0],v1s[1]); } } void la_DrawNodeWires(laUiListDraw* uild){ if(!uild->SocketRecord.pFirst && !MAIN.tNodeIn->Source){ return; } laBoxedTheme* bt=_LA_THEME_SOCKET; tnsUseNoTexture(); #define _RSLICES 16 real v[_RSLICES*4]; int idx[_RSLICES*2+2]; real r=LA_RH2/TNS_MAX2(uild->WiresContainer->Scale,1); for(laSocketRecord*sr=uild->SocketRecord.pFirst;sr;sr=sr->Item.pNext){ int cid=sr->In->ColorId%MAIN.WireColorSlices*4; int inx=sr->In->RuntimeX+sr->In->RuntimePX, iny=sr->In->RuntimeY+sr->In->RuntimePY; int outx=sr->Out->RuntimeX+sr->Out->RuntimePX, outy=sr->Out->RuntimeY+sr->Out->RuntimePY; if(sr->Out==MAIN.tNodeOut){ outx=inx+MAIN.tNodeOut->RuntimeX+MAIN.tNodeOut->RuntimePX; outy=iny+MAIN.tNodeOut->RuntimeY+MAIN.tNodeOut->RuntimePY; } tnsMakeRing2d(v,idx,_RSLICES, inx, iny, r, r*0.6); tnsVertexArray2d(v,_RSLICES*2); tnsIndexArray(idx, _RSLICES*2+2); tnsColor4d(LA_COLOR3(&MAIN.WireColorCache[cid]),1); tnsPackAs(GL_TRIANGLE_STRIP); tnsMakeRing2d(v,idx,_RSLICES, outx, outy, r, r*0.6); tnsVertexArray2d(v,_RSLICES*2); tnsIndexArray(idx, _RSLICES*2+2); tnsColor4d(LA_COLOR3(&MAIN.WireColorCache[cid]),1); tnsPackAs(GL_TRIANGLE_STRIP); } if(MAIN.tNodeIn->Source){ laNodeInSocket* ins=MAIN.tNodeIn; laNodeOutSocket* outs=ins->Source; int cid=ins->ColorId%MAIN.WireColorSlices*4; int outx=outs->RuntimeX+outs->RuntimePX, outy=outs->RuntimeY+outs->RuntimePY; int inx=ins->RuntimeX+ins->RuntimePX+outx, iny=ins->RuntimeY+ins->RuntimePY+outy; tnsMakeRing2d(v,idx,_RSLICES, inx, iny, r, r*0.6); tnsVertexArray2d(v,_RSLICES*2); tnsIndexArray(idx, _RSLICES*2+2); tnsColor4d(LA_COLOR3(&MAIN.WireColorCache[cid]),1); tnsPackAs(GL_TRIANGLE_STRIP); tnsMakeRing2d(v,idx,_RSLICES, outx, outy, r, r*0.6); tnsVertexArray2d(v,_RSLICES*2); tnsIndexArray(idx, _RSLICES*2+2); tnsColor4d(LA_COLOR3(&MAIN.WireColorCache[cid]),1); tnsPackAs(GL_TRIANGLE_STRIP); } #undef _RSLICES tnsFlush(); int ww=MAIN.WireThickness*TNS_MIN2(uild->WiresContainer->Scale,1); glLineWidth(ww); for(laSocketRecord*sr=uild->SocketRecord.pFirst;sr;sr=sr->Item.pNext){ int cid=sr->In->ColorId%MAIN.WireColorSlices*4; int inx=sr->In->RuntimeX+sr->In->RuntimePX, iny=sr->In->RuntimeY+sr->In->RuntimePY; int outx=sr->Out->RuntimeX+sr->Out->RuntimePX, outy=sr->Out->RuntimeY+sr->Out->RuntimePY; if(sr->Out==MAIN.tNodeOut){ outx=inx+MAIN.tNodeOut->RuntimeX+MAIN.tNodeOut->RuntimePX; outy=iny+MAIN.tNodeOut->RuntimeY+MAIN.tNodeOut->RuntimePY; } la_SendWireVerts(inx, iny, outx, outy, r*0.9); tnsColor4dv(&MAIN.WireColorCache[cid]); tnsPackAs(GL_LINE_STRIP); } if(MAIN.tNodeIn->Source){ laNodeInSocket* ins=MAIN.tNodeIn; laNodeOutSocket* outs=ins->Source; int cid=ins->ColorId%MAIN.WireColorSlices*4; int outx=outs->RuntimeX+outs->RuntimePX, outy=outs->RuntimeY+outs->RuntimePY; int inx=ins->RuntimeX+ins->RuntimePX+outx, iny=ins->RuntimeY+ins->RuntimePY+outy; la_SendWireVerts(inx, iny, outx, outy, r*0.9); tnsColor4dv(&MAIN.WireColorCache[cid]); tnsPackAs(GL_LINE_STRIP); } tnsFlush(); glLineWidth(1); la_InitSocketRecord(uild,0); } void la_SwitchThemeQuick(laTheme* t, laTheme* DefaultTheme){ if(!DefaultTheme){return;} MAIN.CurrentTheme = t?t:DefaultTheme; t=MAIN.CurrentTheme; for(laBoxedTheme* bt = t->BoxedThemes.pFirst;bt;bt=bt->Item.pNext){ (*bt->BackRef) = bt; } } int la_DrawUiListRecursive(laUiListDraw *uild, laUiList *uil, int L, int R, int U, int B, int LimH, int ConditionStackLevel, int GlobalX, int GlobalY, int RegisterNodes){ laUiItem *ui; laBoxedTheme *bt; laUiList *sub; laUiListDrawItem *uildi; int Ret = 0; if (!uil) return 0; //printf("d %d\n",MAIN.CurrentPanel->FrameDistinguish); ui = uil->UiItems.pFirst; if(uil->PanY<0){uil->PanY=0;} if (!la_SetUpUiListMatrix(uild, uil, L, R, LimH, B - U, GlobalX, GlobalY)) return 0; uil->SaveScale=MAIN.UiScale; MAIN.UiScale*=uil->Scale; MAIN.ScaledUiRowHeight=MAIN.UiRowHeight*MAIN.UiScale; for (; ui;){ if(ui->Type==&_LA_UI_INVISIBLE){ ui=ui->Item.pNext; continue; } bt = ui->Type->Theme ? (*ui->Type->Theme) : 0; if (ui->Type == &_LA_UI_CONDITION){ laConditionUiExtraData *cued = ui->Extra; la_StepExpression(cued->Expression); cued->IsTrue = la_DoSingleExpression(cued->Expression); if (!cued->IsTrue){ ui = cued->ElseUi ? cued->ElseUi : cued->EndUi; }else{ ui = ui->Item.pNext; } continue; }else if (ui->Type == &_LA_UI_CONDITION_END){ ui = ui->Item.pNext; continue; }else if (ui->Type == &_LA_UI_CONDITION_ELSE){ laConditionUiExtraData *cued = ((laConditionUiExtraData *)ui->Extra)->EndUi->Extra; if (cued->IsTrue) ui = cued->EndUi; else ui = ui->Item.pNext; continue; }else if (ui->Type == _LA_UI_CONDITION_TOGGLE){ laConditionUiExtraData *cued = ui->Extra; ui->Type->Draw(ui, LA_RH); if (ui->State == LA_UI_NORMAL){ cued->IsTrue = 0; ui = cued->ElseUi ? cued->ElseUi : cued->EndUi; }else{ cued->IsTrue = 1; ui = ui->Item.pNext; } continue; } if (ui->AnimationDistinguish != MAIN.CurrentPanel->FrameDistinguish) Ret = 1; int NeedDraw=0; if (la_UiInBoundEx(ui, uild)){ NeedDraw=1; } if(NeedDraw){ if (!ui->Type->Draw){ la_DrawUiItem(ui); tnsFlush(); }else{ ui->Type->Draw(ui, LA_RH); } if (ui->Type->Tag & LA_UI_TAG_IS_OFFSCREEN){ tnsFlush(); tnsDrawToOffscreen(MAIN.CurrentPanel->OffScr, 1, 0); tnsResetViewMatrix(); } if (ui->Type->Tag & (LA_UI_TAG_NEED_REBUILD)){ la_RebuildCurrentUiListMatrix(uild, uil, LimH, B - U); if (ui->CanvasTemplate->SecondDraw) ui->CanvasTemplate->SecondDraw(ui, LA_RH); tnsFlush(); } } if(NeedDraw || RegisterNodes){ if (RegisterNodes && ui->Type==_LA_UI_NODE_SOCKET){ la_RecordSocket(uild,uil,ui); } if (ui->Type == _LA_UI_FIXED_GROUP || ui->Type == _LA_UI_TAB || ui->Type == _LA_UI_COLLECTION_SINGLE || ui->Type == _LA_UI_COLLECTION_SELECTOR && (ui->Subs.pFirst || ui->Page)){ if (!ui->Page){ ui = ui->Item.pNext; continue; } tnsFlush(); int DoNodes=RegisterNodes; int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL; if(ui->Flags&LA_UI_FLAGS_NODE_CONTAINER){ la_InitSocketRecord(uild, ui->Page); DoNodes=1; } Ret += la_DrawUiListRecursive(uild, ui->Page, ui->L+(NoDecal?0:bt->LM), ui->R-(NoDecal?0:bt->RM), U, B, (ui->Page->HeightCoeff ? ui->B - ui->Page->U : 10000) -(NoDecal?0:bt->LM), ConditionStackLevel, GlobalX, GlobalY, DoNodes); if (ui->Page->ScrollerShownH){ la_DrawUiListScrollerH(ui->Page, ui->Page->PanX, ui->Page->R-ui->Page->L-bt->RM-bt->LM, ui->R-ui->Page->L-bt->RM-bt->LM-(ui->Page->ScrollerShownV?LA_SCROLL_W:0),ui->B); } if (ui->Page->HeightCoeff) la_DrawUiListScrollerV(ui->Page, ui->Page->PanY, ui->Page->B-ui->Page->U-(NoDecal?0:bt->TM-bt->BM), ui->B-ui->Page->U-(NoDecal?0:bt->TM-bt->BM)-(ui->Page->ScrollerShownH?LA_SCROLL_W+bt->RM:0),ui->R); if (ui->Page->AllowScale){ la_DrawUiListArrows(ui->Page,ui->L, ui->R, ui->Page->U, ui->B-LA_SCROLL_W-bt->BM*2, laThemeColor(bt, LA_BT_BORDER)); } }elif (ui->Type == _LA_UI_COLLECTION){ int CanGetState = laCanGetState(ui->PP.LastPs->p); int CanGetTheme = laCanGetTheme(ui->PP.LastPs->p);laTheme* OriginalTheme=MAIN.CurrentTheme; void *Active = laGetActiveInstanceStrict(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance); void* SaveInstance = ui->PP.EndInstance; for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){ int State; ui->PP.EndInstance = sub->Instance; if ((!la_UiListInBoundEx(sub, uild)) && (!RegisterNodes)) continue; if(NeedDraw){ int drawn=0; if (!(ui->Flags&LA_UI_COLLECTION_NO_HIGHLIGHT) && sub->Instance == Active){ la_DrawInstanceBkg(sub, laAccentColor(LA_BT_NORMAL),bt->LP,bt->RP); drawn=1; } if (CanGetState && !drawn){ State = laGetUiState(ui->PP.LastPs->p, sub->Instance); if(State >= 0){ la_DrawInstanceBkg(sub, laAccentColor(State),bt->LP,bt->RP); } } } if(sub->TabName && sub->TabName->Ptr){ int NoDecal=ui->Flags&LA_UI_FLAGS_NO_DECAL; int NoGap=ui->Flags&LA_UI_FLAGS_NO_GAP; tnsDrawStringAuto(transLate(sub->TabName->Ptr),laThemeColor(bt,LA_BT_DISABLED|LA_BT_TEXT), ui->L+(NoDecal?0:bt->LM)+(NoGap?0:bt->LP),ui->R,sub->U-LA_RH,LA_TEXT_MONO); tnsFlush(); } if(CanGetTheme){ laTheme* t=laGetUiTheme(ui->PP.LastPs->p, ui->PP.LastPs->UseInstance, ui->PP.EndInstance); la_SwitchThemeQuick(t, OriginalTheme); if(t) la_DrawInstanceBkg(sub, laThemeColor(_LA_THEME_FLOATING_PANEL ,LA_BT_NORMAL),bt->LP,bt->RP); } tnsFlush(); Ret += la_DrawUiListRecursive(uild, sub, L, R, U, B, 10000, ConditionStackLevel, GlobalX, GlobalY, RegisterNodes); if(CanGetTheme){ la_SwitchThemeQuick(0, OriginalTheme); } } //ui->PP.EndInstance = Active; ui->PP.EndInstance = SaveInstance; }elif (ui->Type == _LA_UI_CANVAS){ if(!(ui->Flags&LA_UI_FLAGS_NO_OVERLAY)){ for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){ tnsFlush(); Ret += la_DrawUiListRecursive(uild, sub, L-1, R+1, U-1, B+1, ui->B-bt->TP-bt->BP-bt->BM-bt->TM, ConditionStackLevel, GlobalX, GlobalY, RegisterNodes); } } } ui = ui->Item.pNext; }else{ ui = ui->Item.pNext; } } tnsFlush(); if(uild->WiresContainer == uil){ la_DrawNodeWires(uild); } la_RestoreLastUiListMatrix(uild, B - U); MAIN.UiScale=uil->SaveScale; MAIN.ScaledUiRowHeight=MAIN.UiRowHeight*MAIN.UiScale; return Ret; } int la_DrawPanelScrollBarV(int L, int R, int U, int B, real Total, real Range, real Offset){ int Begin = U + (int)(Offset / Total * (real)(B - U)) + 3; int End = Begin + (int)(Range / Total * (real)(B - U)) - 3; tnsUseNoTexture(); tnsColor4d(1, 1, 1, 1); tnsVertex2d(L, U); tnsVertex2d(R, U); tnsVertex2d(R, B); tnsVertex2d(L, B); tnsPackAs(GL_LINE_LOOP); tnsVertex2d(L + 3, Begin); tnsVertex2d(R - 3, Begin); tnsVertex2d(R - 3, End); tnsVertex2d(L + 3, End); tnsPackAs(GL_LINE_LOOP); } int laIsInUiItem(laUiItem *ui, int x, int y){ if (x < ui->L || x > ui->R || y < ui->U || y > ui->B) return 0; return 1; } int laIsInBound(int x, int y, int l, int r, int u, int b){ if (x < l || x > r || y < u || y > b) return 0; return 1; } laColumn *la_DetectSplit(laColumn *Root, int LocalX); laUiItem *la_DetectUiItemRecursive(laUiList *uil, int x, int y, int LimB, laListHandle *LocalBuf, int Deep){ laUiItem *ui, *tui; laBoxedTheme *bt; laUiList *sub; int CPB = 0; if (!uil || (LimB && y > LimB)) return 0; x += uil->PanX; y += uil->PanY; for (ui = uil->UiItems.pFirst; ui;){ bt = ui->Type->Theme ? (*ui->Type->Theme) : 0; if (ui->Type == &_LA_UI_CONDITION){ laConditionUiExtraData *cued = ui->Extra; //la_StepExpression(cued->Expression); for some reason we can't step here, only step in update :thinking: cued->IsTrue = la_DoSingleExpression(cued->Expression); if (!cued->IsTrue){ ui = cued->ElseUi ? cued->ElseUi : cued->EndUi; }else{ ui = ui->Item.pNext; } continue; }else if (ui->Type == &_LA_UI_CONDITION_END){ ui = ui->Item.pNext; continue; }else if (ui->Type == &_LA_UI_CONDITION_ELSE){ laConditionUiExtraData *cued = ((laConditionUiExtraData *)ui->Extra)->EndUi->Extra; if (cued->IsTrue) ui = cued->EndUi; else ui = ui->Item.pNext; continue; }else if (ui->Type == _LA_UI_CONDITION_TOGGLE){ laConditionUiExtraData *cued = ui->Extra; if (laIsInUiItem(ui, x, y)){ lstAppendPointer(LocalBuf, uil); return ui; } if (ui->State == LA_UI_NORMAL){ cued->IsTrue = 0; ui = cued->ElseUi ? cued->ElseUi : cued->EndUi; }else{ cued->IsTrue = 1; ui = ui->Item.pNext; } continue; } //printf("%s > ",ui->Type->Identifier?ui->Type->Identifier:"-"); if (ui->Type != _LA_UI_COLLECTION && ui->Type != _LA_UI_COLLECTION_SINGLE && ui->Type != _LA_UI_FIXED_GROUP && ui->Type != _LA_UI_TAB && ui->Type != _LA_UI_CANVAS && laIsInUiItem(ui, x, y)){ int Add=1; if(ui->Type==_LA_UI_COLUMN_ADJUSTER){ if(!la_DetectSplit(ui->C, x)) Add=0; } if(Add){ lstAppendPointer(LocalBuf, uil); return ui; } } if ((ui->Type == _LA_UI_FIXED_GROUP || ui->Type == _LA_UI_TAB) && (ui->Subs.pFirst || ui->Page)){ if (ui->Page->HeightCoeff) CPB = ui->B; else CPB = ui->Page->B; if (laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->Page->U, CPB)){ if (tui = la_DetectUiItemRecursive(ui->Page, x /* + ui->Page->PanX*/, y /*+ ui->Page->PanY*/, CPB, LocalBuf, Deep)){ lstAppendPointer(LocalBuf, uil); return tui; } }else if (laIsInUiItem(ui, x, y)){ lstAppendPointer(LocalBuf, uil);return ui; } } if (ui->Type == _LA_UI_COLLECTION || ui->Type==_LA_UI_COLLECTION_SINGLE){ if (laIsInUiItem(ui, x, y)){ lstAppendPointer(LocalBuf, uil); if (ui->Subs.pFirst) ((laUiList *)ui->Subs.pFirst)->HeightCoeff = LimB; if(Deep){ for(laUiList* iuil=ui->Subs.pFirst;iuil;iuil=iuil->Item.pNext){ if (laIsInBound(x, y, iuil->L, iuil->R, iuil->U, iuil->B)){ if (tui = la_DetectUiItemRecursive(iuil, x , y , iuil->B, LocalBuf, Deep)){ lstAppendPointer(LocalBuf, iuil); return tui; } } } } return ui; } } if (ui->Type == _LA_UI_CANVAS){ if(!(ui->Flags&LA_UI_FLAGS_NO_OVERLAY)){ for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){ if (tui = la_DetectUiItemRecursive(sub, x, y, ui->B, LocalBuf, Deep)){ lstAppendPointer(LocalBuf, uil); return tui; } } } if (laIsInUiItem(ui, x, y)){ lstAppendPointer(LocalBuf, uil); return ui; } } ui = ui->Item.pNext; } return 0; } laUiItem *la_DetectSocketRecursive(laUiList* uil, int x, int y, int LimB, laPropContainer* PCInOrOut){ laListHandle Locals={0}; laUiItem* ui=la_DetectUiItemRecursive(uil, x,y,LimB,&Locals, 1); while(lstPopPointer(&Locals)); //printf("%s\n", ui?ui->Type->Identifier:"?"); if(ui && ui->Type==_LA_UI_NODE_SOCKET){ laProp* p=ui->PP.LastPs->p; laPropContainer* pc=la_EnsureSubTarget(p,0); if(pc==PCInOrOut) return ui; } return 0; } laUiList *la_DetectUiListRecursive(laUiList *uil, int x, int y, int LimH, laUiItem **ParentUi, laUiList **ScrollUil, laUiList **ContainerParent, int InToContainerUI, laUiItem *Exception){ laUiItem *ui = uil->UiItems.pFirst; laBoxedTheme *bt; laUiList *tuil; laUiList *sub; int CPB = 0; x += uil->PanX; y += uil->PanY; if (y > LimH) return uil; if ((uil->ScrollerShownV && laIsInBound(x, y, uil->R, uil->R+LA_SCROLL_W+4, uil->U, uil->B)) || (uil->ScrollerShownH && laIsInBound(x, y, uil->L, uil->R, uil->B, uil->B+LA_SCROLL_W+4))){ if (ScrollUil) *ScrollUil = uil; /* if (ParentUi)*ParentUi = uil;*/ return uil; } for (ui = uil->UiItems.pFirst; ui;){ bt = ui->Type->Theme ? (*ui->Type->Theme) : 0; if (ui->Type == &_LA_UI_CONDITION){ laConditionUiExtraData *cued = ui->Extra; //la_StepExpression(cued->Expression); cued->IsTrue = la_DoSingleExpression(cued->Expression); if (!cued->IsTrue){ ui = cued->ElseUi ? cued->ElseUi : cued->EndUi; }else{ ui = ui->Item.pNext; } continue; } if (ui->Type == &_LA_UI_CONDITION_END){ ui = ui->Item.pNext; continue; }else if (ui->Type == &_LA_UI_CONDITION_ELSE){ laConditionUiExtraData *cued = ((laConditionUiExtraData *)ui->Extra)->EndUi->Extra; if (cued->IsTrue) ui = cued->EndUi; else ui = ui->Item.pNext; continue; }else if (ui->Type == _LA_UI_CONDITION_TOGGLE){ laConditionUiExtraData *cued = ui->Extra; if (ui->State == LA_UI_NORMAL){ cued->IsTrue = 0; ui = cued->ElseUi ? cued->ElseUi : cued->EndUi; }else{ cued->IsTrue = 1; ui = ui->Item.pNext; } continue; } if (InToContainerUI && ui != Exception){ if (ui->Type == _LA_UI_CANVAS && !(ui->Flags&LA_UI_FLAGS_NO_OVERLAY)){ if (ContainerParent) (*ContainerParent) = uil; if (ParentUi) *ParentUi = ui; for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){ //if (y > LimH) return uil; if (laIsInBound(x, y, sub->L, sub->R, sub->U, sub->B) && (tuil = la_DetectUiListRecursive(sub, x, y, ui->B, ParentUi, ScrollUil, ContainerParent, InToContainerUI, Exception))){ return tuil; } } } } if ((ui->Type == _LA_UI_FIXED_GROUP || ui->Type == _LA_UI_TAB) && (ui->Subs.pFirst || ui->Page)){ if (ui->Page->HeightCoeff) CPB = ui->B+ui->Page->PanY; else CPB = ui->Page->B; if (ui->Page->ScrollerShownV && laIsInBound(x, y, ui->R - LA_SCROLL_W - bt->RP*2, ui->R, ui->Page->U, CPB)){ if (ScrollUil) *ScrollUil = ui->Page; if (ParentUi) *ParentUi = ui; }elif (ui->Page->ScrollerShownH && laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->B - LA_SCROLL_W - bt->BP*2, ui->B)){ if (ScrollUil) *ScrollUil = ui->Page; if (ParentUi) *ParentUi = ui; }elif (laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->Page->U, CPB)){ if (ParentUi) *ParentUi = ui; if (tuil = la_DetectUiListRecursive(ui->Page, x, y, CPB+ui->Page->PanY, ParentUi, ScrollUil, ContainerParent, InToContainerUI, Exception)) return tuil; } } ui = ui->Item.pNext; } return uil; } laUiList *la_DetectUiListRecursiveDeep(laUiList *uil, int x, int y, int LimH, laUiItem **ParentUi, laUiList **ScrollUil, laUiList **ContainerParent, int InToContainerUI, laUiItem *Exception, laListHandle* levels){ laUiItem *ui = uil->UiItems.pFirst; laBoxedTheme *bt; laUiList *tuil; laUiList *sub; int CPB = 0; laUiListRecord* uilr=lstAppendPointerSized(levels, uil, sizeof(laUiListRecord)); x += uil->PanX; y += uil->PanY; if (y > LimH) return uil; if (/*uil->ScrollerShownV && */ laIsInBound(x, y, uil->R, uil->R+LA_SCROLL_W+4, uil->U, uil->B) || /*uil->ScrollerShownH && */ laIsInBound(x, y, uil->L, uil->R, uil->B, uil->B+LA_SCROLL_W+4)){ if (ScrollUil) *ScrollUil = uil; /* if (ParentUi)*ParentUi = uil;*/ return uil; } for (ui = uil->UiItems.pFirst; ui;){ bt = ui->Type->Theme ? (*ui->Type->Theme) : 0; if (ui->Type == &_LA_UI_CONDITION){ laConditionUiExtraData *cued = ui->Extra; //la_StepExpression(cued->Expression); cued->IsTrue = la_DoSingleExpression(cued->Expression); if (!cued->IsTrue){ ui = cued->ElseUi ? cued->ElseUi : cued->EndUi; }else{ ui = ui->Item.pNext; } continue; } if (ui->Type == &_LA_UI_CONDITION_END){ ui = ui->Item.pNext; continue; }else if (ui->Type == &_LA_UI_CONDITION_ELSE){ laConditionUiExtraData *cued = ((laConditionUiExtraData *)ui->Extra)->EndUi->Extra; if (cued->IsTrue) ui = cued->EndUi; else ui = ui->Item.pNext; continue; }else if (ui->Type == _LA_UI_CONDITION_TOGGLE){ laConditionUiExtraData *cued = ui->Extra; if (ui->State == LA_UI_NORMAL){ cued->IsTrue = 0; ui = cued->ElseUi ? cued->ElseUi : cued->EndUi; }else{ cued->IsTrue = 1; ui = ui->Item.pNext; } continue; } if (InToContainerUI && ui != Exception){ if (ui->Type == _LA_UI_CANVAS && !(ui->Flags&LA_UI_FLAGS_NO_OVERLAY)){ if (ContainerParent) (*ContainerParent) = uil; if (ParentUi) *ParentUi = ui; uilr->pui=ui; for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){ //if (y > LimH) return uil; if (laIsInBound(x, y, sub->L, sub->R, sub->U, sub->B) && (tuil = la_DetectUiListRecursiveDeep(sub, x, y, ui->B, ParentUi, ScrollUil, ContainerParent, InToContainerUI, Exception, levels))){ return tuil; } } } } if ((ui->Type == _LA_UI_FIXED_GROUP || ui->Type == _LA_UI_TAB) && (ui->Subs.pFirst || ui->Page)){ if (ui->Page->HeightCoeff) CPB = ui->B; else CPB = ui->Page->B; if (ui->Page->ScrollerShownV && laIsInBound(x, y, ui->R - LA_SCROLL_W - bt->RP*2, ui->R, ui->Page->U, CPB)){ if (ScrollUil) *ScrollUil = ui->Page; if (ParentUi) *ParentUi = ui; uilr->pui=ui; }elif (ui->Page->ScrollerShownH && laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->B - LA_SCROLL_W - bt->BP*2, ui->B)){ if (ScrollUil) *ScrollUil = ui->Page; if (ParentUi) *ParentUi = ui; uilr->pui=ui; }elif (laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->Page->U, CPB)){ if (ParentUi) *ParentUi = ui; uilr->pui=ui; if (tuil = la_DetectUiListRecursiveDeep(ui->Page, x, y, CPB, ParentUi, ScrollUil, ContainerParent, InToContainerUI, Exception, levels)) return tuil; } } if ((ui->PP.LastPs && ui->PP.LastPs->p->PropertyType == LA_PROP_SUB) && (ui->Subs.pFirst || ui->Page)){ if (ui->Page->HeightCoeff) CPB = ui->B; else CPB = ui->Page->B; if (laIsInBound(x, y, ui->Page->R, ui->Page->R + LA_SCROLL_W + bt->RM, ui->Page->U, CPB)){ if (ScrollUil) *ScrollUil = ui->Page; if (ParentUi) *ParentUi = ui; uilr->pui=ui; } if (laIsInBound(x, y, ui->Page->L, ui->Page->R, ui->Page->U, CPB)){ if (ParentUi) *ParentUi = ui; uilr->pui=ui; if (tuil = la_DetectUiListRecursiveDeep(ui->Page, x, y, CPB, ParentUi, ScrollUil, ContainerParent, InToContainerUI, Exception, levels)) return tuil; } } ui = ui->Item.pNext; } return uil; } int la_TestUiListMinumWidth(laUiList *uil){ laUiItem *ui, *tui; laBoxedTheme *bt; laUiList *sub; int CPB = 0; int W = 0; int tW, sW, RowMode=0, rW; void *Restore; for (ui = uil->UiItems.pFirst; ui;){ bt = ui->Type->Theme ? (*ui->Type->Theme) : 0; if ((ui->Type == _LA_UI_FIXED_GROUP || ui->Type == _LA_UI_TAB) && (ui->Subs.pFirst || ui->Page)){ tW = la_TestUiListMinumWidth(ui->Page) + bt->LP + bt->RP; tW = (int)((float)tW / ui->C->PreWidth + 2); if (W < tW) W = tW; }elif (ui->Type == _LA_UI_COLLECTION){ Restore = ui->PP.EndInstance; tW = 0; sW = 0; for (sub = ui->Subs.pFirst; sub; sub = sub->Item.pNext){ ui->PP.EndInstance = sub->Instance; sW = la_TestUiListMinumWidth(sub) + bt->LP + bt->RP; if (sW > tW) tW = sW; } ui->PP.EndInstance = Restore; tW = (int)((float)tW / ui->C->PreWidth + 2); tW *= (ui->SymbolID > 0 ? ui->SymbolID : 1); if (W < tW) W = tW; }elif (ui->Type==&_LA_UI_ROW_BEGIN){ RowMode=1; rW=0; }elif (ui->Type==&_LA_UI_ROW_END){ RowMode=0; rW=(int)((float)rW / ui->C->PreWidth + 2); if (W < rW) W = rW; }elif (ui->Type->GetMinWidth){ tW = ui->Type->GetMinWidth(ui) + bt->LP + bt->RP; if(RowMode){ rW+=tW; }else{ tW = (int)((float)tW / ui->C->PreWidth + 2); if (W < tW) W = tW; } } ui = ui->Item.pNext; } return W; } void la_InitLLVM(){ //LLVMLinkInMCJIT(); //LLVMInitializeNativeTarget(); //LLVMInitializeNativeAsmPrinter(); //LLVMInitializeNativeAsmParser(); // MAIN.llvmContext = LLVMGetGlobalContext(); //MAIN.llvmModule = LLVMModuleCreateWithNameInContext(LA_NODE_MAIN_MODULE_NAME, MAIN.llvmContext); } //================================================================================================== void la_FreeKeyMapItem(laKeyMapItem* kmi){ if(kmi->Instructions) strSafeDestroy(&kmi->Instructions); if(kmi->Operation) strSafeDestroy(&kmi->Operation); if(kmi->Action.Go) la_FreePropStepCache(kmi->Action.Go); if(kmi->Base.Go) la_FreePropStepCache(kmi->Action.Go); memFree(kmi); } laKeyMapItem *laAssignNewKey(laKeyMapper *km, char *Path, char *Operation, char SelectBase, int SpecialKeyBits, int EventType, int Key, char *ExtraInstructions){ laKeyMapItem *kmi; if (!km) return 0; kmi = memAcquire(sizeof(laKeyMapItem)); if (la_GetPropFromPath(&kmi->Base, 0, Path, 0)){ la_GetPropFromPath(&kmi->Action, &kmi->Base, Operation, 0); }else{ strSafeSet(&kmi->Operation, Operation); } strSafeSet(&kmi->Instructions, ExtraInstructions); kmi->SpecialKeyBits = SpecialKeyBits; kmi->EventType = EventType; kmi->Key = tolowerGuarded(Key); kmi->SelectBase = SelectBase; lstAppendItem(&km->Items, kmi); return kmi; } int laKeyMapExecuteEvent(laOperator *from, laKeyMapper *km, laEvent *e){ laKeyMapItem *kmi; int inv=0; char *instructions; if(e->type==LA_MOUSEMOVE) return 0; for (kmi = km->Items.pFirst; kmi; kmi = kmi->Item.pNext){ if ((kmi->SpecialKeyBits == e->SpecialKeyBit||kmi->EventType==LA_SIGNAL_EVENT) && kmi->EventType == e->type && ((kmi->Key == e->Input) || (kmi->Key == e->key))){ instructions = kmi->Instructions ? kmi->Instructions->Ptr : 0; if (kmi->Operation) laInvoke(from, kmi->Operation->Ptr, e, 0, instructions, 0); else laInvoke(from, ((laOperatorProp *)&kmi->Action.LastPs)->OperatorID, e, &kmi->Base, instructions, 0); inv = 1; } } return inv; } int laKeyMapExecuteEventEx(laOperator *from, laPropPack *UiExtra, laKeyMapper *km, laEvent *e){ laKeyMapItem *kmi; char *instructions; int inv = 0; int lx = -1, ly = -1; if(e->type==LA_MOUSEMOVE) return 0; for (kmi = km->Items.pFirst; kmi; kmi = kmi->Item.pNext){ if ((kmi->SpecialKeyBits == e->SpecialKeyBit||kmi->EventType==LA_SIGNAL_EVENT) && kmi->EventType == e->type && ((kmi->Key == e->Input) || (kmi->Key == e->key))){ if (e->Localized){ lx = e->x; ly = e->y; laLocalToWindow(from, MAIN.ToPanel, &e->x, &e->y); e->Localized = 0; } instructions = kmi->Instructions ? kmi->Instructions->Ptr : 0; if (kmi->SelectBase == LA_KM_SEL_UI_EXTRA){ laInvoke(from, kmi->Operation->Ptr, e, UiExtra, instructions, 0); }elif (kmi->SelectBase == LA_KM_SEL_PANEL){ laInvoke(from, kmi->Operation->Ptr, e, &((laPanel *)MAIN.ToPanel)->PP, instructions, 0); }elif (kmi->Operation){ laInvoke(from, kmi->Operation->Ptr, e, 0, instructions, 0); }else{ laInvoke(from, ((laOperatorProp *)&kmi->Action.LastPs)->OperatorID, e, &kmi->Base, instructions, 0); } inv = 1; if (lx >= 0){ e->x = lx; e->y = ly; e->Localized = 1; } } } return inv; } void la_DefaultOperatorParser(laStringSplitor *ss, char *IconID, char *DisplayString); void la_DestroyOperatorType(laOperatorType* at){ //if(at->PC) la_FreePropertyContainer(at->PC); memFree(at); } laOperatorType *laCreateOperatorType(const char *ID, const char *Name, const char *Description, laCheckFunc Check, laInitFunc Init, laExitFunc Exit, laInvokeFunc Invoke, laModalFunc Modal, uint32_t IconID, int ExtraMark){ laOperatorType *at = memAcquire(sizeof(laOperatorType)); at->Identifier = ID; at->Name = Name; at->Description = Description; at->Check = Check; at->Invoke = Invoke; at->Init = Init; at->Exit = Exit; at->Modal = Modal; at->IconID = IconID; at->ExtraMark = ExtraMark; at->ParseArgs = la_DefaultOperatorParser; hsh256InsertItemCSTR(&MAIN.OperatorTypeHash, at, at->Identifier); return at; } laPropContainer* laDefineOperatorProps(laOperatorType* ot, int HyperLevel){ ot->PC = memAcquire(sizeof(laPropContainer)); ot->PC->Identifier = ot->Identifier; ot->PC->Hyper = HyperLevel; return ot->PC; } laOperator *la_CreateOperator(laOperatorType *at){ laOperator *a = CreateNew(laOperator); a->Type = at; if (at->PC && at->PC->Props.pFirst){ a->PP.LastPs = memAcquireSimple(sizeof(laPropStep)); a->PP.LastPs->p = memAcquire(sizeof(laSubProp)); a->PP.LastPs->p->SubProp = at->PC; a->PP.LastPs->p->PropertyType = LA_PROP_SUB; a->PP.LastPs->p->Identifier = at->PC->Identifier; a->PP.LastPs->Type = U'.'; } return a; } int la_OperatorTypeByID(laOperatorType *a, char *id){ return (!strcmp(a->Identifier, id)); } laOperatorType *laGetOperatorType(const char *ID){ return hsh256FindItemSTR(&MAIN.OperatorTypeHash, la_OperatorTypeByID, ID); } int laOperatorExistsT(laOperatorType* at){ if (!at) return 0; for (laOperator *a = MAIN.CurrentWindow->Operators.pFirst; a; a = a->Item.pNext){ if (at == a->Type){ return 1; } } return 0; } int laOperatorExists(const char* ID){ laOperatorType* at=laGetOperatorType(ID); if (!at) return 0; return laOperatorExistsT(at); } int la_OperatorExists(laOperator *ac){ if (!ac) return 0; laOperator *a; for (a = MAIN.CurrentWindow->Operators.pFirst; a; a = a->Item.pNext){ if (ac == a){return 1;}} return 0; } int la_UiOperatorExists(void *inst){ laOperator *a; if (!inst) return 0; for (a = MAIN.CurrentWindow->Operators.pFirst; a; a = a->Item.pNext){ if (((laUiItem *)a->Instance) == inst){ return 1; } } for (a = MAIN.CurrentWindow->PendingOperators.pFirst; a; a = a->Item.pNext){ if (a->Instance == inst){ return 1; } } return 0; } int la_OperatorPending(laOperator *target){ laOperator *a; if (!target) return 0; for (a = MAIN.CurrentWindow->PendingOperators.pFirst; a; a = a->Item.pNext){ if (a == target){ return 1; } } return 0; } void laSetOperatorLocalizer(void *ToPanel){ MAIN.ToPanel = ToPanel; } void la_DestroyConfirmData(laConfirmData **cd); void *la_DestroyOperator(laOperator **a, laListHandle *Operators, int OnlyThisOne){ laOperator *ai = (*a); laOperator *ac = ((*a)->Child); void *Ret = 0; if (!OnlyThisOne && ac && la_OperatorExists(ac) && !ac->Using && !ac->ModalOver){ la_DestroyOperator(&ac, Operators, OnlyThisOne); } if ((*a)->ConfirmData) la_DestroyConfirmData(&((*a)->ConfirmData)); if ((*a)->PP.LastPs){ memFree((*a)->PP.LastPs->p); memFree((*a)->PP.LastPs); } if (laNonFixedPanelExists((*a)->OperatorPanel)){ la_SetPropMathcerContext((*a)->OperatorPanel); MAIN.CurrentPanel = (*a)->OperatorPanel; laDestroySinglePanel((*a)->OperatorPanel,0); } if ((*a)->CreatedThis) memFree((*a)->CreatedThis); if ((*a)->ExtraInstructionsP) strDestroyStringSplitor(&(*a)->ExtraInstructionsP); lstClearPointer(&(*a)->LocalUiLists); if (Operators){ Ret = ai->Item.pNext; if (la_OperatorPending((*a) /*->Instance*/)) lstRemoveItem(&MAIN.CurrentWindow->PendingOperators, *a); else lstRemoveItem(Operators, *a); for (ai = Operators->pFirst; ai; ai = ai->Item.pNext){ if (ai->Child == (*a)) ai->Child = 0; } } strSafeDestroy(&(*a)->RuntimeHint); free(*a); return Ret; } int laOperatorAvailable(char *ID, laPropPack *This, laStringSplitor *Instructions){ laOperatorType *at = hsh256FindItemSTR(&MAIN.OperatorTypeHash, la_OperatorTypeByID, ID); if (!at) return 0; if (!at->Check) return 1; return (at->Check(This, Instructions)); } int laOperatorAvailableP(laOperatorType *at, laPropPack *This, laStringSplitor *Instructions){ if (!at) return 0; if (!at->Check) return 1; return (at->Check(This, Instructions)); } int laOperatorAvailablePSafe(laOperatorType *at, laPropPack *This, void *Real_FromInstance, laStringSplitor *Instructions){ laPropPack FakePP = {0}; laPropStep FakePs = {0}; if (!at) return 0; if (!at->Check) return 1; FakePP.LastPs = &FakePs; FakePP.Go = FakePP.LastPs; FakePP.LastPs->p = This->LastPs->p; FakePP.LastPs->UseInstance = This->EndInstance; FakePP.EndInstance = Real_FromInstance; FakePP.LastIndex = This->LastIndex; return (at->Check(&FakePP, Instructions)); } int laOperatorAvailableSafe(char *ID, laPropPack *This, void *Real_FromInstance, laStringSplitor *Instructions){ laOperatorType *at = hsh256FindItemSTR(&MAIN.OperatorTypeHash, la_OperatorTypeByID, ID); return laOperatorAvailablePSafe(at, This, Real_FromInstance, Instructions); } int laInvokeP(laOperator *From, laOperatorType *at, laEvent *e, laPropPack *This, char *args, char *args2){ laOperator *a, *f = From; int rev; if (!f && e&&e->Localized) return -1; a = la_CreateOperator(at); a->ToPanel = MAIN.ToPanel; a->This = This; a->ExtraInstructions = args; strMakeInstructions(&a->ExtraInstructionsP, args); strMakeInstructions(&a->ExtraInstructionsP, args2); strMakeInstructions(&a->ExtraInstructionsP, at->ExtraInstructions); if (!laOperatorAvailableP(at, This, a->ExtraInstructionsP)){ la_DestroyOperator(&a, 0, 0); return LA_CANCELED; } lstGeneratePointerList(f ? &f->LocalUiLists : 0, 0, &a->LocalUiLists); if (e&&!e->Localized && at->ExtraMark & LA_EXTRA_TO_PANEL){ laWindowToLocal(0, a->ToPanel, &e->x, &e->y); e->Localized = 1; } if (e&&e->Localized){ if (!at->ExtraMark & LA_EXTRA_TO_PANEL){ laLocalToWindow(f, f->ToPanel, &e->x, &e->y); e->Localized = 0; }else{ laLocalToWindow(f, f->ToPanel, &e->x, &e->y); laWindowToLocal(a, a->ToPanel, &e->x, &e->y); } } if (From) f->Child = a; a->Using = 1; if (at->Init) at->Init(a); rev = at->Invoke(a, e); a->Using = 0; if (rev & LA_FINISH){ a->StopNow = 1; if(From)From->Child=0; laConfirmSameDataIfAny(a); la_DestroyConfirmData(&MAIN.InvokeConfirmData); MAIN.InvokeConfirmData=a->NextConfirmData; } if (!a->StopNow && (rev&LA_BLOCK || rev&LA_PASS_ON)){ if(a->ModalOver){ lstPushItem(&MAIN.CurrentWindow->PendingOperators, a); } else{ lstAppendItem(&MAIN.CurrentWindow->PendingOperators, a); } a->State = rev; a->PP.EndInstance = a->CustomData; if (a->PP.LastPs) a->PP.LastPs->Type = U'.'; }else la_DestroyOperator(&a, 0, 0); return rev; } int laInvoke(laOperator *From, char *ID, laEvent *e, laPropPack *This, char *args, char *args2){ laOperatorType *at; laOperator *a, *f = From; at = hsh256FindItemSTR(&MAIN.OperatorTypeHash, la_OperatorTypeByID, ID); if (!at) return -1; return laInvokeP(From,at,e,This,args,args2); } int laInvokePCreateThis(laOperator *From, laOperatorType *at, laEvent *e, laPropPack *OrigionalThis, void *FromInstance, char *args, char *args2){ laOperator *a, *f = From; int rev; laPropPack *created; if (!f && e&&e->Localized || !OrigionalThis || !OrigionalThis->LastPs) return -1; created = memAcquireSimple(sizeof(laPropPack)); created->LastPs = memAcquireSimple(sizeof(laPropStep)); created->Go = created->LastPs; created->LastPs->p = OrigionalThis->LastPs->p; created->LastPs->UseInstance = OrigionalThis->LastPs->UseInstance; created->EndInstance = FromInstance; created->LastIndex = OrigionalThis->LastIndex; a = la_CreateOperator(at); a->ToPanel = MAIN.ToPanel; a->This = created; a->CreatedThis = created; a->ExtraInstructions = args; strMakeInstructions(&a->ExtraInstructionsP, args); strMakeInstructions(&a->ExtraInstructionsP, args2); strMakeInstructions(&a->ExtraInstructionsP, at->ExtraInstructions); if (!laOperatorAvailableP(at, created, a->ExtraInstructionsP)){ la_DestroyOperator(&a, 0, 0); return LA_CANCELED; } lstGeneratePointerList(f ? &f->LocalUiLists : 0, 0, &a->LocalUiLists); if (e&&!e->Localized && at->ExtraMark & LA_EXTRA_TO_PANEL) laWindowToLocal(0, a->ToPanel, &e->x, &e->y); if (From) f->Child = a; a->Using = 1; if (at->Init) at->Init(a); rev = at->Invoke(a, e); a->Using = 0; if (rev & LA_FINISH){ a->StopNow = 1; if(From)From->Child=0; laConfirmSameDataIfAny(a); la_DestroyConfirmData(&MAIN.InvokeConfirmData); MAIN.InvokeConfirmData=a->NextConfirmData; } if (!a->StopNow && (rev&LA_BLOCK || rev&LA_PASS_ON)){ if(a->ModalOver){ lstPushItem(&MAIN.CurrentWindow->PendingOperators, a); } else{ lstAppendItem(&MAIN.CurrentWindow->PendingOperators, a); } a->State = rev; a->PP.EndInstance = a->CustomData; }else la_DestroyOperator(&a, 0, 0); return rev; } int laInvokeUiP(laOperator *From, laOperatorType *at, laEvent *e, void *inst, laListHandle *Locals, int IgnoreLocals){ laOperator *a, *f = From; int rev; if (!at || (la_UiOperatorExists(inst))){ return -1; } a = la_CreateOperator(at); a->Instance = inst; a->ToPanel = MAIN.ToPanel; if (!IgnoreLocals) lstGeneratePointerList(f ? &f->LocalUiLists : 0, Locals, &a->LocalUiLists); if (From) f->Child = a; a->Using = 1; if (at->Init) at->Init(a); rev = at->Invoke(a, e); a->Using = 0; if (rev & LA_FINISH){ a->StopNow = 1; if(From)From->Child=0; } if (rev & LA_BLOCK){ lstAppendItem(&MAIN.CurrentWindow->PendingOperators, a); a->State = rev; }else la_DestroyOperator(&a, 0, 0); DEB = a; return rev; } int laInvokeUi(laOperator *From, char *ID, laEvent *e, void *inst, laListHandle *Locals, int IgnoreLocals){ laOperatorType *at; laOperator *a, *f = From; if (la_UiOperatorExists(inst)) return -1; at = hsh256FindItemSTR(&MAIN.OperatorTypeHash, la_OperatorTypeByID, ID); if (!at) return -1; return laInvokeUiP(From,at,e,inst,Locals,IgnoreLocals); } void laRequestDelayEvent(real Seconds){ MAIN.DelayTriggered=0; MAIN.DelayStart=MAIN.TimeAccum; MAIN.DelayTime = Seconds; } int la_UiStillInService(void *UiInstance){ laOperator *ai, *dai; if(!MAIN.CurrentWindow) return 0; for (ai = MAIN.CurrentWindow->Operators.pFirst; ai; ai = ai->Item.pNext){ if (ai->Instance == UiInstance) return 1; } return 0; } void la_StopUiOperatorService(void *UiInstance){ laOperator *ai, *dai, *NextAi; if (!MAIN.CurrentWindow) return; for (ai = MAIN.CurrentWindow->PendingOperators.pFirst; ai; ai = NextAi){ NextAi = ai->Item.pNext; if (ai->Instance == UiInstance){ if (ai->Child){ la_StopUiOperatorService(ai->Child->Instance); ai->Child = 0; } laOperator *dai = ai; la_DestroyOperator(&dai, &MAIN.CurrentWindow->PendingOperators, 1); continue; } } for (ai = MAIN.CurrentWindow->Operators.pFirst; ai; ai = NextAi){ NextAi = ai->Item.pNext; if (ai->Instance == UiInstance){ if (ai->Instance == ai->ToPanel){ //laHidePanelWithDissoveEffect(ai->ToPanel); //ai->ToPanel->LaterDestroy = 1; } if (ai->Child && la_OperatorExists(ai->Child)){ la_StopUiOperatorService(ai->Child->Instance); //ai->Child = 0; } if (!ai->Using){ laOperator *dai = ai; la_DestroyOperator(&dai, &MAIN.CurrentWindow->Operators, 1); }else ai->StopNow = 1; } } } void la_StopAllOperators(){ laOperator *ai, *dai, *NextAi; if (!MAIN.CurrentWindow) return; for (ai = MAIN.CurrentWindow->PendingOperators.pFirst; ai; ai = NextAi){ NextAi = ai->Item.pNext; NextAi = la_DestroyOperator(&ai, &MAIN.CurrentWindow->PendingOperators, 1); continue; } for (ai = MAIN.CurrentWindow->Operators.pFirst; ai; ai = NextAi){ NextAi = ai->Item.pNext; if (ai->ToPanel && ai->Instance == ai->ToPanel && !ai->ToPanel->IsMenuPanel){ laHidePanelWithDissoveEffect(ai->ToPanel); ai->ToPanel->LaterDestroy = 1; } if (!ai->Using){ laOperator *dai = ai; la_DestroyOperator(&dai, &MAIN.CurrentWindow->Operators, 1); }else ai->StopNow = 1; } } void la_DestroyConfirmData(laConfirmData **cd){ if((!cd)||!(*cd)) return; if ((*cd)->CustomData && (*cd)->Destroy) (*cd)->Destroy((*cd)->CustomData); if ((*cd)->StrData) free((*cd)->StrData); FreeMem((*cd)); (*cd) = 0; } void laConfirmPointer(laOperator *a, void* Data,laPropContainer* PointerType, int mode){ laOperator *ai = a; laConfirmData *cd = CreateNew(laConfirmData); cd->PointerData = Data; cd->Mode = mode; cd->PointerType=PointerType; ai->NextConfirmData = cd; laRetriggerOperators(); } void laConfirmInt(laOperator *a, int Data, int mode){ laOperator *ai = a;laConfirmData *cd = CreateNew(laConfirmData); cd->IData = Data; cd->Mode = mode; ai->NextConfirmData = cd; laRetriggerOperators(); } void laConfirmFloat(laOperator *a, real Data, int mode){ laOperator *ai = a;laConfirmData *cd = CreateNew(laConfirmData); cd->FData = Data; cd->Mode = mode; ai->NextConfirmData = cd; laRetriggerOperators(); } void laConfirmString(laOperator *a, char *Str, int mode){ laOperator *ai = a; laConfirmData *cd = CreateNew(laConfirmData); int len = strlen(Str); char *buf = calloc(len + 1, sizeof(char)); strcpy(buf, Str); cd->StrData = buf; cd->Mode = mode; cd->Destroy = free; ai->NextConfirmData = cd; laRetriggerOperators(); } int laConfirmSameDataIfAny(laOperator *a){ laOperator *ai = a; laConfirmData *cd; char *buf = 0; if (!ai->ConfirmData || ai->NextConfirmData) return 0; cd = CreateNew(laConfirmData); if (ai->ConfirmData->StrData){ int len = strlen(ai->ConfirmData->StrData); buf = calloc(len + 1, sizeof(char)); strcpy(buf, ai->ConfirmData->StrData); } //cd->CustomData = cd->CustomData; cd->IData = ai->ConfirmData->IData; cd->FData = ai->ConfirmData->FData; cd->PointerData = ai->ConfirmData->PointerData; cd->PointerType = a->ConfirmData->PointerType; cd->StrData = buf; cd->Mode = ai->ConfirmData->Mode; cd->Destroy = ai->ConfirmData->Destroy; ai->NextConfirmData = cd; laRetriggerOperators(); return 1; } void laConfirmUserData(laOperator *a, void *UserData, laConfirmDataDestroyFunc Destroy, int mode){ laOperator *ai = a; laConfirmData *cd = CreateNew(laConfirmData); cd->CustomData = UserData; cd->Mode = mode; cd->Destroy = Destroy; ai->NextConfirmData = cd; laRetriggerOperators(); } int laGetConfirmMode(laOperator *a){ return ((laOperator *)a)->ConfirmData->Mode; } int laGetConfirmInt(laOperator *a){ laOperator *ai = a; int rev = ai->ConfirmData->IData; la_DestroyConfirmData(&ai->ConfirmData); ai->ConfirmData = 0; return rev; } real laGetConfirmFloat(laOperator *a){ laOperator *ai = a; real rev = ai->ConfirmData->FData; la_DestroyConfirmData(&ai->ConfirmData); ai->ConfirmData = 0; return rev; } void laGetConfirmString(laOperator *a, char *buf){ laOperator *ai = a; strcpy(buf, ai->ConfirmData->StrData); la_DestroyConfirmData(&ai->ConfirmData); ai->ConfirmData = 0; } void *laGetConfirmUserData(laOperator *a){ laOperator *ai = a; return ai->ConfirmData->CustomData; } void laFinalizeOperators(){ laOperatorType *at; laListHandle *lst; int i; for (i = 0; i < 256; i++){ lst = &MAIN.OperatorTypeHash.Entries[i]; for (at = lst->pFirst; at; at = at->Item.pNext){ if (at->PC && at->PC->Props.pFirst){ lstAppendItem(&MAIN.PropContainers, at->PC); } } } } //================= #ifdef LA_LINUX static void la_RecordWacomMotions(XIRawEvent *event) { double *valuator = event->valuators.values; int IsStylus=event->deviceid==MAIN.WacomDeviceStylus; if(!IsStylus) MAIN.PointerIsEraser = 1; else MAIN.PointerIsEraser = 0; //SYSWINDOW root_return, child_return; //int root_x_return, root_y_return; //int win_x_return, win_y_return; //unsigned int mask_return; //int retval = XQueryPointer(MAIN.dpy, RootWindow(MAIN.dpy,0), &root_return, &child_return, // &root_x_return, &root_y_return, // &win_x_return, &win_y_return, // &mask_return); // //printf("root: x %d y %d\n", win_x_return, win_y_return); if(XIMaskIsSet(event->valuators.mask, 2)){ if(IsStylus) MAIN.StylusPressure=valuator[2]/MAIN.StylusMaxPressure; else MAIN.EraserPressure=valuator[2]/MAIN.EraserMaxPressure; } if(XIMaskIsSet(event->valuators.mask, 3) && XIMaskIsSet(event->valuators.mask, 4)){ real x=valuator[3],y=valuator[4]; real orientation=atan2(y,x); real deviation=sqrt(x*x+y*y); deviation=rad(deviation); if(IsStylus){ MAIN.StylusOrientation=orientation;MAIN.StylusDeviation=deviation; } else { MAIN.EraserOrientation=orientation;MAIN.EraserDeviation=deviation; } }else{ MAIN.StylusDeviation=MAIN.StylusOrientation=MAIN.EraserDeviation=MAIN.EraserOrientation=0; } if(XIMaskIsSet(event->valuators.mask, 5)){ real angle=valuator[5]; angle=rad((900-angle)/10*2-180); if(angle<0) angle+=TNS_PI*2; MAIN.StylusTwist=angle; if(TNS_DOUBLE_CLOSE_ENOUGH(angle,TNS_PI)){ MAIN.StylusHasTwist=0; }else{ MAIN.StylusHasTwist=1; } }else{ MAIN.StylusTwist=TNS_PI; MAIN.StylusHasTwist=0; } MAIN.IsPen=1; } #endif #ifdef _WIN32 #define PARAM_2_FROM(p) LOWORD(p),HIWORD(p) LRESULT CALLBACK LA_WindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) { static uint32_t ch = 0; static int lead = 0; static wchar_t buf[10] = { 0 }; int adv; char mbuf[10] = { 0 }; uint32_t uchar=0; short wheelmark = 0; int WheelDir = 0; UINT32 pointerId; POINTER_INPUT_TYPE pointerType; POINTER_PEN_INFO penInfo[128]; POINTER_TOUCH_INFO touchInfo; int peninfonum = 128; POINT point; PACKET pkt; static POINT ptOld, ptNew; static UINT prsOld, prsNew, vkey; if (!hwnd) return DefWindowProc(hwnd, message, wparam, lparam); switch (message) { case WM_PAINT: //SwapBuffers(GetDC(hwnd)); break; case WM_MOUSEMOVE: la_SendMouseEvent(hwnd, LA_MOUSEMOVE, PARAM_2_FROM(lparam)); MAIN.IsPen = 0; break; case WM_LBUTTONDOWN: la_SendMouseEvent(hwnd, LA_L_MOUSE_DOWN, PARAM_2_FROM(lparam)); break; case WM_LBUTTONUP: la_SendMouseEvent(hwnd, LA_L_MOUSE_UP, PARAM_2_FROM(lparam)); break; case WM_RBUTTONDOWN: la_SendMouseEvent(hwnd, LA_R_MOUSE_DOWN, PARAM_2_FROM(lparam)); break; case WM_RBUTTONUP: la_SendMouseEvent(hwnd, LA_R_MOUSE_UP, PARAM_2_FROM(lparam)); break; case WM_MBUTTONDOWN: la_SendMouseEvent(hwnd, LA_M_MOUSE_DOWN, PARAM_2_FROM(lparam)); break; case WM_MBUTTONUP: la_SendMouseEvent(hwnd, LA_M_MOUSE_UP, PARAM_2_FROM(lparam)); break; case WM_MOUSEWHEEL: POINT p; p.x=LOWORD(lparam); p.y=HIWORD(lparam); ScreenToClient(hwnd,&p); if ((wheelmark = HIWORD(wparam)) > 0) WheelDir = LA_MOUSEUP; else if ((wheelmark = HIWORD(wparam)) < 0) WheelDir = LA_MOUSEDOWN; la_SendMouseEvent(hwnd, WheelDir|LA_KEY_MOUSE_SCROLL, p.x, p.y); break; case WT_PACKET: if (!MAIN.InkOrWinTab) { break; /* Use Windows Ink. */ } if (gpWTPacket((HCTX)lparam, wparam, &pkt)) { MAIN.StylusPressure = (real)pkt.pkNormalPressure / MAIN.WinTabMaxPenPressure; MAIN.StylusHover = (real)pkt.pkZ / MAIN.WinTabMaxHover; real angle = (real)pkt.pkOrientation.orAzimuth / 3600 * TNS_PI * 2 + TNS_PI / 2; MAIN.StylusOrientation = angle; MAIN.StylusDeviation = rad((90.0f - (real)pkt.pkOrientation.orAltitude / 10.0f)); real tw = (real)pkt.pkOrientation.orTwist; tw = rad(tw / 10); MAIN.StylusTwist = tw; if(TNS_DOUBLE_CLOSE_ENOUGH(tw,TNS_PI)){ MAIN.StylusHasTwist=0; }else{ MAIN.StylusHasTwist=1; } MAIN.EraserDeviation = MAIN.StylusDeviation; MAIN.EraserOrientation = MAIN.StylusOrientation; MAIN.EraserPressure = MAIN.StylusPressure; MAIN.IsPen = 1; MAIN.PointerIsEraser = ((pkt.pkStatus & TPS_INVERT) == TPS_INVERT); point.x = pkt.pkX; point.y = pkt.pkY; ScreenToClient(hwnd, &point); la_SendMouseEvent(hwnd, LA_MOUSEMOVE, point.x, point.y); } return 0; break; case WM_SYSCOMMAND: switch (wparam) { case SC_MAXIMIZE: case SC_RESTORE: la_CommandResizeWindow(hwnd, 0, 0, LOWORD(lparam), HIWORD(lparam)); break; case SC_KEYMENU: return 0; case SC_MINIMIZE: break; } break; case WM_SIZE: if (wparam == SIZE_MINIMIZED) break; case WM_MOVE: /* And size */ la_CommandResizeWindow(hwnd, 0, 0, LOWORD(lparam), HIWORD(lparam)); break; case WM_SETCURSOR: if(MAIN.CurrentCursor) return 1; break; case WM_POINTERDOWN: case WM_POINTERUP: case WM_POINTERUPDATE: if (MAIN.InkOrWinTab) { break;/* Use WinTab. */ } pointerId = GET_POINTERID_WPARAM(wparam); pointerType = PT_POINTER; if(!GetPointerType(pointerId, &pointerType)){ pointerType = PT_POINTER; } if(pointerType == PT_PEN){ if(GetPointerPenInfoHistory(pointerId, &peninfonum, penInfo)){ for (int i = peninfonum-1; i>=0; i--) { point.x = penInfo[i].pointerInfo.ptPixelLocation.x; point.y = penInfo[i].pointerInfo.ptPixelLocation.y; ScreenToClient(hwnd, &point); MAIN.IsPen = 1; MAIN.StylusPressure = (real)penInfo[i].pressure / 1024; MAIN.PointerIsEraser = 0; switch (penInfo[i].pointerInfo.ButtonChangeType) { case POINTER_CHANGE_FIRSTBUTTON_DOWN: la_SendMouseEvent(hwnd, LA_L_MOUSE_DOWN, point.x, point.y); break; case POINTER_CHANGE_FIRSTBUTTON_UP: la_SendMouseEvent(hwnd, LA_L_MOUSE_UP, point.x, point.y); break; case POINTER_CHANGE_SECONDBUTTON_DOWN: la_SendMouseEvent(hwnd, LA_M_MOUSE_DOWN, point.x, point.y); break; case POINTER_CHANGE_SECONDBUTTON_UP: la_SendMouseEvent(hwnd, LA_M_MOUSE_UP, point.x, point.y); break; case POINTER_CHANGE_THIRDBUTTON_DOWN: la_SendMouseEvent(hwnd, LA_R_MOUSE_DOWN, point.x, point.y); break; case POINTER_CHANGE_THIRDBUTTON_UP: la_SendMouseEvent(hwnd, LA_R_MOUSE_UP, point.x, point.y); break; } la_SendMouseEvent(hwnd, LA_MOUSEMOVE, point.x, point.y); } } SkipPointerFrameMessages(pointerId); return 0; } else if (pointerType == PT_TOUCH){ if (GetPointerTouchInfo(pointerId, &touchInfo)) { point.x = touchInfo.pointerInfo.ptPixelLocation.x; point.y = touchInfo.pointerInfo.ptPixelLocation.y; ScreenToClient(hwnd, &point); MAIN.IsPen = 1; MAIN.StylusPressure = (real)touchInfo.pressure / 1024; MAIN.PointerIsEraser = 1; } } break; case WM_SYSKEYDOWN: if (lparam & 0x40000000) break; la_SendKeyboardEvent(hwnd, LA_KEY_DOWN, la_TranslateSpecialKey(wparam)); break; case WM_KEYDOWN: if (lparam & 0x40000000) break; vkey = wparam; la_SendKeyboardEvent(hwnd, LA_KEY_DOWN, la_TranslateSpecialKey(vkey)); break; case WM_KEYUP: la_SendKeyboardEvent(hwnd, LA_KEY_UP, la_TranslateSpecialKey(wparam)); break; case WM_SYSKEYUP: la_SendKeyboardEvent(hwnd, LA_KEY_UP, la_TranslateSpecialKey(wparam)); break; case WM_UNICHAR: la_SendInputEvent(hwnd, wparam); break; case WM_IME_CHAR: la_SendInputEvent(hwnd, wparam); return 0; case WM_CHAR: la_SendInputEvent(hwnd, wparam); break; case WM_SHOWWINDOW: //SendCommandEvent(hwnd, EVT_WND_SIZE_FINISH); break; case WM_CLOSE: if (!la_OnWindowDestroy(hwnd)) return 0; return 1; break; default: return DefWindowProc(hwnd, message, wparam, lparam); } return DefWindowProc(hwnd, message, wparam, lparam); } LRESULT CALLBACK LA_ProgressWindowProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam){ return DefWindowProc(hwnd, message, wparam, lparam); } #endif int la_UpdateOperatorHints(laWindow* w){ laSafeString* ss=0; for(laOperator* o=w->Operators.pFirst;o;o=o->Item.pNext){ if(o->RuntimeHint&&o->RuntimeHint->Ptr){ strSafePrint(&ss, "%s | %s ", o->Type->Name, o->RuntimeHint->Ptr);} } if((w->OperatorHints&&ss&&strSame(ss->Ptr,w->OperatorHints->Ptr))||(!w->OperatorHints&&!ss)){ //pass }else{ if(ss){ strSafeSet(&w->OperatorHints,ss->Ptr); } else { strSafeDestroy(&w->OperatorHints); } laNotifyUsers("la.windows.operator_hints");//printf("op hint\n"); } strSafeDestroy(&ss); } int la_HandleSingleEvent(laEvent *e, laListHandle *Operators){ laOperator *a, *NextA = 0; int Result = 0; laConfirmData *ConfirmData = 0, *NextConfirmData = 0; la_SendSignalsFromEvent(e); if(MAIN.InputProcess){ MAIN.CurrentInputEvent=e; MAIN.InputProcess(e); MAIN.CurrentInputEvent=0; } a = Operators->pFirst; la_DestroyConfirmData(&MAIN.InvokeConfirmData); while (1){ if (!a) break; if (a->StopNow){ NextA = a->Item.pNext; if (a->Type->Exit) a->Type->Exit(a, Result); ConfirmData = a->NextConfirmData; if (a->ConfirmData) la_DestroyConfirmData(&a->ConfirmData); NextConfirmData = ConfirmData; a->ConfirmData = 0; a->NextConfirmData = 0; la_DestroyOperator(&a, Operators, 0); a = NextA; if (a){ a->ConfirmData = NextConfirmData; } continue; } a->Using = 1; la_SetPropMathcerContext(a->ToPanel); laSetOperatorLocalizer(a->ToPanel); MAIN.CurrentPanel = a->ToPanel; if (a->Type->ExtraMark & LA_EXTRA_TO_PANEL){ laWindowToLocal(a, a->ToPanel, &e->x, &e->y); e->Localized = 1; } if (a->State & LA_BLOCK){ Result = a->Type->Modal(a, e); } if (a->Type->ExtraMark & LA_EXTRA_TO_PANEL){ laLocalToWindow(a, a->ToPanel, &e->x, &e->y); e->Localized = 0; } la_SetPropMathcerContext(0); laSetOperatorLocalizer(0); MAIN.CurrentPanel = 0; a->Using = 0; if (Result & LA_PASS_ON){ laConfirmSameDataIfAny(a); NextA = a->Item.pNext; }else{ NextA = 0; if (a->NextConfirmData){ la_DestroyConfirmData(&a->NextConfirmData); } } ConfirmData = a->NextConfirmData; if (a->ConfirmData) la_DestroyConfirmData(&a->ConfirmData); NextConfirmData = ConfirmData; a->ConfirmData = 0; a->NextConfirmData = 0; if (Result & LA_FINISH || Result == LA_CANCEL || (a->StopNow && a->Using == 0)){ if (a->Type->Exit) a->Type->Exit(a, Result); la_DestroyOperator(&a, Operators, 0); int found=0; for(laOperator*iop=Operators->pFirst;iop;iop=iop->Item.pNext){ if(iop==NextA){found=1;} } if(!found){ NextA=0; } if(Result == LA_OPERATOR_CALLS_SHUTOFF){ return 0; } } a = NextA; if (a){ a->ConfirmData = NextConfirmData; } } return 1; } int la_HandleEvents(laWindow *w){ laEvent *e, *NextE; laOperator *a; laThreadNotifier *tn; MAIN.CurrentWindow=w; //laSpinLock(&MAIN.csNotifier); while (tn = lstPopItem(&MAIN.ThreadNotifiers)){ //laSpinUnlock(&MAIN.csNotifier); laNotifyUsers(tn->Path); FreeMem(tn); //if (MAIN.ThreadNotifiers.pFirst) //laSpinLock(&MAIN.csNotifier); } //laSpinUnlock(&MAIN.csNotifier); while (1){ if (MAIN.ReTriggerOperators) laSendOperatorTriggerEvent(); while (w->EventList.pFirst){ while (w->PendingOperators.pLast){ a = w->PendingOperators.pLast; if (a->OperatorPanel){ laSetOperatorLocalizer(a->OperatorPanel); if (a->OperatorPanel->Mode == LA_PANEL_FLOATING_TOP) laInvokeUi(a, "LA_modal_panel_operator", 0, a->OperatorPanel, 0, 1); } lstRemoveItem(&w->PendingOperators, a); lstPushItem(&w->Operators, a); } e = lstPopItem(&w->EventList); if (e && !w->Operators.pFirst){ laInvokeUi(0, "LA_window_operator", e, w, 0, 0); } if (e) if(!la_HandleSingleEvent(e, &w->Operators)){ la_StopAllOperators(); memFree(e); return 0; } //EXIT memFree(e); } MAIN.ControllerHasNewAxis = MAIN.ControllerHasNewKey = 0; if (!MAIN.ReTriggerOperators) break; } la_UpdateOperatorHints(w); return 1; } int la_AllowInput(uint32_t ch){ if(ch>=32 || ch==U'\n' || ch==U'\t' || ch==U'\b') return 1; return 0; } int laCopyToClipboard(unsigned char * text){ #ifdef LA_LINUX XEvent event; SYSWINDOW owner, window=MAIN.CurrentWindow->win; XSetSelectionOwner(MAIN.dpy, MAIN.selection, window, 0); if (XGetSelectionOwner (MAIN.dpy, MAIN.selection) != window) return 0; strSafeSet(&MAIN.CopyPending, text); #endif } int la_ProcessSysMessage(){ int SendDelay = 0, SendIdle = 0; if (!MAIN.DelayTriggered && MAIN.TimeAccum - MAIN.DelayStart > MAIN.DelayTime) SendDelay = 1; if (!MAIN.IdleTriggered && MAIN.TimeAccum - MAIN.IdleStart > MAIN.IdleTime) SendIdle = 1; #ifdef LA_LINUX XEvent e; int type; int InputCount = 0, CharCount=0; KeySym InputKeysym = 0; Status InputStatus = 0; laWindow* wnd ; while(XPending(MAIN.dpy)){ XGenericEventCookie *cookie = &e.xcookie; XNextEvent(MAIN.dpy, &e); if (XFilterEvent(&e, None)) continue; SendIdle=0; MAIN.IdleStart=MAIN.TimeAccum; MAIN.IdleTriggered=0; if (cookie->type == GenericEvent && cookie->extension == MAIN.xi_opcode && XGetEventData(MAIN.dpy, cookie)){ if (cookie->evtype == XI_RawMotion) la_RecordWacomMotions(cookie->data); XFreeEventData(MAIN.dpy, cookie); continue; } switch(e.type){ case ConfigureNotify: la_CommandResizeWindow(e.xconfigure.window, e.xconfigure.x, e.xconfigure.y, e.xconfigure.width, e.xconfigure.height); break; case Expose: wnd = lstFindItem(e.xexpose.window, la_IsThisSysWindow, &MAIN.Windows); if(!wnd) break; laRefreshWindow(wnd); break; case MotionNotify: la_SendMouseEvent(e.xmotion.window, LA_MOUSEMOVE, e.xmotion.x,e.xmotion.y); MAIN.IsPen=0; break; case ButtonPress: type=LA_MOUSEDOWN; if(e.xbutton.button==1){type|=LA_KEY_MOUSE_LEFT;} elif(e.xbutton.button==2){type|=LA_KEY_MOUSE_MIDDLE;} elif(e.xbutton.button==3){type|=LA_KEY_MOUSE_RIGHT;} elif(e.xbutton.button==4){type=LA_MOUSEUP|LA_KEY_MOUSE_SCROLL;} elif(e.xbutton.button==5){type=LA_MOUSEDOWN|LA_KEY_MOUSE_SCROLL;} la_SendMouseEvent(e.xbutton.window, type, e.xbutton.x,e.xbutton.y); MAIN.IsPen=0; break; case ButtonRelease: type=LA_MOUSEUP; if(e.xbutton.button==1){type|=LA_KEY_MOUSE_LEFT;} elif(e.xbutton.button==2){type|=LA_KEY_MOUSE_MIDDLE;} elif(e.xbutton.button==3){type|=LA_KEY_MOUSE_RIGHT;} la_SendMouseEvent(e.xbutton.window, type, e.xbutton.x,e.xbutton.y); MAIN.IsPen=0; break; case KeyPress: InputCount=Xutf8LookupString(MAIN.ic, (XKeyPressedEvent*)&e, MAIN.InputBuf, MAIN.InputBufMax, &InputKeysym, &InputStatus); MAIN.InputBuf[InputCount]=0; if (InputStatus==XBufferOverflow) printf("XInputBufferOverflow\n"); if (InputStatus == XLookupKeySym || InputStatus == XLookupBoth) { /*printf("status: %d\n", InputStatus);*/ } if (InputCount){ MAIN.InputBuf[InputCount]=0; } strToUnicode(MAIN.InputBufU,MAIN.InputBuf); int UCount=strlenU(MAIN.InputBufU); for(int i=0;i=XK_KP_Space && InputKeysym<=XK_KP_9){ InputKeysym=XkbKeycodeToKeysym(e.xkey.display, e.xkey.keycode, 0, 1); } la_SendKeyboardEvent(e.xkey.window, LA_KEY_DOWN, la_TranslateSpecialKey(InputKeysym)); } break; case KeyRelease: if(InputKeysym=XkbKeycodeToKeysym(e.xkey.display, e.xkey.keycode, 0, 0)){ la_SendKeyboardEvent(e.xkey.window, LA_KEY_UP, la_TranslateSpecialKey(InputKeysym)); } case ClientMessage: if(e.xclient.data.l[0]==MAIN.MsgDelWindow){ if(la_OnWindowDestroy(e.xclient.window)){ return 0; } } break; case SelectionNotify: if(e.xselection.selection != MAIN.bufid) continue; if (e.xselection.property){ char *result; unsigned long ressize, restail; int resbits; Atom fmtid; XGetWindowProperty(MAIN.dpy, MAIN.CurrentWindow->win, MAIN.propid, 0, LONG_MAX/4, False, AnyPropertyType, &fmtid, &resbits, &ressize, &restail, (unsigned char**)&result); if (fmtid == MAIN.incrid) logPrintNew("Pasted buffer is too large and INCR reading is not implemented yet.\n"); else if(result) { arrEnsureLength(&MAIN.InputBufU, strlen(result), &MAIN.InputBufUMax, sizeof(uint32_t)); strToUnicode(MAIN.InputBufU,result); int UCount=strlenU(MAIN.InputBufU); for(int i=0;iPtr; int size=strlen(text); if (e.xselectionrequest.selection != MAIN.selection) break; XSelectionRequestEvent * xsr = &e.xselectionrequest; XSelectionEvent ev = {0}; int R = 0; ev.type = SelectionNotify, ev.display = xsr->display, ev.requestor = xsr->requestor, ev.selection = xsr->selection, ev.time = xsr->time, ev.target = xsr->target, ev.property = xsr->property; if (ev.target == MAIN.targets_atom) R = XChangeProperty (ev.display, ev.requestor, ev.property, XA_ATOM, 32, PropModeReplace, (unsigned char*)&MAIN.UTF8, 1); else if (ev.target == XA_STRING || ev.target == MAIN.text_atom) R = XChangeProperty(ev.display, ev.requestor, ev.property, XA_STRING, 8, PropModeReplace, text, size); else if (ev.target == MAIN.UTF8) R = XChangeProperty(ev.display, ev.requestor, ev.property, MAIN.UTF8, 8, PropModeReplace, text, size); else ev.property = None; if ((R & 2) == 0) XSendEvent (MAIN.dpy, ev.requestor, 0, 0, (XEvent *)&ev); break; case SelectionClear: break; default: break; } } #endif //linux #ifdef _WIN32 MSG msg; int Processed = 0; if (PeekMessage(&msg, 0, 0, 0, PM_NOREMOVE) != 0) Processed = 1; while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { if (msg.wParam == VK_PROCESSKEY) { msg.wParam = ImmGetVirtualKey(msg.hwnd); } TranslateMessage(&msg); DispatchMessage(&msg); SendIdle = 0; MAIN.IdleStart = MAIN.TimeAccum; MAIN.IdleTriggered = 0; }; if(!MAIN.Windows.pFirst){ return 0; } #endif #ifdef LAGUI_ANDROID int pollResult = 0; int pollEvents = 0; while ((pollResult = ALooper_pollAll(MAIN.AppEnabled? 0 : -1, NULL, &pollEvents, (void**)&MAIN.event_source)) >= 0){ if (MAIN.event_source != NULL) MAIN.event_source->process(MAIN.app, MAIN.event_source); // NOTE: Never close window, native activity is controlled by the system! if (MAIN.app->destroyRequested != 0) { //CORE.Window.shouldClose = true; //ANativeActivity_finish(MAIN.app->activity); } } #endif for(laWindow* w=MAIN.Windows.pFirst;w;w=w->Item.pNext){ if(SendDelay) { la_SendTimerEvent(w->win, LA_TIME_DELAY); MAIN.DelayTriggered=1; } if(SendIdle) { la_SendTimerEvent(w->win, LA_TIME_IDLE); MAIN.IdleTriggered=1; } } return 1; }; void la_PrintOperatorStack(){ laWindow *w = MAIN.CurrentWindow; laOperator *a; printf("\n"); for (a = w->Operators.pFirst; a; a = a->Item.pNext){ printf("OP [%-25s] For [0x%08x] Child[%-25s][0x%08x]\n", a->Type->Identifier, a->Instance, (a->Child ? a->Child->Type->Identifier : ""), a->Child); } } void la_DrawWindow(laWindow *w){ if(!w->Redraw) return; w->Redraw=0; w->RedrawTouched=1; MAIN.CurrentWindow = w; la_WindowDefDraw(w, 0); } int laFinalize(){ if(!laValidateProperties()){ laShutoff(0); return 0; } laUiTemplate* uit; while(uit=lstPopItem(&MAIN.InitPanelTemplates)) lstAppendItem(&MAIN.PanelTemplates,uit); return 1; } void la_PreFrame(){ if(MAIN.PreFrame){ MAIN.PreFrame(); } la_AnimationPreFrame(); if(MAIN.InitArgs.HasAudio) la_AudioPreFrame(); } void la_PostFrame(){ laPanel* p; while(p=lstPopPointer(&MAIN.DeferredRedrawList)){ laRedrawPanel(p); } if(MAIN.PostFrame){ MAIN.PostFrame(); } } void laMainLoop(){ laWindow *w = MAIN.Windows.pFirst, *NextW; time_t t1, t2; real TimeInterval, Pause, TimeAccum = 0, FrameInterval; static int a = 0; if(!laFinalize()) return; laSetWindowCursor(LA_ARROW); MAIN.DelayTriggered=1; #ifdef LAGUI_ANDROID while(!MAIN.AppReady){ usleep(1000); } la_CommandResizeWindow(0,0,0,MAIN.AppWidth,MAIN.AppHeight); #endif while (1){ laRecordTime(&MAIN.FrameStartTime); la_PerfClear(); la_PreFrame(); if(!la_ProcessSysMessage()){ return; } la_UpdateControllerStatus(); if(MAIN.GraphNeedsRebuild){ MAIN.GraphNeedsRebuild = 0; } for (w=MAIN.Windows.pFirst;w;w = NextW){ NextW = w->Item.pNext; if(!la_HandleEvents(w)){ laShutoff(1); return; } } if(MAIN.PreDraw){ MAIN.PreDraw(); } for(w=MAIN.Windows.pFirst;w;w=w->Item.pNext){ tnsSwitchToCurrentWindowContext(w); la_SetupWindowGLStates(w); if(MAIN.GLDebugNeedsUpdate){ la_SetCurrentGLContextDebug(); } la_DrawWindow(w); } for(w=MAIN.Windows.pFirst;w;w=w->Item.pNext){ if(!w->RedrawTouched) continue; w->RedrawTouched=0; #ifdef LA_LINUX #ifdef LA_USE_GLES eglSwapBuffers(MAIN.egl_dpy, w->egl_surf); #else glXSwapBuffers(MAIN.dpy, w->win); //XSync(MAIN.dpy,0); #endif #endif #ifdef _WIN32 SwapBuffers(w->hdc); #endif #ifdef LAGUI_ANDROID eglSwapBuffers(MAIN.egl_dpy, MAIN.egl_surf); #endif } MAIN.GLDebugNeedsUpdate=0; la_PostFrame(); //t2 = clock(); laRecordTime(&MAIN.FrameEndTime); TimeInterval = laTimeElapsedSecondsf(&MAIN.FrameEndTime, &MAIN.FrameStartTime); Pause = (1.0 / MAIN.TopFramerate - TimeInterval); if (Pause > 0){ int us = Pause * 1000000.0; usleep(us); } MAIN.TimeAccum += (MAIN.LastFrameTime = Pause+TimeInterval); //FrameInterval = 1.0 / MAIN.Animation.FrameRate; la_AnimationPostFrame(); } } #ifdef LAGUI_ANDROID int la_AndroidInitGraphics(void){ MAIN.AppWidth=ANativeWindow_getWidth(MAIN.app->window); MAIN.AppHeight=ANativeWindow_getHeight(MAIN.app->window); logPrintNew("Android init graphics %d x %d", MAIN.AppWidth, MAIN.AppHeight); la_CommandResizeWindow(0,0,0,MAIN.AppWidth,MAIN.AppHeight); EGLint samples = 0; EGLint sampleBuffer = 0; const EGLint framebufferAttribs[] = { EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT, // Type of context support EGL_RED_SIZE, 8, // RED color bit depth (alternative: 5) EGL_GREEN_SIZE, 8, // GREEN color bit depth (alternative: 6) EGL_BLUE_SIZE, 8, // BLUE color bit depth (alternative: 5) //EGL_TRANSPARENT_TYPE, EGL_NONE, // Request transparent framebuffer (EGL_TRANSPARENT_RGB does not work on RPI) EGL_DEPTH_SIZE, 16, // Depth buffer size (Required to use Depth testing!) //EGL_STENCIL_SIZE, 8, // Stencil buffer size EGL_SAMPLE_BUFFERS, sampleBuffer, // Activate MSAA EGL_SAMPLES, samples, // 4x Antialiasing if activated (Free on MALI GPUs) EGL_NONE }; const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE }; EGLint numConfigs = 0; MAIN.egl_dpy=eglGetDisplay(EGL_DEFAULT_DISPLAY); if (MAIN.egl_dpy == EGL_NO_DISPLAY){ logPrint("Android no display"); return -1; } if (eglInitialize(MAIN.egl_dpy, NULL, NULL) == EGL_FALSE){ logPrint("Android can't init display"); return -1; } eglChooseConfig(MAIN.egl_dpy, framebufferAttribs, &MAIN.BestFBC, 1, &numConfigs); eglBindAPI(EGL_OPENGL_API); MAIN.glc = eglCreateContext(MAIN.egl_dpy, MAIN.BestFBC, EGL_NO_CONTEXT, contextAttribs); if (MAIN.glc == EGL_NO_CONTEXT){ logPrint("Android can't create context"); return -1; } EGLint displayFormat = 0; eglGetConfigAttrib(MAIN.egl_dpy, MAIN.BestFBC, EGL_NATIVE_VISUAL_ID, &displayFormat); ANativeWindow_setBuffersGeometry(MAIN.app->window, MAIN.AppWidth, MAIN.AppHeight, displayFormat); MAIN.egl_surf = eglCreateWindowSurface(MAIN.egl_dpy, MAIN.BestFBC, MAIN.app->window, NULL); // There must be at least one frame displayed before the buffers are swapped eglSwapInterval(MAIN.egl_dpy, 1); if (eglMakeCurrent(MAIN.egl_dpy, MAIN.egl_surf, MAIN.egl_surf, MAIN.glc) == EGL_FALSE) { logPrint("Android can't make current"); return -1; } eglSwapBuffers(MAIN.egl_dpy, MAIN.egl_surf); MAIN.AppReady = 1; return 0; } static void la_AndroidCommandCallback(struct android_app *app, int32_t cmd){ switch (cmd){ case APP_CMD_START: break; case APP_CMD_GAINED_FOCUS: MAIN.AppEnabled = 1; break; case APP_CMD_LOST_FOCUS: MAIN.AppEnabled = 0; break; case APP_CMD_RESUME:break;//InitPlatform();break; case APP_CMD_INIT_WINDOW: if (app->window != NULL){ if (MAIN.ContextRebindRequired){ // Reset screen scaling to full display size EGLint displayFormat = 0; eglGetConfigAttrib(MAIN.egl_dpy, MAIN.BestFBC, EGL_NATIVE_VISUAL_ID, &displayFormat); // Adding renderOffset here feels rather hackish, but the viewport scaling is wrong after the // context rebinding if the screen is scaled unless offsets are added. There's probably a more // appropriate way to fix this MAIN.AppWidth=ANativeWindow_getWidth(MAIN.app->window); MAIN.AppHeight=ANativeWindow_getHeight(MAIN.app->window); ANativeWindow_setBuffersGeometry(app->window,MAIN.AppWidth,MAIN.AppHeight, displayFormat); // Recreate display surface and re-attach OpenGL context MAIN.egl_surf = eglCreateWindowSurface(MAIN.egl_dpy, MAIN.BestFBC, app->window, NULL); eglMakeCurrent(MAIN.egl_dpy, MAIN.egl_surf, MAIN.egl_surf, MAIN.glc); //glViewport(0,0,MAIN.AppWidth,MAIN.AppHeight); //glClearColor(1,0.2,1,1); //glClear(GL_COLOR_BUFFER_BIT); //eglSwapBuffers(MAIN.egl_dpy, MAIN.egl_surf); la_CommandResizeWindow(0,0,0,MAIN.AppWidth,MAIN.AppHeight); MAIN.ContextRebindRequired = false; }else{ la_AndroidInitGraphics(); } } break; case APP_CMD_DESTROY: case APP_CMD_TERM_WINDOW: // Detach OpenGL context and destroy discom.yiming.helloplay surface // NOTE 1: This case is used when the user exits the app without closing it. We detach the context to ensure everything is recoverable upon resuming. // NOTE 2: Detaching context before destroying display surface avoids losing our resources (textures, shaders, VBOs...) // NOTE 3: In some cases (too many context loaded), OS could unload context automatically... :( if (MAIN.egl_dpy != EGL_NO_DISPLAY) { eglMakeCurrent(MAIN.egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (MAIN.egl_surf != EGL_NO_SURFACE) { eglDestroySurface(MAIN.egl_dpy, MAIN.egl_surf); MAIN.egl_surf = EGL_NO_SURFACE; } MAIN.ContextRebindRequired = true; } // If 'MAIN.egl_dpy' is already set to 'EGL_NO_DISPLAY' // this means that the user has already called 'CloseWindow()' break; case APP_CMD_SAVE_STATE: break; case APP_CMD_STOP: break; case APP_CMD_CONFIG_CHANGED: case APP_CMD_WINDOW_RESIZED: MAIN.AppWidth=ANativeWindow_getWidth(MAIN.app->window); MAIN.AppHeight=ANativeWindow_getHeight(MAIN.app->window); la_CommandResizeWindow(0,0,0,MAIN.AppWidth,MAIN.AppHeight); //AConfiguration_fromAssetManager(MAIN.app->config, MAIN.app->activity->assetManager); //print_cur_config(MAIN.app); // Check screen orientation here! if (MAIN.egl_dpy != EGL_NO_DISPLAY) { eglMakeCurrent(MAIN.egl_dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); if (MAIN.egl_surf != EGL_NO_SURFACE) { eglDestroySurface(MAIN.egl_dpy, MAIN.egl_surf); MAIN.egl_surf = EGL_NO_SURFACE; } EGLint displayFormat = 0; eglGetConfigAttrib(MAIN.egl_dpy, MAIN.BestFBC, EGL_NATIVE_VISUAL_ID, &displayFormat); ANativeWindow_setBuffersGeometry(app->window,MAIN.AppWidth,MAIN.AppHeight, displayFormat); MAIN.egl_surf = eglCreateWindowSurface(MAIN.egl_dpy, MAIN.BestFBC, app->window, NULL); eglMakeCurrent(MAIN.egl_dpy, MAIN.egl_surf, MAIN.egl_surf, MAIN.glc); } break; default: break; } } #define KEYCODE_MAP_SIZE 162 static const int KeycodeMap[KEYCODE_MAP_SIZE] = { 0, // AKEYCODE_UNKNOWN 0, // AKEYCODE_SOFT_LEFT 0, // AKEYCODE_SOFT_RIGHT 0, // AKEYCODE_HOME 0, // AKEYCODE_BACK 0, // AKEYCODE_CALL 0, // AKEYCODE_ENDCALL '0', // AKEYCODE_0 '1', // AKEYCODE_1 '2', // AKEYCODE_2 '3', // AKEYCODE_3 '4', // AKEYCODE_4 '5', // AKEYCODE_5 '6', // AKEYCODE_6 '7', // AKEYCODE_7 '8', // AKEYCODE_8 '9', // AKEYCODE_9 0, // AKEYCODE_STAR 0, // AKEYCODE_POUND LA_KEY_ARRUP, // AKEYCODE_DPAD_UP LA_KEY_ARRDOWN, // AKEYCODE_DPAD_DOWN LA_KEY_ARRLEFT, // AKEYCODE_DPAD_LEFT LA_KEY_ARRRIGHT, // AKEYCODE_DPAD_RIGHT 0, // AKEYCODE_DPAD_CENTER 0, // AKEYCODE_VOLUME_UP 0, // AKEYCODE_VOLUME_DOWN 0, // AKEYCODE_POWER 0, // AKEYCODE_CAMERA 0, // AKEYCODE_CLEAR 'a', // AKEYCODE_A 'b', // AKEYCODE_B 'c', // AKEYCODE_C 'd', // AKEYCODE_D 'e', // AKEYCODE_E 'f', // AKEYCODE_F 'g', // AKEYCODE_G 'h', // AKEYCODE_H 'i', // AKEYCODE_I 'j', // AKEYCODE_J 'k', // AKEYCODE_K 'l', // AKEYCODE_L 'm', // AKEYCODE_M 'n', // AKEYCODE_N 'o', // AKEYCODE_O 'p', // AKEYCODE_P 'q', // AKEYCODE_Q 'r', // AKEYCODE_R 's', // AKEYCODE_S 't', // AKEYCODE_T 'u', // AKEYCODE_U 'v', // AKEYCODE_V 'w', // AKEYCODE_W 'x', // AKEYCODE_X 'y', // AKEYCODE_Y 'z', // AKEYCODE_Z ',', // AKEYCODE_COMMA '.', // AKEYCODE_PERIOD LA_KEY_ALT, // AKEYCODE_ALT_LEFT LA_KEY_ALT, // AKEYCODE_ALT_RIGHT LA_KEY_SHIFT, // AKEYCODE_SHIFT_LEFT LA_KEY_SHIFT, // AKEYCODE_SHIFT_RIGHT LA_KEY_TAB, // AKEYCODE_TAB ' ', // AKEYCODE_SPACE 0, // AKEYCODE_SYM 0, // AKEYCODE_EXPLORER 0, // AKEYCODE_ENVELOPE LA_KEY_ENTER, // AKEYCODE_ENTER LA_KEY_BACKSPACE, // AKEYCODE_DEL '`', // AKEYCODE_GRAVE '-', // AKEYCODE_MINUS '=', // AKEYCODE_EQUALS '(', // AKEYCODE_LEFT_BRACKET ')', // AKEYCODE_RIGHT_BRACKET '\\', // AKEYCODE_BACKSLASH ';', // AKEYCODE_SEMICOLON '\'', // AKEYCODE_APOSTROPHE '/', // AKEYCODE_SLASH 0, // AKEYCODE_AT 0, // AKEYCODE_NUM 0, // AKEYCODE_HEADSETHOOK 0, // AKEYCODE_FOCUS 0, // AKEYCODE_PLUS 0, // AKEYCODE_MENU 0, // AKEYCODE_NOTIFICATION 0, // AKEYCODE_SEARCH 0, // AKEYCODE_MEDIA_PLAY_PAUSE 0, // AKEYCODE_MEDIA_STOP 0, // AKEYCODE_MEDIA_NEXT 0, // AKEYCODE_MEDIA_PREVIOUS 0, // AKEYCODE_MEDIA_REWIND 0, // AKEYCODE_MEDIA_FAST_FORWARD 0, // AKEYCODE_MUTE 0, // AKEYCODE_PAGE_UP 0, // AKEYCODE_PAGE_DOWN 0, // AKEYCODE_PICTSYMBOLS 0, // AKEYCODE_SWITCH_CHARSET 0, // AKEYCODE_BUTTON_A 0, // AKEYCODE_BUTTON_B 0, // AKEYCODE_BUTTON_C 0, // AKEYCODE_BUTTON_X 0, // AKEYCODE_BUTTON_Y 0, // AKEYCODE_BUTTON_Z 0, // AKEYCODE_BUTTON_L1 0, // AKEYCODE_BUTTON_R1 0, // AKEYCODE_BUTTON_L2 0, // AKEYCODE_BUTTON_R2 0, // AKEYCODE_BUTTON_THUMBL 0, // AKEYCODE_BUTTON_THUMBR 0, // AKEYCODE_BUTTON_START 0, // AKEYCODE_BUTTON_SELECT 0, // AKEYCODE_BUTTON_MODE LA_KEY_ESCAPE, // AKEYCODE_ESCAPE LA_KEY_DELETE, // AKEYCODE_FORWARD_DELL LA_KEY_CTRL, // AKEYCODE_CTRL_LEFT LA_KEY_CTRL, // AKEYCODE_CTRL_RIGHT 0, // AKEYCODE_CAPS_LOCK 0, // AKEYCODE_SCROLL_LOCK LA_KEY_ARRLEFT, // AKEYCODE_META_LEFT LA_KEY_ARRRIGHT, // AKEYCODE_META_RIGHT 0, // AKEYCODE_FUNCTION 0, // AKEYCODE_SYSRQ 0, // AKEYCODE_BREAK 0, // AKEYCODE_MOVE_HOME 0, // AKEYCODE_MOVE_END 0, // AKEYCODE_INSERT 0, // AKEYCODE_FORWARD 0, // AKEYCODE_MEDIA_PLAY 0, // AKEYCODE_MEDIA_PAUSE 0, // AKEYCODE_MEDIA_CLOSE 0, // AKEYCODE_MEDIA_EJECT 0, // AKEYCODE_MEDIA_RECORD LA_KEY_F1, // AKEYCODE_F1 LA_KEY_F2, // AKEYCODE_F2 LA_KEY_F3, // AKEYCODE_F3 LA_KEY_F4, // AKEYCODE_F4 LA_KEY_F5, // AKEYCODE_F5 LA_KEY_F6, // AKEYCODE_F6 LA_KEY_F7, // AKEYCODE_F7 LA_KEY_F8, // AKEYCODE_F8 LA_KEY_F9, // AKEYCODE_F9 LA_KEY_F10, // AKEYCODE_F10 LA_KEY_F11, // AKEYCODE_F11 LA_KEY_F12, // AKEYCODE_F12 0, // AKEYCODE_NUM_LOCK LA_KEY_NUM0, // AKEYCODE_NUMPAD_0 LA_KEY_NUM1, // AKEYCODE_NUMPAD_1 LA_KEY_NUM2, // AKEYCODE_NUMPAD_2 LA_KEY_NUM3, // AKEYCODE_NUMPAD_3 LA_KEY_NUM4, // AKEYCODE_NUMPAD_4 LA_KEY_NUM5, // AKEYCODE_NUMPAD_5 LA_KEY_NUM6, // AKEYCODE_NUMPAD_6 LA_KEY_NUM7, // AKEYCODE_NUMPAD_7 LA_KEY_NUM8, // AKEYCODE_NUMPAD_8 LA_KEY_NUM9, // AKEYCODE_NUMPAD_9 LA_KEY_NUMDIVIDE, // AKEYCODE_NUMPAD_DIVIDE LA_KEY_NUMMULT, // AKEYCODE_NUMPAD_MULTIPLY LA_KEY_NUMMINUS, // AKEYCODE_NUMPAD_SUBTRACT LA_KEY_NUMPLUS, // AKEYCODE_NUMPAD_ADD LA_KEY_NUMDOT, // AKEYCODE_NUMPAD_DOT 0, // AKEYCODE_NUMPAD_COMMA LA_KEY_NUMENTER, // AKEYCODE_NUMPAD_ENTER '=' // AKEYCODE_NUMPAD_EQUALS }; static int32_t la_AndroidInputCallback(struct android_app *app, AInputEvent *event) { __android_log_print(ANDROID_LOG_DEBUG, "huh 5678", "123 input"); if(!MAIN.AppEnabled){return 0;} //laRedrawAllWindows(); static int prev_button_state=0; int type = AInputEvent_getType(event); if(type == AINPUT_EVENT_TYPE_KEY){ int32_t keycode = AKeyEvent_getKeyCode(event); //int32_t AKeyEvent_getMetaState(event); int key = (keycode > 0 && keycode < KEYCODE_MAP_SIZE) ? KeycodeMap[keycode] : 0; if (key != 0){ // Save current key and its state // NOTE: Android key action is 0 for down and 1 for up if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_DOWN){ la_SendKeyboardEvent(0,LA_KEY_DOWN,key); if(key!=LA_KEY_BACKSPACE) la_SendInputEvent(0,key); } else if (AKeyEvent_getAction(event) == AKEY_EVENT_ACTION_MULTIPLE){ la_SendKeyboardEvent(0,LA_KEY_DOWN,key); la_SendInputEvent(0,key); } else la_SendKeyboardEvent(0,LA_KEY_UP,key); // Key up } if (keycode == AKEYCODE_POWER) { // Let the OS handle input to avoid app stuck. Behaviour: CMD_PAUSE -> CMD_SAVE_STATE -> CMD_STOP -> CMD_CONFIG_CHANGED -> CMD_LOST_FOCUS // Resuming Behaviour: CMD_START -> CMD_RESUME -> CMD_CONFIG_CHANGED -> CMD_CONFIG_CHANGED -> CMD_GAINED_FOCUS // It seems like locking mobile, screen size (CMD_CONFIG_CHANGED) is affected. // NOTE: AndroidManifest.xml must have // Before that change, activity was calling CMD_TERM_WINDOW and CMD_DESTROY when locking mobile, so that was not a normal behaviour return 0; } else if ((keycode == AKEYCODE_BACK) || (keycode == AKEYCODE_MENU)) { // Eat BACK_BUTTON and AKEYCODE_MENU, just do nothing... and don't let to be handled by OS! return 1; } else if ((keycode == AKEYCODE_VOLUME_UP) || (keycode == AKEYCODE_VOLUME_DOWN)) { // Set default OS behaviour return 0; } return 0; } elif(type == AINPUT_EVENT_TYPE_MOTION){ static real zoom_offset=1; static real temp_distance=0; real zoom; int gesture_handled=0; int pcount = AMotionEvent_getPointerCount(event); int x,y; static real cx=0,cy=0; int32_t action = AMotionEvent_getAction(event); unsigned int flags = action & AMOTION_EVENT_ACTION_MASK; int32_t pointerIndex = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; real rx=AMotionEvent_getX(event, 0), ry=AMotionEvent_getY(event, 0); if(pcount){ x=rx; y=ry; int tool_type=AMotionEvent_getToolType(event,0); real pressure = AMotionEvent_getAxisValue(event,AMOTION_EVENT_AXIS_PRESSURE,0); if(tool_type == AMOTION_EVENT_TOOL_TYPE_STYLUS || tool_type==AMOTION_EVENT_TOOL_TYPE_ERASER){ MAIN.StylusPressure = MAIN.EraserPressure = pressure; MAIN.IsPen = 1; MAIN.PointerIsEraser = (tool_type==AMOTION_EVENT_TOOL_TYPE_ERASER); }else{ MAIN.IsPen = 0; } if(pcount>=2 && (flags!=AMOTION_EVENT_ACTION_UP) && (flags!=AMOTION_EVENT_ACTION_CANCEL) && (flags!=AMOTION_EVENT_ACTION_POINTER_UP)){ real x2=AMotionEvent_getX(event, 1), y2=AMotionEvent_getY(event, 1); real ctx=(x+x2)/2, cty=(y+y2)/2; real distance = tnsDistIdv2(x2,y2,rx,ry); if(temp_distance){ zoom_offset*=(distance/temp_distance); } temp_distance = distance; while(zoom_offset > 1.1){ zoom_offset-=0.1; la_SendMouseEvent(0, LA_L_MOUSE_UP, x,y); la_SendMouseEvent(0, LA_MOUSEUP|LA_KEY_MOUSE_SCROLL, x,y); gesture_handled=1; } while(zoom_offset < (1.0/1.1)){ zoom_offset+=(0.1/1.1); la_SendMouseEvent(0, LA_L_MOUSE_UP, x,y); la_SendMouseEvent(0, LA_MOUSEDOWN|LA_KEY_MOUSE_SCROLL, x,y); gesture_handled=1; } if(cx || cy){ if(!gesture_handled){ real dist = tnsDistIdv2(ctx,cty,cx,cy); while(dist > LA_RH){ int udlr = fabs(cty-cy) > fabs(ctx-cx); int direction = udlr?(cty>cy?LA_KEY_ARRUP:LA_KEY_ARRDOWN): (ctx>cx?LA_KEY_ARRLEFT:LA_KEY_ARRRIGHT); real fac = (real)(LA_RH)/dist; cx=tnsLinearItp(cx,ctx,fac); cy=tnsLinearItp(cy,cty,fac); la_SendMouseEvent(0, LA_L_MOUSE_UP, x,y); la_SendKeyboardEvent(0, LA_KEY_DOWN, direction|LA_KEYBOARD_EVENT|LA_KEY_PANNING); gesture_handled=1; dist = tnsDistIdv2(ctx,cty,cx,cy); } } }else{ cx=ctx; cy=cty; } }else{ temp_distance = 0; cx=0; cy=0; } if(flags==AMOTION_EVENT_ACTION_HOVER_MOVE){ la_SendMouseEvent(0, LA_MOUSEMOVE, rx,ry); } } if(!gesture_handled){ if (flags == AMOTION_EVENT_ACTION_DOWN || flags == AMOTION_EVENT_ACTION_BUTTON_PRESS){ la_SendMouseEvent(0,LA_MOUSEMOVE,x,y); int btn=AMotionEvent_getButtonState(event); int evtype=LA_L_MOUSE_DOWN; if(btn & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY){ evtype=LA_M_MOUSE_DOWN; } elif(btn & AMOTION_EVENT_BUTTON_STYLUS_SECONDARY){ evtype=LA_R_MOUSE_DOWN; } la_SendMouseEvent(0,evtype,x,y); prev_button_state = btn; } else if (flags == AMOTION_EVENT_ACTION_UP || flags == AMOTION_EVENT_ACTION_BUTTON_RELEASE){ int btn=AMotionEvent_getButtonState(event); int changed = (~btn)&prev_button_state; int evtype=LA_L_MOUSE_UP; if(changed & AMOTION_EVENT_BUTTON_STYLUS_PRIMARY){ evtype=LA_M_MOUSE_UP; } elif(changed & AMOTION_EVENT_BUTTON_STYLUS_SECONDARY){ evtype=LA_R_MOUSE_UP; } la_SendMouseEvent(0,evtype,x,y); } else if (flags == AMOTION_EVENT_ACTION_MOVE){ la_SendMouseEvent(0,LA_MOUSEMOVE,x,y); } else if (flags == AMOTION_EVENT_ACTION_CANCEL){ la_SendMouseEvent(0,LA_L_MOUSE_UP,x,y); } } } //static float r=0; //eglMakeCurrent(MAIN.egl_dpy, MAIN.egl_surf, MAIN.egl_surf, MAIN.glc); //glViewport(0,0,MAIN.AppWidth,MAIN.AppHeight); //glClearColor(r,0.2,1,1); r+=0.01; if(r>1){ r=0; } //glClear(GL_COLOR_BUFFER_BIT); //eglSwapBuffers(MAIN.egl_dpy, MAIN.egl_surf); return 0; } void la_InitAssetManager(AAssetManager *manager, const char *dataPath, const char *externalDataPath){ MAIN.AssetManager = manager; MAIN.InternalDataPath = dataPath; MAIN.ExternalDataPath = externalDataPath; } static int android_read(void *cookie, char *data, int dataSize){ return AAsset_read((AAsset *)cookie, data, dataSize); } static int android_write(void *cookie, const char *data, int dataSize){ return 0; } static fpos_t android_seek(void *cookie, fpos_t offset, int whence){ return AAsset_seek((AAsset *)cookie, offset, whence); } static int android_close(void *cookie){ AAsset_close((AAsset *)cookie); return 0; } // Replacement for fopen() // Ref: https://developer.android.com/ndk/reference/group/asset FILE *android_fopen(const char *fileName, const char *mode) { char buf[1024]; if (mode[0] == 'w') { // fopen() is mapped to android_fopen() that only grants read access to // assets directory through AAssetManager but we want to also be able to // write data when required using the standard stdio FILE access functions // Ref: https://stackoverflow.com/questions/11294487/android-writing-saving-files-from-native-code-only #undef fopen FILE* result=fopen(fileName, mode); if(result){ return result; } sprintf(buf,"%s/%s", MAIN.InternalDataPath, fileName); result=fopen(buf, mode); if(result) return result; sprintf(buf,"%s/%s", MAIN.ExternalDataPath, fileName); return fopen(buf, mode); #define fopen(name, mode) android_fopen(name, mode) } else { // NOTE: AAsset provides access to read-only asset AAsset *asset = AAssetManager_open(MAIN.AssetManager, fileName, AASSET_MODE_UNKNOWN); if (asset != NULL) { // Get pointer to file in the assets return funopen(asset, android_read, android_write, android_seek, android_close); } else { #undef fopen FILE* result=fopen(fileName, mode); if(result){ return result; } // Just do a regular open if file is not found in the assets sprintf(buf,"%s/%s", MAIN.InternalDataPath, fileName); result=fopen(buf, mode); if(result){ return result; } sprintf(buf,"%s/%s", MAIN.ExternalDataPath, fileName); return fopen(buf, mode); #define fopen(name, mode) android_fopen(name, mode) } } } void la_HideNavBar(){ JavaVM* lJavaVM = MAIN.app->activity->vm; JNIEnv* lJNIEnv = MAIN.app->activity->env; (*lJavaVM)->AttachCurrentThread(lJavaVM, &lJNIEnv,0); jclass activityClass = (*lJNIEnv)->FindClass(lJNIEnv,"android/app/NativeActivity"); jmethodID getWindow = (*lJNIEnv)->GetMethodID(lJNIEnv,activityClass, "getWindow", "()Landroid/view/Window;"); jclass windowClass = (*lJNIEnv)->FindClass(lJNIEnv,"android/view/Window"); jmethodID getDecorView = (*lJNIEnv)->GetMethodID(lJNIEnv,windowClass, "getDecorView", "()Landroid/view/View;"); jclass viewClass = (*lJNIEnv)->FindClass(lJNIEnv,"android/view/View"); jmethodID setSystemUiVisibility = (*lJNIEnv)->GetMethodID(lJNIEnv,viewClass, "setSystemUiVisibility", "(I)V"); jobject window = (*lJNIEnv)->CallObjectMethod(lJNIEnv,MAIN.app->activity->clazz, getWindow); jobject decorView = (*lJNIEnv)->CallObjectMethod(lJNIEnv,window, getDecorView); jfieldID flagFullscreenID = (*lJNIEnv)->GetStaticFieldID(lJNIEnv,viewClass, "SYSTEM_UI_FLAG_FULLSCREEN", "I"); jfieldID flagHideNavigationID = (*lJNIEnv)->GetStaticFieldID(lJNIEnv,viewClass, "SYSTEM_UI_FLAG_HIDE_NAVIGATION", "I"); int flagFullscreen = (*lJNIEnv)->GetStaticIntField(lJNIEnv,viewClass, flagFullscreenID); int flagHideNavigation = (*lJNIEnv)->GetStaticIntField(lJNIEnv,viewClass, flagHideNavigationID); int flag = flagFullscreen | flagHideNavigation; (*lJNIEnv)->CallVoidMethod(lJNIEnv,decorView, setSystemUiVisibility, flag); (*lJavaVM)->DetachCurrentThread(lJavaVM); } void la_InitAndroidPlatform(struct android_app *app){ MAIN.app=app; ANativeActivity_setWindowFlags(MAIN.app->activity, AWINDOW_FLAG_FULLSCREEN, 0); //AWINDOW_FLAG_SCALED, AWINDOW_FLAG_DITHER //la_HideNavBar(); MAIN.app->onAppCmd = la_AndroidCommandCallback; MAIN.app->onInputEvent = la_AndroidInputCallback; la_InitAssetManager(MAIN.app->activity->assetManager, MAIN.app->activity->internalDataPath, MAIN.app->activity->externalDataPath); int pollResult = 0; int pollEvents = 0; while (!MAIN.AppReady){ while ((pollResult = ALooper_pollAll(MAIN.AppEnabled? 0 : -1, NULL, &pollEvents, (void**)&MAIN.event_source)) >= 0){ // Process this event if (MAIN.event_source != NULL) MAIN.event_source->process(MAIN.app, MAIN.event_source); // NOTE: Never close window, native activity is controlled by the system! //if (MAIN.app->destroyRequested != 0) CORE.Window.shouldClose = true; } } } int main(int, char *[]); void android_main(struct android_app *app){ char arg0[] = "lagui"; // NOTE: argv[] are mutable la_InitAndroidPlatform(app); // NOTE: Return from main is ignored (void)main(1, (char *[]) { arg0, NULL }); // Request to end the native activity ANativeActivity_finish(app->activity); // Android ALooper_pollAll() variables int pollResult = 0; int pollEvents = 0; // Waiting for application events before complete finishing while (!app->destroyRequested) { while ((pollResult = ALooper_pollAll(0, NULL, &pollEvents, (void **)&MAIN.event_source)) >= 0) { if ( MAIN.event_source != NULL) MAIN.event_source->process(app, MAIN.event_source); } } } void la_DisplayKeyboard(bool pShow) { // Attaches the current thread to the JVM. jint lResult; jint lFlags = 0; JavaVM* lJavaVM = MAIN.app->activity->vm; JNIEnv* lJNIEnv = MAIN.app->activity->env; JavaVMAttachArgs lJavaVMAttachArgs; lJavaVMAttachArgs.version = JNI_VERSION_1_6; lJavaVMAttachArgs.name = "NativeThread"; lJavaVMAttachArgs.group = NULL; lResult=(*lJavaVM)->AttachCurrentThread(lJavaVM, &lJNIEnv,0); if (lResult == JNI_ERR) { return; } // Retrieves NativeActivity. jobject lNativeActivity = MAIN.app->activity->clazz; jclass ClassNativeActivity = (*lJNIEnv)->GetObjectClass(lJNIEnv,lNativeActivity); logPrintNew("jvm3"); // Retrieves Context.INPUT_METHOD_SERVICE. jclass ClassContext = (*lJNIEnv)->FindClass(lJNIEnv,"android/content/Context"); jfieldID FieldINPUT_METHOD_SERVICE = (*lJNIEnv)->GetStaticFieldID(lJNIEnv,ClassContext, "INPUT_METHOD_SERVICE", "Ljava/lang/String;"); jobject INPUT_METHOD_SERVICE = (*lJNIEnv)->GetStaticObjectField(lJNIEnv,ClassContext, FieldINPUT_METHOD_SERVICE); //jniCheck(INPUT_METHOD_SERVICE); logPrintNew("jvm4"); // Runs getSystemService(Context.INPUT_METHOD_SERVICE). jclass ClassInputMethodManager = (*lJNIEnv)->FindClass(lJNIEnv, "android/view/inputmethod/InputMethodManager"); jmethodID MethodGetSystemService = (*lJNIEnv)->GetMethodID(lJNIEnv, ClassNativeActivity, "getSystemService", "(Ljava/lang/String;)Ljava/lang/Object;"); jobject lInputMethodManager = (*lJNIEnv)->CallObjectMethod(lJNIEnv, lNativeActivity, MethodGetSystemService, INPUT_METHOD_SERVICE); // Runs getWindow().getDecorView(). jmethodID MethodGetWindow = (*lJNIEnv)->GetMethodID(lJNIEnv, ClassNativeActivity, "getWindow", "()Landroid/view/Window;"); jobject lWindow = (*lJNIEnv)->CallObjectMethod(lJNIEnv,lNativeActivity, MethodGetWindow); jclass ClassWindow = (*lJNIEnv)->FindClass(lJNIEnv, "android/view/Window"); jmethodID MethodGetDecorView = (*lJNIEnv)->GetMethodID(lJNIEnv, ClassWindow, "getDecorView", "()Landroid/view/View;"); jobject lDecorView = (*lJNIEnv)->CallObjectMethod(lJNIEnv,lWindow, MethodGetDecorView); if (pShow) { // Runs lInputMethodManager.showSoftInput(...). jmethodID MethodShowSoftInput = (*lJNIEnv)->GetMethodID(lJNIEnv, ClassInputMethodManager, "showSoftInput", "(Landroid/view/View;I)Z"); jboolean lResult = (*lJNIEnv)->CallBooleanMethod(lJNIEnv, lInputMethodManager, MethodShowSoftInput, lDecorView, lFlags); } else { // Runs lWindow.getViewToken() jclass ClassView = (*lJNIEnv)->FindClass(lJNIEnv, "android/view/View"); jmethodID MethodGetWindowToken = (*lJNIEnv)->GetMethodID(lJNIEnv, ClassView, "getWindowToken", "()Landroid/os/IBinder;"); jobject lBinder = (*lJNIEnv)->CallObjectMethod(lJNIEnv,lDecorView, MethodGetWindowToken); // lInputMethodManager.hideSoftInput(...). jmethodID MethodHideSoftInput = (*lJNIEnv)->GetMethodID(lJNIEnv, ClassInputMethodManager, "hideSoftInputFromWindow", "(Landroid/os/IBinder;I)Z"); jboolean lRes = (*lJNIEnv)->CallBooleanMethod(lJNIEnv, lInputMethodManager, MethodHideSoftInput, lBinder, lFlags); } // Finished with the JVM. (*lJavaVM)->DetachCurrentThread(lJavaVM); } #endif //android #ifndef LAGUI_ANDROID void la_DisplayKeyboard(bool pShow) { return; } void la_HideNavBar(){ return; } #endif